From 4ce09cf760db8771f9c9b222d6f06df61c058ff7 Mon Sep 17 00:00:00 2001 From: vjpai Date: Fri, 18 Mar 2016 23:09:15 -0700 Subject: Reorder a release store after the operations it protects. --- src/core/iomgr/fd_posix.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src/core/iomgr/fd_posix.c') diff --git a/src/core/iomgr/fd_posix.c b/src/core/iomgr/fd_posix.c index 4ba7c5df94..3edafa0b07 100644 --- a/src/core/iomgr/fd_posix.c +++ b/src/core/iomgr/fd_posix.c @@ -72,6 +72,9 @@ static grpc_fd *fd_freelist = NULL; static gpr_mu fd_freelist_mu; static void freelist_fd(grpc_fd *fd) { + // Note that this function must be called after a release store (or + // full-barrier operation) on refst so that prior actions on the fd are + // ordered before the fd becomes visible to the freelist gpr_mu_lock(&fd_freelist_mu); fd->freelist_next = fd_freelist; fd_freelist = fd; @@ -92,7 +95,6 @@ static grpc_fd *alloc_fd(int fd) { gpr_mu_init(&r->mu); } - gpr_atm_rel_store(&r->refst, 1); r->shutdown = 0; r->read_closure = CLOSURE_NOT_READY; r->write_closure = CLOSURE_NOT_READY; @@ -104,6 +106,11 @@ static grpc_fd *alloc_fd(int fd) { r->on_done_closure = NULL; r->closed = 0; r->released = 0; + // The last operation on r before returning it should be a release-store + // so that all the above fields are globally visible before the value of + // r could escape to another thread. Our refcount itself needs a release-store + // so use this + gpr_atm_rel_store(&r->refst, 1); return r; } -- cgit v1.2.3 From c6993428c271513dfe15c9ff6f823ca656fbcbd6 Mon Sep 17 00:00:00 2001 From: vjpai Date: Mon, 21 Mar 2016 14:33:16 -0700 Subject: Lock the FD when initializing it out of the freelist. --- src/core/iomgr/fd_posix.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'src/core/iomgr/fd_posix.c') diff --git a/src/core/iomgr/fd_posix.c b/src/core/iomgr/fd_posix.c index 3edafa0b07..b4d038a3a1 100644 --- a/src/core/iomgr/fd_posix.c +++ b/src/core/iomgr/fd_posix.c @@ -72,9 +72,6 @@ static grpc_fd *fd_freelist = NULL; static gpr_mu fd_freelist_mu; static void freelist_fd(grpc_fd *fd) { - // Note that this function must be called after a release store (or - // full-barrier operation) on refst so that prior actions on the fd are - // ordered before the fd becomes visible to the freelist gpr_mu_lock(&fd_freelist_mu); fd->freelist_next = fd_freelist; fd_freelist = fd; @@ -95,6 +92,7 @@ static grpc_fd *alloc_fd(int fd) { gpr_mu_init(&r->mu); } + gpr_mu_lock(&r->mu); r->shutdown = 0; r->read_closure = CLOSURE_NOT_READY; r->write_closure = CLOSURE_NOT_READY; @@ -106,11 +104,9 @@ static grpc_fd *alloc_fd(int fd) { r->on_done_closure = NULL; r->closed = 0; r->released = 0; - // The last operation on r before returning it should be a release-store - // so that all the above fields are globally visible before the value of - // r could escape to another thread. Our refcount itself needs a release-store - // so use this gpr_atm_rel_store(&r->refst, 1); + gpr_mu_unlock(&r->mu); + return r; } -- cgit v1.2.3 From f23078cbd302d32649537eedda1769c5685228d8 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 25 Mar 2016 17:07:29 -0700 Subject: Stage #1 of core breakup: move everything under lib --- BUILD | 1948 ++++++++++---------- Makefile | 736 ++++---- binding.gyp | 410 ++-- build.yaml | 722 ++++---- config.m4 | 446 ++--- gRPC.podspec | 1006 +++++----- grpc.gemspec | 708 +++---- package.json | 708 +++---- package.xml | 708 +++---- src/core/census/README.md | 76 - src/core/census/aggregation.h | 66 - src/core/census/context.c | 509 ----- src/core/census/grpc_context.c | 53 - src/core/census/grpc_filter.c | 198 -- src/core/census/grpc_filter.h | 44 - src/core/census/grpc_plugin.c | 70 - src/core/census/grpc_plugin.h | 40 - src/core/census/initialize.c | 54 - src/core/census/mlog.c | 600 ------ src/core/census/mlog.h | 95 - src/core/census/operation.c | 63 - src/core/census/placeholders.c | 109 -- src/core/census/rpc_metric_id.h | 51 - src/core/census/tracing.c | 45 - src/core/channel/channel_args.c | 271 --- src/core/channel/channel_args.h | 94 - src/core/channel/channel_stack.c | 262 --- src/core/channel/channel_stack.h | 260 --- src/core/channel/channel_stack_builder.c | 258 --- src/core/channel/channel_stack_builder.h | 155 -- src/core/channel/client_channel.c | 526 ------ src/core/channel/client_channel.h | 63 - src/core/channel/compress_filter.c | 304 --- src/core/channel/compress_filter.h | 65 - src/core/channel/connected_channel.c | 176 -- src/core/channel/connected_channel.h | 42 - src/core/channel/context.h | 49 - src/core/channel/http_client_filter.c | 255 --- src/core/channel/http_client_filter.h | 44 - src/core/channel/http_server_filter.c | 240 --- src/core/channel/http_server_filter.h | 42 - src/core/channel/subchannel_call_holder.c | 259 --- src/core/channel/subchannel_call_holder.h | 97 - src/core/client_config/README.md | 66 - src/core/client_config/client_config.c | 74 - src/core/client_config/client_config.h | 53 - src/core/client_config/connector.c | 55 - src/core/client_config/connector.h | 92 - .../client_config/default_initial_connect_string.c | 39 - src/core/client_config/initial_connect_string.c | 53 - src/core/client_config/initial_connect_string.h | 50 - .../client_config/lb_policies/load_balancer_api.c | 163 -- .../client_config/lb_policies/load_balancer_api.h | 85 - src/core/client_config/lb_policies/pick_first.c | 421 ----- src/core/client_config/lb_policies/pick_first.h | 43 - src/core/client_config/lb_policies/round_robin.c | 542 ------ src/core/client_config/lb_policies/round_robin.h | 46 - src/core/client_config/lb_policy.c | 134 -- src/core/client_config/lb_policy.h | 144 -- src/core/client_config/lb_policy_factory.c | 48 - src/core/client_config/lb_policy_factory.h | 73 - src/core/client_config/lb_policy_registry.c | 88 - src/core/client_config/lb_policy_registry.h | 54 - src/core/client_config/resolver.c | 82 - src/core/client_config/resolver.h | 94 - src/core/client_config/resolver_factory.c | 55 - src/core/client_config/resolver_factory.h | 82 - src/core/client_config/resolver_registry.c | 137 -- src/core/client_config/resolver_registry.h | 65 - src/core/client_config/resolvers/dns_resolver.c | 309 ---- src/core/client_config/resolvers/dns_resolver.h | 42 - .../client_config/resolvers/sockaddr_resolver.c | 372 ---- .../client_config/resolvers/sockaddr_resolver.h | 50 - .../client_config/resolvers/zookeeper_resolver.c | 520 ------ .../client_config/resolvers/zookeeper_resolver.h | 42 - src/core/client_config/subchannel.c | 678 ------- src/core/client_config/subchannel.h | 174 -- src/core/client_config/subchannel_factory.c | 49 - src/core/client_config/subchannel_factory.h | 66 - src/core/client_config/subchannel_index.c | 262 --- src/core/client_config/subchannel_index.h | 77 - src/core/client_config/uri_parser.c | 242 --- src/core/client_config/uri_parser.h | 51 - src/core/compression/algorithm_metadata.h | 53 - src/core/compression/compression_algorithm.c | 203 -- src/core/compression/message_compress.c | 198 -- src/core/compression/message_compress.h | 52 - src/core/debug/trace.c | 136 -- src/core/debug/trace.h | 43 - src/core/http/format_request.c | 120 -- src/core/http/format_request.h | 45 - src/core/http/httpcli.c | 293 --- src/core/http/httpcli.h | 144 -- src/core/http/httpcli_security_connector.c | 188 -- src/core/http/parser.c | 313 ---- src/core/http/parser.h | 116 -- src/core/iomgr/closure.c | 98 - src/core/iomgr/closure.h | 98 - src/core/iomgr/endpoint.c | 67 - src/core/iomgr/endpoint.h | 102 - src/core/iomgr/endpoint_pair.h | 47 - src/core/iomgr/endpoint_pair_posix.c | 83 - src/core/iomgr/endpoint_pair_windows.c | 97 - src/core/iomgr/exec_ctx.c | 151 -- src/core/iomgr/exec_ctx.h | 98 - src/core/iomgr/executor.c | 143 -- src/core/iomgr/executor.h | 53 - src/core/iomgr/fd_posix.c | 454 ----- src/core/iomgr/fd_posix.h | 192 -- src/core/iomgr/iocp_windows.c | 208 --- src/core/iomgr/iocp_windows.h | 63 - src/core/iomgr/iomgr.c | 175 -- src/core/iomgr/iomgr.h | 43 - src/core/iomgr/iomgr_internal.h | 62 - src/core/iomgr/iomgr_posix.c | 52 - src/core/iomgr/iomgr_posix.h | 39 - src/core/iomgr/iomgr_windows.c | 73 - src/core/iomgr/pollset.h | 94 - src/core/iomgr/pollset_multipoller_with_epoll.c | 324 ---- .../iomgr/pollset_multipoller_with_poll_posix.c | 234 --- src/core/iomgr/pollset_posix.c | 633 ------- src/core/iomgr/pollset_posix.h | 153 -- src/core/iomgr/pollset_set.h | 61 - src/core/iomgr/pollset_set_posix.c | 202 -- src/core/iomgr/pollset_set_posix.h | 45 - src/core/iomgr/pollset_set_windows.c | 60 - src/core/iomgr/pollset_set_windows.h | 39 - src/core/iomgr/pollset_windows.c | 240 --- src/core/iomgr/pollset_windows.h | 75 - src/core/iomgr/resolve_address.h | 72 - src/core/iomgr/resolve_address_posix.c | 178 -- src/core/iomgr/resolve_address_windows.c | 169 -- src/core/iomgr/sockaddr.h | 47 - src/core/iomgr/sockaddr_posix.h | 44 - src/core/iomgr/sockaddr_utils.c | 227 --- src/core/iomgr/sockaddr_utils.h | 89 - src/core/iomgr/sockaddr_win32.h | 43 - src/core/iomgr/socket_utils_common_posix.c | 208 --- src/core/iomgr/socket_utils_linux.c | 51 - src/core/iomgr/socket_utils_posix.c | 70 - src/core/iomgr/socket_utils_posix.h | 113 -- src/core/iomgr/socket_windows.c | 100 - src/core/iomgr/socket_windows.h | 111 -- src/core/iomgr/tcp_client.h | 53 - src/core/iomgr/tcp_client_posix.c | 306 --- src/core/iomgr/tcp_client_windows.c | 221 --- src/core/iomgr/tcp_posix.c | 493 ----- src/core/iomgr/tcp_posix.h | 71 - src/core/iomgr/tcp_server.h | 103 -- src/core/iomgr/tcp_server_posix.c | 607 ------ src/core/iomgr/tcp_server_windows.c | 557 ------ src/core/iomgr/tcp_windows.c | 402 ---- src/core/iomgr/tcp_windows.h | 57 - src/core/iomgr/time_averaged_stats.c | 77 - src/core/iomgr/time_averaged_stats.h | 88 - src/core/iomgr/timer.c | 356 ---- src/core/iomgr/timer.h | 108 -- src/core/iomgr/timer_heap.c | 146 -- src/core/iomgr/timer_heap.h | 57 - src/core/iomgr/udp_server.c | 418 ----- src/core/iomgr/udp_server.h | 77 - src/core/iomgr/unix_sockets_posix.c | 103 -- src/core/iomgr/unix_sockets_posix.h | 61 - src/core/iomgr/unix_sockets_posix_noop.c | 61 - src/core/iomgr/wakeup_fd_eventfd.c | 85 - src/core/iomgr/wakeup_fd_nospecial.c | 51 - src/core/iomgr/wakeup_fd_pipe.c | 102 - src/core/iomgr/wakeup_fd_pipe.h | 41 - src/core/iomgr/wakeup_fd_posix.c | 72 - src/core/iomgr/wakeup_fd_posix.h | 101 - src/core/iomgr/workqueue.h | 83 - src/core/iomgr/workqueue_posix.c | 144 -- src/core/iomgr/workqueue_posix.h | 53 - src/core/iomgr/workqueue_windows.c | 40 - src/core/iomgr/workqueue_windows.h | 37 - src/core/json/json.c | 64 - src/core/json/json.h | 88 - src/core/json/json_common.h | 49 - src/core/json/json_reader.c | 659 ------- src/core/json/json_reader.h | 160 -- src/core/json/json_string.c | 379 ---- src/core/json/json_writer.c | 258 --- src/core/json/json_writer.h | 97 - src/core/lib/census/README.md | 76 + src/core/lib/census/aggregation.h | 66 + src/core/lib/census/context.c | 509 +++++ src/core/lib/census/grpc_context.c | 53 + src/core/lib/census/grpc_filter.c | 198 ++ src/core/lib/census/grpc_filter.h | 44 + src/core/lib/census/grpc_plugin.c | 70 + src/core/lib/census/grpc_plugin.h | 40 + src/core/lib/census/initialize.c | 54 + src/core/lib/census/mlog.c | 600 ++++++ src/core/lib/census/mlog.h | 95 + src/core/lib/census/operation.c | 63 + src/core/lib/census/placeholders.c | 109 ++ src/core/lib/census/rpc_metric_id.h | 51 + src/core/lib/census/tracing.c | 45 + src/core/lib/channel/channel_args.c | 271 +++ src/core/lib/channel/channel_args.h | 94 + src/core/lib/channel/channel_stack.c | 262 +++ src/core/lib/channel/channel_stack.h | 260 +++ src/core/lib/channel/channel_stack_builder.c | 258 +++ src/core/lib/channel/channel_stack_builder.h | 155 ++ src/core/lib/channel/client_channel.c | 526 ++++++ src/core/lib/channel/client_channel.h | 63 + src/core/lib/channel/compress_filter.c | 304 +++ src/core/lib/channel/compress_filter.h | 65 + src/core/lib/channel/connected_channel.c | 176 ++ src/core/lib/channel/connected_channel.h | 42 + src/core/lib/channel/context.h | 49 + src/core/lib/channel/http_client_filter.c | 255 +++ src/core/lib/channel/http_client_filter.h | 44 + src/core/lib/channel/http_server_filter.c | 240 +++ src/core/lib/channel/http_server_filter.h | 42 + src/core/lib/channel/subchannel_call_holder.c | 259 +++ src/core/lib/channel/subchannel_call_holder.h | 97 + src/core/lib/client_config/README.md | 66 + src/core/lib/client_config/client_config.c | 74 + src/core/lib/client_config/client_config.h | 53 + src/core/lib/client_config/connector.c | 55 + src/core/lib/client_config/connector.h | 92 + .../client_config/default_initial_connect_string.c | 39 + .../lib/client_config/initial_connect_string.c | 53 + .../lib/client_config/initial_connect_string.h | 50 + .../client_config/lb_policies/load_balancer_api.c | 163 ++ .../client_config/lb_policies/load_balancer_api.h | 85 + .../lib/client_config/lb_policies/pick_first.c | 421 +++++ .../lib/client_config/lb_policies/pick_first.h | 43 + .../lib/client_config/lb_policies/round_robin.c | 542 ++++++ .../lib/client_config/lb_policies/round_robin.h | 46 + src/core/lib/client_config/lb_policy.c | 134 ++ src/core/lib/client_config/lb_policy.h | 144 ++ src/core/lib/client_config/lb_policy_factory.c | 48 + src/core/lib/client_config/lb_policy_factory.h | 73 + src/core/lib/client_config/lb_policy_registry.c | 88 + src/core/lib/client_config/lb_policy_registry.h | 54 + src/core/lib/client_config/resolver.c | 82 + src/core/lib/client_config/resolver.h | 94 + src/core/lib/client_config/resolver_factory.c | 55 + src/core/lib/client_config/resolver_factory.h | 82 + src/core/lib/client_config/resolver_registry.c | 137 ++ src/core/lib/client_config/resolver_registry.h | 65 + .../lib/client_config/resolvers/dns_resolver.c | 309 ++++ .../lib/client_config/resolvers/dns_resolver.h | 42 + .../client_config/resolvers/sockaddr_resolver.c | 372 ++++ .../client_config/resolvers/sockaddr_resolver.h | 50 + .../client_config/resolvers/zookeeper_resolver.c | 520 ++++++ .../client_config/resolvers/zookeeper_resolver.h | 42 + src/core/lib/client_config/subchannel.c | 678 +++++++ src/core/lib/client_config/subchannel.h | 174 ++ src/core/lib/client_config/subchannel_factory.c | 49 + src/core/lib/client_config/subchannel_factory.h | 66 + src/core/lib/client_config/subchannel_index.c | 262 +++ src/core/lib/client_config/subchannel_index.h | 77 + src/core/lib/client_config/uri_parser.c | 242 +++ src/core/lib/client_config/uri_parser.h | 51 + src/core/lib/compression/algorithm_metadata.h | 53 + src/core/lib/compression/compression_algorithm.c | 203 ++ src/core/lib/compression/message_compress.c | 198 ++ src/core/lib/compression/message_compress.h | 52 + src/core/lib/debug/trace.c | 136 ++ src/core/lib/debug/trace.h | 43 + src/core/lib/http/format_request.c | 120 ++ src/core/lib/http/format_request.h | 45 + src/core/lib/http/httpcli.c | 293 +++ src/core/lib/http/httpcli.h | 144 ++ src/core/lib/http/httpcli_security_connector.c | 188 ++ src/core/lib/http/parser.c | 313 ++++ src/core/lib/http/parser.h | 116 ++ src/core/lib/iomgr/closure.c | 98 + src/core/lib/iomgr/closure.h | 98 + src/core/lib/iomgr/endpoint.c | 67 + src/core/lib/iomgr/endpoint.h | 102 + src/core/lib/iomgr/endpoint_pair.h | 47 + src/core/lib/iomgr/endpoint_pair_posix.c | 83 + src/core/lib/iomgr/endpoint_pair_windows.c | 97 + src/core/lib/iomgr/exec_ctx.c | 151 ++ src/core/lib/iomgr/exec_ctx.h | 98 + src/core/lib/iomgr/executor.c | 143 ++ src/core/lib/iomgr/executor.h | 53 + src/core/lib/iomgr/fd_posix.c | 454 +++++ src/core/lib/iomgr/fd_posix.h | 192 ++ src/core/lib/iomgr/iocp_windows.c | 208 +++ src/core/lib/iomgr/iocp_windows.h | 63 + src/core/lib/iomgr/iomgr.c | 175 ++ src/core/lib/iomgr/iomgr.h | 43 + src/core/lib/iomgr/iomgr_internal.h | 62 + src/core/lib/iomgr/iomgr_posix.c | 52 + src/core/lib/iomgr/iomgr_posix.h | 39 + src/core/lib/iomgr/iomgr_windows.c | 73 + src/core/lib/iomgr/pollset.h | 94 + .../lib/iomgr/pollset_multipoller_with_epoll.c | 324 ++++ .../iomgr/pollset_multipoller_with_poll_posix.c | 234 +++ src/core/lib/iomgr/pollset_posix.c | 633 +++++++ src/core/lib/iomgr/pollset_posix.h | 153 ++ src/core/lib/iomgr/pollset_set.h | 61 + src/core/lib/iomgr/pollset_set_posix.c | 202 ++ src/core/lib/iomgr/pollset_set_posix.h | 45 + src/core/lib/iomgr/pollset_set_windows.c | 60 + src/core/lib/iomgr/pollset_set_windows.h | 39 + src/core/lib/iomgr/pollset_windows.c | 240 +++ src/core/lib/iomgr/pollset_windows.h | 75 + src/core/lib/iomgr/resolve_address.h | 72 + src/core/lib/iomgr/resolve_address_posix.c | 178 ++ src/core/lib/iomgr/resolve_address_windows.c | 169 ++ src/core/lib/iomgr/sockaddr.h | 47 + src/core/lib/iomgr/sockaddr_posix.h | 44 + src/core/lib/iomgr/sockaddr_utils.c | 227 +++ src/core/lib/iomgr/sockaddr_utils.h | 89 + src/core/lib/iomgr/sockaddr_win32.h | 43 + src/core/lib/iomgr/socket_utils_common_posix.c | 208 +++ src/core/lib/iomgr/socket_utils_linux.c | 51 + src/core/lib/iomgr/socket_utils_posix.c | 70 + src/core/lib/iomgr/socket_utils_posix.h | 113 ++ src/core/lib/iomgr/socket_windows.c | 100 + src/core/lib/iomgr/socket_windows.h | 111 ++ src/core/lib/iomgr/tcp_client.h | 53 + src/core/lib/iomgr/tcp_client_posix.c | 306 +++ src/core/lib/iomgr/tcp_client_windows.c | 221 +++ src/core/lib/iomgr/tcp_posix.c | 493 +++++ src/core/lib/iomgr/tcp_posix.h | 71 + src/core/lib/iomgr/tcp_server.h | 103 ++ src/core/lib/iomgr/tcp_server_posix.c | 607 ++++++ src/core/lib/iomgr/tcp_server_windows.c | 557 ++++++ src/core/lib/iomgr/tcp_windows.c | 402 ++++ src/core/lib/iomgr/tcp_windows.h | 57 + src/core/lib/iomgr/time_averaged_stats.c | 77 + src/core/lib/iomgr/time_averaged_stats.h | 88 + src/core/lib/iomgr/timer.c | 356 ++++ src/core/lib/iomgr/timer.h | 108 ++ src/core/lib/iomgr/timer_heap.c | 146 ++ src/core/lib/iomgr/timer_heap.h | 57 + src/core/lib/iomgr/udp_server.c | 418 +++++ src/core/lib/iomgr/udp_server.h | 77 + src/core/lib/iomgr/unix_sockets_posix.c | 103 ++ src/core/lib/iomgr/unix_sockets_posix.h | 61 + src/core/lib/iomgr/unix_sockets_posix_noop.c | 61 + src/core/lib/iomgr/wakeup_fd_eventfd.c | 85 + src/core/lib/iomgr/wakeup_fd_nospecial.c | 51 + src/core/lib/iomgr/wakeup_fd_pipe.c | 102 + src/core/lib/iomgr/wakeup_fd_pipe.h | 41 + src/core/lib/iomgr/wakeup_fd_posix.c | 72 + src/core/lib/iomgr/wakeup_fd_posix.h | 101 + src/core/lib/iomgr/workqueue.h | 83 + src/core/lib/iomgr/workqueue_posix.c | 144 ++ src/core/lib/iomgr/workqueue_posix.h | 53 + src/core/lib/iomgr/workqueue_windows.c | 40 + src/core/lib/iomgr/workqueue_windows.h | 37 + src/core/lib/json/json.c | 64 + src/core/lib/json/json.h | 88 + src/core/lib/json/json_common.h | 49 + src/core/lib/json/json_reader.c | 659 +++++++ src/core/lib/json/json_reader.h | 160 ++ src/core/lib/json/json_string.c | 379 ++++ src/core/lib/json/json_writer.c | 258 +++ src/core/lib/json/json_writer.h | 97 + src/core/lib/profiling/basic_timers.c | 274 +++ src/core/lib/profiling/stap_probes.d | 7 + src/core/lib/profiling/stap_timers.c | 65 + src/core/lib/profiling/timers.h | 119 ++ src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c | 119 ++ src/core/lib/proto/grpc/lb/v0/load_balancer.pb.h | 182 ++ src/core/lib/security/auth_filters.h | 42 + src/core/lib/security/b64.c | 233 +++ src/core/lib/security/b64.h | 52 + src/core/lib/security/client_auth_filter.c | 336 ++++ src/core/lib/security/credentials.c | 1281 +++++++++++++ src/core/lib/security/credentials.h | 377 ++++ src/core/lib/security/credentials_metadata.c | 101 + src/core/lib/security/credentials_posix.c | 61 + src/core/lib/security/credentials_win32.c | 61 + src/core/lib/security/google_default_credentials.c | 266 +++ src/core/lib/security/handshake.c | 336 ++++ src/core/lib/security/handshake.h | 51 + src/core/lib/security/json_token.c | 411 +++++ src/core/lib/security/json_token.h | 118 ++ src/core/lib/security/jwt_verifier.c | 843 +++++++++ src/core/lib/security/jwt_verifier.h | 136 ++ src/core/lib/security/secure_endpoint.c | 384 ++++ src/core/lib/security/secure_endpoint.h | 49 + src/core/lib/security/security_connector.c | 812 ++++++++ src/core/lib/security/security_connector.h | 266 +++ src/core/lib/security/security_context.c | 347 ++++ src/core/lib/security/security_context.h | 114 ++ src/core/lib/security/server_auth_filter.c | 264 +++ src/core/lib/security/server_secure_chttp2.c | 264 +++ src/core/lib/statistics/census_init.c | 48 + src/core/lib/statistics/census_interface.h | 76 + src/core/lib/statistics/census_log.c | 603 ++++++ src/core/lib/statistics/census_log.h | 91 + src/core/lib/statistics/census_rpc_stats.c | 253 +++ src/core/lib/statistics/census_rpc_stats.h | 101 + src/core/lib/statistics/census_tracing.c | 241 +++ src/core/lib/statistics/census_tracing.h | 96 + src/core/lib/statistics/hash_table.c | 303 +++ src/core/lib/statistics/hash_table.h | 131 ++ src/core/lib/statistics/window_stats.c | 316 ++++ src/core/lib/statistics/window_stats.h | 173 ++ src/core/lib/support/alloc.c | 90 + src/core/lib/support/avl.c | 288 +++ src/core/lib/support/backoff.c | 76 + src/core/lib/support/backoff.h | 68 + src/core/lib/support/block_annotate.h | 48 + src/core/lib/support/cmdline.c | 347 ++++ src/core/lib/support/cpu_iphone.c | 49 + src/core/lib/support/cpu_linux.c | 78 + src/core/lib/support/cpu_posix.c | 77 + src/core/lib/support/cpu_windows.c | 47 + src/core/lib/support/env.h | 60 + src/core/lib/support/env_linux.c | 89 + src/core/lib/support/env_posix.c | 57 + src/core/lib/support/env_win32.c | 73 + src/core/lib/support/histogram.c | 244 +++ src/core/lib/support/host_port.c | 110 ++ src/core/lib/support/load_file.c | 91 + src/core/lib/support/load_file.h | 55 + src/core/lib/support/log.c | 66 + src/core/lib/support/log_android.c | 87 + src/core/lib/support/log_linux.c | 105 ++ src/core/lib/support/log_posix.c | 102 + src/core/lib/support/log_win32.c | 126 ++ src/core/lib/support/murmur_hash.c | 96 + src/core/lib/support/murmur_hash.h | 44 + src/core/lib/support/slice.c | 343 ++++ src/core/lib/support/slice_buffer.c | 282 +++ src/core/lib/support/stack_lockfree.c | 185 ++ src/core/lib/support/stack_lockfree.h | 53 + src/core/lib/support/string.c | 296 +++ src/core/lib/support/string.h | 121 ++ src/core/lib/support/string_posix.c | 86 + src/core/lib/support/string_win32.c | 109 ++ src/core/lib/support/string_win32.h | 47 + src/core/lib/support/subprocess_posix.c | 112 ++ src/core/lib/support/subprocess_windows.c | 141 ++ src/core/lib/support/sync.c | 127 ++ src/core/lib/support/sync_posix.c | 104 ++ src/core/lib/support/sync_win32.c | 133 ++ src/core/lib/support/thd.c | 64 + src/core/lib/support/thd_internal.h | 39 + src/core/lib/support/thd_posix.c | 94 + src/core/lib/support/thd_win32.c | 117 ++ src/core/lib/support/time.c | 304 +++ src/core/lib/support/time_posix.c | 170 ++ src/core/lib/support/time_precise.c | 89 + src/core/lib/support/time_precise.h | 42 + src/core/lib/support/time_win32.c | 110 ++ src/core/lib/support/tls_pthread.c | 45 + src/core/lib/support/tmpfile.h | 55 + src/core/lib/support/tmpfile_posix.c | 85 + src/core/lib/support/tmpfile_win32.c | 84 + src/core/lib/support/wrap_memcpy.c | 53 + src/core/lib/surface/alarm.c | 84 + src/core/lib/surface/api_trace.c | 36 + src/core/lib/surface/api_trace.h | 65 + src/core/lib/surface/byte_buffer.c | 97 + src/core/lib/surface/byte_buffer_reader.c | 123 ++ src/core/lib/surface/call.c | 1491 +++++++++++++++ src/core/lib/surface/call.h | 116 ++ src/core/lib/surface/call_details.c | 50 + src/core/lib/surface/call_log_batch.c | 118 ++ src/core/lib/surface/call_test_only.h | 64 + src/core/lib/surface/channel.c | 324 ++++ src/core/lib/surface/channel.h | 75 + src/core/lib/surface/channel_connectivity.c | 207 +++ src/core/lib/surface/channel_create.c | 223 +++ src/core/lib/surface/channel_init.c | 146 ++ src/core/lib/surface/channel_init.h | 86 + src/core/lib/surface/channel_ping.c | 79 + src/core/lib/surface/channel_stack_type.c | 54 + src/core/lib/surface/channel_stack_type.h | 58 + src/core/lib/surface/completion_queue.c | 512 +++++ src/core/lib/surface/completion_queue.h | 91 + src/core/lib/surface/event_string.c | 81 + src/core/lib/surface/event_string.h | 42 + src/core/lib/surface/init.c | 239 +++ src/core/lib/surface/init.h | 41 + src/core/lib/surface/init_secure.c | 89 + src/core/lib/surface/init_unsecure.c | 38 + src/core/lib/surface/lame_client.c | 155 ++ src/core/lib/surface/lame_client.h | 41 + src/core/lib/surface/metadata_array.c | 49 + src/core/lib/surface/secure_channel_create.c | 319 ++++ src/core/lib/surface/server.c | 1319 +++++++++++++ src/core/lib/surface/server.h | 62 + src/core/lib/surface/server_chttp2.c | 146 ++ src/core/lib/surface/surface_trace.h | 48 + src/core/lib/surface/validate_metadata.c | 73 + src/core/lib/surface/version.c | 39 + src/core/lib/transport/byte_stream.c | 78 + src/core/lib/transport/byte_stream.h | 89 + src/core/lib/transport/chttp2/alpn.c | 56 + src/core/lib/transport/chttp2/alpn.h | 49 + src/core/lib/transport/chttp2/bin_encoder.c | 233 +++ src/core/lib/transport/chttp2/bin_encoder.h | 54 + src/core/lib/transport/chttp2/frame.h | 69 + src/core/lib/transport/chttp2/frame_data.c | 248 +++ src/core/lib/transport/chttp2/frame_data.h | 101 + src/core/lib/transport/chttp2/frame_goaway.c | 193 ++ src/core/lib/transport/chttp2/frame_goaway.h | 77 + src/core/lib/transport/chttp2/frame_ping.c | 97 + src/core/lib/transport/chttp2/frame_ping.h | 56 + src/core/lib/transport/chttp2/frame_rst_stream.c | 99 + src/core/lib/transport/chttp2/frame_rst_stream.h | 55 + src/core/lib/transport/chttp2/frame_settings.c | 259 +++ src/core/lib/transport/chttp2/frame_settings.h | 103 ++ .../lib/transport/chttp2/frame_window_update.c | 113 ++ .../lib/transport/chttp2/frame_window_update.h | 56 + src/core/lib/transport/chttp2/hpack_encoder.c | 568 ++++++ src/core/lib/transport/chttp2/hpack_encoder.h | 95 + src/core/lib/transport/chttp2/hpack_parser.c | 1449 +++++++++++++++ src/core/lib/transport/chttp2/hpack_parser.h | 116 ++ src/core/lib/transport/chttp2/hpack_table.c | 361 ++++ src/core/lib/transport/chttp2/hpack_table.h | 108 ++ src/core/lib/transport/chttp2/hpack_tables.txt | 66 + src/core/lib/transport/chttp2/http2_errors.h | 56 + src/core/lib/transport/chttp2/huffsyms.c | 105 ++ src/core/lib/transport/chttp2/huffsyms.h | 48 + src/core/lib/transport/chttp2/incoming_metadata.c | 96 + src/core/lib/transport/chttp2/incoming_metadata.h | 60 + src/core/lib/transport/chttp2/internal.h | 780 ++++++++ src/core/lib/transport/chttp2/parsing.c | 866 +++++++++ src/core/lib/transport/chttp2/status_conversion.c | 109 ++ src/core/lib/transport/chttp2/status_conversion.h | 50 + src/core/lib/transport/chttp2/stream_lists.c | 442 +++++ src/core/lib/transport/chttp2/stream_map.c | 197 ++ src/core/lib/transport/chttp2/stream_map.h | 84 + src/core/lib/transport/chttp2/timeout_encoding.c | 188 ++ src/core/lib/transport/chttp2/timeout_encoding.h | 47 + src/core/lib/transport/chttp2/varint.c | 65 + src/core/lib/transport/chttp2/varint.h | 75 + src/core/lib/transport/chttp2/writing.c | 350 ++++ src/core/lib/transport/chttp2_transport.c | 1785 ++++++++++++++++++ src/core/lib/transport/chttp2_transport.h | 51 + src/core/lib/transport/connectivity_state.c | 164 ++ src/core/lib/transport/connectivity_state.h | 85 + src/core/lib/transport/metadata.c | 698 +++++++ src/core/lib/transport/metadata.h | 156 ++ src/core/lib/transport/metadata_batch.c | 194 ++ src/core/lib/transport/metadata_batch.h | 125 ++ src/core/lib/transport/static_metadata.c | 160 ++ src/core/lib/transport/static_metadata.h | 408 ++++ src/core/lib/transport/transport.c | 184 ++ src/core/lib/transport/transport.h | 242 +++ src/core/lib/transport/transport_impl.h | 81 + src/core/lib/transport/transport_op_string.c | 140 ++ src/core/lib/tsi/fake_transport_security.c | 527 ++++++ src/core/lib/tsi/fake_transport_security.h | 61 + src/core/lib/tsi/ssl_transport_security.c | 1536 +++++++++++++++ src/core/lib/tsi/ssl_transport_security.h | 174 ++ src/core/lib/tsi/ssl_types.h | 55 + src/core/lib/tsi/test_creds/README | 62 + src/core/lib/tsi/test_creds/badclient.key | 16 + src/core/lib/tsi/test_creds/badclient.pem | 17 + src/core/lib/tsi/test_creds/badserver.key | 16 + src/core/lib/tsi/test_creds/badserver.pem | 17 + src/core/lib/tsi/test_creds/ca-openssl.cnf | 17 + src/core/lib/tsi/test_creds/ca.key | 16 + src/core/lib/tsi/test_creds/ca.pem | 15 + src/core/lib/tsi/test_creds/client.key | 16 + src/core/lib/tsi/test_creds/client.pem | 14 + src/core/lib/tsi/test_creds/server0.key | 16 + src/core/lib/tsi/test_creds/server0.pem | 14 + src/core/lib/tsi/test_creds/server1-openssl.cnf | 26 + src/core/lib/tsi/test_creds/server1.key | 16 + src/core/lib/tsi/test_creds/server1.pem | 16 + src/core/lib/tsi/transport_security.c | 284 +++ src/core/lib/tsi/transport_security.h | 111 ++ src/core/lib/tsi/transport_security_interface.h | 344 ++++ src/core/profiling/basic_timers.c | 274 --- src/core/profiling/stap_probes.d | 7 - src/core/profiling/stap_timers.c | 65 - src/core/profiling/timers.h | 119 -- src/core/proto/grpc/lb/v0/load_balancer.pb.c | 119 -- src/core/proto/grpc/lb/v0/load_balancer.pb.h | 182 -- src/core/security/auth_filters.h | 42 - src/core/security/b64.c | 233 --- src/core/security/b64.h | 52 - src/core/security/client_auth_filter.c | 336 ---- src/core/security/credentials.c | 1281 ------------- src/core/security/credentials.h | 377 ---- src/core/security/credentials_metadata.c | 101 - src/core/security/credentials_posix.c | 61 - src/core/security/credentials_win32.c | 61 - src/core/security/google_default_credentials.c | 266 --- src/core/security/handshake.c | 336 ---- src/core/security/handshake.h | 51 - src/core/security/json_token.c | 411 ----- src/core/security/json_token.h | 118 -- src/core/security/jwt_verifier.c | 843 --------- src/core/security/jwt_verifier.h | 136 -- src/core/security/secure_endpoint.c | 384 ---- src/core/security/secure_endpoint.h | 49 - src/core/security/security_connector.c | 812 -------- src/core/security/security_connector.h | 266 --- src/core/security/security_context.c | 347 ---- src/core/security/security_context.h | 114 -- src/core/security/server_auth_filter.c | 264 --- src/core/security/server_secure_chttp2.c | 264 --- src/core/statistics/census_init.c | 48 - src/core/statistics/census_interface.h | 76 - src/core/statistics/census_log.c | 603 ------ src/core/statistics/census_log.h | 91 - src/core/statistics/census_rpc_stats.c | 253 --- src/core/statistics/census_rpc_stats.h | 101 - src/core/statistics/census_tracing.c | 241 --- src/core/statistics/census_tracing.h | 96 - src/core/statistics/hash_table.c | 303 --- src/core/statistics/hash_table.h | 131 -- src/core/statistics/window_stats.c | 316 ---- src/core/statistics/window_stats.h | 173 -- src/core/support/alloc.c | 90 - src/core/support/avl.c | 288 --- src/core/support/backoff.c | 76 - src/core/support/backoff.h | 68 - src/core/support/block_annotate.h | 48 - src/core/support/cmdline.c | 347 ---- src/core/support/cpu_iphone.c | 49 - src/core/support/cpu_linux.c | 78 - src/core/support/cpu_posix.c | 77 - src/core/support/cpu_windows.c | 47 - src/core/support/env.h | 60 - src/core/support/env_linux.c | 89 - src/core/support/env_posix.c | 57 - src/core/support/env_win32.c | 73 - src/core/support/histogram.c | 244 --- src/core/support/host_port.c | 110 -- src/core/support/load_file.c | 91 - src/core/support/load_file.h | 55 - src/core/support/log.c | 66 - src/core/support/log_android.c | 87 - src/core/support/log_linux.c | 105 -- src/core/support/log_posix.c | 102 - src/core/support/log_win32.c | 126 -- src/core/support/murmur_hash.c | 96 - src/core/support/murmur_hash.h | 44 - src/core/support/slice.c | 343 ---- src/core/support/slice_buffer.c | 282 --- src/core/support/stack_lockfree.c | 185 -- src/core/support/stack_lockfree.h | 53 - src/core/support/string.c | 296 --- src/core/support/string.h | 121 -- src/core/support/string_posix.c | 86 - src/core/support/string_win32.c | 109 -- src/core/support/string_win32.h | 47 - src/core/support/subprocess_posix.c | 112 -- src/core/support/subprocess_windows.c | 141 -- src/core/support/sync.c | 127 -- src/core/support/sync_posix.c | 104 -- src/core/support/sync_win32.c | 133 -- src/core/support/thd.c | 64 - src/core/support/thd_internal.h | 39 - src/core/support/thd_posix.c | 94 - src/core/support/thd_win32.c | 117 -- src/core/support/time.c | 304 --- src/core/support/time_posix.c | 170 -- src/core/support/time_precise.c | 89 - src/core/support/time_precise.h | 42 - src/core/support/time_win32.c | 110 -- src/core/support/tls_pthread.c | 45 - src/core/support/tmpfile.h | 55 - src/core/support/tmpfile_posix.c | 85 - src/core/support/tmpfile_win32.c | 84 - src/core/support/wrap_memcpy.c | 53 - src/core/surface/alarm.c | 84 - src/core/surface/api_trace.c | 36 - src/core/surface/api_trace.h | 65 - src/core/surface/byte_buffer.c | 97 - src/core/surface/byte_buffer_reader.c | 123 -- src/core/surface/call.c | 1491 --------------- src/core/surface/call.h | 116 -- src/core/surface/call_details.c | 50 - src/core/surface/call_log_batch.c | 118 -- src/core/surface/call_test_only.h | 64 - src/core/surface/channel.c | 324 ---- src/core/surface/channel.h | 75 - src/core/surface/channel_connectivity.c | 207 --- src/core/surface/channel_create.c | 223 --- src/core/surface/channel_init.c | 146 -- src/core/surface/channel_init.h | 86 - src/core/surface/channel_ping.c | 79 - src/core/surface/channel_stack_type.c | 54 - src/core/surface/channel_stack_type.h | 58 - src/core/surface/completion_queue.c | 512 ----- src/core/surface/completion_queue.h | 91 - src/core/surface/event_string.c | 81 - src/core/surface/event_string.h | 42 - src/core/surface/init.c | 239 --- src/core/surface/init.h | 41 - src/core/surface/init_secure.c | 89 - src/core/surface/init_unsecure.c | 38 - src/core/surface/lame_client.c | 155 -- src/core/surface/lame_client.h | 41 - src/core/surface/metadata_array.c | 49 - src/core/surface/secure_channel_create.c | 319 ---- src/core/surface/server.c | 1319 ------------- src/core/surface/server.h | 62 - src/core/surface/server_chttp2.c | 146 -- src/core/surface/surface_trace.h | 48 - src/core/surface/validate_metadata.c | 73 - src/core/surface/version.c | 39 - src/core/transport/byte_stream.c | 78 - src/core/transport/byte_stream.h | 89 - src/core/transport/chttp2/alpn.c | 56 - src/core/transport/chttp2/alpn.h | 49 - src/core/transport/chttp2/bin_encoder.c | 233 --- src/core/transport/chttp2/bin_encoder.h | 54 - src/core/transport/chttp2/frame.h | 69 - src/core/transport/chttp2/frame_data.c | 248 --- src/core/transport/chttp2/frame_data.h | 101 - src/core/transport/chttp2/frame_goaway.c | 193 -- src/core/transport/chttp2/frame_goaway.h | 77 - src/core/transport/chttp2/frame_ping.c | 97 - src/core/transport/chttp2/frame_ping.h | 56 - src/core/transport/chttp2/frame_rst_stream.c | 99 - src/core/transport/chttp2/frame_rst_stream.h | 55 - src/core/transport/chttp2/frame_settings.c | 259 --- src/core/transport/chttp2/frame_settings.h | 103 -- src/core/transport/chttp2/frame_window_update.c | 113 -- src/core/transport/chttp2/frame_window_update.h | 56 - src/core/transport/chttp2/hpack_encoder.c | 568 ------ src/core/transport/chttp2/hpack_encoder.h | 95 - src/core/transport/chttp2/hpack_parser.c | 1449 --------------- src/core/transport/chttp2/hpack_parser.h | 116 -- src/core/transport/chttp2/hpack_table.c | 361 ---- src/core/transport/chttp2/hpack_table.h | 108 -- src/core/transport/chttp2/hpack_tables.txt | 66 - src/core/transport/chttp2/http2_errors.h | 56 - src/core/transport/chttp2/huffsyms.c | 105 -- src/core/transport/chttp2/huffsyms.h | 48 - src/core/transport/chttp2/incoming_metadata.c | 96 - src/core/transport/chttp2/incoming_metadata.h | 60 - src/core/transport/chttp2/internal.h | 780 -------- src/core/transport/chttp2/parsing.c | 866 --------- src/core/transport/chttp2/status_conversion.c | 109 -- src/core/transport/chttp2/status_conversion.h | 50 - src/core/transport/chttp2/stream_lists.c | 442 ----- src/core/transport/chttp2/stream_map.c | 197 -- src/core/transport/chttp2/stream_map.h | 84 - src/core/transport/chttp2/timeout_encoding.c | 188 -- src/core/transport/chttp2/timeout_encoding.h | 47 - src/core/transport/chttp2/varint.c | 65 - src/core/transport/chttp2/varint.h | 75 - src/core/transport/chttp2/writing.c | 350 ---- src/core/transport/chttp2_transport.c | 1785 ------------------ src/core/transport/chttp2_transport.h | 51 - src/core/transport/connectivity_state.c | 164 -- src/core/transport/connectivity_state.h | 85 - src/core/transport/metadata.c | 698 ------- src/core/transport/metadata.h | 156 -- src/core/transport/metadata_batch.c | 194 -- src/core/transport/metadata_batch.h | 125 -- src/core/transport/static_metadata.c | 160 -- src/core/transport/static_metadata.h | 408 ---- src/core/transport/transport.c | 184 -- src/core/transport/transport.h | 242 --- src/core/transport/transport_impl.h | 81 - src/core/transport/transport_op_string.c | 140 -- src/core/tsi/fake_transport_security.c | 527 ------ src/core/tsi/fake_transport_security.h | 61 - src/core/tsi/ssl_transport_security.c | 1536 --------------- src/core/tsi/ssl_transport_security.h | 174 -- src/core/tsi/ssl_types.h | 55 - src/core/tsi/test_creds/README | 62 - src/core/tsi/test_creds/badclient.key | 16 - src/core/tsi/test_creds/badclient.pem | 17 - src/core/tsi/test_creds/badserver.key | 16 - src/core/tsi/test_creds/badserver.pem | 17 - src/core/tsi/test_creds/ca-openssl.cnf | 17 - src/core/tsi/test_creds/ca.key | 16 - src/core/tsi/test_creds/ca.pem | 15 - src/core/tsi/test_creds/client.key | 16 - src/core/tsi/test_creds/client.pem | 14 - src/core/tsi/test_creds/server0.key | 16 - src/core/tsi/test_creds/server0.pem | 14 - src/core/tsi/test_creds/server1-openssl.cnf | 26 - src/core/tsi/test_creds/server1.key | 16 - src/core/tsi/test_creds/server1.pem | 16 - src/core/tsi/transport_security.c | 284 --- src/core/tsi/transport_security.h | 111 -- src/core/tsi/transport_security_interface.h | 344 ---- src/python/grpcio/grpc_core_dependencies.py | 410 ++-- templates/src/core/lib/surface/version.c.template | 41 + templates/src/core/surface/version.c.template | 41 - tools/doxygen/Doxyfile.core.internal | 708 +++---- tools/run_tests/sources_and_headers.json | 1786 +++++++++--------- vsprojects/vcxproj/gpr/gpr.vcxproj | 112 +- vsprojects/vcxproj/gpr/gpr.vcxproj.filters | 235 +-- vsprojects/vcxproj/grpc/grpc.vcxproj | 596 +++--- vsprojects/vcxproj/grpc/grpc.vcxproj.filters | 1275 ++++++------- .../vcxproj/grpc_unsecure/grpc_unsecure.vcxproj | 528 +++--- .../grpc_unsecure/grpc_unsecure.vcxproj.filters | 1131 ++++++------ 792 files changed, 73079 insertions(+), 73070 deletions(-) delete mode 100644 src/core/census/README.md delete mode 100644 src/core/census/aggregation.h delete mode 100644 src/core/census/context.c delete mode 100644 src/core/census/grpc_context.c delete mode 100644 src/core/census/grpc_filter.c delete mode 100644 src/core/census/grpc_filter.h delete mode 100644 src/core/census/grpc_plugin.c delete mode 100644 src/core/census/grpc_plugin.h delete mode 100644 src/core/census/initialize.c delete mode 100644 src/core/census/mlog.c delete mode 100644 src/core/census/mlog.h delete mode 100644 src/core/census/operation.c delete mode 100644 src/core/census/placeholders.c delete mode 100644 src/core/census/rpc_metric_id.h delete mode 100644 src/core/census/tracing.c delete mode 100644 src/core/channel/channel_args.c delete mode 100644 src/core/channel/channel_args.h delete mode 100644 src/core/channel/channel_stack.c delete mode 100644 src/core/channel/channel_stack.h delete mode 100644 src/core/channel/channel_stack_builder.c delete mode 100644 src/core/channel/channel_stack_builder.h delete mode 100644 src/core/channel/client_channel.c delete mode 100644 src/core/channel/client_channel.h delete mode 100644 src/core/channel/compress_filter.c delete mode 100644 src/core/channel/compress_filter.h delete mode 100644 src/core/channel/connected_channel.c delete mode 100644 src/core/channel/connected_channel.h delete mode 100644 src/core/channel/context.h delete mode 100644 src/core/channel/http_client_filter.c delete mode 100644 src/core/channel/http_client_filter.h delete mode 100644 src/core/channel/http_server_filter.c delete mode 100644 src/core/channel/http_server_filter.h delete mode 100644 src/core/channel/subchannel_call_holder.c delete mode 100644 src/core/channel/subchannel_call_holder.h delete mode 100644 src/core/client_config/README.md delete mode 100644 src/core/client_config/client_config.c delete mode 100644 src/core/client_config/client_config.h delete mode 100644 src/core/client_config/connector.c delete mode 100644 src/core/client_config/connector.h delete mode 100644 src/core/client_config/default_initial_connect_string.c delete mode 100644 src/core/client_config/initial_connect_string.c delete mode 100644 src/core/client_config/initial_connect_string.h delete mode 100644 src/core/client_config/lb_policies/load_balancer_api.c delete mode 100644 src/core/client_config/lb_policies/load_balancer_api.h delete mode 100644 src/core/client_config/lb_policies/pick_first.c delete mode 100644 src/core/client_config/lb_policies/pick_first.h delete mode 100644 src/core/client_config/lb_policies/round_robin.c delete mode 100644 src/core/client_config/lb_policies/round_robin.h delete mode 100644 src/core/client_config/lb_policy.c delete mode 100644 src/core/client_config/lb_policy.h delete mode 100644 src/core/client_config/lb_policy_factory.c delete mode 100644 src/core/client_config/lb_policy_factory.h delete mode 100644 src/core/client_config/lb_policy_registry.c delete mode 100644 src/core/client_config/lb_policy_registry.h delete mode 100644 src/core/client_config/resolver.c delete mode 100644 src/core/client_config/resolver.h delete mode 100644 src/core/client_config/resolver_factory.c delete mode 100644 src/core/client_config/resolver_factory.h delete mode 100644 src/core/client_config/resolver_registry.c delete mode 100644 src/core/client_config/resolver_registry.h delete mode 100644 src/core/client_config/resolvers/dns_resolver.c delete mode 100644 src/core/client_config/resolvers/dns_resolver.h delete mode 100644 src/core/client_config/resolvers/sockaddr_resolver.c delete mode 100644 src/core/client_config/resolvers/sockaddr_resolver.h delete mode 100644 src/core/client_config/resolvers/zookeeper_resolver.c delete mode 100644 src/core/client_config/resolvers/zookeeper_resolver.h delete mode 100644 src/core/client_config/subchannel.c delete mode 100644 src/core/client_config/subchannel.h delete mode 100644 src/core/client_config/subchannel_factory.c delete mode 100644 src/core/client_config/subchannel_factory.h delete mode 100644 src/core/client_config/subchannel_index.c delete mode 100644 src/core/client_config/subchannel_index.h delete mode 100644 src/core/client_config/uri_parser.c delete mode 100644 src/core/client_config/uri_parser.h delete mode 100644 src/core/compression/algorithm_metadata.h delete mode 100644 src/core/compression/compression_algorithm.c delete mode 100644 src/core/compression/message_compress.c delete mode 100644 src/core/compression/message_compress.h delete mode 100644 src/core/debug/trace.c delete mode 100644 src/core/debug/trace.h delete mode 100644 src/core/http/format_request.c delete mode 100644 src/core/http/format_request.h delete mode 100644 src/core/http/httpcli.c delete mode 100644 src/core/http/httpcli.h delete mode 100644 src/core/http/httpcli_security_connector.c delete mode 100644 src/core/http/parser.c delete mode 100644 src/core/http/parser.h delete mode 100644 src/core/iomgr/closure.c delete mode 100644 src/core/iomgr/closure.h delete mode 100644 src/core/iomgr/endpoint.c delete mode 100644 src/core/iomgr/endpoint.h delete mode 100644 src/core/iomgr/endpoint_pair.h delete mode 100644 src/core/iomgr/endpoint_pair_posix.c delete mode 100644 src/core/iomgr/endpoint_pair_windows.c delete mode 100644 src/core/iomgr/exec_ctx.c delete mode 100644 src/core/iomgr/exec_ctx.h delete mode 100644 src/core/iomgr/executor.c delete mode 100644 src/core/iomgr/executor.h delete mode 100644 src/core/iomgr/fd_posix.c delete mode 100644 src/core/iomgr/fd_posix.h delete mode 100644 src/core/iomgr/iocp_windows.c delete mode 100644 src/core/iomgr/iocp_windows.h delete mode 100644 src/core/iomgr/iomgr.c delete mode 100644 src/core/iomgr/iomgr.h delete mode 100644 src/core/iomgr/iomgr_internal.h delete mode 100644 src/core/iomgr/iomgr_posix.c delete mode 100644 src/core/iomgr/iomgr_posix.h delete mode 100644 src/core/iomgr/iomgr_windows.c delete mode 100644 src/core/iomgr/pollset.h delete mode 100644 src/core/iomgr/pollset_multipoller_with_epoll.c delete mode 100644 src/core/iomgr/pollset_multipoller_with_poll_posix.c delete mode 100644 src/core/iomgr/pollset_posix.c delete mode 100644 src/core/iomgr/pollset_posix.h delete mode 100644 src/core/iomgr/pollset_set.h delete mode 100644 src/core/iomgr/pollset_set_posix.c delete mode 100644 src/core/iomgr/pollset_set_posix.h delete mode 100644 src/core/iomgr/pollset_set_windows.c delete mode 100644 src/core/iomgr/pollset_set_windows.h delete mode 100644 src/core/iomgr/pollset_windows.c delete mode 100644 src/core/iomgr/pollset_windows.h delete mode 100644 src/core/iomgr/resolve_address.h delete mode 100644 src/core/iomgr/resolve_address_posix.c delete mode 100644 src/core/iomgr/resolve_address_windows.c delete mode 100644 src/core/iomgr/sockaddr.h delete mode 100644 src/core/iomgr/sockaddr_posix.h delete mode 100644 src/core/iomgr/sockaddr_utils.c delete mode 100644 src/core/iomgr/sockaddr_utils.h delete mode 100644 src/core/iomgr/sockaddr_win32.h delete mode 100644 src/core/iomgr/socket_utils_common_posix.c delete mode 100644 src/core/iomgr/socket_utils_linux.c delete mode 100644 src/core/iomgr/socket_utils_posix.c delete mode 100644 src/core/iomgr/socket_utils_posix.h delete mode 100644 src/core/iomgr/socket_windows.c delete mode 100644 src/core/iomgr/socket_windows.h delete mode 100644 src/core/iomgr/tcp_client.h delete mode 100644 src/core/iomgr/tcp_client_posix.c delete mode 100644 src/core/iomgr/tcp_client_windows.c delete mode 100644 src/core/iomgr/tcp_posix.c delete mode 100644 src/core/iomgr/tcp_posix.h delete mode 100644 src/core/iomgr/tcp_server.h delete mode 100644 src/core/iomgr/tcp_server_posix.c delete mode 100644 src/core/iomgr/tcp_server_windows.c delete mode 100644 src/core/iomgr/tcp_windows.c delete mode 100644 src/core/iomgr/tcp_windows.h delete mode 100644 src/core/iomgr/time_averaged_stats.c delete mode 100644 src/core/iomgr/time_averaged_stats.h delete mode 100644 src/core/iomgr/timer.c delete mode 100644 src/core/iomgr/timer.h delete mode 100644 src/core/iomgr/timer_heap.c delete mode 100644 src/core/iomgr/timer_heap.h delete mode 100644 src/core/iomgr/udp_server.c delete mode 100644 src/core/iomgr/udp_server.h delete mode 100644 src/core/iomgr/unix_sockets_posix.c delete mode 100644 src/core/iomgr/unix_sockets_posix.h delete mode 100644 src/core/iomgr/unix_sockets_posix_noop.c delete mode 100644 src/core/iomgr/wakeup_fd_eventfd.c delete mode 100644 src/core/iomgr/wakeup_fd_nospecial.c delete mode 100644 src/core/iomgr/wakeup_fd_pipe.c delete mode 100644 src/core/iomgr/wakeup_fd_pipe.h delete mode 100644 src/core/iomgr/wakeup_fd_posix.c delete mode 100644 src/core/iomgr/wakeup_fd_posix.h delete mode 100644 src/core/iomgr/workqueue.h delete mode 100644 src/core/iomgr/workqueue_posix.c delete mode 100644 src/core/iomgr/workqueue_posix.h delete mode 100644 src/core/iomgr/workqueue_windows.c delete mode 100644 src/core/iomgr/workqueue_windows.h delete mode 100644 src/core/json/json.c delete mode 100644 src/core/json/json.h delete mode 100644 src/core/json/json_common.h delete mode 100644 src/core/json/json_reader.c delete mode 100644 src/core/json/json_reader.h delete mode 100644 src/core/json/json_string.c delete mode 100644 src/core/json/json_writer.c delete mode 100644 src/core/json/json_writer.h create mode 100644 src/core/lib/census/README.md create mode 100644 src/core/lib/census/aggregation.h create mode 100644 src/core/lib/census/context.c create mode 100644 src/core/lib/census/grpc_context.c create mode 100644 src/core/lib/census/grpc_filter.c create mode 100644 src/core/lib/census/grpc_filter.h create mode 100644 src/core/lib/census/grpc_plugin.c create mode 100644 src/core/lib/census/grpc_plugin.h create mode 100644 src/core/lib/census/initialize.c create mode 100644 src/core/lib/census/mlog.c create mode 100644 src/core/lib/census/mlog.h create mode 100644 src/core/lib/census/operation.c create mode 100644 src/core/lib/census/placeholders.c create mode 100644 src/core/lib/census/rpc_metric_id.h create mode 100644 src/core/lib/census/tracing.c create mode 100644 src/core/lib/channel/channel_args.c create mode 100644 src/core/lib/channel/channel_args.h create mode 100644 src/core/lib/channel/channel_stack.c create mode 100644 src/core/lib/channel/channel_stack.h create mode 100644 src/core/lib/channel/channel_stack_builder.c create mode 100644 src/core/lib/channel/channel_stack_builder.h create mode 100644 src/core/lib/channel/client_channel.c create mode 100644 src/core/lib/channel/client_channel.h create mode 100644 src/core/lib/channel/compress_filter.c create mode 100644 src/core/lib/channel/compress_filter.h create mode 100644 src/core/lib/channel/connected_channel.c create mode 100644 src/core/lib/channel/connected_channel.h create mode 100644 src/core/lib/channel/context.h create mode 100644 src/core/lib/channel/http_client_filter.c create mode 100644 src/core/lib/channel/http_client_filter.h create mode 100644 src/core/lib/channel/http_server_filter.c create mode 100644 src/core/lib/channel/http_server_filter.h create mode 100644 src/core/lib/channel/subchannel_call_holder.c create mode 100644 src/core/lib/channel/subchannel_call_holder.h create mode 100644 src/core/lib/client_config/README.md create mode 100644 src/core/lib/client_config/client_config.c create mode 100644 src/core/lib/client_config/client_config.h create mode 100644 src/core/lib/client_config/connector.c create mode 100644 src/core/lib/client_config/connector.h create mode 100644 src/core/lib/client_config/default_initial_connect_string.c create mode 100644 src/core/lib/client_config/initial_connect_string.c create mode 100644 src/core/lib/client_config/initial_connect_string.h create mode 100644 src/core/lib/client_config/lb_policies/load_balancer_api.c create mode 100644 src/core/lib/client_config/lb_policies/load_balancer_api.h create mode 100644 src/core/lib/client_config/lb_policies/pick_first.c create mode 100644 src/core/lib/client_config/lb_policies/pick_first.h create mode 100644 src/core/lib/client_config/lb_policies/round_robin.c create mode 100644 src/core/lib/client_config/lb_policies/round_robin.h create mode 100644 src/core/lib/client_config/lb_policy.c create mode 100644 src/core/lib/client_config/lb_policy.h create mode 100644 src/core/lib/client_config/lb_policy_factory.c create mode 100644 src/core/lib/client_config/lb_policy_factory.h create mode 100644 src/core/lib/client_config/lb_policy_registry.c create mode 100644 src/core/lib/client_config/lb_policy_registry.h create mode 100644 src/core/lib/client_config/resolver.c create mode 100644 src/core/lib/client_config/resolver.h create mode 100644 src/core/lib/client_config/resolver_factory.c create mode 100644 src/core/lib/client_config/resolver_factory.h create mode 100644 src/core/lib/client_config/resolver_registry.c create mode 100644 src/core/lib/client_config/resolver_registry.h create mode 100644 src/core/lib/client_config/resolvers/dns_resolver.c create mode 100644 src/core/lib/client_config/resolvers/dns_resolver.h create mode 100644 src/core/lib/client_config/resolvers/sockaddr_resolver.c create mode 100644 src/core/lib/client_config/resolvers/sockaddr_resolver.h create mode 100644 src/core/lib/client_config/resolvers/zookeeper_resolver.c create mode 100644 src/core/lib/client_config/resolvers/zookeeper_resolver.h create mode 100644 src/core/lib/client_config/subchannel.c create mode 100644 src/core/lib/client_config/subchannel.h create mode 100644 src/core/lib/client_config/subchannel_factory.c create mode 100644 src/core/lib/client_config/subchannel_factory.h create mode 100644 src/core/lib/client_config/subchannel_index.c create mode 100644 src/core/lib/client_config/subchannel_index.h create mode 100644 src/core/lib/client_config/uri_parser.c create mode 100644 src/core/lib/client_config/uri_parser.h create mode 100644 src/core/lib/compression/algorithm_metadata.h create mode 100644 src/core/lib/compression/compression_algorithm.c create mode 100644 src/core/lib/compression/message_compress.c create mode 100644 src/core/lib/compression/message_compress.h create mode 100644 src/core/lib/debug/trace.c create mode 100644 src/core/lib/debug/trace.h create mode 100644 src/core/lib/http/format_request.c create mode 100644 src/core/lib/http/format_request.h create mode 100644 src/core/lib/http/httpcli.c create mode 100644 src/core/lib/http/httpcli.h create mode 100644 src/core/lib/http/httpcli_security_connector.c create mode 100644 src/core/lib/http/parser.c create mode 100644 src/core/lib/http/parser.h create mode 100644 src/core/lib/iomgr/closure.c create mode 100644 src/core/lib/iomgr/closure.h create mode 100644 src/core/lib/iomgr/endpoint.c create mode 100644 src/core/lib/iomgr/endpoint.h create mode 100644 src/core/lib/iomgr/endpoint_pair.h create mode 100644 src/core/lib/iomgr/endpoint_pair_posix.c create mode 100644 src/core/lib/iomgr/endpoint_pair_windows.c create mode 100644 src/core/lib/iomgr/exec_ctx.c create mode 100644 src/core/lib/iomgr/exec_ctx.h create mode 100644 src/core/lib/iomgr/executor.c create mode 100644 src/core/lib/iomgr/executor.h create mode 100644 src/core/lib/iomgr/fd_posix.c create mode 100644 src/core/lib/iomgr/fd_posix.h create mode 100644 src/core/lib/iomgr/iocp_windows.c create mode 100644 src/core/lib/iomgr/iocp_windows.h create mode 100644 src/core/lib/iomgr/iomgr.c create mode 100644 src/core/lib/iomgr/iomgr.h create mode 100644 src/core/lib/iomgr/iomgr_internal.h create mode 100644 src/core/lib/iomgr/iomgr_posix.c create mode 100644 src/core/lib/iomgr/iomgr_posix.h create mode 100644 src/core/lib/iomgr/iomgr_windows.c create mode 100644 src/core/lib/iomgr/pollset.h create mode 100644 src/core/lib/iomgr/pollset_multipoller_with_epoll.c create mode 100644 src/core/lib/iomgr/pollset_multipoller_with_poll_posix.c create mode 100644 src/core/lib/iomgr/pollset_posix.c create mode 100644 src/core/lib/iomgr/pollset_posix.h create mode 100644 src/core/lib/iomgr/pollset_set.h create mode 100644 src/core/lib/iomgr/pollset_set_posix.c create mode 100644 src/core/lib/iomgr/pollset_set_posix.h create mode 100644 src/core/lib/iomgr/pollset_set_windows.c create mode 100644 src/core/lib/iomgr/pollset_set_windows.h create mode 100644 src/core/lib/iomgr/pollset_windows.c create mode 100644 src/core/lib/iomgr/pollset_windows.h create mode 100644 src/core/lib/iomgr/resolve_address.h create mode 100644 src/core/lib/iomgr/resolve_address_posix.c create mode 100644 src/core/lib/iomgr/resolve_address_windows.c create mode 100644 src/core/lib/iomgr/sockaddr.h create mode 100644 src/core/lib/iomgr/sockaddr_posix.h create mode 100644 src/core/lib/iomgr/sockaddr_utils.c create mode 100644 src/core/lib/iomgr/sockaddr_utils.h create mode 100644 src/core/lib/iomgr/sockaddr_win32.h create mode 100644 src/core/lib/iomgr/socket_utils_common_posix.c create mode 100644 src/core/lib/iomgr/socket_utils_linux.c create mode 100644 src/core/lib/iomgr/socket_utils_posix.c create mode 100644 src/core/lib/iomgr/socket_utils_posix.h create mode 100644 src/core/lib/iomgr/socket_windows.c create mode 100644 src/core/lib/iomgr/socket_windows.h create mode 100644 src/core/lib/iomgr/tcp_client.h create mode 100644 src/core/lib/iomgr/tcp_client_posix.c create mode 100644 src/core/lib/iomgr/tcp_client_windows.c create mode 100644 src/core/lib/iomgr/tcp_posix.c create mode 100644 src/core/lib/iomgr/tcp_posix.h create mode 100644 src/core/lib/iomgr/tcp_server.h create mode 100644 src/core/lib/iomgr/tcp_server_posix.c create mode 100644 src/core/lib/iomgr/tcp_server_windows.c create mode 100644 src/core/lib/iomgr/tcp_windows.c create mode 100644 src/core/lib/iomgr/tcp_windows.h create mode 100644 src/core/lib/iomgr/time_averaged_stats.c create mode 100644 src/core/lib/iomgr/time_averaged_stats.h create mode 100644 src/core/lib/iomgr/timer.c create mode 100644 src/core/lib/iomgr/timer.h create mode 100644 src/core/lib/iomgr/timer_heap.c create mode 100644 src/core/lib/iomgr/timer_heap.h create mode 100644 src/core/lib/iomgr/udp_server.c create mode 100644 src/core/lib/iomgr/udp_server.h create mode 100644 src/core/lib/iomgr/unix_sockets_posix.c create mode 100644 src/core/lib/iomgr/unix_sockets_posix.h create mode 100644 src/core/lib/iomgr/unix_sockets_posix_noop.c create mode 100644 src/core/lib/iomgr/wakeup_fd_eventfd.c create mode 100644 src/core/lib/iomgr/wakeup_fd_nospecial.c create mode 100644 src/core/lib/iomgr/wakeup_fd_pipe.c create mode 100644 src/core/lib/iomgr/wakeup_fd_pipe.h create mode 100644 src/core/lib/iomgr/wakeup_fd_posix.c create mode 100644 src/core/lib/iomgr/wakeup_fd_posix.h create mode 100644 src/core/lib/iomgr/workqueue.h create mode 100644 src/core/lib/iomgr/workqueue_posix.c create mode 100644 src/core/lib/iomgr/workqueue_posix.h create mode 100644 src/core/lib/iomgr/workqueue_windows.c create mode 100644 src/core/lib/iomgr/workqueue_windows.h create mode 100644 src/core/lib/json/json.c create mode 100644 src/core/lib/json/json.h create mode 100644 src/core/lib/json/json_common.h create mode 100644 src/core/lib/json/json_reader.c create mode 100644 src/core/lib/json/json_reader.h create mode 100644 src/core/lib/json/json_string.c create mode 100644 src/core/lib/json/json_writer.c create mode 100644 src/core/lib/json/json_writer.h create mode 100644 src/core/lib/profiling/basic_timers.c create mode 100644 src/core/lib/profiling/stap_probes.d create mode 100644 src/core/lib/profiling/stap_timers.c create mode 100644 src/core/lib/profiling/timers.h create mode 100644 src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c create mode 100644 src/core/lib/proto/grpc/lb/v0/load_balancer.pb.h create mode 100644 src/core/lib/security/auth_filters.h create mode 100644 src/core/lib/security/b64.c create mode 100644 src/core/lib/security/b64.h create mode 100644 src/core/lib/security/client_auth_filter.c create mode 100644 src/core/lib/security/credentials.c create mode 100644 src/core/lib/security/credentials.h create mode 100644 src/core/lib/security/credentials_metadata.c create mode 100644 src/core/lib/security/credentials_posix.c create mode 100644 src/core/lib/security/credentials_win32.c create mode 100644 src/core/lib/security/google_default_credentials.c create mode 100644 src/core/lib/security/handshake.c create mode 100644 src/core/lib/security/handshake.h create mode 100644 src/core/lib/security/json_token.c create mode 100644 src/core/lib/security/json_token.h create mode 100644 src/core/lib/security/jwt_verifier.c create mode 100644 src/core/lib/security/jwt_verifier.h create mode 100644 src/core/lib/security/secure_endpoint.c create mode 100644 src/core/lib/security/secure_endpoint.h create mode 100644 src/core/lib/security/security_connector.c create mode 100644 src/core/lib/security/security_connector.h create mode 100644 src/core/lib/security/security_context.c create mode 100644 src/core/lib/security/security_context.h create mode 100644 src/core/lib/security/server_auth_filter.c create mode 100644 src/core/lib/security/server_secure_chttp2.c create mode 100644 src/core/lib/statistics/census_init.c create mode 100644 src/core/lib/statistics/census_interface.h create mode 100644 src/core/lib/statistics/census_log.c create mode 100644 src/core/lib/statistics/census_log.h create mode 100644 src/core/lib/statistics/census_rpc_stats.c create mode 100644 src/core/lib/statistics/census_rpc_stats.h create mode 100644 src/core/lib/statistics/census_tracing.c create mode 100644 src/core/lib/statistics/census_tracing.h create mode 100644 src/core/lib/statistics/hash_table.c create mode 100644 src/core/lib/statistics/hash_table.h create mode 100644 src/core/lib/statistics/window_stats.c create mode 100644 src/core/lib/statistics/window_stats.h create mode 100644 src/core/lib/support/alloc.c create mode 100644 src/core/lib/support/avl.c create mode 100644 src/core/lib/support/backoff.c create mode 100644 src/core/lib/support/backoff.h create mode 100644 src/core/lib/support/block_annotate.h create mode 100644 src/core/lib/support/cmdline.c create mode 100644 src/core/lib/support/cpu_iphone.c create mode 100644 src/core/lib/support/cpu_linux.c create mode 100644 src/core/lib/support/cpu_posix.c create mode 100644 src/core/lib/support/cpu_windows.c create mode 100644 src/core/lib/support/env.h create mode 100644 src/core/lib/support/env_linux.c create mode 100644 src/core/lib/support/env_posix.c create mode 100644 src/core/lib/support/env_win32.c create mode 100644 src/core/lib/support/histogram.c create mode 100644 src/core/lib/support/host_port.c create mode 100644 src/core/lib/support/load_file.c create mode 100644 src/core/lib/support/load_file.h create mode 100644 src/core/lib/support/log.c create mode 100644 src/core/lib/support/log_android.c create mode 100644 src/core/lib/support/log_linux.c create mode 100644 src/core/lib/support/log_posix.c create mode 100644 src/core/lib/support/log_win32.c create mode 100644 src/core/lib/support/murmur_hash.c create mode 100644 src/core/lib/support/murmur_hash.h create mode 100644 src/core/lib/support/slice.c create mode 100644 src/core/lib/support/slice_buffer.c create mode 100644 src/core/lib/support/stack_lockfree.c create mode 100644 src/core/lib/support/stack_lockfree.h create mode 100644 src/core/lib/support/string.c create mode 100644 src/core/lib/support/string.h create mode 100644 src/core/lib/support/string_posix.c create mode 100644 src/core/lib/support/string_win32.c create mode 100644 src/core/lib/support/string_win32.h create mode 100644 src/core/lib/support/subprocess_posix.c create mode 100644 src/core/lib/support/subprocess_windows.c create mode 100644 src/core/lib/support/sync.c create mode 100644 src/core/lib/support/sync_posix.c create mode 100644 src/core/lib/support/sync_win32.c create mode 100644 src/core/lib/support/thd.c create mode 100644 src/core/lib/support/thd_internal.h create mode 100644 src/core/lib/support/thd_posix.c create mode 100644 src/core/lib/support/thd_win32.c create mode 100644 src/core/lib/support/time.c create mode 100644 src/core/lib/support/time_posix.c create mode 100644 src/core/lib/support/time_precise.c create mode 100644 src/core/lib/support/time_precise.h create mode 100644 src/core/lib/support/time_win32.c create mode 100644 src/core/lib/support/tls_pthread.c create mode 100644 src/core/lib/support/tmpfile.h create mode 100644 src/core/lib/support/tmpfile_posix.c create mode 100644 src/core/lib/support/tmpfile_win32.c create mode 100644 src/core/lib/support/wrap_memcpy.c create mode 100644 src/core/lib/surface/alarm.c create mode 100644 src/core/lib/surface/api_trace.c create mode 100644 src/core/lib/surface/api_trace.h create mode 100644 src/core/lib/surface/byte_buffer.c create mode 100644 src/core/lib/surface/byte_buffer_reader.c create mode 100644 src/core/lib/surface/call.c create mode 100644 src/core/lib/surface/call.h create mode 100644 src/core/lib/surface/call_details.c create mode 100644 src/core/lib/surface/call_log_batch.c create mode 100644 src/core/lib/surface/call_test_only.h create mode 100644 src/core/lib/surface/channel.c create mode 100644 src/core/lib/surface/channel.h create mode 100644 src/core/lib/surface/channel_connectivity.c create mode 100644 src/core/lib/surface/channel_create.c create mode 100644 src/core/lib/surface/channel_init.c create mode 100644 src/core/lib/surface/channel_init.h create mode 100644 src/core/lib/surface/channel_ping.c create mode 100644 src/core/lib/surface/channel_stack_type.c create mode 100644 src/core/lib/surface/channel_stack_type.h create mode 100644 src/core/lib/surface/completion_queue.c create mode 100644 src/core/lib/surface/completion_queue.h create mode 100644 src/core/lib/surface/event_string.c create mode 100644 src/core/lib/surface/event_string.h create mode 100644 src/core/lib/surface/init.c create mode 100644 src/core/lib/surface/init.h create mode 100644 src/core/lib/surface/init_secure.c create mode 100644 src/core/lib/surface/init_unsecure.c create mode 100644 src/core/lib/surface/lame_client.c create mode 100644 src/core/lib/surface/lame_client.h create mode 100644 src/core/lib/surface/metadata_array.c create mode 100644 src/core/lib/surface/secure_channel_create.c create mode 100644 src/core/lib/surface/server.c create mode 100644 src/core/lib/surface/server.h create mode 100644 src/core/lib/surface/server_chttp2.c create mode 100644 src/core/lib/surface/surface_trace.h create mode 100644 src/core/lib/surface/validate_metadata.c create mode 100644 src/core/lib/surface/version.c create mode 100644 src/core/lib/transport/byte_stream.c create mode 100644 src/core/lib/transport/byte_stream.h create mode 100644 src/core/lib/transport/chttp2/alpn.c create mode 100644 src/core/lib/transport/chttp2/alpn.h create mode 100644 src/core/lib/transport/chttp2/bin_encoder.c create mode 100644 src/core/lib/transport/chttp2/bin_encoder.h create mode 100644 src/core/lib/transport/chttp2/frame.h create mode 100644 src/core/lib/transport/chttp2/frame_data.c create mode 100644 src/core/lib/transport/chttp2/frame_data.h create mode 100644 src/core/lib/transport/chttp2/frame_goaway.c create mode 100644 src/core/lib/transport/chttp2/frame_goaway.h create mode 100644 src/core/lib/transport/chttp2/frame_ping.c create mode 100644 src/core/lib/transport/chttp2/frame_ping.h create mode 100644 src/core/lib/transport/chttp2/frame_rst_stream.c create mode 100644 src/core/lib/transport/chttp2/frame_rst_stream.h create mode 100644 src/core/lib/transport/chttp2/frame_settings.c create mode 100644 src/core/lib/transport/chttp2/frame_settings.h create mode 100644 src/core/lib/transport/chttp2/frame_window_update.c create mode 100644 src/core/lib/transport/chttp2/frame_window_update.h create mode 100644 src/core/lib/transport/chttp2/hpack_encoder.c create mode 100644 src/core/lib/transport/chttp2/hpack_encoder.h create mode 100644 src/core/lib/transport/chttp2/hpack_parser.c create mode 100644 src/core/lib/transport/chttp2/hpack_parser.h create mode 100644 src/core/lib/transport/chttp2/hpack_table.c create mode 100644 src/core/lib/transport/chttp2/hpack_table.h create mode 100644 src/core/lib/transport/chttp2/hpack_tables.txt create mode 100644 src/core/lib/transport/chttp2/http2_errors.h create mode 100644 src/core/lib/transport/chttp2/huffsyms.c create mode 100644 src/core/lib/transport/chttp2/huffsyms.h create mode 100644 src/core/lib/transport/chttp2/incoming_metadata.c create mode 100644 src/core/lib/transport/chttp2/incoming_metadata.h create mode 100644 src/core/lib/transport/chttp2/internal.h create mode 100644 src/core/lib/transport/chttp2/parsing.c create mode 100644 src/core/lib/transport/chttp2/status_conversion.c create mode 100644 src/core/lib/transport/chttp2/status_conversion.h create mode 100644 src/core/lib/transport/chttp2/stream_lists.c create mode 100644 src/core/lib/transport/chttp2/stream_map.c create mode 100644 src/core/lib/transport/chttp2/stream_map.h create mode 100644 src/core/lib/transport/chttp2/timeout_encoding.c create mode 100644 src/core/lib/transport/chttp2/timeout_encoding.h create mode 100644 src/core/lib/transport/chttp2/varint.c create mode 100644 src/core/lib/transport/chttp2/varint.h create mode 100644 src/core/lib/transport/chttp2/writing.c create mode 100644 src/core/lib/transport/chttp2_transport.c create mode 100644 src/core/lib/transport/chttp2_transport.h create mode 100644 src/core/lib/transport/connectivity_state.c create mode 100644 src/core/lib/transport/connectivity_state.h create mode 100644 src/core/lib/transport/metadata.c create mode 100644 src/core/lib/transport/metadata.h create mode 100644 src/core/lib/transport/metadata_batch.c create mode 100644 src/core/lib/transport/metadata_batch.h create mode 100644 src/core/lib/transport/static_metadata.c create mode 100644 src/core/lib/transport/static_metadata.h create mode 100644 src/core/lib/transport/transport.c create mode 100644 src/core/lib/transport/transport.h create mode 100644 src/core/lib/transport/transport_impl.h create mode 100644 src/core/lib/transport/transport_op_string.c create mode 100644 src/core/lib/tsi/fake_transport_security.c create mode 100644 src/core/lib/tsi/fake_transport_security.h create mode 100644 src/core/lib/tsi/ssl_transport_security.c create mode 100644 src/core/lib/tsi/ssl_transport_security.h create mode 100644 src/core/lib/tsi/ssl_types.h create mode 100644 src/core/lib/tsi/test_creds/README create mode 100644 src/core/lib/tsi/test_creds/badclient.key create mode 100644 src/core/lib/tsi/test_creds/badclient.pem create mode 100644 src/core/lib/tsi/test_creds/badserver.key create mode 100644 src/core/lib/tsi/test_creds/badserver.pem create mode 100644 src/core/lib/tsi/test_creds/ca-openssl.cnf create mode 100644 src/core/lib/tsi/test_creds/ca.key create mode 100644 src/core/lib/tsi/test_creds/ca.pem create mode 100644 src/core/lib/tsi/test_creds/client.key create mode 100644 src/core/lib/tsi/test_creds/client.pem create mode 100644 src/core/lib/tsi/test_creds/server0.key create mode 100644 src/core/lib/tsi/test_creds/server0.pem create mode 100644 src/core/lib/tsi/test_creds/server1-openssl.cnf create mode 100644 src/core/lib/tsi/test_creds/server1.key create mode 100644 src/core/lib/tsi/test_creds/server1.pem create mode 100644 src/core/lib/tsi/transport_security.c create mode 100644 src/core/lib/tsi/transport_security.h create mode 100644 src/core/lib/tsi/transport_security_interface.h delete mode 100644 src/core/profiling/basic_timers.c delete mode 100644 src/core/profiling/stap_probes.d delete mode 100644 src/core/profiling/stap_timers.c delete mode 100644 src/core/profiling/timers.h delete mode 100644 src/core/proto/grpc/lb/v0/load_balancer.pb.c delete mode 100644 src/core/proto/grpc/lb/v0/load_balancer.pb.h delete mode 100644 src/core/security/auth_filters.h delete mode 100644 src/core/security/b64.c delete mode 100644 src/core/security/b64.h delete mode 100644 src/core/security/client_auth_filter.c delete mode 100644 src/core/security/credentials.c delete mode 100644 src/core/security/credentials.h delete mode 100644 src/core/security/credentials_metadata.c delete mode 100644 src/core/security/credentials_posix.c delete mode 100644 src/core/security/credentials_win32.c delete mode 100644 src/core/security/google_default_credentials.c delete mode 100644 src/core/security/handshake.c delete mode 100644 src/core/security/handshake.h delete mode 100644 src/core/security/json_token.c delete mode 100644 src/core/security/json_token.h delete mode 100644 src/core/security/jwt_verifier.c delete mode 100644 src/core/security/jwt_verifier.h delete mode 100644 src/core/security/secure_endpoint.c delete mode 100644 src/core/security/secure_endpoint.h delete mode 100644 src/core/security/security_connector.c delete mode 100644 src/core/security/security_connector.h delete mode 100644 src/core/security/security_context.c delete mode 100644 src/core/security/security_context.h delete mode 100644 src/core/security/server_auth_filter.c delete mode 100644 src/core/security/server_secure_chttp2.c delete mode 100644 src/core/statistics/census_init.c delete mode 100644 src/core/statistics/census_interface.h delete mode 100644 src/core/statistics/census_log.c delete mode 100644 src/core/statistics/census_log.h delete mode 100644 src/core/statistics/census_rpc_stats.c delete mode 100644 src/core/statistics/census_rpc_stats.h delete mode 100644 src/core/statistics/census_tracing.c delete mode 100644 src/core/statistics/census_tracing.h delete mode 100644 src/core/statistics/hash_table.c delete mode 100644 src/core/statistics/hash_table.h delete mode 100644 src/core/statistics/window_stats.c delete mode 100644 src/core/statistics/window_stats.h delete mode 100644 src/core/support/alloc.c delete mode 100644 src/core/support/avl.c delete mode 100644 src/core/support/backoff.c delete mode 100644 src/core/support/backoff.h delete mode 100644 src/core/support/block_annotate.h delete mode 100644 src/core/support/cmdline.c delete mode 100644 src/core/support/cpu_iphone.c delete mode 100644 src/core/support/cpu_linux.c delete mode 100644 src/core/support/cpu_posix.c delete mode 100644 src/core/support/cpu_windows.c delete mode 100644 src/core/support/env.h delete mode 100644 src/core/support/env_linux.c delete mode 100644 src/core/support/env_posix.c delete mode 100644 src/core/support/env_win32.c delete mode 100644 src/core/support/histogram.c delete mode 100644 src/core/support/host_port.c delete mode 100644 src/core/support/load_file.c delete mode 100644 src/core/support/load_file.h delete mode 100644 src/core/support/log.c delete mode 100644 src/core/support/log_android.c delete mode 100644 src/core/support/log_linux.c delete mode 100644 src/core/support/log_posix.c delete mode 100644 src/core/support/log_win32.c delete mode 100644 src/core/support/murmur_hash.c delete mode 100644 src/core/support/murmur_hash.h delete mode 100644 src/core/support/slice.c delete mode 100644 src/core/support/slice_buffer.c delete mode 100644 src/core/support/stack_lockfree.c delete mode 100644 src/core/support/stack_lockfree.h delete mode 100644 src/core/support/string.c delete mode 100644 src/core/support/string.h delete mode 100644 src/core/support/string_posix.c delete mode 100644 src/core/support/string_win32.c delete mode 100644 src/core/support/string_win32.h delete mode 100644 src/core/support/subprocess_posix.c delete mode 100644 src/core/support/subprocess_windows.c delete mode 100644 src/core/support/sync.c delete mode 100644 src/core/support/sync_posix.c delete mode 100644 src/core/support/sync_win32.c delete mode 100644 src/core/support/thd.c delete mode 100644 src/core/support/thd_internal.h delete mode 100644 src/core/support/thd_posix.c delete mode 100644 src/core/support/thd_win32.c delete mode 100644 src/core/support/time.c delete mode 100644 src/core/support/time_posix.c delete mode 100644 src/core/support/time_precise.c delete mode 100644 src/core/support/time_precise.h delete mode 100644 src/core/support/time_win32.c delete mode 100644 src/core/support/tls_pthread.c delete mode 100644 src/core/support/tmpfile.h delete mode 100644 src/core/support/tmpfile_posix.c delete mode 100644 src/core/support/tmpfile_win32.c delete mode 100644 src/core/support/wrap_memcpy.c delete mode 100644 src/core/surface/alarm.c delete mode 100644 src/core/surface/api_trace.c delete mode 100644 src/core/surface/api_trace.h delete mode 100644 src/core/surface/byte_buffer.c delete mode 100644 src/core/surface/byte_buffer_reader.c delete mode 100644 src/core/surface/call.c delete mode 100644 src/core/surface/call.h delete mode 100644 src/core/surface/call_details.c delete mode 100644 src/core/surface/call_log_batch.c delete mode 100644 src/core/surface/call_test_only.h delete mode 100644 src/core/surface/channel.c delete mode 100644 src/core/surface/channel.h delete mode 100644 src/core/surface/channel_connectivity.c delete mode 100644 src/core/surface/channel_create.c delete mode 100644 src/core/surface/channel_init.c delete mode 100644 src/core/surface/channel_init.h delete mode 100644 src/core/surface/channel_ping.c delete mode 100644 src/core/surface/channel_stack_type.c delete mode 100644 src/core/surface/channel_stack_type.h delete mode 100644 src/core/surface/completion_queue.c delete mode 100644 src/core/surface/completion_queue.h delete mode 100644 src/core/surface/event_string.c delete mode 100644 src/core/surface/event_string.h delete mode 100644 src/core/surface/init.c delete mode 100644 src/core/surface/init.h delete mode 100644 src/core/surface/init_secure.c delete mode 100644 src/core/surface/init_unsecure.c delete mode 100644 src/core/surface/lame_client.c delete mode 100644 src/core/surface/lame_client.h delete mode 100644 src/core/surface/metadata_array.c delete mode 100644 src/core/surface/secure_channel_create.c delete mode 100644 src/core/surface/server.c delete mode 100644 src/core/surface/server.h delete mode 100644 src/core/surface/server_chttp2.c delete mode 100644 src/core/surface/surface_trace.h delete mode 100644 src/core/surface/validate_metadata.c delete mode 100644 src/core/surface/version.c delete mode 100644 src/core/transport/byte_stream.c delete mode 100644 src/core/transport/byte_stream.h delete mode 100644 src/core/transport/chttp2/alpn.c delete mode 100644 src/core/transport/chttp2/alpn.h delete mode 100644 src/core/transport/chttp2/bin_encoder.c delete mode 100644 src/core/transport/chttp2/bin_encoder.h delete mode 100644 src/core/transport/chttp2/frame.h delete mode 100644 src/core/transport/chttp2/frame_data.c delete mode 100644 src/core/transport/chttp2/frame_data.h delete mode 100644 src/core/transport/chttp2/frame_goaway.c delete mode 100644 src/core/transport/chttp2/frame_goaway.h delete mode 100644 src/core/transport/chttp2/frame_ping.c delete mode 100644 src/core/transport/chttp2/frame_ping.h delete mode 100644 src/core/transport/chttp2/frame_rst_stream.c delete mode 100644 src/core/transport/chttp2/frame_rst_stream.h delete mode 100644 src/core/transport/chttp2/frame_settings.c delete mode 100644 src/core/transport/chttp2/frame_settings.h delete mode 100644 src/core/transport/chttp2/frame_window_update.c delete mode 100644 src/core/transport/chttp2/frame_window_update.h delete mode 100644 src/core/transport/chttp2/hpack_encoder.c delete mode 100644 src/core/transport/chttp2/hpack_encoder.h delete mode 100644 src/core/transport/chttp2/hpack_parser.c delete mode 100644 src/core/transport/chttp2/hpack_parser.h delete mode 100644 src/core/transport/chttp2/hpack_table.c delete mode 100644 src/core/transport/chttp2/hpack_table.h delete mode 100644 src/core/transport/chttp2/hpack_tables.txt delete mode 100644 src/core/transport/chttp2/http2_errors.h delete mode 100644 src/core/transport/chttp2/huffsyms.c delete mode 100644 src/core/transport/chttp2/huffsyms.h delete mode 100644 src/core/transport/chttp2/incoming_metadata.c delete mode 100644 src/core/transport/chttp2/incoming_metadata.h delete mode 100644 src/core/transport/chttp2/internal.h delete mode 100644 src/core/transport/chttp2/parsing.c delete mode 100644 src/core/transport/chttp2/status_conversion.c delete mode 100644 src/core/transport/chttp2/status_conversion.h delete mode 100644 src/core/transport/chttp2/stream_lists.c delete mode 100644 src/core/transport/chttp2/stream_map.c delete mode 100644 src/core/transport/chttp2/stream_map.h delete mode 100644 src/core/transport/chttp2/timeout_encoding.c delete mode 100644 src/core/transport/chttp2/timeout_encoding.h delete mode 100644 src/core/transport/chttp2/varint.c delete mode 100644 src/core/transport/chttp2/varint.h delete mode 100644 src/core/transport/chttp2/writing.c delete mode 100644 src/core/transport/chttp2_transport.c delete mode 100644 src/core/transport/chttp2_transport.h delete mode 100644 src/core/transport/connectivity_state.c delete mode 100644 src/core/transport/connectivity_state.h delete mode 100644 src/core/transport/metadata.c delete mode 100644 src/core/transport/metadata.h delete mode 100644 src/core/transport/metadata_batch.c delete mode 100644 src/core/transport/metadata_batch.h delete mode 100644 src/core/transport/static_metadata.c delete mode 100644 src/core/transport/static_metadata.h delete mode 100644 src/core/transport/transport.c delete mode 100644 src/core/transport/transport.h delete mode 100644 src/core/transport/transport_impl.h delete mode 100644 src/core/transport/transport_op_string.c delete mode 100644 src/core/tsi/fake_transport_security.c delete mode 100644 src/core/tsi/fake_transport_security.h delete mode 100644 src/core/tsi/ssl_transport_security.c delete mode 100644 src/core/tsi/ssl_transport_security.h delete mode 100644 src/core/tsi/ssl_types.h delete mode 100644 src/core/tsi/test_creds/README delete mode 100644 src/core/tsi/test_creds/badclient.key delete mode 100644 src/core/tsi/test_creds/badclient.pem delete mode 100644 src/core/tsi/test_creds/badserver.key delete mode 100644 src/core/tsi/test_creds/badserver.pem delete mode 100644 src/core/tsi/test_creds/ca-openssl.cnf delete mode 100644 src/core/tsi/test_creds/ca.key delete mode 100644 src/core/tsi/test_creds/ca.pem delete mode 100644 src/core/tsi/test_creds/client.key delete mode 100644 src/core/tsi/test_creds/client.pem delete mode 100644 src/core/tsi/test_creds/server0.key delete mode 100644 src/core/tsi/test_creds/server0.pem delete mode 100644 src/core/tsi/test_creds/server1-openssl.cnf delete mode 100644 src/core/tsi/test_creds/server1.key delete mode 100644 src/core/tsi/test_creds/server1.pem delete mode 100644 src/core/tsi/transport_security.c delete mode 100644 src/core/tsi/transport_security.h delete mode 100644 src/core/tsi/transport_security_interface.h create mode 100644 templates/src/core/lib/surface/version.c.template delete mode 100644 templates/src/core/surface/version.c.template (limited to 'src/core/iomgr/fd_posix.c') diff --git a/BUILD b/BUILD index 7f8d8a423e..ef78f44508 100644 --- a/BUILD +++ b/BUILD @@ -44,62 +44,62 @@ package(default_visibility = ["//visibility:public"]) cc_library( name = "gpr", srcs = [ - "src/core/profiling/timers.h", - "src/core/support/backoff.h", - "src/core/support/block_annotate.h", - "src/core/support/env.h", - "src/core/support/load_file.h", - "src/core/support/murmur_hash.h", - "src/core/support/stack_lockfree.h", - "src/core/support/string.h", - "src/core/support/string_win32.h", - "src/core/support/thd_internal.h", - "src/core/support/time_precise.h", - "src/core/support/tmpfile.h", - "src/core/profiling/basic_timers.c", - "src/core/profiling/stap_timers.c", - "src/core/support/alloc.c", - "src/core/support/avl.c", - "src/core/support/backoff.c", - "src/core/support/cmdline.c", - "src/core/support/cpu_iphone.c", - "src/core/support/cpu_linux.c", - "src/core/support/cpu_posix.c", - "src/core/support/cpu_windows.c", - "src/core/support/env_linux.c", - "src/core/support/env_posix.c", - "src/core/support/env_win32.c", - "src/core/support/histogram.c", - "src/core/support/host_port.c", - "src/core/support/load_file.c", - "src/core/support/log.c", - "src/core/support/log_android.c", - "src/core/support/log_linux.c", - "src/core/support/log_posix.c", - "src/core/support/log_win32.c", - "src/core/support/murmur_hash.c", - "src/core/support/slice.c", - "src/core/support/slice_buffer.c", - "src/core/support/stack_lockfree.c", - "src/core/support/string.c", - "src/core/support/string_posix.c", - "src/core/support/string_win32.c", - "src/core/support/subprocess_posix.c", - "src/core/support/subprocess_windows.c", - "src/core/support/sync.c", - "src/core/support/sync_posix.c", - "src/core/support/sync_win32.c", - "src/core/support/thd.c", - "src/core/support/thd_posix.c", - "src/core/support/thd_win32.c", - "src/core/support/time.c", - "src/core/support/time_posix.c", - "src/core/support/time_precise.c", - "src/core/support/time_win32.c", - "src/core/support/tls_pthread.c", - "src/core/support/tmpfile_posix.c", - "src/core/support/tmpfile_win32.c", - "src/core/support/wrap_memcpy.c", + "src/core/lib/profiling/timers.h", + "src/core/lib/support/backoff.h", + "src/core/lib/support/block_annotate.h", + "src/core/lib/support/env.h", + "src/core/lib/support/load_file.h", + "src/core/lib/support/murmur_hash.h", + "src/core/lib/support/stack_lockfree.h", + "src/core/lib/support/string.h", + "src/core/lib/support/string_win32.h", + "src/core/lib/support/thd_internal.h", + "src/core/lib/support/time_precise.h", + "src/core/lib/support/tmpfile.h", + "src/core/lib/profiling/basic_timers.c", + "src/core/lib/profiling/stap_timers.c", + "src/core/lib/support/alloc.c", + "src/core/lib/support/avl.c", + "src/core/lib/support/backoff.c", + "src/core/lib/support/cmdline.c", + "src/core/lib/support/cpu_iphone.c", + "src/core/lib/support/cpu_linux.c", + "src/core/lib/support/cpu_posix.c", + "src/core/lib/support/cpu_windows.c", + "src/core/lib/support/env_linux.c", + "src/core/lib/support/env_posix.c", + "src/core/lib/support/env_win32.c", + "src/core/lib/support/histogram.c", + "src/core/lib/support/host_port.c", + "src/core/lib/support/load_file.c", + "src/core/lib/support/log.c", + "src/core/lib/support/log_android.c", + "src/core/lib/support/log_linux.c", + "src/core/lib/support/log_posix.c", + "src/core/lib/support/log_win32.c", + "src/core/lib/support/murmur_hash.c", + "src/core/lib/support/slice.c", + "src/core/lib/support/slice_buffer.c", + "src/core/lib/support/stack_lockfree.c", + "src/core/lib/support/string.c", + "src/core/lib/support/string_posix.c", + "src/core/lib/support/string_win32.c", + "src/core/lib/support/subprocess_posix.c", + "src/core/lib/support/subprocess_windows.c", + "src/core/lib/support/sync.c", + "src/core/lib/support/sync_posix.c", + "src/core/lib/support/sync_win32.c", + "src/core/lib/support/thd.c", + "src/core/lib/support/thd_posix.c", + "src/core/lib/support/thd_win32.c", + "src/core/lib/support/time.c", + "src/core/lib/support/time_posix.c", + "src/core/lib/support/time_precise.c", + "src/core/lib/support/time_win32.c", + "src/core/lib/support/tls_pthread.c", + "src/core/lib/support/tmpfile_posix.c", + "src/core/lib/support/tmpfile_win32.c", + "src/core/lib/support/wrap_memcpy.c", ], hdrs = [ "include/grpc/support/alloc.h", @@ -157,308 +157,308 @@ cc_library( cc_library( name = "grpc", srcs = [ - "src/core/census/grpc_filter.h", - "src/core/census/grpc_plugin.h", - "src/core/channel/channel_args.h", - "src/core/channel/channel_stack.h", - "src/core/channel/channel_stack_builder.h", - "src/core/channel/client_channel.h", - "src/core/channel/compress_filter.h", - "src/core/channel/connected_channel.h", - "src/core/channel/context.h", - "src/core/channel/http_client_filter.h", - "src/core/channel/http_server_filter.h", - "src/core/channel/subchannel_call_holder.h", - "src/core/client_config/client_config.h", - "src/core/client_config/connector.h", - "src/core/client_config/initial_connect_string.h", - "src/core/client_config/lb_policies/load_balancer_api.h", - "src/core/client_config/lb_policies/pick_first.h", - "src/core/client_config/lb_policies/round_robin.h", - "src/core/client_config/lb_policy.h", - "src/core/client_config/lb_policy_factory.h", - "src/core/client_config/lb_policy_registry.h", - "src/core/client_config/resolver.h", - "src/core/client_config/resolver_factory.h", - "src/core/client_config/resolver_registry.h", - "src/core/client_config/resolvers/dns_resolver.h", - "src/core/client_config/resolvers/sockaddr_resolver.h", - "src/core/client_config/subchannel.h", - "src/core/client_config/subchannel_factory.h", - "src/core/client_config/subchannel_index.h", - "src/core/client_config/uri_parser.h", - "src/core/compression/algorithm_metadata.h", - "src/core/compression/message_compress.h", - "src/core/debug/trace.h", - "src/core/http/format_request.h", - "src/core/http/httpcli.h", - "src/core/http/parser.h", - "src/core/iomgr/closure.h", - "src/core/iomgr/endpoint.h", - "src/core/iomgr/endpoint_pair.h", - "src/core/iomgr/exec_ctx.h", - "src/core/iomgr/executor.h", - "src/core/iomgr/fd_posix.h", - "src/core/iomgr/iocp_windows.h", - "src/core/iomgr/iomgr.h", - "src/core/iomgr/iomgr_internal.h", - "src/core/iomgr/iomgr_posix.h", - "src/core/iomgr/pollset.h", - "src/core/iomgr/pollset_posix.h", - "src/core/iomgr/pollset_set.h", - "src/core/iomgr/pollset_set_posix.h", - "src/core/iomgr/pollset_set_windows.h", - "src/core/iomgr/pollset_windows.h", - "src/core/iomgr/resolve_address.h", - "src/core/iomgr/sockaddr.h", - "src/core/iomgr/sockaddr_posix.h", - "src/core/iomgr/sockaddr_utils.h", - "src/core/iomgr/sockaddr_win32.h", - "src/core/iomgr/socket_utils_posix.h", - "src/core/iomgr/socket_windows.h", - "src/core/iomgr/tcp_client.h", - "src/core/iomgr/tcp_posix.h", - "src/core/iomgr/tcp_server.h", - "src/core/iomgr/tcp_windows.h", - "src/core/iomgr/time_averaged_stats.h", - "src/core/iomgr/timer.h", - "src/core/iomgr/timer_heap.h", - "src/core/iomgr/udp_server.h", - "src/core/iomgr/unix_sockets_posix.h", - "src/core/iomgr/wakeup_fd_pipe.h", - "src/core/iomgr/wakeup_fd_posix.h", - "src/core/iomgr/workqueue.h", - "src/core/iomgr/workqueue_posix.h", - "src/core/iomgr/workqueue_windows.h", - "src/core/json/json.h", - "src/core/json/json_common.h", - "src/core/json/json_reader.h", - "src/core/json/json_writer.h", - "src/core/proto/grpc/lb/v0/load_balancer.pb.h", - "src/core/statistics/census_interface.h", - "src/core/statistics/census_rpc_stats.h", - "src/core/surface/api_trace.h", - "src/core/surface/call.h", - "src/core/surface/call_test_only.h", - "src/core/surface/channel.h", - "src/core/surface/channel_init.h", - "src/core/surface/channel_stack_type.h", - "src/core/surface/completion_queue.h", - "src/core/surface/event_string.h", - "src/core/surface/init.h", - "src/core/surface/lame_client.h", - "src/core/surface/server.h", - "src/core/surface/surface_trace.h", - "src/core/transport/byte_stream.h", - "src/core/transport/chttp2/alpn.h", - "src/core/transport/chttp2/bin_encoder.h", - "src/core/transport/chttp2/frame.h", - "src/core/transport/chttp2/frame_data.h", - "src/core/transport/chttp2/frame_goaway.h", - "src/core/transport/chttp2/frame_ping.h", - "src/core/transport/chttp2/frame_rst_stream.h", - "src/core/transport/chttp2/frame_settings.h", - "src/core/transport/chttp2/frame_window_update.h", - "src/core/transport/chttp2/hpack_encoder.h", - "src/core/transport/chttp2/hpack_parser.h", - "src/core/transport/chttp2/hpack_table.h", - "src/core/transport/chttp2/http2_errors.h", - "src/core/transport/chttp2/huffsyms.h", - "src/core/transport/chttp2/incoming_metadata.h", - "src/core/transport/chttp2/internal.h", - "src/core/transport/chttp2/status_conversion.h", - "src/core/transport/chttp2/stream_map.h", - "src/core/transport/chttp2/timeout_encoding.h", - "src/core/transport/chttp2/varint.h", - "src/core/transport/chttp2_transport.h", - "src/core/transport/connectivity_state.h", - "src/core/transport/metadata.h", - "src/core/transport/metadata_batch.h", - "src/core/transport/static_metadata.h", - "src/core/transport/transport.h", - "src/core/transport/transport_impl.h", - "src/core/security/auth_filters.h", - "src/core/security/b64.h", - "src/core/security/credentials.h", - "src/core/security/handshake.h", - "src/core/security/json_token.h", - "src/core/security/jwt_verifier.h", - "src/core/security/secure_endpoint.h", - "src/core/security/security_connector.h", - "src/core/security/security_context.h", - "src/core/tsi/fake_transport_security.h", - "src/core/tsi/ssl_transport_security.h", - "src/core/tsi/ssl_types.h", - "src/core/tsi/transport_security.h", - "src/core/tsi/transport_security_interface.h", - "src/core/census/aggregation.h", - "src/core/census/mlog.h", - "src/core/census/rpc_metric_id.h", + "src/core/lib/census/grpc_filter.h", + "src/core/lib/census/grpc_plugin.h", + "src/core/lib/channel/channel_args.h", + "src/core/lib/channel/channel_stack.h", + "src/core/lib/channel/channel_stack_builder.h", + "src/core/lib/channel/client_channel.h", + "src/core/lib/channel/compress_filter.h", + "src/core/lib/channel/connected_channel.h", + "src/core/lib/channel/context.h", + "src/core/lib/channel/http_client_filter.h", + "src/core/lib/channel/http_server_filter.h", + "src/core/lib/channel/subchannel_call_holder.h", + "src/core/lib/client_config/client_config.h", + "src/core/lib/client_config/connector.h", + "src/core/lib/client_config/initial_connect_string.h", + "src/core/lib/client_config/lb_policies/load_balancer_api.h", + "src/core/lib/client_config/lb_policies/pick_first.h", + "src/core/lib/client_config/lb_policies/round_robin.h", + "src/core/lib/client_config/lb_policy.h", + "src/core/lib/client_config/lb_policy_factory.h", + "src/core/lib/client_config/lb_policy_registry.h", + "src/core/lib/client_config/resolver.h", + "src/core/lib/client_config/resolver_factory.h", + "src/core/lib/client_config/resolver_registry.h", + "src/core/lib/client_config/resolvers/dns_resolver.h", + "src/core/lib/client_config/resolvers/sockaddr_resolver.h", + "src/core/lib/client_config/subchannel.h", + "src/core/lib/client_config/subchannel_factory.h", + "src/core/lib/client_config/subchannel_index.h", + "src/core/lib/client_config/uri_parser.h", + "src/core/lib/compression/algorithm_metadata.h", + "src/core/lib/compression/message_compress.h", + "src/core/lib/debug/trace.h", + "src/core/lib/http/format_request.h", + "src/core/lib/http/httpcli.h", + "src/core/lib/http/parser.h", + "src/core/lib/iomgr/closure.h", + "src/core/lib/iomgr/endpoint.h", + "src/core/lib/iomgr/endpoint_pair.h", + "src/core/lib/iomgr/exec_ctx.h", + "src/core/lib/iomgr/executor.h", + "src/core/lib/iomgr/fd_posix.h", + "src/core/lib/iomgr/iocp_windows.h", + "src/core/lib/iomgr/iomgr.h", + "src/core/lib/iomgr/iomgr_internal.h", + "src/core/lib/iomgr/iomgr_posix.h", + "src/core/lib/iomgr/pollset.h", + "src/core/lib/iomgr/pollset_posix.h", + "src/core/lib/iomgr/pollset_set.h", + "src/core/lib/iomgr/pollset_set_posix.h", + "src/core/lib/iomgr/pollset_set_windows.h", + "src/core/lib/iomgr/pollset_windows.h", + "src/core/lib/iomgr/resolve_address.h", + "src/core/lib/iomgr/sockaddr.h", + "src/core/lib/iomgr/sockaddr_posix.h", + "src/core/lib/iomgr/sockaddr_utils.h", + "src/core/lib/iomgr/sockaddr_win32.h", + "src/core/lib/iomgr/socket_utils_posix.h", + "src/core/lib/iomgr/socket_windows.h", + "src/core/lib/iomgr/tcp_client.h", + "src/core/lib/iomgr/tcp_posix.h", + "src/core/lib/iomgr/tcp_server.h", + "src/core/lib/iomgr/tcp_windows.h", + "src/core/lib/iomgr/time_averaged_stats.h", + "src/core/lib/iomgr/timer.h", + "src/core/lib/iomgr/timer_heap.h", + "src/core/lib/iomgr/udp_server.h", + "src/core/lib/iomgr/unix_sockets_posix.h", + "src/core/lib/iomgr/wakeup_fd_pipe.h", + "src/core/lib/iomgr/wakeup_fd_posix.h", + "src/core/lib/iomgr/workqueue.h", + "src/core/lib/iomgr/workqueue_posix.h", + "src/core/lib/iomgr/workqueue_windows.h", + "src/core/lib/json/json.h", + "src/core/lib/json/json_common.h", + "src/core/lib/json/json_reader.h", + "src/core/lib/json/json_writer.h", + "src/core/lib/proto/grpc/lb/v0/load_balancer.pb.h", + "src/core/lib/statistics/census_interface.h", + "src/core/lib/statistics/census_rpc_stats.h", + "src/core/lib/surface/api_trace.h", + "src/core/lib/surface/call.h", + "src/core/lib/surface/call_test_only.h", + "src/core/lib/surface/channel.h", + "src/core/lib/surface/channel_init.h", + "src/core/lib/surface/channel_stack_type.h", + "src/core/lib/surface/completion_queue.h", + "src/core/lib/surface/event_string.h", + "src/core/lib/surface/init.h", + "src/core/lib/surface/lame_client.h", + "src/core/lib/surface/server.h", + "src/core/lib/surface/surface_trace.h", + "src/core/lib/transport/byte_stream.h", + "src/core/lib/transport/chttp2/alpn.h", + "src/core/lib/transport/chttp2/bin_encoder.h", + "src/core/lib/transport/chttp2/frame.h", + "src/core/lib/transport/chttp2/frame_data.h", + "src/core/lib/transport/chttp2/frame_goaway.h", + "src/core/lib/transport/chttp2/frame_ping.h", + "src/core/lib/transport/chttp2/frame_rst_stream.h", + "src/core/lib/transport/chttp2/frame_settings.h", + "src/core/lib/transport/chttp2/frame_window_update.h", + "src/core/lib/transport/chttp2/hpack_encoder.h", + "src/core/lib/transport/chttp2/hpack_parser.h", + "src/core/lib/transport/chttp2/hpack_table.h", + "src/core/lib/transport/chttp2/http2_errors.h", + "src/core/lib/transport/chttp2/huffsyms.h", + "src/core/lib/transport/chttp2/incoming_metadata.h", + "src/core/lib/transport/chttp2/internal.h", + "src/core/lib/transport/chttp2/status_conversion.h", + "src/core/lib/transport/chttp2/stream_map.h", + "src/core/lib/transport/chttp2/timeout_encoding.h", + "src/core/lib/transport/chttp2/varint.h", + "src/core/lib/transport/chttp2_transport.h", + "src/core/lib/transport/connectivity_state.h", + "src/core/lib/transport/metadata.h", + "src/core/lib/transport/metadata_batch.h", + "src/core/lib/transport/static_metadata.h", + "src/core/lib/transport/transport.h", + "src/core/lib/transport/transport_impl.h", + "src/core/lib/security/auth_filters.h", + "src/core/lib/security/b64.h", + "src/core/lib/security/credentials.h", + "src/core/lib/security/handshake.h", + "src/core/lib/security/json_token.h", + "src/core/lib/security/jwt_verifier.h", + "src/core/lib/security/secure_endpoint.h", + "src/core/lib/security/security_connector.h", + "src/core/lib/security/security_context.h", + "src/core/lib/tsi/fake_transport_security.h", + "src/core/lib/tsi/ssl_transport_security.h", + "src/core/lib/tsi/ssl_types.h", + "src/core/lib/tsi/transport_security.h", + "src/core/lib/tsi/transport_security_interface.h", + "src/core/lib/census/aggregation.h", + "src/core/lib/census/mlog.h", + "src/core/lib/census/rpc_metric_id.h", "third_party/nanopb/pb.h", "third_party/nanopb/pb_common.h", "third_party/nanopb/pb_decode.h", "third_party/nanopb/pb_encode.h", - "src/core/census/grpc_context.c", - "src/core/census/grpc_filter.c", - "src/core/census/grpc_plugin.c", - "src/core/channel/channel_args.c", - "src/core/channel/channel_stack.c", - "src/core/channel/channel_stack_builder.c", - "src/core/channel/client_channel.c", - "src/core/channel/compress_filter.c", - "src/core/channel/connected_channel.c", - "src/core/channel/http_client_filter.c", - "src/core/channel/http_server_filter.c", - "src/core/channel/subchannel_call_holder.c", - "src/core/client_config/client_config.c", - "src/core/client_config/connector.c", - "src/core/client_config/default_initial_connect_string.c", - "src/core/client_config/initial_connect_string.c", - "src/core/client_config/lb_policies/load_balancer_api.c", - "src/core/client_config/lb_policies/pick_first.c", - "src/core/client_config/lb_policies/round_robin.c", - "src/core/client_config/lb_policy.c", - "src/core/client_config/lb_policy_factory.c", - "src/core/client_config/lb_policy_registry.c", - "src/core/client_config/resolver.c", - "src/core/client_config/resolver_factory.c", - "src/core/client_config/resolver_registry.c", - "src/core/client_config/resolvers/dns_resolver.c", - "src/core/client_config/resolvers/sockaddr_resolver.c", - "src/core/client_config/subchannel.c", - "src/core/client_config/subchannel_factory.c", - "src/core/client_config/subchannel_index.c", - "src/core/client_config/uri_parser.c", - "src/core/compression/compression_algorithm.c", - "src/core/compression/message_compress.c", - "src/core/debug/trace.c", - "src/core/http/format_request.c", - "src/core/http/httpcli.c", - "src/core/http/parser.c", - "src/core/iomgr/closure.c", - "src/core/iomgr/endpoint.c", - "src/core/iomgr/endpoint_pair_posix.c", - "src/core/iomgr/endpoint_pair_windows.c", - "src/core/iomgr/exec_ctx.c", - "src/core/iomgr/executor.c", - "src/core/iomgr/fd_posix.c", - "src/core/iomgr/iocp_windows.c", - "src/core/iomgr/iomgr.c", - "src/core/iomgr/iomgr_posix.c", - "src/core/iomgr/iomgr_windows.c", - "src/core/iomgr/pollset_multipoller_with_epoll.c", - "src/core/iomgr/pollset_multipoller_with_poll_posix.c", - "src/core/iomgr/pollset_posix.c", - "src/core/iomgr/pollset_set_posix.c", - "src/core/iomgr/pollset_set_windows.c", - "src/core/iomgr/pollset_windows.c", - "src/core/iomgr/resolve_address_posix.c", - "src/core/iomgr/resolve_address_windows.c", - "src/core/iomgr/sockaddr_utils.c", - "src/core/iomgr/socket_utils_common_posix.c", - "src/core/iomgr/socket_utils_linux.c", - "src/core/iomgr/socket_utils_posix.c", - "src/core/iomgr/socket_windows.c", - "src/core/iomgr/tcp_client_posix.c", - "src/core/iomgr/tcp_client_windows.c", - "src/core/iomgr/tcp_posix.c", - "src/core/iomgr/tcp_server_posix.c", - "src/core/iomgr/tcp_server_windows.c", - "src/core/iomgr/tcp_windows.c", - "src/core/iomgr/time_averaged_stats.c", - "src/core/iomgr/timer.c", - "src/core/iomgr/timer_heap.c", - "src/core/iomgr/udp_server.c", - "src/core/iomgr/unix_sockets_posix.c", - "src/core/iomgr/unix_sockets_posix_noop.c", - "src/core/iomgr/wakeup_fd_eventfd.c", - "src/core/iomgr/wakeup_fd_nospecial.c", - "src/core/iomgr/wakeup_fd_pipe.c", - "src/core/iomgr/wakeup_fd_posix.c", - "src/core/iomgr/workqueue_posix.c", - "src/core/iomgr/workqueue_windows.c", - "src/core/json/json.c", - "src/core/json/json_reader.c", - "src/core/json/json_string.c", - "src/core/json/json_writer.c", - "src/core/proto/grpc/lb/v0/load_balancer.pb.c", - "src/core/surface/alarm.c", - "src/core/surface/api_trace.c", - "src/core/surface/byte_buffer.c", - "src/core/surface/byte_buffer_reader.c", - "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/channel_init.c", - "src/core/surface/channel_ping.c", - "src/core/surface/channel_stack_type.c", - "src/core/surface/completion_queue.c", - "src/core/surface/event_string.c", - "src/core/surface/init.c", - "src/core/surface/lame_client.c", - "src/core/surface/metadata_array.c", - "src/core/surface/server.c", - "src/core/surface/server_chttp2.c", - "src/core/surface/validate_metadata.c", - "src/core/surface/version.c", - "src/core/transport/byte_stream.c", - "src/core/transport/chttp2/alpn.c", - "src/core/transport/chttp2/bin_encoder.c", - "src/core/transport/chttp2/frame_data.c", - "src/core/transport/chttp2/frame_goaway.c", - "src/core/transport/chttp2/frame_ping.c", - "src/core/transport/chttp2/frame_rst_stream.c", - "src/core/transport/chttp2/frame_settings.c", - "src/core/transport/chttp2/frame_window_update.c", - "src/core/transport/chttp2/hpack_encoder.c", - "src/core/transport/chttp2/hpack_parser.c", - "src/core/transport/chttp2/hpack_table.c", - "src/core/transport/chttp2/huffsyms.c", - "src/core/transport/chttp2/incoming_metadata.c", - "src/core/transport/chttp2/parsing.c", - "src/core/transport/chttp2/status_conversion.c", - "src/core/transport/chttp2/stream_lists.c", - "src/core/transport/chttp2/stream_map.c", - "src/core/transport/chttp2/timeout_encoding.c", - "src/core/transport/chttp2/varint.c", - "src/core/transport/chttp2/writing.c", - "src/core/transport/chttp2_transport.c", - "src/core/transport/connectivity_state.c", - "src/core/transport/metadata.c", - "src/core/transport/metadata_batch.c", - "src/core/transport/static_metadata.c", - "src/core/transport/transport.c", - "src/core/transport/transport_op_string.c", - "src/core/http/httpcli_security_connector.c", - "src/core/security/b64.c", - "src/core/security/client_auth_filter.c", - "src/core/security/credentials.c", - "src/core/security/credentials_metadata.c", - "src/core/security/credentials_posix.c", - "src/core/security/credentials_win32.c", - "src/core/security/google_default_credentials.c", - "src/core/security/handshake.c", - "src/core/security/json_token.c", - "src/core/security/jwt_verifier.c", - "src/core/security/secure_endpoint.c", - "src/core/security/security_connector.c", - "src/core/security/security_context.c", - "src/core/security/server_auth_filter.c", - "src/core/security/server_secure_chttp2.c", - "src/core/surface/init_secure.c", - "src/core/surface/secure_channel_create.c", - "src/core/tsi/fake_transport_security.c", - "src/core/tsi/ssl_transport_security.c", - "src/core/tsi/transport_security.c", - "src/core/census/context.c", - "src/core/census/initialize.c", - "src/core/census/mlog.c", - "src/core/census/operation.c", - "src/core/census/placeholders.c", - "src/core/census/tracing.c", + "src/core/lib/census/grpc_context.c", + "src/core/lib/census/grpc_filter.c", + "src/core/lib/census/grpc_plugin.c", + "src/core/lib/channel/channel_args.c", + "src/core/lib/channel/channel_stack.c", + "src/core/lib/channel/channel_stack_builder.c", + "src/core/lib/channel/client_channel.c", + "src/core/lib/channel/compress_filter.c", + "src/core/lib/channel/connected_channel.c", + "src/core/lib/channel/http_client_filter.c", + "src/core/lib/channel/http_server_filter.c", + "src/core/lib/channel/subchannel_call_holder.c", + "src/core/lib/client_config/client_config.c", + "src/core/lib/client_config/connector.c", + "src/core/lib/client_config/default_initial_connect_string.c", + "src/core/lib/client_config/initial_connect_string.c", + "src/core/lib/client_config/lb_policies/load_balancer_api.c", + "src/core/lib/client_config/lb_policies/pick_first.c", + "src/core/lib/client_config/lb_policies/round_robin.c", + "src/core/lib/client_config/lb_policy.c", + "src/core/lib/client_config/lb_policy_factory.c", + "src/core/lib/client_config/lb_policy_registry.c", + "src/core/lib/client_config/resolver.c", + "src/core/lib/client_config/resolver_factory.c", + "src/core/lib/client_config/resolver_registry.c", + "src/core/lib/client_config/resolvers/dns_resolver.c", + "src/core/lib/client_config/resolvers/sockaddr_resolver.c", + "src/core/lib/client_config/subchannel.c", + "src/core/lib/client_config/subchannel_factory.c", + "src/core/lib/client_config/subchannel_index.c", + "src/core/lib/client_config/uri_parser.c", + "src/core/lib/compression/compression_algorithm.c", + "src/core/lib/compression/message_compress.c", + "src/core/lib/debug/trace.c", + "src/core/lib/http/format_request.c", + "src/core/lib/http/httpcli.c", + "src/core/lib/http/parser.c", + "src/core/lib/iomgr/closure.c", + "src/core/lib/iomgr/endpoint.c", + "src/core/lib/iomgr/endpoint_pair_posix.c", + "src/core/lib/iomgr/endpoint_pair_windows.c", + "src/core/lib/iomgr/exec_ctx.c", + "src/core/lib/iomgr/executor.c", + "src/core/lib/iomgr/fd_posix.c", + "src/core/lib/iomgr/iocp_windows.c", + "src/core/lib/iomgr/iomgr.c", + "src/core/lib/iomgr/iomgr_posix.c", + "src/core/lib/iomgr/iomgr_windows.c", + "src/core/lib/iomgr/pollset_multipoller_with_epoll.c", + "src/core/lib/iomgr/pollset_multipoller_with_poll_posix.c", + "src/core/lib/iomgr/pollset_posix.c", + "src/core/lib/iomgr/pollset_set_posix.c", + "src/core/lib/iomgr/pollset_set_windows.c", + "src/core/lib/iomgr/pollset_windows.c", + "src/core/lib/iomgr/resolve_address_posix.c", + "src/core/lib/iomgr/resolve_address_windows.c", + "src/core/lib/iomgr/sockaddr_utils.c", + "src/core/lib/iomgr/socket_utils_common_posix.c", + "src/core/lib/iomgr/socket_utils_linux.c", + "src/core/lib/iomgr/socket_utils_posix.c", + "src/core/lib/iomgr/socket_windows.c", + "src/core/lib/iomgr/tcp_client_posix.c", + "src/core/lib/iomgr/tcp_client_windows.c", + "src/core/lib/iomgr/tcp_posix.c", + "src/core/lib/iomgr/tcp_server_posix.c", + "src/core/lib/iomgr/tcp_server_windows.c", + "src/core/lib/iomgr/tcp_windows.c", + "src/core/lib/iomgr/time_averaged_stats.c", + "src/core/lib/iomgr/timer.c", + "src/core/lib/iomgr/timer_heap.c", + "src/core/lib/iomgr/udp_server.c", + "src/core/lib/iomgr/unix_sockets_posix.c", + "src/core/lib/iomgr/unix_sockets_posix_noop.c", + "src/core/lib/iomgr/wakeup_fd_eventfd.c", + "src/core/lib/iomgr/wakeup_fd_nospecial.c", + "src/core/lib/iomgr/wakeup_fd_pipe.c", + "src/core/lib/iomgr/wakeup_fd_posix.c", + "src/core/lib/iomgr/workqueue_posix.c", + "src/core/lib/iomgr/workqueue_windows.c", + "src/core/lib/json/json.c", + "src/core/lib/json/json_reader.c", + "src/core/lib/json/json_string.c", + "src/core/lib/json/json_writer.c", + "src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c", + "src/core/lib/surface/alarm.c", + "src/core/lib/surface/api_trace.c", + "src/core/lib/surface/byte_buffer.c", + "src/core/lib/surface/byte_buffer_reader.c", + "src/core/lib/surface/call.c", + "src/core/lib/surface/call_details.c", + "src/core/lib/surface/call_log_batch.c", + "src/core/lib/surface/channel.c", + "src/core/lib/surface/channel_connectivity.c", + "src/core/lib/surface/channel_create.c", + "src/core/lib/surface/channel_init.c", + "src/core/lib/surface/channel_ping.c", + "src/core/lib/surface/channel_stack_type.c", + "src/core/lib/surface/completion_queue.c", + "src/core/lib/surface/event_string.c", + "src/core/lib/surface/init.c", + "src/core/lib/surface/lame_client.c", + "src/core/lib/surface/metadata_array.c", + "src/core/lib/surface/server.c", + "src/core/lib/surface/server_chttp2.c", + "src/core/lib/surface/validate_metadata.c", + "src/core/lib/surface/version.c", + "src/core/lib/transport/byte_stream.c", + "src/core/lib/transport/chttp2/alpn.c", + "src/core/lib/transport/chttp2/bin_encoder.c", + "src/core/lib/transport/chttp2/frame_data.c", + "src/core/lib/transport/chttp2/frame_goaway.c", + "src/core/lib/transport/chttp2/frame_ping.c", + "src/core/lib/transport/chttp2/frame_rst_stream.c", + "src/core/lib/transport/chttp2/frame_settings.c", + "src/core/lib/transport/chttp2/frame_window_update.c", + "src/core/lib/transport/chttp2/hpack_encoder.c", + "src/core/lib/transport/chttp2/hpack_parser.c", + "src/core/lib/transport/chttp2/hpack_table.c", + "src/core/lib/transport/chttp2/huffsyms.c", + "src/core/lib/transport/chttp2/incoming_metadata.c", + "src/core/lib/transport/chttp2/parsing.c", + "src/core/lib/transport/chttp2/status_conversion.c", + "src/core/lib/transport/chttp2/stream_lists.c", + "src/core/lib/transport/chttp2/stream_map.c", + "src/core/lib/transport/chttp2/timeout_encoding.c", + "src/core/lib/transport/chttp2/varint.c", + "src/core/lib/transport/chttp2/writing.c", + "src/core/lib/transport/chttp2_transport.c", + "src/core/lib/transport/connectivity_state.c", + "src/core/lib/transport/metadata.c", + "src/core/lib/transport/metadata_batch.c", + "src/core/lib/transport/static_metadata.c", + "src/core/lib/transport/transport.c", + "src/core/lib/transport/transport_op_string.c", + "src/core/lib/http/httpcli_security_connector.c", + "src/core/lib/security/b64.c", + "src/core/lib/security/client_auth_filter.c", + "src/core/lib/security/credentials.c", + "src/core/lib/security/credentials_metadata.c", + "src/core/lib/security/credentials_posix.c", + "src/core/lib/security/credentials_win32.c", + "src/core/lib/security/google_default_credentials.c", + "src/core/lib/security/handshake.c", + "src/core/lib/security/json_token.c", + "src/core/lib/security/jwt_verifier.c", + "src/core/lib/security/secure_endpoint.c", + "src/core/lib/security/security_connector.c", + "src/core/lib/security/security_context.c", + "src/core/lib/security/server_auth_filter.c", + "src/core/lib/security/server_secure_chttp2.c", + "src/core/lib/surface/init_secure.c", + "src/core/lib/surface/secure_channel_create.c", + "src/core/lib/tsi/fake_transport_security.c", + "src/core/lib/tsi/ssl_transport_security.c", + "src/core/lib/tsi/transport_security.c", + "src/core/lib/census/context.c", + "src/core/lib/census/initialize.c", + "src/core/lib/census/mlog.c", + "src/core/lib/census/operation.c", + "src/core/lib/census/placeholders.c", + "src/core/lib/census/tracing.c", "third_party/nanopb/pb_common.c", "third_party/nanopb/pb_decode.c", "third_party/nanopb/pb_encode.c", @@ -532,274 +532,274 @@ cc_library( cc_library( name = "grpc_unsecure", srcs = [ - "src/core/census/grpc_filter.h", - "src/core/census/grpc_plugin.h", - "src/core/channel/channel_args.h", - "src/core/channel/channel_stack.h", - "src/core/channel/channel_stack_builder.h", - "src/core/channel/client_channel.h", - "src/core/channel/compress_filter.h", - "src/core/channel/connected_channel.h", - "src/core/channel/context.h", - "src/core/channel/http_client_filter.h", - "src/core/channel/http_server_filter.h", - "src/core/channel/subchannel_call_holder.h", - "src/core/client_config/client_config.h", - "src/core/client_config/connector.h", - "src/core/client_config/initial_connect_string.h", - "src/core/client_config/lb_policies/load_balancer_api.h", - "src/core/client_config/lb_policies/pick_first.h", - "src/core/client_config/lb_policies/round_robin.h", - "src/core/client_config/lb_policy.h", - "src/core/client_config/lb_policy_factory.h", - "src/core/client_config/lb_policy_registry.h", - "src/core/client_config/resolver.h", - "src/core/client_config/resolver_factory.h", - "src/core/client_config/resolver_registry.h", - "src/core/client_config/resolvers/dns_resolver.h", - "src/core/client_config/resolvers/sockaddr_resolver.h", - "src/core/client_config/subchannel.h", - "src/core/client_config/subchannel_factory.h", - "src/core/client_config/subchannel_index.h", - "src/core/client_config/uri_parser.h", - "src/core/compression/algorithm_metadata.h", - "src/core/compression/message_compress.h", - "src/core/debug/trace.h", - "src/core/http/format_request.h", - "src/core/http/httpcli.h", - "src/core/http/parser.h", - "src/core/iomgr/closure.h", - "src/core/iomgr/endpoint.h", - "src/core/iomgr/endpoint_pair.h", - "src/core/iomgr/exec_ctx.h", - "src/core/iomgr/executor.h", - "src/core/iomgr/fd_posix.h", - "src/core/iomgr/iocp_windows.h", - "src/core/iomgr/iomgr.h", - "src/core/iomgr/iomgr_internal.h", - "src/core/iomgr/iomgr_posix.h", - "src/core/iomgr/pollset.h", - "src/core/iomgr/pollset_posix.h", - "src/core/iomgr/pollset_set.h", - "src/core/iomgr/pollset_set_posix.h", - "src/core/iomgr/pollset_set_windows.h", - "src/core/iomgr/pollset_windows.h", - "src/core/iomgr/resolve_address.h", - "src/core/iomgr/sockaddr.h", - "src/core/iomgr/sockaddr_posix.h", - "src/core/iomgr/sockaddr_utils.h", - "src/core/iomgr/sockaddr_win32.h", - "src/core/iomgr/socket_utils_posix.h", - "src/core/iomgr/socket_windows.h", - "src/core/iomgr/tcp_client.h", - "src/core/iomgr/tcp_posix.h", - "src/core/iomgr/tcp_server.h", - "src/core/iomgr/tcp_windows.h", - "src/core/iomgr/time_averaged_stats.h", - "src/core/iomgr/timer.h", - "src/core/iomgr/timer_heap.h", - "src/core/iomgr/udp_server.h", - "src/core/iomgr/unix_sockets_posix.h", - "src/core/iomgr/wakeup_fd_pipe.h", - "src/core/iomgr/wakeup_fd_posix.h", - "src/core/iomgr/workqueue.h", - "src/core/iomgr/workqueue_posix.h", - "src/core/iomgr/workqueue_windows.h", - "src/core/json/json.h", - "src/core/json/json_common.h", - "src/core/json/json_reader.h", - "src/core/json/json_writer.h", - "src/core/proto/grpc/lb/v0/load_balancer.pb.h", - "src/core/statistics/census_interface.h", - "src/core/statistics/census_rpc_stats.h", - "src/core/surface/api_trace.h", - "src/core/surface/call.h", - "src/core/surface/call_test_only.h", - "src/core/surface/channel.h", - "src/core/surface/channel_init.h", - "src/core/surface/channel_stack_type.h", - "src/core/surface/completion_queue.h", - "src/core/surface/event_string.h", - "src/core/surface/init.h", - "src/core/surface/lame_client.h", - "src/core/surface/server.h", - "src/core/surface/surface_trace.h", - "src/core/transport/byte_stream.h", - "src/core/transport/chttp2/alpn.h", - "src/core/transport/chttp2/bin_encoder.h", - "src/core/transport/chttp2/frame.h", - "src/core/transport/chttp2/frame_data.h", - "src/core/transport/chttp2/frame_goaway.h", - "src/core/transport/chttp2/frame_ping.h", - "src/core/transport/chttp2/frame_rst_stream.h", - "src/core/transport/chttp2/frame_settings.h", - "src/core/transport/chttp2/frame_window_update.h", - "src/core/transport/chttp2/hpack_encoder.h", - "src/core/transport/chttp2/hpack_parser.h", - "src/core/transport/chttp2/hpack_table.h", - "src/core/transport/chttp2/http2_errors.h", - "src/core/transport/chttp2/huffsyms.h", - "src/core/transport/chttp2/incoming_metadata.h", - "src/core/transport/chttp2/internal.h", - "src/core/transport/chttp2/status_conversion.h", - "src/core/transport/chttp2/stream_map.h", - "src/core/transport/chttp2/timeout_encoding.h", - "src/core/transport/chttp2/varint.h", - "src/core/transport/chttp2_transport.h", - "src/core/transport/connectivity_state.h", - "src/core/transport/metadata.h", - "src/core/transport/metadata_batch.h", - "src/core/transport/static_metadata.h", - "src/core/transport/transport.h", - "src/core/transport/transport_impl.h", - "src/core/census/aggregation.h", - "src/core/census/mlog.h", - "src/core/census/rpc_metric_id.h", + "src/core/lib/census/grpc_filter.h", + "src/core/lib/census/grpc_plugin.h", + "src/core/lib/channel/channel_args.h", + "src/core/lib/channel/channel_stack.h", + "src/core/lib/channel/channel_stack_builder.h", + "src/core/lib/channel/client_channel.h", + "src/core/lib/channel/compress_filter.h", + "src/core/lib/channel/connected_channel.h", + "src/core/lib/channel/context.h", + "src/core/lib/channel/http_client_filter.h", + "src/core/lib/channel/http_server_filter.h", + "src/core/lib/channel/subchannel_call_holder.h", + "src/core/lib/client_config/client_config.h", + "src/core/lib/client_config/connector.h", + "src/core/lib/client_config/initial_connect_string.h", + "src/core/lib/client_config/lb_policies/load_balancer_api.h", + "src/core/lib/client_config/lb_policies/pick_first.h", + "src/core/lib/client_config/lb_policies/round_robin.h", + "src/core/lib/client_config/lb_policy.h", + "src/core/lib/client_config/lb_policy_factory.h", + "src/core/lib/client_config/lb_policy_registry.h", + "src/core/lib/client_config/resolver.h", + "src/core/lib/client_config/resolver_factory.h", + "src/core/lib/client_config/resolver_registry.h", + "src/core/lib/client_config/resolvers/dns_resolver.h", + "src/core/lib/client_config/resolvers/sockaddr_resolver.h", + "src/core/lib/client_config/subchannel.h", + "src/core/lib/client_config/subchannel_factory.h", + "src/core/lib/client_config/subchannel_index.h", + "src/core/lib/client_config/uri_parser.h", + "src/core/lib/compression/algorithm_metadata.h", + "src/core/lib/compression/message_compress.h", + "src/core/lib/debug/trace.h", + "src/core/lib/http/format_request.h", + "src/core/lib/http/httpcli.h", + "src/core/lib/http/parser.h", + "src/core/lib/iomgr/closure.h", + "src/core/lib/iomgr/endpoint.h", + "src/core/lib/iomgr/endpoint_pair.h", + "src/core/lib/iomgr/exec_ctx.h", + "src/core/lib/iomgr/executor.h", + "src/core/lib/iomgr/fd_posix.h", + "src/core/lib/iomgr/iocp_windows.h", + "src/core/lib/iomgr/iomgr.h", + "src/core/lib/iomgr/iomgr_internal.h", + "src/core/lib/iomgr/iomgr_posix.h", + "src/core/lib/iomgr/pollset.h", + "src/core/lib/iomgr/pollset_posix.h", + "src/core/lib/iomgr/pollset_set.h", + "src/core/lib/iomgr/pollset_set_posix.h", + "src/core/lib/iomgr/pollset_set_windows.h", + "src/core/lib/iomgr/pollset_windows.h", + "src/core/lib/iomgr/resolve_address.h", + "src/core/lib/iomgr/sockaddr.h", + "src/core/lib/iomgr/sockaddr_posix.h", + "src/core/lib/iomgr/sockaddr_utils.h", + "src/core/lib/iomgr/sockaddr_win32.h", + "src/core/lib/iomgr/socket_utils_posix.h", + "src/core/lib/iomgr/socket_windows.h", + "src/core/lib/iomgr/tcp_client.h", + "src/core/lib/iomgr/tcp_posix.h", + "src/core/lib/iomgr/tcp_server.h", + "src/core/lib/iomgr/tcp_windows.h", + "src/core/lib/iomgr/time_averaged_stats.h", + "src/core/lib/iomgr/timer.h", + "src/core/lib/iomgr/timer_heap.h", + "src/core/lib/iomgr/udp_server.h", + "src/core/lib/iomgr/unix_sockets_posix.h", + "src/core/lib/iomgr/wakeup_fd_pipe.h", + "src/core/lib/iomgr/wakeup_fd_posix.h", + "src/core/lib/iomgr/workqueue.h", + "src/core/lib/iomgr/workqueue_posix.h", + "src/core/lib/iomgr/workqueue_windows.h", + "src/core/lib/json/json.h", + "src/core/lib/json/json_common.h", + "src/core/lib/json/json_reader.h", + "src/core/lib/json/json_writer.h", + "src/core/lib/proto/grpc/lb/v0/load_balancer.pb.h", + "src/core/lib/statistics/census_interface.h", + "src/core/lib/statistics/census_rpc_stats.h", + "src/core/lib/surface/api_trace.h", + "src/core/lib/surface/call.h", + "src/core/lib/surface/call_test_only.h", + "src/core/lib/surface/channel.h", + "src/core/lib/surface/channel_init.h", + "src/core/lib/surface/channel_stack_type.h", + "src/core/lib/surface/completion_queue.h", + "src/core/lib/surface/event_string.h", + "src/core/lib/surface/init.h", + "src/core/lib/surface/lame_client.h", + "src/core/lib/surface/server.h", + "src/core/lib/surface/surface_trace.h", + "src/core/lib/transport/byte_stream.h", + "src/core/lib/transport/chttp2/alpn.h", + "src/core/lib/transport/chttp2/bin_encoder.h", + "src/core/lib/transport/chttp2/frame.h", + "src/core/lib/transport/chttp2/frame_data.h", + "src/core/lib/transport/chttp2/frame_goaway.h", + "src/core/lib/transport/chttp2/frame_ping.h", + "src/core/lib/transport/chttp2/frame_rst_stream.h", + "src/core/lib/transport/chttp2/frame_settings.h", + "src/core/lib/transport/chttp2/frame_window_update.h", + "src/core/lib/transport/chttp2/hpack_encoder.h", + "src/core/lib/transport/chttp2/hpack_parser.h", + "src/core/lib/transport/chttp2/hpack_table.h", + "src/core/lib/transport/chttp2/http2_errors.h", + "src/core/lib/transport/chttp2/huffsyms.h", + "src/core/lib/transport/chttp2/incoming_metadata.h", + "src/core/lib/transport/chttp2/internal.h", + "src/core/lib/transport/chttp2/status_conversion.h", + "src/core/lib/transport/chttp2/stream_map.h", + "src/core/lib/transport/chttp2/timeout_encoding.h", + "src/core/lib/transport/chttp2/varint.h", + "src/core/lib/transport/chttp2_transport.h", + "src/core/lib/transport/connectivity_state.h", + "src/core/lib/transport/metadata.h", + "src/core/lib/transport/metadata_batch.h", + "src/core/lib/transport/static_metadata.h", + "src/core/lib/transport/transport.h", + "src/core/lib/transport/transport_impl.h", + "src/core/lib/census/aggregation.h", + "src/core/lib/census/mlog.h", + "src/core/lib/census/rpc_metric_id.h", "third_party/nanopb/pb.h", "third_party/nanopb/pb_common.h", "third_party/nanopb/pb_decode.h", "third_party/nanopb/pb_encode.h", - "src/core/surface/init_unsecure.c", - "src/core/census/grpc_context.c", - "src/core/census/grpc_filter.c", - "src/core/census/grpc_plugin.c", - "src/core/channel/channel_args.c", - "src/core/channel/channel_stack.c", - "src/core/channel/channel_stack_builder.c", - "src/core/channel/client_channel.c", - "src/core/channel/compress_filter.c", - "src/core/channel/connected_channel.c", - "src/core/channel/http_client_filter.c", - "src/core/channel/http_server_filter.c", - "src/core/channel/subchannel_call_holder.c", - "src/core/client_config/client_config.c", - "src/core/client_config/connector.c", - "src/core/client_config/default_initial_connect_string.c", - "src/core/client_config/initial_connect_string.c", - "src/core/client_config/lb_policies/load_balancer_api.c", - "src/core/client_config/lb_policies/pick_first.c", - "src/core/client_config/lb_policies/round_robin.c", - "src/core/client_config/lb_policy.c", - "src/core/client_config/lb_policy_factory.c", - "src/core/client_config/lb_policy_registry.c", - "src/core/client_config/resolver.c", - "src/core/client_config/resolver_factory.c", - "src/core/client_config/resolver_registry.c", - "src/core/client_config/resolvers/dns_resolver.c", - "src/core/client_config/resolvers/sockaddr_resolver.c", - "src/core/client_config/subchannel.c", - "src/core/client_config/subchannel_factory.c", - "src/core/client_config/subchannel_index.c", - "src/core/client_config/uri_parser.c", - "src/core/compression/compression_algorithm.c", - "src/core/compression/message_compress.c", - "src/core/debug/trace.c", - "src/core/http/format_request.c", - "src/core/http/httpcli.c", - "src/core/http/parser.c", - "src/core/iomgr/closure.c", - "src/core/iomgr/endpoint.c", - "src/core/iomgr/endpoint_pair_posix.c", - "src/core/iomgr/endpoint_pair_windows.c", - "src/core/iomgr/exec_ctx.c", - "src/core/iomgr/executor.c", - "src/core/iomgr/fd_posix.c", - "src/core/iomgr/iocp_windows.c", - "src/core/iomgr/iomgr.c", - "src/core/iomgr/iomgr_posix.c", - "src/core/iomgr/iomgr_windows.c", - "src/core/iomgr/pollset_multipoller_with_epoll.c", - "src/core/iomgr/pollset_multipoller_with_poll_posix.c", - "src/core/iomgr/pollset_posix.c", - "src/core/iomgr/pollset_set_posix.c", - "src/core/iomgr/pollset_set_windows.c", - "src/core/iomgr/pollset_windows.c", - "src/core/iomgr/resolve_address_posix.c", - "src/core/iomgr/resolve_address_windows.c", - "src/core/iomgr/sockaddr_utils.c", - "src/core/iomgr/socket_utils_common_posix.c", - "src/core/iomgr/socket_utils_linux.c", - "src/core/iomgr/socket_utils_posix.c", - "src/core/iomgr/socket_windows.c", - "src/core/iomgr/tcp_client_posix.c", - "src/core/iomgr/tcp_client_windows.c", - "src/core/iomgr/tcp_posix.c", - "src/core/iomgr/tcp_server_posix.c", - "src/core/iomgr/tcp_server_windows.c", - "src/core/iomgr/tcp_windows.c", - "src/core/iomgr/time_averaged_stats.c", - "src/core/iomgr/timer.c", - "src/core/iomgr/timer_heap.c", - "src/core/iomgr/udp_server.c", - "src/core/iomgr/unix_sockets_posix.c", - "src/core/iomgr/unix_sockets_posix_noop.c", - "src/core/iomgr/wakeup_fd_eventfd.c", - "src/core/iomgr/wakeup_fd_nospecial.c", - "src/core/iomgr/wakeup_fd_pipe.c", - "src/core/iomgr/wakeup_fd_posix.c", - "src/core/iomgr/workqueue_posix.c", - "src/core/iomgr/workqueue_windows.c", - "src/core/json/json.c", - "src/core/json/json_reader.c", - "src/core/json/json_string.c", - "src/core/json/json_writer.c", - "src/core/proto/grpc/lb/v0/load_balancer.pb.c", - "src/core/surface/alarm.c", - "src/core/surface/api_trace.c", - "src/core/surface/byte_buffer.c", - "src/core/surface/byte_buffer_reader.c", - "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/channel_init.c", - "src/core/surface/channel_ping.c", - "src/core/surface/channel_stack_type.c", - "src/core/surface/completion_queue.c", - "src/core/surface/event_string.c", - "src/core/surface/init.c", - "src/core/surface/lame_client.c", - "src/core/surface/metadata_array.c", - "src/core/surface/server.c", - "src/core/surface/server_chttp2.c", - "src/core/surface/validate_metadata.c", - "src/core/surface/version.c", - "src/core/transport/byte_stream.c", - "src/core/transport/chttp2/alpn.c", - "src/core/transport/chttp2/bin_encoder.c", - "src/core/transport/chttp2/frame_data.c", - "src/core/transport/chttp2/frame_goaway.c", - "src/core/transport/chttp2/frame_ping.c", - "src/core/transport/chttp2/frame_rst_stream.c", - "src/core/transport/chttp2/frame_settings.c", - "src/core/transport/chttp2/frame_window_update.c", - "src/core/transport/chttp2/hpack_encoder.c", - "src/core/transport/chttp2/hpack_parser.c", - "src/core/transport/chttp2/hpack_table.c", - "src/core/transport/chttp2/huffsyms.c", - "src/core/transport/chttp2/incoming_metadata.c", - "src/core/transport/chttp2/parsing.c", - "src/core/transport/chttp2/status_conversion.c", - "src/core/transport/chttp2/stream_lists.c", - "src/core/transport/chttp2/stream_map.c", - "src/core/transport/chttp2/timeout_encoding.c", - "src/core/transport/chttp2/varint.c", - "src/core/transport/chttp2/writing.c", - "src/core/transport/chttp2_transport.c", - "src/core/transport/connectivity_state.c", - "src/core/transport/metadata.c", - "src/core/transport/metadata_batch.c", - "src/core/transport/static_metadata.c", - "src/core/transport/transport.c", - "src/core/transport/transport_op_string.c", - "src/core/census/context.c", - "src/core/census/initialize.c", - "src/core/census/mlog.c", - "src/core/census/operation.c", - "src/core/census/placeholders.c", - "src/core/census/tracing.c", + "src/core/lib/surface/init_unsecure.c", + "src/core/lib/census/grpc_context.c", + "src/core/lib/census/grpc_filter.c", + "src/core/lib/census/grpc_plugin.c", + "src/core/lib/channel/channel_args.c", + "src/core/lib/channel/channel_stack.c", + "src/core/lib/channel/channel_stack_builder.c", + "src/core/lib/channel/client_channel.c", + "src/core/lib/channel/compress_filter.c", + "src/core/lib/channel/connected_channel.c", + "src/core/lib/channel/http_client_filter.c", + "src/core/lib/channel/http_server_filter.c", + "src/core/lib/channel/subchannel_call_holder.c", + "src/core/lib/client_config/client_config.c", + "src/core/lib/client_config/connector.c", + "src/core/lib/client_config/default_initial_connect_string.c", + "src/core/lib/client_config/initial_connect_string.c", + "src/core/lib/client_config/lb_policies/load_balancer_api.c", + "src/core/lib/client_config/lb_policies/pick_first.c", + "src/core/lib/client_config/lb_policies/round_robin.c", + "src/core/lib/client_config/lb_policy.c", + "src/core/lib/client_config/lb_policy_factory.c", + "src/core/lib/client_config/lb_policy_registry.c", + "src/core/lib/client_config/resolver.c", + "src/core/lib/client_config/resolver_factory.c", + "src/core/lib/client_config/resolver_registry.c", + "src/core/lib/client_config/resolvers/dns_resolver.c", + "src/core/lib/client_config/resolvers/sockaddr_resolver.c", + "src/core/lib/client_config/subchannel.c", + "src/core/lib/client_config/subchannel_factory.c", + "src/core/lib/client_config/subchannel_index.c", + "src/core/lib/client_config/uri_parser.c", + "src/core/lib/compression/compression_algorithm.c", + "src/core/lib/compression/message_compress.c", + "src/core/lib/debug/trace.c", + "src/core/lib/http/format_request.c", + "src/core/lib/http/httpcli.c", + "src/core/lib/http/parser.c", + "src/core/lib/iomgr/closure.c", + "src/core/lib/iomgr/endpoint.c", + "src/core/lib/iomgr/endpoint_pair_posix.c", + "src/core/lib/iomgr/endpoint_pair_windows.c", + "src/core/lib/iomgr/exec_ctx.c", + "src/core/lib/iomgr/executor.c", + "src/core/lib/iomgr/fd_posix.c", + "src/core/lib/iomgr/iocp_windows.c", + "src/core/lib/iomgr/iomgr.c", + "src/core/lib/iomgr/iomgr_posix.c", + "src/core/lib/iomgr/iomgr_windows.c", + "src/core/lib/iomgr/pollset_multipoller_with_epoll.c", + "src/core/lib/iomgr/pollset_multipoller_with_poll_posix.c", + "src/core/lib/iomgr/pollset_posix.c", + "src/core/lib/iomgr/pollset_set_posix.c", + "src/core/lib/iomgr/pollset_set_windows.c", + "src/core/lib/iomgr/pollset_windows.c", + "src/core/lib/iomgr/resolve_address_posix.c", + "src/core/lib/iomgr/resolve_address_windows.c", + "src/core/lib/iomgr/sockaddr_utils.c", + "src/core/lib/iomgr/socket_utils_common_posix.c", + "src/core/lib/iomgr/socket_utils_linux.c", + "src/core/lib/iomgr/socket_utils_posix.c", + "src/core/lib/iomgr/socket_windows.c", + "src/core/lib/iomgr/tcp_client_posix.c", + "src/core/lib/iomgr/tcp_client_windows.c", + "src/core/lib/iomgr/tcp_posix.c", + "src/core/lib/iomgr/tcp_server_posix.c", + "src/core/lib/iomgr/tcp_server_windows.c", + "src/core/lib/iomgr/tcp_windows.c", + "src/core/lib/iomgr/time_averaged_stats.c", + "src/core/lib/iomgr/timer.c", + "src/core/lib/iomgr/timer_heap.c", + "src/core/lib/iomgr/udp_server.c", + "src/core/lib/iomgr/unix_sockets_posix.c", + "src/core/lib/iomgr/unix_sockets_posix_noop.c", + "src/core/lib/iomgr/wakeup_fd_eventfd.c", + "src/core/lib/iomgr/wakeup_fd_nospecial.c", + "src/core/lib/iomgr/wakeup_fd_pipe.c", + "src/core/lib/iomgr/wakeup_fd_posix.c", + "src/core/lib/iomgr/workqueue_posix.c", + "src/core/lib/iomgr/workqueue_windows.c", + "src/core/lib/json/json.c", + "src/core/lib/json/json_reader.c", + "src/core/lib/json/json_string.c", + "src/core/lib/json/json_writer.c", + "src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c", + "src/core/lib/surface/alarm.c", + "src/core/lib/surface/api_trace.c", + "src/core/lib/surface/byte_buffer.c", + "src/core/lib/surface/byte_buffer_reader.c", + "src/core/lib/surface/call.c", + "src/core/lib/surface/call_details.c", + "src/core/lib/surface/call_log_batch.c", + "src/core/lib/surface/channel.c", + "src/core/lib/surface/channel_connectivity.c", + "src/core/lib/surface/channel_create.c", + "src/core/lib/surface/channel_init.c", + "src/core/lib/surface/channel_ping.c", + "src/core/lib/surface/channel_stack_type.c", + "src/core/lib/surface/completion_queue.c", + "src/core/lib/surface/event_string.c", + "src/core/lib/surface/init.c", + "src/core/lib/surface/lame_client.c", + "src/core/lib/surface/metadata_array.c", + "src/core/lib/surface/server.c", + "src/core/lib/surface/server_chttp2.c", + "src/core/lib/surface/validate_metadata.c", + "src/core/lib/surface/version.c", + "src/core/lib/transport/byte_stream.c", + "src/core/lib/transport/chttp2/alpn.c", + "src/core/lib/transport/chttp2/bin_encoder.c", + "src/core/lib/transport/chttp2/frame_data.c", + "src/core/lib/transport/chttp2/frame_goaway.c", + "src/core/lib/transport/chttp2/frame_ping.c", + "src/core/lib/transport/chttp2/frame_rst_stream.c", + "src/core/lib/transport/chttp2/frame_settings.c", + "src/core/lib/transport/chttp2/frame_window_update.c", + "src/core/lib/transport/chttp2/hpack_encoder.c", + "src/core/lib/transport/chttp2/hpack_parser.c", + "src/core/lib/transport/chttp2/hpack_table.c", + "src/core/lib/transport/chttp2/huffsyms.c", + "src/core/lib/transport/chttp2/incoming_metadata.c", + "src/core/lib/transport/chttp2/parsing.c", + "src/core/lib/transport/chttp2/status_conversion.c", + "src/core/lib/transport/chttp2/stream_lists.c", + "src/core/lib/transport/chttp2/stream_map.c", + "src/core/lib/transport/chttp2/timeout_encoding.c", + "src/core/lib/transport/chttp2/varint.c", + "src/core/lib/transport/chttp2/writing.c", + "src/core/lib/transport/chttp2_transport.c", + "src/core/lib/transport/connectivity_state.c", + "src/core/lib/transport/metadata.c", + "src/core/lib/transport/metadata_batch.c", + "src/core/lib/transport/static_metadata.c", + "src/core/lib/transport/transport.c", + "src/core/lib/transport/transport_op_string.c", + "src/core/lib/census/context.c", + "src/core/lib/census/initialize.c", + "src/core/lib/census/mlog.c", + "src/core/lib/census/operation.c", + "src/core/lib/census/placeholders.c", + "src/core/lib/census/tracing.c", "third_party/nanopb/pb_common.c", "third_party/nanopb/pb_decode.c", "third_party/nanopb/pb_encode.c", @@ -834,8 +834,8 @@ cc_library( cc_library( name = "grpc_zookeeper", srcs = [ - "src/core/client_config/resolvers/zookeeper_resolver.h", - "src/core/client_config/resolvers/zookeeper_resolver.c", + "src/core/lib/client_config/resolvers/zookeeper_resolver.h", + "src/core/lib/client_config/resolvers/zookeeper_resolver.c", ], hdrs = [ "include/grpc/grpc_zookeeper.h", @@ -1248,50 +1248,50 @@ cc_library( objc_library( name = "gpr_objc", srcs = [ - "src/core/profiling/basic_timers.c", - "src/core/profiling/stap_timers.c", - "src/core/support/alloc.c", - "src/core/support/avl.c", - "src/core/support/backoff.c", - "src/core/support/cmdline.c", - "src/core/support/cpu_iphone.c", - "src/core/support/cpu_linux.c", - "src/core/support/cpu_posix.c", - "src/core/support/cpu_windows.c", - "src/core/support/env_linux.c", - "src/core/support/env_posix.c", - "src/core/support/env_win32.c", - "src/core/support/histogram.c", - "src/core/support/host_port.c", - "src/core/support/load_file.c", - "src/core/support/log.c", - "src/core/support/log_android.c", - "src/core/support/log_linux.c", - "src/core/support/log_posix.c", - "src/core/support/log_win32.c", - "src/core/support/murmur_hash.c", - "src/core/support/slice.c", - "src/core/support/slice_buffer.c", - "src/core/support/stack_lockfree.c", - "src/core/support/string.c", - "src/core/support/string_posix.c", - "src/core/support/string_win32.c", - "src/core/support/subprocess_posix.c", - "src/core/support/subprocess_windows.c", - "src/core/support/sync.c", - "src/core/support/sync_posix.c", - "src/core/support/sync_win32.c", - "src/core/support/thd.c", - "src/core/support/thd_posix.c", - "src/core/support/thd_win32.c", - "src/core/support/time.c", - "src/core/support/time_posix.c", - "src/core/support/time_precise.c", - "src/core/support/time_win32.c", - "src/core/support/tls_pthread.c", - "src/core/support/tmpfile_posix.c", - "src/core/support/tmpfile_win32.c", - "src/core/support/wrap_memcpy.c", + "src/core/lib/profiling/basic_timers.c", + "src/core/lib/profiling/stap_timers.c", + "src/core/lib/support/alloc.c", + "src/core/lib/support/avl.c", + "src/core/lib/support/backoff.c", + "src/core/lib/support/cmdline.c", + "src/core/lib/support/cpu_iphone.c", + "src/core/lib/support/cpu_linux.c", + "src/core/lib/support/cpu_posix.c", + "src/core/lib/support/cpu_windows.c", + "src/core/lib/support/env_linux.c", + "src/core/lib/support/env_posix.c", + "src/core/lib/support/env_win32.c", + "src/core/lib/support/histogram.c", + "src/core/lib/support/host_port.c", + "src/core/lib/support/load_file.c", + "src/core/lib/support/log.c", + "src/core/lib/support/log_android.c", + "src/core/lib/support/log_linux.c", + "src/core/lib/support/log_posix.c", + "src/core/lib/support/log_win32.c", + "src/core/lib/support/murmur_hash.c", + "src/core/lib/support/slice.c", + "src/core/lib/support/slice_buffer.c", + "src/core/lib/support/stack_lockfree.c", + "src/core/lib/support/string.c", + "src/core/lib/support/string_posix.c", + "src/core/lib/support/string_win32.c", + "src/core/lib/support/subprocess_posix.c", + "src/core/lib/support/subprocess_windows.c", + "src/core/lib/support/sync.c", + "src/core/lib/support/sync_posix.c", + "src/core/lib/support/sync_win32.c", + "src/core/lib/support/thd.c", + "src/core/lib/support/thd_posix.c", + "src/core/lib/support/thd_win32.c", + "src/core/lib/support/time.c", + "src/core/lib/support/time_posix.c", + "src/core/lib/support/time_precise.c", + "src/core/lib/support/time_win32.c", + "src/core/lib/support/tls_pthread.c", + "src/core/lib/support/tmpfile_posix.c", + "src/core/lib/support/tmpfile_win32.c", + "src/core/lib/support/wrap_memcpy.c", ], hdrs = [ "include/grpc/support/alloc.h", @@ -1336,18 +1336,18 @@ objc_library( "include/grpc/impl/codegen/sync_posix.h", "include/grpc/impl/codegen/sync_win32.h", "include/grpc/impl/codegen/time.h", - "src/core/profiling/timers.h", - "src/core/support/backoff.h", - "src/core/support/block_annotate.h", - "src/core/support/env.h", - "src/core/support/load_file.h", - "src/core/support/murmur_hash.h", - "src/core/support/stack_lockfree.h", - "src/core/support/string.h", - "src/core/support/string_win32.h", - "src/core/support/thd_internal.h", - "src/core/support/time_precise.h", - "src/core/support/tmpfile.h", + "src/core/lib/profiling/timers.h", + "src/core/lib/support/backoff.h", + "src/core/lib/support/block_annotate.h", + "src/core/lib/support/env.h", + "src/core/lib/support/load_file.h", + "src/core/lib/support/murmur_hash.h", + "src/core/lib/support/stack_lockfree.h", + "src/core/lib/support/string.h", + "src/core/lib/support/string_win32.h", + "src/core/lib/support/thd_internal.h", + "src/core/lib/support/time_precise.h", + "src/core/lib/support/tmpfile.h", ], includes = [ "include", @@ -1361,167 +1361,167 @@ objc_library( objc_library( name = "grpc_objc", srcs = [ - "src/core/census/grpc_context.c", - "src/core/census/grpc_filter.c", - "src/core/census/grpc_plugin.c", - "src/core/channel/channel_args.c", - "src/core/channel/channel_stack.c", - "src/core/channel/channel_stack_builder.c", - "src/core/channel/client_channel.c", - "src/core/channel/compress_filter.c", - "src/core/channel/connected_channel.c", - "src/core/channel/http_client_filter.c", - "src/core/channel/http_server_filter.c", - "src/core/channel/subchannel_call_holder.c", - "src/core/client_config/client_config.c", - "src/core/client_config/connector.c", - "src/core/client_config/default_initial_connect_string.c", - "src/core/client_config/initial_connect_string.c", - "src/core/client_config/lb_policies/load_balancer_api.c", - "src/core/client_config/lb_policies/pick_first.c", - "src/core/client_config/lb_policies/round_robin.c", - "src/core/client_config/lb_policy.c", - "src/core/client_config/lb_policy_factory.c", - "src/core/client_config/lb_policy_registry.c", - "src/core/client_config/resolver.c", - "src/core/client_config/resolver_factory.c", - "src/core/client_config/resolver_registry.c", - "src/core/client_config/resolvers/dns_resolver.c", - "src/core/client_config/resolvers/sockaddr_resolver.c", - "src/core/client_config/subchannel.c", - "src/core/client_config/subchannel_factory.c", - "src/core/client_config/subchannel_index.c", - "src/core/client_config/uri_parser.c", - "src/core/compression/compression_algorithm.c", - "src/core/compression/message_compress.c", - "src/core/debug/trace.c", - "src/core/http/format_request.c", - "src/core/http/httpcli.c", - "src/core/http/parser.c", - "src/core/iomgr/closure.c", - "src/core/iomgr/endpoint.c", - "src/core/iomgr/endpoint_pair_posix.c", - "src/core/iomgr/endpoint_pair_windows.c", - "src/core/iomgr/exec_ctx.c", - "src/core/iomgr/executor.c", - "src/core/iomgr/fd_posix.c", - "src/core/iomgr/iocp_windows.c", - "src/core/iomgr/iomgr.c", - "src/core/iomgr/iomgr_posix.c", - "src/core/iomgr/iomgr_windows.c", - "src/core/iomgr/pollset_multipoller_with_epoll.c", - "src/core/iomgr/pollset_multipoller_with_poll_posix.c", - "src/core/iomgr/pollset_posix.c", - "src/core/iomgr/pollset_set_posix.c", - "src/core/iomgr/pollset_set_windows.c", - "src/core/iomgr/pollset_windows.c", - "src/core/iomgr/resolve_address_posix.c", - "src/core/iomgr/resolve_address_windows.c", - "src/core/iomgr/sockaddr_utils.c", - "src/core/iomgr/socket_utils_common_posix.c", - "src/core/iomgr/socket_utils_linux.c", - "src/core/iomgr/socket_utils_posix.c", - "src/core/iomgr/socket_windows.c", - "src/core/iomgr/tcp_client_posix.c", - "src/core/iomgr/tcp_client_windows.c", - "src/core/iomgr/tcp_posix.c", - "src/core/iomgr/tcp_server_posix.c", - "src/core/iomgr/tcp_server_windows.c", - "src/core/iomgr/tcp_windows.c", - "src/core/iomgr/time_averaged_stats.c", - "src/core/iomgr/timer.c", - "src/core/iomgr/timer_heap.c", - "src/core/iomgr/udp_server.c", - "src/core/iomgr/unix_sockets_posix.c", - "src/core/iomgr/unix_sockets_posix_noop.c", - "src/core/iomgr/wakeup_fd_eventfd.c", - "src/core/iomgr/wakeup_fd_nospecial.c", - "src/core/iomgr/wakeup_fd_pipe.c", - "src/core/iomgr/wakeup_fd_posix.c", - "src/core/iomgr/workqueue_posix.c", - "src/core/iomgr/workqueue_windows.c", - "src/core/json/json.c", - "src/core/json/json_reader.c", - "src/core/json/json_string.c", - "src/core/json/json_writer.c", - "src/core/proto/grpc/lb/v0/load_balancer.pb.c", - "src/core/surface/alarm.c", - "src/core/surface/api_trace.c", - "src/core/surface/byte_buffer.c", - "src/core/surface/byte_buffer_reader.c", - "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/channel_init.c", - "src/core/surface/channel_ping.c", - "src/core/surface/channel_stack_type.c", - "src/core/surface/completion_queue.c", - "src/core/surface/event_string.c", - "src/core/surface/init.c", - "src/core/surface/lame_client.c", - "src/core/surface/metadata_array.c", - "src/core/surface/server.c", - "src/core/surface/server_chttp2.c", - "src/core/surface/validate_metadata.c", - "src/core/surface/version.c", - "src/core/transport/byte_stream.c", - "src/core/transport/chttp2/alpn.c", - "src/core/transport/chttp2/bin_encoder.c", - "src/core/transport/chttp2/frame_data.c", - "src/core/transport/chttp2/frame_goaway.c", - "src/core/transport/chttp2/frame_ping.c", - "src/core/transport/chttp2/frame_rst_stream.c", - "src/core/transport/chttp2/frame_settings.c", - "src/core/transport/chttp2/frame_window_update.c", - "src/core/transport/chttp2/hpack_encoder.c", - "src/core/transport/chttp2/hpack_parser.c", - "src/core/transport/chttp2/hpack_table.c", - "src/core/transport/chttp2/huffsyms.c", - "src/core/transport/chttp2/incoming_metadata.c", - "src/core/transport/chttp2/parsing.c", - "src/core/transport/chttp2/status_conversion.c", - "src/core/transport/chttp2/stream_lists.c", - "src/core/transport/chttp2/stream_map.c", - "src/core/transport/chttp2/timeout_encoding.c", - "src/core/transport/chttp2/varint.c", - "src/core/transport/chttp2/writing.c", - "src/core/transport/chttp2_transport.c", - "src/core/transport/connectivity_state.c", - "src/core/transport/metadata.c", - "src/core/transport/metadata_batch.c", - "src/core/transport/static_metadata.c", - "src/core/transport/transport.c", - "src/core/transport/transport_op_string.c", - "src/core/http/httpcli_security_connector.c", - "src/core/security/b64.c", - "src/core/security/client_auth_filter.c", - "src/core/security/credentials.c", - "src/core/security/credentials_metadata.c", - "src/core/security/credentials_posix.c", - "src/core/security/credentials_win32.c", - "src/core/security/google_default_credentials.c", - "src/core/security/handshake.c", - "src/core/security/json_token.c", - "src/core/security/jwt_verifier.c", - "src/core/security/secure_endpoint.c", - "src/core/security/security_connector.c", - "src/core/security/security_context.c", - "src/core/security/server_auth_filter.c", - "src/core/security/server_secure_chttp2.c", - "src/core/surface/init_secure.c", - "src/core/surface/secure_channel_create.c", - "src/core/tsi/fake_transport_security.c", - "src/core/tsi/ssl_transport_security.c", - "src/core/tsi/transport_security.c", - "src/core/census/context.c", - "src/core/census/initialize.c", - "src/core/census/mlog.c", - "src/core/census/operation.c", - "src/core/census/placeholders.c", - "src/core/census/tracing.c", + "src/core/lib/census/grpc_context.c", + "src/core/lib/census/grpc_filter.c", + "src/core/lib/census/grpc_plugin.c", + "src/core/lib/channel/channel_args.c", + "src/core/lib/channel/channel_stack.c", + "src/core/lib/channel/channel_stack_builder.c", + "src/core/lib/channel/client_channel.c", + "src/core/lib/channel/compress_filter.c", + "src/core/lib/channel/connected_channel.c", + "src/core/lib/channel/http_client_filter.c", + "src/core/lib/channel/http_server_filter.c", + "src/core/lib/channel/subchannel_call_holder.c", + "src/core/lib/client_config/client_config.c", + "src/core/lib/client_config/connector.c", + "src/core/lib/client_config/default_initial_connect_string.c", + "src/core/lib/client_config/initial_connect_string.c", + "src/core/lib/client_config/lb_policies/load_balancer_api.c", + "src/core/lib/client_config/lb_policies/pick_first.c", + "src/core/lib/client_config/lb_policies/round_robin.c", + "src/core/lib/client_config/lb_policy.c", + "src/core/lib/client_config/lb_policy_factory.c", + "src/core/lib/client_config/lb_policy_registry.c", + "src/core/lib/client_config/resolver.c", + "src/core/lib/client_config/resolver_factory.c", + "src/core/lib/client_config/resolver_registry.c", + "src/core/lib/client_config/resolvers/dns_resolver.c", + "src/core/lib/client_config/resolvers/sockaddr_resolver.c", + "src/core/lib/client_config/subchannel.c", + "src/core/lib/client_config/subchannel_factory.c", + "src/core/lib/client_config/subchannel_index.c", + "src/core/lib/client_config/uri_parser.c", + "src/core/lib/compression/compression_algorithm.c", + "src/core/lib/compression/message_compress.c", + "src/core/lib/debug/trace.c", + "src/core/lib/http/format_request.c", + "src/core/lib/http/httpcli.c", + "src/core/lib/http/parser.c", + "src/core/lib/iomgr/closure.c", + "src/core/lib/iomgr/endpoint.c", + "src/core/lib/iomgr/endpoint_pair_posix.c", + "src/core/lib/iomgr/endpoint_pair_windows.c", + "src/core/lib/iomgr/exec_ctx.c", + "src/core/lib/iomgr/executor.c", + "src/core/lib/iomgr/fd_posix.c", + "src/core/lib/iomgr/iocp_windows.c", + "src/core/lib/iomgr/iomgr.c", + "src/core/lib/iomgr/iomgr_posix.c", + "src/core/lib/iomgr/iomgr_windows.c", + "src/core/lib/iomgr/pollset_multipoller_with_epoll.c", + "src/core/lib/iomgr/pollset_multipoller_with_poll_posix.c", + "src/core/lib/iomgr/pollset_posix.c", + "src/core/lib/iomgr/pollset_set_posix.c", + "src/core/lib/iomgr/pollset_set_windows.c", + "src/core/lib/iomgr/pollset_windows.c", + "src/core/lib/iomgr/resolve_address_posix.c", + "src/core/lib/iomgr/resolve_address_windows.c", + "src/core/lib/iomgr/sockaddr_utils.c", + "src/core/lib/iomgr/socket_utils_common_posix.c", + "src/core/lib/iomgr/socket_utils_linux.c", + "src/core/lib/iomgr/socket_utils_posix.c", + "src/core/lib/iomgr/socket_windows.c", + "src/core/lib/iomgr/tcp_client_posix.c", + "src/core/lib/iomgr/tcp_client_windows.c", + "src/core/lib/iomgr/tcp_posix.c", + "src/core/lib/iomgr/tcp_server_posix.c", + "src/core/lib/iomgr/tcp_server_windows.c", + "src/core/lib/iomgr/tcp_windows.c", + "src/core/lib/iomgr/time_averaged_stats.c", + "src/core/lib/iomgr/timer.c", + "src/core/lib/iomgr/timer_heap.c", + "src/core/lib/iomgr/udp_server.c", + "src/core/lib/iomgr/unix_sockets_posix.c", + "src/core/lib/iomgr/unix_sockets_posix_noop.c", + "src/core/lib/iomgr/wakeup_fd_eventfd.c", + "src/core/lib/iomgr/wakeup_fd_nospecial.c", + "src/core/lib/iomgr/wakeup_fd_pipe.c", + "src/core/lib/iomgr/wakeup_fd_posix.c", + "src/core/lib/iomgr/workqueue_posix.c", + "src/core/lib/iomgr/workqueue_windows.c", + "src/core/lib/json/json.c", + "src/core/lib/json/json_reader.c", + "src/core/lib/json/json_string.c", + "src/core/lib/json/json_writer.c", + "src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c", + "src/core/lib/surface/alarm.c", + "src/core/lib/surface/api_trace.c", + "src/core/lib/surface/byte_buffer.c", + "src/core/lib/surface/byte_buffer_reader.c", + "src/core/lib/surface/call.c", + "src/core/lib/surface/call_details.c", + "src/core/lib/surface/call_log_batch.c", + "src/core/lib/surface/channel.c", + "src/core/lib/surface/channel_connectivity.c", + "src/core/lib/surface/channel_create.c", + "src/core/lib/surface/channel_init.c", + "src/core/lib/surface/channel_ping.c", + "src/core/lib/surface/channel_stack_type.c", + "src/core/lib/surface/completion_queue.c", + "src/core/lib/surface/event_string.c", + "src/core/lib/surface/init.c", + "src/core/lib/surface/lame_client.c", + "src/core/lib/surface/metadata_array.c", + "src/core/lib/surface/server.c", + "src/core/lib/surface/server_chttp2.c", + "src/core/lib/surface/validate_metadata.c", + "src/core/lib/surface/version.c", + "src/core/lib/transport/byte_stream.c", + "src/core/lib/transport/chttp2/alpn.c", + "src/core/lib/transport/chttp2/bin_encoder.c", + "src/core/lib/transport/chttp2/frame_data.c", + "src/core/lib/transport/chttp2/frame_goaway.c", + "src/core/lib/transport/chttp2/frame_ping.c", + "src/core/lib/transport/chttp2/frame_rst_stream.c", + "src/core/lib/transport/chttp2/frame_settings.c", + "src/core/lib/transport/chttp2/frame_window_update.c", + "src/core/lib/transport/chttp2/hpack_encoder.c", + "src/core/lib/transport/chttp2/hpack_parser.c", + "src/core/lib/transport/chttp2/hpack_table.c", + "src/core/lib/transport/chttp2/huffsyms.c", + "src/core/lib/transport/chttp2/incoming_metadata.c", + "src/core/lib/transport/chttp2/parsing.c", + "src/core/lib/transport/chttp2/status_conversion.c", + "src/core/lib/transport/chttp2/stream_lists.c", + "src/core/lib/transport/chttp2/stream_map.c", + "src/core/lib/transport/chttp2/timeout_encoding.c", + "src/core/lib/transport/chttp2/varint.c", + "src/core/lib/transport/chttp2/writing.c", + "src/core/lib/transport/chttp2_transport.c", + "src/core/lib/transport/connectivity_state.c", + "src/core/lib/transport/metadata.c", + "src/core/lib/transport/metadata_batch.c", + "src/core/lib/transport/static_metadata.c", + "src/core/lib/transport/transport.c", + "src/core/lib/transport/transport_op_string.c", + "src/core/lib/http/httpcli_security_connector.c", + "src/core/lib/security/b64.c", + "src/core/lib/security/client_auth_filter.c", + "src/core/lib/security/credentials.c", + "src/core/lib/security/credentials_metadata.c", + "src/core/lib/security/credentials_posix.c", + "src/core/lib/security/credentials_win32.c", + "src/core/lib/security/google_default_credentials.c", + "src/core/lib/security/handshake.c", + "src/core/lib/security/json_token.c", + "src/core/lib/security/jwt_verifier.c", + "src/core/lib/security/secure_endpoint.c", + "src/core/lib/security/security_connector.c", + "src/core/lib/security/security_context.c", + "src/core/lib/security/server_auth_filter.c", + "src/core/lib/security/server_secure_chttp2.c", + "src/core/lib/surface/init_secure.c", + "src/core/lib/surface/secure_channel_create.c", + "src/core/lib/tsi/fake_transport_security.c", + "src/core/lib/tsi/ssl_transport_security.c", + "src/core/lib/tsi/transport_security.c", + "src/core/lib/census/context.c", + "src/core/lib/census/initialize.c", + "src/core/lib/census/mlog.c", + "src/core/lib/census/operation.c", + "src/core/lib/census/placeholders.c", + "src/core/lib/census/tracing.c", "third_party/nanopb/pb_common.c", "third_party/nanopb/pb_decode.c", "third_party/nanopb/pb_encode.c", @@ -1540,143 +1540,143 @@ objc_library( "include/grpc/impl/codegen/propagation_bits.h", "include/grpc/impl/codegen/status.h", "include/grpc/census.h", - "src/core/census/grpc_filter.h", - "src/core/census/grpc_plugin.h", - "src/core/channel/channel_args.h", - "src/core/channel/channel_stack.h", - "src/core/channel/channel_stack_builder.h", - "src/core/channel/client_channel.h", - "src/core/channel/compress_filter.h", - "src/core/channel/connected_channel.h", - "src/core/channel/context.h", - "src/core/channel/http_client_filter.h", - "src/core/channel/http_server_filter.h", - "src/core/channel/subchannel_call_holder.h", - "src/core/client_config/client_config.h", - "src/core/client_config/connector.h", - "src/core/client_config/initial_connect_string.h", - "src/core/client_config/lb_policies/load_balancer_api.h", - "src/core/client_config/lb_policies/pick_first.h", - "src/core/client_config/lb_policies/round_robin.h", - "src/core/client_config/lb_policy.h", - "src/core/client_config/lb_policy_factory.h", - "src/core/client_config/lb_policy_registry.h", - "src/core/client_config/resolver.h", - "src/core/client_config/resolver_factory.h", - "src/core/client_config/resolver_registry.h", - "src/core/client_config/resolvers/dns_resolver.h", - "src/core/client_config/resolvers/sockaddr_resolver.h", - "src/core/client_config/subchannel.h", - "src/core/client_config/subchannel_factory.h", - "src/core/client_config/subchannel_index.h", - "src/core/client_config/uri_parser.h", - "src/core/compression/algorithm_metadata.h", - "src/core/compression/message_compress.h", - "src/core/debug/trace.h", - "src/core/http/format_request.h", - "src/core/http/httpcli.h", - "src/core/http/parser.h", - "src/core/iomgr/closure.h", - "src/core/iomgr/endpoint.h", - "src/core/iomgr/endpoint_pair.h", - "src/core/iomgr/exec_ctx.h", - "src/core/iomgr/executor.h", - "src/core/iomgr/fd_posix.h", - "src/core/iomgr/iocp_windows.h", - "src/core/iomgr/iomgr.h", - "src/core/iomgr/iomgr_internal.h", - "src/core/iomgr/iomgr_posix.h", - "src/core/iomgr/pollset.h", - "src/core/iomgr/pollset_posix.h", - "src/core/iomgr/pollset_set.h", - "src/core/iomgr/pollset_set_posix.h", - "src/core/iomgr/pollset_set_windows.h", - "src/core/iomgr/pollset_windows.h", - "src/core/iomgr/resolve_address.h", - "src/core/iomgr/sockaddr.h", - "src/core/iomgr/sockaddr_posix.h", - "src/core/iomgr/sockaddr_utils.h", - "src/core/iomgr/sockaddr_win32.h", - "src/core/iomgr/socket_utils_posix.h", - "src/core/iomgr/socket_windows.h", - "src/core/iomgr/tcp_client.h", - "src/core/iomgr/tcp_posix.h", - "src/core/iomgr/tcp_server.h", - "src/core/iomgr/tcp_windows.h", - "src/core/iomgr/time_averaged_stats.h", - "src/core/iomgr/timer.h", - "src/core/iomgr/timer_heap.h", - "src/core/iomgr/udp_server.h", - "src/core/iomgr/unix_sockets_posix.h", - "src/core/iomgr/wakeup_fd_pipe.h", - "src/core/iomgr/wakeup_fd_posix.h", - "src/core/iomgr/workqueue.h", - "src/core/iomgr/workqueue_posix.h", - "src/core/iomgr/workqueue_windows.h", - "src/core/json/json.h", - "src/core/json/json_common.h", - "src/core/json/json_reader.h", - "src/core/json/json_writer.h", - "src/core/proto/grpc/lb/v0/load_balancer.pb.h", - "src/core/statistics/census_interface.h", - "src/core/statistics/census_rpc_stats.h", - "src/core/surface/api_trace.h", - "src/core/surface/call.h", - "src/core/surface/call_test_only.h", - "src/core/surface/channel.h", - "src/core/surface/channel_init.h", - "src/core/surface/channel_stack_type.h", - "src/core/surface/completion_queue.h", - "src/core/surface/event_string.h", - "src/core/surface/init.h", - "src/core/surface/lame_client.h", - "src/core/surface/server.h", - "src/core/surface/surface_trace.h", - "src/core/transport/byte_stream.h", - "src/core/transport/chttp2/alpn.h", - "src/core/transport/chttp2/bin_encoder.h", - "src/core/transport/chttp2/frame.h", - "src/core/transport/chttp2/frame_data.h", - "src/core/transport/chttp2/frame_goaway.h", - "src/core/transport/chttp2/frame_ping.h", - "src/core/transport/chttp2/frame_rst_stream.h", - "src/core/transport/chttp2/frame_settings.h", - "src/core/transport/chttp2/frame_window_update.h", - "src/core/transport/chttp2/hpack_encoder.h", - "src/core/transport/chttp2/hpack_parser.h", - "src/core/transport/chttp2/hpack_table.h", - "src/core/transport/chttp2/http2_errors.h", - "src/core/transport/chttp2/huffsyms.h", - "src/core/transport/chttp2/incoming_metadata.h", - "src/core/transport/chttp2/internal.h", - "src/core/transport/chttp2/status_conversion.h", - "src/core/transport/chttp2/stream_map.h", - "src/core/transport/chttp2/timeout_encoding.h", - "src/core/transport/chttp2/varint.h", - "src/core/transport/chttp2_transport.h", - "src/core/transport/connectivity_state.h", - "src/core/transport/metadata.h", - "src/core/transport/metadata_batch.h", - "src/core/transport/static_metadata.h", - "src/core/transport/transport.h", - "src/core/transport/transport_impl.h", - "src/core/security/auth_filters.h", - "src/core/security/b64.h", - "src/core/security/credentials.h", - "src/core/security/handshake.h", - "src/core/security/json_token.h", - "src/core/security/jwt_verifier.h", - "src/core/security/secure_endpoint.h", - "src/core/security/security_connector.h", - "src/core/security/security_context.h", - "src/core/tsi/fake_transport_security.h", - "src/core/tsi/ssl_transport_security.h", - "src/core/tsi/ssl_types.h", - "src/core/tsi/transport_security.h", - "src/core/tsi/transport_security_interface.h", - "src/core/census/aggregation.h", - "src/core/census/mlog.h", - "src/core/census/rpc_metric_id.h", + "src/core/lib/census/grpc_filter.h", + "src/core/lib/census/grpc_plugin.h", + "src/core/lib/channel/channel_args.h", + "src/core/lib/channel/channel_stack.h", + "src/core/lib/channel/channel_stack_builder.h", + "src/core/lib/channel/client_channel.h", + "src/core/lib/channel/compress_filter.h", + "src/core/lib/channel/connected_channel.h", + "src/core/lib/channel/context.h", + "src/core/lib/channel/http_client_filter.h", + "src/core/lib/channel/http_server_filter.h", + "src/core/lib/channel/subchannel_call_holder.h", + "src/core/lib/client_config/client_config.h", + "src/core/lib/client_config/connector.h", + "src/core/lib/client_config/initial_connect_string.h", + "src/core/lib/client_config/lb_policies/load_balancer_api.h", + "src/core/lib/client_config/lb_policies/pick_first.h", + "src/core/lib/client_config/lb_policies/round_robin.h", + "src/core/lib/client_config/lb_policy.h", + "src/core/lib/client_config/lb_policy_factory.h", + "src/core/lib/client_config/lb_policy_registry.h", + "src/core/lib/client_config/resolver.h", + "src/core/lib/client_config/resolver_factory.h", + "src/core/lib/client_config/resolver_registry.h", + "src/core/lib/client_config/resolvers/dns_resolver.h", + "src/core/lib/client_config/resolvers/sockaddr_resolver.h", + "src/core/lib/client_config/subchannel.h", + "src/core/lib/client_config/subchannel_factory.h", + "src/core/lib/client_config/subchannel_index.h", + "src/core/lib/client_config/uri_parser.h", + "src/core/lib/compression/algorithm_metadata.h", + "src/core/lib/compression/message_compress.h", + "src/core/lib/debug/trace.h", + "src/core/lib/http/format_request.h", + "src/core/lib/http/httpcli.h", + "src/core/lib/http/parser.h", + "src/core/lib/iomgr/closure.h", + "src/core/lib/iomgr/endpoint.h", + "src/core/lib/iomgr/endpoint_pair.h", + "src/core/lib/iomgr/exec_ctx.h", + "src/core/lib/iomgr/executor.h", + "src/core/lib/iomgr/fd_posix.h", + "src/core/lib/iomgr/iocp_windows.h", + "src/core/lib/iomgr/iomgr.h", + "src/core/lib/iomgr/iomgr_internal.h", + "src/core/lib/iomgr/iomgr_posix.h", + "src/core/lib/iomgr/pollset.h", + "src/core/lib/iomgr/pollset_posix.h", + "src/core/lib/iomgr/pollset_set.h", + "src/core/lib/iomgr/pollset_set_posix.h", + "src/core/lib/iomgr/pollset_set_windows.h", + "src/core/lib/iomgr/pollset_windows.h", + "src/core/lib/iomgr/resolve_address.h", + "src/core/lib/iomgr/sockaddr.h", + "src/core/lib/iomgr/sockaddr_posix.h", + "src/core/lib/iomgr/sockaddr_utils.h", + "src/core/lib/iomgr/sockaddr_win32.h", + "src/core/lib/iomgr/socket_utils_posix.h", + "src/core/lib/iomgr/socket_windows.h", + "src/core/lib/iomgr/tcp_client.h", + "src/core/lib/iomgr/tcp_posix.h", + "src/core/lib/iomgr/tcp_server.h", + "src/core/lib/iomgr/tcp_windows.h", + "src/core/lib/iomgr/time_averaged_stats.h", + "src/core/lib/iomgr/timer.h", + "src/core/lib/iomgr/timer_heap.h", + "src/core/lib/iomgr/udp_server.h", + "src/core/lib/iomgr/unix_sockets_posix.h", + "src/core/lib/iomgr/wakeup_fd_pipe.h", + "src/core/lib/iomgr/wakeup_fd_posix.h", + "src/core/lib/iomgr/workqueue.h", + "src/core/lib/iomgr/workqueue_posix.h", + "src/core/lib/iomgr/workqueue_windows.h", + "src/core/lib/json/json.h", + "src/core/lib/json/json_common.h", + "src/core/lib/json/json_reader.h", + "src/core/lib/json/json_writer.h", + "src/core/lib/proto/grpc/lb/v0/load_balancer.pb.h", + "src/core/lib/statistics/census_interface.h", + "src/core/lib/statistics/census_rpc_stats.h", + "src/core/lib/surface/api_trace.h", + "src/core/lib/surface/call.h", + "src/core/lib/surface/call_test_only.h", + "src/core/lib/surface/channel.h", + "src/core/lib/surface/channel_init.h", + "src/core/lib/surface/channel_stack_type.h", + "src/core/lib/surface/completion_queue.h", + "src/core/lib/surface/event_string.h", + "src/core/lib/surface/init.h", + "src/core/lib/surface/lame_client.h", + "src/core/lib/surface/server.h", + "src/core/lib/surface/surface_trace.h", + "src/core/lib/transport/byte_stream.h", + "src/core/lib/transport/chttp2/alpn.h", + "src/core/lib/transport/chttp2/bin_encoder.h", + "src/core/lib/transport/chttp2/frame.h", + "src/core/lib/transport/chttp2/frame_data.h", + "src/core/lib/transport/chttp2/frame_goaway.h", + "src/core/lib/transport/chttp2/frame_ping.h", + "src/core/lib/transport/chttp2/frame_rst_stream.h", + "src/core/lib/transport/chttp2/frame_settings.h", + "src/core/lib/transport/chttp2/frame_window_update.h", + "src/core/lib/transport/chttp2/hpack_encoder.h", + "src/core/lib/transport/chttp2/hpack_parser.h", + "src/core/lib/transport/chttp2/hpack_table.h", + "src/core/lib/transport/chttp2/http2_errors.h", + "src/core/lib/transport/chttp2/huffsyms.h", + "src/core/lib/transport/chttp2/incoming_metadata.h", + "src/core/lib/transport/chttp2/internal.h", + "src/core/lib/transport/chttp2/status_conversion.h", + "src/core/lib/transport/chttp2/stream_map.h", + "src/core/lib/transport/chttp2/timeout_encoding.h", + "src/core/lib/transport/chttp2/varint.h", + "src/core/lib/transport/chttp2_transport.h", + "src/core/lib/transport/connectivity_state.h", + "src/core/lib/transport/metadata.h", + "src/core/lib/transport/metadata_batch.h", + "src/core/lib/transport/static_metadata.h", + "src/core/lib/transport/transport.h", + "src/core/lib/transport/transport_impl.h", + "src/core/lib/security/auth_filters.h", + "src/core/lib/security/b64.h", + "src/core/lib/security/credentials.h", + "src/core/lib/security/handshake.h", + "src/core/lib/security/json_token.h", + "src/core/lib/security/jwt_verifier.h", + "src/core/lib/security/secure_endpoint.h", + "src/core/lib/security/security_connector.h", + "src/core/lib/security/security_context.h", + "src/core/lib/tsi/fake_transport_security.h", + "src/core/lib/tsi/ssl_transport_security.h", + "src/core/lib/tsi/ssl_types.h", + "src/core/lib/tsi/transport_security.h", + "src/core/lib/tsi/transport_security_interface.h", + "src/core/lib/census/aggregation.h", + "src/core/lib/census/mlog.h", + "src/core/lib/census/rpc_metric_id.h", "third_party/nanopb/pb.h", "third_party/nanopb/pb_common.h", "third_party/nanopb/pb_decode.h", diff --git a/Makefile b/Makefile index 6c100f6cbd..112b7f8777 100644 --- a/Makefile +++ b/Makefile @@ -2268,50 +2268,50 @@ clean: LIBGPR_SRC = \ - src/core/profiling/basic_timers.c \ - src/core/profiling/stap_timers.c \ - src/core/support/alloc.c \ - src/core/support/avl.c \ - src/core/support/backoff.c \ - src/core/support/cmdline.c \ - src/core/support/cpu_iphone.c \ - src/core/support/cpu_linux.c \ - src/core/support/cpu_posix.c \ - src/core/support/cpu_windows.c \ - src/core/support/env_linux.c \ - src/core/support/env_posix.c \ - src/core/support/env_win32.c \ - src/core/support/histogram.c \ - src/core/support/host_port.c \ - src/core/support/load_file.c \ - src/core/support/log.c \ - src/core/support/log_android.c \ - src/core/support/log_linux.c \ - src/core/support/log_posix.c \ - src/core/support/log_win32.c \ - src/core/support/murmur_hash.c \ - src/core/support/slice.c \ - src/core/support/slice_buffer.c \ - src/core/support/stack_lockfree.c \ - src/core/support/string.c \ - src/core/support/string_posix.c \ - src/core/support/string_win32.c \ - src/core/support/subprocess_posix.c \ - src/core/support/subprocess_windows.c \ - src/core/support/sync.c \ - src/core/support/sync_posix.c \ - src/core/support/sync_win32.c \ - src/core/support/thd.c \ - src/core/support/thd_posix.c \ - src/core/support/thd_win32.c \ - src/core/support/time.c \ - src/core/support/time_posix.c \ - src/core/support/time_precise.c \ - src/core/support/time_win32.c \ - src/core/support/tls_pthread.c \ - src/core/support/tmpfile_posix.c \ - src/core/support/tmpfile_win32.c \ - src/core/support/wrap_memcpy.c \ + src/core/lib/profiling/basic_timers.c \ + src/core/lib/profiling/stap_timers.c \ + src/core/lib/support/alloc.c \ + src/core/lib/support/avl.c \ + src/core/lib/support/backoff.c \ + src/core/lib/support/cmdline.c \ + src/core/lib/support/cpu_iphone.c \ + src/core/lib/support/cpu_linux.c \ + src/core/lib/support/cpu_posix.c \ + src/core/lib/support/cpu_windows.c \ + src/core/lib/support/env_linux.c \ + src/core/lib/support/env_posix.c \ + src/core/lib/support/env_win32.c \ + src/core/lib/support/histogram.c \ + src/core/lib/support/host_port.c \ + src/core/lib/support/load_file.c \ + src/core/lib/support/log.c \ + src/core/lib/support/log_android.c \ + src/core/lib/support/log_linux.c \ + src/core/lib/support/log_posix.c \ + src/core/lib/support/log_win32.c \ + src/core/lib/support/murmur_hash.c \ + src/core/lib/support/slice.c \ + src/core/lib/support/slice_buffer.c \ + src/core/lib/support/stack_lockfree.c \ + src/core/lib/support/string.c \ + src/core/lib/support/string_posix.c \ + src/core/lib/support/string_win32.c \ + src/core/lib/support/subprocess_posix.c \ + src/core/lib/support/subprocess_windows.c \ + src/core/lib/support/sync.c \ + src/core/lib/support/sync_posix.c \ + src/core/lib/support/sync_win32.c \ + src/core/lib/support/thd.c \ + src/core/lib/support/thd_posix.c \ + src/core/lib/support/thd_win32.c \ + src/core/lib/support/time.c \ + src/core/lib/support/time_posix.c \ + src/core/lib/support/time_precise.c \ + src/core/lib/support/time_win32.c \ + src/core/lib/support/tls_pthread.c \ + src/core/lib/support/tmpfile_posix.c \ + src/core/lib/support/tmpfile_win32.c \ + src/core/lib/support/wrap_memcpy.c \ PUBLIC_HEADERS_C += \ include/grpc/support/alloc.h \ @@ -2419,167 +2419,167 @@ endif LIBGRPC_SRC = \ - src/core/census/grpc_context.c \ - src/core/census/grpc_filter.c \ - src/core/census/grpc_plugin.c \ - src/core/channel/channel_args.c \ - src/core/channel/channel_stack.c \ - src/core/channel/channel_stack_builder.c \ - src/core/channel/client_channel.c \ - src/core/channel/compress_filter.c \ - src/core/channel/connected_channel.c \ - src/core/channel/http_client_filter.c \ - src/core/channel/http_server_filter.c \ - src/core/channel/subchannel_call_holder.c \ - src/core/client_config/client_config.c \ - src/core/client_config/connector.c \ - src/core/client_config/default_initial_connect_string.c \ - src/core/client_config/initial_connect_string.c \ - src/core/client_config/lb_policies/load_balancer_api.c \ - src/core/client_config/lb_policies/pick_first.c \ - src/core/client_config/lb_policies/round_robin.c \ - src/core/client_config/lb_policy.c \ - src/core/client_config/lb_policy_factory.c \ - src/core/client_config/lb_policy_registry.c \ - src/core/client_config/resolver.c \ - src/core/client_config/resolver_factory.c \ - src/core/client_config/resolver_registry.c \ - src/core/client_config/resolvers/dns_resolver.c \ - src/core/client_config/resolvers/sockaddr_resolver.c \ - src/core/client_config/subchannel.c \ - src/core/client_config/subchannel_factory.c \ - src/core/client_config/subchannel_index.c \ - src/core/client_config/uri_parser.c \ - src/core/compression/compression_algorithm.c \ - src/core/compression/message_compress.c \ - src/core/debug/trace.c \ - src/core/http/format_request.c \ - src/core/http/httpcli.c \ - src/core/http/parser.c \ - src/core/iomgr/closure.c \ - src/core/iomgr/endpoint.c \ - src/core/iomgr/endpoint_pair_posix.c \ - src/core/iomgr/endpoint_pair_windows.c \ - src/core/iomgr/exec_ctx.c \ - src/core/iomgr/executor.c \ - src/core/iomgr/fd_posix.c \ - src/core/iomgr/iocp_windows.c \ - src/core/iomgr/iomgr.c \ - src/core/iomgr/iomgr_posix.c \ - src/core/iomgr/iomgr_windows.c \ - src/core/iomgr/pollset_multipoller_with_epoll.c \ - src/core/iomgr/pollset_multipoller_with_poll_posix.c \ - src/core/iomgr/pollset_posix.c \ - src/core/iomgr/pollset_set_posix.c \ - src/core/iomgr/pollset_set_windows.c \ - src/core/iomgr/pollset_windows.c \ - src/core/iomgr/resolve_address_posix.c \ - src/core/iomgr/resolve_address_windows.c \ - src/core/iomgr/sockaddr_utils.c \ - src/core/iomgr/socket_utils_common_posix.c \ - src/core/iomgr/socket_utils_linux.c \ - src/core/iomgr/socket_utils_posix.c \ - src/core/iomgr/socket_windows.c \ - src/core/iomgr/tcp_client_posix.c \ - src/core/iomgr/tcp_client_windows.c \ - src/core/iomgr/tcp_posix.c \ - src/core/iomgr/tcp_server_posix.c \ - src/core/iomgr/tcp_server_windows.c \ - src/core/iomgr/tcp_windows.c \ - src/core/iomgr/time_averaged_stats.c \ - src/core/iomgr/timer.c \ - src/core/iomgr/timer_heap.c \ - src/core/iomgr/udp_server.c \ - src/core/iomgr/unix_sockets_posix.c \ - src/core/iomgr/unix_sockets_posix_noop.c \ - src/core/iomgr/wakeup_fd_eventfd.c \ - src/core/iomgr/wakeup_fd_nospecial.c \ - src/core/iomgr/wakeup_fd_pipe.c \ - src/core/iomgr/wakeup_fd_posix.c \ - src/core/iomgr/workqueue_posix.c \ - src/core/iomgr/workqueue_windows.c \ - src/core/json/json.c \ - src/core/json/json_reader.c \ - src/core/json/json_string.c \ - src/core/json/json_writer.c \ - src/core/proto/grpc/lb/v0/load_balancer.pb.c \ - src/core/surface/alarm.c \ - src/core/surface/api_trace.c \ - src/core/surface/byte_buffer.c \ - src/core/surface/byte_buffer_reader.c \ - 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/channel_init.c \ - src/core/surface/channel_ping.c \ - src/core/surface/channel_stack_type.c \ - src/core/surface/completion_queue.c \ - src/core/surface/event_string.c \ - src/core/surface/init.c \ - src/core/surface/lame_client.c \ - src/core/surface/metadata_array.c \ - src/core/surface/server.c \ - src/core/surface/server_chttp2.c \ - src/core/surface/validate_metadata.c \ - src/core/surface/version.c \ - src/core/transport/byte_stream.c \ - src/core/transport/chttp2/alpn.c \ - src/core/transport/chttp2/bin_encoder.c \ - src/core/transport/chttp2/frame_data.c \ - src/core/transport/chttp2/frame_goaway.c \ - src/core/transport/chttp2/frame_ping.c \ - src/core/transport/chttp2/frame_rst_stream.c \ - src/core/transport/chttp2/frame_settings.c \ - src/core/transport/chttp2/frame_window_update.c \ - src/core/transport/chttp2/hpack_encoder.c \ - src/core/transport/chttp2/hpack_parser.c \ - src/core/transport/chttp2/hpack_table.c \ - src/core/transport/chttp2/huffsyms.c \ - src/core/transport/chttp2/incoming_metadata.c \ - src/core/transport/chttp2/parsing.c \ - src/core/transport/chttp2/status_conversion.c \ - src/core/transport/chttp2/stream_lists.c \ - src/core/transport/chttp2/stream_map.c \ - src/core/transport/chttp2/timeout_encoding.c \ - src/core/transport/chttp2/varint.c \ - src/core/transport/chttp2/writing.c \ - src/core/transport/chttp2_transport.c \ - src/core/transport/connectivity_state.c \ - src/core/transport/metadata.c \ - src/core/transport/metadata_batch.c \ - src/core/transport/static_metadata.c \ - src/core/transport/transport.c \ - src/core/transport/transport_op_string.c \ - src/core/http/httpcli_security_connector.c \ - src/core/security/b64.c \ - src/core/security/client_auth_filter.c \ - src/core/security/credentials.c \ - src/core/security/credentials_metadata.c \ - src/core/security/credentials_posix.c \ - src/core/security/credentials_win32.c \ - src/core/security/google_default_credentials.c \ - src/core/security/handshake.c \ - src/core/security/json_token.c \ - src/core/security/jwt_verifier.c \ - src/core/security/secure_endpoint.c \ - src/core/security/security_connector.c \ - src/core/security/security_context.c \ - src/core/security/server_auth_filter.c \ - src/core/security/server_secure_chttp2.c \ - src/core/surface/init_secure.c \ - src/core/surface/secure_channel_create.c \ - src/core/tsi/fake_transport_security.c \ - src/core/tsi/ssl_transport_security.c \ - src/core/tsi/transport_security.c \ - src/core/census/context.c \ - src/core/census/initialize.c \ - src/core/census/mlog.c \ - src/core/census/operation.c \ - src/core/census/placeholders.c \ - src/core/census/tracing.c \ + src/core/lib/census/grpc_context.c \ + src/core/lib/census/grpc_filter.c \ + src/core/lib/census/grpc_plugin.c \ + src/core/lib/channel/channel_args.c \ + src/core/lib/channel/channel_stack.c \ + src/core/lib/channel/channel_stack_builder.c \ + src/core/lib/channel/client_channel.c \ + src/core/lib/channel/compress_filter.c \ + src/core/lib/channel/connected_channel.c \ + src/core/lib/channel/http_client_filter.c \ + src/core/lib/channel/http_server_filter.c \ + src/core/lib/channel/subchannel_call_holder.c \ + src/core/lib/client_config/client_config.c \ + src/core/lib/client_config/connector.c \ + src/core/lib/client_config/default_initial_connect_string.c \ + src/core/lib/client_config/initial_connect_string.c \ + src/core/lib/client_config/lb_policies/load_balancer_api.c \ + src/core/lib/client_config/lb_policies/pick_first.c \ + src/core/lib/client_config/lb_policies/round_robin.c \ + src/core/lib/client_config/lb_policy.c \ + src/core/lib/client_config/lb_policy_factory.c \ + src/core/lib/client_config/lb_policy_registry.c \ + src/core/lib/client_config/resolver.c \ + src/core/lib/client_config/resolver_factory.c \ + src/core/lib/client_config/resolver_registry.c \ + src/core/lib/client_config/resolvers/dns_resolver.c \ + src/core/lib/client_config/resolvers/sockaddr_resolver.c \ + src/core/lib/client_config/subchannel.c \ + src/core/lib/client_config/subchannel_factory.c \ + src/core/lib/client_config/subchannel_index.c \ + src/core/lib/client_config/uri_parser.c \ + src/core/lib/compression/compression_algorithm.c \ + src/core/lib/compression/message_compress.c \ + src/core/lib/debug/trace.c \ + src/core/lib/http/format_request.c \ + src/core/lib/http/httpcli.c \ + src/core/lib/http/parser.c \ + src/core/lib/iomgr/closure.c \ + src/core/lib/iomgr/endpoint.c \ + src/core/lib/iomgr/endpoint_pair_posix.c \ + src/core/lib/iomgr/endpoint_pair_windows.c \ + src/core/lib/iomgr/exec_ctx.c \ + src/core/lib/iomgr/executor.c \ + src/core/lib/iomgr/fd_posix.c \ + src/core/lib/iomgr/iocp_windows.c \ + src/core/lib/iomgr/iomgr.c \ + src/core/lib/iomgr/iomgr_posix.c \ + src/core/lib/iomgr/iomgr_windows.c \ + src/core/lib/iomgr/pollset_multipoller_with_epoll.c \ + src/core/lib/iomgr/pollset_multipoller_with_poll_posix.c \ + src/core/lib/iomgr/pollset_posix.c \ + src/core/lib/iomgr/pollset_set_posix.c \ + src/core/lib/iomgr/pollset_set_windows.c \ + src/core/lib/iomgr/pollset_windows.c \ + src/core/lib/iomgr/resolve_address_posix.c \ + src/core/lib/iomgr/resolve_address_windows.c \ + src/core/lib/iomgr/sockaddr_utils.c \ + src/core/lib/iomgr/socket_utils_common_posix.c \ + src/core/lib/iomgr/socket_utils_linux.c \ + src/core/lib/iomgr/socket_utils_posix.c \ + src/core/lib/iomgr/socket_windows.c \ + src/core/lib/iomgr/tcp_client_posix.c \ + src/core/lib/iomgr/tcp_client_windows.c \ + src/core/lib/iomgr/tcp_posix.c \ + src/core/lib/iomgr/tcp_server_posix.c \ + src/core/lib/iomgr/tcp_server_windows.c \ + src/core/lib/iomgr/tcp_windows.c \ + src/core/lib/iomgr/time_averaged_stats.c \ + src/core/lib/iomgr/timer.c \ + src/core/lib/iomgr/timer_heap.c \ + src/core/lib/iomgr/udp_server.c \ + src/core/lib/iomgr/unix_sockets_posix.c \ + src/core/lib/iomgr/unix_sockets_posix_noop.c \ + src/core/lib/iomgr/wakeup_fd_eventfd.c \ + src/core/lib/iomgr/wakeup_fd_nospecial.c \ + src/core/lib/iomgr/wakeup_fd_pipe.c \ + src/core/lib/iomgr/wakeup_fd_posix.c \ + src/core/lib/iomgr/workqueue_posix.c \ + src/core/lib/iomgr/workqueue_windows.c \ + src/core/lib/json/json.c \ + src/core/lib/json/json_reader.c \ + src/core/lib/json/json_string.c \ + src/core/lib/json/json_writer.c \ + src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c \ + src/core/lib/surface/alarm.c \ + src/core/lib/surface/api_trace.c \ + src/core/lib/surface/byte_buffer.c \ + src/core/lib/surface/byte_buffer_reader.c \ + src/core/lib/surface/call.c \ + src/core/lib/surface/call_details.c \ + src/core/lib/surface/call_log_batch.c \ + src/core/lib/surface/channel.c \ + src/core/lib/surface/channel_connectivity.c \ + src/core/lib/surface/channel_create.c \ + src/core/lib/surface/channel_init.c \ + src/core/lib/surface/channel_ping.c \ + src/core/lib/surface/channel_stack_type.c \ + src/core/lib/surface/completion_queue.c \ + src/core/lib/surface/event_string.c \ + src/core/lib/surface/init.c \ + src/core/lib/surface/lame_client.c \ + src/core/lib/surface/metadata_array.c \ + src/core/lib/surface/server.c \ + src/core/lib/surface/server_chttp2.c \ + src/core/lib/surface/validate_metadata.c \ + src/core/lib/surface/version.c \ + src/core/lib/transport/byte_stream.c \ + src/core/lib/transport/chttp2/alpn.c \ + src/core/lib/transport/chttp2/bin_encoder.c \ + src/core/lib/transport/chttp2/frame_data.c \ + src/core/lib/transport/chttp2/frame_goaway.c \ + src/core/lib/transport/chttp2/frame_ping.c \ + src/core/lib/transport/chttp2/frame_rst_stream.c \ + src/core/lib/transport/chttp2/frame_settings.c \ + src/core/lib/transport/chttp2/frame_window_update.c \ + src/core/lib/transport/chttp2/hpack_encoder.c \ + src/core/lib/transport/chttp2/hpack_parser.c \ + src/core/lib/transport/chttp2/hpack_table.c \ + src/core/lib/transport/chttp2/huffsyms.c \ + src/core/lib/transport/chttp2/incoming_metadata.c \ + src/core/lib/transport/chttp2/parsing.c \ + src/core/lib/transport/chttp2/status_conversion.c \ + src/core/lib/transport/chttp2/stream_lists.c \ + src/core/lib/transport/chttp2/stream_map.c \ + src/core/lib/transport/chttp2/timeout_encoding.c \ + src/core/lib/transport/chttp2/varint.c \ + src/core/lib/transport/chttp2/writing.c \ + src/core/lib/transport/chttp2_transport.c \ + src/core/lib/transport/connectivity_state.c \ + src/core/lib/transport/metadata.c \ + src/core/lib/transport/metadata_batch.c \ + src/core/lib/transport/static_metadata.c \ + src/core/lib/transport/transport.c \ + src/core/lib/transport/transport_op_string.c \ + src/core/lib/http/httpcli_security_connector.c \ + src/core/lib/security/b64.c \ + src/core/lib/security/client_auth_filter.c \ + src/core/lib/security/credentials.c \ + src/core/lib/security/credentials_metadata.c \ + src/core/lib/security/credentials_posix.c \ + src/core/lib/security/credentials_win32.c \ + src/core/lib/security/google_default_credentials.c \ + src/core/lib/security/handshake.c \ + src/core/lib/security/json_token.c \ + src/core/lib/security/jwt_verifier.c \ + src/core/lib/security/secure_endpoint.c \ + src/core/lib/security/security_connector.c \ + src/core/lib/security/security_context.c \ + src/core/lib/security/server_auth_filter.c \ + src/core/lib/security/server_secure_chttp2.c \ + src/core/lib/surface/init_secure.c \ + src/core/lib/surface/secure_channel_create.c \ + src/core/lib/tsi/fake_transport_security.c \ + src/core/lib/tsi/ssl_transport_security.c \ + src/core/lib/tsi/transport_security.c \ + src/core/lib/census/context.c \ + src/core/lib/census/initialize.c \ + src/core/lib/census/mlog.c \ + src/core/lib/census/operation.c \ + src/core/lib/census/placeholders.c \ + src/core/lib/census/tracing.c \ third_party/nanopb/pb_common.c \ third_party/nanopb/pb_decode.c \ third_party/nanopb/pb_encode.c \ @@ -2780,147 +2780,147 @@ endif LIBGRPC_UNSECURE_SRC = \ - src/core/surface/init_unsecure.c \ - src/core/census/grpc_context.c \ - src/core/census/grpc_filter.c \ - src/core/census/grpc_plugin.c \ - src/core/channel/channel_args.c \ - src/core/channel/channel_stack.c \ - src/core/channel/channel_stack_builder.c \ - src/core/channel/client_channel.c \ - src/core/channel/compress_filter.c \ - src/core/channel/connected_channel.c \ - src/core/channel/http_client_filter.c \ - src/core/channel/http_server_filter.c \ - src/core/channel/subchannel_call_holder.c \ - src/core/client_config/client_config.c \ - src/core/client_config/connector.c \ - src/core/client_config/default_initial_connect_string.c \ - src/core/client_config/initial_connect_string.c \ - src/core/client_config/lb_policies/load_balancer_api.c \ - src/core/client_config/lb_policies/pick_first.c \ - src/core/client_config/lb_policies/round_robin.c \ - src/core/client_config/lb_policy.c \ - src/core/client_config/lb_policy_factory.c \ - src/core/client_config/lb_policy_registry.c \ - src/core/client_config/resolver.c \ - src/core/client_config/resolver_factory.c \ - src/core/client_config/resolver_registry.c \ - src/core/client_config/resolvers/dns_resolver.c \ - src/core/client_config/resolvers/sockaddr_resolver.c \ - src/core/client_config/subchannel.c \ - src/core/client_config/subchannel_factory.c \ - src/core/client_config/subchannel_index.c \ - src/core/client_config/uri_parser.c \ - src/core/compression/compression_algorithm.c \ - src/core/compression/message_compress.c \ - src/core/debug/trace.c \ - src/core/http/format_request.c \ - src/core/http/httpcli.c \ - src/core/http/parser.c \ - src/core/iomgr/closure.c \ - src/core/iomgr/endpoint.c \ - src/core/iomgr/endpoint_pair_posix.c \ - src/core/iomgr/endpoint_pair_windows.c \ - src/core/iomgr/exec_ctx.c \ - src/core/iomgr/executor.c \ - src/core/iomgr/fd_posix.c \ - src/core/iomgr/iocp_windows.c \ - src/core/iomgr/iomgr.c \ - src/core/iomgr/iomgr_posix.c \ - src/core/iomgr/iomgr_windows.c \ - src/core/iomgr/pollset_multipoller_with_epoll.c \ - src/core/iomgr/pollset_multipoller_with_poll_posix.c \ - src/core/iomgr/pollset_posix.c \ - src/core/iomgr/pollset_set_posix.c \ - src/core/iomgr/pollset_set_windows.c \ - src/core/iomgr/pollset_windows.c \ - src/core/iomgr/resolve_address_posix.c \ - src/core/iomgr/resolve_address_windows.c \ - src/core/iomgr/sockaddr_utils.c \ - src/core/iomgr/socket_utils_common_posix.c \ - src/core/iomgr/socket_utils_linux.c \ - src/core/iomgr/socket_utils_posix.c \ - src/core/iomgr/socket_windows.c \ - src/core/iomgr/tcp_client_posix.c \ - src/core/iomgr/tcp_client_windows.c \ - src/core/iomgr/tcp_posix.c \ - src/core/iomgr/tcp_server_posix.c \ - src/core/iomgr/tcp_server_windows.c \ - src/core/iomgr/tcp_windows.c \ - src/core/iomgr/time_averaged_stats.c \ - src/core/iomgr/timer.c \ - src/core/iomgr/timer_heap.c \ - src/core/iomgr/udp_server.c \ - src/core/iomgr/unix_sockets_posix.c \ - src/core/iomgr/unix_sockets_posix_noop.c \ - src/core/iomgr/wakeup_fd_eventfd.c \ - src/core/iomgr/wakeup_fd_nospecial.c \ - src/core/iomgr/wakeup_fd_pipe.c \ - src/core/iomgr/wakeup_fd_posix.c \ - src/core/iomgr/workqueue_posix.c \ - src/core/iomgr/workqueue_windows.c \ - src/core/json/json.c \ - src/core/json/json_reader.c \ - src/core/json/json_string.c \ - src/core/json/json_writer.c \ - src/core/proto/grpc/lb/v0/load_balancer.pb.c \ - src/core/surface/alarm.c \ - src/core/surface/api_trace.c \ - src/core/surface/byte_buffer.c \ - src/core/surface/byte_buffer_reader.c \ - 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/channel_init.c \ - src/core/surface/channel_ping.c \ - src/core/surface/channel_stack_type.c \ - src/core/surface/completion_queue.c \ - src/core/surface/event_string.c \ - src/core/surface/init.c \ - src/core/surface/lame_client.c \ - src/core/surface/metadata_array.c \ - src/core/surface/server.c \ - src/core/surface/server_chttp2.c \ - src/core/surface/validate_metadata.c \ - src/core/surface/version.c \ - src/core/transport/byte_stream.c \ - src/core/transport/chttp2/alpn.c \ - src/core/transport/chttp2/bin_encoder.c \ - src/core/transport/chttp2/frame_data.c \ - src/core/transport/chttp2/frame_goaway.c \ - src/core/transport/chttp2/frame_ping.c \ - src/core/transport/chttp2/frame_rst_stream.c \ - src/core/transport/chttp2/frame_settings.c \ - src/core/transport/chttp2/frame_window_update.c \ - src/core/transport/chttp2/hpack_encoder.c \ - src/core/transport/chttp2/hpack_parser.c \ - src/core/transport/chttp2/hpack_table.c \ - src/core/transport/chttp2/huffsyms.c \ - src/core/transport/chttp2/incoming_metadata.c \ - src/core/transport/chttp2/parsing.c \ - src/core/transport/chttp2/status_conversion.c \ - src/core/transport/chttp2/stream_lists.c \ - src/core/transport/chttp2/stream_map.c \ - src/core/transport/chttp2/timeout_encoding.c \ - src/core/transport/chttp2/varint.c \ - src/core/transport/chttp2/writing.c \ - src/core/transport/chttp2_transport.c \ - src/core/transport/connectivity_state.c \ - src/core/transport/metadata.c \ - src/core/transport/metadata_batch.c \ - src/core/transport/static_metadata.c \ - src/core/transport/transport.c \ - src/core/transport/transport_op_string.c \ - src/core/census/context.c \ - src/core/census/initialize.c \ - src/core/census/mlog.c \ - src/core/census/operation.c \ - src/core/census/placeholders.c \ - src/core/census/tracing.c \ + src/core/lib/surface/init_unsecure.c \ + src/core/lib/census/grpc_context.c \ + src/core/lib/census/grpc_filter.c \ + src/core/lib/census/grpc_plugin.c \ + src/core/lib/channel/channel_args.c \ + src/core/lib/channel/channel_stack.c \ + src/core/lib/channel/channel_stack_builder.c \ + src/core/lib/channel/client_channel.c \ + src/core/lib/channel/compress_filter.c \ + src/core/lib/channel/connected_channel.c \ + src/core/lib/channel/http_client_filter.c \ + src/core/lib/channel/http_server_filter.c \ + src/core/lib/channel/subchannel_call_holder.c \ + src/core/lib/client_config/client_config.c \ + src/core/lib/client_config/connector.c \ + src/core/lib/client_config/default_initial_connect_string.c \ + src/core/lib/client_config/initial_connect_string.c \ + src/core/lib/client_config/lb_policies/load_balancer_api.c \ + src/core/lib/client_config/lb_policies/pick_first.c \ + src/core/lib/client_config/lb_policies/round_robin.c \ + src/core/lib/client_config/lb_policy.c \ + src/core/lib/client_config/lb_policy_factory.c \ + src/core/lib/client_config/lb_policy_registry.c \ + src/core/lib/client_config/resolver.c \ + src/core/lib/client_config/resolver_factory.c \ + src/core/lib/client_config/resolver_registry.c \ + src/core/lib/client_config/resolvers/dns_resolver.c \ + src/core/lib/client_config/resolvers/sockaddr_resolver.c \ + src/core/lib/client_config/subchannel.c \ + src/core/lib/client_config/subchannel_factory.c \ + src/core/lib/client_config/subchannel_index.c \ + src/core/lib/client_config/uri_parser.c \ + src/core/lib/compression/compression_algorithm.c \ + src/core/lib/compression/message_compress.c \ + src/core/lib/debug/trace.c \ + src/core/lib/http/format_request.c \ + src/core/lib/http/httpcli.c \ + src/core/lib/http/parser.c \ + src/core/lib/iomgr/closure.c \ + src/core/lib/iomgr/endpoint.c \ + src/core/lib/iomgr/endpoint_pair_posix.c \ + src/core/lib/iomgr/endpoint_pair_windows.c \ + src/core/lib/iomgr/exec_ctx.c \ + src/core/lib/iomgr/executor.c \ + src/core/lib/iomgr/fd_posix.c \ + src/core/lib/iomgr/iocp_windows.c \ + src/core/lib/iomgr/iomgr.c \ + src/core/lib/iomgr/iomgr_posix.c \ + src/core/lib/iomgr/iomgr_windows.c \ + src/core/lib/iomgr/pollset_multipoller_with_epoll.c \ + src/core/lib/iomgr/pollset_multipoller_with_poll_posix.c \ + src/core/lib/iomgr/pollset_posix.c \ + src/core/lib/iomgr/pollset_set_posix.c \ + src/core/lib/iomgr/pollset_set_windows.c \ + src/core/lib/iomgr/pollset_windows.c \ + src/core/lib/iomgr/resolve_address_posix.c \ + src/core/lib/iomgr/resolve_address_windows.c \ + src/core/lib/iomgr/sockaddr_utils.c \ + src/core/lib/iomgr/socket_utils_common_posix.c \ + src/core/lib/iomgr/socket_utils_linux.c \ + src/core/lib/iomgr/socket_utils_posix.c \ + src/core/lib/iomgr/socket_windows.c \ + src/core/lib/iomgr/tcp_client_posix.c \ + src/core/lib/iomgr/tcp_client_windows.c \ + src/core/lib/iomgr/tcp_posix.c \ + src/core/lib/iomgr/tcp_server_posix.c \ + src/core/lib/iomgr/tcp_server_windows.c \ + src/core/lib/iomgr/tcp_windows.c \ + src/core/lib/iomgr/time_averaged_stats.c \ + src/core/lib/iomgr/timer.c \ + src/core/lib/iomgr/timer_heap.c \ + src/core/lib/iomgr/udp_server.c \ + src/core/lib/iomgr/unix_sockets_posix.c \ + src/core/lib/iomgr/unix_sockets_posix_noop.c \ + src/core/lib/iomgr/wakeup_fd_eventfd.c \ + src/core/lib/iomgr/wakeup_fd_nospecial.c \ + src/core/lib/iomgr/wakeup_fd_pipe.c \ + src/core/lib/iomgr/wakeup_fd_posix.c \ + src/core/lib/iomgr/workqueue_posix.c \ + src/core/lib/iomgr/workqueue_windows.c \ + src/core/lib/json/json.c \ + src/core/lib/json/json_reader.c \ + src/core/lib/json/json_string.c \ + src/core/lib/json/json_writer.c \ + src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c \ + src/core/lib/surface/alarm.c \ + src/core/lib/surface/api_trace.c \ + src/core/lib/surface/byte_buffer.c \ + src/core/lib/surface/byte_buffer_reader.c \ + src/core/lib/surface/call.c \ + src/core/lib/surface/call_details.c \ + src/core/lib/surface/call_log_batch.c \ + src/core/lib/surface/channel.c \ + src/core/lib/surface/channel_connectivity.c \ + src/core/lib/surface/channel_create.c \ + src/core/lib/surface/channel_init.c \ + src/core/lib/surface/channel_ping.c \ + src/core/lib/surface/channel_stack_type.c \ + src/core/lib/surface/completion_queue.c \ + src/core/lib/surface/event_string.c \ + src/core/lib/surface/init.c \ + src/core/lib/surface/lame_client.c \ + src/core/lib/surface/metadata_array.c \ + src/core/lib/surface/server.c \ + src/core/lib/surface/server_chttp2.c \ + src/core/lib/surface/validate_metadata.c \ + src/core/lib/surface/version.c \ + src/core/lib/transport/byte_stream.c \ + src/core/lib/transport/chttp2/alpn.c \ + src/core/lib/transport/chttp2/bin_encoder.c \ + src/core/lib/transport/chttp2/frame_data.c \ + src/core/lib/transport/chttp2/frame_goaway.c \ + src/core/lib/transport/chttp2/frame_ping.c \ + src/core/lib/transport/chttp2/frame_rst_stream.c \ + src/core/lib/transport/chttp2/frame_settings.c \ + src/core/lib/transport/chttp2/frame_window_update.c \ + src/core/lib/transport/chttp2/hpack_encoder.c \ + src/core/lib/transport/chttp2/hpack_parser.c \ + src/core/lib/transport/chttp2/hpack_table.c \ + src/core/lib/transport/chttp2/huffsyms.c \ + src/core/lib/transport/chttp2/incoming_metadata.c \ + src/core/lib/transport/chttp2/parsing.c \ + src/core/lib/transport/chttp2/status_conversion.c \ + src/core/lib/transport/chttp2/stream_lists.c \ + src/core/lib/transport/chttp2/stream_map.c \ + src/core/lib/transport/chttp2/timeout_encoding.c \ + src/core/lib/transport/chttp2/varint.c \ + src/core/lib/transport/chttp2/writing.c \ + src/core/lib/transport/chttp2_transport.c \ + src/core/lib/transport/connectivity_state.c \ + src/core/lib/transport/metadata.c \ + src/core/lib/transport/metadata_batch.c \ + src/core/lib/transport/static_metadata.c \ + src/core/lib/transport/transport.c \ + src/core/lib/transport/transport_op_string.c \ + src/core/lib/census/context.c \ + src/core/lib/census/initialize.c \ + src/core/lib/census/mlog.c \ + src/core/lib/census/operation.c \ + src/core/lib/census/placeholders.c \ + src/core/lib/census/tracing.c \ third_party/nanopb/pb_common.c \ third_party/nanopb/pb_decode.c \ third_party/nanopb/pb_encode.c \ @@ -2977,7 +2977,7 @@ endif LIBGRPC_ZOOKEEPER_SRC = \ - src/core/client_config/resolvers/zookeeper_resolver.c \ + src/core/lib/client_config/resolvers/zookeeper_resolver.c \ PUBLIC_HEADERS_C += \ include/grpc/grpc_zookeeper.h \ @@ -13416,27 +13416,27 @@ ifneq ($(OPENSSL_DEP),) # This is to ensure the embedded OpenSSL is built beforehand, properly # installing headers to their final destination on the drive. We need this # otherwise parallel compilation will fail if a source is compiled first. -src/core/http/httpcli_security_connector.c: $(OPENSSL_DEP) -src/core/security/b64.c: $(OPENSSL_DEP) -src/core/security/client_auth_filter.c: $(OPENSSL_DEP) -src/core/security/credentials.c: $(OPENSSL_DEP) -src/core/security/credentials_metadata.c: $(OPENSSL_DEP) -src/core/security/credentials_posix.c: $(OPENSSL_DEP) -src/core/security/credentials_win32.c: $(OPENSSL_DEP) -src/core/security/google_default_credentials.c: $(OPENSSL_DEP) -src/core/security/handshake.c: $(OPENSSL_DEP) -src/core/security/json_token.c: $(OPENSSL_DEP) -src/core/security/jwt_verifier.c: $(OPENSSL_DEP) -src/core/security/secure_endpoint.c: $(OPENSSL_DEP) -src/core/security/security_connector.c: $(OPENSSL_DEP) -src/core/security/security_context.c: $(OPENSSL_DEP) -src/core/security/server_auth_filter.c: $(OPENSSL_DEP) -src/core/security/server_secure_chttp2.c: $(OPENSSL_DEP) -src/core/surface/init_secure.c: $(OPENSSL_DEP) -src/core/surface/secure_channel_create.c: $(OPENSSL_DEP) -src/core/tsi/fake_transport_security.c: $(OPENSSL_DEP) -src/core/tsi/ssl_transport_security.c: $(OPENSSL_DEP) -src/core/tsi/transport_security.c: $(OPENSSL_DEP) +src/core/lib/http/httpcli_security_connector.c: $(OPENSSL_DEP) +src/core/lib/security/b64.c: $(OPENSSL_DEP) +src/core/lib/security/client_auth_filter.c: $(OPENSSL_DEP) +src/core/lib/security/credentials.c: $(OPENSSL_DEP) +src/core/lib/security/credentials_metadata.c: $(OPENSSL_DEP) +src/core/lib/security/credentials_posix.c: $(OPENSSL_DEP) +src/core/lib/security/credentials_win32.c: $(OPENSSL_DEP) +src/core/lib/security/google_default_credentials.c: $(OPENSSL_DEP) +src/core/lib/security/handshake.c: $(OPENSSL_DEP) +src/core/lib/security/json_token.c: $(OPENSSL_DEP) +src/core/lib/security/jwt_verifier.c: $(OPENSSL_DEP) +src/core/lib/security/secure_endpoint.c: $(OPENSSL_DEP) +src/core/lib/security/security_connector.c: $(OPENSSL_DEP) +src/core/lib/security/security_context.c: $(OPENSSL_DEP) +src/core/lib/security/server_auth_filter.c: $(OPENSSL_DEP) +src/core/lib/security/server_secure_chttp2.c: $(OPENSSL_DEP) +src/core/lib/surface/init_secure.c: $(OPENSSL_DEP) +src/core/lib/surface/secure_channel_create.c: $(OPENSSL_DEP) +src/core/lib/tsi/fake_transport_security.c: $(OPENSSL_DEP) +src/core/lib/tsi/ssl_transport_security.c: $(OPENSSL_DEP) +src/core/lib/tsi/transport_security.c: $(OPENSSL_DEP) src/cpp/client/secure_credentials.cc: $(OPENSSL_DEP) src/cpp/common/auth_property_iterator.cc: $(OPENSSL_DEP) src/cpp/common/secure_auth_context.cc: $(OPENSSL_DEP) diff --git a/binding.gyp b/binding.gyp index 2ee383a95c..416ce20864 100644 --- a/binding.gyp +++ b/binding.gyp @@ -492,50 +492,50 @@ 'dependencies': [ ], 'sources': [ - 'src/core/profiling/basic_timers.c', - 'src/core/profiling/stap_timers.c', - 'src/core/support/alloc.c', - 'src/core/support/avl.c', - 'src/core/support/backoff.c', - 'src/core/support/cmdline.c', - 'src/core/support/cpu_iphone.c', - 'src/core/support/cpu_linux.c', - 'src/core/support/cpu_posix.c', - 'src/core/support/cpu_windows.c', - 'src/core/support/env_linux.c', - 'src/core/support/env_posix.c', - 'src/core/support/env_win32.c', - 'src/core/support/histogram.c', - 'src/core/support/host_port.c', - 'src/core/support/load_file.c', - 'src/core/support/log.c', - 'src/core/support/log_android.c', - 'src/core/support/log_linux.c', - 'src/core/support/log_posix.c', - 'src/core/support/log_win32.c', - 'src/core/support/murmur_hash.c', - 'src/core/support/slice.c', - 'src/core/support/slice_buffer.c', - 'src/core/support/stack_lockfree.c', - 'src/core/support/string.c', - 'src/core/support/string_posix.c', - 'src/core/support/string_win32.c', - 'src/core/support/subprocess_posix.c', - 'src/core/support/subprocess_windows.c', - 'src/core/support/sync.c', - 'src/core/support/sync_posix.c', - 'src/core/support/sync_win32.c', - 'src/core/support/thd.c', - 'src/core/support/thd_posix.c', - 'src/core/support/thd_win32.c', - 'src/core/support/time.c', - 'src/core/support/time_posix.c', - 'src/core/support/time_precise.c', - 'src/core/support/time_win32.c', - 'src/core/support/tls_pthread.c', - 'src/core/support/tmpfile_posix.c', - 'src/core/support/tmpfile_win32.c', - 'src/core/support/wrap_memcpy.c', + 'src/core/lib/profiling/basic_timers.c', + 'src/core/lib/profiling/stap_timers.c', + 'src/core/lib/support/alloc.c', + 'src/core/lib/support/avl.c', + 'src/core/lib/support/backoff.c', + 'src/core/lib/support/cmdline.c', + 'src/core/lib/support/cpu_iphone.c', + 'src/core/lib/support/cpu_linux.c', + 'src/core/lib/support/cpu_posix.c', + 'src/core/lib/support/cpu_windows.c', + 'src/core/lib/support/env_linux.c', + 'src/core/lib/support/env_posix.c', + 'src/core/lib/support/env_win32.c', + 'src/core/lib/support/histogram.c', + 'src/core/lib/support/host_port.c', + 'src/core/lib/support/load_file.c', + 'src/core/lib/support/log.c', + 'src/core/lib/support/log_android.c', + 'src/core/lib/support/log_linux.c', + 'src/core/lib/support/log_posix.c', + 'src/core/lib/support/log_win32.c', + 'src/core/lib/support/murmur_hash.c', + 'src/core/lib/support/slice.c', + 'src/core/lib/support/slice_buffer.c', + 'src/core/lib/support/stack_lockfree.c', + 'src/core/lib/support/string.c', + 'src/core/lib/support/string_posix.c', + 'src/core/lib/support/string_win32.c', + 'src/core/lib/support/subprocess_posix.c', + 'src/core/lib/support/subprocess_windows.c', + 'src/core/lib/support/sync.c', + 'src/core/lib/support/sync_posix.c', + 'src/core/lib/support/sync_win32.c', + 'src/core/lib/support/thd.c', + 'src/core/lib/support/thd_posix.c', + 'src/core/lib/support/thd_win32.c', + 'src/core/lib/support/time.c', + 'src/core/lib/support/time_posix.c', + 'src/core/lib/support/time_precise.c', + 'src/core/lib/support/time_win32.c', + 'src/core/lib/support/tls_pthread.c', + 'src/core/lib/support/tmpfile_posix.c', + 'src/core/lib/support/tmpfile_win32.c', + 'src/core/lib/support/wrap_memcpy.c', ], "conditions": [ ['OS == "mac"', { @@ -558,167 +558,167 @@ 'gpr', ], 'sources': [ - 'src/core/census/grpc_context.c', - 'src/core/census/grpc_filter.c', - 'src/core/census/grpc_plugin.c', - 'src/core/channel/channel_args.c', - 'src/core/channel/channel_stack.c', - 'src/core/channel/channel_stack_builder.c', - 'src/core/channel/client_channel.c', - 'src/core/channel/compress_filter.c', - 'src/core/channel/connected_channel.c', - 'src/core/channel/http_client_filter.c', - 'src/core/channel/http_server_filter.c', - 'src/core/channel/subchannel_call_holder.c', - 'src/core/client_config/client_config.c', - 'src/core/client_config/connector.c', - 'src/core/client_config/default_initial_connect_string.c', - 'src/core/client_config/initial_connect_string.c', - 'src/core/client_config/lb_policies/load_balancer_api.c', - 'src/core/client_config/lb_policies/pick_first.c', - 'src/core/client_config/lb_policies/round_robin.c', - 'src/core/client_config/lb_policy.c', - 'src/core/client_config/lb_policy_factory.c', - 'src/core/client_config/lb_policy_registry.c', - 'src/core/client_config/resolver.c', - 'src/core/client_config/resolver_factory.c', - 'src/core/client_config/resolver_registry.c', - 'src/core/client_config/resolvers/dns_resolver.c', - 'src/core/client_config/resolvers/sockaddr_resolver.c', - 'src/core/client_config/subchannel.c', - 'src/core/client_config/subchannel_factory.c', - 'src/core/client_config/subchannel_index.c', - 'src/core/client_config/uri_parser.c', - 'src/core/compression/compression_algorithm.c', - 'src/core/compression/message_compress.c', - 'src/core/debug/trace.c', - 'src/core/http/format_request.c', - 'src/core/http/httpcli.c', - 'src/core/http/parser.c', - 'src/core/iomgr/closure.c', - 'src/core/iomgr/endpoint.c', - 'src/core/iomgr/endpoint_pair_posix.c', - 'src/core/iomgr/endpoint_pair_windows.c', - 'src/core/iomgr/exec_ctx.c', - 'src/core/iomgr/executor.c', - 'src/core/iomgr/fd_posix.c', - 'src/core/iomgr/iocp_windows.c', - 'src/core/iomgr/iomgr.c', - 'src/core/iomgr/iomgr_posix.c', - 'src/core/iomgr/iomgr_windows.c', - 'src/core/iomgr/pollset_multipoller_with_epoll.c', - 'src/core/iomgr/pollset_multipoller_with_poll_posix.c', - 'src/core/iomgr/pollset_posix.c', - 'src/core/iomgr/pollset_set_posix.c', - 'src/core/iomgr/pollset_set_windows.c', - 'src/core/iomgr/pollset_windows.c', - 'src/core/iomgr/resolve_address_posix.c', - 'src/core/iomgr/resolve_address_windows.c', - 'src/core/iomgr/sockaddr_utils.c', - 'src/core/iomgr/socket_utils_common_posix.c', - 'src/core/iomgr/socket_utils_linux.c', - 'src/core/iomgr/socket_utils_posix.c', - 'src/core/iomgr/socket_windows.c', - 'src/core/iomgr/tcp_client_posix.c', - 'src/core/iomgr/tcp_client_windows.c', - 'src/core/iomgr/tcp_posix.c', - 'src/core/iomgr/tcp_server_posix.c', - 'src/core/iomgr/tcp_server_windows.c', - 'src/core/iomgr/tcp_windows.c', - 'src/core/iomgr/time_averaged_stats.c', - 'src/core/iomgr/timer.c', - 'src/core/iomgr/timer_heap.c', - 'src/core/iomgr/udp_server.c', - 'src/core/iomgr/unix_sockets_posix.c', - 'src/core/iomgr/unix_sockets_posix_noop.c', - 'src/core/iomgr/wakeup_fd_eventfd.c', - 'src/core/iomgr/wakeup_fd_nospecial.c', - 'src/core/iomgr/wakeup_fd_pipe.c', - 'src/core/iomgr/wakeup_fd_posix.c', - 'src/core/iomgr/workqueue_posix.c', - 'src/core/iomgr/workqueue_windows.c', - 'src/core/json/json.c', - 'src/core/json/json_reader.c', - 'src/core/json/json_string.c', - 'src/core/json/json_writer.c', - 'src/core/proto/grpc/lb/v0/load_balancer.pb.c', - 'src/core/surface/alarm.c', - 'src/core/surface/api_trace.c', - 'src/core/surface/byte_buffer.c', - 'src/core/surface/byte_buffer_reader.c', - '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/channel_init.c', - 'src/core/surface/channel_ping.c', - 'src/core/surface/channel_stack_type.c', - 'src/core/surface/completion_queue.c', - 'src/core/surface/event_string.c', - 'src/core/surface/init.c', - 'src/core/surface/lame_client.c', - 'src/core/surface/metadata_array.c', - 'src/core/surface/server.c', - 'src/core/surface/server_chttp2.c', - 'src/core/surface/validate_metadata.c', - 'src/core/surface/version.c', - 'src/core/transport/byte_stream.c', - 'src/core/transport/chttp2/alpn.c', - 'src/core/transport/chttp2/bin_encoder.c', - 'src/core/transport/chttp2/frame_data.c', - 'src/core/transport/chttp2/frame_goaway.c', - 'src/core/transport/chttp2/frame_ping.c', - 'src/core/transport/chttp2/frame_rst_stream.c', - 'src/core/transport/chttp2/frame_settings.c', - 'src/core/transport/chttp2/frame_window_update.c', - 'src/core/transport/chttp2/hpack_encoder.c', - 'src/core/transport/chttp2/hpack_parser.c', - 'src/core/transport/chttp2/hpack_table.c', - 'src/core/transport/chttp2/huffsyms.c', - 'src/core/transport/chttp2/incoming_metadata.c', - 'src/core/transport/chttp2/parsing.c', - 'src/core/transport/chttp2/status_conversion.c', - 'src/core/transport/chttp2/stream_lists.c', - 'src/core/transport/chttp2/stream_map.c', - 'src/core/transport/chttp2/timeout_encoding.c', - 'src/core/transport/chttp2/varint.c', - 'src/core/transport/chttp2/writing.c', - 'src/core/transport/chttp2_transport.c', - 'src/core/transport/connectivity_state.c', - 'src/core/transport/metadata.c', - 'src/core/transport/metadata_batch.c', - 'src/core/transport/static_metadata.c', - 'src/core/transport/transport.c', - 'src/core/transport/transport_op_string.c', - 'src/core/http/httpcli_security_connector.c', - 'src/core/security/b64.c', - 'src/core/security/client_auth_filter.c', - 'src/core/security/credentials.c', - 'src/core/security/credentials_metadata.c', - 'src/core/security/credentials_posix.c', - 'src/core/security/credentials_win32.c', - 'src/core/security/google_default_credentials.c', - 'src/core/security/handshake.c', - 'src/core/security/json_token.c', - 'src/core/security/jwt_verifier.c', - 'src/core/security/secure_endpoint.c', - 'src/core/security/security_connector.c', - 'src/core/security/security_context.c', - 'src/core/security/server_auth_filter.c', - 'src/core/security/server_secure_chttp2.c', - 'src/core/surface/init_secure.c', - 'src/core/surface/secure_channel_create.c', - 'src/core/tsi/fake_transport_security.c', - 'src/core/tsi/ssl_transport_security.c', - 'src/core/tsi/transport_security.c', - 'src/core/census/context.c', - 'src/core/census/initialize.c', - 'src/core/census/mlog.c', - 'src/core/census/operation.c', - 'src/core/census/placeholders.c', - 'src/core/census/tracing.c', + 'src/core/lib/census/grpc_context.c', + 'src/core/lib/census/grpc_filter.c', + 'src/core/lib/census/grpc_plugin.c', + 'src/core/lib/channel/channel_args.c', + 'src/core/lib/channel/channel_stack.c', + 'src/core/lib/channel/channel_stack_builder.c', + 'src/core/lib/channel/client_channel.c', + 'src/core/lib/channel/compress_filter.c', + 'src/core/lib/channel/connected_channel.c', + 'src/core/lib/channel/http_client_filter.c', + 'src/core/lib/channel/http_server_filter.c', + 'src/core/lib/channel/subchannel_call_holder.c', + 'src/core/lib/client_config/client_config.c', + 'src/core/lib/client_config/connector.c', + 'src/core/lib/client_config/default_initial_connect_string.c', + 'src/core/lib/client_config/initial_connect_string.c', + 'src/core/lib/client_config/lb_policies/load_balancer_api.c', + 'src/core/lib/client_config/lb_policies/pick_first.c', + 'src/core/lib/client_config/lb_policies/round_robin.c', + 'src/core/lib/client_config/lb_policy.c', + 'src/core/lib/client_config/lb_policy_factory.c', + 'src/core/lib/client_config/lb_policy_registry.c', + 'src/core/lib/client_config/resolver.c', + 'src/core/lib/client_config/resolver_factory.c', + 'src/core/lib/client_config/resolver_registry.c', + 'src/core/lib/client_config/resolvers/dns_resolver.c', + 'src/core/lib/client_config/resolvers/sockaddr_resolver.c', + 'src/core/lib/client_config/subchannel.c', + 'src/core/lib/client_config/subchannel_factory.c', + 'src/core/lib/client_config/subchannel_index.c', + 'src/core/lib/client_config/uri_parser.c', + 'src/core/lib/compression/compression_algorithm.c', + 'src/core/lib/compression/message_compress.c', + 'src/core/lib/debug/trace.c', + 'src/core/lib/http/format_request.c', + 'src/core/lib/http/httpcli.c', + 'src/core/lib/http/parser.c', + 'src/core/lib/iomgr/closure.c', + 'src/core/lib/iomgr/endpoint.c', + 'src/core/lib/iomgr/endpoint_pair_posix.c', + 'src/core/lib/iomgr/endpoint_pair_windows.c', + 'src/core/lib/iomgr/exec_ctx.c', + 'src/core/lib/iomgr/executor.c', + 'src/core/lib/iomgr/fd_posix.c', + 'src/core/lib/iomgr/iocp_windows.c', + 'src/core/lib/iomgr/iomgr.c', + 'src/core/lib/iomgr/iomgr_posix.c', + 'src/core/lib/iomgr/iomgr_windows.c', + 'src/core/lib/iomgr/pollset_multipoller_with_epoll.c', + 'src/core/lib/iomgr/pollset_multipoller_with_poll_posix.c', + 'src/core/lib/iomgr/pollset_posix.c', + 'src/core/lib/iomgr/pollset_set_posix.c', + 'src/core/lib/iomgr/pollset_set_windows.c', + 'src/core/lib/iomgr/pollset_windows.c', + 'src/core/lib/iomgr/resolve_address_posix.c', + 'src/core/lib/iomgr/resolve_address_windows.c', + 'src/core/lib/iomgr/sockaddr_utils.c', + 'src/core/lib/iomgr/socket_utils_common_posix.c', + 'src/core/lib/iomgr/socket_utils_linux.c', + 'src/core/lib/iomgr/socket_utils_posix.c', + 'src/core/lib/iomgr/socket_windows.c', + 'src/core/lib/iomgr/tcp_client_posix.c', + 'src/core/lib/iomgr/tcp_client_windows.c', + 'src/core/lib/iomgr/tcp_posix.c', + 'src/core/lib/iomgr/tcp_server_posix.c', + 'src/core/lib/iomgr/tcp_server_windows.c', + 'src/core/lib/iomgr/tcp_windows.c', + 'src/core/lib/iomgr/time_averaged_stats.c', + 'src/core/lib/iomgr/timer.c', + 'src/core/lib/iomgr/timer_heap.c', + 'src/core/lib/iomgr/udp_server.c', + 'src/core/lib/iomgr/unix_sockets_posix.c', + 'src/core/lib/iomgr/unix_sockets_posix_noop.c', + 'src/core/lib/iomgr/wakeup_fd_eventfd.c', + 'src/core/lib/iomgr/wakeup_fd_nospecial.c', + 'src/core/lib/iomgr/wakeup_fd_pipe.c', + 'src/core/lib/iomgr/wakeup_fd_posix.c', + 'src/core/lib/iomgr/workqueue_posix.c', + 'src/core/lib/iomgr/workqueue_windows.c', + 'src/core/lib/json/json.c', + 'src/core/lib/json/json_reader.c', + 'src/core/lib/json/json_string.c', + 'src/core/lib/json/json_writer.c', + 'src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c', + 'src/core/lib/surface/alarm.c', + 'src/core/lib/surface/api_trace.c', + 'src/core/lib/surface/byte_buffer.c', + 'src/core/lib/surface/byte_buffer_reader.c', + 'src/core/lib/surface/call.c', + 'src/core/lib/surface/call_details.c', + 'src/core/lib/surface/call_log_batch.c', + 'src/core/lib/surface/channel.c', + 'src/core/lib/surface/channel_connectivity.c', + 'src/core/lib/surface/channel_create.c', + 'src/core/lib/surface/channel_init.c', + 'src/core/lib/surface/channel_ping.c', + 'src/core/lib/surface/channel_stack_type.c', + 'src/core/lib/surface/completion_queue.c', + 'src/core/lib/surface/event_string.c', + 'src/core/lib/surface/init.c', + 'src/core/lib/surface/lame_client.c', + 'src/core/lib/surface/metadata_array.c', + 'src/core/lib/surface/server.c', + 'src/core/lib/surface/server_chttp2.c', + 'src/core/lib/surface/validate_metadata.c', + 'src/core/lib/surface/version.c', + 'src/core/lib/transport/byte_stream.c', + 'src/core/lib/transport/chttp2/alpn.c', + 'src/core/lib/transport/chttp2/bin_encoder.c', + 'src/core/lib/transport/chttp2/frame_data.c', + 'src/core/lib/transport/chttp2/frame_goaway.c', + 'src/core/lib/transport/chttp2/frame_ping.c', + 'src/core/lib/transport/chttp2/frame_rst_stream.c', + 'src/core/lib/transport/chttp2/frame_settings.c', + 'src/core/lib/transport/chttp2/frame_window_update.c', + 'src/core/lib/transport/chttp2/hpack_encoder.c', + 'src/core/lib/transport/chttp2/hpack_parser.c', + 'src/core/lib/transport/chttp2/hpack_table.c', + 'src/core/lib/transport/chttp2/huffsyms.c', + 'src/core/lib/transport/chttp2/incoming_metadata.c', + 'src/core/lib/transport/chttp2/parsing.c', + 'src/core/lib/transport/chttp2/status_conversion.c', + 'src/core/lib/transport/chttp2/stream_lists.c', + 'src/core/lib/transport/chttp2/stream_map.c', + 'src/core/lib/transport/chttp2/timeout_encoding.c', + 'src/core/lib/transport/chttp2/varint.c', + 'src/core/lib/transport/chttp2/writing.c', + 'src/core/lib/transport/chttp2_transport.c', + 'src/core/lib/transport/connectivity_state.c', + 'src/core/lib/transport/metadata.c', + 'src/core/lib/transport/metadata_batch.c', + 'src/core/lib/transport/static_metadata.c', + 'src/core/lib/transport/transport.c', + 'src/core/lib/transport/transport_op_string.c', + 'src/core/lib/http/httpcli_security_connector.c', + 'src/core/lib/security/b64.c', + 'src/core/lib/security/client_auth_filter.c', + 'src/core/lib/security/credentials.c', + 'src/core/lib/security/credentials_metadata.c', + 'src/core/lib/security/credentials_posix.c', + 'src/core/lib/security/credentials_win32.c', + 'src/core/lib/security/google_default_credentials.c', + 'src/core/lib/security/handshake.c', + 'src/core/lib/security/json_token.c', + 'src/core/lib/security/jwt_verifier.c', + 'src/core/lib/security/secure_endpoint.c', + 'src/core/lib/security/security_connector.c', + 'src/core/lib/security/security_context.c', + 'src/core/lib/security/server_auth_filter.c', + 'src/core/lib/security/server_secure_chttp2.c', + 'src/core/lib/surface/init_secure.c', + 'src/core/lib/surface/secure_channel_create.c', + 'src/core/lib/tsi/fake_transport_security.c', + 'src/core/lib/tsi/ssl_transport_security.c', + 'src/core/lib/tsi/transport_security.c', + 'src/core/lib/census/context.c', + 'src/core/lib/census/initialize.c', + 'src/core/lib/census/mlog.c', + 'src/core/lib/census/operation.c', + 'src/core/lib/census/placeholders.c', + 'src/core/lib/census/tracing.c', 'third_party/nanopb/pb_common.c', 'third_party/nanopb/pb_decode.c', 'third_party/nanopb/pb_encode.c', diff --git a/build.yaml b/build.yaml index fc170cc1ab..0398bc23b8 100644 --- a/build.yaml +++ b/build.yaml @@ -13,16 +13,16 @@ filegroups: public_headers: - include/grpc/census.h headers: - - src/core/census/aggregation.h - - src/core/census/mlog.h - - src/core/census/rpc_metric_id.h - src: - - src/core/census/context.c - - src/core/census/initialize.c - - src/core/census/mlog.c - - src/core/census/operation.c - - src/core/census/placeholders.c - - src/core/census/tracing.c + - src/core/lib/census/aggregation.h + - src/core/lib/census/mlog.h + - src/core/lib/census/rpc_metric_id.h + src: + - src/core/lib/census/context.c + - src/core/lib/census/initialize.c + - src/core/lib/census/mlog.c + - src/core/lib/census/operation.c + - src/core/lib/census/placeholders.c + - src/core/lib/census/tracing.c - name: gpr public_headers: - include/grpc/support/alloc.h @@ -54,63 +54,63 @@ filegroups: - include/grpc/support/tls_pthread.h - include/grpc/support/useful.h headers: - - src/core/profiling/timers.h - - src/core/support/backoff.h - - src/core/support/block_annotate.h - - src/core/support/env.h - - src/core/support/load_file.h - - src/core/support/murmur_hash.h - - src/core/support/stack_lockfree.h - - src/core/support/string.h - - src/core/support/string_win32.h - - src/core/support/thd_internal.h - - src/core/support/time_precise.h - - src/core/support/tmpfile.h - src: - - src/core/profiling/basic_timers.c - - src/core/profiling/stap_timers.c - - src/core/support/alloc.c - - src/core/support/avl.c - - src/core/support/backoff.c - - src/core/support/cmdline.c - - src/core/support/cpu_iphone.c - - src/core/support/cpu_linux.c - - src/core/support/cpu_posix.c - - src/core/support/cpu_windows.c - - src/core/support/env_linux.c - - src/core/support/env_posix.c - - src/core/support/env_win32.c - - src/core/support/histogram.c - - src/core/support/host_port.c - - src/core/support/load_file.c - - src/core/support/log.c - - src/core/support/log_android.c - - src/core/support/log_linux.c - - src/core/support/log_posix.c - - src/core/support/log_win32.c - - src/core/support/murmur_hash.c - - src/core/support/slice.c - - src/core/support/slice_buffer.c - - src/core/support/stack_lockfree.c - - src/core/support/string.c - - src/core/support/string_posix.c - - src/core/support/string_win32.c - - src/core/support/subprocess_posix.c - - src/core/support/subprocess_windows.c - - src/core/support/sync.c - - src/core/support/sync_posix.c - - src/core/support/sync_win32.c - - src/core/support/thd.c - - src/core/support/thd_posix.c - - src/core/support/thd_win32.c - - src/core/support/time.c - - src/core/support/time_posix.c - - src/core/support/time_precise.c - - src/core/support/time_win32.c - - src/core/support/tls_pthread.c - - src/core/support/tmpfile_posix.c - - src/core/support/tmpfile_win32.c - - src/core/support/wrap_memcpy.c + - src/core/lib/profiling/timers.h + - src/core/lib/support/backoff.h + - src/core/lib/support/block_annotate.h + - src/core/lib/support/env.h + - src/core/lib/support/load_file.h + - src/core/lib/support/murmur_hash.h + - src/core/lib/support/stack_lockfree.h + - src/core/lib/support/string.h + - src/core/lib/support/string_win32.h + - src/core/lib/support/thd_internal.h + - src/core/lib/support/time_precise.h + - src/core/lib/support/tmpfile.h + src: + - src/core/lib/profiling/basic_timers.c + - src/core/lib/profiling/stap_timers.c + - src/core/lib/support/alloc.c + - src/core/lib/support/avl.c + - src/core/lib/support/backoff.c + - src/core/lib/support/cmdline.c + - src/core/lib/support/cpu_iphone.c + - src/core/lib/support/cpu_linux.c + - src/core/lib/support/cpu_posix.c + - src/core/lib/support/cpu_windows.c + - src/core/lib/support/env_linux.c + - src/core/lib/support/env_posix.c + - src/core/lib/support/env_win32.c + - src/core/lib/support/histogram.c + - src/core/lib/support/host_port.c + - src/core/lib/support/load_file.c + - src/core/lib/support/log.c + - src/core/lib/support/log_android.c + - src/core/lib/support/log_linux.c + - src/core/lib/support/log_posix.c + - src/core/lib/support/log_win32.c + - src/core/lib/support/murmur_hash.c + - src/core/lib/support/slice.c + - src/core/lib/support/slice_buffer.c + - src/core/lib/support/stack_lockfree.c + - src/core/lib/support/string.c + - src/core/lib/support/string_posix.c + - src/core/lib/support/string_win32.c + - src/core/lib/support/subprocess_posix.c + - src/core/lib/support/subprocess_windows.c + - src/core/lib/support/sync.c + - src/core/lib/support/sync_posix.c + - src/core/lib/support/sync_win32.c + - src/core/lib/support/thd.c + - src/core/lib/support/thd_posix.c + - src/core/lib/support/thd_win32.c + - src/core/lib/support/time.c + - src/core/lib/support/time_posix.c + - src/core/lib/support/time_precise.c + - src/core/lib/support/time_win32.c + - src/core/lib/support/tls_pthread.c + - src/core/lib/support/tmpfile_posix.c + - src/core/lib/support/tmpfile_win32.c + - src/core/lib/support/wrap_memcpy.c - name: gpr_codegen public_headers: - include/grpc/impl/codegen/alloc.h @@ -247,261 +247,261 @@ filegroups: - include/grpc/grpc.h - include/grpc/status.h headers: - - src/core/census/grpc_filter.h - - src/core/census/grpc_plugin.h - - src/core/channel/channel_args.h - - src/core/channel/channel_stack.h - - src/core/channel/channel_stack_builder.h - - src/core/channel/client_channel.h - - src/core/channel/compress_filter.h - - src/core/channel/connected_channel.h - - src/core/channel/context.h - - src/core/channel/http_client_filter.h - - src/core/channel/http_server_filter.h - - src/core/channel/subchannel_call_holder.h - - src/core/client_config/client_config.h - - src/core/client_config/connector.h - - src/core/client_config/initial_connect_string.h - - src/core/client_config/lb_policies/load_balancer_api.h - - src/core/client_config/lb_policies/pick_first.h - - src/core/client_config/lb_policies/round_robin.h - - src/core/client_config/lb_policy.h - - src/core/client_config/lb_policy_factory.h - - src/core/client_config/lb_policy_registry.h - - src/core/client_config/resolver.h - - src/core/client_config/resolver_factory.h - - src/core/client_config/resolver_registry.h - - src/core/client_config/resolvers/dns_resolver.h - - src/core/client_config/resolvers/sockaddr_resolver.h - - src/core/client_config/subchannel.h - - src/core/client_config/subchannel_factory.h - - src/core/client_config/subchannel_index.h - - src/core/client_config/uri_parser.h - - src/core/compression/algorithm_metadata.h - - src/core/compression/message_compress.h - - src/core/debug/trace.h - - src/core/http/format_request.h - - src/core/http/httpcli.h - - src/core/http/parser.h - - src/core/iomgr/closure.h - - src/core/iomgr/endpoint.h - - src/core/iomgr/endpoint_pair.h - - src/core/iomgr/exec_ctx.h - - src/core/iomgr/executor.h - - src/core/iomgr/fd_posix.h - - src/core/iomgr/iocp_windows.h - - src/core/iomgr/iomgr.h - - src/core/iomgr/iomgr_internal.h - - src/core/iomgr/iomgr_posix.h - - src/core/iomgr/pollset.h - - src/core/iomgr/pollset_posix.h - - src/core/iomgr/pollset_set.h - - src/core/iomgr/pollset_set_posix.h - - src/core/iomgr/pollset_set_windows.h - - src/core/iomgr/pollset_windows.h - - src/core/iomgr/resolve_address.h - - src/core/iomgr/sockaddr.h - - src/core/iomgr/sockaddr_posix.h - - src/core/iomgr/sockaddr_utils.h - - src/core/iomgr/sockaddr_win32.h - - src/core/iomgr/socket_utils_posix.h - - src/core/iomgr/socket_windows.h - - src/core/iomgr/tcp_client.h - - src/core/iomgr/tcp_posix.h - - src/core/iomgr/tcp_server.h - - src/core/iomgr/tcp_windows.h - - src/core/iomgr/time_averaged_stats.h - - src/core/iomgr/timer.h - - src/core/iomgr/timer_heap.h - - src/core/iomgr/udp_server.h - - src/core/iomgr/unix_sockets_posix.h - - src/core/iomgr/wakeup_fd_pipe.h - - src/core/iomgr/wakeup_fd_posix.h - - src/core/iomgr/workqueue.h - - src/core/iomgr/workqueue_posix.h - - src/core/iomgr/workqueue_windows.h - - src/core/json/json.h - - src/core/json/json_common.h - - src/core/json/json_reader.h - - src/core/json/json_writer.h - - src/core/proto/grpc/lb/v0/load_balancer.pb.h - - src/core/statistics/census_interface.h - - src/core/statistics/census_rpc_stats.h - - src/core/surface/api_trace.h - - src/core/surface/call.h - - src/core/surface/call_test_only.h - - src/core/surface/channel.h - - src/core/surface/channel_init.h - - src/core/surface/channel_stack_type.h - - src/core/surface/completion_queue.h - - src/core/surface/event_string.h - - src/core/surface/init.h - - src/core/surface/lame_client.h - - src/core/surface/server.h - - src/core/surface/surface_trace.h - - src/core/transport/byte_stream.h - - src/core/transport/chttp2/alpn.h - - src/core/transport/chttp2/bin_encoder.h - - src/core/transport/chttp2/frame.h - - src/core/transport/chttp2/frame_data.h - - src/core/transport/chttp2/frame_goaway.h - - src/core/transport/chttp2/frame_ping.h - - src/core/transport/chttp2/frame_rst_stream.h - - src/core/transport/chttp2/frame_settings.h - - src/core/transport/chttp2/frame_window_update.h - - src/core/transport/chttp2/hpack_encoder.h - - src/core/transport/chttp2/hpack_parser.h - - src/core/transport/chttp2/hpack_table.h - - src/core/transport/chttp2/http2_errors.h - - src/core/transport/chttp2/huffsyms.h - - src/core/transport/chttp2/incoming_metadata.h - - src/core/transport/chttp2/internal.h - - src/core/transport/chttp2/status_conversion.h - - src/core/transport/chttp2/stream_map.h - - src/core/transport/chttp2/timeout_encoding.h - - src/core/transport/chttp2/varint.h - - src/core/transport/chttp2_transport.h - - src/core/transport/connectivity_state.h - - src/core/transport/metadata.h - - src/core/transport/metadata_batch.h - - src/core/transport/static_metadata.h - - src/core/transport/transport.h - - src/core/transport/transport_impl.h - src: - - src/core/census/grpc_context.c - - src/core/census/grpc_filter.c - - src/core/census/grpc_plugin.c - - src/core/channel/channel_args.c - - src/core/channel/channel_stack.c - - src/core/channel/channel_stack_builder.c - - src/core/channel/client_channel.c - - src/core/channel/compress_filter.c - - src/core/channel/connected_channel.c - - src/core/channel/http_client_filter.c - - src/core/channel/http_server_filter.c - - src/core/channel/subchannel_call_holder.c - - src/core/client_config/client_config.c - - src/core/client_config/connector.c - - src/core/client_config/default_initial_connect_string.c - - src/core/client_config/initial_connect_string.c - - src/core/client_config/lb_policies/load_balancer_api.c - - src/core/client_config/lb_policies/pick_first.c - - src/core/client_config/lb_policies/round_robin.c - - src/core/client_config/lb_policy.c - - src/core/client_config/lb_policy_factory.c - - src/core/client_config/lb_policy_registry.c - - src/core/client_config/resolver.c - - src/core/client_config/resolver_factory.c - - src/core/client_config/resolver_registry.c - - src/core/client_config/resolvers/dns_resolver.c - - src/core/client_config/resolvers/sockaddr_resolver.c - - src/core/client_config/subchannel.c - - src/core/client_config/subchannel_factory.c - - src/core/client_config/subchannel_index.c - - src/core/client_config/uri_parser.c - - src/core/compression/compression_algorithm.c - - src/core/compression/message_compress.c - - src/core/debug/trace.c - - src/core/http/format_request.c - - src/core/http/httpcli.c - - src/core/http/parser.c - - src/core/iomgr/closure.c - - src/core/iomgr/endpoint.c - - src/core/iomgr/endpoint_pair_posix.c - - src/core/iomgr/endpoint_pair_windows.c - - src/core/iomgr/exec_ctx.c - - src/core/iomgr/executor.c - - src/core/iomgr/fd_posix.c - - src/core/iomgr/iocp_windows.c - - src/core/iomgr/iomgr.c - - src/core/iomgr/iomgr_posix.c - - src/core/iomgr/iomgr_windows.c - - src/core/iomgr/pollset_multipoller_with_epoll.c - - src/core/iomgr/pollset_multipoller_with_poll_posix.c - - src/core/iomgr/pollset_posix.c - - src/core/iomgr/pollset_set_posix.c - - src/core/iomgr/pollset_set_windows.c - - src/core/iomgr/pollset_windows.c - - src/core/iomgr/resolve_address_posix.c - - src/core/iomgr/resolve_address_windows.c - - src/core/iomgr/sockaddr_utils.c - - src/core/iomgr/socket_utils_common_posix.c - - src/core/iomgr/socket_utils_linux.c - - src/core/iomgr/socket_utils_posix.c - - src/core/iomgr/socket_windows.c - - src/core/iomgr/tcp_client_posix.c - - src/core/iomgr/tcp_client_windows.c - - src/core/iomgr/tcp_posix.c - - src/core/iomgr/tcp_server_posix.c - - src/core/iomgr/tcp_server_windows.c - - src/core/iomgr/tcp_windows.c - - src/core/iomgr/time_averaged_stats.c - - src/core/iomgr/timer.c - - src/core/iomgr/timer_heap.c - - src/core/iomgr/udp_server.c - - src/core/iomgr/unix_sockets_posix.c - - src/core/iomgr/unix_sockets_posix_noop.c - - src/core/iomgr/wakeup_fd_eventfd.c - - src/core/iomgr/wakeup_fd_nospecial.c - - src/core/iomgr/wakeup_fd_pipe.c - - src/core/iomgr/wakeup_fd_posix.c - - src/core/iomgr/workqueue_posix.c - - src/core/iomgr/workqueue_windows.c - - src/core/json/json.c - - src/core/json/json_reader.c - - src/core/json/json_string.c - - src/core/json/json_writer.c - - src/core/proto/grpc/lb/v0/load_balancer.pb.c - - src/core/surface/alarm.c - - src/core/surface/api_trace.c - - src/core/surface/byte_buffer.c - - src/core/surface/byte_buffer_reader.c - - 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/channel_init.c - - src/core/surface/channel_ping.c - - src/core/surface/channel_stack_type.c - - src/core/surface/completion_queue.c - - src/core/surface/event_string.c - - src/core/surface/init.c - - src/core/surface/lame_client.c - - src/core/surface/metadata_array.c - - src/core/surface/server.c - - src/core/surface/server_chttp2.c - - src/core/surface/validate_metadata.c - - src/core/surface/version.c - - src/core/transport/byte_stream.c - - src/core/transport/chttp2/alpn.c - - src/core/transport/chttp2/bin_encoder.c - - src/core/transport/chttp2/frame_data.c - - src/core/transport/chttp2/frame_goaway.c - - src/core/transport/chttp2/frame_ping.c - - src/core/transport/chttp2/frame_rst_stream.c - - src/core/transport/chttp2/frame_settings.c - - src/core/transport/chttp2/frame_window_update.c - - src/core/transport/chttp2/hpack_encoder.c - - src/core/transport/chttp2/hpack_parser.c - - src/core/transport/chttp2/hpack_table.c - - src/core/transport/chttp2/huffsyms.c - - src/core/transport/chttp2/incoming_metadata.c - - src/core/transport/chttp2/parsing.c - - src/core/transport/chttp2/status_conversion.c - - src/core/transport/chttp2/stream_lists.c - - src/core/transport/chttp2/stream_map.c - - src/core/transport/chttp2/timeout_encoding.c - - src/core/transport/chttp2/varint.c - - src/core/transport/chttp2/writing.c - - src/core/transport/chttp2_transport.c - - src/core/transport/connectivity_state.c - - src/core/transport/metadata.c - - src/core/transport/metadata_batch.c - - src/core/transport/static_metadata.c - - src/core/transport/transport.c - - src/core/transport/transport_op_string.c + - src/core/lib/census/grpc_filter.h + - src/core/lib/census/grpc_plugin.h + - src/core/lib/channel/channel_args.h + - src/core/lib/channel/channel_stack.h + - src/core/lib/channel/channel_stack_builder.h + - src/core/lib/channel/client_channel.h + - src/core/lib/channel/compress_filter.h + - src/core/lib/channel/connected_channel.h + - src/core/lib/channel/context.h + - src/core/lib/channel/http_client_filter.h + - src/core/lib/channel/http_server_filter.h + - src/core/lib/channel/subchannel_call_holder.h + - src/core/lib/client_config/client_config.h + - src/core/lib/client_config/connector.h + - src/core/lib/client_config/initial_connect_string.h + - src/core/lib/client_config/lb_policies/load_balancer_api.h + - src/core/lib/client_config/lb_policies/pick_first.h + - src/core/lib/client_config/lb_policies/round_robin.h + - src/core/lib/client_config/lb_policy.h + - src/core/lib/client_config/lb_policy_factory.h + - src/core/lib/client_config/lb_policy_registry.h + - src/core/lib/client_config/resolver.h + - src/core/lib/client_config/resolver_factory.h + - src/core/lib/client_config/resolver_registry.h + - src/core/lib/client_config/resolvers/dns_resolver.h + - src/core/lib/client_config/resolvers/sockaddr_resolver.h + - src/core/lib/client_config/subchannel.h + - src/core/lib/client_config/subchannel_factory.h + - src/core/lib/client_config/subchannel_index.h + - src/core/lib/client_config/uri_parser.h + - src/core/lib/compression/algorithm_metadata.h + - src/core/lib/compression/message_compress.h + - src/core/lib/debug/trace.h + - src/core/lib/http/format_request.h + - src/core/lib/http/httpcli.h + - src/core/lib/http/parser.h + - src/core/lib/iomgr/closure.h + - src/core/lib/iomgr/endpoint.h + - src/core/lib/iomgr/endpoint_pair.h + - src/core/lib/iomgr/exec_ctx.h + - src/core/lib/iomgr/executor.h + - src/core/lib/iomgr/fd_posix.h + - src/core/lib/iomgr/iocp_windows.h + - src/core/lib/iomgr/iomgr.h + - src/core/lib/iomgr/iomgr_internal.h + - src/core/lib/iomgr/iomgr_posix.h + - src/core/lib/iomgr/pollset.h + - src/core/lib/iomgr/pollset_posix.h + - src/core/lib/iomgr/pollset_set.h + - src/core/lib/iomgr/pollset_set_posix.h + - src/core/lib/iomgr/pollset_set_windows.h + - src/core/lib/iomgr/pollset_windows.h + - src/core/lib/iomgr/resolve_address.h + - src/core/lib/iomgr/sockaddr.h + - src/core/lib/iomgr/sockaddr_posix.h + - src/core/lib/iomgr/sockaddr_utils.h + - src/core/lib/iomgr/sockaddr_win32.h + - src/core/lib/iomgr/socket_utils_posix.h + - src/core/lib/iomgr/socket_windows.h + - src/core/lib/iomgr/tcp_client.h + - src/core/lib/iomgr/tcp_posix.h + - src/core/lib/iomgr/tcp_server.h + - src/core/lib/iomgr/tcp_windows.h + - src/core/lib/iomgr/time_averaged_stats.h + - src/core/lib/iomgr/timer.h + - src/core/lib/iomgr/timer_heap.h + - src/core/lib/iomgr/udp_server.h + - src/core/lib/iomgr/unix_sockets_posix.h + - src/core/lib/iomgr/wakeup_fd_pipe.h + - src/core/lib/iomgr/wakeup_fd_posix.h + - src/core/lib/iomgr/workqueue.h + - src/core/lib/iomgr/workqueue_posix.h + - src/core/lib/iomgr/workqueue_windows.h + - src/core/lib/json/json.h + - src/core/lib/json/json_common.h + - src/core/lib/json/json_reader.h + - src/core/lib/json/json_writer.h + - src/core/lib/proto/grpc/lb/v0/load_balancer.pb.h + - src/core/lib/statistics/census_interface.h + - src/core/lib/statistics/census_rpc_stats.h + - src/core/lib/surface/api_trace.h + - src/core/lib/surface/call.h + - src/core/lib/surface/call_test_only.h + - src/core/lib/surface/channel.h + - src/core/lib/surface/channel_init.h + - src/core/lib/surface/channel_stack_type.h + - src/core/lib/surface/completion_queue.h + - src/core/lib/surface/event_string.h + - src/core/lib/surface/init.h + - src/core/lib/surface/lame_client.h + - src/core/lib/surface/server.h + - src/core/lib/surface/surface_trace.h + - src/core/lib/transport/byte_stream.h + - src/core/lib/transport/chttp2/alpn.h + - src/core/lib/transport/chttp2/bin_encoder.h + - src/core/lib/transport/chttp2/frame.h + - src/core/lib/transport/chttp2/frame_data.h + - src/core/lib/transport/chttp2/frame_goaway.h + - src/core/lib/transport/chttp2/frame_ping.h + - src/core/lib/transport/chttp2/frame_rst_stream.h + - src/core/lib/transport/chttp2/frame_settings.h + - src/core/lib/transport/chttp2/frame_window_update.h + - src/core/lib/transport/chttp2/hpack_encoder.h + - src/core/lib/transport/chttp2/hpack_parser.h + - src/core/lib/transport/chttp2/hpack_table.h + - src/core/lib/transport/chttp2/http2_errors.h + - src/core/lib/transport/chttp2/huffsyms.h + - src/core/lib/transport/chttp2/incoming_metadata.h + - src/core/lib/transport/chttp2/internal.h + - src/core/lib/transport/chttp2/status_conversion.h + - src/core/lib/transport/chttp2/stream_map.h + - src/core/lib/transport/chttp2/timeout_encoding.h + - src/core/lib/transport/chttp2/varint.h + - src/core/lib/transport/chttp2_transport.h + - src/core/lib/transport/connectivity_state.h + - src/core/lib/transport/metadata.h + - src/core/lib/transport/metadata_batch.h + - src/core/lib/transport/static_metadata.h + - src/core/lib/transport/transport.h + - src/core/lib/transport/transport_impl.h + src: + - src/core/lib/census/grpc_context.c + - src/core/lib/census/grpc_filter.c + - src/core/lib/census/grpc_plugin.c + - src/core/lib/channel/channel_args.c + - src/core/lib/channel/channel_stack.c + - src/core/lib/channel/channel_stack_builder.c + - src/core/lib/channel/client_channel.c + - src/core/lib/channel/compress_filter.c + - src/core/lib/channel/connected_channel.c + - src/core/lib/channel/http_client_filter.c + - src/core/lib/channel/http_server_filter.c + - src/core/lib/channel/subchannel_call_holder.c + - src/core/lib/client_config/client_config.c + - src/core/lib/client_config/connector.c + - src/core/lib/client_config/default_initial_connect_string.c + - src/core/lib/client_config/initial_connect_string.c + - src/core/lib/client_config/lb_policies/load_balancer_api.c + - src/core/lib/client_config/lb_policies/pick_first.c + - src/core/lib/client_config/lb_policies/round_robin.c + - src/core/lib/client_config/lb_policy.c + - src/core/lib/client_config/lb_policy_factory.c + - src/core/lib/client_config/lb_policy_registry.c + - src/core/lib/client_config/resolver.c + - src/core/lib/client_config/resolver_factory.c + - src/core/lib/client_config/resolver_registry.c + - src/core/lib/client_config/resolvers/dns_resolver.c + - src/core/lib/client_config/resolvers/sockaddr_resolver.c + - src/core/lib/client_config/subchannel.c + - src/core/lib/client_config/subchannel_factory.c + - src/core/lib/client_config/subchannel_index.c + - src/core/lib/client_config/uri_parser.c + - src/core/lib/compression/compression_algorithm.c + - src/core/lib/compression/message_compress.c + - src/core/lib/debug/trace.c + - src/core/lib/http/format_request.c + - src/core/lib/http/httpcli.c + - src/core/lib/http/parser.c + - src/core/lib/iomgr/closure.c + - src/core/lib/iomgr/endpoint.c + - src/core/lib/iomgr/endpoint_pair_posix.c + - src/core/lib/iomgr/endpoint_pair_windows.c + - src/core/lib/iomgr/exec_ctx.c + - src/core/lib/iomgr/executor.c + - src/core/lib/iomgr/fd_posix.c + - src/core/lib/iomgr/iocp_windows.c + - src/core/lib/iomgr/iomgr.c + - src/core/lib/iomgr/iomgr_posix.c + - src/core/lib/iomgr/iomgr_windows.c + - src/core/lib/iomgr/pollset_multipoller_with_epoll.c + - src/core/lib/iomgr/pollset_multipoller_with_poll_posix.c + - src/core/lib/iomgr/pollset_posix.c + - src/core/lib/iomgr/pollset_set_posix.c + - src/core/lib/iomgr/pollset_set_windows.c + - src/core/lib/iomgr/pollset_windows.c + - src/core/lib/iomgr/resolve_address_posix.c + - src/core/lib/iomgr/resolve_address_windows.c + - src/core/lib/iomgr/sockaddr_utils.c + - src/core/lib/iomgr/socket_utils_common_posix.c + - src/core/lib/iomgr/socket_utils_linux.c + - src/core/lib/iomgr/socket_utils_posix.c + - src/core/lib/iomgr/socket_windows.c + - src/core/lib/iomgr/tcp_client_posix.c + - src/core/lib/iomgr/tcp_client_windows.c + - src/core/lib/iomgr/tcp_posix.c + - src/core/lib/iomgr/tcp_server_posix.c + - src/core/lib/iomgr/tcp_server_windows.c + - src/core/lib/iomgr/tcp_windows.c + - src/core/lib/iomgr/time_averaged_stats.c + - src/core/lib/iomgr/timer.c + - src/core/lib/iomgr/timer_heap.c + - src/core/lib/iomgr/udp_server.c + - src/core/lib/iomgr/unix_sockets_posix.c + - src/core/lib/iomgr/unix_sockets_posix_noop.c + - src/core/lib/iomgr/wakeup_fd_eventfd.c + - src/core/lib/iomgr/wakeup_fd_nospecial.c + - src/core/lib/iomgr/wakeup_fd_pipe.c + - src/core/lib/iomgr/wakeup_fd_posix.c + - src/core/lib/iomgr/workqueue_posix.c + - src/core/lib/iomgr/workqueue_windows.c + - src/core/lib/json/json.c + - src/core/lib/json/json_reader.c + - src/core/lib/json/json_string.c + - src/core/lib/json/json_writer.c + - src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c + - src/core/lib/surface/alarm.c + - src/core/lib/surface/api_trace.c + - src/core/lib/surface/byte_buffer.c + - src/core/lib/surface/byte_buffer_reader.c + - src/core/lib/surface/call.c + - src/core/lib/surface/call_details.c + - src/core/lib/surface/call_log_batch.c + - src/core/lib/surface/channel.c + - src/core/lib/surface/channel_connectivity.c + - src/core/lib/surface/channel_create.c + - src/core/lib/surface/channel_init.c + - src/core/lib/surface/channel_ping.c + - src/core/lib/surface/channel_stack_type.c + - src/core/lib/surface/completion_queue.c + - src/core/lib/surface/event_string.c + - src/core/lib/surface/init.c + - src/core/lib/surface/lame_client.c + - src/core/lib/surface/metadata_array.c + - src/core/lib/surface/server.c + - src/core/lib/surface/server_chttp2.c + - src/core/lib/surface/validate_metadata.c + - src/core/lib/surface/version.c + - src/core/lib/transport/byte_stream.c + - src/core/lib/transport/chttp2/alpn.c + - src/core/lib/transport/chttp2/bin_encoder.c + - src/core/lib/transport/chttp2/frame_data.c + - src/core/lib/transport/chttp2/frame_goaway.c + - src/core/lib/transport/chttp2/frame_ping.c + - src/core/lib/transport/chttp2/frame_rst_stream.c + - src/core/lib/transport/chttp2/frame_settings.c + - src/core/lib/transport/chttp2/frame_window_update.c + - src/core/lib/transport/chttp2/hpack_encoder.c + - src/core/lib/transport/chttp2/hpack_parser.c + - src/core/lib/transport/chttp2/hpack_table.c + - src/core/lib/transport/chttp2/huffsyms.c + - src/core/lib/transport/chttp2/incoming_metadata.c + - src/core/lib/transport/chttp2/parsing.c + - src/core/lib/transport/chttp2/status_conversion.c + - src/core/lib/transport/chttp2/stream_lists.c + - src/core/lib/transport/chttp2/stream_map.c + - src/core/lib/transport/chttp2/timeout_encoding.c + - src/core/lib/transport/chttp2/varint.c + - src/core/lib/transport/chttp2/writing.c + - src/core/lib/transport/chttp2_transport.c + - src/core/lib/transport/connectivity_state.c + - src/core/lib/transport/metadata.c + - src/core/lib/transport/metadata_batch.c + - src/core/lib/transport/static_metadata.c + - src/core/lib/transport/transport.c + - src/core/lib/transport/transport_op_string.c - name: grpc_codegen public_headers: - include/grpc/impl/codegen/byte_buffer.h @@ -512,42 +512,42 @@ filegroups: - include/grpc/impl/codegen/status.h - name: grpc_secure headers: - - src/core/security/auth_filters.h - - src/core/security/b64.h - - src/core/security/credentials.h - - src/core/security/handshake.h - - src/core/security/json_token.h - - src/core/security/jwt_verifier.h - - src/core/security/secure_endpoint.h - - src/core/security/security_connector.h - - src/core/security/security_context.h - - src/core/tsi/fake_transport_security.h - - src/core/tsi/ssl_transport_security.h - - src/core/tsi/ssl_types.h - - src/core/tsi/transport_security.h - - src/core/tsi/transport_security_interface.h - src: - - src/core/http/httpcli_security_connector.c - - src/core/security/b64.c - - src/core/security/client_auth_filter.c - - src/core/security/credentials.c - - src/core/security/credentials_metadata.c - - src/core/security/credentials_posix.c - - src/core/security/credentials_win32.c - - src/core/security/google_default_credentials.c - - src/core/security/handshake.c - - src/core/security/json_token.c - - src/core/security/jwt_verifier.c - - src/core/security/secure_endpoint.c - - src/core/security/security_connector.c - - src/core/security/security_context.c - - src/core/security/server_auth_filter.c - - src/core/security/server_secure_chttp2.c - - src/core/surface/init_secure.c - - src/core/surface/secure_channel_create.c - - src/core/tsi/fake_transport_security.c - - src/core/tsi/ssl_transport_security.c - - src/core/tsi/transport_security.c + - src/core/lib/security/auth_filters.h + - src/core/lib/security/b64.h + - src/core/lib/security/credentials.h + - src/core/lib/security/handshake.h + - src/core/lib/security/json_token.h + - src/core/lib/security/jwt_verifier.h + - src/core/lib/security/secure_endpoint.h + - src/core/lib/security/security_connector.h + - src/core/lib/security/security_context.h + - src/core/lib/tsi/fake_transport_security.h + - src/core/lib/tsi/ssl_transport_security.h + - src/core/lib/tsi/ssl_types.h + - src/core/lib/tsi/transport_security.h + - src/core/lib/tsi/transport_security_interface.h + src: + - src/core/lib/http/httpcli_security_connector.c + - src/core/lib/security/b64.c + - src/core/lib/security/client_auth_filter.c + - src/core/lib/security/credentials.c + - src/core/lib/security/credentials_metadata.c + - src/core/lib/security/credentials_posix.c + - src/core/lib/security/credentials_win32.c + - src/core/lib/security/google_default_credentials.c + - src/core/lib/security/handshake.c + - src/core/lib/security/json_token.c + - src/core/lib/security/jwt_verifier.c + - src/core/lib/security/secure_endpoint.c + - src/core/lib/security/security_connector.c + - src/core/lib/security/security_context.c + - src/core/lib/security/server_auth_filter.c + - src/core/lib/security/server_secure_chttp2.c + - src/core/lib/surface/init_secure.c + - src/core/lib/surface/secure_channel_create.c + - src/core/lib/tsi/fake_transport_security.c + - src/core/lib/tsi/ssl_transport_security.c + - src/core/lib/tsi/transport_security.c - name: grpc_test_util_base headers: - test/core/end2end/cq_verifier.h @@ -683,7 +683,7 @@ libs: build: all language: c src: - - src/core/surface/init_unsecure.c + - src/core/lib/surface/init_unsecure.c deps: - gpr baselib: true @@ -702,9 +702,9 @@ libs: public_headers: - include/grpc/grpc_zookeeper.h headers: - - src/core/client_config/resolvers/zookeeper_resolver.h + - src/core/lib/client_config/resolvers/zookeeper_resolver.h src: - - src/core/client_config/resolvers/zookeeper_resolver.c + - src/core/lib/client_config/resolvers/zookeeper_resolver.c deps: - gpr - grpc diff --git a/config.m4 b/config.m4 index 8a5b2391b9..549e632cee 100644 --- a/config.m4 +++ b/config.m4 @@ -36,211 +36,211 @@ if test "$PHP_GRPC" != "no"; then src/php/ext/grpc/server.c \ src/php/ext/grpc/server_credentials.c \ src/php/ext/grpc/timeval.c \ - src/core/profiling/basic_timers.c \ - src/core/profiling/stap_timers.c \ - src/core/support/alloc.c \ - src/core/support/avl.c \ - src/core/support/backoff.c \ - src/core/support/cmdline.c \ - src/core/support/cpu_iphone.c \ - src/core/support/cpu_linux.c \ - src/core/support/cpu_posix.c \ - src/core/support/cpu_windows.c \ - src/core/support/env_linux.c \ - src/core/support/env_posix.c \ - src/core/support/env_win32.c \ - src/core/support/histogram.c \ - src/core/support/host_port.c \ - src/core/support/load_file.c \ - src/core/support/log.c \ - src/core/support/log_android.c \ - src/core/support/log_linux.c \ - src/core/support/log_posix.c \ - src/core/support/log_win32.c \ - src/core/support/murmur_hash.c \ - src/core/support/slice.c \ - src/core/support/slice_buffer.c \ - src/core/support/stack_lockfree.c \ - src/core/support/string.c \ - src/core/support/string_posix.c \ - src/core/support/string_win32.c \ - src/core/support/subprocess_posix.c \ - src/core/support/subprocess_windows.c \ - src/core/support/sync.c \ - src/core/support/sync_posix.c \ - src/core/support/sync_win32.c \ - src/core/support/thd.c \ - src/core/support/thd_posix.c \ - src/core/support/thd_win32.c \ - src/core/support/time.c \ - src/core/support/time_posix.c \ - src/core/support/time_precise.c \ - src/core/support/time_win32.c \ - src/core/support/tls_pthread.c \ - src/core/support/tmpfile_posix.c \ - src/core/support/tmpfile_win32.c \ - src/core/support/wrap_memcpy.c \ - src/core/census/grpc_context.c \ - src/core/census/grpc_filter.c \ - src/core/census/grpc_plugin.c \ - src/core/channel/channel_args.c \ - src/core/channel/channel_stack.c \ - src/core/channel/channel_stack_builder.c \ - src/core/channel/client_channel.c \ - src/core/channel/compress_filter.c \ - src/core/channel/connected_channel.c \ - src/core/channel/http_client_filter.c \ - src/core/channel/http_server_filter.c \ - src/core/channel/subchannel_call_holder.c \ - src/core/client_config/client_config.c \ - src/core/client_config/connector.c \ - src/core/client_config/default_initial_connect_string.c \ - src/core/client_config/initial_connect_string.c \ - src/core/client_config/lb_policies/load_balancer_api.c \ - src/core/client_config/lb_policies/pick_first.c \ - src/core/client_config/lb_policies/round_robin.c \ - src/core/client_config/lb_policy.c \ - src/core/client_config/lb_policy_factory.c \ - src/core/client_config/lb_policy_registry.c \ - src/core/client_config/resolver.c \ - src/core/client_config/resolver_factory.c \ - src/core/client_config/resolver_registry.c \ - src/core/client_config/resolvers/dns_resolver.c \ - src/core/client_config/resolvers/sockaddr_resolver.c \ - src/core/client_config/subchannel.c \ - src/core/client_config/subchannel_factory.c \ - src/core/client_config/subchannel_index.c \ - src/core/client_config/uri_parser.c \ - src/core/compression/compression_algorithm.c \ - src/core/compression/message_compress.c \ - src/core/debug/trace.c \ - src/core/http/format_request.c \ - src/core/http/httpcli.c \ - src/core/http/parser.c \ - src/core/iomgr/closure.c \ - src/core/iomgr/endpoint.c \ - src/core/iomgr/endpoint_pair_posix.c \ - src/core/iomgr/endpoint_pair_windows.c \ - src/core/iomgr/exec_ctx.c \ - src/core/iomgr/executor.c \ - src/core/iomgr/fd_posix.c \ - src/core/iomgr/iocp_windows.c \ - src/core/iomgr/iomgr.c \ - src/core/iomgr/iomgr_posix.c \ - src/core/iomgr/iomgr_windows.c \ - src/core/iomgr/pollset_multipoller_with_epoll.c \ - src/core/iomgr/pollset_multipoller_with_poll_posix.c \ - src/core/iomgr/pollset_posix.c \ - src/core/iomgr/pollset_set_posix.c \ - src/core/iomgr/pollset_set_windows.c \ - src/core/iomgr/pollset_windows.c \ - src/core/iomgr/resolve_address_posix.c \ - src/core/iomgr/resolve_address_windows.c \ - src/core/iomgr/sockaddr_utils.c \ - src/core/iomgr/socket_utils_common_posix.c \ - src/core/iomgr/socket_utils_linux.c \ - src/core/iomgr/socket_utils_posix.c \ - src/core/iomgr/socket_windows.c \ - src/core/iomgr/tcp_client_posix.c \ - src/core/iomgr/tcp_client_windows.c \ - src/core/iomgr/tcp_posix.c \ - src/core/iomgr/tcp_server_posix.c \ - src/core/iomgr/tcp_server_windows.c \ - src/core/iomgr/tcp_windows.c \ - src/core/iomgr/time_averaged_stats.c \ - src/core/iomgr/timer.c \ - src/core/iomgr/timer_heap.c \ - src/core/iomgr/udp_server.c \ - src/core/iomgr/unix_sockets_posix.c \ - src/core/iomgr/unix_sockets_posix_noop.c \ - src/core/iomgr/wakeup_fd_eventfd.c \ - src/core/iomgr/wakeup_fd_nospecial.c \ - src/core/iomgr/wakeup_fd_pipe.c \ - src/core/iomgr/wakeup_fd_posix.c \ - src/core/iomgr/workqueue_posix.c \ - src/core/iomgr/workqueue_windows.c \ - src/core/json/json.c \ - src/core/json/json_reader.c \ - src/core/json/json_string.c \ - src/core/json/json_writer.c \ - src/core/proto/grpc/lb/v0/load_balancer.pb.c \ - src/core/surface/alarm.c \ - src/core/surface/api_trace.c \ - src/core/surface/byte_buffer.c \ - src/core/surface/byte_buffer_reader.c \ - 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/channel_init.c \ - src/core/surface/channel_ping.c \ - src/core/surface/channel_stack_type.c \ - src/core/surface/completion_queue.c \ - src/core/surface/event_string.c \ - src/core/surface/init.c \ - src/core/surface/lame_client.c \ - src/core/surface/metadata_array.c \ - src/core/surface/server.c \ - src/core/surface/server_chttp2.c \ - src/core/surface/validate_metadata.c \ - src/core/surface/version.c \ - src/core/transport/byte_stream.c \ - src/core/transport/chttp2/alpn.c \ - src/core/transport/chttp2/bin_encoder.c \ - src/core/transport/chttp2/frame_data.c \ - src/core/transport/chttp2/frame_goaway.c \ - src/core/transport/chttp2/frame_ping.c \ - src/core/transport/chttp2/frame_rst_stream.c \ - src/core/transport/chttp2/frame_settings.c \ - src/core/transport/chttp2/frame_window_update.c \ - src/core/transport/chttp2/hpack_encoder.c \ - src/core/transport/chttp2/hpack_parser.c \ - src/core/transport/chttp2/hpack_table.c \ - src/core/transport/chttp2/huffsyms.c \ - src/core/transport/chttp2/incoming_metadata.c \ - src/core/transport/chttp2/parsing.c \ - src/core/transport/chttp2/status_conversion.c \ - src/core/transport/chttp2/stream_lists.c \ - src/core/transport/chttp2/stream_map.c \ - src/core/transport/chttp2/timeout_encoding.c \ - src/core/transport/chttp2/varint.c \ - src/core/transport/chttp2/writing.c \ - src/core/transport/chttp2_transport.c \ - src/core/transport/connectivity_state.c \ - src/core/transport/metadata.c \ - src/core/transport/metadata_batch.c \ - src/core/transport/static_metadata.c \ - src/core/transport/transport.c \ - src/core/transport/transport_op_string.c \ - src/core/http/httpcli_security_connector.c \ - src/core/security/b64.c \ - src/core/security/client_auth_filter.c \ - src/core/security/credentials.c \ - src/core/security/credentials_metadata.c \ - src/core/security/credentials_posix.c \ - src/core/security/credentials_win32.c \ - src/core/security/google_default_credentials.c \ - src/core/security/handshake.c \ - src/core/security/json_token.c \ - src/core/security/jwt_verifier.c \ - src/core/security/secure_endpoint.c \ - src/core/security/security_connector.c \ - src/core/security/security_context.c \ - src/core/security/server_auth_filter.c \ - src/core/security/server_secure_chttp2.c \ - src/core/surface/init_secure.c \ - src/core/surface/secure_channel_create.c \ - src/core/tsi/fake_transport_security.c \ - src/core/tsi/ssl_transport_security.c \ - src/core/tsi/transport_security.c \ - src/core/census/context.c \ - src/core/census/initialize.c \ - src/core/census/mlog.c \ - src/core/census/operation.c \ - src/core/census/placeholders.c \ - src/core/census/tracing.c \ + src/core/lib/profiling/basic_timers.c \ + src/core/lib/profiling/stap_timers.c \ + src/core/lib/support/alloc.c \ + src/core/lib/support/avl.c \ + src/core/lib/support/backoff.c \ + src/core/lib/support/cmdline.c \ + src/core/lib/support/cpu_iphone.c \ + src/core/lib/support/cpu_linux.c \ + src/core/lib/support/cpu_posix.c \ + src/core/lib/support/cpu_windows.c \ + src/core/lib/support/env_linux.c \ + src/core/lib/support/env_posix.c \ + src/core/lib/support/env_win32.c \ + src/core/lib/support/histogram.c \ + src/core/lib/support/host_port.c \ + src/core/lib/support/load_file.c \ + src/core/lib/support/log.c \ + src/core/lib/support/log_android.c \ + src/core/lib/support/log_linux.c \ + src/core/lib/support/log_posix.c \ + src/core/lib/support/log_win32.c \ + src/core/lib/support/murmur_hash.c \ + src/core/lib/support/slice.c \ + src/core/lib/support/slice_buffer.c \ + src/core/lib/support/stack_lockfree.c \ + src/core/lib/support/string.c \ + src/core/lib/support/string_posix.c \ + src/core/lib/support/string_win32.c \ + src/core/lib/support/subprocess_posix.c \ + src/core/lib/support/subprocess_windows.c \ + src/core/lib/support/sync.c \ + src/core/lib/support/sync_posix.c \ + src/core/lib/support/sync_win32.c \ + src/core/lib/support/thd.c \ + src/core/lib/support/thd_posix.c \ + src/core/lib/support/thd_win32.c \ + src/core/lib/support/time.c \ + src/core/lib/support/time_posix.c \ + src/core/lib/support/time_precise.c \ + src/core/lib/support/time_win32.c \ + src/core/lib/support/tls_pthread.c \ + src/core/lib/support/tmpfile_posix.c \ + src/core/lib/support/tmpfile_win32.c \ + src/core/lib/support/wrap_memcpy.c \ + src/core/lib/census/grpc_context.c \ + src/core/lib/census/grpc_filter.c \ + src/core/lib/census/grpc_plugin.c \ + src/core/lib/channel/channel_args.c \ + src/core/lib/channel/channel_stack.c \ + src/core/lib/channel/channel_stack_builder.c \ + src/core/lib/channel/client_channel.c \ + src/core/lib/channel/compress_filter.c \ + src/core/lib/channel/connected_channel.c \ + src/core/lib/channel/http_client_filter.c \ + src/core/lib/channel/http_server_filter.c \ + src/core/lib/channel/subchannel_call_holder.c \ + src/core/lib/client_config/client_config.c \ + src/core/lib/client_config/connector.c \ + src/core/lib/client_config/default_initial_connect_string.c \ + src/core/lib/client_config/initial_connect_string.c \ + src/core/lib/client_config/lb_policies/load_balancer_api.c \ + src/core/lib/client_config/lb_policies/pick_first.c \ + src/core/lib/client_config/lb_policies/round_robin.c \ + src/core/lib/client_config/lb_policy.c \ + src/core/lib/client_config/lb_policy_factory.c \ + src/core/lib/client_config/lb_policy_registry.c \ + src/core/lib/client_config/resolver.c \ + src/core/lib/client_config/resolver_factory.c \ + src/core/lib/client_config/resolver_registry.c \ + src/core/lib/client_config/resolvers/dns_resolver.c \ + src/core/lib/client_config/resolvers/sockaddr_resolver.c \ + src/core/lib/client_config/subchannel.c \ + src/core/lib/client_config/subchannel_factory.c \ + src/core/lib/client_config/subchannel_index.c \ + src/core/lib/client_config/uri_parser.c \ + src/core/lib/compression/compression_algorithm.c \ + src/core/lib/compression/message_compress.c \ + src/core/lib/debug/trace.c \ + src/core/lib/http/format_request.c \ + src/core/lib/http/httpcli.c \ + src/core/lib/http/parser.c \ + src/core/lib/iomgr/closure.c \ + src/core/lib/iomgr/endpoint.c \ + src/core/lib/iomgr/endpoint_pair_posix.c \ + src/core/lib/iomgr/endpoint_pair_windows.c \ + src/core/lib/iomgr/exec_ctx.c \ + src/core/lib/iomgr/executor.c \ + src/core/lib/iomgr/fd_posix.c \ + src/core/lib/iomgr/iocp_windows.c \ + src/core/lib/iomgr/iomgr.c \ + src/core/lib/iomgr/iomgr_posix.c \ + src/core/lib/iomgr/iomgr_windows.c \ + src/core/lib/iomgr/pollset_multipoller_with_epoll.c \ + src/core/lib/iomgr/pollset_multipoller_with_poll_posix.c \ + src/core/lib/iomgr/pollset_posix.c \ + src/core/lib/iomgr/pollset_set_posix.c \ + src/core/lib/iomgr/pollset_set_windows.c \ + src/core/lib/iomgr/pollset_windows.c \ + src/core/lib/iomgr/resolve_address_posix.c \ + src/core/lib/iomgr/resolve_address_windows.c \ + src/core/lib/iomgr/sockaddr_utils.c \ + src/core/lib/iomgr/socket_utils_common_posix.c \ + src/core/lib/iomgr/socket_utils_linux.c \ + src/core/lib/iomgr/socket_utils_posix.c \ + src/core/lib/iomgr/socket_windows.c \ + src/core/lib/iomgr/tcp_client_posix.c \ + src/core/lib/iomgr/tcp_client_windows.c \ + src/core/lib/iomgr/tcp_posix.c \ + src/core/lib/iomgr/tcp_server_posix.c \ + src/core/lib/iomgr/tcp_server_windows.c \ + src/core/lib/iomgr/tcp_windows.c \ + src/core/lib/iomgr/time_averaged_stats.c \ + src/core/lib/iomgr/timer.c \ + src/core/lib/iomgr/timer_heap.c \ + src/core/lib/iomgr/udp_server.c \ + src/core/lib/iomgr/unix_sockets_posix.c \ + src/core/lib/iomgr/unix_sockets_posix_noop.c \ + src/core/lib/iomgr/wakeup_fd_eventfd.c \ + src/core/lib/iomgr/wakeup_fd_nospecial.c \ + src/core/lib/iomgr/wakeup_fd_pipe.c \ + src/core/lib/iomgr/wakeup_fd_posix.c \ + src/core/lib/iomgr/workqueue_posix.c \ + src/core/lib/iomgr/workqueue_windows.c \ + src/core/lib/json/json.c \ + src/core/lib/json/json_reader.c \ + src/core/lib/json/json_string.c \ + src/core/lib/json/json_writer.c \ + src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c \ + src/core/lib/surface/alarm.c \ + src/core/lib/surface/api_trace.c \ + src/core/lib/surface/byte_buffer.c \ + src/core/lib/surface/byte_buffer_reader.c \ + src/core/lib/surface/call.c \ + src/core/lib/surface/call_details.c \ + src/core/lib/surface/call_log_batch.c \ + src/core/lib/surface/channel.c \ + src/core/lib/surface/channel_connectivity.c \ + src/core/lib/surface/channel_create.c \ + src/core/lib/surface/channel_init.c \ + src/core/lib/surface/channel_ping.c \ + src/core/lib/surface/channel_stack_type.c \ + src/core/lib/surface/completion_queue.c \ + src/core/lib/surface/event_string.c \ + src/core/lib/surface/init.c \ + src/core/lib/surface/lame_client.c \ + src/core/lib/surface/metadata_array.c \ + src/core/lib/surface/server.c \ + src/core/lib/surface/server_chttp2.c \ + src/core/lib/surface/validate_metadata.c \ + src/core/lib/surface/version.c \ + src/core/lib/transport/byte_stream.c \ + src/core/lib/transport/chttp2/alpn.c \ + src/core/lib/transport/chttp2/bin_encoder.c \ + src/core/lib/transport/chttp2/frame_data.c \ + src/core/lib/transport/chttp2/frame_goaway.c \ + src/core/lib/transport/chttp2/frame_ping.c \ + src/core/lib/transport/chttp2/frame_rst_stream.c \ + src/core/lib/transport/chttp2/frame_settings.c \ + src/core/lib/transport/chttp2/frame_window_update.c \ + src/core/lib/transport/chttp2/hpack_encoder.c \ + src/core/lib/transport/chttp2/hpack_parser.c \ + src/core/lib/transport/chttp2/hpack_table.c \ + src/core/lib/transport/chttp2/huffsyms.c \ + src/core/lib/transport/chttp2/incoming_metadata.c \ + src/core/lib/transport/chttp2/parsing.c \ + src/core/lib/transport/chttp2/status_conversion.c \ + src/core/lib/transport/chttp2/stream_lists.c \ + src/core/lib/transport/chttp2/stream_map.c \ + src/core/lib/transport/chttp2/timeout_encoding.c \ + src/core/lib/transport/chttp2/varint.c \ + src/core/lib/transport/chttp2/writing.c \ + src/core/lib/transport/chttp2_transport.c \ + src/core/lib/transport/connectivity_state.c \ + src/core/lib/transport/metadata.c \ + src/core/lib/transport/metadata_batch.c \ + src/core/lib/transport/static_metadata.c \ + src/core/lib/transport/transport.c \ + src/core/lib/transport/transport_op_string.c \ + src/core/lib/http/httpcli_security_connector.c \ + src/core/lib/security/b64.c \ + src/core/lib/security/client_auth_filter.c \ + src/core/lib/security/credentials.c \ + src/core/lib/security/credentials_metadata.c \ + src/core/lib/security/credentials_posix.c \ + src/core/lib/security/credentials_win32.c \ + src/core/lib/security/google_default_credentials.c \ + src/core/lib/security/handshake.c \ + src/core/lib/security/json_token.c \ + src/core/lib/security/jwt_verifier.c \ + src/core/lib/security/secure_endpoint.c \ + src/core/lib/security/security_connector.c \ + src/core/lib/security/security_context.c \ + src/core/lib/security/server_auth_filter.c \ + src/core/lib/security/server_secure_chttp2.c \ + src/core/lib/surface/init_secure.c \ + src/core/lib/surface/secure_channel_create.c \ + src/core/lib/tsi/fake_transport_security.c \ + src/core/lib/tsi/ssl_transport_security.c \ + src/core/lib/tsi/transport_security.c \ + src/core/lib/census/context.c \ + src/core/lib/census/initialize.c \ + src/core/lib/census/mlog.c \ + src/core/lib/census/operation.c \ + src/core/lib/census/placeholders.c \ + src/core/lib/census/tracing.c \ third_party/nanopb/pb_common.c \ third_party/nanopb/pb_decode.c \ third_party/nanopb/pb_encode.c \ @@ -546,24 +546,24 @@ if test "$PHP_GRPC" != "no"; then PHP_ADD_BUILD_DIR($ext_builddir/src/php/ext/grpc) PHP_ADD_BUILD_DIR($ext_builddir/src/boringssl) - PHP_ADD_BUILD_DIR($ext_builddir/src/core/census) - PHP_ADD_BUILD_DIR($ext_builddir/src/core/channel) - PHP_ADD_BUILD_DIR($ext_builddir/src/core/client_config) - PHP_ADD_BUILD_DIR($ext_builddir/src/core/client_config/lb_policies) - PHP_ADD_BUILD_DIR($ext_builddir/src/core/client_config/resolvers) - PHP_ADD_BUILD_DIR($ext_builddir/src/core/compression) - PHP_ADD_BUILD_DIR($ext_builddir/src/core/debug) - PHP_ADD_BUILD_DIR($ext_builddir/src/core/http) - PHP_ADD_BUILD_DIR($ext_builddir/src/core/iomgr) - PHP_ADD_BUILD_DIR($ext_builddir/src/core/json) - PHP_ADD_BUILD_DIR($ext_builddir/src/core/profiling) - PHP_ADD_BUILD_DIR($ext_builddir/src/core/proto/grpc/lb/v0) - PHP_ADD_BUILD_DIR($ext_builddir/src/core/security) - PHP_ADD_BUILD_DIR($ext_builddir/src/core/support) - PHP_ADD_BUILD_DIR($ext_builddir/src/core/surface) - PHP_ADD_BUILD_DIR($ext_builddir/src/core/transport) - PHP_ADD_BUILD_DIR($ext_builddir/src/core/transport/chttp2) - PHP_ADD_BUILD_DIR($ext_builddir/src/core/tsi) + PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/census) + PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/channel) + PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/client_config) + PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/client_config/lb_policies) + PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/client_config/resolvers) + PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/compression) + PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/debug) + PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/http) + PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/iomgr) + PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/json) + PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/profiling) + PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/proto/grpc/lb/v0) + PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/security) + PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/support) + PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/surface) + PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/transport) + PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/transport/chttp2) + PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/tsi) PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl/crypto) PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl/crypto/aes) PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl/crypto/asn1) diff --git a/gRPC.podspec b/gRPC.podspec index 2a3ed15141..3d5e8af15f 100644 --- a/gRPC.podspec +++ b/gRPC.podspec @@ -63,18 +63,18 @@ Pod::Spec.new do |s| # Core cross-platform gRPC library, written in C. s.subspec 'C-Core' do |ss| - ss.source_files = 'src/core/profiling/timers.h', - 'src/core/support/backoff.h', - 'src/core/support/block_annotate.h', - 'src/core/support/env.h', - 'src/core/support/load_file.h', - 'src/core/support/murmur_hash.h', - 'src/core/support/stack_lockfree.h', - 'src/core/support/string.h', - 'src/core/support/string_win32.h', - 'src/core/support/thd_internal.h', - 'src/core/support/time_precise.h', - 'src/core/support/tmpfile.h', + ss.source_files = 'src/core/lib/profiling/timers.h', + 'src/core/lib/support/backoff.h', + 'src/core/lib/support/block_annotate.h', + 'src/core/lib/support/env.h', + 'src/core/lib/support/load_file.h', + 'src/core/lib/support/murmur_hash.h', + 'src/core/lib/support/stack_lockfree.h', + 'src/core/lib/support/string.h', + 'src/core/lib/support/string_win32.h', + 'src/core/lib/support/thd_internal.h', + 'src/core/lib/support/time_precise.h', + 'src/core/lib/support/tmpfile.h', 'include/grpc/support/alloc.h', 'include/grpc/support/atm.h', 'include/grpc/support/atm_gcc_atomic.h', @@ -117,187 +117,187 @@ Pod::Spec.new do |s| 'include/grpc/impl/codegen/sync_posix.h', 'include/grpc/impl/codegen/sync_win32.h', 'include/grpc/impl/codegen/time.h', - 'src/core/profiling/basic_timers.c', - 'src/core/profiling/stap_timers.c', - 'src/core/support/alloc.c', - 'src/core/support/avl.c', - 'src/core/support/backoff.c', - 'src/core/support/cmdline.c', - 'src/core/support/cpu_iphone.c', - 'src/core/support/cpu_linux.c', - 'src/core/support/cpu_posix.c', - 'src/core/support/cpu_windows.c', - 'src/core/support/env_linux.c', - 'src/core/support/env_posix.c', - 'src/core/support/env_win32.c', - 'src/core/support/histogram.c', - 'src/core/support/host_port.c', - 'src/core/support/load_file.c', - 'src/core/support/log.c', - 'src/core/support/log_android.c', - 'src/core/support/log_linux.c', - 'src/core/support/log_posix.c', - 'src/core/support/log_win32.c', - 'src/core/support/murmur_hash.c', - 'src/core/support/slice.c', - 'src/core/support/slice_buffer.c', - 'src/core/support/stack_lockfree.c', - 'src/core/support/string.c', - 'src/core/support/string_posix.c', - 'src/core/support/string_win32.c', - 'src/core/support/subprocess_posix.c', - 'src/core/support/subprocess_windows.c', - 'src/core/support/sync.c', - 'src/core/support/sync_posix.c', - 'src/core/support/sync_win32.c', - 'src/core/support/thd.c', - 'src/core/support/thd_posix.c', - 'src/core/support/thd_win32.c', - 'src/core/support/time.c', - 'src/core/support/time_posix.c', - 'src/core/support/time_precise.c', - 'src/core/support/time_win32.c', - 'src/core/support/tls_pthread.c', - 'src/core/support/tmpfile_posix.c', - 'src/core/support/tmpfile_win32.c', - 'src/core/support/wrap_memcpy.c', - 'src/core/census/grpc_filter.h', - 'src/core/census/grpc_plugin.h', - 'src/core/channel/channel_args.h', - 'src/core/channel/channel_stack.h', - 'src/core/channel/channel_stack_builder.h', - 'src/core/channel/client_channel.h', - 'src/core/channel/compress_filter.h', - 'src/core/channel/connected_channel.h', - 'src/core/channel/context.h', - 'src/core/channel/http_client_filter.h', - 'src/core/channel/http_server_filter.h', - 'src/core/channel/subchannel_call_holder.h', - 'src/core/client_config/client_config.h', - 'src/core/client_config/connector.h', - 'src/core/client_config/initial_connect_string.h', - 'src/core/client_config/lb_policies/load_balancer_api.h', - 'src/core/client_config/lb_policies/pick_first.h', - 'src/core/client_config/lb_policies/round_robin.h', - 'src/core/client_config/lb_policy.h', - 'src/core/client_config/lb_policy_factory.h', - 'src/core/client_config/lb_policy_registry.h', - 'src/core/client_config/resolver.h', - 'src/core/client_config/resolver_factory.h', - 'src/core/client_config/resolver_registry.h', - 'src/core/client_config/resolvers/dns_resolver.h', - 'src/core/client_config/resolvers/sockaddr_resolver.h', - 'src/core/client_config/subchannel.h', - 'src/core/client_config/subchannel_factory.h', - 'src/core/client_config/subchannel_index.h', - 'src/core/client_config/uri_parser.h', - 'src/core/compression/algorithm_metadata.h', - 'src/core/compression/message_compress.h', - 'src/core/debug/trace.h', - 'src/core/http/format_request.h', - 'src/core/http/httpcli.h', - 'src/core/http/parser.h', - 'src/core/iomgr/closure.h', - 'src/core/iomgr/endpoint.h', - 'src/core/iomgr/endpoint_pair.h', - 'src/core/iomgr/exec_ctx.h', - 'src/core/iomgr/executor.h', - 'src/core/iomgr/fd_posix.h', - 'src/core/iomgr/iocp_windows.h', - 'src/core/iomgr/iomgr.h', - 'src/core/iomgr/iomgr_internal.h', - 'src/core/iomgr/iomgr_posix.h', - 'src/core/iomgr/pollset.h', - 'src/core/iomgr/pollset_posix.h', - 'src/core/iomgr/pollset_set.h', - 'src/core/iomgr/pollset_set_posix.h', - 'src/core/iomgr/pollset_set_windows.h', - 'src/core/iomgr/pollset_windows.h', - 'src/core/iomgr/resolve_address.h', - 'src/core/iomgr/sockaddr.h', - 'src/core/iomgr/sockaddr_posix.h', - 'src/core/iomgr/sockaddr_utils.h', - 'src/core/iomgr/sockaddr_win32.h', - 'src/core/iomgr/socket_utils_posix.h', - 'src/core/iomgr/socket_windows.h', - 'src/core/iomgr/tcp_client.h', - 'src/core/iomgr/tcp_posix.h', - 'src/core/iomgr/tcp_server.h', - 'src/core/iomgr/tcp_windows.h', - 'src/core/iomgr/time_averaged_stats.h', - 'src/core/iomgr/timer.h', - 'src/core/iomgr/timer_heap.h', - 'src/core/iomgr/udp_server.h', - 'src/core/iomgr/unix_sockets_posix.h', - 'src/core/iomgr/wakeup_fd_pipe.h', - 'src/core/iomgr/wakeup_fd_posix.h', - 'src/core/iomgr/workqueue.h', - 'src/core/iomgr/workqueue_posix.h', - 'src/core/iomgr/workqueue_windows.h', - 'src/core/json/json.h', - 'src/core/json/json_common.h', - 'src/core/json/json_reader.h', - 'src/core/json/json_writer.h', - 'src/core/proto/grpc/lb/v0/load_balancer.pb.h', - 'src/core/statistics/census_interface.h', - 'src/core/statistics/census_rpc_stats.h', - 'src/core/surface/api_trace.h', - 'src/core/surface/call.h', - 'src/core/surface/call_test_only.h', - 'src/core/surface/channel.h', - 'src/core/surface/channel_init.h', - 'src/core/surface/channel_stack_type.h', - 'src/core/surface/completion_queue.h', - 'src/core/surface/event_string.h', - 'src/core/surface/init.h', - 'src/core/surface/lame_client.h', - 'src/core/surface/server.h', - 'src/core/surface/surface_trace.h', - 'src/core/transport/byte_stream.h', - 'src/core/transport/chttp2/alpn.h', - 'src/core/transport/chttp2/bin_encoder.h', - 'src/core/transport/chttp2/frame.h', - 'src/core/transport/chttp2/frame_data.h', - 'src/core/transport/chttp2/frame_goaway.h', - 'src/core/transport/chttp2/frame_ping.h', - 'src/core/transport/chttp2/frame_rst_stream.h', - 'src/core/transport/chttp2/frame_settings.h', - 'src/core/transport/chttp2/frame_window_update.h', - 'src/core/transport/chttp2/hpack_encoder.h', - 'src/core/transport/chttp2/hpack_parser.h', - 'src/core/transport/chttp2/hpack_table.h', - 'src/core/transport/chttp2/http2_errors.h', - 'src/core/transport/chttp2/huffsyms.h', - 'src/core/transport/chttp2/incoming_metadata.h', - 'src/core/transport/chttp2/internal.h', - 'src/core/transport/chttp2/status_conversion.h', - 'src/core/transport/chttp2/stream_map.h', - 'src/core/transport/chttp2/timeout_encoding.h', - 'src/core/transport/chttp2/varint.h', - 'src/core/transport/chttp2_transport.h', - 'src/core/transport/connectivity_state.h', - 'src/core/transport/metadata.h', - 'src/core/transport/metadata_batch.h', - 'src/core/transport/static_metadata.h', - 'src/core/transport/transport.h', - 'src/core/transport/transport_impl.h', - 'src/core/security/auth_filters.h', - 'src/core/security/b64.h', - 'src/core/security/credentials.h', - 'src/core/security/handshake.h', - 'src/core/security/json_token.h', - 'src/core/security/jwt_verifier.h', - 'src/core/security/secure_endpoint.h', - 'src/core/security/security_connector.h', - 'src/core/security/security_context.h', - 'src/core/tsi/fake_transport_security.h', - 'src/core/tsi/ssl_transport_security.h', - 'src/core/tsi/ssl_types.h', - 'src/core/tsi/transport_security.h', - 'src/core/tsi/transport_security_interface.h', - 'src/core/census/aggregation.h', - 'src/core/census/mlog.h', - 'src/core/census/rpc_metric_id.h', + 'src/core/lib/profiling/basic_timers.c', + 'src/core/lib/profiling/stap_timers.c', + 'src/core/lib/support/alloc.c', + 'src/core/lib/support/avl.c', + 'src/core/lib/support/backoff.c', + 'src/core/lib/support/cmdline.c', + 'src/core/lib/support/cpu_iphone.c', + 'src/core/lib/support/cpu_linux.c', + 'src/core/lib/support/cpu_posix.c', + 'src/core/lib/support/cpu_windows.c', + 'src/core/lib/support/env_linux.c', + 'src/core/lib/support/env_posix.c', + 'src/core/lib/support/env_win32.c', + 'src/core/lib/support/histogram.c', + 'src/core/lib/support/host_port.c', + 'src/core/lib/support/load_file.c', + 'src/core/lib/support/log.c', + 'src/core/lib/support/log_android.c', + 'src/core/lib/support/log_linux.c', + 'src/core/lib/support/log_posix.c', + 'src/core/lib/support/log_win32.c', + 'src/core/lib/support/murmur_hash.c', + 'src/core/lib/support/slice.c', + 'src/core/lib/support/slice_buffer.c', + 'src/core/lib/support/stack_lockfree.c', + 'src/core/lib/support/string.c', + 'src/core/lib/support/string_posix.c', + 'src/core/lib/support/string_win32.c', + 'src/core/lib/support/subprocess_posix.c', + 'src/core/lib/support/subprocess_windows.c', + 'src/core/lib/support/sync.c', + 'src/core/lib/support/sync_posix.c', + 'src/core/lib/support/sync_win32.c', + 'src/core/lib/support/thd.c', + 'src/core/lib/support/thd_posix.c', + 'src/core/lib/support/thd_win32.c', + 'src/core/lib/support/time.c', + 'src/core/lib/support/time_posix.c', + 'src/core/lib/support/time_precise.c', + 'src/core/lib/support/time_win32.c', + 'src/core/lib/support/tls_pthread.c', + 'src/core/lib/support/tmpfile_posix.c', + 'src/core/lib/support/tmpfile_win32.c', + 'src/core/lib/support/wrap_memcpy.c', + 'src/core/lib/census/grpc_filter.h', + 'src/core/lib/census/grpc_plugin.h', + 'src/core/lib/channel/channel_args.h', + 'src/core/lib/channel/channel_stack.h', + 'src/core/lib/channel/channel_stack_builder.h', + 'src/core/lib/channel/client_channel.h', + 'src/core/lib/channel/compress_filter.h', + 'src/core/lib/channel/connected_channel.h', + 'src/core/lib/channel/context.h', + 'src/core/lib/channel/http_client_filter.h', + 'src/core/lib/channel/http_server_filter.h', + 'src/core/lib/channel/subchannel_call_holder.h', + 'src/core/lib/client_config/client_config.h', + 'src/core/lib/client_config/connector.h', + 'src/core/lib/client_config/initial_connect_string.h', + 'src/core/lib/client_config/lb_policies/load_balancer_api.h', + 'src/core/lib/client_config/lb_policies/pick_first.h', + 'src/core/lib/client_config/lb_policies/round_robin.h', + 'src/core/lib/client_config/lb_policy.h', + 'src/core/lib/client_config/lb_policy_factory.h', + 'src/core/lib/client_config/lb_policy_registry.h', + 'src/core/lib/client_config/resolver.h', + 'src/core/lib/client_config/resolver_factory.h', + 'src/core/lib/client_config/resolver_registry.h', + 'src/core/lib/client_config/resolvers/dns_resolver.h', + 'src/core/lib/client_config/resolvers/sockaddr_resolver.h', + 'src/core/lib/client_config/subchannel.h', + 'src/core/lib/client_config/subchannel_factory.h', + 'src/core/lib/client_config/subchannel_index.h', + 'src/core/lib/client_config/uri_parser.h', + 'src/core/lib/compression/algorithm_metadata.h', + 'src/core/lib/compression/message_compress.h', + 'src/core/lib/debug/trace.h', + 'src/core/lib/http/format_request.h', + 'src/core/lib/http/httpcli.h', + 'src/core/lib/http/parser.h', + 'src/core/lib/iomgr/closure.h', + 'src/core/lib/iomgr/endpoint.h', + 'src/core/lib/iomgr/endpoint_pair.h', + 'src/core/lib/iomgr/exec_ctx.h', + 'src/core/lib/iomgr/executor.h', + 'src/core/lib/iomgr/fd_posix.h', + 'src/core/lib/iomgr/iocp_windows.h', + 'src/core/lib/iomgr/iomgr.h', + 'src/core/lib/iomgr/iomgr_internal.h', + 'src/core/lib/iomgr/iomgr_posix.h', + 'src/core/lib/iomgr/pollset.h', + 'src/core/lib/iomgr/pollset_posix.h', + 'src/core/lib/iomgr/pollset_set.h', + 'src/core/lib/iomgr/pollset_set_posix.h', + 'src/core/lib/iomgr/pollset_set_windows.h', + 'src/core/lib/iomgr/pollset_windows.h', + 'src/core/lib/iomgr/resolve_address.h', + 'src/core/lib/iomgr/sockaddr.h', + 'src/core/lib/iomgr/sockaddr_posix.h', + 'src/core/lib/iomgr/sockaddr_utils.h', + 'src/core/lib/iomgr/sockaddr_win32.h', + 'src/core/lib/iomgr/socket_utils_posix.h', + 'src/core/lib/iomgr/socket_windows.h', + 'src/core/lib/iomgr/tcp_client.h', + 'src/core/lib/iomgr/tcp_posix.h', + 'src/core/lib/iomgr/tcp_server.h', + 'src/core/lib/iomgr/tcp_windows.h', + 'src/core/lib/iomgr/time_averaged_stats.h', + 'src/core/lib/iomgr/timer.h', + 'src/core/lib/iomgr/timer_heap.h', + 'src/core/lib/iomgr/udp_server.h', + 'src/core/lib/iomgr/unix_sockets_posix.h', + 'src/core/lib/iomgr/wakeup_fd_pipe.h', + 'src/core/lib/iomgr/wakeup_fd_posix.h', + 'src/core/lib/iomgr/workqueue.h', + 'src/core/lib/iomgr/workqueue_posix.h', + 'src/core/lib/iomgr/workqueue_windows.h', + 'src/core/lib/json/json.h', + 'src/core/lib/json/json_common.h', + 'src/core/lib/json/json_reader.h', + 'src/core/lib/json/json_writer.h', + 'src/core/lib/proto/grpc/lb/v0/load_balancer.pb.h', + 'src/core/lib/statistics/census_interface.h', + 'src/core/lib/statistics/census_rpc_stats.h', + 'src/core/lib/surface/api_trace.h', + 'src/core/lib/surface/call.h', + 'src/core/lib/surface/call_test_only.h', + 'src/core/lib/surface/channel.h', + 'src/core/lib/surface/channel_init.h', + 'src/core/lib/surface/channel_stack_type.h', + 'src/core/lib/surface/completion_queue.h', + 'src/core/lib/surface/event_string.h', + 'src/core/lib/surface/init.h', + 'src/core/lib/surface/lame_client.h', + 'src/core/lib/surface/server.h', + 'src/core/lib/surface/surface_trace.h', + 'src/core/lib/transport/byte_stream.h', + 'src/core/lib/transport/chttp2/alpn.h', + 'src/core/lib/transport/chttp2/bin_encoder.h', + 'src/core/lib/transport/chttp2/frame.h', + 'src/core/lib/transport/chttp2/frame_data.h', + 'src/core/lib/transport/chttp2/frame_goaway.h', + 'src/core/lib/transport/chttp2/frame_ping.h', + 'src/core/lib/transport/chttp2/frame_rst_stream.h', + 'src/core/lib/transport/chttp2/frame_settings.h', + 'src/core/lib/transport/chttp2/frame_window_update.h', + 'src/core/lib/transport/chttp2/hpack_encoder.h', + 'src/core/lib/transport/chttp2/hpack_parser.h', + 'src/core/lib/transport/chttp2/hpack_table.h', + 'src/core/lib/transport/chttp2/http2_errors.h', + 'src/core/lib/transport/chttp2/huffsyms.h', + 'src/core/lib/transport/chttp2/incoming_metadata.h', + 'src/core/lib/transport/chttp2/internal.h', + 'src/core/lib/transport/chttp2/status_conversion.h', + 'src/core/lib/transport/chttp2/stream_map.h', + 'src/core/lib/transport/chttp2/timeout_encoding.h', + 'src/core/lib/transport/chttp2/varint.h', + 'src/core/lib/transport/chttp2_transport.h', + 'src/core/lib/transport/connectivity_state.h', + 'src/core/lib/transport/metadata.h', + 'src/core/lib/transport/metadata_batch.h', + 'src/core/lib/transport/static_metadata.h', + 'src/core/lib/transport/transport.h', + 'src/core/lib/transport/transport_impl.h', + 'src/core/lib/security/auth_filters.h', + 'src/core/lib/security/b64.h', + 'src/core/lib/security/credentials.h', + 'src/core/lib/security/handshake.h', + 'src/core/lib/security/json_token.h', + 'src/core/lib/security/jwt_verifier.h', + 'src/core/lib/security/secure_endpoint.h', + 'src/core/lib/security/security_connector.h', + 'src/core/lib/security/security_context.h', + 'src/core/lib/tsi/fake_transport_security.h', + 'src/core/lib/tsi/ssl_transport_security.h', + 'src/core/lib/tsi/ssl_types.h', + 'src/core/lib/tsi/transport_security.h', + 'src/core/lib/tsi/transport_security_interface.h', + 'src/core/lib/census/aggregation.h', + 'src/core/lib/census/mlog.h', + 'src/core/lib/census/rpc_metric_id.h', 'third_party/nanopb/pb.h', 'third_party/nanopb/pb_common.h', 'third_party/nanopb/pb_decode.h', @@ -315,320 +315,320 @@ Pod::Spec.new do |s| 'include/grpc/impl/codegen/propagation_bits.h', 'include/grpc/impl/codegen/status.h', 'include/grpc/census.h', - 'src/core/census/grpc_context.c', - 'src/core/census/grpc_filter.c', - 'src/core/census/grpc_plugin.c', - 'src/core/channel/channel_args.c', - 'src/core/channel/channel_stack.c', - 'src/core/channel/channel_stack_builder.c', - 'src/core/channel/client_channel.c', - 'src/core/channel/compress_filter.c', - 'src/core/channel/connected_channel.c', - 'src/core/channel/http_client_filter.c', - 'src/core/channel/http_server_filter.c', - 'src/core/channel/subchannel_call_holder.c', - 'src/core/client_config/client_config.c', - 'src/core/client_config/connector.c', - 'src/core/client_config/default_initial_connect_string.c', - 'src/core/client_config/initial_connect_string.c', - 'src/core/client_config/lb_policies/load_balancer_api.c', - 'src/core/client_config/lb_policies/pick_first.c', - 'src/core/client_config/lb_policies/round_robin.c', - 'src/core/client_config/lb_policy.c', - 'src/core/client_config/lb_policy_factory.c', - 'src/core/client_config/lb_policy_registry.c', - 'src/core/client_config/resolver.c', - 'src/core/client_config/resolver_factory.c', - 'src/core/client_config/resolver_registry.c', - 'src/core/client_config/resolvers/dns_resolver.c', - 'src/core/client_config/resolvers/sockaddr_resolver.c', - 'src/core/client_config/subchannel.c', - 'src/core/client_config/subchannel_factory.c', - 'src/core/client_config/subchannel_index.c', - 'src/core/client_config/uri_parser.c', - 'src/core/compression/compression_algorithm.c', - 'src/core/compression/message_compress.c', - 'src/core/debug/trace.c', - 'src/core/http/format_request.c', - 'src/core/http/httpcli.c', - 'src/core/http/parser.c', - 'src/core/iomgr/closure.c', - 'src/core/iomgr/endpoint.c', - 'src/core/iomgr/endpoint_pair_posix.c', - 'src/core/iomgr/endpoint_pair_windows.c', - 'src/core/iomgr/exec_ctx.c', - 'src/core/iomgr/executor.c', - 'src/core/iomgr/fd_posix.c', - 'src/core/iomgr/iocp_windows.c', - 'src/core/iomgr/iomgr.c', - 'src/core/iomgr/iomgr_posix.c', - 'src/core/iomgr/iomgr_windows.c', - 'src/core/iomgr/pollset_multipoller_with_epoll.c', - 'src/core/iomgr/pollset_multipoller_with_poll_posix.c', - 'src/core/iomgr/pollset_posix.c', - 'src/core/iomgr/pollset_set_posix.c', - 'src/core/iomgr/pollset_set_windows.c', - 'src/core/iomgr/pollset_windows.c', - 'src/core/iomgr/resolve_address_posix.c', - 'src/core/iomgr/resolve_address_windows.c', - 'src/core/iomgr/sockaddr_utils.c', - 'src/core/iomgr/socket_utils_common_posix.c', - 'src/core/iomgr/socket_utils_linux.c', - 'src/core/iomgr/socket_utils_posix.c', - 'src/core/iomgr/socket_windows.c', - 'src/core/iomgr/tcp_client_posix.c', - 'src/core/iomgr/tcp_client_windows.c', - 'src/core/iomgr/tcp_posix.c', - 'src/core/iomgr/tcp_server_posix.c', - 'src/core/iomgr/tcp_server_windows.c', - 'src/core/iomgr/tcp_windows.c', - 'src/core/iomgr/time_averaged_stats.c', - 'src/core/iomgr/timer.c', - 'src/core/iomgr/timer_heap.c', - 'src/core/iomgr/udp_server.c', - 'src/core/iomgr/unix_sockets_posix.c', - 'src/core/iomgr/unix_sockets_posix_noop.c', - 'src/core/iomgr/wakeup_fd_eventfd.c', - 'src/core/iomgr/wakeup_fd_nospecial.c', - 'src/core/iomgr/wakeup_fd_pipe.c', - 'src/core/iomgr/wakeup_fd_posix.c', - 'src/core/iomgr/workqueue_posix.c', - 'src/core/iomgr/workqueue_windows.c', - 'src/core/json/json.c', - 'src/core/json/json_reader.c', - 'src/core/json/json_string.c', - 'src/core/json/json_writer.c', - 'src/core/proto/grpc/lb/v0/load_balancer.pb.c', - 'src/core/surface/alarm.c', - 'src/core/surface/api_trace.c', - 'src/core/surface/byte_buffer.c', - 'src/core/surface/byte_buffer_reader.c', - '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/channel_init.c', - 'src/core/surface/channel_ping.c', - 'src/core/surface/channel_stack_type.c', - 'src/core/surface/completion_queue.c', - 'src/core/surface/event_string.c', - 'src/core/surface/init.c', - 'src/core/surface/lame_client.c', - 'src/core/surface/metadata_array.c', - 'src/core/surface/server.c', - 'src/core/surface/server_chttp2.c', - 'src/core/surface/validate_metadata.c', - 'src/core/surface/version.c', - 'src/core/transport/byte_stream.c', - 'src/core/transport/chttp2/alpn.c', - 'src/core/transport/chttp2/bin_encoder.c', - 'src/core/transport/chttp2/frame_data.c', - 'src/core/transport/chttp2/frame_goaway.c', - 'src/core/transport/chttp2/frame_ping.c', - 'src/core/transport/chttp2/frame_rst_stream.c', - 'src/core/transport/chttp2/frame_settings.c', - 'src/core/transport/chttp2/frame_window_update.c', - 'src/core/transport/chttp2/hpack_encoder.c', - 'src/core/transport/chttp2/hpack_parser.c', - 'src/core/transport/chttp2/hpack_table.c', - 'src/core/transport/chttp2/huffsyms.c', - 'src/core/transport/chttp2/incoming_metadata.c', - 'src/core/transport/chttp2/parsing.c', - 'src/core/transport/chttp2/status_conversion.c', - 'src/core/transport/chttp2/stream_lists.c', - 'src/core/transport/chttp2/stream_map.c', - 'src/core/transport/chttp2/timeout_encoding.c', - 'src/core/transport/chttp2/varint.c', - 'src/core/transport/chttp2/writing.c', - 'src/core/transport/chttp2_transport.c', - 'src/core/transport/connectivity_state.c', - 'src/core/transport/metadata.c', - 'src/core/transport/metadata_batch.c', - 'src/core/transport/static_metadata.c', - 'src/core/transport/transport.c', - 'src/core/transport/transport_op_string.c', - 'src/core/http/httpcli_security_connector.c', - 'src/core/security/b64.c', - 'src/core/security/client_auth_filter.c', - 'src/core/security/credentials.c', - 'src/core/security/credentials_metadata.c', - 'src/core/security/credentials_posix.c', - 'src/core/security/credentials_win32.c', - 'src/core/security/google_default_credentials.c', - 'src/core/security/handshake.c', - 'src/core/security/json_token.c', - 'src/core/security/jwt_verifier.c', - 'src/core/security/secure_endpoint.c', - 'src/core/security/security_connector.c', - 'src/core/security/security_context.c', - 'src/core/security/server_auth_filter.c', - 'src/core/security/server_secure_chttp2.c', - 'src/core/surface/init_secure.c', - 'src/core/surface/secure_channel_create.c', - 'src/core/tsi/fake_transport_security.c', - 'src/core/tsi/ssl_transport_security.c', - 'src/core/tsi/transport_security.c', - 'src/core/census/context.c', - 'src/core/census/initialize.c', - 'src/core/census/mlog.c', - 'src/core/census/operation.c', - 'src/core/census/placeholders.c', - 'src/core/census/tracing.c', + 'src/core/lib/census/grpc_context.c', + 'src/core/lib/census/grpc_filter.c', + 'src/core/lib/census/grpc_plugin.c', + 'src/core/lib/channel/channel_args.c', + 'src/core/lib/channel/channel_stack.c', + 'src/core/lib/channel/channel_stack_builder.c', + 'src/core/lib/channel/client_channel.c', + 'src/core/lib/channel/compress_filter.c', + 'src/core/lib/channel/connected_channel.c', + 'src/core/lib/channel/http_client_filter.c', + 'src/core/lib/channel/http_server_filter.c', + 'src/core/lib/channel/subchannel_call_holder.c', + 'src/core/lib/client_config/client_config.c', + 'src/core/lib/client_config/connector.c', + 'src/core/lib/client_config/default_initial_connect_string.c', + 'src/core/lib/client_config/initial_connect_string.c', + 'src/core/lib/client_config/lb_policies/load_balancer_api.c', + 'src/core/lib/client_config/lb_policies/pick_first.c', + 'src/core/lib/client_config/lb_policies/round_robin.c', + 'src/core/lib/client_config/lb_policy.c', + 'src/core/lib/client_config/lb_policy_factory.c', + 'src/core/lib/client_config/lb_policy_registry.c', + 'src/core/lib/client_config/resolver.c', + 'src/core/lib/client_config/resolver_factory.c', + 'src/core/lib/client_config/resolver_registry.c', + 'src/core/lib/client_config/resolvers/dns_resolver.c', + 'src/core/lib/client_config/resolvers/sockaddr_resolver.c', + 'src/core/lib/client_config/subchannel.c', + 'src/core/lib/client_config/subchannel_factory.c', + 'src/core/lib/client_config/subchannel_index.c', + 'src/core/lib/client_config/uri_parser.c', + 'src/core/lib/compression/compression_algorithm.c', + 'src/core/lib/compression/message_compress.c', + 'src/core/lib/debug/trace.c', + 'src/core/lib/http/format_request.c', + 'src/core/lib/http/httpcli.c', + 'src/core/lib/http/parser.c', + 'src/core/lib/iomgr/closure.c', + 'src/core/lib/iomgr/endpoint.c', + 'src/core/lib/iomgr/endpoint_pair_posix.c', + 'src/core/lib/iomgr/endpoint_pair_windows.c', + 'src/core/lib/iomgr/exec_ctx.c', + 'src/core/lib/iomgr/executor.c', + 'src/core/lib/iomgr/fd_posix.c', + 'src/core/lib/iomgr/iocp_windows.c', + 'src/core/lib/iomgr/iomgr.c', + 'src/core/lib/iomgr/iomgr_posix.c', + 'src/core/lib/iomgr/iomgr_windows.c', + 'src/core/lib/iomgr/pollset_multipoller_with_epoll.c', + 'src/core/lib/iomgr/pollset_multipoller_with_poll_posix.c', + 'src/core/lib/iomgr/pollset_posix.c', + 'src/core/lib/iomgr/pollset_set_posix.c', + 'src/core/lib/iomgr/pollset_set_windows.c', + 'src/core/lib/iomgr/pollset_windows.c', + 'src/core/lib/iomgr/resolve_address_posix.c', + 'src/core/lib/iomgr/resolve_address_windows.c', + 'src/core/lib/iomgr/sockaddr_utils.c', + 'src/core/lib/iomgr/socket_utils_common_posix.c', + 'src/core/lib/iomgr/socket_utils_linux.c', + 'src/core/lib/iomgr/socket_utils_posix.c', + 'src/core/lib/iomgr/socket_windows.c', + 'src/core/lib/iomgr/tcp_client_posix.c', + 'src/core/lib/iomgr/tcp_client_windows.c', + 'src/core/lib/iomgr/tcp_posix.c', + 'src/core/lib/iomgr/tcp_server_posix.c', + 'src/core/lib/iomgr/tcp_server_windows.c', + 'src/core/lib/iomgr/tcp_windows.c', + 'src/core/lib/iomgr/time_averaged_stats.c', + 'src/core/lib/iomgr/timer.c', + 'src/core/lib/iomgr/timer_heap.c', + 'src/core/lib/iomgr/udp_server.c', + 'src/core/lib/iomgr/unix_sockets_posix.c', + 'src/core/lib/iomgr/unix_sockets_posix_noop.c', + 'src/core/lib/iomgr/wakeup_fd_eventfd.c', + 'src/core/lib/iomgr/wakeup_fd_nospecial.c', + 'src/core/lib/iomgr/wakeup_fd_pipe.c', + 'src/core/lib/iomgr/wakeup_fd_posix.c', + 'src/core/lib/iomgr/workqueue_posix.c', + 'src/core/lib/iomgr/workqueue_windows.c', + 'src/core/lib/json/json.c', + 'src/core/lib/json/json_reader.c', + 'src/core/lib/json/json_string.c', + 'src/core/lib/json/json_writer.c', + 'src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c', + 'src/core/lib/surface/alarm.c', + 'src/core/lib/surface/api_trace.c', + 'src/core/lib/surface/byte_buffer.c', + 'src/core/lib/surface/byte_buffer_reader.c', + 'src/core/lib/surface/call.c', + 'src/core/lib/surface/call_details.c', + 'src/core/lib/surface/call_log_batch.c', + 'src/core/lib/surface/channel.c', + 'src/core/lib/surface/channel_connectivity.c', + 'src/core/lib/surface/channel_create.c', + 'src/core/lib/surface/channel_init.c', + 'src/core/lib/surface/channel_ping.c', + 'src/core/lib/surface/channel_stack_type.c', + 'src/core/lib/surface/completion_queue.c', + 'src/core/lib/surface/event_string.c', + 'src/core/lib/surface/init.c', + 'src/core/lib/surface/lame_client.c', + 'src/core/lib/surface/metadata_array.c', + 'src/core/lib/surface/server.c', + 'src/core/lib/surface/server_chttp2.c', + 'src/core/lib/surface/validate_metadata.c', + 'src/core/lib/surface/version.c', + 'src/core/lib/transport/byte_stream.c', + 'src/core/lib/transport/chttp2/alpn.c', + 'src/core/lib/transport/chttp2/bin_encoder.c', + 'src/core/lib/transport/chttp2/frame_data.c', + 'src/core/lib/transport/chttp2/frame_goaway.c', + 'src/core/lib/transport/chttp2/frame_ping.c', + 'src/core/lib/transport/chttp2/frame_rst_stream.c', + 'src/core/lib/transport/chttp2/frame_settings.c', + 'src/core/lib/transport/chttp2/frame_window_update.c', + 'src/core/lib/transport/chttp2/hpack_encoder.c', + 'src/core/lib/transport/chttp2/hpack_parser.c', + 'src/core/lib/transport/chttp2/hpack_table.c', + 'src/core/lib/transport/chttp2/huffsyms.c', + 'src/core/lib/transport/chttp2/incoming_metadata.c', + 'src/core/lib/transport/chttp2/parsing.c', + 'src/core/lib/transport/chttp2/status_conversion.c', + 'src/core/lib/transport/chttp2/stream_lists.c', + 'src/core/lib/transport/chttp2/stream_map.c', + 'src/core/lib/transport/chttp2/timeout_encoding.c', + 'src/core/lib/transport/chttp2/varint.c', + 'src/core/lib/transport/chttp2/writing.c', + 'src/core/lib/transport/chttp2_transport.c', + 'src/core/lib/transport/connectivity_state.c', + 'src/core/lib/transport/metadata.c', + 'src/core/lib/transport/metadata_batch.c', + 'src/core/lib/transport/static_metadata.c', + 'src/core/lib/transport/transport.c', + 'src/core/lib/transport/transport_op_string.c', + 'src/core/lib/http/httpcli_security_connector.c', + 'src/core/lib/security/b64.c', + 'src/core/lib/security/client_auth_filter.c', + 'src/core/lib/security/credentials.c', + 'src/core/lib/security/credentials_metadata.c', + 'src/core/lib/security/credentials_posix.c', + 'src/core/lib/security/credentials_win32.c', + 'src/core/lib/security/google_default_credentials.c', + 'src/core/lib/security/handshake.c', + 'src/core/lib/security/json_token.c', + 'src/core/lib/security/jwt_verifier.c', + 'src/core/lib/security/secure_endpoint.c', + 'src/core/lib/security/security_connector.c', + 'src/core/lib/security/security_context.c', + 'src/core/lib/security/server_auth_filter.c', + 'src/core/lib/security/server_secure_chttp2.c', + 'src/core/lib/surface/init_secure.c', + 'src/core/lib/surface/secure_channel_create.c', + 'src/core/lib/tsi/fake_transport_security.c', + 'src/core/lib/tsi/ssl_transport_security.c', + 'src/core/lib/tsi/transport_security.c', + 'src/core/lib/census/context.c', + 'src/core/lib/census/initialize.c', + 'src/core/lib/census/mlog.c', + 'src/core/lib/census/operation.c', + 'src/core/lib/census/placeholders.c', + 'src/core/lib/census/tracing.c', 'third_party/nanopb/pb_common.c', 'third_party/nanopb/pb_decode.c', 'third_party/nanopb/pb_encode.c' - ss.private_header_files = 'src/core/profiling/timers.h', - 'src/core/support/backoff.h', - 'src/core/support/block_annotate.h', - 'src/core/support/env.h', - 'src/core/support/load_file.h', - 'src/core/support/murmur_hash.h', - 'src/core/support/stack_lockfree.h', - 'src/core/support/string.h', - 'src/core/support/string_win32.h', - 'src/core/support/thd_internal.h', - 'src/core/support/time_precise.h', - 'src/core/support/tmpfile.h', - 'src/core/census/grpc_filter.h', - 'src/core/census/grpc_plugin.h', - 'src/core/channel/channel_args.h', - 'src/core/channel/channel_stack.h', - 'src/core/channel/channel_stack_builder.h', - 'src/core/channel/client_channel.h', - 'src/core/channel/compress_filter.h', - 'src/core/channel/connected_channel.h', - 'src/core/channel/context.h', - 'src/core/channel/http_client_filter.h', - 'src/core/channel/http_server_filter.h', - 'src/core/channel/subchannel_call_holder.h', - 'src/core/client_config/client_config.h', - 'src/core/client_config/connector.h', - 'src/core/client_config/initial_connect_string.h', - 'src/core/client_config/lb_policies/load_balancer_api.h', - 'src/core/client_config/lb_policies/pick_first.h', - 'src/core/client_config/lb_policies/round_robin.h', - 'src/core/client_config/lb_policy.h', - 'src/core/client_config/lb_policy_factory.h', - 'src/core/client_config/lb_policy_registry.h', - 'src/core/client_config/resolver.h', - 'src/core/client_config/resolver_factory.h', - 'src/core/client_config/resolver_registry.h', - 'src/core/client_config/resolvers/dns_resolver.h', - 'src/core/client_config/resolvers/sockaddr_resolver.h', - 'src/core/client_config/subchannel.h', - 'src/core/client_config/subchannel_factory.h', - 'src/core/client_config/subchannel_index.h', - 'src/core/client_config/uri_parser.h', - 'src/core/compression/algorithm_metadata.h', - 'src/core/compression/message_compress.h', - 'src/core/debug/trace.h', - 'src/core/http/format_request.h', - 'src/core/http/httpcli.h', - 'src/core/http/parser.h', - 'src/core/iomgr/closure.h', - 'src/core/iomgr/endpoint.h', - 'src/core/iomgr/endpoint_pair.h', - 'src/core/iomgr/exec_ctx.h', - 'src/core/iomgr/executor.h', - 'src/core/iomgr/fd_posix.h', - 'src/core/iomgr/iocp_windows.h', - 'src/core/iomgr/iomgr.h', - 'src/core/iomgr/iomgr_internal.h', - 'src/core/iomgr/iomgr_posix.h', - 'src/core/iomgr/pollset.h', - 'src/core/iomgr/pollset_posix.h', - 'src/core/iomgr/pollset_set.h', - 'src/core/iomgr/pollset_set_posix.h', - 'src/core/iomgr/pollset_set_windows.h', - 'src/core/iomgr/pollset_windows.h', - 'src/core/iomgr/resolve_address.h', - 'src/core/iomgr/sockaddr.h', - 'src/core/iomgr/sockaddr_posix.h', - 'src/core/iomgr/sockaddr_utils.h', - 'src/core/iomgr/sockaddr_win32.h', - 'src/core/iomgr/socket_utils_posix.h', - 'src/core/iomgr/socket_windows.h', - 'src/core/iomgr/tcp_client.h', - 'src/core/iomgr/tcp_posix.h', - 'src/core/iomgr/tcp_server.h', - 'src/core/iomgr/tcp_windows.h', - 'src/core/iomgr/time_averaged_stats.h', - 'src/core/iomgr/timer.h', - 'src/core/iomgr/timer_heap.h', - 'src/core/iomgr/udp_server.h', - 'src/core/iomgr/unix_sockets_posix.h', - 'src/core/iomgr/wakeup_fd_pipe.h', - 'src/core/iomgr/wakeup_fd_posix.h', - 'src/core/iomgr/workqueue.h', - 'src/core/iomgr/workqueue_posix.h', - 'src/core/iomgr/workqueue_windows.h', - 'src/core/json/json.h', - 'src/core/json/json_common.h', - 'src/core/json/json_reader.h', - 'src/core/json/json_writer.h', - 'src/core/proto/grpc/lb/v0/load_balancer.pb.h', - 'src/core/statistics/census_interface.h', - 'src/core/statistics/census_rpc_stats.h', - 'src/core/surface/api_trace.h', - 'src/core/surface/call.h', - 'src/core/surface/call_test_only.h', - 'src/core/surface/channel.h', - 'src/core/surface/channel_init.h', - 'src/core/surface/channel_stack_type.h', - 'src/core/surface/completion_queue.h', - 'src/core/surface/event_string.h', - 'src/core/surface/init.h', - 'src/core/surface/lame_client.h', - 'src/core/surface/server.h', - 'src/core/surface/surface_trace.h', - 'src/core/transport/byte_stream.h', - 'src/core/transport/chttp2/alpn.h', - 'src/core/transport/chttp2/bin_encoder.h', - 'src/core/transport/chttp2/frame.h', - 'src/core/transport/chttp2/frame_data.h', - 'src/core/transport/chttp2/frame_goaway.h', - 'src/core/transport/chttp2/frame_ping.h', - 'src/core/transport/chttp2/frame_rst_stream.h', - 'src/core/transport/chttp2/frame_settings.h', - 'src/core/transport/chttp2/frame_window_update.h', - 'src/core/transport/chttp2/hpack_encoder.h', - 'src/core/transport/chttp2/hpack_parser.h', - 'src/core/transport/chttp2/hpack_table.h', - 'src/core/transport/chttp2/http2_errors.h', - 'src/core/transport/chttp2/huffsyms.h', - 'src/core/transport/chttp2/incoming_metadata.h', - 'src/core/transport/chttp2/internal.h', - 'src/core/transport/chttp2/status_conversion.h', - 'src/core/transport/chttp2/stream_map.h', - 'src/core/transport/chttp2/timeout_encoding.h', - 'src/core/transport/chttp2/varint.h', - 'src/core/transport/chttp2_transport.h', - 'src/core/transport/connectivity_state.h', - 'src/core/transport/metadata.h', - 'src/core/transport/metadata_batch.h', - 'src/core/transport/static_metadata.h', - 'src/core/transport/transport.h', - 'src/core/transport/transport_impl.h', - 'src/core/security/auth_filters.h', - 'src/core/security/b64.h', - 'src/core/security/credentials.h', - 'src/core/security/handshake.h', - 'src/core/security/json_token.h', - 'src/core/security/jwt_verifier.h', - 'src/core/security/secure_endpoint.h', - 'src/core/security/security_connector.h', - 'src/core/security/security_context.h', - 'src/core/tsi/fake_transport_security.h', - 'src/core/tsi/ssl_transport_security.h', - 'src/core/tsi/ssl_types.h', - 'src/core/tsi/transport_security.h', - 'src/core/tsi/transport_security_interface.h', - 'src/core/census/aggregation.h', - 'src/core/census/mlog.h', - 'src/core/census/rpc_metric_id.h', + ss.private_header_files = 'src/core/lib/profiling/timers.h', + 'src/core/lib/support/backoff.h', + 'src/core/lib/support/block_annotate.h', + 'src/core/lib/support/env.h', + 'src/core/lib/support/load_file.h', + 'src/core/lib/support/murmur_hash.h', + 'src/core/lib/support/stack_lockfree.h', + 'src/core/lib/support/string.h', + 'src/core/lib/support/string_win32.h', + 'src/core/lib/support/thd_internal.h', + 'src/core/lib/support/time_precise.h', + 'src/core/lib/support/tmpfile.h', + 'src/core/lib/census/grpc_filter.h', + 'src/core/lib/census/grpc_plugin.h', + 'src/core/lib/channel/channel_args.h', + 'src/core/lib/channel/channel_stack.h', + 'src/core/lib/channel/channel_stack_builder.h', + 'src/core/lib/channel/client_channel.h', + 'src/core/lib/channel/compress_filter.h', + 'src/core/lib/channel/connected_channel.h', + 'src/core/lib/channel/context.h', + 'src/core/lib/channel/http_client_filter.h', + 'src/core/lib/channel/http_server_filter.h', + 'src/core/lib/channel/subchannel_call_holder.h', + 'src/core/lib/client_config/client_config.h', + 'src/core/lib/client_config/connector.h', + 'src/core/lib/client_config/initial_connect_string.h', + 'src/core/lib/client_config/lb_policies/load_balancer_api.h', + 'src/core/lib/client_config/lb_policies/pick_first.h', + 'src/core/lib/client_config/lb_policies/round_robin.h', + 'src/core/lib/client_config/lb_policy.h', + 'src/core/lib/client_config/lb_policy_factory.h', + 'src/core/lib/client_config/lb_policy_registry.h', + 'src/core/lib/client_config/resolver.h', + 'src/core/lib/client_config/resolver_factory.h', + 'src/core/lib/client_config/resolver_registry.h', + 'src/core/lib/client_config/resolvers/dns_resolver.h', + 'src/core/lib/client_config/resolvers/sockaddr_resolver.h', + 'src/core/lib/client_config/subchannel.h', + 'src/core/lib/client_config/subchannel_factory.h', + 'src/core/lib/client_config/subchannel_index.h', + 'src/core/lib/client_config/uri_parser.h', + 'src/core/lib/compression/algorithm_metadata.h', + 'src/core/lib/compression/message_compress.h', + 'src/core/lib/debug/trace.h', + 'src/core/lib/http/format_request.h', + 'src/core/lib/http/httpcli.h', + 'src/core/lib/http/parser.h', + 'src/core/lib/iomgr/closure.h', + 'src/core/lib/iomgr/endpoint.h', + 'src/core/lib/iomgr/endpoint_pair.h', + 'src/core/lib/iomgr/exec_ctx.h', + 'src/core/lib/iomgr/executor.h', + 'src/core/lib/iomgr/fd_posix.h', + 'src/core/lib/iomgr/iocp_windows.h', + 'src/core/lib/iomgr/iomgr.h', + 'src/core/lib/iomgr/iomgr_internal.h', + 'src/core/lib/iomgr/iomgr_posix.h', + 'src/core/lib/iomgr/pollset.h', + 'src/core/lib/iomgr/pollset_posix.h', + 'src/core/lib/iomgr/pollset_set.h', + 'src/core/lib/iomgr/pollset_set_posix.h', + 'src/core/lib/iomgr/pollset_set_windows.h', + 'src/core/lib/iomgr/pollset_windows.h', + 'src/core/lib/iomgr/resolve_address.h', + 'src/core/lib/iomgr/sockaddr.h', + 'src/core/lib/iomgr/sockaddr_posix.h', + 'src/core/lib/iomgr/sockaddr_utils.h', + 'src/core/lib/iomgr/sockaddr_win32.h', + 'src/core/lib/iomgr/socket_utils_posix.h', + 'src/core/lib/iomgr/socket_windows.h', + 'src/core/lib/iomgr/tcp_client.h', + 'src/core/lib/iomgr/tcp_posix.h', + 'src/core/lib/iomgr/tcp_server.h', + 'src/core/lib/iomgr/tcp_windows.h', + 'src/core/lib/iomgr/time_averaged_stats.h', + 'src/core/lib/iomgr/timer.h', + 'src/core/lib/iomgr/timer_heap.h', + 'src/core/lib/iomgr/udp_server.h', + 'src/core/lib/iomgr/unix_sockets_posix.h', + 'src/core/lib/iomgr/wakeup_fd_pipe.h', + 'src/core/lib/iomgr/wakeup_fd_posix.h', + 'src/core/lib/iomgr/workqueue.h', + 'src/core/lib/iomgr/workqueue_posix.h', + 'src/core/lib/iomgr/workqueue_windows.h', + 'src/core/lib/json/json.h', + 'src/core/lib/json/json_common.h', + 'src/core/lib/json/json_reader.h', + 'src/core/lib/json/json_writer.h', + 'src/core/lib/proto/grpc/lb/v0/load_balancer.pb.h', + 'src/core/lib/statistics/census_interface.h', + 'src/core/lib/statistics/census_rpc_stats.h', + 'src/core/lib/surface/api_trace.h', + 'src/core/lib/surface/call.h', + 'src/core/lib/surface/call_test_only.h', + 'src/core/lib/surface/channel.h', + 'src/core/lib/surface/channel_init.h', + 'src/core/lib/surface/channel_stack_type.h', + 'src/core/lib/surface/completion_queue.h', + 'src/core/lib/surface/event_string.h', + 'src/core/lib/surface/init.h', + 'src/core/lib/surface/lame_client.h', + 'src/core/lib/surface/server.h', + 'src/core/lib/surface/surface_trace.h', + 'src/core/lib/transport/byte_stream.h', + 'src/core/lib/transport/chttp2/alpn.h', + 'src/core/lib/transport/chttp2/bin_encoder.h', + 'src/core/lib/transport/chttp2/frame.h', + 'src/core/lib/transport/chttp2/frame_data.h', + 'src/core/lib/transport/chttp2/frame_goaway.h', + 'src/core/lib/transport/chttp2/frame_ping.h', + 'src/core/lib/transport/chttp2/frame_rst_stream.h', + 'src/core/lib/transport/chttp2/frame_settings.h', + 'src/core/lib/transport/chttp2/frame_window_update.h', + 'src/core/lib/transport/chttp2/hpack_encoder.h', + 'src/core/lib/transport/chttp2/hpack_parser.h', + 'src/core/lib/transport/chttp2/hpack_table.h', + 'src/core/lib/transport/chttp2/http2_errors.h', + 'src/core/lib/transport/chttp2/huffsyms.h', + 'src/core/lib/transport/chttp2/incoming_metadata.h', + 'src/core/lib/transport/chttp2/internal.h', + 'src/core/lib/transport/chttp2/status_conversion.h', + 'src/core/lib/transport/chttp2/stream_map.h', + 'src/core/lib/transport/chttp2/timeout_encoding.h', + 'src/core/lib/transport/chttp2/varint.h', + 'src/core/lib/transport/chttp2_transport.h', + 'src/core/lib/transport/connectivity_state.h', + 'src/core/lib/transport/metadata.h', + 'src/core/lib/transport/metadata_batch.h', + 'src/core/lib/transport/static_metadata.h', + 'src/core/lib/transport/transport.h', + 'src/core/lib/transport/transport_impl.h', + 'src/core/lib/security/auth_filters.h', + 'src/core/lib/security/b64.h', + 'src/core/lib/security/credentials.h', + 'src/core/lib/security/handshake.h', + 'src/core/lib/security/json_token.h', + 'src/core/lib/security/jwt_verifier.h', + 'src/core/lib/security/secure_endpoint.h', + 'src/core/lib/security/security_connector.h', + 'src/core/lib/security/security_context.h', + 'src/core/lib/tsi/fake_transport_security.h', + 'src/core/lib/tsi/ssl_transport_security.h', + 'src/core/lib/tsi/ssl_types.h', + 'src/core/lib/tsi/transport_security.h', + 'src/core/lib/tsi/transport_security_interface.h', + 'src/core/lib/census/aggregation.h', + 'src/core/lib/census/mlog.h', + 'src/core/lib/census/rpc_metric_id.h', 'third_party/nanopb/pb.h', 'third_party/nanopb/pb_common.h', 'third_party/nanopb/pb_decode.h', diff --git a/grpc.gemspec b/grpc.gemspec index eeda035ee8..aa52890aeb 100755 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -88,62 +88,62 @@ Gem::Specification.new do |s| s.files += %w( include/grpc/impl/codegen/sync_posix.h ) s.files += %w( include/grpc/impl/codegen/sync_win32.h ) s.files += %w( include/grpc/impl/codegen/time.h ) - s.files += %w( src/core/profiling/timers.h ) - s.files += %w( src/core/support/backoff.h ) - s.files += %w( src/core/support/block_annotate.h ) - s.files += %w( src/core/support/env.h ) - s.files += %w( src/core/support/load_file.h ) - s.files += %w( src/core/support/murmur_hash.h ) - s.files += %w( src/core/support/stack_lockfree.h ) - s.files += %w( src/core/support/string.h ) - s.files += %w( src/core/support/string_win32.h ) - s.files += %w( src/core/support/thd_internal.h ) - s.files += %w( src/core/support/time_precise.h ) - s.files += %w( src/core/support/tmpfile.h ) - s.files += %w( src/core/profiling/basic_timers.c ) - s.files += %w( src/core/profiling/stap_timers.c ) - s.files += %w( src/core/support/alloc.c ) - s.files += %w( src/core/support/avl.c ) - s.files += %w( src/core/support/backoff.c ) - s.files += %w( src/core/support/cmdline.c ) - s.files += %w( src/core/support/cpu_iphone.c ) - s.files += %w( src/core/support/cpu_linux.c ) - s.files += %w( src/core/support/cpu_posix.c ) - s.files += %w( src/core/support/cpu_windows.c ) - s.files += %w( src/core/support/env_linux.c ) - s.files += %w( src/core/support/env_posix.c ) - s.files += %w( src/core/support/env_win32.c ) - s.files += %w( src/core/support/histogram.c ) - s.files += %w( src/core/support/host_port.c ) - s.files += %w( src/core/support/load_file.c ) - s.files += %w( src/core/support/log.c ) - s.files += %w( src/core/support/log_android.c ) - s.files += %w( src/core/support/log_linux.c ) - s.files += %w( src/core/support/log_posix.c ) - s.files += %w( src/core/support/log_win32.c ) - s.files += %w( src/core/support/murmur_hash.c ) - s.files += %w( src/core/support/slice.c ) - s.files += %w( src/core/support/slice_buffer.c ) - s.files += %w( src/core/support/stack_lockfree.c ) - s.files += %w( src/core/support/string.c ) - s.files += %w( src/core/support/string_posix.c ) - s.files += %w( src/core/support/string_win32.c ) - s.files += %w( src/core/support/subprocess_posix.c ) - s.files += %w( src/core/support/subprocess_windows.c ) - s.files += %w( src/core/support/sync.c ) - s.files += %w( src/core/support/sync_posix.c ) - s.files += %w( src/core/support/sync_win32.c ) - s.files += %w( src/core/support/thd.c ) - s.files += %w( src/core/support/thd_posix.c ) - s.files += %w( src/core/support/thd_win32.c ) - s.files += %w( src/core/support/time.c ) - s.files += %w( src/core/support/time_posix.c ) - s.files += %w( src/core/support/time_precise.c ) - s.files += %w( src/core/support/time_win32.c ) - s.files += %w( src/core/support/tls_pthread.c ) - s.files += %w( src/core/support/tmpfile_posix.c ) - s.files += %w( src/core/support/tmpfile_win32.c ) - s.files += %w( src/core/support/wrap_memcpy.c ) + s.files += %w( src/core/lib/profiling/timers.h ) + s.files += %w( src/core/lib/support/backoff.h ) + s.files += %w( src/core/lib/support/block_annotate.h ) + s.files += %w( src/core/lib/support/env.h ) + s.files += %w( src/core/lib/support/load_file.h ) + s.files += %w( src/core/lib/support/murmur_hash.h ) + s.files += %w( src/core/lib/support/stack_lockfree.h ) + s.files += %w( src/core/lib/support/string.h ) + s.files += %w( src/core/lib/support/string_win32.h ) + s.files += %w( src/core/lib/support/thd_internal.h ) + s.files += %w( src/core/lib/support/time_precise.h ) + s.files += %w( src/core/lib/support/tmpfile.h ) + s.files += %w( src/core/lib/profiling/basic_timers.c ) + s.files += %w( src/core/lib/profiling/stap_timers.c ) + s.files += %w( src/core/lib/support/alloc.c ) + s.files += %w( src/core/lib/support/avl.c ) + s.files += %w( src/core/lib/support/backoff.c ) + s.files += %w( src/core/lib/support/cmdline.c ) + s.files += %w( src/core/lib/support/cpu_iphone.c ) + s.files += %w( src/core/lib/support/cpu_linux.c ) + s.files += %w( src/core/lib/support/cpu_posix.c ) + s.files += %w( src/core/lib/support/cpu_windows.c ) + s.files += %w( src/core/lib/support/env_linux.c ) + s.files += %w( src/core/lib/support/env_posix.c ) + s.files += %w( src/core/lib/support/env_win32.c ) + s.files += %w( src/core/lib/support/histogram.c ) + s.files += %w( src/core/lib/support/host_port.c ) + s.files += %w( src/core/lib/support/load_file.c ) + s.files += %w( src/core/lib/support/log.c ) + s.files += %w( src/core/lib/support/log_android.c ) + s.files += %w( src/core/lib/support/log_linux.c ) + s.files += %w( src/core/lib/support/log_posix.c ) + s.files += %w( src/core/lib/support/log_win32.c ) + s.files += %w( src/core/lib/support/murmur_hash.c ) + s.files += %w( src/core/lib/support/slice.c ) + s.files += %w( src/core/lib/support/slice_buffer.c ) + s.files += %w( src/core/lib/support/stack_lockfree.c ) + s.files += %w( src/core/lib/support/string.c ) + s.files += %w( src/core/lib/support/string_posix.c ) + s.files += %w( src/core/lib/support/string_win32.c ) + s.files += %w( src/core/lib/support/subprocess_posix.c ) + s.files += %w( src/core/lib/support/subprocess_windows.c ) + s.files += %w( src/core/lib/support/sync.c ) + s.files += %w( src/core/lib/support/sync_posix.c ) + s.files += %w( src/core/lib/support/sync_win32.c ) + s.files += %w( src/core/lib/support/thd.c ) + s.files += %w( src/core/lib/support/thd_posix.c ) + s.files += %w( src/core/lib/support/thd_win32.c ) + s.files += %w( src/core/lib/support/time.c ) + s.files += %w( src/core/lib/support/time_posix.c ) + s.files += %w( src/core/lib/support/time_precise.c ) + s.files += %w( src/core/lib/support/time_win32.c ) + s.files += %w( src/core/lib/support/tls_pthread.c ) + s.files += %w( src/core/lib/support/tmpfile_posix.c ) + s.files += %w( src/core/lib/support/tmpfile_win32.c ) + s.files += %w( src/core/lib/support/wrap_memcpy.c ) s.files += %w( include/grpc/grpc_security.h ) s.files += %w( include/grpc/byte_buffer.h ) s.files += %w( include/grpc/byte_buffer_reader.h ) @@ -157,308 +157,308 @@ Gem::Specification.new do |s| s.files += %w( include/grpc/impl/codegen/propagation_bits.h ) s.files += %w( include/grpc/impl/codegen/status.h ) s.files += %w( include/grpc/census.h ) - s.files += %w( src/core/census/grpc_filter.h ) - s.files += %w( src/core/census/grpc_plugin.h ) - s.files += %w( src/core/channel/channel_args.h ) - s.files += %w( src/core/channel/channel_stack.h ) - s.files += %w( src/core/channel/channel_stack_builder.h ) - s.files += %w( src/core/channel/client_channel.h ) - s.files += %w( src/core/channel/compress_filter.h ) - s.files += %w( src/core/channel/connected_channel.h ) - s.files += %w( src/core/channel/context.h ) - s.files += %w( src/core/channel/http_client_filter.h ) - s.files += %w( src/core/channel/http_server_filter.h ) - s.files += %w( src/core/channel/subchannel_call_holder.h ) - s.files += %w( src/core/client_config/client_config.h ) - s.files += %w( src/core/client_config/connector.h ) - s.files += %w( src/core/client_config/initial_connect_string.h ) - s.files += %w( src/core/client_config/lb_policies/load_balancer_api.h ) - s.files += %w( src/core/client_config/lb_policies/pick_first.h ) - s.files += %w( src/core/client_config/lb_policies/round_robin.h ) - s.files += %w( src/core/client_config/lb_policy.h ) - s.files += %w( src/core/client_config/lb_policy_factory.h ) - s.files += %w( src/core/client_config/lb_policy_registry.h ) - s.files += %w( src/core/client_config/resolver.h ) - s.files += %w( src/core/client_config/resolver_factory.h ) - s.files += %w( src/core/client_config/resolver_registry.h ) - s.files += %w( src/core/client_config/resolvers/dns_resolver.h ) - s.files += %w( src/core/client_config/resolvers/sockaddr_resolver.h ) - s.files += %w( src/core/client_config/subchannel.h ) - s.files += %w( src/core/client_config/subchannel_factory.h ) - s.files += %w( src/core/client_config/subchannel_index.h ) - s.files += %w( src/core/client_config/uri_parser.h ) - s.files += %w( src/core/compression/algorithm_metadata.h ) - s.files += %w( src/core/compression/message_compress.h ) - s.files += %w( src/core/debug/trace.h ) - s.files += %w( src/core/http/format_request.h ) - s.files += %w( src/core/http/httpcli.h ) - s.files += %w( src/core/http/parser.h ) - s.files += %w( src/core/iomgr/closure.h ) - s.files += %w( src/core/iomgr/endpoint.h ) - s.files += %w( src/core/iomgr/endpoint_pair.h ) - s.files += %w( src/core/iomgr/exec_ctx.h ) - s.files += %w( src/core/iomgr/executor.h ) - s.files += %w( src/core/iomgr/fd_posix.h ) - s.files += %w( src/core/iomgr/iocp_windows.h ) - s.files += %w( src/core/iomgr/iomgr.h ) - s.files += %w( src/core/iomgr/iomgr_internal.h ) - s.files += %w( src/core/iomgr/iomgr_posix.h ) - s.files += %w( src/core/iomgr/pollset.h ) - s.files += %w( src/core/iomgr/pollset_posix.h ) - s.files += %w( src/core/iomgr/pollset_set.h ) - s.files += %w( src/core/iomgr/pollset_set_posix.h ) - s.files += %w( src/core/iomgr/pollset_set_windows.h ) - s.files += %w( src/core/iomgr/pollset_windows.h ) - s.files += %w( src/core/iomgr/resolve_address.h ) - s.files += %w( src/core/iomgr/sockaddr.h ) - s.files += %w( src/core/iomgr/sockaddr_posix.h ) - s.files += %w( src/core/iomgr/sockaddr_utils.h ) - s.files += %w( src/core/iomgr/sockaddr_win32.h ) - s.files += %w( src/core/iomgr/socket_utils_posix.h ) - s.files += %w( src/core/iomgr/socket_windows.h ) - s.files += %w( src/core/iomgr/tcp_client.h ) - s.files += %w( src/core/iomgr/tcp_posix.h ) - s.files += %w( src/core/iomgr/tcp_server.h ) - s.files += %w( src/core/iomgr/tcp_windows.h ) - s.files += %w( src/core/iomgr/time_averaged_stats.h ) - s.files += %w( src/core/iomgr/timer.h ) - s.files += %w( src/core/iomgr/timer_heap.h ) - s.files += %w( src/core/iomgr/udp_server.h ) - s.files += %w( src/core/iomgr/unix_sockets_posix.h ) - s.files += %w( src/core/iomgr/wakeup_fd_pipe.h ) - s.files += %w( src/core/iomgr/wakeup_fd_posix.h ) - s.files += %w( src/core/iomgr/workqueue.h ) - s.files += %w( src/core/iomgr/workqueue_posix.h ) - s.files += %w( src/core/iomgr/workqueue_windows.h ) - s.files += %w( src/core/json/json.h ) - s.files += %w( src/core/json/json_common.h ) - s.files += %w( src/core/json/json_reader.h ) - s.files += %w( src/core/json/json_writer.h ) - s.files += %w( src/core/proto/grpc/lb/v0/load_balancer.pb.h ) - s.files += %w( src/core/statistics/census_interface.h ) - s.files += %w( src/core/statistics/census_rpc_stats.h ) - s.files += %w( src/core/surface/api_trace.h ) - s.files += %w( src/core/surface/call.h ) - s.files += %w( src/core/surface/call_test_only.h ) - s.files += %w( src/core/surface/channel.h ) - s.files += %w( src/core/surface/channel_init.h ) - s.files += %w( src/core/surface/channel_stack_type.h ) - s.files += %w( src/core/surface/completion_queue.h ) - s.files += %w( src/core/surface/event_string.h ) - s.files += %w( src/core/surface/init.h ) - s.files += %w( src/core/surface/lame_client.h ) - s.files += %w( src/core/surface/server.h ) - s.files += %w( src/core/surface/surface_trace.h ) - s.files += %w( src/core/transport/byte_stream.h ) - s.files += %w( src/core/transport/chttp2/alpn.h ) - s.files += %w( src/core/transport/chttp2/bin_encoder.h ) - s.files += %w( src/core/transport/chttp2/frame.h ) - s.files += %w( src/core/transport/chttp2/frame_data.h ) - s.files += %w( src/core/transport/chttp2/frame_goaway.h ) - s.files += %w( src/core/transport/chttp2/frame_ping.h ) - s.files += %w( src/core/transport/chttp2/frame_rst_stream.h ) - s.files += %w( src/core/transport/chttp2/frame_settings.h ) - s.files += %w( src/core/transport/chttp2/frame_window_update.h ) - s.files += %w( src/core/transport/chttp2/hpack_encoder.h ) - s.files += %w( src/core/transport/chttp2/hpack_parser.h ) - s.files += %w( src/core/transport/chttp2/hpack_table.h ) - s.files += %w( src/core/transport/chttp2/http2_errors.h ) - s.files += %w( src/core/transport/chttp2/huffsyms.h ) - s.files += %w( src/core/transport/chttp2/incoming_metadata.h ) - s.files += %w( src/core/transport/chttp2/internal.h ) - s.files += %w( src/core/transport/chttp2/status_conversion.h ) - s.files += %w( src/core/transport/chttp2/stream_map.h ) - s.files += %w( src/core/transport/chttp2/timeout_encoding.h ) - s.files += %w( src/core/transport/chttp2/varint.h ) - s.files += %w( src/core/transport/chttp2_transport.h ) - s.files += %w( src/core/transport/connectivity_state.h ) - s.files += %w( src/core/transport/metadata.h ) - s.files += %w( src/core/transport/metadata_batch.h ) - s.files += %w( src/core/transport/static_metadata.h ) - s.files += %w( src/core/transport/transport.h ) - s.files += %w( src/core/transport/transport_impl.h ) - s.files += %w( src/core/security/auth_filters.h ) - s.files += %w( src/core/security/b64.h ) - s.files += %w( src/core/security/credentials.h ) - s.files += %w( src/core/security/handshake.h ) - s.files += %w( src/core/security/json_token.h ) - s.files += %w( src/core/security/jwt_verifier.h ) - s.files += %w( src/core/security/secure_endpoint.h ) - s.files += %w( src/core/security/security_connector.h ) - s.files += %w( src/core/security/security_context.h ) - s.files += %w( src/core/tsi/fake_transport_security.h ) - s.files += %w( src/core/tsi/ssl_transport_security.h ) - s.files += %w( src/core/tsi/ssl_types.h ) - s.files += %w( src/core/tsi/transport_security.h ) - s.files += %w( src/core/tsi/transport_security_interface.h ) - s.files += %w( src/core/census/aggregation.h ) - s.files += %w( src/core/census/mlog.h ) - s.files += %w( src/core/census/rpc_metric_id.h ) + s.files += %w( src/core/lib/census/grpc_filter.h ) + s.files += %w( src/core/lib/census/grpc_plugin.h ) + s.files += %w( src/core/lib/channel/channel_args.h ) + s.files += %w( src/core/lib/channel/channel_stack.h ) + s.files += %w( src/core/lib/channel/channel_stack_builder.h ) + s.files += %w( src/core/lib/channel/client_channel.h ) + s.files += %w( src/core/lib/channel/compress_filter.h ) + s.files += %w( src/core/lib/channel/connected_channel.h ) + s.files += %w( src/core/lib/channel/context.h ) + s.files += %w( src/core/lib/channel/http_client_filter.h ) + s.files += %w( src/core/lib/channel/http_server_filter.h ) + s.files += %w( src/core/lib/channel/subchannel_call_holder.h ) + s.files += %w( src/core/lib/client_config/client_config.h ) + s.files += %w( src/core/lib/client_config/connector.h ) + s.files += %w( src/core/lib/client_config/initial_connect_string.h ) + s.files += %w( src/core/lib/client_config/lb_policies/load_balancer_api.h ) + s.files += %w( src/core/lib/client_config/lb_policies/pick_first.h ) + s.files += %w( src/core/lib/client_config/lb_policies/round_robin.h ) + s.files += %w( src/core/lib/client_config/lb_policy.h ) + s.files += %w( src/core/lib/client_config/lb_policy_factory.h ) + s.files += %w( src/core/lib/client_config/lb_policy_registry.h ) + s.files += %w( src/core/lib/client_config/resolver.h ) + s.files += %w( src/core/lib/client_config/resolver_factory.h ) + s.files += %w( src/core/lib/client_config/resolver_registry.h ) + s.files += %w( src/core/lib/client_config/resolvers/dns_resolver.h ) + s.files += %w( src/core/lib/client_config/resolvers/sockaddr_resolver.h ) + s.files += %w( src/core/lib/client_config/subchannel.h ) + s.files += %w( src/core/lib/client_config/subchannel_factory.h ) + s.files += %w( src/core/lib/client_config/subchannel_index.h ) + s.files += %w( src/core/lib/client_config/uri_parser.h ) + s.files += %w( src/core/lib/compression/algorithm_metadata.h ) + s.files += %w( src/core/lib/compression/message_compress.h ) + s.files += %w( src/core/lib/debug/trace.h ) + s.files += %w( src/core/lib/http/format_request.h ) + s.files += %w( src/core/lib/http/httpcli.h ) + s.files += %w( src/core/lib/http/parser.h ) + s.files += %w( src/core/lib/iomgr/closure.h ) + s.files += %w( src/core/lib/iomgr/endpoint.h ) + s.files += %w( src/core/lib/iomgr/endpoint_pair.h ) + s.files += %w( src/core/lib/iomgr/exec_ctx.h ) + s.files += %w( src/core/lib/iomgr/executor.h ) + s.files += %w( src/core/lib/iomgr/fd_posix.h ) + s.files += %w( src/core/lib/iomgr/iocp_windows.h ) + s.files += %w( src/core/lib/iomgr/iomgr.h ) + s.files += %w( src/core/lib/iomgr/iomgr_internal.h ) + s.files += %w( src/core/lib/iomgr/iomgr_posix.h ) + s.files += %w( src/core/lib/iomgr/pollset.h ) + s.files += %w( src/core/lib/iomgr/pollset_posix.h ) + s.files += %w( src/core/lib/iomgr/pollset_set.h ) + s.files += %w( src/core/lib/iomgr/pollset_set_posix.h ) + s.files += %w( src/core/lib/iomgr/pollset_set_windows.h ) + s.files += %w( src/core/lib/iomgr/pollset_windows.h ) + s.files += %w( src/core/lib/iomgr/resolve_address.h ) + s.files += %w( src/core/lib/iomgr/sockaddr.h ) + s.files += %w( src/core/lib/iomgr/sockaddr_posix.h ) + s.files += %w( src/core/lib/iomgr/sockaddr_utils.h ) + s.files += %w( src/core/lib/iomgr/sockaddr_win32.h ) + s.files += %w( src/core/lib/iomgr/socket_utils_posix.h ) + s.files += %w( src/core/lib/iomgr/socket_windows.h ) + s.files += %w( src/core/lib/iomgr/tcp_client.h ) + s.files += %w( src/core/lib/iomgr/tcp_posix.h ) + s.files += %w( src/core/lib/iomgr/tcp_server.h ) + s.files += %w( src/core/lib/iomgr/tcp_windows.h ) + s.files += %w( src/core/lib/iomgr/time_averaged_stats.h ) + s.files += %w( src/core/lib/iomgr/timer.h ) + s.files += %w( src/core/lib/iomgr/timer_heap.h ) + s.files += %w( src/core/lib/iomgr/udp_server.h ) + s.files += %w( src/core/lib/iomgr/unix_sockets_posix.h ) + s.files += %w( src/core/lib/iomgr/wakeup_fd_pipe.h ) + s.files += %w( src/core/lib/iomgr/wakeup_fd_posix.h ) + s.files += %w( src/core/lib/iomgr/workqueue.h ) + s.files += %w( src/core/lib/iomgr/workqueue_posix.h ) + s.files += %w( src/core/lib/iomgr/workqueue_windows.h ) + s.files += %w( src/core/lib/json/json.h ) + s.files += %w( src/core/lib/json/json_common.h ) + s.files += %w( src/core/lib/json/json_reader.h ) + s.files += %w( src/core/lib/json/json_writer.h ) + s.files += %w( src/core/lib/proto/grpc/lb/v0/load_balancer.pb.h ) + s.files += %w( src/core/lib/statistics/census_interface.h ) + s.files += %w( src/core/lib/statistics/census_rpc_stats.h ) + s.files += %w( src/core/lib/surface/api_trace.h ) + s.files += %w( src/core/lib/surface/call.h ) + s.files += %w( src/core/lib/surface/call_test_only.h ) + s.files += %w( src/core/lib/surface/channel.h ) + s.files += %w( src/core/lib/surface/channel_init.h ) + s.files += %w( src/core/lib/surface/channel_stack_type.h ) + s.files += %w( src/core/lib/surface/completion_queue.h ) + s.files += %w( src/core/lib/surface/event_string.h ) + s.files += %w( src/core/lib/surface/init.h ) + s.files += %w( src/core/lib/surface/lame_client.h ) + s.files += %w( src/core/lib/surface/server.h ) + s.files += %w( src/core/lib/surface/surface_trace.h ) + s.files += %w( src/core/lib/transport/byte_stream.h ) + s.files += %w( src/core/lib/transport/chttp2/alpn.h ) + s.files += %w( src/core/lib/transport/chttp2/bin_encoder.h ) + s.files += %w( src/core/lib/transport/chttp2/frame.h ) + s.files += %w( src/core/lib/transport/chttp2/frame_data.h ) + s.files += %w( src/core/lib/transport/chttp2/frame_goaway.h ) + s.files += %w( src/core/lib/transport/chttp2/frame_ping.h ) + s.files += %w( src/core/lib/transport/chttp2/frame_rst_stream.h ) + s.files += %w( src/core/lib/transport/chttp2/frame_settings.h ) + s.files += %w( src/core/lib/transport/chttp2/frame_window_update.h ) + s.files += %w( src/core/lib/transport/chttp2/hpack_encoder.h ) + s.files += %w( src/core/lib/transport/chttp2/hpack_parser.h ) + s.files += %w( src/core/lib/transport/chttp2/hpack_table.h ) + s.files += %w( src/core/lib/transport/chttp2/http2_errors.h ) + s.files += %w( src/core/lib/transport/chttp2/huffsyms.h ) + s.files += %w( src/core/lib/transport/chttp2/incoming_metadata.h ) + s.files += %w( src/core/lib/transport/chttp2/internal.h ) + s.files += %w( src/core/lib/transport/chttp2/status_conversion.h ) + s.files += %w( src/core/lib/transport/chttp2/stream_map.h ) + s.files += %w( src/core/lib/transport/chttp2/timeout_encoding.h ) + s.files += %w( src/core/lib/transport/chttp2/varint.h ) + s.files += %w( src/core/lib/transport/chttp2_transport.h ) + s.files += %w( src/core/lib/transport/connectivity_state.h ) + s.files += %w( src/core/lib/transport/metadata.h ) + s.files += %w( src/core/lib/transport/metadata_batch.h ) + s.files += %w( src/core/lib/transport/static_metadata.h ) + s.files += %w( src/core/lib/transport/transport.h ) + s.files += %w( src/core/lib/transport/transport_impl.h ) + s.files += %w( src/core/lib/security/auth_filters.h ) + s.files += %w( src/core/lib/security/b64.h ) + s.files += %w( src/core/lib/security/credentials.h ) + s.files += %w( src/core/lib/security/handshake.h ) + s.files += %w( src/core/lib/security/json_token.h ) + s.files += %w( src/core/lib/security/jwt_verifier.h ) + s.files += %w( src/core/lib/security/secure_endpoint.h ) + s.files += %w( src/core/lib/security/security_connector.h ) + s.files += %w( src/core/lib/security/security_context.h ) + s.files += %w( src/core/lib/tsi/fake_transport_security.h ) + s.files += %w( src/core/lib/tsi/ssl_transport_security.h ) + s.files += %w( src/core/lib/tsi/ssl_types.h ) + s.files += %w( src/core/lib/tsi/transport_security.h ) + s.files += %w( src/core/lib/tsi/transport_security_interface.h ) + s.files += %w( src/core/lib/census/aggregation.h ) + s.files += %w( src/core/lib/census/mlog.h ) + s.files += %w( src/core/lib/census/rpc_metric_id.h ) s.files += %w( third_party/nanopb/pb.h ) s.files += %w( third_party/nanopb/pb_common.h ) s.files += %w( third_party/nanopb/pb_decode.h ) s.files += %w( third_party/nanopb/pb_encode.h ) - s.files += %w( src/core/census/grpc_context.c ) - s.files += %w( src/core/census/grpc_filter.c ) - s.files += %w( src/core/census/grpc_plugin.c ) - s.files += %w( src/core/channel/channel_args.c ) - s.files += %w( src/core/channel/channel_stack.c ) - s.files += %w( src/core/channel/channel_stack_builder.c ) - s.files += %w( src/core/channel/client_channel.c ) - s.files += %w( src/core/channel/compress_filter.c ) - s.files += %w( src/core/channel/connected_channel.c ) - s.files += %w( src/core/channel/http_client_filter.c ) - s.files += %w( src/core/channel/http_server_filter.c ) - s.files += %w( src/core/channel/subchannel_call_holder.c ) - s.files += %w( src/core/client_config/client_config.c ) - s.files += %w( src/core/client_config/connector.c ) - s.files += %w( src/core/client_config/default_initial_connect_string.c ) - s.files += %w( src/core/client_config/initial_connect_string.c ) - s.files += %w( src/core/client_config/lb_policies/load_balancer_api.c ) - s.files += %w( src/core/client_config/lb_policies/pick_first.c ) - s.files += %w( src/core/client_config/lb_policies/round_robin.c ) - s.files += %w( src/core/client_config/lb_policy.c ) - s.files += %w( src/core/client_config/lb_policy_factory.c ) - s.files += %w( src/core/client_config/lb_policy_registry.c ) - s.files += %w( src/core/client_config/resolver.c ) - s.files += %w( src/core/client_config/resolver_factory.c ) - s.files += %w( src/core/client_config/resolver_registry.c ) - s.files += %w( src/core/client_config/resolvers/dns_resolver.c ) - s.files += %w( src/core/client_config/resolvers/sockaddr_resolver.c ) - s.files += %w( src/core/client_config/subchannel.c ) - s.files += %w( src/core/client_config/subchannel_factory.c ) - s.files += %w( src/core/client_config/subchannel_index.c ) - s.files += %w( src/core/client_config/uri_parser.c ) - s.files += %w( src/core/compression/compression_algorithm.c ) - s.files += %w( src/core/compression/message_compress.c ) - s.files += %w( src/core/debug/trace.c ) - s.files += %w( src/core/http/format_request.c ) - s.files += %w( src/core/http/httpcli.c ) - s.files += %w( src/core/http/parser.c ) - s.files += %w( src/core/iomgr/closure.c ) - s.files += %w( src/core/iomgr/endpoint.c ) - s.files += %w( src/core/iomgr/endpoint_pair_posix.c ) - s.files += %w( src/core/iomgr/endpoint_pair_windows.c ) - s.files += %w( src/core/iomgr/exec_ctx.c ) - s.files += %w( src/core/iomgr/executor.c ) - s.files += %w( src/core/iomgr/fd_posix.c ) - s.files += %w( src/core/iomgr/iocp_windows.c ) - s.files += %w( src/core/iomgr/iomgr.c ) - s.files += %w( src/core/iomgr/iomgr_posix.c ) - s.files += %w( src/core/iomgr/iomgr_windows.c ) - s.files += %w( src/core/iomgr/pollset_multipoller_with_epoll.c ) - s.files += %w( src/core/iomgr/pollset_multipoller_with_poll_posix.c ) - s.files += %w( src/core/iomgr/pollset_posix.c ) - s.files += %w( src/core/iomgr/pollset_set_posix.c ) - s.files += %w( src/core/iomgr/pollset_set_windows.c ) - s.files += %w( src/core/iomgr/pollset_windows.c ) - s.files += %w( src/core/iomgr/resolve_address_posix.c ) - s.files += %w( src/core/iomgr/resolve_address_windows.c ) - s.files += %w( src/core/iomgr/sockaddr_utils.c ) - s.files += %w( src/core/iomgr/socket_utils_common_posix.c ) - s.files += %w( src/core/iomgr/socket_utils_linux.c ) - s.files += %w( src/core/iomgr/socket_utils_posix.c ) - s.files += %w( src/core/iomgr/socket_windows.c ) - s.files += %w( src/core/iomgr/tcp_client_posix.c ) - s.files += %w( src/core/iomgr/tcp_client_windows.c ) - s.files += %w( src/core/iomgr/tcp_posix.c ) - s.files += %w( src/core/iomgr/tcp_server_posix.c ) - s.files += %w( src/core/iomgr/tcp_server_windows.c ) - s.files += %w( src/core/iomgr/tcp_windows.c ) - s.files += %w( src/core/iomgr/time_averaged_stats.c ) - s.files += %w( src/core/iomgr/timer.c ) - s.files += %w( src/core/iomgr/timer_heap.c ) - s.files += %w( src/core/iomgr/udp_server.c ) - s.files += %w( src/core/iomgr/unix_sockets_posix.c ) - s.files += %w( src/core/iomgr/unix_sockets_posix_noop.c ) - s.files += %w( src/core/iomgr/wakeup_fd_eventfd.c ) - s.files += %w( src/core/iomgr/wakeup_fd_nospecial.c ) - s.files += %w( src/core/iomgr/wakeup_fd_pipe.c ) - s.files += %w( src/core/iomgr/wakeup_fd_posix.c ) - s.files += %w( src/core/iomgr/workqueue_posix.c ) - s.files += %w( src/core/iomgr/workqueue_windows.c ) - s.files += %w( src/core/json/json.c ) - s.files += %w( src/core/json/json_reader.c ) - s.files += %w( src/core/json/json_string.c ) - s.files += %w( src/core/json/json_writer.c ) - s.files += %w( src/core/proto/grpc/lb/v0/load_balancer.pb.c ) - s.files += %w( src/core/surface/alarm.c ) - s.files += %w( src/core/surface/api_trace.c ) - s.files += %w( src/core/surface/byte_buffer.c ) - s.files += %w( src/core/surface/byte_buffer_reader.c ) - s.files += %w( src/core/surface/call.c ) - s.files += %w( src/core/surface/call_details.c ) - s.files += %w( src/core/surface/call_log_batch.c ) - s.files += %w( src/core/surface/channel.c ) - s.files += %w( src/core/surface/channel_connectivity.c ) - s.files += %w( src/core/surface/channel_create.c ) - s.files += %w( src/core/surface/channel_init.c ) - s.files += %w( src/core/surface/channel_ping.c ) - s.files += %w( src/core/surface/channel_stack_type.c ) - s.files += %w( src/core/surface/completion_queue.c ) - s.files += %w( src/core/surface/event_string.c ) - s.files += %w( src/core/surface/init.c ) - s.files += %w( src/core/surface/lame_client.c ) - s.files += %w( src/core/surface/metadata_array.c ) - s.files += %w( src/core/surface/server.c ) - s.files += %w( src/core/surface/server_chttp2.c ) - s.files += %w( src/core/surface/validate_metadata.c ) - s.files += %w( src/core/surface/version.c ) - s.files += %w( src/core/transport/byte_stream.c ) - s.files += %w( src/core/transport/chttp2/alpn.c ) - s.files += %w( src/core/transport/chttp2/bin_encoder.c ) - s.files += %w( src/core/transport/chttp2/frame_data.c ) - s.files += %w( src/core/transport/chttp2/frame_goaway.c ) - s.files += %w( src/core/transport/chttp2/frame_ping.c ) - s.files += %w( src/core/transport/chttp2/frame_rst_stream.c ) - s.files += %w( src/core/transport/chttp2/frame_settings.c ) - s.files += %w( src/core/transport/chttp2/frame_window_update.c ) - s.files += %w( src/core/transport/chttp2/hpack_encoder.c ) - s.files += %w( src/core/transport/chttp2/hpack_parser.c ) - s.files += %w( src/core/transport/chttp2/hpack_table.c ) - s.files += %w( src/core/transport/chttp2/huffsyms.c ) - s.files += %w( src/core/transport/chttp2/incoming_metadata.c ) - s.files += %w( src/core/transport/chttp2/parsing.c ) - s.files += %w( src/core/transport/chttp2/status_conversion.c ) - s.files += %w( src/core/transport/chttp2/stream_lists.c ) - s.files += %w( src/core/transport/chttp2/stream_map.c ) - s.files += %w( src/core/transport/chttp2/timeout_encoding.c ) - s.files += %w( src/core/transport/chttp2/varint.c ) - s.files += %w( src/core/transport/chttp2/writing.c ) - s.files += %w( src/core/transport/chttp2_transport.c ) - s.files += %w( src/core/transport/connectivity_state.c ) - s.files += %w( src/core/transport/metadata.c ) - s.files += %w( src/core/transport/metadata_batch.c ) - s.files += %w( src/core/transport/static_metadata.c ) - s.files += %w( src/core/transport/transport.c ) - s.files += %w( src/core/transport/transport_op_string.c ) - s.files += %w( src/core/http/httpcli_security_connector.c ) - s.files += %w( src/core/security/b64.c ) - s.files += %w( src/core/security/client_auth_filter.c ) - s.files += %w( src/core/security/credentials.c ) - s.files += %w( src/core/security/credentials_metadata.c ) - s.files += %w( src/core/security/credentials_posix.c ) - s.files += %w( src/core/security/credentials_win32.c ) - s.files += %w( src/core/security/google_default_credentials.c ) - s.files += %w( src/core/security/handshake.c ) - s.files += %w( src/core/security/json_token.c ) - s.files += %w( src/core/security/jwt_verifier.c ) - s.files += %w( src/core/security/secure_endpoint.c ) - s.files += %w( src/core/security/security_connector.c ) - s.files += %w( src/core/security/security_context.c ) - s.files += %w( src/core/security/server_auth_filter.c ) - s.files += %w( src/core/security/server_secure_chttp2.c ) - s.files += %w( src/core/surface/init_secure.c ) - s.files += %w( src/core/surface/secure_channel_create.c ) - s.files += %w( src/core/tsi/fake_transport_security.c ) - s.files += %w( src/core/tsi/ssl_transport_security.c ) - s.files += %w( src/core/tsi/transport_security.c ) - s.files += %w( src/core/census/context.c ) - s.files += %w( src/core/census/initialize.c ) - s.files += %w( src/core/census/mlog.c ) - s.files += %w( src/core/census/operation.c ) - s.files += %w( src/core/census/placeholders.c ) - s.files += %w( src/core/census/tracing.c ) + s.files += %w( src/core/lib/census/grpc_context.c ) + s.files += %w( src/core/lib/census/grpc_filter.c ) + s.files += %w( src/core/lib/census/grpc_plugin.c ) + s.files += %w( src/core/lib/channel/channel_args.c ) + s.files += %w( src/core/lib/channel/channel_stack.c ) + s.files += %w( src/core/lib/channel/channel_stack_builder.c ) + s.files += %w( src/core/lib/channel/client_channel.c ) + s.files += %w( src/core/lib/channel/compress_filter.c ) + s.files += %w( src/core/lib/channel/connected_channel.c ) + s.files += %w( src/core/lib/channel/http_client_filter.c ) + s.files += %w( src/core/lib/channel/http_server_filter.c ) + s.files += %w( src/core/lib/channel/subchannel_call_holder.c ) + s.files += %w( src/core/lib/client_config/client_config.c ) + s.files += %w( src/core/lib/client_config/connector.c ) + s.files += %w( src/core/lib/client_config/default_initial_connect_string.c ) + s.files += %w( src/core/lib/client_config/initial_connect_string.c ) + s.files += %w( src/core/lib/client_config/lb_policies/load_balancer_api.c ) + s.files += %w( src/core/lib/client_config/lb_policies/pick_first.c ) + s.files += %w( src/core/lib/client_config/lb_policies/round_robin.c ) + s.files += %w( src/core/lib/client_config/lb_policy.c ) + s.files += %w( src/core/lib/client_config/lb_policy_factory.c ) + s.files += %w( src/core/lib/client_config/lb_policy_registry.c ) + s.files += %w( src/core/lib/client_config/resolver.c ) + s.files += %w( src/core/lib/client_config/resolver_factory.c ) + s.files += %w( src/core/lib/client_config/resolver_registry.c ) + s.files += %w( src/core/lib/client_config/resolvers/dns_resolver.c ) + s.files += %w( src/core/lib/client_config/resolvers/sockaddr_resolver.c ) + s.files += %w( src/core/lib/client_config/subchannel.c ) + s.files += %w( src/core/lib/client_config/subchannel_factory.c ) + s.files += %w( src/core/lib/client_config/subchannel_index.c ) + s.files += %w( src/core/lib/client_config/uri_parser.c ) + s.files += %w( src/core/lib/compression/compression_algorithm.c ) + s.files += %w( src/core/lib/compression/message_compress.c ) + s.files += %w( src/core/lib/debug/trace.c ) + s.files += %w( src/core/lib/http/format_request.c ) + s.files += %w( src/core/lib/http/httpcli.c ) + s.files += %w( src/core/lib/http/parser.c ) + s.files += %w( src/core/lib/iomgr/closure.c ) + s.files += %w( src/core/lib/iomgr/endpoint.c ) + s.files += %w( src/core/lib/iomgr/endpoint_pair_posix.c ) + s.files += %w( src/core/lib/iomgr/endpoint_pair_windows.c ) + s.files += %w( src/core/lib/iomgr/exec_ctx.c ) + s.files += %w( src/core/lib/iomgr/executor.c ) + s.files += %w( src/core/lib/iomgr/fd_posix.c ) + s.files += %w( src/core/lib/iomgr/iocp_windows.c ) + s.files += %w( src/core/lib/iomgr/iomgr.c ) + s.files += %w( src/core/lib/iomgr/iomgr_posix.c ) + s.files += %w( src/core/lib/iomgr/iomgr_windows.c ) + s.files += %w( src/core/lib/iomgr/pollset_multipoller_with_epoll.c ) + s.files += %w( src/core/lib/iomgr/pollset_multipoller_with_poll_posix.c ) + s.files += %w( src/core/lib/iomgr/pollset_posix.c ) + s.files += %w( src/core/lib/iomgr/pollset_set_posix.c ) + s.files += %w( src/core/lib/iomgr/pollset_set_windows.c ) + s.files += %w( src/core/lib/iomgr/pollset_windows.c ) + s.files += %w( src/core/lib/iomgr/resolve_address_posix.c ) + s.files += %w( src/core/lib/iomgr/resolve_address_windows.c ) + s.files += %w( src/core/lib/iomgr/sockaddr_utils.c ) + s.files += %w( src/core/lib/iomgr/socket_utils_common_posix.c ) + s.files += %w( src/core/lib/iomgr/socket_utils_linux.c ) + s.files += %w( src/core/lib/iomgr/socket_utils_posix.c ) + s.files += %w( src/core/lib/iomgr/socket_windows.c ) + s.files += %w( src/core/lib/iomgr/tcp_client_posix.c ) + s.files += %w( src/core/lib/iomgr/tcp_client_windows.c ) + s.files += %w( src/core/lib/iomgr/tcp_posix.c ) + s.files += %w( src/core/lib/iomgr/tcp_server_posix.c ) + s.files += %w( src/core/lib/iomgr/tcp_server_windows.c ) + s.files += %w( src/core/lib/iomgr/tcp_windows.c ) + s.files += %w( src/core/lib/iomgr/time_averaged_stats.c ) + s.files += %w( src/core/lib/iomgr/timer.c ) + s.files += %w( src/core/lib/iomgr/timer_heap.c ) + s.files += %w( src/core/lib/iomgr/udp_server.c ) + s.files += %w( src/core/lib/iomgr/unix_sockets_posix.c ) + s.files += %w( src/core/lib/iomgr/unix_sockets_posix_noop.c ) + s.files += %w( src/core/lib/iomgr/wakeup_fd_eventfd.c ) + s.files += %w( src/core/lib/iomgr/wakeup_fd_nospecial.c ) + s.files += %w( src/core/lib/iomgr/wakeup_fd_pipe.c ) + s.files += %w( src/core/lib/iomgr/wakeup_fd_posix.c ) + s.files += %w( src/core/lib/iomgr/workqueue_posix.c ) + s.files += %w( src/core/lib/iomgr/workqueue_windows.c ) + s.files += %w( src/core/lib/json/json.c ) + s.files += %w( src/core/lib/json/json_reader.c ) + s.files += %w( src/core/lib/json/json_string.c ) + s.files += %w( src/core/lib/json/json_writer.c ) + s.files += %w( src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c ) + s.files += %w( src/core/lib/surface/alarm.c ) + s.files += %w( src/core/lib/surface/api_trace.c ) + s.files += %w( src/core/lib/surface/byte_buffer.c ) + s.files += %w( src/core/lib/surface/byte_buffer_reader.c ) + s.files += %w( src/core/lib/surface/call.c ) + s.files += %w( src/core/lib/surface/call_details.c ) + s.files += %w( src/core/lib/surface/call_log_batch.c ) + s.files += %w( src/core/lib/surface/channel.c ) + s.files += %w( src/core/lib/surface/channel_connectivity.c ) + s.files += %w( src/core/lib/surface/channel_create.c ) + s.files += %w( src/core/lib/surface/channel_init.c ) + s.files += %w( src/core/lib/surface/channel_ping.c ) + s.files += %w( src/core/lib/surface/channel_stack_type.c ) + s.files += %w( src/core/lib/surface/completion_queue.c ) + s.files += %w( src/core/lib/surface/event_string.c ) + s.files += %w( src/core/lib/surface/init.c ) + s.files += %w( src/core/lib/surface/lame_client.c ) + s.files += %w( src/core/lib/surface/metadata_array.c ) + s.files += %w( src/core/lib/surface/server.c ) + s.files += %w( src/core/lib/surface/server_chttp2.c ) + s.files += %w( src/core/lib/surface/validate_metadata.c ) + s.files += %w( src/core/lib/surface/version.c ) + s.files += %w( src/core/lib/transport/byte_stream.c ) + s.files += %w( src/core/lib/transport/chttp2/alpn.c ) + s.files += %w( src/core/lib/transport/chttp2/bin_encoder.c ) + s.files += %w( src/core/lib/transport/chttp2/frame_data.c ) + s.files += %w( src/core/lib/transport/chttp2/frame_goaway.c ) + s.files += %w( src/core/lib/transport/chttp2/frame_ping.c ) + s.files += %w( src/core/lib/transport/chttp2/frame_rst_stream.c ) + s.files += %w( src/core/lib/transport/chttp2/frame_settings.c ) + s.files += %w( src/core/lib/transport/chttp2/frame_window_update.c ) + s.files += %w( src/core/lib/transport/chttp2/hpack_encoder.c ) + s.files += %w( src/core/lib/transport/chttp2/hpack_parser.c ) + s.files += %w( src/core/lib/transport/chttp2/hpack_table.c ) + s.files += %w( src/core/lib/transport/chttp2/huffsyms.c ) + s.files += %w( src/core/lib/transport/chttp2/incoming_metadata.c ) + s.files += %w( src/core/lib/transport/chttp2/parsing.c ) + s.files += %w( src/core/lib/transport/chttp2/status_conversion.c ) + s.files += %w( src/core/lib/transport/chttp2/stream_lists.c ) + s.files += %w( src/core/lib/transport/chttp2/stream_map.c ) + s.files += %w( src/core/lib/transport/chttp2/timeout_encoding.c ) + s.files += %w( src/core/lib/transport/chttp2/varint.c ) + s.files += %w( src/core/lib/transport/chttp2/writing.c ) + s.files += %w( src/core/lib/transport/chttp2_transport.c ) + s.files += %w( src/core/lib/transport/connectivity_state.c ) + s.files += %w( src/core/lib/transport/metadata.c ) + s.files += %w( src/core/lib/transport/metadata_batch.c ) + s.files += %w( src/core/lib/transport/static_metadata.c ) + s.files += %w( src/core/lib/transport/transport.c ) + s.files += %w( src/core/lib/transport/transport_op_string.c ) + s.files += %w( src/core/lib/http/httpcli_security_connector.c ) + s.files += %w( src/core/lib/security/b64.c ) + s.files += %w( src/core/lib/security/client_auth_filter.c ) + s.files += %w( src/core/lib/security/credentials.c ) + s.files += %w( src/core/lib/security/credentials_metadata.c ) + s.files += %w( src/core/lib/security/credentials_posix.c ) + s.files += %w( src/core/lib/security/credentials_win32.c ) + s.files += %w( src/core/lib/security/google_default_credentials.c ) + s.files += %w( src/core/lib/security/handshake.c ) + s.files += %w( src/core/lib/security/json_token.c ) + s.files += %w( src/core/lib/security/jwt_verifier.c ) + s.files += %w( src/core/lib/security/secure_endpoint.c ) + s.files += %w( src/core/lib/security/security_connector.c ) + s.files += %w( src/core/lib/security/security_context.c ) + s.files += %w( src/core/lib/security/server_auth_filter.c ) + s.files += %w( src/core/lib/security/server_secure_chttp2.c ) + s.files += %w( src/core/lib/surface/init_secure.c ) + s.files += %w( src/core/lib/surface/secure_channel_create.c ) + s.files += %w( src/core/lib/tsi/fake_transport_security.c ) + s.files += %w( src/core/lib/tsi/ssl_transport_security.c ) + s.files += %w( src/core/lib/tsi/transport_security.c ) + s.files += %w( src/core/lib/census/context.c ) + s.files += %w( src/core/lib/census/initialize.c ) + s.files += %w( src/core/lib/census/mlog.c ) + s.files += %w( src/core/lib/census/operation.c ) + s.files += %w( src/core/lib/census/placeholders.c ) + s.files += %w( src/core/lib/census/tracing.c ) s.files += %w( third_party/nanopb/pb_common.c ) s.files += %w( third_party/nanopb/pb_decode.c ) s.files += %w( third_party/nanopb/pb_encode.c ) diff --git a/package.json b/package.json index fe085775f8..37856d7cc7 100644 --- a/package.json +++ b/package.json @@ -99,308 +99,308 @@ "include/grpc/impl/codegen/propagation_bits.h", "include/grpc/impl/codegen/status.h", "include/grpc/census.h", - "src/core/census/grpc_filter.h", - "src/core/census/grpc_plugin.h", - "src/core/channel/channel_args.h", - "src/core/channel/channel_stack.h", - "src/core/channel/channel_stack_builder.h", - "src/core/channel/client_channel.h", - "src/core/channel/compress_filter.h", - "src/core/channel/connected_channel.h", - "src/core/channel/context.h", - "src/core/channel/http_client_filter.h", - "src/core/channel/http_server_filter.h", - "src/core/channel/subchannel_call_holder.h", - "src/core/client_config/client_config.h", - "src/core/client_config/connector.h", - "src/core/client_config/initial_connect_string.h", - "src/core/client_config/lb_policies/load_balancer_api.h", - "src/core/client_config/lb_policies/pick_first.h", - "src/core/client_config/lb_policies/round_robin.h", - "src/core/client_config/lb_policy.h", - "src/core/client_config/lb_policy_factory.h", - "src/core/client_config/lb_policy_registry.h", - "src/core/client_config/resolver.h", - "src/core/client_config/resolver_factory.h", - "src/core/client_config/resolver_registry.h", - "src/core/client_config/resolvers/dns_resolver.h", - "src/core/client_config/resolvers/sockaddr_resolver.h", - "src/core/client_config/subchannel.h", - "src/core/client_config/subchannel_factory.h", - "src/core/client_config/subchannel_index.h", - "src/core/client_config/uri_parser.h", - "src/core/compression/algorithm_metadata.h", - "src/core/compression/message_compress.h", - "src/core/debug/trace.h", - "src/core/http/format_request.h", - "src/core/http/httpcli.h", - "src/core/http/parser.h", - "src/core/iomgr/closure.h", - "src/core/iomgr/endpoint.h", - "src/core/iomgr/endpoint_pair.h", - "src/core/iomgr/exec_ctx.h", - "src/core/iomgr/executor.h", - "src/core/iomgr/fd_posix.h", - "src/core/iomgr/iocp_windows.h", - "src/core/iomgr/iomgr.h", - "src/core/iomgr/iomgr_internal.h", - "src/core/iomgr/iomgr_posix.h", - "src/core/iomgr/pollset.h", - "src/core/iomgr/pollset_posix.h", - "src/core/iomgr/pollset_set.h", - "src/core/iomgr/pollset_set_posix.h", - "src/core/iomgr/pollset_set_windows.h", - "src/core/iomgr/pollset_windows.h", - "src/core/iomgr/resolve_address.h", - "src/core/iomgr/sockaddr.h", - "src/core/iomgr/sockaddr_posix.h", - "src/core/iomgr/sockaddr_utils.h", - "src/core/iomgr/sockaddr_win32.h", - "src/core/iomgr/socket_utils_posix.h", - "src/core/iomgr/socket_windows.h", - "src/core/iomgr/tcp_client.h", - "src/core/iomgr/tcp_posix.h", - "src/core/iomgr/tcp_server.h", - "src/core/iomgr/tcp_windows.h", - "src/core/iomgr/time_averaged_stats.h", - "src/core/iomgr/timer.h", - "src/core/iomgr/timer_heap.h", - "src/core/iomgr/udp_server.h", - "src/core/iomgr/unix_sockets_posix.h", - "src/core/iomgr/wakeup_fd_pipe.h", - "src/core/iomgr/wakeup_fd_posix.h", - "src/core/iomgr/workqueue.h", - "src/core/iomgr/workqueue_posix.h", - "src/core/iomgr/workqueue_windows.h", - "src/core/json/json.h", - "src/core/json/json_common.h", - "src/core/json/json_reader.h", - "src/core/json/json_writer.h", - "src/core/proto/grpc/lb/v0/load_balancer.pb.h", - "src/core/statistics/census_interface.h", - "src/core/statistics/census_rpc_stats.h", - "src/core/surface/api_trace.h", - "src/core/surface/call.h", - "src/core/surface/call_test_only.h", - "src/core/surface/channel.h", - "src/core/surface/channel_init.h", - "src/core/surface/channel_stack_type.h", - "src/core/surface/completion_queue.h", - "src/core/surface/event_string.h", - "src/core/surface/init.h", - "src/core/surface/lame_client.h", - "src/core/surface/server.h", - "src/core/surface/surface_trace.h", - "src/core/transport/byte_stream.h", - "src/core/transport/chttp2/alpn.h", - "src/core/transport/chttp2/bin_encoder.h", - "src/core/transport/chttp2/frame.h", - "src/core/transport/chttp2/frame_data.h", - "src/core/transport/chttp2/frame_goaway.h", - "src/core/transport/chttp2/frame_ping.h", - "src/core/transport/chttp2/frame_rst_stream.h", - "src/core/transport/chttp2/frame_settings.h", - "src/core/transport/chttp2/frame_window_update.h", - "src/core/transport/chttp2/hpack_encoder.h", - "src/core/transport/chttp2/hpack_parser.h", - "src/core/transport/chttp2/hpack_table.h", - "src/core/transport/chttp2/http2_errors.h", - "src/core/transport/chttp2/huffsyms.h", - "src/core/transport/chttp2/incoming_metadata.h", - "src/core/transport/chttp2/internal.h", - "src/core/transport/chttp2/status_conversion.h", - "src/core/transport/chttp2/stream_map.h", - "src/core/transport/chttp2/timeout_encoding.h", - "src/core/transport/chttp2/varint.h", - "src/core/transport/chttp2_transport.h", - "src/core/transport/connectivity_state.h", - "src/core/transport/metadata.h", - "src/core/transport/metadata_batch.h", - "src/core/transport/static_metadata.h", - "src/core/transport/transport.h", - "src/core/transport/transport_impl.h", - "src/core/security/auth_filters.h", - "src/core/security/b64.h", - "src/core/security/credentials.h", - "src/core/security/handshake.h", - "src/core/security/json_token.h", - "src/core/security/jwt_verifier.h", - "src/core/security/secure_endpoint.h", - "src/core/security/security_connector.h", - "src/core/security/security_context.h", - "src/core/tsi/fake_transport_security.h", - "src/core/tsi/ssl_transport_security.h", - "src/core/tsi/ssl_types.h", - "src/core/tsi/transport_security.h", - "src/core/tsi/transport_security_interface.h", - "src/core/census/aggregation.h", - "src/core/census/mlog.h", - "src/core/census/rpc_metric_id.h", + "src/core/lib/census/grpc_filter.h", + "src/core/lib/census/grpc_plugin.h", + "src/core/lib/channel/channel_args.h", + "src/core/lib/channel/channel_stack.h", + "src/core/lib/channel/channel_stack_builder.h", + "src/core/lib/channel/client_channel.h", + "src/core/lib/channel/compress_filter.h", + "src/core/lib/channel/connected_channel.h", + "src/core/lib/channel/context.h", + "src/core/lib/channel/http_client_filter.h", + "src/core/lib/channel/http_server_filter.h", + "src/core/lib/channel/subchannel_call_holder.h", + "src/core/lib/client_config/client_config.h", + "src/core/lib/client_config/connector.h", + "src/core/lib/client_config/initial_connect_string.h", + "src/core/lib/client_config/lb_policies/load_balancer_api.h", + "src/core/lib/client_config/lb_policies/pick_first.h", + "src/core/lib/client_config/lb_policies/round_robin.h", + "src/core/lib/client_config/lb_policy.h", + "src/core/lib/client_config/lb_policy_factory.h", + "src/core/lib/client_config/lb_policy_registry.h", + "src/core/lib/client_config/resolver.h", + "src/core/lib/client_config/resolver_factory.h", + "src/core/lib/client_config/resolver_registry.h", + "src/core/lib/client_config/resolvers/dns_resolver.h", + "src/core/lib/client_config/resolvers/sockaddr_resolver.h", + "src/core/lib/client_config/subchannel.h", + "src/core/lib/client_config/subchannel_factory.h", + "src/core/lib/client_config/subchannel_index.h", + "src/core/lib/client_config/uri_parser.h", + "src/core/lib/compression/algorithm_metadata.h", + "src/core/lib/compression/message_compress.h", + "src/core/lib/debug/trace.h", + "src/core/lib/http/format_request.h", + "src/core/lib/http/httpcli.h", + "src/core/lib/http/parser.h", + "src/core/lib/iomgr/closure.h", + "src/core/lib/iomgr/endpoint.h", + "src/core/lib/iomgr/endpoint_pair.h", + "src/core/lib/iomgr/exec_ctx.h", + "src/core/lib/iomgr/executor.h", + "src/core/lib/iomgr/fd_posix.h", + "src/core/lib/iomgr/iocp_windows.h", + "src/core/lib/iomgr/iomgr.h", + "src/core/lib/iomgr/iomgr_internal.h", + "src/core/lib/iomgr/iomgr_posix.h", + "src/core/lib/iomgr/pollset.h", + "src/core/lib/iomgr/pollset_posix.h", + "src/core/lib/iomgr/pollset_set.h", + "src/core/lib/iomgr/pollset_set_posix.h", + "src/core/lib/iomgr/pollset_set_windows.h", + "src/core/lib/iomgr/pollset_windows.h", + "src/core/lib/iomgr/resolve_address.h", + "src/core/lib/iomgr/sockaddr.h", + "src/core/lib/iomgr/sockaddr_posix.h", + "src/core/lib/iomgr/sockaddr_utils.h", + "src/core/lib/iomgr/sockaddr_win32.h", + "src/core/lib/iomgr/socket_utils_posix.h", + "src/core/lib/iomgr/socket_windows.h", + "src/core/lib/iomgr/tcp_client.h", + "src/core/lib/iomgr/tcp_posix.h", + "src/core/lib/iomgr/tcp_server.h", + "src/core/lib/iomgr/tcp_windows.h", + "src/core/lib/iomgr/time_averaged_stats.h", + "src/core/lib/iomgr/timer.h", + "src/core/lib/iomgr/timer_heap.h", + "src/core/lib/iomgr/udp_server.h", + "src/core/lib/iomgr/unix_sockets_posix.h", + "src/core/lib/iomgr/wakeup_fd_pipe.h", + "src/core/lib/iomgr/wakeup_fd_posix.h", + "src/core/lib/iomgr/workqueue.h", + "src/core/lib/iomgr/workqueue_posix.h", + "src/core/lib/iomgr/workqueue_windows.h", + "src/core/lib/json/json.h", + "src/core/lib/json/json_common.h", + "src/core/lib/json/json_reader.h", + "src/core/lib/json/json_writer.h", + "src/core/lib/proto/grpc/lb/v0/load_balancer.pb.h", + "src/core/lib/statistics/census_interface.h", + "src/core/lib/statistics/census_rpc_stats.h", + "src/core/lib/surface/api_trace.h", + "src/core/lib/surface/call.h", + "src/core/lib/surface/call_test_only.h", + "src/core/lib/surface/channel.h", + "src/core/lib/surface/channel_init.h", + "src/core/lib/surface/channel_stack_type.h", + "src/core/lib/surface/completion_queue.h", + "src/core/lib/surface/event_string.h", + "src/core/lib/surface/init.h", + "src/core/lib/surface/lame_client.h", + "src/core/lib/surface/server.h", + "src/core/lib/surface/surface_trace.h", + "src/core/lib/transport/byte_stream.h", + "src/core/lib/transport/chttp2/alpn.h", + "src/core/lib/transport/chttp2/bin_encoder.h", + "src/core/lib/transport/chttp2/frame.h", + "src/core/lib/transport/chttp2/frame_data.h", + "src/core/lib/transport/chttp2/frame_goaway.h", + "src/core/lib/transport/chttp2/frame_ping.h", + "src/core/lib/transport/chttp2/frame_rst_stream.h", + "src/core/lib/transport/chttp2/frame_settings.h", + "src/core/lib/transport/chttp2/frame_window_update.h", + "src/core/lib/transport/chttp2/hpack_encoder.h", + "src/core/lib/transport/chttp2/hpack_parser.h", + "src/core/lib/transport/chttp2/hpack_table.h", + "src/core/lib/transport/chttp2/http2_errors.h", + "src/core/lib/transport/chttp2/huffsyms.h", + "src/core/lib/transport/chttp2/incoming_metadata.h", + "src/core/lib/transport/chttp2/internal.h", + "src/core/lib/transport/chttp2/status_conversion.h", + "src/core/lib/transport/chttp2/stream_map.h", + "src/core/lib/transport/chttp2/timeout_encoding.h", + "src/core/lib/transport/chttp2/varint.h", + "src/core/lib/transport/chttp2_transport.h", + "src/core/lib/transport/connectivity_state.h", + "src/core/lib/transport/metadata.h", + "src/core/lib/transport/metadata_batch.h", + "src/core/lib/transport/static_metadata.h", + "src/core/lib/transport/transport.h", + "src/core/lib/transport/transport_impl.h", + "src/core/lib/security/auth_filters.h", + "src/core/lib/security/b64.h", + "src/core/lib/security/credentials.h", + "src/core/lib/security/handshake.h", + "src/core/lib/security/json_token.h", + "src/core/lib/security/jwt_verifier.h", + "src/core/lib/security/secure_endpoint.h", + "src/core/lib/security/security_connector.h", + "src/core/lib/security/security_context.h", + "src/core/lib/tsi/fake_transport_security.h", + "src/core/lib/tsi/ssl_transport_security.h", + "src/core/lib/tsi/ssl_types.h", + "src/core/lib/tsi/transport_security.h", + "src/core/lib/tsi/transport_security_interface.h", + "src/core/lib/census/aggregation.h", + "src/core/lib/census/mlog.h", + "src/core/lib/census/rpc_metric_id.h", "third_party/nanopb/pb.h", "third_party/nanopb/pb_common.h", "third_party/nanopb/pb_decode.h", "third_party/nanopb/pb_encode.h", - "src/core/census/grpc_context.c", - "src/core/census/grpc_filter.c", - "src/core/census/grpc_plugin.c", - "src/core/channel/channel_args.c", - "src/core/channel/channel_stack.c", - "src/core/channel/channel_stack_builder.c", - "src/core/channel/client_channel.c", - "src/core/channel/compress_filter.c", - "src/core/channel/connected_channel.c", - "src/core/channel/http_client_filter.c", - "src/core/channel/http_server_filter.c", - "src/core/channel/subchannel_call_holder.c", - "src/core/client_config/client_config.c", - "src/core/client_config/connector.c", - "src/core/client_config/default_initial_connect_string.c", - "src/core/client_config/initial_connect_string.c", - "src/core/client_config/lb_policies/load_balancer_api.c", - "src/core/client_config/lb_policies/pick_first.c", - "src/core/client_config/lb_policies/round_robin.c", - "src/core/client_config/lb_policy.c", - "src/core/client_config/lb_policy_factory.c", - "src/core/client_config/lb_policy_registry.c", - "src/core/client_config/resolver.c", - "src/core/client_config/resolver_factory.c", - "src/core/client_config/resolver_registry.c", - "src/core/client_config/resolvers/dns_resolver.c", - "src/core/client_config/resolvers/sockaddr_resolver.c", - "src/core/client_config/subchannel.c", - "src/core/client_config/subchannel_factory.c", - "src/core/client_config/subchannel_index.c", - "src/core/client_config/uri_parser.c", - "src/core/compression/compression_algorithm.c", - "src/core/compression/message_compress.c", - "src/core/debug/trace.c", - "src/core/http/format_request.c", - "src/core/http/httpcli.c", - "src/core/http/parser.c", - "src/core/iomgr/closure.c", - "src/core/iomgr/endpoint.c", - "src/core/iomgr/endpoint_pair_posix.c", - "src/core/iomgr/endpoint_pair_windows.c", - "src/core/iomgr/exec_ctx.c", - "src/core/iomgr/executor.c", - "src/core/iomgr/fd_posix.c", - "src/core/iomgr/iocp_windows.c", - "src/core/iomgr/iomgr.c", - "src/core/iomgr/iomgr_posix.c", - "src/core/iomgr/iomgr_windows.c", - "src/core/iomgr/pollset_multipoller_with_epoll.c", - "src/core/iomgr/pollset_multipoller_with_poll_posix.c", - "src/core/iomgr/pollset_posix.c", - "src/core/iomgr/pollset_set_posix.c", - "src/core/iomgr/pollset_set_windows.c", - "src/core/iomgr/pollset_windows.c", - "src/core/iomgr/resolve_address_posix.c", - "src/core/iomgr/resolve_address_windows.c", - "src/core/iomgr/sockaddr_utils.c", - "src/core/iomgr/socket_utils_common_posix.c", - "src/core/iomgr/socket_utils_linux.c", - "src/core/iomgr/socket_utils_posix.c", - "src/core/iomgr/socket_windows.c", - "src/core/iomgr/tcp_client_posix.c", - "src/core/iomgr/tcp_client_windows.c", - "src/core/iomgr/tcp_posix.c", - "src/core/iomgr/tcp_server_posix.c", - "src/core/iomgr/tcp_server_windows.c", - "src/core/iomgr/tcp_windows.c", - "src/core/iomgr/time_averaged_stats.c", - "src/core/iomgr/timer.c", - "src/core/iomgr/timer_heap.c", - "src/core/iomgr/udp_server.c", - "src/core/iomgr/unix_sockets_posix.c", - "src/core/iomgr/unix_sockets_posix_noop.c", - "src/core/iomgr/wakeup_fd_eventfd.c", - "src/core/iomgr/wakeup_fd_nospecial.c", - "src/core/iomgr/wakeup_fd_pipe.c", - "src/core/iomgr/wakeup_fd_posix.c", - "src/core/iomgr/workqueue_posix.c", - "src/core/iomgr/workqueue_windows.c", - "src/core/json/json.c", - "src/core/json/json_reader.c", - "src/core/json/json_string.c", - "src/core/json/json_writer.c", - "src/core/proto/grpc/lb/v0/load_balancer.pb.c", - "src/core/surface/alarm.c", - "src/core/surface/api_trace.c", - "src/core/surface/byte_buffer.c", - "src/core/surface/byte_buffer_reader.c", - "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/channel_init.c", - "src/core/surface/channel_ping.c", - "src/core/surface/channel_stack_type.c", - "src/core/surface/completion_queue.c", - "src/core/surface/event_string.c", - "src/core/surface/init.c", - "src/core/surface/lame_client.c", - "src/core/surface/metadata_array.c", - "src/core/surface/server.c", - "src/core/surface/server_chttp2.c", - "src/core/surface/validate_metadata.c", - "src/core/surface/version.c", - "src/core/transport/byte_stream.c", - "src/core/transport/chttp2/alpn.c", - "src/core/transport/chttp2/bin_encoder.c", - "src/core/transport/chttp2/frame_data.c", - "src/core/transport/chttp2/frame_goaway.c", - "src/core/transport/chttp2/frame_ping.c", - "src/core/transport/chttp2/frame_rst_stream.c", - "src/core/transport/chttp2/frame_settings.c", - "src/core/transport/chttp2/frame_window_update.c", - "src/core/transport/chttp2/hpack_encoder.c", - "src/core/transport/chttp2/hpack_parser.c", - "src/core/transport/chttp2/hpack_table.c", - "src/core/transport/chttp2/huffsyms.c", - "src/core/transport/chttp2/incoming_metadata.c", - "src/core/transport/chttp2/parsing.c", - "src/core/transport/chttp2/status_conversion.c", - "src/core/transport/chttp2/stream_lists.c", - "src/core/transport/chttp2/stream_map.c", - "src/core/transport/chttp2/timeout_encoding.c", - "src/core/transport/chttp2/varint.c", - "src/core/transport/chttp2/writing.c", - "src/core/transport/chttp2_transport.c", - "src/core/transport/connectivity_state.c", - "src/core/transport/metadata.c", - "src/core/transport/metadata_batch.c", - "src/core/transport/static_metadata.c", - "src/core/transport/transport.c", - "src/core/transport/transport_op_string.c", - "src/core/http/httpcli_security_connector.c", - "src/core/security/b64.c", - "src/core/security/client_auth_filter.c", - "src/core/security/credentials.c", - "src/core/security/credentials_metadata.c", - "src/core/security/credentials_posix.c", - "src/core/security/credentials_win32.c", - "src/core/security/google_default_credentials.c", - "src/core/security/handshake.c", - "src/core/security/json_token.c", - "src/core/security/jwt_verifier.c", - "src/core/security/secure_endpoint.c", - "src/core/security/security_connector.c", - "src/core/security/security_context.c", - "src/core/security/server_auth_filter.c", - "src/core/security/server_secure_chttp2.c", - "src/core/surface/init_secure.c", - "src/core/surface/secure_channel_create.c", - "src/core/tsi/fake_transport_security.c", - "src/core/tsi/ssl_transport_security.c", - "src/core/tsi/transport_security.c", - "src/core/census/context.c", - "src/core/census/initialize.c", - "src/core/census/mlog.c", - "src/core/census/operation.c", - "src/core/census/placeholders.c", - "src/core/census/tracing.c", + "src/core/lib/census/grpc_context.c", + "src/core/lib/census/grpc_filter.c", + "src/core/lib/census/grpc_plugin.c", + "src/core/lib/channel/channel_args.c", + "src/core/lib/channel/channel_stack.c", + "src/core/lib/channel/channel_stack_builder.c", + "src/core/lib/channel/client_channel.c", + "src/core/lib/channel/compress_filter.c", + "src/core/lib/channel/connected_channel.c", + "src/core/lib/channel/http_client_filter.c", + "src/core/lib/channel/http_server_filter.c", + "src/core/lib/channel/subchannel_call_holder.c", + "src/core/lib/client_config/client_config.c", + "src/core/lib/client_config/connector.c", + "src/core/lib/client_config/default_initial_connect_string.c", + "src/core/lib/client_config/initial_connect_string.c", + "src/core/lib/client_config/lb_policies/load_balancer_api.c", + "src/core/lib/client_config/lb_policies/pick_first.c", + "src/core/lib/client_config/lb_policies/round_robin.c", + "src/core/lib/client_config/lb_policy.c", + "src/core/lib/client_config/lb_policy_factory.c", + "src/core/lib/client_config/lb_policy_registry.c", + "src/core/lib/client_config/resolver.c", + "src/core/lib/client_config/resolver_factory.c", + "src/core/lib/client_config/resolver_registry.c", + "src/core/lib/client_config/resolvers/dns_resolver.c", + "src/core/lib/client_config/resolvers/sockaddr_resolver.c", + "src/core/lib/client_config/subchannel.c", + "src/core/lib/client_config/subchannel_factory.c", + "src/core/lib/client_config/subchannel_index.c", + "src/core/lib/client_config/uri_parser.c", + "src/core/lib/compression/compression_algorithm.c", + "src/core/lib/compression/message_compress.c", + "src/core/lib/debug/trace.c", + "src/core/lib/http/format_request.c", + "src/core/lib/http/httpcli.c", + "src/core/lib/http/parser.c", + "src/core/lib/iomgr/closure.c", + "src/core/lib/iomgr/endpoint.c", + "src/core/lib/iomgr/endpoint_pair_posix.c", + "src/core/lib/iomgr/endpoint_pair_windows.c", + "src/core/lib/iomgr/exec_ctx.c", + "src/core/lib/iomgr/executor.c", + "src/core/lib/iomgr/fd_posix.c", + "src/core/lib/iomgr/iocp_windows.c", + "src/core/lib/iomgr/iomgr.c", + "src/core/lib/iomgr/iomgr_posix.c", + "src/core/lib/iomgr/iomgr_windows.c", + "src/core/lib/iomgr/pollset_multipoller_with_epoll.c", + "src/core/lib/iomgr/pollset_multipoller_with_poll_posix.c", + "src/core/lib/iomgr/pollset_posix.c", + "src/core/lib/iomgr/pollset_set_posix.c", + "src/core/lib/iomgr/pollset_set_windows.c", + "src/core/lib/iomgr/pollset_windows.c", + "src/core/lib/iomgr/resolve_address_posix.c", + "src/core/lib/iomgr/resolve_address_windows.c", + "src/core/lib/iomgr/sockaddr_utils.c", + "src/core/lib/iomgr/socket_utils_common_posix.c", + "src/core/lib/iomgr/socket_utils_linux.c", + "src/core/lib/iomgr/socket_utils_posix.c", + "src/core/lib/iomgr/socket_windows.c", + "src/core/lib/iomgr/tcp_client_posix.c", + "src/core/lib/iomgr/tcp_client_windows.c", + "src/core/lib/iomgr/tcp_posix.c", + "src/core/lib/iomgr/tcp_server_posix.c", + "src/core/lib/iomgr/tcp_server_windows.c", + "src/core/lib/iomgr/tcp_windows.c", + "src/core/lib/iomgr/time_averaged_stats.c", + "src/core/lib/iomgr/timer.c", + "src/core/lib/iomgr/timer_heap.c", + "src/core/lib/iomgr/udp_server.c", + "src/core/lib/iomgr/unix_sockets_posix.c", + "src/core/lib/iomgr/unix_sockets_posix_noop.c", + "src/core/lib/iomgr/wakeup_fd_eventfd.c", + "src/core/lib/iomgr/wakeup_fd_nospecial.c", + "src/core/lib/iomgr/wakeup_fd_pipe.c", + "src/core/lib/iomgr/wakeup_fd_posix.c", + "src/core/lib/iomgr/workqueue_posix.c", + "src/core/lib/iomgr/workqueue_windows.c", + "src/core/lib/json/json.c", + "src/core/lib/json/json_reader.c", + "src/core/lib/json/json_string.c", + "src/core/lib/json/json_writer.c", + "src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c", + "src/core/lib/surface/alarm.c", + "src/core/lib/surface/api_trace.c", + "src/core/lib/surface/byte_buffer.c", + "src/core/lib/surface/byte_buffer_reader.c", + "src/core/lib/surface/call.c", + "src/core/lib/surface/call_details.c", + "src/core/lib/surface/call_log_batch.c", + "src/core/lib/surface/channel.c", + "src/core/lib/surface/channel_connectivity.c", + "src/core/lib/surface/channel_create.c", + "src/core/lib/surface/channel_init.c", + "src/core/lib/surface/channel_ping.c", + "src/core/lib/surface/channel_stack_type.c", + "src/core/lib/surface/completion_queue.c", + "src/core/lib/surface/event_string.c", + "src/core/lib/surface/init.c", + "src/core/lib/surface/lame_client.c", + "src/core/lib/surface/metadata_array.c", + "src/core/lib/surface/server.c", + "src/core/lib/surface/server_chttp2.c", + "src/core/lib/surface/validate_metadata.c", + "src/core/lib/surface/version.c", + "src/core/lib/transport/byte_stream.c", + "src/core/lib/transport/chttp2/alpn.c", + "src/core/lib/transport/chttp2/bin_encoder.c", + "src/core/lib/transport/chttp2/frame_data.c", + "src/core/lib/transport/chttp2/frame_goaway.c", + "src/core/lib/transport/chttp2/frame_ping.c", + "src/core/lib/transport/chttp2/frame_rst_stream.c", + "src/core/lib/transport/chttp2/frame_settings.c", + "src/core/lib/transport/chttp2/frame_window_update.c", + "src/core/lib/transport/chttp2/hpack_encoder.c", + "src/core/lib/transport/chttp2/hpack_parser.c", + "src/core/lib/transport/chttp2/hpack_table.c", + "src/core/lib/transport/chttp2/huffsyms.c", + "src/core/lib/transport/chttp2/incoming_metadata.c", + "src/core/lib/transport/chttp2/parsing.c", + "src/core/lib/transport/chttp2/status_conversion.c", + "src/core/lib/transport/chttp2/stream_lists.c", + "src/core/lib/transport/chttp2/stream_map.c", + "src/core/lib/transport/chttp2/timeout_encoding.c", + "src/core/lib/transport/chttp2/varint.c", + "src/core/lib/transport/chttp2/writing.c", + "src/core/lib/transport/chttp2_transport.c", + "src/core/lib/transport/connectivity_state.c", + "src/core/lib/transport/metadata.c", + "src/core/lib/transport/metadata_batch.c", + "src/core/lib/transport/static_metadata.c", + "src/core/lib/transport/transport.c", + "src/core/lib/transport/transport_op_string.c", + "src/core/lib/http/httpcli_security_connector.c", + "src/core/lib/security/b64.c", + "src/core/lib/security/client_auth_filter.c", + "src/core/lib/security/credentials.c", + "src/core/lib/security/credentials_metadata.c", + "src/core/lib/security/credentials_posix.c", + "src/core/lib/security/credentials_win32.c", + "src/core/lib/security/google_default_credentials.c", + "src/core/lib/security/handshake.c", + "src/core/lib/security/json_token.c", + "src/core/lib/security/jwt_verifier.c", + "src/core/lib/security/secure_endpoint.c", + "src/core/lib/security/security_connector.c", + "src/core/lib/security/security_context.c", + "src/core/lib/security/server_auth_filter.c", + "src/core/lib/security/server_secure_chttp2.c", + "src/core/lib/surface/init_secure.c", + "src/core/lib/surface/secure_channel_create.c", + "src/core/lib/tsi/fake_transport_security.c", + "src/core/lib/tsi/ssl_transport_security.c", + "src/core/lib/tsi/transport_security.c", + "src/core/lib/census/context.c", + "src/core/lib/census/initialize.c", + "src/core/lib/census/mlog.c", + "src/core/lib/census/operation.c", + "src/core/lib/census/placeholders.c", + "src/core/lib/census/tracing.c", "third_party/nanopb/pb_common.c", "third_party/nanopb/pb_decode.c", "third_party/nanopb/pb_encode.c", @@ -873,62 +873,62 @@ "include/grpc/impl/codegen/sync_posix.h", "include/grpc/impl/codegen/sync_win32.h", "include/grpc/impl/codegen/time.h", - "src/core/profiling/timers.h", - "src/core/support/backoff.h", - "src/core/support/block_annotate.h", - "src/core/support/env.h", - "src/core/support/load_file.h", - "src/core/support/murmur_hash.h", - "src/core/support/stack_lockfree.h", - "src/core/support/string.h", - "src/core/support/string_win32.h", - "src/core/support/thd_internal.h", - "src/core/support/time_precise.h", - "src/core/support/tmpfile.h", - "src/core/profiling/basic_timers.c", - "src/core/profiling/stap_timers.c", - "src/core/support/alloc.c", - "src/core/support/avl.c", - "src/core/support/backoff.c", - "src/core/support/cmdline.c", - "src/core/support/cpu_iphone.c", - "src/core/support/cpu_linux.c", - "src/core/support/cpu_posix.c", - "src/core/support/cpu_windows.c", - "src/core/support/env_linux.c", - "src/core/support/env_posix.c", - "src/core/support/env_win32.c", - "src/core/support/histogram.c", - "src/core/support/host_port.c", - "src/core/support/load_file.c", - "src/core/support/log.c", - "src/core/support/log_android.c", - "src/core/support/log_linux.c", - "src/core/support/log_posix.c", - "src/core/support/log_win32.c", - "src/core/support/murmur_hash.c", - "src/core/support/slice.c", - "src/core/support/slice_buffer.c", - "src/core/support/stack_lockfree.c", - "src/core/support/string.c", - "src/core/support/string_posix.c", - "src/core/support/string_win32.c", - "src/core/support/subprocess_posix.c", - "src/core/support/subprocess_windows.c", - "src/core/support/sync.c", - "src/core/support/sync_posix.c", - "src/core/support/sync_win32.c", - "src/core/support/thd.c", - "src/core/support/thd_posix.c", - "src/core/support/thd_win32.c", - "src/core/support/time.c", - "src/core/support/time_posix.c", - "src/core/support/time_precise.c", - "src/core/support/time_win32.c", - "src/core/support/tls_pthread.c", - "src/core/support/tmpfile_posix.c", - "src/core/support/tmpfile_win32.c", - "src/core/support/wrap_memcpy.c", + "src/core/lib/profiling/timers.h", + "src/core/lib/support/backoff.h", + "src/core/lib/support/block_annotate.h", + "src/core/lib/support/env.h", + "src/core/lib/support/load_file.h", + "src/core/lib/support/murmur_hash.h", + "src/core/lib/support/stack_lockfree.h", + "src/core/lib/support/string.h", + "src/core/lib/support/string_win32.h", + "src/core/lib/support/thd_internal.h", + "src/core/lib/support/time_precise.h", + "src/core/lib/support/tmpfile.h", + "src/core/lib/profiling/basic_timers.c", + "src/core/lib/profiling/stap_timers.c", + "src/core/lib/support/alloc.c", + "src/core/lib/support/avl.c", + "src/core/lib/support/backoff.c", + "src/core/lib/support/cmdline.c", + "src/core/lib/support/cpu_iphone.c", + "src/core/lib/support/cpu_linux.c", + "src/core/lib/support/cpu_posix.c", + "src/core/lib/support/cpu_windows.c", + "src/core/lib/support/env_linux.c", + "src/core/lib/support/env_posix.c", + "src/core/lib/support/env_win32.c", + "src/core/lib/support/histogram.c", + "src/core/lib/support/host_port.c", + "src/core/lib/support/load_file.c", + "src/core/lib/support/log.c", + "src/core/lib/support/log_android.c", + "src/core/lib/support/log_linux.c", + "src/core/lib/support/log_posix.c", + "src/core/lib/support/log_win32.c", + "src/core/lib/support/murmur_hash.c", + "src/core/lib/support/slice.c", + "src/core/lib/support/slice_buffer.c", + "src/core/lib/support/stack_lockfree.c", + "src/core/lib/support/string.c", + "src/core/lib/support/string_posix.c", + "src/core/lib/support/string_win32.c", + "src/core/lib/support/subprocess_posix.c", + "src/core/lib/support/subprocess_windows.c", + "src/core/lib/support/sync.c", + "src/core/lib/support/sync_posix.c", + "src/core/lib/support/sync_win32.c", + "src/core/lib/support/thd.c", + "src/core/lib/support/thd_posix.c", + "src/core/lib/support/thd_win32.c", + "src/core/lib/support/time.c", + "src/core/lib/support/time_posix.c", + "src/core/lib/support/time_precise.c", + "src/core/lib/support/time_win32.c", + "src/core/lib/support/tls_pthread.c", + "src/core/lib/support/tmpfile_posix.c", + "src/core/lib/support/tmpfile_win32.c", + "src/core/lib/support/wrap_memcpy.c", "binding.gyp" ], "main": "src/node/index.js", diff --git a/package.xml b/package.xml index 4a99922fb3..bb969d115c 100644 --- a/package.xml +++ b/package.xml @@ -92,62 +92,62 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -161,308 +161,308 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/core/census/README.md b/src/core/census/README.md deleted file mode 100644 index fb615a2194..0000000000 --- a/src/core/census/README.md +++ /dev/null @@ -1,76 +0,0 @@ - - -# Census - a resource measurement and tracing system - -This directory contains code for Census, which will ultimately provide the -following features for any gRPC-using system: -* A [dapper](http://research.google.com/pubs/pub36356.html)-like tracing - system, enabling tracing across a distributed infrastructure. -* RPC statistics and measurements for key metrics, such as latency, bytes - transferred, number of errors etc. -* Resource measurement framework which can be used for measuring custom - metrics. Through the use of [tags](#Tags), these can be broken down across - the entire distributed stack. -* Easy integration of the above with - [Google Cloud Trace](https://cloud.google.com/tools/cloud-trace) and - [Google Cloud Monitoring](https://cloud.google.com/monitoring/). - -## Concepts - -### Context - -### Operations - -### Tags - -### Metrics - -## API - -### Internal/RPC API - -### External/Client API - -### RPC API - -## Files in this directory - -Note that files and functions in this directory can be split into two -categories: -* Files that define core census library functions. Functions etc. in these - files are named census\_\*, and constitute the core census library - functionality. At some time in the future, these will become a standalone - library. -* Files that define functions etc. that provide a convenient interface between - grpc and the core census functionality. These files are all named - grpc\_\*.{c,h}, and define function names beginning with grpc\_census\_\*. - diff --git a/src/core/census/aggregation.h b/src/core/census/aggregation.h deleted file mode 100644 index e0ef9630c9..0000000000 --- a/src/core/census/aggregation.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * - * Copyright 2015-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 - -#ifndef GRPC_CORE_CENSUS_AGGREGATION_H -#define GRPC_CORE_CENSUS_AGGREGATION_H - -/** Structure used to describe an aggregation type. */ -struct census_aggregation_ops { - /* Create a new aggregation. The pointer returned can be used in future calls - to clone(), free(), record(), data() and reset(). */ - void *(*create)(const void *create_arg); - /* Make a copy of an aggregation created by create() */ - void *(*clone)(const void *aggregation); - /* Destroy an aggregation created by create() */ - void (*free)(void *aggregation); - /* Record a new value against aggregation. */ - void (*record)(void *aggregation, double value); - /* Return current aggregation data. The caller must cast this object into - the correct type for the aggregation result. The object returned can be - freed by using free_data(). */ - void *(*data)(const void *aggregation); - /* free data returned by data() */ - void (*free_data)(void *data); - /* Reset an aggregation to default (zero) values. */ - void (*reset)(void *aggregation); - /* Merge 'from' aggregation into 'to'. Both aggregations must be compatible */ - void (*merge)(void *to, const void *from); - /* Fill buffer with printable string version of aggregation contents. For - debugging only. Returns the number of bytes added to buffer (a value == n - implies the buffer was of insufficient size). */ - size_t (*print)(const void *aggregation, char *buffer, size_t n); -}; - -#endif /* GRPC_CORE_CENSUS_AGGREGATION_H */ diff --git a/src/core/census/context.c b/src/core/census/context.c deleted file mode 100644 index 89b8ee0b39..0000000000 --- a/src/core/census/context.c +++ /dev/null @@ -1,509 +0,0 @@ -/* - * - * Copyright 2015-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 -#include -#include -#include -#include -#include -#include -#include "src/core/support/string.h" - -// Functions in this file support the public context API, including -// encoding/decoding as part of context propagation across RPC's. The overall -// requirements (in approximate priority order) for the -// context representation: -// 1. Efficient conversion to/from wire format -// 2. Minimal bytes used on-wire -// 3. Efficient context creation -// 4. Efficient lookup of tag value for a key -// 5. Efficient iteration over tags -// 6. Minimal memory footprint -// -// Notes on tradeoffs/decisions: -// * tag includes 1 byte length of key, as well as nil-terminating byte. These -// are to aid in efficient parsing and the ability to directly return key -// strings. This is more important than saving a single byte/tag on the wire. -// * The wire encoding uses only single byte values. This eliminates the need -// to handle endian-ness conversions. It also means there is a hard upper -// limit of 255 for both CENSUS_MAX_TAG_KV_LEN and CENSUS_MAX_PROPAGATED_TAGS. -// * Keep all tag information (keys/values/flags) in a single memory buffer, -// that can be directly copied to the wire. - -// min and max valid chars in tag keys and values. All printable ASCII is OK. -#define MIN_VALID_TAG_CHAR 32 // ' ' -#define MAX_VALID_TAG_CHAR 126 // '~' - -// Structure representing a set of tags. Essentially a count of number of tags -// present, and pointer to a chunk of memory that contains the per-tag details. -struct tag_set { - int ntags; // number of tags. - int ntags_alloc; // ntags + number of deleted tags (total number of tags - // in all of kvm). This will always be == ntags, except during the process - // of building a new tag set. - size_t kvm_size; // number of bytes allocated for key/value storage. - size_t kvm_used; // number of bytes of used key/value memory - char *kvm; // key/value memory. Consists of repeated entries of: - // Offset Size Description - // 0 1 Key length, including trailing 0. (K) - // 1 1 Value length, including trailing 0 (V) - // 2 1 Flags - // 3 K Key bytes - // 3 + K V Value bytes - // - // We refer to the first 3 entries as the 'tag header'. If extra values are - // introduced in the header, you will need to modify the TAG_HEADER_SIZE - // constant, the raw_tag structure (and everything that uses it) and the - // encode/decode functions appropriately. -}; - -// Number of bytes in tag header. -#define TAG_HEADER_SIZE 3 // key length (1) + value length (1) + flags (1) -// Offsets to tag header entries. -#define KEY_LEN_OFFSET 0 -#define VALUE_LEN_OFFSET 1 -#define FLAG_OFFSET 2 - -// raw_tag represents the raw-storage form of a tag in the kvm of a tag_set. -struct raw_tag { - uint8_t key_len; - uint8_t value_len; - uint8_t flags; - char *key; - char *value; -}; - -// Use a reserved flag bit for indication of deleted tag. -#define CENSUS_TAG_DELETED CENSUS_TAG_RESERVED -#define CENSUS_TAG_IS_DELETED(flags) (flags & CENSUS_TAG_DELETED) - -// Primary representation of a context. Composed of 2 underlying tag_set -// structs, one each for propagated and local (non-propagated) tags. This is -// to efficiently support tag encoding/decoding. -// TODO(aveitch): need to add tracing id's/structure. -struct census_context { - struct tag_set tags[2]; - census_context_status status; -}; - -// Indices into the tags member of census_context -#define PROPAGATED_TAGS 0 -#define LOCAL_TAGS 1 - -// Validate (check all characters are in range and size is less than limit) a -// key or value string. Returns 0 if the string is invalid, or the length -// (including terminator) if valid. -static size_t validate_tag(const char *kv) { - size_t len = 1; - char ch; - while ((ch = *kv++) != 0) { - if (ch < MIN_VALID_TAG_CHAR || ch > MAX_VALID_TAG_CHAR) { - return 0; - } - len++; - } - if (len > CENSUS_MAX_TAG_KV_LEN) { - return 0; - } - return len; -} - -// Extract a raw tag given a pointer (raw) to the tag header. Allow for some -// extra bytes in the tag header (see encode/decode functions for usage: this -// allows for future expansion of the tag header). -static char *decode_tag(struct raw_tag *tag, char *header, int offset) { - tag->key_len = (uint8_t)(*header++); - tag->value_len = (uint8_t)(*header++); - tag->flags = (uint8_t)(*header++); - header += offset; - tag->key = header; - header += tag->key_len; - tag->value = header; - return header + tag->value_len; -} - -// Make a copy (in 'to') of an existing tag_set. -static void tag_set_copy(struct tag_set *to, const struct tag_set *from) { - memcpy(to, from, sizeof(struct tag_set)); - to->kvm = gpr_malloc(to->kvm_size); - memcpy(to->kvm, from->kvm, from->kvm_used); -} - -// Delete a tag from a tag_set, if it exists (returns true if it did). -static bool tag_set_delete_tag(struct tag_set *tags, const char *key, - size_t key_len) { - char *kvp = tags->kvm; - for (int i = 0; i < tags->ntags_alloc; i++) { - uint8_t *flags = (uint8_t *)(kvp + FLAG_OFFSET); - struct raw_tag tag; - kvp = decode_tag(&tag, kvp, 0); - if (CENSUS_TAG_IS_DELETED(tag.flags)) continue; - if ((key_len == tag.key_len) && (memcmp(key, tag.key, key_len) == 0)) { - *flags |= CENSUS_TAG_DELETED; - tags->ntags--; - return true; - } - } - return false; -} - -// Delete a tag from a context, return true if it existed. -static bool context_delete_tag(census_context *context, const census_tag *tag, - size_t key_len) { - return ( - tag_set_delete_tag(&context->tags[LOCAL_TAGS], tag->key, key_len) || - tag_set_delete_tag(&context->tags[PROPAGATED_TAGS], tag->key, key_len)); -} - -// Add a tag to a tag_set. Return true on success, false if the tag could -// not be added because of constraints on tag set size. This function should -// not be called if the tag may already exist (in a non-deleted state) in -// the tag_set, as that would result in two tags with the same key. -static bool tag_set_add_tag(struct tag_set *tags, const census_tag *tag, - size_t key_len, size_t value_len) { - if (tags->ntags == CENSUS_MAX_PROPAGATED_TAGS) { - return false; - } - const size_t tag_size = key_len + value_len + TAG_HEADER_SIZE; - if (tags->kvm_used + tag_size > tags->kvm_size) { - // allocate new memory if needed - tags->kvm_size += 2 * CENSUS_MAX_TAG_KV_LEN + TAG_HEADER_SIZE; - char *new_kvm = gpr_malloc(tags->kvm_size); - memcpy(new_kvm, tags->kvm, tags->kvm_used); - gpr_free(tags->kvm); - tags->kvm = new_kvm; - } - char *kvp = tags->kvm + tags->kvm_used; - *kvp++ = (char)key_len; - *kvp++ = (char)value_len; - // ensure reserved flags are not used. - *kvp++ = (char)(tag->flags & (CENSUS_TAG_PROPAGATE | CENSUS_TAG_STATS)); - memcpy(kvp, tag->key, key_len); - kvp += key_len; - memcpy(kvp, tag->value, value_len); - tags->kvm_used += tag_size; - tags->ntags++; - tags->ntags_alloc++; - return true; -} - -// Add/modify/delete a tag to/in a context. Caller must validate that tag key -// etc. are valid. -static void context_modify_tag(census_context *context, const census_tag *tag, - size_t key_len, size_t value_len) { - // First delete the tag if it is already present. - bool deleted = context_delete_tag(context, tag, key_len); - bool added = false; - if (CENSUS_TAG_IS_PROPAGATED(tag->flags)) { - added = tag_set_add_tag(&context->tags[PROPAGATED_TAGS], tag, key_len, - value_len); - } else { - added = - tag_set_add_tag(&context->tags[LOCAL_TAGS], tag, key_len, value_len); - } - - if (deleted) { - context->status.n_modified_tags++; - } else { - if (added) { - context->status.n_added_tags++; - } else { - context->status.n_ignored_tags++; - } - } -} - -// Remove memory used for deleted tags from a tag set. Basic algorithm: -// 1) Walk through tag set to find first deleted tag. Record where it is. -// 2) Find the next not-deleted tag. Copy all of kvm from there to the end -// "over" the deleted tags -// 3) repeat #1 and #2 until we have seen all tags -// 4) if we are still looking for a not-deleted tag, then all the end portion -// of the kvm is deleted. Just reduce the used amount of memory by the -// appropriate amount. -static void tag_set_flatten(struct tag_set *tags) { - if (tags->ntags == tags->ntags_alloc) return; - bool found_deleted = false; // found a deleted tag. - char *kvp = tags->kvm; - char *dbase = NULL; // record location of deleted tag - for (int i = 0; i < tags->ntags_alloc; i++) { - struct raw_tag tag; - char *next_kvp = decode_tag(&tag, kvp, 0); - if (found_deleted) { - if (!CENSUS_TAG_IS_DELETED(tag.flags)) { - ptrdiff_t reduce = kvp - dbase; // #bytes in deleted tags - GPR_ASSERT(reduce > 0); - ptrdiff_t copy_size = tags->kvm + tags->kvm_used - kvp; - GPR_ASSERT(copy_size > 0); - memmove(dbase, kvp, (size_t)copy_size); - tags->kvm_used -= (size_t)reduce; - next_kvp -= reduce; - found_deleted = false; - } - } else { - if (CENSUS_TAG_IS_DELETED(tag.flags)) { - dbase = kvp; - found_deleted = true; - } - } - kvp = next_kvp; - } - if (found_deleted) { - GPR_ASSERT(dbase > tags->kvm); - tags->kvm_used = (size_t)(dbase - tags->kvm); - } - tags->ntags_alloc = tags->ntags; -} - -census_context *census_context_create(const census_context *base, - const census_tag *tags, int ntags, - census_context_status const **status) { - census_context *context = gpr_malloc(sizeof(census_context)); - // If we are given a base, copy it into our new tag set. Otherwise set it - // to zero/NULL everything. - if (base == NULL) { - memset(context, 0, sizeof(census_context)); - } else { - tag_set_copy(&context->tags[PROPAGATED_TAGS], &base->tags[PROPAGATED_TAGS]); - tag_set_copy(&context->tags[LOCAL_TAGS], &base->tags[LOCAL_TAGS]); - memset(&context->status, 0, sizeof(context->status)); - } - // Walk over the additional tags and, for those that aren't invalid, modify - // the context to add/replace/delete as required. - for (int i = 0; i < ntags; i++) { - const census_tag *tag = &tags[i]; - size_t key_len = validate_tag(tag->key); - // ignore the tag if it is invalid or too short. - if (key_len <= 1) { - context->status.n_invalid_tags++; - } else { - if (tag->value != NULL) { - size_t value_len = validate_tag(tag->value); - if (value_len != 0) { - context_modify_tag(context, tag, key_len, value_len); - } else { - context->status.n_invalid_tags++; - } - } else { - if (context_delete_tag(context, tag, key_len)) { - context->status.n_deleted_tags++; - } - } - } - } - // Remove any deleted tags, update status if needed, and return. - tag_set_flatten(&context->tags[PROPAGATED_TAGS]); - tag_set_flatten(&context->tags[LOCAL_TAGS]); - context->status.n_propagated_tags = context->tags[PROPAGATED_TAGS].ntags; - context->status.n_local_tags = context->tags[LOCAL_TAGS].ntags; - if (status) { - *status = &context->status; - } - return context; -} - -const census_context_status *census_context_get_status( - const census_context *context) { - return &context->status; -} - -void census_context_destroy(census_context *context) { - gpr_free(context->tags[PROPAGATED_TAGS].kvm); - gpr_free(context->tags[LOCAL_TAGS].kvm); - gpr_free(context); -} - -void census_context_initialize_iterator(const census_context *context, - census_context_iterator *iterator) { - iterator->context = context; - iterator->index = 0; - if (context->tags[PROPAGATED_TAGS].ntags != 0) { - iterator->base = PROPAGATED_TAGS; - iterator->kvm = context->tags[PROPAGATED_TAGS].kvm; - } else if (context->tags[LOCAL_TAGS].ntags != 0) { - iterator->base = LOCAL_TAGS; - iterator->kvm = context->tags[LOCAL_TAGS].kvm; - } else { - iterator->base = -1; - } -} - -int census_context_next_tag(census_context_iterator *iterator, - census_tag *tag) { - if (iterator->base < 0) { - return 0; - } - struct raw_tag raw; - iterator->kvm = decode_tag(&raw, iterator->kvm, 0); - tag->key = raw.key; - tag->value = raw.value; - tag->flags = raw.flags; - if (++iterator->index == iterator->context->tags[iterator->base].ntags) { - do { - if (iterator->base == LOCAL_TAGS) { - iterator->base = -1; - return 1; - } - } while (iterator->context->tags[++iterator->base].ntags == 0); - iterator->index = 0; - iterator->kvm = iterator->context->tags[iterator->base].kvm; - } - return 1; -} - -// Find a tag in a tag_set by key. Return true if found, false otherwise. -static bool tag_set_get_tag(const struct tag_set *tags, const char *key, - size_t key_len, census_tag *tag) { - char *kvp = tags->kvm; - for (int i = 0; i < tags->ntags; i++) { - struct raw_tag raw; - kvp = decode_tag(&raw, kvp, 0); - if (key_len == raw.key_len && memcmp(raw.key, key, key_len) == 0) { - tag->key = raw.key; - tag->value = raw.value; - tag->flags = raw.flags; - return true; - } - } - return false; -} - -int census_context_get_tag(const census_context *context, const char *key, - census_tag *tag) { - size_t key_len = strlen(key) + 1; - if (key_len == 1) { - return 0; - } - if (tag_set_get_tag(&context->tags[PROPAGATED_TAGS], key, key_len, tag) || - tag_set_get_tag(&context->tags[LOCAL_TAGS], key, key_len, tag)) { - return 1; - } - return 0; -} - -// Context encoding and decoding functions. -// -// Wire format for tag_set's on the wire: -// -// First, a tag set header: -// -// offset bytes description -// 0 1 version number -// 1 1 number of bytes in this header. This allows for future -// expansion. -// 2 1 number of bytes in each tag header. -// 3 1 ntags value from tag set. -// -// This is followed by the key/value memory from struct tag_set. - -#define ENCODED_VERSION 0 // Version number -#define ENCODED_HEADER_SIZE 4 // size of tag set header - -// Encode a tag set. Returns 0 if buffer is too small. -static size_t tag_set_encode(const struct tag_set *tags, char *buffer, - size_t buf_size) { - if (buf_size < ENCODED_HEADER_SIZE + tags->kvm_used) { - return 0; - } - buf_size -= ENCODED_HEADER_SIZE; - *buffer++ = (char)ENCODED_VERSION; - *buffer++ = (char)ENCODED_HEADER_SIZE; - *buffer++ = (char)TAG_HEADER_SIZE; - *buffer++ = (char)tags->ntags; - if (tags->ntags == 0) { - return ENCODED_HEADER_SIZE; - } - memcpy(buffer, tags->kvm, tags->kvm_used); - return ENCODED_HEADER_SIZE + tags->kvm_used; -} - -size_t census_context_encode(const census_context *context, char *buffer, - size_t buf_size) { - return tag_set_encode(&context->tags[PROPAGATED_TAGS], buffer, buf_size); -} - -// Decode a tag set. -static void tag_set_decode(struct tag_set *tags, const char *buffer, - size_t size) { - uint8_t version = (uint8_t)(*buffer++); - uint8_t header_size = (uint8_t)(*buffer++); - uint8_t tag_header_size = (uint8_t)(*buffer++); - tags->ntags = tags->ntags_alloc = (int)(*buffer++); - if (tags->ntags == 0) { - tags->ntags_alloc = 0; - tags->kvm_size = 0; - tags->kvm_used = 0; - tags->kvm = NULL; - return; - } - if (header_size != ENCODED_HEADER_SIZE) { - GPR_ASSERT(version != ENCODED_VERSION); - GPR_ASSERT(ENCODED_HEADER_SIZE < header_size); - buffer += (header_size - ENCODED_HEADER_SIZE); - } - tags->kvm_used = size - header_size; - tags->kvm_size = tags->kvm_used + CENSUS_MAX_TAG_KV_LEN; - tags->kvm = gpr_malloc(tags->kvm_size); - if (tag_header_size != TAG_HEADER_SIZE) { - // something new in the tag information. I don't understand it, so - // don't copy it over. - GPR_ASSERT(version != ENCODED_VERSION); - GPR_ASSERT(tag_header_size > TAG_HEADER_SIZE); - char *kvp = tags->kvm; - for (int i = 0; i < tags->ntags; i++) { - memcpy(kvp, buffer, TAG_HEADER_SIZE); - kvp += header_size; - struct raw_tag raw; - buffer = - decode_tag(&raw, (char *)buffer, tag_header_size - TAG_HEADER_SIZE); - memcpy(kvp, raw.key, (size_t)raw.key_len + raw.value_len); - kvp += raw.key_len + raw.value_len; - } - } else { - memcpy(tags->kvm, buffer, tags->kvm_used); - } -} - -census_context *census_context_decode(const char *buffer, size_t size) { - census_context *context = gpr_malloc(sizeof(census_context)); - memset(&context->tags[LOCAL_TAGS], 0, sizeof(struct tag_set)); - if (buffer == NULL) { - memset(&context->tags[PROPAGATED_TAGS], 0, sizeof(struct tag_set)); - } else { - tag_set_decode(&context->tags[PROPAGATED_TAGS], buffer, size); - } - memset(&context->status, 0, sizeof(context->status)); - context->status.n_propagated_tags = context->tags[PROPAGATED_TAGS].ntags; - return context; -} diff --git a/src/core/census/grpc_context.c b/src/core/census/grpc_context.c deleted file mode 100644 index 4b61382a2c..0000000000 --- a/src/core/census/grpc_context.c +++ /dev/null @@ -1,53 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include -#include -#include "src/core/surface/api_trace.h" -#include "src/core/surface/call.h" - -void grpc_census_call_set_context(grpc_call *call, census_context *context) { - GRPC_API_TRACE("grpc_census_call_set_context(call=%p, census_context=%p)", 2, - (call, context)); - if (census_enabled() == CENSUS_FEATURE_NONE) { - return; - } - if (context != NULL) { - grpc_call_context_set(call, GRPC_CONTEXT_TRACING, context, NULL); - } -} - -census_context *grpc_census_call_get_context(grpc_call *call) { - GRPC_API_TRACE("grpc_census_call_get_context(call=%p)", 1, (call)); - return (census_context *)grpc_call_context_get(call, GRPC_CONTEXT_TRACING); -} diff --git a/src/core/census/grpc_filter.c b/src/core/census/grpc_filter.c deleted file mode 100644 index 11120a28d1..0000000000 --- a/src/core/census/grpc_filter.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - * - * Copyright 2015-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/census/grpc_filter.h" - -#include -#include - -#include -#include -#include -#include -#include - -#include "src/core/channel/channel_stack.h" -#include "src/core/statistics/census_interface.h" -#include "src/core/statistics/census_rpc_stats.h" -#include "src/core/transport/static_metadata.h" - -typedef struct call_data { - census_op_id op_id; - census_context *ctxt; - gpr_timespec start_ts; - int error; - - /* recv callback */ - grpc_metadata_batch *recv_initial_metadata; - grpc_closure *on_done_recv; - grpc_closure finish_recv; -} call_data; - -typedef struct channel_data { uint8_t unused; } channel_data; - -static void extract_and_annotate_method_tag(grpc_metadata_batch *md, - call_data *calld, - channel_data *chand) { - grpc_linked_mdelem *m; - for (m = md->list.head; m != NULL; m = m->next) { - if (m->md->key == GRPC_MDSTR_PATH) { - gpr_log(GPR_DEBUG, "%s", - (const char *)GPR_SLICE_START_PTR(m->md->value->slice)); - /* Add method tag here */ - } - } -} - -static void client_mutate_op(grpc_call_element *elem, - grpc_transport_stream_op *op) { - call_data *calld = elem->call_data; - channel_data *chand = elem->channel_data; - if (op->send_initial_metadata) { - extract_and_annotate_method_tag(op->send_initial_metadata, calld, chand); - } -} - -static void client_start_transport_op(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_transport_stream_op *op) { - client_mutate_op(elem, op); - grpc_call_next_op(exec_ctx, elem, op); -} - -static void server_on_done_recv(grpc_exec_ctx *exec_ctx, void *ptr, - bool success) { - grpc_call_element *elem = ptr; - call_data *calld = elem->call_data; - channel_data *chand = elem->channel_data; - if (success) { - extract_and_annotate_method_tag(calld->recv_initial_metadata, calld, chand); - } - calld->on_done_recv->cb(exec_ctx, calld->on_done_recv->cb_arg, success); -} - -static void server_mutate_op(grpc_call_element *elem, - grpc_transport_stream_op *op) { - call_data *calld = elem->call_data; - if (op->recv_initial_metadata) { - /* substitute our callback for the op callback */ - calld->recv_initial_metadata = op->recv_initial_metadata; - calld->on_done_recv = op->recv_initial_metadata_ready; - op->recv_initial_metadata_ready = &calld->finish_recv; - } -} - -static void server_start_transport_op(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_transport_stream_op *op) { - /* TODO(ctiller): this code fails. I don't know why. I expect it's - incomplete, and someone should look at it soon. - - call_data *calld = elem->call_data; - GPR_ASSERT((calld->op_id.upper != 0) || (calld->op_id.lower != 0)); */ - server_mutate_op(elem, op); - grpc_call_next_op(exec_ctx, elem, op); -} - -static void client_init_call_elem(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_call_element_args *args) { - call_data *d = elem->call_data; - GPR_ASSERT(d != NULL); - memset(d, 0, sizeof(*d)); - d->start_ts = gpr_now(GPR_CLOCK_REALTIME); -} - -static void client_destroy_call_elem(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem) { - call_data *d = elem->call_data; - GPR_ASSERT(d != NULL); - /* TODO(hongyu): record rpc client stats and census_rpc_end_op here */ -} - -static void server_init_call_elem(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_call_element_args *args) { - call_data *d = elem->call_data; - GPR_ASSERT(d != NULL); - memset(d, 0, sizeof(*d)); - d->start_ts = gpr_now(GPR_CLOCK_REALTIME); - /* TODO(hongyu): call census_tracing_start_op here. */ - grpc_closure_init(&d->finish_recv, server_on_done_recv, elem); -} - -static void server_destroy_call_elem(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem) { - call_data *d = elem->call_data; - GPR_ASSERT(d != NULL); - /* TODO(hongyu): record rpc server stats and census_tracing_end_op here */ -} - -static void init_channel_elem(grpc_exec_ctx *exec_ctx, - grpc_channel_element *elem, - grpc_channel_element_args *args) { - channel_data *chand = elem->channel_data; - GPR_ASSERT(chand != NULL); -} - -static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, - grpc_channel_element *elem) { - channel_data *chand = elem->channel_data; - GPR_ASSERT(chand != NULL); -} - -const grpc_channel_filter grpc_client_census_filter = { - client_start_transport_op, - grpc_channel_next_op, - sizeof(call_data), - client_init_call_elem, - grpc_call_stack_ignore_set_pollset, - client_destroy_call_elem, - sizeof(channel_data), - init_channel_elem, - destroy_channel_elem, - grpc_call_next_get_peer, - "census-client"}; - -const grpc_channel_filter grpc_server_census_filter = { - server_start_transport_op, - grpc_channel_next_op, - sizeof(call_data), - server_init_call_elem, - grpc_call_stack_ignore_set_pollset, - server_destroy_call_elem, - sizeof(channel_data), - init_channel_elem, - destroy_channel_elem, - grpc_call_next_get_peer, - "census-server"}; diff --git a/src/core/census/grpc_filter.h b/src/core/census/grpc_filter.h deleted file mode 100644 index 4699e4d692..0000000000 --- a/src/core/census/grpc_filter.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * - * Copyright 2015-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_CENSUS_GRPC_FILTER_H -#define GRPC_CORE_CENSUS_GRPC_FILTER_H - -#include "src/core/channel/channel_stack.h" - -/* Census filters: provides tracing and stats collection functionalities. It - needs to reside right below the surface filter in the channel stack. */ -extern const grpc_channel_filter grpc_client_census_filter; -extern const grpc_channel_filter grpc_server_census_filter; - -#endif /* GRPC_CORE_CENSUS_GRPC_FILTER_H */ diff --git a/src/core/census/grpc_plugin.c b/src/core/census/grpc_plugin.c deleted file mode 100644 index 3ca9400f7e..0000000000 --- a/src/core/census/grpc_plugin.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * - * Copyright 2015-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/census/grpc_plugin.h" - -#include - -#include - -#include "src/core/census/grpc_filter.h" -#include "src/core/channel/channel_stack_builder.h" -#include "src/core/surface/channel_init.h" - -static bool maybe_add_census_filter(grpc_channel_stack_builder *builder, - void *arg_must_be_null) { - const grpc_channel_args *args = - grpc_channel_stack_builder_get_channel_arguments(builder); - if (grpc_channel_args_is_census_enabled(args)) { - return grpc_channel_stack_builder_prepend_filter( - builder, &grpc_client_census_filter, NULL, NULL); - } - return true; -} - -void census_grpc_plugin_init(void) { - /* Only initialize census if no one else has and some features are - * available. */ - if (census_enabled() == CENSUS_FEATURE_NONE && - census_supported() != CENSUS_FEATURE_NONE) { - if (census_initialize(census_supported())) { /* enable all features. */ - gpr_log(GPR_ERROR, "Could not initialize census."); - } - } - grpc_channel_init_register_stage(GRPC_CLIENT_CHANNEL, INT_MAX, - maybe_add_census_filter, NULL); - grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX, - maybe_add_census_filter, NULL); -} - -void census_grpc_plugin_destroy(void) { census_shutdown(); } diff --git a/src/core/census/grpc_plugin.h b/src/core/census/grpc_plugin.h deleted file mode 100644 index 9321c2c30f..0000000000 --- a/src/core/census/grpc_plugin.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * - * Copyright 2015-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_CENSUS_GRPC_PLUGIN_H -#define GRPC_CORE_CENSUS_GRPC_PLUGIN_H - -void census_grpc_plugin_init(void); -void census_grpc_plugin_destroy(void); - -#endif /* GRPC_CORE_CENSUS_GRPC_PLUGIN_H */ diff --git a/src/core/census/initialize.c b/src/core/census/initialize.c deleted file mode 100644 index ce7ec09b89..0000000000 --- a/src/core/census/initialize.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * - * Copyright 2015-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 - -static int features_enabled = CENSUS_FEATURE_NONE; - -int census_initialize(int features) { - if (features_enabled != CENSUS_FEATURE_NONE) { - // Must have been a previous call to census_initialize; return error - return 1; - } - features_enabled = features; - return 0; -} - -void census_shutdown(void) { features_enabled = CENSUS_FEATURE_NONE; } - -int census_supported(void) { - /* TODO(aveitch): improve this as we implement features... */ - return CENSUS_FEATURE_NONE; -} - -int census_enabled(void) { return features_enabled; } diff --git a/src/core/census/mlog.c b/src/core/census/mlog.c deleted file mode 100644 index a2cc46d3f2..0000000000 --- a/src/core/census/mlog.c +++ /dev/null @@ -1,600 +0,0 @@ -/* - * - * Copyright 2015-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. - * - */ - -// Implements an efficient in-memory log, optimized for multiple writers and -// a single reader. Available log space is divided up in blocks of -// CENSUS_LOG_2_MAX_RECORD_SIZE bytes. A block can be in one of the following -// three data structures: -// - Free blocks (free_block_list) -// - Blocks with unread data (dirty_block_list) -// - Blocks currently attached to cores (core_local_blocks[]) -// -// census_log_start_write() moves a block from core_local_blocks[] to the end of -// dirty_block_list when block: -// - is out-of-space OR -// - has an incomplete record (an incomplete record occurs when a thread calls -// census_log_start_write() and is context-switched before calling -// census_log_end_write() -// So, blocks in dirty_block_list are ordered, from oldest to newest, by the -// time when block is detached from the core. -// -// census_log_read_next() first iterates over dirty_block_list and then -// core_local_blocks[]. It moves completely read blocks from dirty_block_list -// to free_block_list. Blocks in core_local_blocks[] are not freed, even when -// completely read. -// -// If the log is configured to discard old records and free_block_list is empty, -// census_log_start_write() iterates over dirty_block_list to allocate a -// new block. It moves the oldest available block (no pending read/write) to -// core_local_blocks[]. -// -// core_local_block_struct is used to implement a map from core id to the block -// associated with that core. This mapping is advisory. It is possible that the -// block returned by this mapping is no longer associated with that core. This -// mapping is updated, lazily, by census_log_start_write(). -// -// Locking in block struct: -// -// Exclusive g_log.lock must be held before calling any functions operating on -// block structs except census_log_start_write() and census_log_end_write(). -// -// Writes to a block are serialized via writer_lock. census_log_start_write() -// acquires this lock and census_log_end_write() releases it. On failure to -// acquire the lock, writer allocates a new block for the current core and -// updates core_local_block accordingly. -// -// Simultaneous read and write access is allowed. Readers can safely read up to -// committed bytes (bytes_committed). -// -// reader_lock protects the block, currently being read, from getting recycled. -// start_read() acquires reader_lock and end_read() releases the lock. -// -// Read/write access to a block is disabled via try_disable_access(). It returns -// with both writer_lock and reader_lock held. These locks are subsequently -// released by enable_access() to enable access to the block. -// -// A note on naming: Most function/struct names are prepended by cl_ -// (shorthand for census_log). Further, functions that manipulate structures -// include the name of the structure, which will be passed as the first -// argument. E.g. cl_block_initialize() will initialize a cl_block. - -#include "src/core/census/mlog.h" -#include -#include -#include -#include -#include -#include -#include -#include - -// End of platform specific code - -typedef struct census_log_block_list_struct { - struct census_log_block_list_struct* next; - struct census_log_block_list_struct* prev; - struct census_log_block* block; -} cl_block_list_struct; - -typedef struct census_log_block { - // Pointer to underlying buffer. - char* buffer; - gpr_atm writer_lock; - gpr_atm reader_lock; - // Keeps completely written bytes. Declared atomic because accessed - // simultaneously by reader and writer. - gpr_atm bytes_committed; - // Bytes already read. - size_t bytes_read; - // Links for list. - cl_block_list_struct link; -// We want this structure to be cacheline aligned. We assume the following -// sizes for the various parts on 32/64bit systems: -// type 32b size 64b size -// char* 4 8 -// 3x gpr_atm 12 24 -// size_t 4 8 -// cl_block_list_struct 12 24 -// TOTAL 32 64 -// -// Depending on the size of our cacheline and the architecture, we -// selectively add char buffering to this structure. The size is checked -// via assert in census_log_initialize(). -#if defined(GPR_ARCH_64) -#define CL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 64) -#else -#if defined(GPR_ARCH_32) -#define CL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 32) -#else -#error "Unknown architecture" -#endif -#endif -#if CL_BLOCK_PAD_SIZE > 0 - char padding[CL_BLOCK_PAD_SIZE]; -#endif -} cl_block; - -// A list of cl_blocks, doubly-linked through cl_block::link. -typedef struct census_log_block_list { - int32_t count; // Number of items in list. - cl_block_list_struct ht; // head/tail of linked list. -} cl_block_list; - -// Cacheline aligned block pointers to avoid false sharing. Block pointer must -// be initialized via set_block(), before calling other functions -typedef struct census_log_core_local_block { - gpr_atm block; -// Ensure cachline alignment: we assume sizeof(gpr_atm) == 4 or 8 -#if defined(GPR_ARCH_64) -#define CL_CORE_LOCAL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 8) -#else -#if defined(GPR_ARCH_32) -#define CL_CORE_LOCAL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 4) -#else -#error "Unknown architecture" -#endif -#endif -#if CL_CORE_LOCAL_BLOCK_PAD_SIZE > 0 - char padding[CL_CORE_LOCAL_BLOCK_PAD_SIZE]; -#endif -} cl_core_local_block; - -struct census_log { - int discard_old_records; - // Number of cores (aka hardware-contexts) - unsigned num_cores; - // number of CENSUS_LOG_2_MAX_RECORD_SIZE blocks in log - uint32_t num_blocks; - cl_block* blocks; // Block metadata. - cl_core_local_block* core_local_blocks; // Keeps core to block mappings. - gpr_mu lock; - int initialized; // has log been initialized? - // Keeps the state of the reader iterator. A value of 0 indicates that - // iterator has reached the end. census_log_init_reader() resets the value - // to num_core to restart iteration. - uint32_t read_iterator_state; - // Points to the block being read. If non-NULL, the block is locked for - // reading(block_being_read_->reader_lock is held). - cl_block* block_being_read; - char* buffer; - cl_block_list free_block_list; - cl_block_list dirty_block_list; - gpr_atm out_of_space_count; -}; - -// Single internal log. -static struct census_log g_log; - -// Functions that operate on an atomic memory location used as a lock. - -// Returns non-zero if lock is acquired. -static int cl_try_lock(gpr_atm* lock) { return gpr_atm_acq_cas(lock, 0, 1); } - -static void cl_unlock(gpr_atm* lock) { gpr_atm_rel_store(lock, 0); } - -// Functions that operate on cl_core_local_block's. - -static void cl_core_local_block_set_block(cl_core_local_block* clb, - cl_block* block) { - gpr_atm_rel_store(&clb->block, (gpr_atm)block); -} - -static cl_block* cl_core_local_block_get_block(cl_core_local_block* clb) { - return (cl_block*)gpr_atm_acq_load(&clb->block); -} - -// Functions that operate on cl_block_list_struct's. - -static void cl_block_list_struct_initialize(cl_block_list_struct* bls, - cl_block* block) { - bls->next = bls->prev = bls; - bls->block = block; -} - -// Functions that operate on cl_block_list's. - -static void cl_block_list_initialize(cl_block_list* list) { - list->count = 0; - cl_block_list_struct_initialize(&list->ht, NULL); -} - -// Returns head of *this, or NULL if empty. -static cl_block* cl_block_list_head(cl_block_list* list) { - return list->ht.next->block; -} - -// Insert element *e after *pos. -static void cl_block_list_insert(cl_block_list* list, cl_block_list_struct* pos, - cl_block_list_struct* e) { - list->count++; - e->next = pos->next; - e->prev = pos; - e->next->prev = e; - e->prev->next = e; -} - -// Insert block at the head of the list -static void cl_block_list_insert_at_head(cl_block_list* list, cl_block* block) { - cl_block_list_insert(list, &list->ht, &block->link); -} - -// Insert block at the tail of the list. -static void cl_block_list_insert_at_tail(cl_block_list* list, cl_block* block) { - cl_block_list_insert(list, list->ht.prev, &block->link); -} - -// Removes block *b. Requires *b be in the list. -static void cl_block_list_remove(cl_block_list* list, cl_block* b) { - list->count--; - b->link.next->prev = b->link.prev; - b->link.prev->next = b->link.next; -} - -// Functions that operate on cl_block's - -static void cl_block_initialize(cl_block* block, char* buffer) { - block->buffer = buffer; - gpr_atm_rel_store(&block->writer_lock, 0); - gpr_atm_rel_store(&block->reader_lock, 0); - gpr_atm_rel_store(&block->bytes_committed, 0); - block->bytes_read = 0; - cl_block_list_struct_initialize(&block->link, block); -} - -// Guards against exposing partially written buffer to the reader. -static void cl_block_set_bytes_committed(cl_block* block, - size_t bytes_committed) { - gpr_atm_rel_store(&block->bytes_committed, (gpr_atm)bytes_committed); -} - -static size_t cl_block_get_bytes_committed(cl_block* block) { - return (size_t)gpr_atm_acq_load(&block->bytes_committed); -} - -// Tries to disable future read/write access to this block. Succeeds if: -// - no in-progress write AND -// - no in-progress read AND -// - 'discard_data' set to true OR no unread data -// On success, clears the block state and returns with writer_lock_ and -// reader_lock_ held. These locks are released by a subsequent -// cl_block_access_enable() call. -static bool cl_block_try_disable_access(cl_block* block, int discard_data) { - if (!cl_try_lock(&block->writer_lock)) { - return false; - } - if (!cl_try_lock(&block->reader_lock)) { - cl_unlock(&block->writer_lock); - return false; - } - if (!discard_data && - (block->bytes_read != cl_block_get_bytes_committed(block))) { - cl_unlock(&block->reader_lock); - cl_unlock(&block->writer_lock); - return false; - } - cl_block_set_bytes_committed(block, 0); - block->bytes_read = 0; - return true; -} - -static void cl_block_enable_access(cl_block* block) { - cl_unlock(&block->reader_lock); - cl_unlock(&block->writer_lock); -} - -// Returns with writer_lock held. -static void* cl_block_start_write(cl_block* block, size_t size) { - if (!cl_try_lock(&block->writer_lock)) { - return NULL; - } - size_t bytes_committed = cl_block_get_bytes_committed(block); - if (bytes_committed + size > CENSUS_LOG_MAX_RECORD_SIZE) { - cl_unlock(&block->writer_lock); - return NULL; - } - return block->buffer + bytes_committed; -} - -// Releases writer_lock and increments committed bytes by 'bytes_written'. -// 'bytes_written' must be <= 'size' specified in the corresponding -// StartWrite() call. This function is thread-safe. -static void cl_block_end_write(cl_block* block, size_t bytes_written) { - cl_block_set_bytes_committed( - block, cl_block_get_bytes_committed(block) + bytes_written); - cl_unlock(&block->writer_lock); -} - -// Returns a pointer to the first unread byte in buffer. The number of bytes -// available are returned in 'bytes_available'. Acquires reader lock that is -// released by a subsequent cl_block_end_read() call. Returns NULL if: -// - read in progress -// - no data available -static void* cl_block_start_read(cl_block* block, size_t* bytes_available) { - if (!cl_try_lock(&block->reader_lock)) { - return NULL; - } - // bytes_committed may change from under us. Use bytes_available to update - // bytes_read below. - size_t bytes_committed = cl_block_get_bytes_committed(block); - GPR_ASSERT(bytes_committed >= block->bytes_read); - *bytes_available = bytes_committed - block->bytes_read; - if (*bytes_available == 0) { - cl_unlock(&block->reader_lock); - return NULL; - } - void* record = block->buffer + block->bytes_read; - block->bytes_read += *bytes_available; - return record; -} - -static void cl_block_end_read(cl_block* block) { - cl_unlock(&block->reader_lock); -} - -// Internal functions operating on g_log - -// Allocates a new free block (or recycles an available dirty block if log is -// configured to discard old records). Returns NULL if out-of-space. -static cl_block* cl_allocate_block(void) { - cl_block* block = cl_block_list_head(&g_log.free_block_list); - if (block != NULL) { - cl_block_list_remove(&g_log.free_block_list, block); - return block; - } - if (!g_log.discard_old_records) { - // No free block and log is configured to keep old records. - return NULL; - } - // Recycle dirty block. Start from the oldest. - for (block = cl_block_list_head(&g_log.dirty_block_list); block != NULL; - block = block->link.next->block) { - if (cl_block_try_disable_access(block, 1 /* discard data */)) { - cl_block_list_remove(&g_log.dirty_block_list, block); - return block; - } - } - return NULL; -} - -// Allocates a new block and updates core id => block mapping. 'old_block' -// points to the block that the caller thinks is attached to -// 'core_id'. 'old_block' may be NULL. Returns true if: -// - allocated a new block OR -// - 'core_id' => 'old_block' mapping changed (another thread allocated a -// block before lock was acquired). -static bool cl_allocate_core_local_block(uint32_t core_id, - cl_block* old_block) { - // Now that we have the lock, check if core-local mapping has changed. - cl_core_local_block* core_local_block = &g_log.core_local_blocks[core_id]; - cl_block* block = cl_core_local_block_get_block(core_local_block); - if ((block != NULL) && (block != old_block)) { - return true; - } - if (block != NULL) { - cl_core_local_block_set_block(core_local_block, NULL); - cl_block_list_insert_at_tail(&g_log.dirty_block_list, block); - } - block = cl_allocate_block(); - if (block == NULL) { - return false; - } - cl_core_local_block_set_block(core_local_block, block); - cl_block_enable_access(block); - return true; -} - -static cl_block* cl_get_block(void* record) { - uintptr_t p = (uintptr_t)((char*)record - g_log.buffer); - uintptr_t index = p >> CENSUS_LOG_2_MAX_RECORD_SIZE; - return &g_log.blocks[index]; -} - -// Gets the next block to read and tries to free 'prev' block (if not NULL). -// Returns NULL if reached the end. -static cl_block* cl_next_block_to_read(cl_block* prev) { - cl_block* block = NULL; - if (g_log.read_iterator_state == g_log.num_cores) { - // We are traversing dirty list; find the next dirty block. - if (prev != NULL) { - // Try to free the previous block if there is no unread data. This - // block - // may have unread data if previously incomplete record completed - // between - // read_next() calls. - block = prev->link.next->block; - if (cl_block_try_disable_access(prev, 0 /* do not discard data */)) { - cl_block_list_remove(&g_log.dirty_block_list, prev); - cl_block_list_insert_at_head(&g_log.free_block_list, prev); - } - } else { - block = cl_block_list_head(&g_log.dirty_block_list); - } - if (block != NULL) { - return block; - } - // We are done with the dirty list; moving on to core-local blocks. - } - while (g_log.read_iterator_state > 0) { - g_log.read_iterator_state--; - block = cl_core_local_block_get_block( - &g_log.core_local_blocks[g_log.read_iterator_state]); - if (block != NULL) { - return block; - } - } - return NULL; -} - -#define CL_LOG_2_MB 20 // 2^20 = 1MB - -// External functions: primary stats_log interface -void census_log_initialize(size_t size_in_mb, int discard_old_records) { - // Check cacheline alignment. - GPR_ASSERT(sizeof(cl_block) % GPR_CACHELINE_SIZE == 0); - GPR_ASSERT(sizeof(cl_core_local_block) % GPR_CACHELINE_SIZE == 0); - GPR_ASSERT(!g_log.initialized); - g_log.discard_old_records = discard_old_records; - g_log.num_cores = gpr_cpu_num_cores(); - // Ensure that we will not get any overflow in calaculating num_blocks - GPR_ASSERT(CL_LOG_2_MB >= CENSUS_LOG_2_MAX_RECORD_SIZE); - GPR_ASSERT(size_in_mb < 1000); - // Ensure at least 2x as many blocks as there are cores. - g_log.num_blocks = - (uint32_t)GPR_MAX(2 * g_log.num_cores, (size_in_mb << CL_LOG_2_MB) >> - CENSUS_LOG_2_MAX_RECORD_SIZE); - gpr_mu_init(&g_log.lock); - g_log.read_iterator_state = 0; - g_log.block_being_read = NULL; - g_log.core_local_blocks = (cl_core_local_block*)gpr_malloc_aligned( - g_log.num_cores * sizeof(cl_core_local_block), GPR_CACHELINE_SIZE_LOG); - memset(g_log.core_local_blocks, 0, - g_log.num_cores * sizeof(cl_core_local_block)); - g_log.blocks = (cl_block*)gpr_malloc_aligned( - g_log.num_blocks * sizeof(cl_block), GPR_CACHELINE_SIZE_LOG); - memset(g_log.blocks, 0, g_log.num_blocks * sizeof(cl_block)); - g_log.buffer = gpr_malloc(g_log.num_blocks * CENSUS_LOG_MAX_RECORD_SIZE); - memset(g_log.buffer, 0, g_log.num_blocks * CENSUS_LOG_MAX_RECORD_SIZE); - cl_block_list_initialize(&g_log.free_block_list); - cl_block_list_initialize(&g_log.dirty_block_list); - for (uint32_t i = 0; i < g_log.num_blocks; ++i) { - cl_block* block = g_log.blocks + i; - cl_block_initialize(block, g_log.buffer + (CENSUS_LOG_MAX_RECORD_SIZE * i)); - cl_block_try_disable_access(block, 1 /* discard data */); - cl_block_list_insert_at_tail(&g_log.free_block_list, block); - } - gpr_atm_rel_store(&g_log.out_of_space_count, 0); - g_log.initialized = 1; -} - -void census_log_shutdown(void) { - GPR_ASSERT(g_log.initialized); - gpr_mu_destroy(&g_log.lock); - gpr_free_aligned(g_log.core_local_blocks); - g_log.core_local_blocks = NULL; - gpr_free_aligned(g_log.blocks); - g_log.blocks = NULL; - gpr_free(g_log.buffer); - g_log.buffer = NULL; - g_log.initialized = 0; -} - -void* census_log_start_write(size_t size) { - // Used to bound number of times block allocation is attempted. - GPR_ASSERT(size > 0); - GPR_ASSERT(g_log.initialized); - if (size > CENSUS_LOG_MAX_RECORD_SIZE) { - return NULL; - } - uint32_t attempts_remaining = g_log.num_blocks; - uint32_t core_id = gpr_cpu_current_cpu(); - do { - void* record = NULL; - cl_block* block = - cl_core_local_block_get_block(&g_log.core_local_blocks[core_id]); - if (block && (record = cl_block_start_write(block, size))) { - return record; - } - // Need to allocate a new block. We are here if: - // - No block associated with the core OR - // - Write in-progress on the block OR - // - block is out of space - gpr_mu_lock(&g_log.lock); - bool allocated = cl_allocate_core_local_block(core_id, block); - gpr_mu_unlock(&g_log.lock); - if (!allocated) { - gpr_atm_no_barrier_fetch_add(&g_log.out_of_space_count, 1); - return NULL; - } - } while (attempts_remaining--); - // Give up. - gpr_atm_no_barrier_fetch_add(&g_log.out_of_space_count, 1); - return NULL; -} - -void census_log_end_write(void* record, size_t bytes_written) { - GPR_ASSERT(g_log.initialized); - cl_block_end_write(cl_get_block(record), bytes_written); -} - -void census_log_init_reader(void) { - GPR_ASSERT(g_log.initialized); - gpr_mu_lock(&g_log.lock); - // If a block is locked for reading unlock it. - if (g_log.block_being_read != NULL) { - cl_block_end_read(g_log.block_being_read); - g_log.block_being_read = NULL; - } - g_log.read_iterator_state = g_log.num_cores; - gpr_mu_unlock(&g_log.lock); -} - -const void* census_log_read_next(size_t* bytes_available) { - GPR_ASSERT(g_log.initialized); - gpr_mu_lock(&g_log.lock); - if (g_log.block_being_read != NULL) { - cl_block_end_read(g_log.block_being_read); - } - do { - g_log.block_being_read = cl_next_block_to_read(g_log.block_being_read); - if (g_log.block_being_read != NULL) { - void* record = - cl_block_start_read(g_log.block_being_read, bytes_available); - if (record != NULL) { - gpr_mu_unlock(&g_log.lock); - return record; - } - } - } while (g_log.block_being_read != NULL); - gpr_mu_unlock(&g_log.lock); - return NULL; -} - -size_t census_log_remaining_space(void) { - GPR_ASSERT(g_log.initialized); - size_t space = 0; - gpr_mu_lock(&g_log.lock); - if (g_log.discard_old_records) { - // Remaining space is not meaningful; just return the entire log space. - space = g_log.num_blocks << CENSUS_LOG_2_MAX_RECORD_SIZE; - } else { - GPR_ASSERT(g_log.free_block_list.count >= 0); - space = (size_t)g_log.free_block_list.count * CENSUS_LOG_MAX_RECORD_SIZE; - } - gpr_mu_unlock(&g_log.lock); - return space; -} - -int64_t census_log_out_of_space_count(void) { - GPR_ASSERT(g_log.initialized); - return gpr_atm_acq_load(&g_log.out_of_space_count); -} diff --git a/src/core/census/mlog.h b/src/core/census/mlog.h deleted file mode 100644 index bc6eaeaf28..0000000000 --- a/src/core/census/mlog.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * - * Copyright 2015-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. - * - */ - -/* A very fast in-memory log, optimized for multiple writers. */ - -#ifndef GRPC_CORE_CENSUS_MLOG_H -#define GRPC_CORE_CENSUS_MLOG_H - -#include -#include - -/* Maximum record size, in bytes. */ -#define CENSUS_LOG_2_MAX_RECORD_SIZE 14 /* 2^14 = 16KB */ -#define CENSUS_LOG_MAX_RECORD_SIZE (1 << CENSUS_LOG_2_MAX_RECORD_SIZE) - -/* Initialize the statistics logging subsystem with the given log size. A log - size of 0 will result in the smallest possible log for the platform - (approximately CENSUS_LOG_MAX_RECORD_SIZE * gpr_cpu_num_cores()). If - discard_old_records is non-zero, then new records will displace older ones - when the log is full. This function must be called before any other - census_log functions. -*/ -void census_log_initialize(size_t size_in_mb, int discard_old_records); - -/* Shutdown the logging subsystem. Caller must ensure that: - - no in progress or future call to any census_log functions - - no incomplete records -*/ -void census_log_shutdown(void); - -/* Allocates and returns a 'size' bytes record and marks it in use. A - subsequent census_log_end_write() marks the record complete. The - 'bytes_written' census_log_end_write() argument must be <= - 'size'. Returns NULL if out-of-space AND: - - log is configured to keep old records OR - - all blocks are pinned by incomplete records. -*/ -void* census_log_start_write(size_t size); - -void census_log_end_write(void* record, size_t bytes_written); - -void census_log_init_reader(void); - -/* census_log_read_next() iterates over blocks with data and for each block - returns a pointer to the first unread byte. The number of bytes that can be - read are returned in 'bytes_available'. Reader is expected to read all - available data. Reading the data consumes it i.e. it cannot be read again. - census_log_read_next() returns NULL if the end is reached i.e last block - is read. census_log_init_reader() starts the iteration or aborts the - current iteration. -*/ -const void* census_log_read_next(size_t* bytes_available); - -/* Returns estimated remaining space across all blocks, in bytes. If log is - configured to discard old records, returns total log space. Otherwise, - returns space available in empty blocks (partially filled blocks are - treated as full). -*/ -size_t census_log_remaining_space(void); - -/* Returns the number of times gprc_stats_log_start_write() failed due to - out-of-space. */ -int64_t census_log_out_of_space_count(void); - -#endif /* GRPC_CORE_CENSUS_MLOG_H */ diff --git a/src/core/census/operation.c b/src/core/census/operation.c deleted file mode 100644 index 5c58704372..0000000000 --- a/src/core/census/operation.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include - -/* TODO(aveitch): These are all placeholder implementations. */ - -census_timestamp census_start_rpc_op_timestamp(void) { - census_timestamp ct; - /* TODO(aveitch): assumes gpr_timespec implementation of census_timestamp. */ - ct.ts = gpr_now(GPR_CLOCK_MONOTONIC); - return ct; -} - -census_context *census_start_client_rpc_op( - const census_context *context, int64_t rpc_name_id, - const census_rpc_name_info *rpc_name_info, const char *peer, int trace_mask, - const census_timestamp *start_time) { - return NULL; -} - -census_context *census_start_server_rpc_op( - const char *buffer, int64_t rpc_name_id, - const census_rpc_name_info *rpc_name_info, const char *peer, int trace_mask, - census_timestamp *start_time) { - return NULL; -} - -census_context *census_start_op(census_context *context, const char *family, - const char *name, int trace_mask) { - return NULL; -} - -void census_end_op(census_context *context, int status) {} diff --git a/src/core/census/placeholders.c b/src/core/census/placeholders.c deleted file mode 100644 index fe23d13971..0000000000 --- a/src/core/census/placeholders.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * - * 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 - -#include - -/* Placeholders for the pending APIs */ - -int census_get_trace_record(census_trace_record *trace_record) { - (void)trace_record; - abort(); -} - -void census_record_values(census_context *context, census_value *values, - size_t nvalues) { - (void)context; - (void)values; - (void)nvalues; - abort(); -} - -void census_set_rpc_client_peer(census_context *context, const char *peer) { - (void)context; - (void)peer; - abort(); -} - -void census_trace_scan_end() { abort(); } - -int census_trace_scan_start(int consume) { - (void)consume; - abort(); -} - -const census_aggregation *census_view_aggregrations(const census_view *view) { - (void)view; - abort(); -} - -census_view *census_view_create(uint32_t metric_id, const census_context *tags, - const census_aggregation *aggregations, - size_t naggregations) { - (void)metric_id; - (void)tags; - (void)aggregations; - (void)naggregations; - abort(); -} - -const census_context *census_view_tags(const census_view *view) { - (void)view; - abort(); -} - -void census_view_delete(census_view *view) { - (void)view; - abort(); -} - -const census_view_data *census_view_get_data(const census_view *view) { - (void)view; - abort(); -} - -size_t census_view_metric(const census_view *view) { - (void)view; - abort(); -} - -size_t census_view_naggregations(const census_view *view) { - (void)view; - abort(); -} - -void census_view_reset(census_view *view) { - (void)view; - abort(); -} diff --git a/src/core/census/rpc_metric_id.h b/src/core/census/rpc_metric_id.h deleted file mode 100644 index f8d8dad0bf..0000000000 --- a/src/core/census/rpc_metric_id.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * - * Copyright 2015-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_CENSUS_RPC_METRIC_ID_H -#define GRPC_CORE_CENSUS_RPC_METRIC_ID_H - -/* Metric ID's used for RPC measurements. */ -/* Count of client requests sent. */ -#define CENSUS_METRIC_RPC_CLIENT_REQUESTS ((uint32_t)0) -/* Count of server requests sent. */ -#define CENSUS_METRIC_RPC_SERVER_REQUESTS ((uint32_t)1) -/* Client error counts. */ -#define CENSUS_METRIC_RPC_CLIENT_ERRORS ((uint32_t)2) -/* Server error counts. */ -#define CENSUS_METRIC_RPC_SERVER_ERRORS ((uint32_t)3) -/* Client side request latency. */ -#define CENSUS_METRIC_RPC_CLIENT_LATENCY ((uint32_t)4) -/* Server side request latency. */ -#define CENSUS_METRIC_RPC_SERVER_LATENCY ((uint32_t)5) - -#endif /* GRPC_CORE_CENSUS_RPC_METRIC_ID_H */ diff --git a/src/core/census/tracing.c b/src/core/census/tracing.c deleted file mode 100644 index 3b5d6dab2b..0000000000 --- a/src/core/census/tracing.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include - -/* TODO(aveitch): These are all placeholder implementations. */ - -int census_trace_mask(const census_context *context) { - return CENSUS_TRACE_MASK_NONE; -} - -void census_set_trace_mask(int trace_mask) {} - -void census_trace_print(census_context *context, uint32_t type, - const char *buffer, size_t n) {} diff --git a/src/core/channel/channel_args.c b/src/core/channel/channel_args.c deleted file mode 100644 index e0382fa0d9..0000000000 --- a/src/core/channel/channel_args.c +++ /dev/null @@ -1,271 +0,0 @@ -/* - * - * Copyright 2015-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/channel/channel_args.h" -#include -#include "src/core/support/string.h" - -#include -#include -#include -#include -#include - -#include - -static grpc_arg copy_arg(const grpc_arg *src) { - grpc_arg dst; - dst.type = src->type; - dst.key = gpr_strdup(src->key); - switch (dst.type) { - case GRPC_ARG_STRING: - dst.value.string = gpr_strdup(src->value.string); - break; - case GRPC_ARG_INTEGER: - dst.value.integer = src->value.integer; - break; - case GRPC_ARG_POINTER: - dst.value.pointer = src->value.pointer; - dst.value.pointer.p = - src->value.pointer.vtable->copy(src->value.pointer.p); - break; - } - return dst; -} - -grpc_channel_args *grpc_channel_args_copy_and_add(const grpc_channel_args *src, - const grpc_arg *to_add, - size_t num_to_add) { - grpc_channel_args *dst = gpr_malloc(sizeof(grpc_channel_args)); - size_t i; - size_t src_num_args = (src == NULL) ? 0 : src->num_args; - if (!src && !to_add) { - dst->num_args = 0; - dst->args = NULL; - return dst; - } - dst->num_args = src_num_args + num_to_add; - dst->args = gpr_malloc(sizeof(grpc_arg) * dst->num_args); - for (i = 0; i < src_num_args; i++) { - dst->args[i] = copy_arg(&src->args[i]); - } - for (i = 0; i < num_to_add; i++) { - dst->args[i + src_num_args] = copy_arg(&to_add[i]); - } - return dst; -} - -grpc_channel_args *grpc_channel_args_copy(const grpc_channel_args *src) { - return grpc_channel_args_copy_and_add(src, NULL, 0); -} - -grpc_channel_args *grpc_channel_args_merge(const grpc_channel_args *a, - const grpc_channel_args *b) { - return grpc_channel_args_copy_and_add(a, b->args, b->num_args); -} - -static int cmp_arg(const grpc_arg *a, const grpc_arg *b) { - int c = GPR_ICMP(a->type, b->type); - if (c != 0) return c; - c = strcmp(a->key, b->key); - if (c != 0) return c; - switch (a->type) { - case GRPC_ARG_STRING: - return strcmp(a->value.string, b->value.string); - case GRPC_ARG_INTEGER: - return GPR_ICMP(a->value.integer, b->value.integer); - case GRPC_ARG_POINTER: - c = GPR_ICMP(a->value.pointer.p, b->value.pointer.p); - if (c != 0) { - c = GPR_ICMP(a->value.pointer.vtable, b->value.pointer.vtable); - if (c == 0) { - c = a->value.pointer.vtable->cmp(a->value.pointer.p, - b->value.pointer.p); - } - } - return c; - } - GPR_UNREACHABLE_CODE(return 0); -} - -/* stabilizing comparison function: since channel_args ordering matters for - * keys with the same name, we need to preserve that ordering */ -static int cmp_key_stable(const void *ap, const void *bp) { - const grpc_arg *const *a = ap; - const grpc_arg *const *b = bp; - int c = strcmp((*a)->key, (*b)->key); - if (c == 0) c = GPR_ICMP(*a, *b); - return c; -} - -grpc_channel_args *grpc_channel_args_normalize(const grpc_channel_args *a) { - grpc_arg **args = gpr_malloc(sizeof(grpc_arg *) * a->num_args); - for (size_t i = 0; i < a->num_args; i++) { - args[i] = &a->args[i]; - } - qsort(args, a->num_args, sizeof(grpc_arg *), cmp_key_stable); - - grpc_channel_args *b = gpr_malloc(sizeof(grpc_channel_args)); - b->num_args = a->num_args; - b->args = gpr_malloc(sizeof(grpc_arg) * b->num_args); - for (size_t i = 0; i < a->num_args; i++) { - b->args[i] = copy_arg(args[i]); - } - - gpr_free(args); - return b; -} - -void grpc_channel_args_destroy(grpc_channel_args *a) { - size_t i; - for (i = 0; i < a->num_args; i++) { - switch (a->args[i].type) { - case GRPC_ARG_STRING: - gpr_free(a->args[i].value.string); - break; - case GRPC_ARG_INTEGER: - break; - case GRPC_ARG_POINTER: - a->args[i].value.pointer.vtable->destroy(a->args[i].value.pointer.p); - break; - } - gpr_free(a->args[i].key); - } - gpr_free(a->args); - gpr_free(a); -} - -int grpc_channel_args_is_census_enabled(const grpc_channel_args *a) { - size_t i; - if (a == NULL) return 0; - for (i = 0; i < a->num_args; i++) { - if (0 == strcmp(a->args[i].key, GRPC_ARG_ENABLE_CENSUS)) { - return a->args[i].value.integer != 0 && census_enabled(); - } - } - return census_enabled(); -} - -grpc_compression_algorithm grpc_channel_args_get_compression_algorithm( - const grpc_channel_args *a) { - size_t i; - if (a == NULL) return 0; - for (i = 0; i < a->num_args; ++i) { - if (a->args[i].type == GRPC_ARG_INTEGER && - !strcmp(GRPC_COMPRESSION_ALGORITHM_ARG, a->args[i].key)) { - return (grpc_compression_algorithm)a->args[i].value.integer; - break; - } - } - return GRPC_COMPRESS_NONE; -} - -grpc_channel_args *grpc_channel_args_set_compression_algorithm( - grpc_channel_args *a, grpc_compression_algorithm algorithm) { - grpc_arg tmp; - tmp.type = GRPC_ARG_INTEGER; - tmp.key = GRPC_COMPRESSION_ALGORITHM_ARG; - tmp.value.integer = algorithm; - return grpc_channel_args_copy_and_add(a, &tmp, 1); -} - -/** Returns 1 if the argument for compression algorithm's enabled states bitset - * was found in \a a, returning the arg's value in \a states. Otherwise, returns - * 0. */ -static int find_compression_algorithm_states_bitset(const grpc_channel_args *a, - int **states_arg) { - if (a != NULL) { - size_t i; - for (i = 0; i < a->num_args; ++i) { - if (a->args[i].type == GRPC_ARG_INTEGER && - !strcmp(GRPC_COMPRESSION_ALGORITHM_STATE_ARG, a->args[i].key)) { - *states_arg = &a->args[i].value.integer; - return 1; /* GPR_TRUE */ - } - } - } - return 0; /* GPR_FALSE */ -} - -grpc_channel_args *grpc_channel_args_compression_algorithm_set_state( - grpc_channel_args **a, grpc_compression_algorithm algorithm, int state) { - int *states_arg; - grpc_channel_args *result = *a; - const int states_arg_found = - find_compression_algorithm_states_bitset(*a, &states_arg); - - if (states_arg_found) { - if (state != 0) { - GPR_BITSET((unsigned *)states_arg, algorithm); - } else { - GPR_BITCLEAR((unsigned *)states_arg, algorithm); - } - } else { - /* create a new arg */ - grpc_arg tmp; - tmp.type = GRPC_ARG_INTEGER; - tmp.key = GRPC_COMPRESSION_ALGORITHM_STATE_ARG; - /* all enabled by default */ - tmp.value.integer = (1u << GRPC_COMPRESS_ALGORITHMS_COUNT) - 1; - if (state != 0) { - GPR_BITSET((unsigned *)&tmp.value.integer, algorithm); - } else { - GPR_BITCLEAR((unsigned *)&tmp.value.integer, algorithm); - } - result = grpc_channel_args_copy_and_add(*a, &tmp, 1); - grpc_channel_args_destroy(*a); - *a = result; - } - return result; -} - -int grpc_channel_args_compression_algorithm_get_states( - const grpc_channel_args *a) { - int *states_arg; - if (find_compression_algorithm_states_bitset(a, &states_arg)) { - return *states_arg; - } else { - return (1u << GRPC_COMPRESS_ALGORITHMS_COUNT) - 1; /* All algs. enabled */ - } -} - -int grpc_channel_args_compare(const grpc_channel_args *a, - const grpc_channel_args *b) { - int c = GPR_ICMP(a->num_args, b->num_args); - if (c != 0) return c; - for (size_t i = 0; i < a->num_args; i++) { - c = cmp_arg(&a->args[i], &b->args[i]); - if (c != 0) return c; - } - return 0; -} diff --git a/src/core/channel/channel_args.h b/src/core/channel/channel_args.h deleted file mode 100644 index e19440f76f..0000000000 --- a/src/core/channel/channel_args.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * - * Copyright 2015-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_CHANNEL_CHANNEL_ARGS_H -#define GRPC_CORE_CHANNEL_CHANNEL_ARGS_H - -#include -#include - -/* Copy some arguments */ -grpc_channel_args *grpc_channel_args_copy(const grpc_channel_args *src); - -/* Copy some arguments, stably sorting keys */ -grpc_channel_args *grpc_channel_args_normalize(const grpc_channel_args *a); - -/** Copy some arguments and add the to_add parameter in the end. - If to_add is NULL, it is equivalent to call grpc_channel_args_copy. */ -grpc_channel_args *grpc_channel_args_copy_and_add(const grpc_channel_args *src, - const grpc_arg *to_add, - size_t num_to_add); - -/** Copy args from a then args from b into a new channel args */ -grpc_channel_args *grpc_channel_args_merge(const grpc_channel_args *a, - const grpc_channel_args *b); - -/** Destroy arguments created by grpc_channel_args_copy */ -void grpc_channel_args_destroy(grpc_channel_args *a); - -/** Reads census_enabled settings from channel args. Returns 1 if census_enabled - * is specified in channel args, otherwise returns 0. */ -int grpc_channel_args_is_census_enabled(const grpc_channel_args *a); - -/** Returns the compression algorithm set in \a a. */ -grpc_compression_algorithm grpc_channel_args_get_compression_algorithm( - const grpc_channel_args *a); - -/** Returns a channel arg instance with compression enabled. If \a a is - * non-NULL, its args are copied. N.B. GRPC_COMPRESS_NONE disables compression - * for the channel. */ -grpc_channel_args *grpc_channel_args_set_compression_algorithm( - grpc_channel_args *a, grpc_compression_algorithm algorithm); - -/** Sets the support for the given compression algorithm. By default, all - * compression algorithms are enabled. It's an error to disable an algorithm set - * by grpc_channel_args_set_compression_algorithm. - * - * Returns an instance with the updated algorithm states. The \a a pointer is - * modified to point to the returned instance (which may be different from the - * input value of \a a). */ -grpc_channel_args *grpc_channel_args_compression_algorithm_set_state( - grpc_channel_args **a, grpc_compression_algorithm algorithm, int enabled); - -/** Returns the bitset representing the support state (true for enabled, false - * for disabled) for compression algorithms. - * - * The i-th bit of the returned bitset corresponds to the i-th entry in the - * grpc_compression_algorithm enum. */ -int grpc_channel_args_compression_algorithm_get_states( - const grpc_channel_args *a); - -int grpc_channel_args_compare(const grpc_channel_args *a, - const grpc_channel_args *b); - -#endif /* GRPC_CORE_CHANNEL_CHANNEL_ARGS_H */ diff --git a/src/core/channel/channel_stack.c b/src/core/channel/channel_stack.c deleted file mode 100644 index 3e61688364..0000000000 --- a/src/core/channel/channel_stack.c +++ /dev/null @@ -1,262 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/channel/channel_stack.h" -#include - -#include -#include - -int grpc_trace_channel = 0; - -/* Memory layouts. - - Channel stack is laid out as: { - grpc_channel_stack stk; - padding to GPR_MAX_ALIGNMENT - grpc_channel_element[stk.count]; - per-filter memory, aligned to GPR_MAX_ALIGNMENT - } - - Call stack is laid out as: { - grpc_call_stack stk; - padding to GPR_MAX_ALIGNMENT - grpc_call_element[stk.count]; - per-filter memory, aligned to GPR_MAX_ALIGNMENT - } */ - -/* Given a size, round up to the next multiple of sizeof(void*) */ -#define ROUND_UP_TO_ALIGNMENT_SIZE(x) \ - (((x) + GPR_MAX_ALIGNMENT - 1u) & ~(GPR_MAX_ALIGNMENT - 1u)) - -size_t grpc_channel_stack_size(const grpc_channel_filter **filters, - size_t filter_count) { - /* always need the header, and size for the channel elements */ - size_t size = - ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_channel_stack)) + - ROUND_UP_TO_ALIGNMENT_SIZE(filter_count * sizeof(grpc_channel_element)); - size_t i; - - GPR_ASSERT((GPR_MAX_ALIGNMENT & (GPR_MAX_ALIGNMENT - 1)) == 0 && - "GPR_MAX_ALIGNMENT must be a power of two"); - - /* add the size for each filter */ - for (i = 0; i < filter_count; i++) { - size += ROUND_UP_TO_ALIGNMENT_SIZE(filters[i]->sizeof_channel_data); - } - - return size; -} - -#define CHANNEL_ELEMS_FROM_STACK(stk) \ - ((grpc_channel_element *)((char *)(stk) + ROUND_UP_TO_ALIGNMENT_SIZE( \ - sizeof(grpc_channel_stack)))) - -#define CALL_ELEMS_FROM_STACK(stk) \ - ((grpc_call_element *)((char *)(stk) + \ - ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call_stack)))) - -grpc_channel_element *grpc_channel_stack_element( - grpc_channel_stack *channel_stack, size_t index) { - return CHANNEL_ELEMS_FROM_STACK(channel_stack) + index; -} - -grpc_channel_element *grpc_channel_stack_last_element( - grpc_channel_stack *channel_stack) { - return grpc_channel_stack_element(channel_stack, channel_stack->count - 1); -} - -grpc_call_element *grpc_call_stack_element(grpc_call_stack *call_stack, - size_t index) { - return CALL_ELEMS_FROM_STACK(call_stack) + index; -} - -void grpc_channel_stack_init(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 *channel_args, - const char *name, grpc_channel_stack *stack) { - size_t call_size = - ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call_stack)) + - ROUND_UP_TO_ALIGNMENT_SIZE(filter_count * sizeof(grpc_call_element)); - grpc_channel_element *elems; - grpc_channel_element_args args; - char *user_data; - size_t i; - - stack->count = filter_count; - GRPC_STREAM_REF_INIT(&stack->refcount, initial_refs, destroy, destroy_arg, - name); - elems = CHANNEL_ELEMS_FROM_STACK(stack); - user_data = - ((char *)elems) + - ROUND_UP_TO_ALIGNMENT_SIZE(filter_count * sizeof(grpc_channel_element)); - - /* init per-filter data */ - for (i = 0; i < filter_count; i++) { - args.channel_stack = stack; - args.channel_args = channel_args; - args.is_first = i == 0; - args.is_last = i == (filter_count - 1); - elems[i].filter = filters[i]; - elems[i].channel_data = user_data; - elems[i].filter->init_channel_elem(exec_ctx, &elems[i], &args); - user_data += ROUND_UP_TO_ALIGNMENT_SIZE(filters[i]->sizeof_channel_data); - call_size += ROUND_UP_TO_ALIGNMENT_SIZE(filters[i]->sizeof_call_data); - } - - GPR_ASSERT(user_data > (char *)stack); - GPR_ASSERT((uintptr_t)(user_data - (char *)stack) == - grpc_channel_stack_size(filters, filter_count)); - - stack->call_stack_size = call_size; -} - -void grpc_channel_stack_destroy(grpc_exec_ctx *exec_ctx, - grpc_channel_stack *stack) { - grpc_channel_element *channel_elems = CHANNEL_ELEMS_FROM_STACK(stack); - size_t count = stack->count; - size_t i; - - /* destroy per-filter data */ - for (i = 0; i < count; i++) { - channel_elems[i].filter->destroy_channel_elem(exec_ctx, &channel_elems[i]); - } -} - -void grpc_call_stack_init(grpc_exec_ctx *exec_ctx, - grpc_channel_stack *channel_stack, int initial_refs, - grpc_iomgr_cb_func destroy, void *destroy_arg, - grpc_call_context_element *context, - const void *transport_server_data, - grpc_call_stack *call_stack) { - grpc_channel_element *channel_elems = CHANNEL_ELEMS_FROM_STACK(channel_stack); - grpc_call_element_args args; - size_t count = channel_stack->count; - grpc_call_element *call_elems; - char *user_data; - size_t i; - - call_stack->count = count; - GRPC_STREAM_REF_INIT(&call_stack->refcount, initial_refs, destroy, - destroy_arg, "CALL_STACK"); - call_elems = CALL_ELEMS_FROM_STACK(call_stack); - user_data = ((char *)call_elems) + - ROUND_UP_TO_ALIGNMENT_SIZE(count * sizeof(grpc_call_element)); - - /* init per-filter data */ - for (i = 0; i < count; i++) { - args.call_stack = call_stack; - args.server_transport_data = transport_server_data; - args.context = context; - call_elems[i].filter = channel_elems[i].filter; - call_elems[i].channel_data = channel_elems[i].channel_data; - call_elems[i].call_data = user_data; - call_elems[i].filter->init_call_elem(exec_ctx, &call_elems[i], &args); - user_data += - ROUND_UP_TO_ALIGNMENT_SIZE(call_elems[i].filter->sizeof_call_data); - } -} - -void grpc_call_stack_set_pollset(grpc_exec_ctx *exec_ctx, - grpc_call_stack *call_stack, - grpc_pollset *pollset) { - size_t count = call_stack->count; - grpc_call_element *call_elems; - char *user_data; - size_t i; - - call_elems = CALL_ELEMS_FROM_STACK(call_stack); - user_data = ((char *)call_elems) + - ROUND_UP_TO_ALIGNMENT_SIZE(count * sizeof(grpc_call_element)); - - /* init per-filter data */ - for (i = 0; i < count; i++) { - call_elems[i].filter->set_pollset(exec_ctx, &call_elems[i], pollset); - user_data += - ROUND_UP_TO_ALIGNMENT_SIZE(call_elems[i].filter->sizeof_call_data); - } -} - -void grpc_call_stack_ignore_set_pollset(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_pollset *pollset) {} - -void grpc_call_stack_destroy(grpc_exec_ctx *exec_ctx, grpc_call_stack *stack) { - grpc_call_element *elems = CALL_ELEMS_FROM_STACK(stack); - size_t count = stack->count; - size_t i; - - /* destroy per-filter data */ - for (i = 0; i < count; i++) { - elems[i].filter->destroy_call_elem(exec_ctx, &elems[i]); - } -} - -void grpc_call_next_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_transport_stream_op *op) { - grpc_call_element *next_elem = elem + 1; - next_elem->filter->start_transport_stream_op(exec_ctx, next_elem, op); -} - -char *grpc_call_next_get_peer(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem) { - grpc_call_element *next_elem = elem + 1; - return next_elem->filter->get_peer(exec_ctx, next_elem); -} - -void grpc_channel_next_op(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, - grpc_transport_op *op) { - grpc_channel_element *next_elem = elem + 1; - next_elem->filter->start_transport_op(exec_ctx, next_elem, op); -} - -grpc_channel_stack *grpc_channel_stack_from_top_element( - grpc_channel_element *elem) { - return (grpc_channel_stack *)((char *)(elem)-ROUND_UP_TO_ALIGNMENT_SIZE( - sizeof(grpc_channel_stack))); -} - -grpc_call_stack *grpc_call_stack_from_top_element(grpc_call_element *elem) { - return (grpc_call_stack *)((char *)(elem)-ROUND_UP_TO_ALIGNMENT_SIZE( - sizeof(grpc_call_stack))); -} - -void grpc_call_element_send_cancel(grpc_exec_ctx *exec_ctx, - grpc_call_element *cur_elem) { - grpc_transport_stream_op op; - memset(&op, 0, sizeof(op)); - op.cancel_with_status = GRPC_STATUS_CANCELLED; - grpc_call_next_op(exec_ctx, cur_elem, &op); -} diff --git a/src/core/channel/channel_stack.h b/src/core/channel/channel_stack.h deleted file mode 100644 index 52362f0b20..0000000000 --- a/src/core/channel/channel_stack.h +++ /dev/null @@ -1,260 +0,0 @@ -/* - * - * Copyright 2015-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_CHANNEL_CHANNEL_STACK_H -#define GRPC_CORE_CHANNEL_CHANNEL_STACK_H - -/* A channel filter defines how operations on a channel are implemented. - Channel filters are chained together to create full channels, and if those - chains are linear, then channel stacks provide a mechanism to minimize - allocations for that chain. - Call stacks are created by channel stacks and represent the per-call data - for that stack. */ - -#include - -#include -#include -#include "src/core/debug/trace.h" -#include "src/core/transport/transport.h" - -typedef struct grpc_channel_element grpc_channel_element; -typedef struct grpc_call_element grpc_call_element; - -typedef struct grpc_channel_stack grpc_channel_stack; -typedef struct grpc_call_stack grpc_call_stack; - -typedef struct { - grpc_channel_stack *channel_stack; - const grpc_channel_args *channel_args; - int is_first; - int is_last; -} grpc_channel_element_args; - -typedef struct { - grpc_call_stack *call_stack; - const void *server_transport_data; - grpc_call_context_element *context; -} grpc_call_element_args; - -/* Channel filters specify: - 1. the amount of memory needed in the channel & call (via the sizeof_XXX - members) - 2. functions to initialize and destroy channel & call data - (init_XXX, destroy_XXX) - 3. functions to implement call operations and channel operations (call_op, - channel_op) - 4. a name, which is useful when debugging - - Members are laid out in approximate frequency of use order. */ -typedef struct { - /* Called to eg. send/receive data on a call. - See grpc_call_next_op on how to call the next element in the stack */ - void (*start_transport_stream_op)(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_transport_stream_op *op); - /* Called to handle channel level operations - e.g. new calls, or transport - closure. - See grpc_channel_next_op on how to call the next element in the stack */ - void (*start_transport_op)(grpc_exec_ctx *exec_ctx, - grpc_channel_element *elem, grpc_transport_op *op); - - /* sizeof(per call data) */ - size_t sizeof_call_data; - /* Initialize per call data. - elem is initialized at the start of the call, and elem->call_data is what - needs initializing. - The filter does not need to do any chaining. - server_transport_data is an opaque pointer. If it is NULL, this call is - on a client; if it is non-NULL, then it points to memory owned by the - transport and is on the server. Most filters want to ignore this - argument. */ - void (*init_call_elem)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_call_element_args *args); - void (*set_pollset)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_pollset *pollset); - /* Destroy per call data. - The filter does not need to do any chaining */ - void (*destroy_call_elem)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem); - - /* sizeof(per channel data) */ - size_t sizeof_channel_data; - /* Initialize per-channel data. - elem is initialized at the start of the call, and elem->channel_data is - what needs initializing. - is_first, is_last designate this elements position in the stack, and are - useful for asserting correct configuration by upper layer code. - The filter does not need to do any chaining */ - void (*init_channel_elem)(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, - grpc_channel_element_args *args); - /* Destroy per channel data. - The filter does not need to do any chaining */ - void (*destroy_channel_elem)(grpc_exec_ctx *exec_ctx, - grpc_channel_element *elem); - - /* Implement grpc_call_get_peer() */ - char *(*get_peer)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem); - - /* The name of this filter */ - const char *name; -} grpc_channel_filter; - -/* A channel_element tracks its filter and the filter requested memory within - a channel allocation */ -struct grpc_channel_element { - const grpc_channel_filter *filter; - void *channel_data; -}; - -/* A call_element tracks its filter, the filter requested memory within - a channel allocation, and the filter requested memory within a call - allocation */ -struct grpc_call_element { - const grpc_channel_filter *filter; - void *channel_data; - void *call_data; -}; - -/* A channel stack tracks a set of related filters for one channel, and - guarantees they live within a single malloc() allocation */ -struct grpc_channel_stack { - grpc_stream_refcount refcount; - size_t count; - /* Memory required for a call stack (computed at channel stack - initialization) */ - size_t call_stack_size; -}; - -/* A call stack tracks a set of related filters for one call, and guarantees - they live within a single malloc() allocation */ -struct grpc_call_stack { - /* shared refcount for this channel stack. - MUST be the first element: the underlying code calls destroy - with the address of the refcount, but higher layers prefer to think - about the address of the call stack itself. */ - grpc_stream_refcount refcount; - size_t count; -}; - -/* Get a channel element given a channel stack and its index */ -grpc_channel_element *grpc_channel_stack_element(grpc_channel_stack *stack, - size_t i); -/* Get the last channel element in a channel stack */ -grpc_channel_element *grpc_channel_stack_last_element( - grpc_channel_stack *stack); -/* Get a call stack element given a call stack and an index */ -grpc_call_element *grpc_call_stack_element(grpc_call_stack *stack, size_t i); - -/* Determine memory required for a channel stack containing a set of filters */ -size_t grpc_channel_stack_size(const grpc_channel_filter **filters, - size_t filter_count); -/* Initialize a channel stack given some filters */ -void grpc_channel_stack_init(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, - const char *name, grpc_channel_stack *stack); -/* Destroy a channel stack */ -void grpc_channel_stack_destroy(grpc_exec_ctx *exec_ctx, - grpc_channel_stack *stack); - -/* Initialize a call stack given a channel stack. transport_server_data is - expected to be NULL on a client, or an opaque transport owned pointer on the - server. */ -void grpc_call_stack_init(grpc_exec_ctx *exec_ctx, - grpc_channel_stack *channel_stack, int initial_refs, - grpc_iomgr_cb_func destroy, void *destroy_arg, - grpc_call_context_element *context, - const void *transport_server_data, - grpc_call_stack *call_stack); -/* Set a pollset for a call stack: must occur before the first op is started */ -void grpc_call_stack_set_pollset(grpc_exec_ctx *exec_ctx, - grpc_call_stack *call_stack, - grpc_pollset *pollset); - -#ifdef GRPC_STREAM_REFCOUNT_DEBUG -#define GRPC_CALL_STACK_REF(call_stack, reason) \ - grpc_stream_ref(&(call_stack)->refcount, reason) -#define GRPC_CALL_STACK_UNREF(exec_ctx, call_stack, reason) \ - grpc_stream_unref(exec_ctx, &(call_stack)->refcount, reason) -#define GRPC_CHANNEL_STACK_REF(channel_stack, reason) \ - grpc_stream_ref(&(channel_stack)->refcount, reason) -#define GRPC_CHANNEL_STACK_UNREF(exec_ctx, channel_stack, reason) \ - grpc_stream_unref(exec_ctx, &(channel_stack)->refcount, reason) -#else -#define GRPC_CALL_STACK_REF(call_stack, reason) \ - grpc_stream_ref(&(call_stack)->refcount) -#define GRPC_CALL_STACK_UNREF(exec_ctx, call_stack, reason) \ - grpc_stream_unref(exec_ctx, &(call_stack)->refcount) -#define GRPC_CHANNEL_STACK_REF(channel_stack, reason) \ - grpc_stream_ref(&(channel_stack)->refcount) -#define GRPC_CHANNEL_STACK_UNREF(exec_ctx, channel_stack, reason) \ - grpc_stream_unref(exec_ctx, &(channel_stack)->refcount) -#endif - -/* Destroy a call stack */ -void grpc_call_stack_destroy(grpc_exec_ctx *exec_ctx, grpc_call_stack *stack); - -/* Ignore set pollset - used by filters to implement the set_pollset method - if they don't care about pollsets at all. Does nothing. */ -void grpc_call_stack_ignore_set_pollset(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_pollset *pollset); -/* Call the next operation in a call stack */ -void grpc_call_next_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_transport_stream_op *op); -/* Call the next operation (depending on call directionality) in a channel - stack */ -void grpc_channel_next_op(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, - grpc_transport_op *op); -/* Pass through a request to get_peer to the next child element */ -char *grpc_call_next_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem); - -/* Given the top element of a channel stack, get the channel stack itself */ -grpc_channel_stack *grpc_channel_stack_from_top_element( - grpc_channel_element *elem); -/* Given the top element of a call stack, get the call stack itself */ -grpc_call_stack *grpc_call_stack_from_top_element(grpc_call_element *elem); - -void grpc_call_log_op(char *file, int line, gpr_log_severity severity, - grpc_call_element *elem, grpc_transport_stream_op *op); - -void grpc_call_element_send_cancel(grpc_exec_ctx *exec_ctx, - grpc_call_element *cur_elem); - -extern int grpc_trace_channel; - -#define GRPC_CALL_LOG_OP(sev, elem, op) \ - if (grpc_trace_channel) grpc_call_log_op(sev, elem, op) - -#endif /* GRPC_CORE_CHANNEL_CHANNEL_STACK_H */ diff --git a/src/core/channel/channel_stack_builder.c b/src/core/channel/channel_stack_builder.c deleted file mode 100644 index 1b1004e5f9..0000000000 --- a/src/core/channel/channel_stack_builder.c +++ /dev/null @@ -1,258 +0,0 @@ -/* - * - * 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/channel/channel_stack_builder.h" - -#include - -#include - -int grpc_trace_channel_stack_builder = 0; - -typedef struct filter_node { - struct filter_node *next; - struct filter_node *prev; - const grpc_channel_filter *filter; - grpc_post_filter_create_init_func init; - void *init_arg; -} filter_node; - -struct grpc_channel_stack_builder { - // sentinel nodes for filters that have been added - filter_node begin; - filter_node end; - // various set/get-able parameters - const grpc_channel_args *args; - grpc_transport *transport; - const char *name; -}; - -struct grpc_channel_stack_builder_iterator { - grpc_channel_stack_builder *builder; - filter_node *node; -}; - -grpc_channel_stack_builder *grpc_channel_stack_builder_create(void) { - grpc_channel_stack_builder *b = gpr_malloc(sizeof(*b)); - memset(b, 0, sizeof(*b)); - - b->begin.filter = NULL; - b->end.filter = NULL; - b->begin.next = &b->end; - b->begin.prev = &b->end; - b->end.next = &b->begin; - b->end.prev = &b->begin; - - return b; -} - -static grpc_channel_stack_builder_iterator *create_iterator_at_filter_node( - grpc_channel_stack_builder *builder, filter_node *node) { - grpc_channel_stack_builder_iterator *it = gpr_malloc(sizeof(*it)); - it->builder = builder; - it->node = node; - return it; -} - -void grpc_channel_stack_builder_iterator_destroy( - grpc_channel_stack_builder_iterator *it) { - gpr_free(it); -} - -grpc_channel_stack_builder_iterator * -grpc_channel_stack_builder_create_iterator_at_first( - grpc_channel_stack_builder *builder) { - return create_iterator_at_filter_node(builder, &builder->begin); -} - -grpc_channel_stack_builder_iterator * -grpc_channel_stack_builder_create_iterator_at_last( - grpc_channel_stack_builder *builder) { - return create_iterator_at_filter_node(builder, &builder->end); -} - -bool grpc_channel_stack_builder_move_next( - grpc_channel_stack_builder_iterator *iterator) { - if (iterator->node == &iterator->builder->end) return false; - iterator->node = iterator->node->next; - return true; -} - -bool grpc_channel_stack_builder_move_prev( - grpc_channel_stack_builder_iterator *iterator) { - if (iterator->node == &iterator->builder->begin) return false; - iterator->node = iterator->node->prev; - return true; -} - -bool grpc_channel_stack_builder_move_prev( - grpc_channel_stack_builder_iterator *iterator); - -void grpc_channel_stack_builder_set_name(grpc_channel_stack_builder *builder, - const char *name) { - GPR_ASSERT(builder->name == NULL); - builder->name = name; -} - -void grpc_channel_stack_builder_set_channel_arguments( - grpc_channel_stack_builder *builder, const grpc_channel_args *args) { - GPR_ASSERT(builder->args == NULL); - builder->args = args; -} - -void grpc_channel_stack_builder_set_transport( - grpc_channel_stack_builder *builder, grpc_transport *transport) { - GPR_ASSERT(builder->transport == NULL); - builder->transport = transport; -} - -grpc_transport *grpc_channel_stack_builder_get_transport( - grpc_channel_stack_builder *builder) { - return builder->transport; -} - -const grpc_channel_args *grpc_channel_stack_builder_get_channel_arguments( - grpc_channel_stack_builder *builder) { - return builder->args; -} - -bool grpc_channel_stack_builder_append_filter( - grpc_channel_stack_builder *builder, const grpc_channel_filter *filter, - grpc_post_filter_create_init_func post_init_func, void *user_data) { - grpc_channel_stack_builder_iterator *it = - grpc_channel_stack_builder_create_iterator_at_last(builder); - bool ok = grpc_channel_stack_builder_add_filter_before( - it, filter, post_init_func, user_data); - grpc_channel_stack_builder_iterator_destroy(it); - return ok; -} - -bool grpc_channel_stack_builder_prepend_filter( - grpc_channel_stack_builder *builder, const grpc_channel_filter *filter, - grpc_post_filter_create_init_func post_init_func, void *user_data) { - grpc_channel_stack_builder_iterator *it = - grpc_channel_stack_builder_create_iterator_at_first(builder); - bool ok = grpc_channel_stack_builder_add_filter_after( - it, filter, post_init_func, user_data); - grpc_channel_stack_builder_iterator_destroy(it); - return ok; -} - -static void add_after(filter_node *before, const grpc_channel_filter *filter, - grpc_post_filter_create_init_func post_init_func, - void *user_data) { - filter_node *new = gpr_malloc(sizeof(*new)); - new->next = before->next; - new->prev = before; - new->next->prev = new->prev->next = new; - new->filter = filter; - new->init = post_init_func; - new->init_arg = user_data; -} - -bool grpc_channel_stack_builder_add_filter_before( - grpc_channel_stack_builder_iterator *iterator, - const grpc_channel_filter *filter, - grpc_post_filter_create_init_func post_init_func, void *user_data) { - if (iterator->node == &iterator->builder->begin) return false; - add_after(iterator->node->prev, filter, post_init_func, user_data); - return true; -} - -bool grpc_channel_stack_builder_add_filter_after( - grpc_channel_stack_builder_iterator *iterator, - const grpc_channel_filter *filter, - grpc_post_filter_create_init_func post_init_func, void *user_data) { - if (iterator->node == &iterator->builder->end) return false; - add_after(iterator->node, filter, post_init_func, user_data); - return true; -} - -void grpc_channel_stack_builder_destroy(grpc_channel_stack_builder *builder) { - filter_node *p = builder->begin.next; - while (p != &builder->end) { - filter_node *next = p->next; - gpr_free(p); - p = next; - } - gpr_free(builder); -} - -void *grpc_channel_stack_builder_finish(grpc_exec_ctx *exec_ctx, - grpc_channel_stack_builder *builder, - size_t prefix_bytes, int initial_refs, - grpc_iomgr_cb_func destroy, - void *destroy_arg) { - // count the number of filters - size_t num_filters = 0; - for (filter_node *p = builder->begin.next; p != &builder->end; p = p->next) { - num_filters++; - } - - // create an array of filters - const grpc_channel_filter **filters = - gpr_malloc(sizeof(*filters) * num_filters); - size_t i = 0; - for (filter_node *p = builder->begin.next; p != &builder->end; p = p->next) { - filters[i++] = p->filter; - } - - // calculate the size of the channel stack - size_t channel_stack_size = grpc_channel_stack_size(filters, num_filters); - - // allocate memory, with prefix_bytes followed by channel_stack_size - char *result = gpr_malloc(prefix_bytes + channel_stack_size); - // fetch a pointer to the channel stack - grpc_channel_stack *channel_stack = - (grpc_channel_stack *)(result + prefix_bytes); - // 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); - - // run post-initialization functions - i = 0; - for (filter_node *p = builder->begin.next; p != &builder->end; p = p->next) { - if (p->init != NULL) { - p->init(channel_stack, grpc_channel_stack_element(channel_stack, i), - p->init_arg); - } - i++; - } - - grpc_channel_stack_builder_destroy(builder); - gpr_free((grpc_channel_filter **)filters); - - return result; -} diff --git a/src/core/channel/channel_stack_builder.h b/src/core/channel/channel_stack_builder.h deleted file mode 100644 index 15f395e8b8..0000000000 --- a/src/core/channel/channel_stack_builder.h +++ /dev/null @@ -1,155 +0,0 @@ -/* - * - * 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_CHANNEL_CHANNEL_STACK_BUILDER_H -#define GRPC_CORE_CHANNEL_CHANNEL_STACK_BUILDER_H - -#include - -#include "src/core/channel/channel_args.h" -#include "src/core/channel/channel_stack.h" - -/// grpc_channel_stack_builder offers a programmatic interface to selected -/// and order channel filters -typedef struct grpc_channel_stack_builder grpc_channel_stack_builder; -typedef struct grpc_channel_stack_builder_iterator - grpc_channel_stack_builder_iterator; - -/// Create a new channel stack builder -grpc_channel_stack_builder *grpc_channel_stack_builder_create(void); - -/// Assign a name to the channel stack: \a name must be statically allocated -void grpc_channel_stack_builder_set_name(grpc_channel_stack_builder *builder, - const char *name); - -/// Attach \a transport to the builder (does not take ownership) -void grpc_channel_stack_builder_set_transport( - grpc_channel_stack_builder *builder, grpc_transport *transport); - -/// Fetch attached transport -grpc_transport *grpc_channel_stack_builder_get_transport( - grpc_channel_stack_builder *builder); - -/// Set channel arguments: \a args must continue to exist until after -/// grpc_channel_stack_builder_finish returns -void grpc_channel_stack_builder_set_channel_arguments( - grpc_channel_stack_builder *builder, const grpc_channel_args *args); - -/// Return a borrowed pointer to the channel arguments -const grpc_channel_args *grpc_channel_stack_builder_get_channel_arguments( - grpc_channel_stack_builder *builder); - -/// Begin iterating over already defined filters in the builder at the beginning -grpc_channel_stack_builder_iterator * -grpc_channel_stack_builder_create_iterator_at_first( - grpc_channel_stack_builder *builder); - -/// Begin iterating over already defined filters in the builder at the end -grpc_channel_stack_builder_iterator * -grpc_channel_stack_builder_create_iterator_at_last( - grpc_channel_stack_builder *builder); - -/// Is an iterator at the first element? -bool grpc_channel_stack_builder_iterator_is_first( - grpc_channel_stack_builder_iterator *iterator); - -/// Is an iterator at the end? -bool grpc_channel_stack_builder_iterator_is_end( - grpc_channel_stack_builder_iterator *iterator); - -/// Move an iterator to the next item -bool grpc_channel_stack_builder_move_next( - grpc_channel_stack_builder_iterator *iterator); - -/// Move an iterator to the previous item -bool grpc_channel_stack_builder_move_prev( - grpc_channel_stack_builder_iterator *iterator); - -typedef void (*grpc_post_filter_create_init_func)( - grpc_channel_stack *channel_stack, grpc_channel_element *elem, void *arg); - -/// Add \a filter to the stack, after \a iterator. -/// Call \a post_init_func(..., \a user_data) once the channel stack is -/// created. -bool grpc_channel_stack_builder_add_filter_after( - grpc_channel_stack_builder_iterator *iterator, - const grpc_channel_filter *filter, - grpc_post_filter_create_init_func post_init_func, - void *user_data) GRPC_MUST_USE_RESULT; - -/// Add \a filter to the stack, before \a iterator. -/// Call \a post_init_func(..., \a user_data) once the channel stack is -/// created. -bool grpc_channel_stack_builder_add_filter_before( - grpc_channel_stack_builder_iterator *iterator, - const grpc_channel_filter *filter, - grpc_post_filter_create_init_func post_init_func, - void *user_data) GRPC_MUST_USE_RESULT; - -/// Add \a filter to the beginning of the filter list. -/// Call \a post_init_func(..., \a user_data) once the channel stack is -/// created. -bool grpc_channel_stack_builder_prepend_filter( - grpc_channel_stack_builder *builder, const grpc_channel_filter *filter, - grpc_post_filter_create_init_func post_init_func, - void *user_data) GRPC_MUST_USE_RESULT; - -/// Add \a filter to the end of the filter list. -/// Call \a post_init_func(..., \a user_data) once the channel stack is -/// created. -bool grpc_channel_stack_builder_append_filter( - grpc_channel_stack_builder *builder, const grpc_channel_filter *filter, - grpc_post_filter_create_init_func post_init_func, - void *user_data) GRPC_MUST_USE_RESULT; - -/// Terminate iteration and destroy \a iterator -void grpc_channel_stack_builder_iterator_destroy( - grpc_channel_stack_builder_iterator *iterator); - -/// Destroy the builder, return the freshly minted channel stack -/// Allocates \a prefix_bytes bytes before the channel stack -/// Returns the base pointer of the allocated block -/// \a initial_refs, \a destroy, \a destroy_arg are as per -/// grpc_channel_stack_init -void *grpc_channel_stack_builder_finish(grpc_exec_ctx *exec_ctx, - grpc_channel_stack_builder *builder, - size_t prefix_bytes, int initial_refs, - grpc_iomgr_cb_func destroy, - void *destroy_arg); - -/// Destroy the builder without creating a channel stack -void grpc_channel_stack_builder_destroy(grpc_channel_stack_builder *builder); - -extern int grpc_trace_channel_stack_builder; - -#endif /* GRPC_CORE_CHANNEL_CHANNEL_STACK_BUILDER_H */ diff --git a/src/core/channel/client_channel.c b/src/core/channel/client_channel.c deleted file mode 100644 index ad1ded9ab7..0000000000 --- a/src/core/channel/client_channel.c +++ /dev/null @@ -1,526 +0,0 @@ -/* - * - * Copyright 2015-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/channel/client_channel.h" - -#include -#include - -#include -#include -#include -#include - -#include "src/core/channel/channel_args.h" -#include "src/core/channel/connected_channel.h" -#include "src/core/channel/subchannel_call_holder.h" -#include "src/core/iomgr/iomgr.h" -#include "src/core/profiling/timers.h" -#include "src/core/support/string.h" -#include "src/core/surface/channel.h" -#include "src/core/transport/connectivity_state.h" - -/* Client channel implementation */ - -typedef grpc_subchannel_call_holder call_data; - -typedef struct client_channel_channel_data { - /** resolver for this channel */ - grpc_resolver *resolver; - /** have we started resolving this channel */ - int started_resolving; - - /** mutex protecting client configuration, including all - variables below in this data structure */ - gpr_mu mu_config; - /** currently active load balancer - guarded by mu_config */ - grpc_lb_policy *lb_policy; - /** incoming configuration - set by resolver.next - guarded by mu_config */ - grpc_client_config *incoming_configuration; - /** a list of closures that are all waiting for config to come in */ - grpc_closure_list waiting_for_config_closures; - /** resolver callback */ - grpc_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; - /** owning stack */ - grpc_channel_stack *owning_stack; - /** interested parties (owned) */ - grpc_pollset_set *interested_parties; -} 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_closure on_changed; - grpc_connectivity_state state; - grpc_lb_policy *lb_policy; -} lb_policy_connectivity_watcher; - -typedef struct { - grpc_closure closure; - grpc_call_element *elem; -} waiting_call; - -static char *cc_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) { - return grpc_subchannel_call_holder_get_peer(exec_ctx, elem->call_data); -} - -static void cc_start_transport_stream_op(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_transport_stream_op *op) { - GRPC_CALL_LOG_OP(GPR_INFO, elem, op); - grpc_subchannel_call_holder_perform_op(exec_ctx, elem->call_data, op); -} - -static void watch_lb_policy(grpc_exec_ctx *exec_ctx, channel_data *chand, - grpc_lb_policy *lb_policy, - grpc_connectivity_state current_state); - -static void on_lb_policy_state_changed_locked( - grpc_exec_ctx *exec_ctx, lb_policy_connectivity_watcher *w) { - grpc_connectivity_state publish_state = w->state; - /* check if the notification is for a stale policy */ - if (w->lb_policy != w->chand->lb_policy) return; - - if (publish_state == GRPC_CHANNEL_FATAL_FAILURE && - w->chand->resolver != NULL) { - publish_state = GRPC_CHANNEL_TRANSIENT_FAILURE; - grpc_resolver_channel_saw_error(exec_ctx, w->chand->resolver); - GRPC_LB_POLICY_UNREF(exec_ctx, w->chand->lb_policy, "channel"); - w->chand->lb_policy = NULL; - } - grpc_connectivity_state_set(exec_ctx, &w->chand->state_tracker, publish_state, - "lb_changed"); - if (w->state != GRPC_CHANNEL_FATAL_FAILURE) { - watch_lb_policy(exec_ctx, w->chand, w->lb_policy, w->state); - } -} - -static void on_lb_policy_state_changed(grpc_exec_ctx *exec_ctx, void *arg, - bool iomgr_success) { - lb_policy_connectivity_watcher *w = arg; - - gpr_mu_lock(&w->chand->mu_config); - on_lb_policy_state_changed_locked(exec_ctx, w); - gpr_mu_unlock(&w->chand->mu_config); - - GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack, "watch_lb_policy"); - gpr_free(w); -} - -static void watch_lb_policy(grpc_exec_ctx *exec_ctx, channel_data *chand, - grpc_lb_policy *lb_policy, - grpc_connectivity_state current_state) { - lb_policy_connectivity_watcher *w = gpr_malloc(sizeof(*w)); - GRPC_CHANNEL_STACK_REF(chand->owning_stack, "watch_lb_policy"); - - w->chand = chand; - grpc_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(exec_ctx, lb_policy, &w->state, - &w->on_changed); -} - -static void cc_on_config_changed(grpc_exec_ctx *exec_ctx, void *arg, - bool iomgr_success) { - channel_data *chand = arg; - grpc_lb_policy *lb_policy = NULL; - grpc_lb_policy *old_lb_policy; - grpc_connectivity_state state = GRPC_CHANNEL_TRANSIENT_FAILURE; - int exit_idle = 0; - - if (chand->incoming_configuration != NULL) { - lb_policy = grpc_client_config_get_lb_policy(chand->incoming_configuration); - if (lb_policy != NULL) { - GRPC_LB_POLICY_REF(lb_policy, "channel"); - GRPC_LB_POLICY_REF(lb_policy, "config_change"); - state = grpc_lb_policy_check_connectivity(exec_ctx, lb_policy); - } - - grpc_client_config_unref(exec_ctx, chand->incoming_configuration); - } - - chand->incoming_configuration = NULL; - - if (lb_policy != NULL) { - grpc_pollset_set_add_pollset_set(exec_ctx, lb_policy->interested_parties, - chand->interested_parties); - } - - gpr_mu_lock(&chand->mu_config); - old_lb_policy = chand->lb_policy; - chand->lb_policy = lb_policy; - if (lb_policy != NULL || chand->resolver == NULL /* disconnected */) { - grpc_exec_ctx_enqueue_list(exec_ctx, &chand->waiting_for_config_closures, - NULL); - } - if (lb_policy != NULL && chand->exit_idle_when_lb_policy_arrives) { - GRPC_LB_POLICY_REF(lb_policy, "exit_idle"); - exit_idle = 1; - chand->exit_idle_when_lb_policy_arrives = 0; - } - - if (iomgr_success && chand->resolver) { - grpc_connectivity_state_set(exec_ctx, &chand->state_tracker, state, - "new_lb+resolver"); - if (lb_policy != NULL) { - watch_lb_policy(exec_ctx, chand, lb_policy, state); - } - GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver"); - grpc_resolver_next(exec_ctx, chand->resolver, - &chand->incoming_configuration, - &chand->on_config_changed); - gpr_mu_unlock(&chand->mu_config); - } else { - if (chand->resolver != NULL) { - grpc_resolver_shutdown(exec_ctx, chand->resolver); - GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel"); - chand->resolver = NULL; - } - grpc_connectivity_state_set(exec_ctx, &chand->state_tracker, - GRPC_CHANNEL_FATAL_FAILURE, "resolver_gone"); - gpr_mu_unlock(&chand->mu_config); - } - - if (exit_idle) { - grpc_lb_policy_exit_idle(exec_ctx, lb_policy); - GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "exit_idle"); - } - - if (old_lb_policy != NULL) { - grpc_pollset_set_del_pollset_set( - exec_ctx, old_lb_policy->interested_parties, chand->interested_parties); - GRPC_LB_POLICY_UNREF(exec_ctx, old_lb_policy, "channel"); - } - - if (lb_policy != NULL) { - GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "config_change"); - } - - GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->owning_stack, "resolver"); -} - -static void cc_start_transport_op(grpc_exec_ctx *exec_ctx, - grpc_channel_element *elem, - grpc_transport_op *op) { - channel_data *chand = elem->channel_data; - - grpc_exec_ctx_enqueue(exec_ctx, op->on_consumed, true, NULL); - - GPR_ASSERT(op->set_accept_stream == false); - if (op->bind_pollset != NULL) { - grpc_pollset_set_add_pollset(exec_ctx, chand->interested_parties, - op->bind_pollset); - } - - gpr_mu_lock(&chand->mu_config); - if (op->on_connectivity_state_change != NULL) { - grpc_connectivity_state_notify_on_state_change( - exec_ctx, &chand->state_tracker, op->connectivity_state, - op->on_connectivity_state_change); - op->on_connectivity_state_change = NULL; - op->connectivity_state = NULL; - } - - if (op->send_ping != NULL) { - if (chand->lb_policy == NULL) { - grpc_exec_ctx_enqueue(exec_ctx, op->send_ping, false, NULL); - } else { - grpc_lb_policy_ping_one(exec_ctx, chand->lb_policy, op->send_ping); - op->bind_pollset = NULL; - } - op->send_ping = NULL; - } - - if (op->disconnect && chand->resolver != NULL) { - grpc_connectivity_state_set(exec_ctx, &chand->state_tracker, - GRPC_CHANNEL_FATAL_FAILURE, "disconnect"); - grpc_resolver_shutdown(exec_ctx, chand->resolver); - GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel"); - chand->resolver = NULL; - if (chand->lb_policy != NULL) { - grpc_pollset_set_del_pollset_set(exec_ctx, - chand->lb_policy->interested_parties, - chand->interested_parties); - GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel"); - chand->lb_policy = NULL; - } - } - gpr_mu_unlock(&chand->mu_config); -} - -typedef struct { - grpc_metadata_batch *initial_metadata; - grpc_connected_subchannel **connected_subchannel; - grpc_closure *on_ready; - grpc_call_element *elem; - grpc_closure closure; -} continue_picking_args; - -static int cc_pick_subchannel(grpc_exec_ctx *exec_ctx, void *arg, - grpc_metadata_batch *initial_metadata, - grpc_connected_subchannel **connected_subchannel, - grpc_closure *on_ready); - -static void continue_picking(grpc_exec_ctx *exec_ctx, void *arg, bool success) { - continue_picking_args *cpa = arg; - if (!success) { - grpc_exec_ctx_enqueue(exec_ctx, cpa->on_ready, false, NULL); - } else if (cpa->connected_subchannel == NULL) { - /* cancelled, do nothing */ - } else if (cc_pick_subchannel(exec_ctx, cpa->elem, cpa->initial_metadata, - cpa->connected_subchannel, cpa->on_ready)) { - grpc_exec_ctx_enqueue(exec_ctx, cpa->on_ready, true, NULL); - } - gpr_free(cpa); -} - -static int cc_pick_subchannel(grpc_exec_ctx *exec_ctx, void *elemp, - grpc_metadata_batch *initial_metadata, - grpc_connected_subchannel **connected_subchannel, - grpc_closure *on_ready) { - grpc_call_element *elem = elemp; - channel_data *chand = elem->channel_data; - call_data *calld = elem->call_data; - continue_picking_args *cpa; - grpc_closure *closure; - - GPR_ASSERT(connected_subchannel); - - gpr_mu_lock(&chand->mu_config); - if (initial_metadata == NULL) { - if (chand->lb_policy != NULL) { - grpc_lb_policy_cancel_pick(exec_ctx, chand->lb_policy, - connected_subchannel); - } - for (closure = chand->waiting_for_config_closures.head; closure != NULL; - closure = grpc_closure_next(closure)) { - cpa = closure->cb_arg; - if (cpa->connected_subchannel == connected_subchannel) { - cpa->connected_subchannel = NULL; - grpc_exec_ctx_enqueue(exec_ctx, cpa->on_ready, false, NULL); - } - } - gpr_mu_unlock(&chand->mu_config); - return 1; - } - if (chand->lb_policy != NULL) { - grpc_lb_policy *lb_policy = chand->lb_policy; - int r; - GRPC_LB_POLICY_REF(lb_policy, "cc_pick_subchannel"); - gpr_mu_unlock(&chand->mu_config); - r = grpc_lb_policy_pick(exec_ctx, lb_policy, calld->pollset, - initial_metadata, connected_subchannel, on_ready); - GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "cc_pick_subchannel"); - return r; - } - if (chand->resolver != NULL && !chand->started_resolving) { - chand->started_resolving = 1; - GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver"); - grpc_resolver_next(exec_ctx, chand->resolver, - &chand->incoming_configuration, - &chand->on_config_changed); - } - cpa = gpr_malloc(sizeof(*cpa)); - cpa->initial_metadata = initial_metadata; - cpa->connected_subchannel = connected_subchannel; - cpa->on_ready = on_ready; - cpa->elem = elem; - grpc_closure_init(&cpa->closure, continue_picking, cpa); - grpc_closure_list_add(&chand->waiting_for_config_closures, &cpa->closure, 1); - gpr_mu_unlock(&chand->mu_config); - return 0; -} - -/* Constructor for call_data */ -static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_call_element_args *args) { - grpc_subchannel_call_holder_init(elem->call_data, cc_pick_subchannel, elem, - args->call_stack); -} - -/* Destructor for call_data */ -static void destroy_call_elem(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem) { - grpc_subchannel_call_holder_destroy(exec_ctx, elem->call_data); -} - -/* Constructor for channel_data */ -static void init_channel_elem(grpc_exec_ctx *exec_ctx, - grpc_channel_element *elem, - grpc_channel_element_args *args) { - channel_data *chand = elem->channel_data; - - memset(chand, 0, sizeof(*chand)); - - GPR_ASSERT(args->is_last); - GPR_ASSERT(elem->filter == &grpc_client_channel_filter); - - gpr_mu_init(&chand->mu_config); - grpc_closure_init(&chand->on_config_changed, cc_on_config_changed, chand); - chand->owning_stack = args->channel_stack; - - grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE, - "client_channel"); - chand->interested_parties = grpc_pollset_set_create(); -} - -/* Destructor for channel_data */ -static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, - grpc_channel_element *elem) { - channel_data *chand = elem->channel_data; - - if (chand->resolver != NULL) { - grpc_resolver_shutdown(exec_ctx, chand->resolver); - GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel"); - } - if (chand->lb_policy != NULL) { - grpc_pollset_set_del_pollset_set(exec_ctx, - chand->lb_policy->interested_parties, - chand->interested_parties); - GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel"); - } - grpc_connectivity_state_destroy(exec_ctx, &chand->state_tracker); - grpc_pollset_set_destroy(chand->interested_parties); - gpr_mu_destroy(&chand->mu_config); -} - -static void cc_set_pollset(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_pollset *pollset) { - call_data *calld = elem->call_data; - calld->pollset = pollset; -} - -const grpc_channel_filter grpc_client_channel_filter = { - cc_start_transport_stream_op, - cc_start_transport_op, - sizeof(call_data), - init_call_elem, - cc_set_pollset, - destroy_call_elem, - sizeof(channel_data), - init_channel_elem, - destroy_channel_elem, - cc_get_peer, - "client-channel", -}; - -void grpc_client_channel_set_resolver(grpc_exec_ctx *exec_ctx, - grpc_channel_stack *channel_stack, - grpc_resolver *resolver) { - /* post construction initialization: set the transport setup pointer */ - grpc_channel_element *elem = grpc_channel_stack_last_element(channel_stack); - channel_data *chand = elem->channel_data; - gpr_mu_lock(&chand->mu_config); - GPR_ASSERT(!chand->resolver); - chand->resolver = resolver; - GRPC_RESOLVER_REF(resolver, "channel"); - if (!grpc_closure_list_empty(chand->waiting_for_config_closures) || - chand->exit_idle_when_lb_policy_arrives) { - chand->started_resolving = 1; - GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver"); - grpc_resolver_next(exec_ctx, resolver, &chand->incoming_configuration, - &chand->on_config_changed); - } - gpr_mu_unlock(&chand->mu_config); -} - -grpc_connectivity_state grpc_client_channel_check_connectivity_state( - grpc_exec_ctx *exec_ctx, 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(exec_ctx, chand->lb_policy); - } else { - chand->exit_idle_when_lb_policy_arrives = 1; - if (!chand->started_resolving && chand->resolver != NULL) { - GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver"); - chand->started_resolving = 1; - grpc_resolver_next(exec_ctx, chand->resolver, - &chand->incoming_configuration, - &chand->on_config_changed); - } - } - } - gpr_mu_unlock(&chand->mu_config); - return out; -} - -typedef struct { - channel_data *chand; - grpc_pollset *pollset; - grpc_closure *on_complete; - grpc_closure my_closure; -} external_connectivity_watcher; - -static void on_external_watch_complete(grpc_exec_ctx *exec_ctx, void *arg, - bool iomgr_success) { - external_connectivity_watcher *w = arg; - grpc_closure *follow_up = w->on_complete; - grpc_pollset_set_del_pollset(exec_ctx, w->chand->interested_parties, - w->pollset); - GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack, - "external_connectivity_watcher"); - gpr_free(w); - follow_up->cb(exec_ctx, follow_up->cb_arg, iomgr_success); -} - -void grpc_client_channel_watch_connectivity_state( - grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_pollset *pollset, - grpc_connectivity_state *state, grpc_closure *on_complete) { - channel_data *chand = elem->channel_data; - external_connectivity_watcher *w = gpr_malloc(sizeof(*w)); - w->chand = chand; - w->pollset = pollset; - w->on_complete = on_complete; - grpc_pollset_set_add_pollset(exec_ctx, chand->interested_parties, pollset); - grpc_closure_init(&w->my_closure, on_external_watch_complete, w); - GRPC_CHANNEL_STACK_REF(w->chand->owning_stack, - "external_connectivity_watcher"); - gpr_mu_lock(&chand->mu_config); - grpc_connectivity_state_notify_on_state_change( - exec_ctx, &chand->state_tracker, state, &w->my_closure); - gpr_mu_unlock(&chand->mu_config); -} diff --git a/src/core/channel/client_channel.h b/src/core/channel/client_channel.h deleted file mode 100644 index 422f7f8374..0000000000 --- a/src/core/channel/client_channel.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * - * Copyright 2015-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_CHANNEL_CLIENT_CHANNEL_H -#define GRPC_CORE_CHANNEL_CLIENT_CHANNEL_H - -#include "src/core/channel/channel_stack.h" -#include "src/core/client_config/resolver.h" - -/* A client channel is a channel that begins disconnected, and can connect - to some endpoint on demand. If that endpoint disconnects, it will be - connected to again later. - - Calls on a disconnected client channel are queued until a connection is - established. */ - -extern const grpc_channel_filter grpc_client_channel_filter; - -/* post-construction initializer to let the client channel know which - transport setup it should cancel upon destruction, or initiate when it needs - a connection */ -void grpc_client_channel_set_resolver(grpc_exec_ctx *exec_ctx, - grpc_channel_stack *channel_stack, - grpc_resolver *resolver); - -grpc_connectivity_state grpc_client_channel_check_connectivity_state( - grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, int try_to_connect); - -void grpc_client_channel_watch_connectivity_state( - grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_pollset *pollset, - grpc_connectivity_state *state, grpc_closure *on_complete); - -#endif /* GRPC_CORE_CHANNEL_CLIENT_CHANNEL_H */ diff --git a/src/core/channel/compress_filter.c b/src/core/channel/compress_filter.c deleted file mode 100644 index 6f5a9740ad..0000000000 --- a/src/core/channel/compress_filter.c +++ /dev/null @@ -1,304 +0,0 @@ -/* - * - * Copyright 2015-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 -#include - -#include -#include -#include -#include - -#include "src/core/channel/channel_args.h" -#include "src/core/channel/compress_filter.h" -#include "src/core/compression/algorithm_metadata.h" -#include "src/core/compression/message_compress.h" -#include "src/core/profiling/timers.h" -#include "src/core/support/string.h" -#include "src/core/transport/static_metadata.h" - -typedef struct call_data { - gpr_slice_buffer slices; /**< Buffers up input slices to be compressed */ - grpc_linked_mdelem compression_algorithm_storage; - grpc_linked_mdelem accept_encoding_storage; - uint32_t remaining_slice_bytes; - /** Compression algorithm we'll try to use. It may be given by incoming - * metadata, or by the channel's default compression settings. */ - grpc_compression_algorithm compression_algorithm; - /** If true, contents of \a compression_algorithm are authoritative */ - int has_compression_algorithm; - - grpc_transport_stream_op send_op; - uint32_t send_length; - uint32_t send_flags; - gpr_slice incoming_slice; - grpc_slice_buffer_stream replacement_stream; - grpc_closure *post_send; - grpc_closure send_done; - grpc_closure got_slice; -} 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; - /** Supported compression algorithms */ - uint32_t supported_compression_algorithms; -} channel_data; - -/** For each \a md element from the incoming metadata, filter out the entry for - * "grpc-encoding", using its value to populate the call data's - * compression_algorithm field. */ -static grpc_mdelem *compression_md_filter(void *user_data, grpc_mdelem *md) { - grpc_call_element *elem = user_data; - call_data *calld = elem->call_data; - channel_data *channeld = elem->channel_data; - - if (md->key == GRPC_MDSTR_GRPC_INTERNAL_ENCODING_REQUEST) { - const char *md_c_str = grpc_mdstr_as_c_string(md->value); - if (!grpc_compression_algorithm_parse(md_c_str, strlen(md_c_str), - &calld->compression_algorithm)) { - gpr_log(GPR_ERROR, - "Invalid compression algorithm: '%s' (unknown). Ignoring.", - md_c_str); - calld->compression_algorithm = GRPC_COMPRESS_NONE; - } - if (grpc_compression_options_is_algorithm_enabled( - &channeld->compression_options, calld->compression_algorithm) == - 0) { - gpr_log(GPR_ERROR, - "Invalid compression algorithm: '%s' (previously disabled). " - "Ignoring.", - md_c_str); - calld->compression_algorithm = GRPC_COMPRESS_NONE; - } - calld->has_compression_algorithm = 1; - return NULL; - } - - return md; -} - -static int skip_compression(grpc_call_element *elem) { - call_data *calld = elem->call_data; - channel_data *channeld = elem->channel_data; - if (calld->has_compression_algorithm) { - if (calld->compression_algorithm == GRPC_COMPRESS_NONE) { - return 1; - } - return 0; /* we have an actual call-specific algorithm */ - } - /* no per-call compression override */ - return channeld->default_compression_algorithm == GRPC_COMPRESS_NONE; -} - -/** Filter initial metadata */ -static void process_send_initial_metadata( - grpc_call_element *elem, grpc_metadata_batch *initial_metadata) { - call_data *calld = elem->call_data; - channel_data *channeld = elem->channel_data; - /* Parse incoming request for compression. If any, it'll be available - * at calld->compression_algorithm */ - grpc_metadata_batch_filter(initial_metadata, compression_md_filter, elem); - if (!calld->has_compression_algorithm) { - /* If no algorithm was found in the metadata and we aren't - * exceptionally skipping compression, fall back to the channel - * default */ - calld->compression_algorithm = channeld->default_compression_algorithm; - calld->has_compression_algorithm = 1; /* GPR_TRUE */ - } - /* hint compression algorithm */ - grpc_metadata_batch_add_tail( - initial_metadata, &calld->compression_algorithm_storage, - grpc_compression_encoding_mdelem(calld->compression_algorithm)); - - /* convey supported compression algorithms */ - grpc_metadata_batch_add_tail(initial_metadata, - &calld->accept_encoding_storage, - GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS( - channeld->supported_compression_algorithms)); -} - -static void continue_send_message(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem); - -static void send_done(grpc_exec_ctx *exec_ctx, void *elemp, bool success) { - grpc_call_element *elem = elemp; - call_data *calld = elem->call_data; - gpr_slice_buffer_reset_and_unref(&calld->slices); - calld->post_send->cb(exec_ctx, calld->post_send->cb_arg, success); -} - -static void finish_send_message(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem) { - call_data *calld = elem->call_data; - int did_compress; - gpr_slice_buffer tmp; - gpr_slice_buffer_init(&tmp); - did_compress = - grpc_msg_compress(calld->compression_algorithm, &calld->slices, &tmp); - if (did_compress) { - gpr_slice_buffer_swap(&calld->slices, &tmp); - calld->send_flags |= GRPC_WRITE_INTERNAL_COMPRESS; - } - gpr_slice_buffer_destroy(&tmp); - - grpc_slice_buffer_stream_init(&calld->replacement_stream, &calld->slices, - calld->send_flags); - calld->send_op.send_message = &calld->replacement_stream.base; - calld->post_send = calld->send_op.on_complete; - calld->send_op.on_complete = &calld->send_done; - - grpc_call_next_op(exec_ctx, elem, &calld->send_op); -} - -static void got_slice(grpc_exec_ctx *exec_ctx, void *elemp, bool success) { - grpc_call_element *elem = elemp; - call_data *calld = elem->call_data; - gpr_slice_buffer_add(&calld->slices, calld->incoming_slice); - if (calld->send_length == calld->slices.length) { - finish_send_message(exec_ctx, elem); - } else { - continue_send_message(exec_ctx, elem); - } -} - -static void continue_send_message(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem) { - call_data *calld = elem->call_data; - while (grpc_byte_stream_next(exec_ctx, calld->send_op.send_message, - &calld->incoming_slice, ~(size_t)0, - &calld->got_slice)) { - gpr_slice_buffer_add(&calld->slices, calld->incoming_slice); - if (calld->send_length == calld->slices.length) { - finish_send_message(exec_ctx, elem); - break; - } - } -} - -static void compress_start_transport_stream_op(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_transport_stream_op *op) { - call_data *calld = elem->call_data; - - GPR_TIMER_BEGIN("compress_start_transport_stream_op", 0); - - if (op->send_initial_metadata) { - process_send_initial_metadata(elem, op->send_initial_metadata); - } - if (op->send_message != NULL && !skip_compression(elem) && - 0 == (op->send_message->flags & GRPC_WRITE_NO_COMPRESS)) { - calld->send_op = *op; - calld->send_length = op->send_message->length; - calld->send_flags = op->send_message->flags; - continue_send_message(exec_ctx, elem); - } else { - /* pass control down the stack */ - grpc_call_next_op(exec_ctx, elem, op); - } - - GPR_TIMER_END("compress_start_transport_stream_op", 0); -} - -/* Constructor for call_data */ -static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_call_element_args *args) { - /* grab pointers to our data from the call element */ - call_data *calld = elem->call_data; - - /* initialize members */ - gpr_slice_buffer_init(&calld->slices); - calld->has_compression_algorithm = 0; - grpc_closure_init(&calld->got_slice, got_slice, elem); - grpc_closure_init(&calld->send_done, send_done, elem); -} - -/* Destructor for call_data */ -static void destroy_call_elem(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem) { - /* grab pointers to our data from the call element */ - call_data *calld = elem->call_data; - gpr_slice_buffer_destroy(&calld->slices); -} - -/* Constructor for channel_data */ -static void init_channel_elem(grpc_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->default_compression_algorithm = - grpc_channel_args_get_compression_algorithm(args->channel_args); - /* Make sure the default isn't disabled. */ - GPR_ASSERT(grpc_compression_options_is_algorithm_enabled( - &channeld->compression_options, channeld->default_compression_algorithm)); - 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) { - /* skip disabled algorithms */ - if (grpc_compression_options_is_algorithm_enabled( - &channeld->compression_options, algo_idx) == 0) { - continue; - } - channeld->supported_compression_algorithms |= 1u << algo_idx; - } - - GPR_ASSERT(!args->is_last); -} - -/* Destructor for channel data */ -static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, - grpc_channel_element *elem) {} - -const grpc_channel_filter grpc_compress_filter = { - compress_start_transport_stream_op, - grpc_channel_next_op, - sizeof(call_data), - init_call_elem, - grpc_call_stack_ignore_set_pollset, - destroy_call_elem, - sizeof(channel_data), - init_channel_elem, - destroy_channel_elem, - grpc_call_next_get_peer, - "compress"}; diff --git a/src/core/channel/compress_filter.h b/src/core/channel/compress_filter.h deleted file mode 100644 index 8c208ac799..0000000000 --- a/src/core/channel/compress_filter.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * - * Copyright 2015-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_CHANNEL_COMPRESS_FILTER_H -#define GRPC_CORE_CHANNEL_COMPRESS_FILTER_H - -#include "src/core/channel/channel_stack.h" - -#define GRPC_COMPRESS_REQUEST_ALGORITHM_KEY "grpc-internal-encoding-request" - -/** Compression filter for outgoing data. - * - * See for the available compression settings. - * - * Compression settings may come from: - * - Channel configuration, as established at channel creation time. - * - The metadata accompanying the outgoing data to be compressed. This is - * taken as a request only. We may choose not to honor it. The metadata key - * is given by \a GRPC_COMPRESS_REQUEST_ALGORITHM_KEY. - * - * Compression can be disabled for concrete messages (for instance in order to - * prevent CRIME/BEAST type attacks) by having the GRPC_WRITE_NO_COMPRESS set in - * the BEGIN_MESSAGE flags. - * - * The attempted compression mechanism is added to the resulting initial - * metadata under the'grpc-encoding' key. - * - * If compression is actually performed, BEGIN_MESSAGE's flag is modified to - * incorporate GRPC_WRITE_INTERNAL_COMPRESS. Otherwise, and regardless of the - * aforementioned 'grpc-encoding' metadata value, data will pass through - * uncompressed. */ - -extern const grpc_channel_filter grpc_compress_filter; - -#endif /* GRPC_CORE_CHANNEL_COMPRESS_FILTER_H */ diff --git a/src/core/channel/connected_channel.c b/src/core/channel/connected_channel.c deleted file mode 100644 index df11d54297..0000000000 --- a/src/core/channel/connected_channel.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - * - * Copyright 2015-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/channel/connected_channel.h" - -#include -#include -#include - -#include -#include -#include -#include -#include "src/core/profiling/timers.h" -#include "src/core/support/string.h" -#include "src/core/transport/transport.h" - -#define MAX_BUFFER_LENGTH 8192 - -typedef struct connected_channel_channel_data { - grpc_transport *transport; -} channel_data; - -typedef struct connected_channel_call_data { void *unused; } call_data; - -/* We perform a small hack to locate transport data alongside the connected - channel data in call allocations, to allow everything to be pulled in minimal - cache line requests */ -#define TRANSPORT_STREAM_FROM_CALL_DATA(calld) ((grpc_stream *)((calld) + 1)) -#define CALL_DATA_FROM_TRANSPORT_STREAM(transport_stream) \ - (((call_data *)(transport_stream)) - 1) - -/* Intercept a call operation and either push it directly up or translate it - into transport stream operations */ -static void con_start_transport_stream_op(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_transport_stream_op *op) { - call_data *calld = elem->call_data; - channel_data *chand = elem->channel_data; - GRPC_CALL_LOG_OP(GPR_INFO, elem, op); - - grpc_transport_perform_stream_op(exec_ctx, chand->transport, - TRANSPORT_STREAM_FROM_CALL_DATA(calld), op); -} - -static void con_start_transport_op(grpc_exec_ctx *exec_ctx, - grpc_channel_element *elem, - grpc_transport_op *op) { - channel_data *chand = elem->channel_data; - grpc_transport_perform_op(exec_ctx, chand->transport, op); -} - -/* Constructor for call_data */ -static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_call_element_args *args) { - call_data *calld = elem->call_data; - channel_data *chand = elem->channel_data; - int r; - - r = grpc_transport_init_stream( - exec_ctx, chand->transport, TRANSPORT_STREAM_FROM_CALL_DATA(calld), - &args->call_stack->refcount, args->server_transport_data); - GPR_ASSERT(r == 0); -} - -static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_pollset *pollset) { - call_data *calld = elem->call_data; - channel_data *chand = elem->channel_data; - grpc_transport_set_pollset(exec_ctx, chand->transport, - TRANSPORT_STREAM_FROM_CALL_DATA(calld), pollset); -} - -/* Destructor for call_data */ -static void destroy_call_elem(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem) { - call_data *calld = elem->call_data; - channel_data *chand = elem->channel_data; - grpc_transport_destroy_stream(exec_ctx, chand->transport, - TRANSPORT_STREAM_FROM_CALL_DATA(calld)); -} - -/* Constructor for channel_data */ -static void init_channel_elem(grpc_exec_ctx *exec_ctx, - grpc_channel_element *elem, - grpc_channel_element_args *args) { - channel_data *cd = (channel_data *)elem->channel_data; - GPR_ASSERT(args->is_last); - cd->transport = NULL; -} - -/* Destructor for channel_data */ -static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, - grpc_channel_element *elem) { - channel_data *cd = (channel_data *)elem->channel_data; - grpc_transport_destroy(exec_ctx, cd->transport); -} - -static char *con_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) { - channel_data *chand = elem->channel_data; - return grpc_transport_get_peer(exec_ctx, chand->transport); -} - -static const grpc_channel_filter connected_channel_filter = { - con_start_transport_stream_op, - con_start_transport_op, - sizeof(call_data), - init_call_elem, - set_pollset, - destroy_call_elem, - sizeof(channel_data), - init_channel_elem, - destroy_channel_elem, - con_get_peer, - "connected", -}; - -static void bind_transport(grpc_channel_stack *channel_stack, - grpc_channel_element *elem, void *t) { - channel_data *cd = (channel_data *)elem->channel_data; - GPR_ASSERT(elem->filter == &connected_channel_filter); - GPR_ASSERT(cd->transport == NULL); - cd->transport = t; - - /* HACK(ctiller): increase call stack size for the channel to make space - for channel data. We need a cleaner (but performant) way to do this, - and I'm not sure what that is yet. - This is only "safe" because call stacks place no additional data after - the last call element, and the last call element MUST be the connected - channel. */ - channel_stack->call_stack_size += grpc_transport_stream_size(t); -} - -bool grpc_add_connected_filter(grpc_channel_stack_builder *builder, - void *arg_must_be_null) { - GPR_ASSERT(arg_must_be_null == NULL); - grpc_transport *t = grpc_channel_stack_builder_get_transport(builder); - GPR_ASSERT(t != NULL); - return grpc_channel_stack_builder_append_filter( - builder, &connected_channel_filter, bind_transport, t); -} - -grpc_stream *grpc_connected_channel_get_stream(grpc_call_element *elem) { - call_data *calld = elem->call_data; - return TRANSPORT_STREAM_FROM_CALL_DATA(calld); -} diff --git a/src/core/channel/connected_channel.h b/src/core/channel/connected_channel.h deleted file mode 100644 index 7c0c8359a4..0000000000 --- a/src/core/channel/connected_channel.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * - * Copyright 2015-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_CHANNEL_CONNECTED_CHANNEL_H -#define GRPC_CORE_CHANNEL_CONNECTED_CHANNEL_H - -#include "src/core/channel/channel_stack_builder.h" - -bool grpc_add_connected_filter(grpc_channel_stack_builder *builder, - void *arg_must_be_null); - -#endif /* GRPC_CORE_CHANNEL_CONNECTED_CHANNEL_H */ diff --git a/src/core/channel/context.h b/src/core/channel/context.h deleted file mode 100644 index db217dc133..0000000000 --- a/src/core/channel/context.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * - * Copyright 2015-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_CHANNEL_CONTEXT_H -#define GRPC_CORE_CHANNEL_CONTEXT_H - -/* Call object context pointers */ -typedef enum { - GRPC_CONTEXT_SECURITY = 0, - GRPC_CONTEXT_TRACING, - GRPC_CONTEXT_COUNT -} grpc_context_index; - -typedef struct { - void *value; - void (*destroy)(void *); -} grpc_call_context_element; - -#endif /* GRPC_CORE_CHANNEL_CONTEXT_H */ diff --git a/src/core/channel/http_client_filter.c b/src/core/channel/http_client_filter.c deleted file mode 100644 index 582427daf9..0000000000 --- a/src/core/channel/http_client_filter.c +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright 2015-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/channel/http_client_filter.h" -#include -#include -#include -#include -#include "src/core/profiling/timers.h" -#include "src/core/support/string.h" -#include "src/core/transport/static_metadata.h" - -typedef struct call_data { - grpc_linked_mdelem method; - grpc_linked_mdelem scheme; - grpc_linked_mdelem authority; - grpc_linked_mdelem te_trailers; - grpc_linked_mdelem content_type; - grpc_linked_mdelem user_agent; - - grpc_metadata_batch *recv_initial_metadata; - - /** Closure to call when finished with the hc_on_recv hook */ - grpc_closure *on_done_recv; - /** Receive closures are chained: we inject this closure as the on_done_recv - up-call on transport_op, and remember to call our on_done_recv member - after handling it. */ - grpc_closure hc_on_recv; -} call_data; - -typedef struct channel_data { - grpc_mdelem *static_scheme; - grpc_mdelem *user_agent; -} channel_data; - -typedef struct { - grpc_call_element *elem; - grpc_exec_ctx *exec_ctx; -} client_recv_filter_args; - -static grpc_mdelem *client_recv_filter(void *user_data, grpc_mdelem *md) { - client_recv_filter_args *a = user_data; - if (md == GRPC_MDELEM_STATUS_200) { - return NULL; - } else if (md->key == GRPC_MDSTR_STATUS) { - grpc_call_element_send_cancel(a->exec_ctx, a->elem); - return NULL; - } else if (md->key == GRPC_MDSTR_CONTENT_TYPE) { - return NULL; - } - return md; -} - -static void hc_on_recv(grpc_exec_ctx *exec_ctx, void *user_data, bool success) { - grpc_call_element *elem = user_data; - call_data *calld = elem->call_data; - client_recv_filter_args a; - a.elem = elem; - a.exec_ctx = exec_ctx; - grpc_metadata_batch_filter(calld->recv_initial_metadata, client_recv_filter, - &a); - calld->on_done_recv->cb(exec_ctx, calld->on_done_recv->cb_arg, success); -} - -static grpc_mdelem *client_strip_filter(void *user_data, grpc_mdelem *md) { - /* eat the things we'd like to set ourselves */ - if (md->key == GRPC_MDSTR_METHOD) return NULL; - if (md->key == GRPC_MDSTR_SCHEME) return NULL; - if (md->key == GRPC_MDSTR_TE) return NULL; - if (md->key == GRPC_MDSTR_CONTENT_TYPE) return NULL; - if (md->key == GRPC_MDSTR_USER_AGENT) return NULL; - return md; -} - -static void hc_mutate_op(grpc_call_element *elem, - grpc_transport_stream_op *op) { - /* grab pointers to our data from the call element */ - call_data *calld = elem->call_data; - channel_data *channeld = elem->channel_data; - if (op->send_initial_metadata != NULL) { - grpc_metadata_batch_filter(op->send_initial_metadata, client_strip_filter, - elem); - /* Send : prefixed headers, which have to be before any application - layer headers. */ - grpc_metadata_batch_add_head(op->send_initial_metadata, &calld->method, - GRPC_MDELEM_METHOD_POST); - grpc_metadata_batch_add_head(op->send_initial_metadata, &calld->scheme, - channeld->static_scheme); - grpc_metadata_batch_add_tail(op->send_initial_metadata, &calld->te_trailers, - GRPC_MDELEM_TE_TRAILERS); - grpc_metadata_batch_add_tail( - op->send_initial_metadata, &calld->content_type, - GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC); - grpc_metadata_batch_add_tail(op->send_initial_metadata, &calld->user_agent, - GRPC_MDELEM_REF(channeld->user_agent)); - } - - if (op->recv_initial_metadata != NULL) { - /* substitute our callback for the higher callback */ - calld->recv_initial_metadata = op->recv_initial_metadata; - calld->on_done_recv = op->recv_initial_metadata_ready; - op->recv_initial_metadata_ready = &calld->hc_on_recv; - } -} - -static void hc_start_transport_op(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_transport_stream_op *op) { - GPR_TIMER_BEGIN("hc_start_transport_op", 0); - GRPC_CALL_LOG_OP(GPR_INFO, elem, op); - hc_mutate_op(elem, op); - GPR_TIMER_END("hc_start_transport_op", 0); - grpc_call_next_op(exec_ctx, elem, op); -} - -/* Constructor for call_data */ -static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_call_element_args *args) { - call_data *calld = elem->call_data; - calld->on_done_recv = NULL; - grpc_closure_init(&calld->hc_on_recv, hc_on_recv, elem); -} - -/* Destructor for call_data */ -static void destroy_call_elem(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem) {} - -static grpc_mdelem *scheme_from_args(const grpc_channel_args *args) { - unsigned i; - size_t j; - grpc_mdelem *valid_schemes[] = {GRPC_MDELEM_SCHEME_HTTP, - GRPC_MDELEM_SCHEME_HTTPS}; - if (args != NULL) { - for (i = 0; i < args->num_args; ++i) { - if (args->args[i].type == GRPC_ARG_STRING && - strcmp(args->args[i].key, GRPC_ARG_HTTP2_SCHEME) == 0) { - for (j = 0; j < GPR_ARRAY_SIZE(valid_schemes); j++) { - if (0 == strcmp(grpc_mdstr_as_c_string(valid_schemes[j]->value), - args->args[i].value.string)) { - return valid_schemes[j]; - } - } - } - } - } - return GRPC_MDELEM_SCHEME_HTTP; -} - -static grpc_mdstr *user_agent_from_args(const grpc_channel_args *args) { - gpr_strvec v; - size_t i; - int is_first = 1; - char *tmp; - grpc_mdstr *result; - - gpr_strvec_init(&v); - - for (i = 0; args && i < args->num_args; i++) { - if (0 == strcmp(args->args[i].key, GRPC_ARG_PRIMARY_USER_AGENT_STRING)) { - if (args->args[i].type != GRPC_ARG_STRING) { - gpr_log(GPR_ERROR, "Channel argument '%s' should be a string", - GRPC_ARG_PRIMARY_USER_AGENT_STRING); - } else { - if (!is_first) gpr_strvec_add(&v, gpr_strdup(" ")); - is_first = 0; - gpr_strvec_add(&v, gpr_strdup(args->args[i].value.string)); - } - } - } - - gpr_asprintf(&tmp, "%sgrpc-c/%s (%s)", is_first ? "" : " ", - grpc_version_string(), GPR_PLATFORM_STRING); - is_first = 0; - gpr_strvec_add(&v, tmp); - - for (i = 0; args && i < args->num_args; i++) { - if (0 == strcmp(args->args[i].key, GRPC_ARG_SECONDARY_USER_AGENT_STRING)) { - if (args->args[i].type != GRPC_ARG_STRING) { - gpr_log(GPR_ERROR, "Channel argument '%s' should be a string", - GRPC_ARG_SECONDARY_USER_AGENT_STRING); - } else { - if (!is_first) gpr_strvec_add(&v, gpr_strdup(" ")); - is_first = 0; - gpr_strvec_add(&v, gpr_strdup(args->args[i].value.string)); - } - } - } - - tmp = gpr_strvec_flatten(&v, NULL); - gpr_strvec_destroy(&v); - result = grpc_mdstr_from_string(tmp); - gpr_free(tmp); - - return result; -} - -/* Constructor for channel_data */ -static void init_channel_elem(grpc_exec_ctx *exec_ctx, - grpc_channel_element *elem, - grpc_channel_element_args *args) { - channel_data *chand = elem->channel_data; - GPR_ASSERT(!args->is_last); - 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)); -} - -/* Destructor for channel data */ -static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, - grpc_channel_element *elem) { - channel_data *chand = elem->channel_data; - GRPC_MDELEM_UNREF(chand->user_agent); -} - -const grpc_channel_filter grpc_http_client_filter = { - hc_start_transport_op, - grpc_channel_next_op, - sizeof(call_data), - init_call_elem, - grpc_call_stack_ignore_set_pollset, - destroy_call_elem, - sizeof(channel_data), - init_channel_elem, - destroy_channel_elem, - grpc_call_next_get_peer, - "http-client"}; diff --git a/src/core/channel/http_client_filter.h b/src/core/channel/http_client_filter.h deleted file mode 100644 index 6f619bbf00..0000000000 --- a/src/core/channel/http_client_filter.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * - * Copyright 2015-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_CHANNEL_HTTP_CLIENT_FILTER_H -#define GRPC_CORE_CHANNEL_HTTP_CLIENT_FILTER_H - -#include "src/core/channel/channel_stack.h" - -/* Processes metadata on the client side for HTTP2 transports */ -extern const grpc_channel_filter grpc_http_client_filter; - -#define GRPC_ARG_HTTP2_SCHEME "grpc.http2_scheme" - -#endif /* GRPC_CORE_CHANNEL_HTTP_CLIENT_FILTER_H */ diff --git a/src/core/channel/http_server_filter.c b/src/core/channel/http_server_filter.c deleted file mode 100644 index 1a2e0c5db3..0000000000 --- a/src/core/channel/http_server_filter.c +++ /dev/null @@ -1,240 +0,0 @@ -/* - * - * Copyright 2015-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/channel/http_server_filter.h" - -#include -#include -#include -#include "src/core/profiling/timers.h" -#include "src/core/transport/static_metadata.h" - -typedef struct call_data { - uint8_t seen_path; - uint8_t seen_post; - uint8_t sent_status; - uint8_t seen_scheme; - uint8_t seen_te_trailers; - uint8_t seen_authority; - grpc_linked_mdelem status; - grpc_linked_mdelem content_type; - - grpc_metadata_batch *recv_initial_metadata; - /** Closure to call when finished with the hs_on_recv hook */ - grpc_closure *on_done_recv; - /** Receive closures are chained: we inject this closure as the on_done_recv - up-call on transport_op, and remember to call our on_done_recv member - after handling it. */ - grpc_closure hs_on_recv; -} call_data; - -typedef struct channel_data { uint8_t unused; } channel_data; - -typedef struct { - grpc_call_element *elem; - grpc_exec_ctx *exec_ctx; -} server_filter_args; - -static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) { - server_filter_args *a = user_data; - grpc_call_element *elem = a->elem; - call_data *calld = elem->call_data; - - /* Check if it is one of the headers we care about. */ - if (md == GRPC_MDELEM_TE_TRAILERS || md == GRPC_MDELEM_METHOD_POST || - md == GRPC_MDELEM_SCHEME_HTTP || md == GRPC_MDELEM_SCHEME_HTTPS || - md == GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC) { - /* swallow it */ - if (md == GRPC_MDELEM_METHOD_POST) { - calld->seen_post = 1; - } else if (md->key == GRPC_MDSTR_SCHEME) { - calld->seen_scheme = 1; - } else if (md == GRPC_MDELEM_TE_TRAILERS) { - calld->seen_te_trailers = 1; - } - /* TODO(klempner): Track that we've seen all the headers we should - require */ - return NULL; - } else if (md->key == GRPC_MDSTR_CONTENT_TYPE) { - if (strncmp(grpc_mdstr_as_c_string(md->value), "application/grpc+", 17) == - 0) { - /* Although the C implementation doesn't (currently) generate them, - any custom +-suffix is explicitly valid. */ - /* TODO(klempner): We should consider preallocating common values such - as +proto or +json, or at least stashing them if we see them. */ - /* TODO(klempner): Should we be surfacing this to application code? */ - } else { - /* TODO(klempner): We're currently allowing this, but we shouldn't - see it without a proxy so log for now. */ - gpr_log(GPR_INFO, "Unexpected content-type %s", - grpc_mdstr_as_c_string(md->value)); - } - return NULL; - } else if (md->key == GRPC_MDSTR_TE || md->key == GRPC_MDSTR_METHOD || - md->key == GRPC_MDSTR_SCHEME) { - gpr_log(GPR_ERROR, "Invalid %s: header: '%s'", - grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value)); - /* swallow it and error everything out. */ - /* TODO(klempner): We ought to generate more descriptive error messages - on the wire here. */ - grpc_call_element_send_cancel(a->exec_ctx, elem); - return NULL; - } else if (md->key == GRPC_MDSTR_PATH) { - if (calld->seen_path) { - gpr_log(GPR_ERROR, "Received :path twice"); - return NULL; - } - calld->seen_path = 1; - return md; - } else if (md->key == GRPC_MDSTR_AUTHORITY) { - calld->seen_authority = 1; - return md; - } else if (md->key == GRPC_MDSTR_HOST) { - /* translate host to :authority since :authority may be - omitted */ - grpc_mdelem *authority = grpc_mdelem_from_metadata_strings( - GRPC_MDSTR_AUTHORITY, GRPC_MDSTR_REF(md->value)); - calld->seen_authority = 1; - return authority; - } else { - return md; - } -} - -static void hs_on_recv(grpc_exec_ctx *exec_ctx, void *user_data, bool success) { - grpc_call_element *elem = user_data; - call_data *calld = elem->call_data; - if (success) { - server_filter_args a; - a.elem = elem; - a.exec_ctx = exec_ctx; - grpc_metadata_batch_filter(calld->recv_initial_metadata, server_filter, &a); - /* Have we seen the required http2 transport headers? - (:method, :scheme, content-type, with :path and :authority covered - at the channel level right now) */ - if (calld->seen_post && calld->seen_scheme && calld->seen_te_trailers && - calld->seen_path && calld->seen_authority) { - /* do nothing */ - } else { - if (!calld->seen_path) { - gpr_log(GPR_ERROR, "Missing :path header"); - } - if (!calld->seen_authority) { - gpr_log(GPR_ERROR, "Missing :authority header"); - } - if (!calld->seen_post) { - gpr_log(GPR_ERROR, "Missing :method header"); - } - if (!calld->seen_scheme) { - gpr_log(GPR_ERROR, "Missing :scheme header"); - } - if (!calld->seen_te_trailers) { - gpr_log(GPR_ERROR, "Missing te trailers header"); - } - /* Error this call out */ - success = 0; - grpc_call_element_send_cancel(exec_ctx, elem); - } - } - calld->on_done_recv->cb(exec_ctx, calld->on_done_recv->cb_arg, success); -} - -static void hs_mutate_op(grpc_call_element *elem, - grpc_transport_stream_op *op) { - /* grab pointers to our data from the call element */ - call_data *calld = elem->call_data; - - if (op->send_initial_metadata != NULL && !calld->sent_status) { - calld->sent_status = 1; - grpc_metadata_batch_add_head(op->send_initial_metadata, &calld->status, - GRPC_MDELEM_STATUS_200); - grpc_metadata_batch_add_tail( - op->send_initial_metadata, &calld->content_type, - GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC); - } - - if (op->recv_initial_metadata) { - /* substitute our callback for the higher callback */ - calld->recv_initial_metadata = op->recv_initial_metadata; - calld->on_done_recv = op->recv_initial_metadata_ready; - op->recv_initial_metadata_ready = &calld->hs_on_recv; - } -} - -static void hs_start_transport_op(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_transport_stream_op *op) { - GRPC_CALL_LOG_OP(GPR_INFO, elem, op); - GPR_TIMER_BEGIN("hs_start_transport_op", 0); - hs_mutate_op(elem, op); - grpc_call_next_op(exec_ctx, elem, op); - GPR_TIMER_END("hs_start_transport_op", 0); -} - -/* Constructor for call_data */ -static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_call_element_args *args) { - /* grab pointers to our data from the call element */ - call_data *calld = elem->call_data; - /* initialize members */ - memset(calld, 0, sizeof(*calld)); - grpc_closure_init(&calld->hs_on_recv, hs_on_recv, elem); -} - -/* Destructor for call_data */ -static void destroy_call_elem(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem) {} - -/* Constructor for channel_data */ -static void init_channel_elem(grpc_exec_ctx *exec_ctx, - grpc_channel_element *elem, - grpc_channel_element_args *args) { - GPR_ASSERT(!args->is_last); -} - -/* Destructor for channel data */ -static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, - grpc_channel_element *elem) {} - -const grpc_channel_filter grpc_http_server_filter = { - hs_start_transport_op, - grpc_channel_next_op, - sizeof(call_data), - init_call_elem, - grpc_call_stack_ignore_set_pollset, - destroy_call_elem, - sizeof(channel_data), - init_channel_elem, - destroy_channel_elem, - grpc_call_next_get_peer, - "http-server"}; diff --git a/src/core/channel/http_server_filter.h b/src/core/channel/http_server_filter.h deleted file mode 100644 index 528c8648fd..0000000000 --- a/src/core/channel/http_server_filter.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * - * Copyright 2015-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_CHANNEL_HTTP_SERVER_FILTER_H -#define GRPC_CORE_CHANNEL_HTTP_SERVER_FILTER_H - -#include "src/core/channel/channel_stack.h" - -/* Processes metadata on the client side for HTTP2 transports */ -extern const grpc_channel_filter grpc_http_server_filter; - -#endif /* GRPC_CORE_CHANNEL_HTTP_SERVER_FILTER_H */ diff --git a/src/core/channel/subchannel_call_holder.c b/src/core/channel/subchannel_call_holder.c deleted file mode 100644 index 9c087dc2a1..0000000000 --- a/src/core/channel/subchannel_call_holder.c +++ /dev/null @@ -1,259 +0,0 @@ -/* - * - * Copyright 2015-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/channel/subchannel_call_holder.h" - -#include - -#include "src/core/profiling/timers.h" - -#define GET_CALL(holder) \ - ((grpc_subchannel_call *)(gpr_atm_acq_load(&(holder)->subchannel_call))) - -#define CANCELLED_CALL ((grpc_subchannel_call *)1) - -static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *holder, - bool success); -static void retry_ops(grpc_exec_ctx *exec_ctx, void *retry_ops_args, - bool success); - -static void add_waiting_locked(grpc_subchannel_call_holder *holder, - grpc_transport_stream_op *op); -static void fail_locked(grpc_exec_ctx *exec_ctx, - grpc_subchannel_call_holder *holder); -static void retry_waiting_locked(grpc_exec_ctx *exec_ctx, - grpc_subchannel_call_holder *holder); - -void grpc_subchannel_call_holder_init( - grpc_subchannel_call_holder *holder, - grpc_subchannel_call_holder_pick_subchannel pick_subchannel, - void *pick_subchannel_arg, grpc_call_stack *owning_call) { - gpr_atm_rel_store(&holder->subchannel_call, 0); - holder->pick_subchannel = pick_subchannel; - holder->pick_subchannel_arg = pick_subchannel_arg; - gpr_mu_init(&holder->mu); - holder->connected_subchannel = NULL; - holder->waiting_ops = NULL; - holder->waiting_ops_count = 0; - holder->waiting_ops_capacity = 0; - holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING; - holder->owning_call = owning_call; -} - -void grpc_subchannel_call_holder_destroy(grpc_exec_ctx *exec_ctx, - grpc_subchannel_call_holder *holder) { - grpc_subchannel_call *call = GET_CALL(holder); - if (call != NULL && call != CANCELLED_CALL) { - GRPC_SUBCHANNEL_CALL_UNREF(exec_ctx, call, "holder"); - } - GPR_ASSERT(holder->creation_phase == - GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING); - gpr_mu_destroy(&holder->mu); - GPR_ASSERT(holder->waiting_ops_count == 0); - gpr_free(holder->waiting_ops); -} - -void grpc_subchannel_call_holder_perform_op(grpc_exec_ctx *exec_ctx, - grpc_subchannel_call_holder *holder, - grpc_transport_stream_op *op) { - /* try to (atomically) get the call */ - grpc_subchannel_call *call = GET_CALL(holder); - GPR_TIMER_BEGIN("grpc_subchannel_call_holder_perform_op", 0); - if (call == CANCELLED_CALL) { - grpc_transport_stream_op_finish_with_failure(exec_ctx, op); - GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0); - return; - } - if (call != NULL) { - grpc_subchannel_call_process_op(exec_ctx, call, op); - GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0); - return; - } - /* we failed; lock and figure out what to do */ - gpr_mu_lock(&holder->mu); -retry: - /* need to recheck that another thread hasn't set the call */ - call = GET_CALL(holder); - if (call == CANCELLED_CALL) { - gpr_mu_unlock(&holder->mu); - grpc_transport_stream_op_finish_with_failure(exec_ctx, op); - GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0); - return; - } - if (call != NULL) { - gpr_mu_unlock(&holder->mu); - grpc_subchannel_call_process_op(exec_ctx, call, op); - GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0); - return; - } - /* if this is a cancellation, then we can raise our cancelled flag */ - if (op->cancel_with_status != GRPC_STATUS_OK) { - if (!gpr_atm_rel_cas(&holder->subchannel_call, 0, 1)) { - goto retry; - } else { - switch (holder->creation_phase) { - case GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING: - fail_locked(exec_ctx, holder); - break; - case GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL: - holder->pick_subchannel(exec_ctx, holder->pick_subchannel_arg, NULL, - &holder->connected_subchannel, NULL); - break; - } - gpr_mu_unlock(&holder->mu); - grpc_transport_stream_op_finish_with_failure(exec_ctx, op); - GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0); - return; - } - } - /* if we don't have a subchannel, try to get one */ - if (holder->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING && - holder->connected_subchannel == NULL && - op->send_initial_metadata != NULL) { - holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL; - grpc_closure_init(&holder->next_step, subchannel_ready, holder); - GRPC_CALL_STACK_REF(holder->owning_call, "pick_subchannel"); - if (holder->pick_subchannel( - exec_ctx, holder->pick_subchannel_arg, op->send_initial_metadata, - &holder->connected_subchannel, &holder->next_step)) { - holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING; - GRPC_CALL_STACK_UNREF(exec_ctx, holder->owning_call, "pick_subchannel"); - } - } - /* if we've got a subchannel, then let's ask it to create a call */ - if (holder->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING && - holder->connected_subchannel != NULL) { - gpr_atm_rel_store( - &holder->subchannel_call, - (gpr_atm)(uintptr_t)grpc_connected_subchannel_create_call( - exec_ctx, holder->connected_subchannel, holder->pollset)); - retry_waiting_locked(exec_ctx, holder); - goto retry; - } - /* nothing to be done but wait */ - add_waiting_locked(holder, op); - gpr_mu_unlock(&holder->mu); - GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0); -} - -static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *arg, bool success) { - grpc_subchannel_call_holder *holder = arg; - gpr_mu_lock(&holder->mu); - GPR_ASSERT(holder->creation_phase == - GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL); - holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING; - if (holder->connected_subchannel == NULL) { - fail_locked(exec_ctx, holder); - } else if (1 == gpr_atm_acq_load(&holder->subchannel_call)) { - /* already cancelled before subchannel became ready */ - fail_locked(exec_ctx, holder); - } else { - gpr_atm_rel_store( - &holder->subchannel_call, - (gpr_atm)(uintptr_t)grpc_connected_subchannel_create_call( - exec_ctx, holder->connected_subchannel, holder->pollset)); - retry_waiting_locked(exec_ctx, holder); - } - gpr_mu_unlock(&holder->mu); - GRPC_CALL_STACK_UNREF(exec_ctx, holder->owning_call, "pick_subchannel"); -} - -typedef struct { - grpc_transport_stream_op *ops; - size_t nops; - grpc_subchannel_call *call; -} retry_ops_args; - -static void retry_waiting_locked(grpc_exec_ctx *exec_ctx, - grpc_subchannel_call_holder *holder) { - retry_ops_args *a = gpr_malloc(sizeof(*a)); - a->ops = holder->waiting_ops; - a->nops = holder->waiting_ops_count; - a->call = GET_CALL(holder); - if (a->call == CANCELLED_CALL) { - gpr_free(a); - fail_locked(exec_ctx, holder); - return; - } - holder->waiting_ops = NULL; - holder->waiting_ops_count = 0; - holder->waiting_ops_capacity = 0; - GRPC_SUBCHANNEL_CALL_REF(a->call, "retry_ops"); - grpc_exec_ctx_enqueue(exec_ctx, grpc_closure_create(retry_ops, a), true, - NULL); -} - -static void retry_ops(grpc_exec_ctx *exec_ctx, void *args, bool success) { - retry_ops_args *a = args; - size_t i; - for (i = 0; i < a->nops; i++) { - grpc_subchannel_call_process_op(exec_ctx, a->call, &a->ops[i]); - } - GRPC_SUBCHANNEL_CALL_UNREF(exec_ctx, a->call, "retry_ops"); - gpr_free(a->ops); - gpr_free(a); -} - -static void add_waiting_locked(grpc_subchannel_call_holder *holder, - grpc_transport_stream_op *op) { - GPR_TIMER_BEGIN("add_waiting_locked", 0); - if (holder->waiting_ops_count == holder->waiting_ops_capacity) { - holder->waiting_ops_capacity = GPR_MAX(3, 2 * holder->waiting_ops_capacity); - holder->waiting_ops = - gpr_realloc(holder->waiting_ops, holder->waiting_ops_capacity * - sizeof(*holder->waiting_ops)); - } - holder->waiting_ops[holder->waiting_ops_count++] = *op; - GPR_TIMER_END("add_waiting_locked", 0); -} - -static void fail_locked(grpc_exec_ctx *exec_ctx, - grpc_subchannel_call_holder *holder) { - size_t i; - for (i = 0; i < holder->waiting_ops_count; i++) { - grpc_transport_stream_op_finish_with_failure(exec_ctx, - &holder->waiting_ops[i]); - } - holder->waiting_ops_count = 0; -} - -char *grpc_subchannel_call_holder_get_peer( - grpc_exec_ctx *exec_ctx, grpc_subchannel_call_holder *holder) { - grpc_subchannel_call *subchannel_call = GET_CALL(holder); - - if (subchannel_call) { - return grpc_subchannel_call_get_peer(exec_ctx, subchannel_call); - } else { - return NULL; - } -} diff --git a/src/core/channel/subchannel_call_holder.h b/src/core/channel/subchannel_call_holder.h deleted file mode 100644 index 84b4657db4..0000000000 --- a/src/core/channel/subchannel_call_holder.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * - * Copyright 2015-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_CHANNEL_SUBCHANNEL_CALL_HOLDER_H -#define GRPC_CORE_CHANNEL_SUBCHANNEL_CALL_HOLDER_H - -#include "src/core/client_config/subchannel.h" - -/** Pick a subchannel for grpc_subchannel_call_holder; - Return 1 if subchannel is available immediately (in which case on_ready - should not be called), or 0 otherwise (in which case on_ready should be - called when the subchannel is available) */ -typedef int (*grpc_subchannel_call_holder_pick_subchannel)( - grpc_exec_ctx *exec_ctx, void *arg, grpc_metadata_batch *initial_metadata, - grpc_connected_subchannel **connected_subchannel, grpc_closure *on_ready); - -typedef enum { - GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING, - GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL -} grpc_subchannel_call_holder_creation_phase; - -/** Wrapper for holding a pointer to grpc_subchannel_call, and the - associated machinery to create such a pointer. - Handles queueing of stream ops until a call object is ready, waiting - for initial metadata before trying to create a call object, - and handling cancellation gracefully. - - The channel filter uses this as their call_data. */ -typedef struct grpc_subchannel_call_holder { - /** either 0 for no call, 1 for cancelled, or a pointer to a - grpc_subchannel_call */ - gpr_atm subchannel_call; - /** Helper function to choose the subchannel on which to create - the call object. Channel filter delegates to the load - balancing policy (once it's ready). */ - grpc_subchannel_call_holder_pick_subchannel pick_subchannel; - void *pick_subchannel_arg; - - gpr_mu mu; - - grpc_subchannel_call_holder_creation_phase creation_phase; - grpc_connected_subchannel *connected_subchannel; - grpc_pollset *pollset; - - grpc_transport_stream_op *waiting_ops; - size_t waiting_ops_count; - size_t waiting_ops_capacity; - - grpc_closure next_step; - - grpc_call_stack *owning_call; -} grpc_subchannel_call_holder; - -void grpc_subchannel_call_holder_init( - grpc_subchannel_call_holder *holder, - grpc_subchannel_call_holder_pick_subchannel pick_subchannel, - void *pick_subchannel_arg, grpc_call_stack *owning_call); -void grpc_subchannel_call_holder_destroy(grpc_exec_ctx *exec_ctx, - grpc_subchannel_call_holder *holder); - -void grpc_subchannel_call_holder_perform_op(grpc_exec_ctx *exec_ctx, - grpc_subchannel_call_holder *holder, - grpc_transport_stream_op *op); -char *grpc_subchannel_call_holder_get_peer(grpc_exec_ctx *exec_ctx, - grpc_subchannel_call_holder *holder); - -#endif /* GRPC_CORE_CHANNEL_SUBCHANNEL_CALL_HOLDER_H */ diff --git a/src/core/client_config/README.md b/src/core/client_config/README.md deleted file mode 100644 index fff7a5af5b..0000000000 --- a/src/core/client_config/README.md +++ /dev/null @@ -1,66 +0,0 @@ -Client Configuration Support for GRPC -===================================== - -This library provides high level configuration machinery to construct client -channels and load balance between them. - -Each grpc_channel is created with a grpc_resolver. It is the resolver's duty -to resolve a name into configuration data for the channel. Such configuration -data might include: - -- a list of (ip, port) addresses to connect to -- a load balancing policy to decide which server to send a request to -- a set of filters to mutate outgoing requests (say, by adding metadata) - -The resolver provides this data as a stream of grpc_client_config objects to -the channel. We represent configuration as a stream so that it can be changed -by the resolver during execution, by reacting to external events (such as a -new configuration file being pushed to some store). - - -Load Balancing --------------- - -Load balancing configuration is provided by a grpc_lb_policy object, stored as -part of grpc_client_config. - -The primary job of the load balancing policies is to pick a target server given only the -initial metadata for a request. It does this by providing a grpc_subchannel -object to the owning channel. - - -Sub-Channels ------------- - -A sub-channel provides a connection to a server for a client channel. It has a -connectivity state like a regular channel, and so can be connected or -disconnected. This connectivity state can be used to inform load balancing -decisions (for example, by avoiding disconnected backends). - -Configured sub-channels are fully setup to participate in the grpc data plane. -Their behavior is specified by a set of grpc channel filters defined at their -construction. To customize this behavior, resolvers build -grpc_subchannel_factory objects, which use the decorator pattern to customize -construction arguments for concrete grpc_subchannel instances. - - -Naming for GRPC -=============== - -Names in GRPC are represented by a URI (as defined in -[RFC 3986](https://tools.ietf.org/html/rfc3986)). - -The following schemes are currently supported: - -dns:///host:port - dns schemes are currently supported so long as authority is - empty (authority based dns resolution is expected in a future - release) - -unix:path - the unix scheme is used to create and connect to unix domain - sockets - the authority must be empty, and the path - represents the absolute or relative path to the desired - socket - -ipv4:host:port - a pre-resolved ipv4 dotted decimal address/port combination - -ipv6:[host]:port - a pre-resolved ipv6 address/port combination diff --git a/src/core/client_config/client_config.c b/src/core/client_config/client_config.c deleted file mode 100644 index c500af25ee..0000000000 --- a/src/core/client_config/client_config.c +++ /dev/null @@ -1,74 +0,0 @@ -/* - * - * Copyright 2015-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/client_config/client_config.h" - -#include - -#include - -struct grpc_client_config { - gpr_refcount refs; - grpc_lb_policy *lb_policy; -}; - -grpc_client_config *grpc_client_config_create() { - grpc_client_config *c = gpr_malloc(sizeof(*c)); - memset(c, 0, sizeof(*c)); - gpr_ref_init(&c->refs, 1); - return c; -} - -void grpc_client_config_ref(grpc_client_config *c) { gpr_ref(&c->refs); } - -void grpc_client_config_unref(grpc_exec_ctx *exec_ctx, grpc_client_config *c) { - if (gpr_unref(&c->refs)) { - if (c->lb_policy != NULL) { - GRPC_LB_POLICY_UNREF(exec_ctx, c->lb_policy, "client_config"); - } - gpr_free(c); - } -} - -void grpc_client_config_set_lb_policy(grpc_client_config *c, - grpc_lb_policy *lb_policy) { - GPR_ASSERT(c->lb_policy == NULL); - if (lb_policy) { - GRPC_LB_POLICY_REF(lb_policy, "client_config"); - } - c->lb_policy = lb_policy; -} - -grpc_lb_policy *grpc_client_config_get_lb_policy(grpc_client_config *c) { - return c->lb_policy; -} diff --git a/src/core/client_config/client_config.h b/src/core/client_config/client_config.h deleted file mode 100644 index 9b37fdc211..0000000000 --- a/src/core/client_config/client_config.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * - * Copyright 2015-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_CLIENT_CONFIG_CLIENT_CONFIG_H -#define GRPC_CORE_CLIENT_CONFIG_CLIENT_CONFIG_H - -#include "src/core/client_config/lb_policy.h" - -/** Total configuration for a client. Provided, and updated, by - grpc_resolver */ -typedef struct grpc_client_config grpc_client_config; - -grpc_client_config *grpc_client_config_create(); -void grpc_client_config_ref(grpc_client_config *client_config); -void grpc_client_config_unref(grpc_exec_ctx *exec_ctx, - grpc_client_config *client_config); - -void grpc_client_config_set_lb_policy(grpc_client_config *client_config, - grpc_lb_policy *lb_policy); -grpc_lb_policy *grpc_client_config_get_lb_policy( - grpc_client_config *client_config); - -#endif /* GRPC_CORE_CLIENT_CONFIG_CLIENT_CONFIG_H */ diff --git a/src/core/client_config/connector.c b/src/core/client_config/connector.c deleted file mode 100644 index aa34aa7fab..0000000000 --- a/src/core/client_config/connector.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * - * Copyright 2015-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/client_config/connector.h" - -grpc_connector* grpc_connector_ref(grpc_connector* connector) { - connector->vtable->ref(connector); - return connector; -} - -void grpc_connector_unref(grpc_exec_ctx* exec_ctx, grpc_connector* connector) { - connector->vtable->unref(exec_ctx, connector); -} - -void grpc_connector_connect(grpc_exec_ctx* exec_ctx, grpc_connector* connector, - const grpc_connect_in_args* in_args, - grpc_connect_out_args* out_args, - grpc_closure* notify) { - connector->vtable->connect(exec_ctx, connector, in_args, out_args, notify); -} - -void grpc_connector_shutdown(grpc_exec_ctx* exec_ctx, - grpc_connector* connector) { - connector->vtable->shutdown(exec_ctx, connector); -} diff --git a/src/core/client_config/connector.h b/src/core/client_config/connector.h deleted file mode 100644 index 93248fca4b..0000000000 --- a/src/core/client_config/connector.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * - * Copyright 2015-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_CLIENT_CONFIG_CONNECTOR_H -#define GRPC_CORE_CLIENT_CONFIG_CONNECTOR_H - -#include "src/core/channel/channel_stack.h" -#include "src/core/iomgr/sockaddr.h" -#include "src/core/transport/transport.h" - -typedef struct grpc_connector grpc_connector; -typedef struct grpc_connector_vtable grpc_connector_vtable; - -struct grpc_connector { - const grpc_connector_vtable *vtable; -}; - -typedef struct { - /** set of pollsets interested in this connection */ - grpc_pollset_set *interested_parties; - /** address to connect to */ - const struct sockaddr *addr; - size_t addr_len; - /** initial connect string to send */ - gpr_slice initial_connect_string; - /** deadline for connection */ - gpr_timespec deadline; - /** channel arguments (to be passed to transport) */ - const grpc_channel_args *channel_args; -} grpc_connect_in_args; - -typedef struct { - /** the connected transport */ - grpc_transport *transport; - - /** channel arguments (to be passed to the filters) */ - const grpc_channel_args *channel_args; -} grpc_connect_out_args; - -struct grpc_connector_vtable { - void (*ref)(grpc_connector *connector); - void (*unref)(grpc_exec_ctx *exec_ctx, grpc_connector *connector); - /** Implementation of grpc_connector_shutdown */ - void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_connector *connector); - /** Implementation of grpc_connector_connect */ - void (*connect)(grpc_exec_ctx *exec_ctx, grpc_connector *connector, - const grpc_connect_in_args *in_args, - grpc_connect_out_args *out_args, grpc_closure *notify); -}; - -grpc_connector *grpc_connector_ref(grpc_connector *connector); -void grpc_connector_unref(grpc_exec_ctx *exec_ctx, grpc_connector *connector); -/** Connect using the connector: max one outstanding call at a time */ -void grpc_connector_connect(grpc_exec_ctx *exec_ctx, grpc_connector *connector, - const grpc_connect_in_args *in_args, - grpc_connect_out_args *out_args, - grpc_closure *notify); -/** Cancel any pending connection */ -void grpc_connector_shutdown(grpc_exec_ctx *exec_ctx, - grpc_connector *connector); - -#endif /* GRPC_CORE_CLIENT_CONFIG_CONNECTOR_H */ diff --git a/src/core/client_config/default_initial_connect_string.c b/src/core/client_config/default_initial_connect_string.c deleted file mode 100644 index 6a4e23e6f2..0000000000 --- a/src/core/client_config/default_initial_connect_string.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include -#include "src/core/iomgr/sockaddr.h" - -void grpc_set_default_initial_connect_string(struct sockaddr **addr, - size_t *addr_len, - gpr_slice *initial_str) {} diff --git a/src/core/client_config/initial_connect_string.c b/src/core/client_config/initial_connect_string.c deleted file mode 100644 index 19afa1675a..0000000000 --- a/src/core/client_config/initial_connect_string.c +++ /dev/null @@ -1,53 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/client_config/initial_connect_string.h" - -#include - -extern void grpc_set_default_initial_connect_string(struct sockaddr **addr, - size_t *addr_len, - gpr_slice *initial_str); - -static grpc_set_initial_connect_string_func g_set_initial_connect_string_func = - grpc_set_default_initial_connect_string; - -void grpc_test_set_initial_connect_string_function( - grpc_set_initial_connect_string_func func) { - g_set_initial_connect_string_func = func; -} - -void grpc_set_initial_connect_string(struct sockaddr **addr, size_t *addr_len, - gpr_slice *initial_str) { - g_set_initial_connect_string_func(addr, addr_len, initial_str); -} diff --git a/src/core/client_config/initial_connect_string.h b/src/core/client_config/initial_connect_string.h deleted file mode 100644 index e6d2d8f8fe..0000000000 --- a/src/core/client_config/initial_connect_string.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * - * Copyright 2015-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_CLIENT_CONFIG_INITIAL_CONNECT_STRING_H -#define GRPC_CORE_CLIENT_CONFIG_INITIAL_CONNECT_STRING_H - -#include -#include "src/core/iomgr/sockaddr.h" - -typedef void (*grpc_set_initial_connect_string_func)(struct sockaddr **addr, - size_t *addr_len, - gpr_slice *initial_str); -void grpc_test_set_initial_connect_string_function( - grpc_set_initial_connect_string_func func); - -/** Set a string to be sent once connected. Optionally reset addr. */ -void grpc_set_initial_connect_string(struct sockaddr **addr, size_t *addr_len, - gpr_slice *connect_string); - -#endif /* GRPC_CORE_CLIENT_CONFIG_INITIAL_CONNECT_STRING_H */ diff --git a/src/core/client_config/lb_policies/load_balancer_api.c b/src/core/client_config/lb_policies/load_balancer_api.c deleted file mode 100644 index a6b5785fe4..0000000000 --- a/src/core/client_config/lb_policies/load_balancer_api.c +++ /dev/null @@ -1,163 +0,0 @@ -/* - * - * 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/client_config/lb_policies/load_balancer_api.h" -#include "third_party/nanopb/pb_decode.h" -#include "third_party/nanopb/pb_encode.h" - -#include - -typedef struct decode_serverlist_arg { - int first_pass; - int i; - size_t num_servers; - grpc_grpclb_server **servers; -} decode_serverlist_arg; - -/* invoked once for every Server in ServerList */ -static bool decode_serverlist(pb_istream_t *stream, const pb_field_t *field, - void **arg) { - decode_serverlist_arg *dec_arg = *arg; - if (dec_arg->first_pass != 0) { /* first pass */ - grpc_grpclb_server server; - if (!pb_decode(stream, grpc_lb_v0_Server_fields, &server)) { - return false; - } - dec_arg->num_servers++; - } else { /* second pass */ - grpc_grpclb_server *server = gpr_malloc(sizeof(grpc_grpclb_server)); - GPR_ASSERT(dec_arg->num_servers > 0); - if (dec_arg->i == 0) { /* first iteration of second pass */ - dec_arg->servers = - gpr_malloc(sizeof(grpc_grpclb_server *) * dec_arg->num_servers); - } - if (!pb_decode(stream, grpc_lb_v0_Server_fields, server)) { - return false; - } - dec_arg->servers[dec_arg->i++] = server; - } - - return true; -} - -grpc_grpclb_request *grpc_grpclb_request_create(const char *lb_service_name) { - grpc_grpclb_request *req = gpr_malloc(sizeof(grpc_grpclb_request)); - - req->has_client_stats = 0; /* TODO(dgq): add support for stats once defined */ - req->has_initial_request = 1; - req->initial_request.has_name = 1; - strncpy(req->initial_request.name, lb_service_name, - GRPC_GRPCLB_SERVICE_NAME_MAX_LENGTH); - return req; -} - -gpr_slice grpc_grpclb_request_encode(const grpc_grpclb_request *request) { - size_t encoded_length; - pb_ostream_t sizestream; - pb_ostream_t outputstream; - gpr_slice slice; - memset(&sizestream, 0, sizeof(pb_ostream_t)); - pb_encode(&sizestream, grpc_lb_v0_LoadBalanceRequest_fields, request); - encoded_length = sizestream.bytes_written; - - slice = gpr_slice_malloc(encoded_length); - outputstream = - pb_ostream_from_buffer(GPR_SLICE_START_PTR(slice), encoded_length); - GPR_ASSERT(pb_encode(&outputstream, grpc_lb_v0_LoadBalanceRequest_fields, - request) != 0); - return slice; -} - -void grpc_grpclb_request_destroy(grpc_grpclb_request *request) { - gpr_free(request); -} - -grpc_grpclb_response *grpc_grpclb_response_parse(gpr_slice encoded_response) { - bool status; - pb_istream_t stream = - pb_istream_from_buffer(GPR_SLICE_START_PTR(encoded_response), - GPR_SLICE_LENGTH(encoded_response)); - grpc_grpclb_response *res = gpr_malloc(sizeof(grpc_grpclb_response)); - memset(res, 0, sizeof(*res)); - status = pb_decode(&stream, grpc_lb_v0_LoadBalanceResponse_fields, res); - GPR_ASSERT(status == true); - return res; -} - -grpc_grpclb_serverlist *grpc_grpclb_response_parse_serverlist( - gpr_slice encoded_response) { - grpc_grpclb_serverlist *sl = gpr_malloc(sizeof(grpc_grpclb_serverlist)); - bool status; - decode_serverlist_arg arg; - pb_istream_t stream = - pb_istream_from_buffer(GPR_SLICE_START_PTR(encoded_response), - GPR_SLICE_LENGTH(encoded_response)); - pb_istream_t stream_at_start = stream; - grpc_grpclb_response *res = gpr_malloc(sizeof(grpc_grpclb_response)); - memset(res, 0, sizeof(*res)); - memset(&arg, 0, sizeof(decode_serverlist_arg)); - - res->server_list.servers.funcs.decode = decode_serverlist; - res->server_list.servers.arg = &arg; - arg.first_pass = 1; - status = pb_decode(&stream, grpc_lb_v0_LoadBalanceResponse_fields, res); - GPR_ASSERT(status == true); - GPR_ASSERT(arg.num_servers > 0); - - arg.first_pass = 0; - status = - pb_decode(&stream_at_start, grpc_lb_v0_LoadBalanceResponse_fields, res); - GPR_ASSERT(status == true); - GPR_ASSERT(arg.servers != NULL); - - sl->num_servers = arg.num_servers; - sl->servers = arg.servers; - if (res->server_list.has_expiration_interval) { - sl->expiration_interval = res->server_list.expiration_interval; - } - grpc_grpclb_response_destroy(res); - return sl; -} - -void grpc_grpclb_destroy_serverlist(grpc_grpclb_serverlist *serverlist) { - size_t i; - for (i = 0; i < serverlist->num_servers; i++) { - gpr_free(serverlist->servers[i]); - } - gpr_free(serverlist->servers); - gpr_free(serverlist); -} - -void grpc_grpclb_response_destroy(grpc_grpclb_response *response) { - gpr_free(response); -} diff --git a/src/core/client_config/lb_policies/load_balancer_api.h b/src/core/client_config/lb_policies/load_balancer_api.h deleted file mode 100644 index b7a4c9c8f5..0000000000 --- a/src/core/client_config/lb_policies/load_balancer_api.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * - * 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_CLIENT_CONFIG_LB_POLICIES_LOAD_BALANCER_API_H -#define GRPC_CORE_CLIENT_CONFIG_LB_POLICIES_LOAD_BALANCER_API_H - -#include - -#include "src/core/client_config/lb_policy_factory.h" -#include "src/core/proto/grpc/lb/v0/load_balancer.pb.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define GRPC_GRPCLB_SERVICE_NAME_MAX_LENGTH 128 - -typedef grpc_lb_v0_LoadBalanceRequest grpc_grpclb_request; -typedef grpc_lb_v0_LoadBalanceResponse grpc_grpclb_response; -typedef grpc_lb_v0_Server grpc_grpclb_server; -typedef grpc_lb_v0_Duration grpc_grpclb_duration; -typedef struct grpc_grpclb_serverlist { - grpc_grpclb_server **servers; - size_t num_servers; - grpc_grpclb_duration expiration_interval; -} grpc_grpclb_serverlist; - -/** Create a request for a gRPC LB service under \a lb_service_name */ -grpc_grpclb_request *grpc_grpclb_request_create(const char *lb_service_name); - -/** Protocol Buffers v3-encode \a request */ -gpr_slice grpc_grpclb_request_encode(const grpc_grpclb_request *request); - -/** Destroy \a request */ -void grpc_grpclb_request_destroy(grpc_grpclb_request *request); - -/** Parse (ie, decode) the bytes in \a encoded_response as a \a - * grpc_grpclb_response */ -grpc_grpclb_response *grpc_grpclb_response_parse(gpr_slice encoded_response); - -/** Destroy \a serverlist */ -void grpc_grpclb_destroy_serverlist(grpc_grpclb_serverlist *serverlist); - -/** Parse the list of servers from an encoded \a grpc_grpclb_response */ -grpc_grpclb_serverlist *grpc_grpclb_response_parse_serverlist( - gpr_slice encoded_response); - -/** Destroy \a response */ -void grpc_grpclb_response_destroy(grpc_grpclb_response *response); - -#ifdef __cplusplus -} -#endif - -#endif /* GRPC_CORE_CLIENT_CONFIG_LB_POLICIES_LOAD_BALANCER_API_H */ diff --git a/src/core/client_config/lb_policies/pick_first.c b/src/core/client_config/lb_policies/pick_first.c deleted file mode 100644 index 2833f112f4..0000000000 --- a/src/core/client_config/lb_policies/pick_first.c +++ /dev/null @@ -1,421 +0,0 @@ -/* - * - * Copyright 2015-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/client_config/lb_policies/pick_first.h" -#include "src/core/client_config/lb_policy_factory.h" - -#include - -#include -#include "src/core/transport/connectivity_state.h" - -typedef struct pending_pick { - struct pending_pick *next; - grpc_pollset *pollset; - grpc_connected_subchannel **target; - grpc_closure *on_complete; -} pending_pick; - -typedef struct { - /** base policy: must be first */ - grpc_lb_policy base; - /** all our subchannels */ - grpc_subchannel **subchannels; - size_t num_subchannels; - - grpc_closure connectivity_changed; - - /** the selected channel (a grpc_connected_subchannel) */ - gpr_atm selected; - - /** mutex protecting remaining members */ - gpr_mu mu; - /** have we started picking? */ - int started_picking; - /** are we shut down? */ - int shutdown; - /** which subchannel are we watching? */ - size_t checking_subchannel; - /** what is the connectivity of that channel? */ - grpc_connectivity_state checking_connectivity; - /** list of picks that are waiting on connectivity */ - pending_pick *pending_picks; - - /** our connectivity state tracker */ - grpc_connectivity_state_tracker state_tracker; -} pick_first_lb_policy; - -#define GET_SELECTED(p) \ - ((grpc_connected_subchannel *)gpr_atm_acq_load(&(p)->selected)) - -void pf_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { - pick_first_lb_policy *p = (pick_first_lb_policy *)pol; - grpc_connected_subchannel *selected = GET_SELECTED(p); - size_t i; - GPR_ASSERT(p->pending_picks == NULL); - for (i = 0; i < p->num_subchannels; i++) { - GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[i], "pick_first"); - } - if (selected != NULL) { - GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, selected, "picked_first"); - } - grpc_connectivity_state_destroy(exec_ctx, &p->state_tracker); - gpr_free(p->subchannels); - gpr_mu_destroy(&p->mu); - gpr_free(p); -} - -void pf_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { - pick_first_lb_policy *p = (pick_first_lb_policy *)pol; - pending_pick *pp; - grpc_connected_subchannel *selected; - gpr_mu_lock(&p->mu); - selected = GET_SELECTED(p); - p->shutdown = 1; - pp = p->pending_picks; - p->pending_picks = NULL; - grpc_connectivity_state_set(exec_ctx, &p->state_tracker, - GRPC_CHANNEL_FATAL_FAILURE, "shutdown"); - /* cancel subscription */ - if (selected != NULL) { - grpc_connected_subchannel_notify_on_state_change( - exec_ctx, selected, NULL, NULL, &p->connectivity_changed); - } else { - grpc_subchannel_notify_on_state_change( - exec_ctx, p->subchannels[p->checking_subchannel], NULL, NULL, - &p->connectivity_changed); - } - gpr_mu_unlock(&p->mu); - while (pp != NULL) { - pending_pick *next = pp->next; - *pp->target = NULL; - grpc_pollset_set_del_pollset(exec_ctx, p->base.interested_parties, - pp->pollset); - grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL); - gpr_free(pp); - pp = next; - } -} - -static void pf_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, - grpc_connected_subchannel **target) { - pick_first_lb_policy *p = (pick_first_lb_policy *)pol; - pending_pick *pp; - gpr_mu_lock(&p->mu); - pp = p->pending_picks; - p->pending_picks = NULL; - while (pp != NULL) { - pending_pick *next = pp->next; - if (pp->target == target) { - grpc_pollset_set_del_pollset(exec_ctx, p->base.interested_parties, - pp->pollset); - *target = NULL; - grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, false, NULL); - gpr_free(pp); - } else { - pp->next = p->pending_picks; - p->pending_picks = pp; - } - pp = next; - } - gpr_mu_unlock(&p->mu); -} - -static void start_picking(grpc_exec_ctx *exec_ctx, pick_first_lb_policy *p) { - p->started_picking = 1; - p->checking_subchannel = 0; - p->checking_connectivity = GRPC_CHANNEL_IDLE; - GRPC_LB_POLICY_WEAK_REF(&p->base, "pick_first_connectivity"); - grpc_subchannel_notify_on_state_change( - exec_ctx, p->subchannels[p->checking_subchannel], - p->base.interested_parties, &p->checking_connectivity, - &p->connectivity_changed); -} - -void pf_exit_idle(grpc_exec_ctx *exec_ctx, 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(exec_ctx, p); - } - gpr_mu_unlock(&p->mu); -} - -int pf_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, grpc_pollset *pollset, - grpc_metadata_batch *initial_metadata, - grpc_connected_subchannel **target, grpc_closure *on_complete) { - pick_first_lb_policy *p = (pick_first_lb_policy *)pol; - pending_pick *pp; - - /* Check atomically for a selected channel */ - grpc_connected_subchannel *selected = GET_SELECTED(p); - if (selected != NULL) { - *target = selected; - return 1; - } - - /* No subchannel selected yet, so acquire lock and then attempt again */ - gpr_mu_lock(&p->mu); - selected = GET_SELECTED(p); - if (selected) { - gpr_mu_unlock(&p->mu); - *target = selected; - return 1; - } else { - if (!p->started_picking) { - start_picking(exec_ctx, p); - } - grpc_pollset_set_add_pollset(exec_ctx, p->base.interested_parties, pollset); - pp = gpr_malloc(sizeof(*pp)); - pp->next = p->pending_picks; - pp->pollset = pollset; - pp->target = target; - pp->on_complete = on_complete; - p->pending_picks = pp; - gpr_mu_unlock(&p->mu); - return 0; - } -} - -static void destroy_subchannels(grpc_exec_ctx *exec_ctx, void *arg, - bool iomgr_success) { - pick_first_lb_policy *p = arg; - size_t i; - size_t num_subchannels = p->num_subchannels; - grpc_subchannel **subchannels; - - gpr_mu_lock(&p->mu); - subchannels = p->subchannels; - p->num_subchannels = 0; - p->subchannels = NULL; - gpr_mu_unlock(&p->mu); - GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "destroy_subchannels"); - - for (i = 0; i < num_subchannels; i++) { - GRPC_SUBCHANNEL_UNREF(exec_ctx, subchannels[i], "pick_first"); - } - - gpr_free(subchannels); -} - -static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg, - bool iomgr_success) { - pick_first_lb_policy *p = arg; - grpc_subchannel *selected_subchannel; - pending_pick *pp; - grpc_connected_subchannel *selected; - - gpr_mu_lock(&p->mu); - - selected = GET_SELECTED(p); - - if (p->shutdown) { - gpr_mu_unlock(&p->mu); - GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "pick_first_connectivity"); - return; - } else if (selected != NULL) { - if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) { - /* if the selected channel goes bad, we're done */ - p->checking_connectivity = GRPC_CHANNEL_FATAL_FAILURE; - } - grpc_connectivity_state_set(exec_ctx, &p->state_tracker, - p->checking_connectivity, "selected_changed"); - if (p->checking_connectivity != GRPC_CHANNEL_FATAL_FAILURE) { - grpc_connected_subchannel_notify_on_state_change( - exec_ctx, selected, p->base.interested_parties, - &p->checking_connectivity, &p->connectivity_changed); - } else { - GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "pick_first_connectivity"); - } - } else { - loop: - switch (p->checking_connectivity) { - case GRPC_CHANNEL_READY: - grpc_connectivity_state_set(exec_ctx, &p->state_tracker, - GRPC_CHANNEL_READY, "connecting_ready"); - selected_subchannel = p->subchannels[p->checking_subchannel]; - selected = - grpc_subchannel_get_connected_subchannel(selected_subchannel); - GPR_ASSERT(selected != NULL); - GRPC_CONNECTED_SUBCHANNEL_REF(selected, "picked_first"); - /* drop the pick list: we are connected now */ - GRPC_LB_POLICY_WEAK_REF(&p->base, "destroy_subchannels"); - gpr_atm_rel_store(&p->selected, (gpr_atm)selected); - grpc_exec_ctx_enqueue( - exec_ctx, grpc_closure_create(destroy_subchannels, p), true, NULL); - /* update any calls that were waiting for a pick */ - while ((pp = p->pending_picks)) { - p->pending_picks = pp->next; - *pp->target = selected; - grpc_pollset_set_del_pollset(exec_ctx, p->base.interested_parties, - pp->pollset); - grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL); - gpr_free(pp); - } - grpc_connected_subchannel_notify_on_state_change( - exec_ctx, selected, p->base.interested_parties, - &p->checking_connectivity, &p->connectivity_changed); - break; - case GRPC_CHANNEL_TRANSIENT_FAILURE: - grpc_connectivity_state_set(exec_ctx, &p->state_tracker, - GRPC_CHANNEL_TRANSIENT_FAILURE, - "connecting_transient_failure"); - p->checking_subchannel = - (p->checking_subchannel + 1) % p->num_subchannels; - p->checking_connectivity = grpc_subchannel_check_connectivity( - p->subchannels[p->checking_subchannel]); - if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) { - grpc_subchannel_notify_on_state_change( - exec_ctx, p->subchannels[p->checking_subchannel], - p->base.interested_parties, &p->checking_connectivity, - &p->connectivity_changed); - } else { - goto loop; - } - break; - case GRPC_CHANNEL_CONNECTING: - case GRPC_CHANNEL_IDLE: - grpc_connectivity_state_set(exec_ctx, &p->state_tracker, - GRPC_CHANNEL_CONNECTING, - "connecting_changed"); - grpc_subchannel_notify_on_state_change( - exec_ctx, p->subchannels[p->checking_subchannel], - p->base.interested_parties, &p->checking_connectivity, - &p->connectivity_changed); - break; - case GRPC_CHANNEL_FATAL_FAILURE: - p->num_subchannels--; - GPR_SWAP(grpc_subchannel *, p->subchannels[p->checking_subchannel], - p->subchannels[p->num_subchannels]); - GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[p->num_subchannels], - "pick_first"); - if (p->num_subchannels == 0) { - grpc_connectivity_state_set(exec_ctx, &p->state_tracker, - GRPC_CHANNEL_FATAL_FAILURE, - "no_more_channels"); - while ((pp = p->pending_picks)) { - p->pending_picks = pp->next; - *pp->target = NULL; - grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL); - gpr_free(pp); - } - GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, - "pick_first_connectivity"); - } else { - grpc_connectivity_state_set(exec_ctx, &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]); - goto loop; - } - } - } - - gpr_mu_unlock(&p->mu); -} - -static grpc_connectivity_state pf_check_connectivity(grpc_exec_ctx *exec_ctx, - grpc_lb_policy *pol) { - pick_first_lb_policy *p = (pick_first_lb_policy *)pol; - grpc_connectivity_state st; - gpr_mu_lock(&p->mu); - st = grpc_connectivity_state_check(&p->state_tracker); - gpr_mu_unlock(&p->mu); - return st; -} - -void pf_notify_on_state_change(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, - grpc_connectivity_state *current, - grpc_closure *notify) { - pick_first_lb_policy *p = (pick_first_lb_policy *)pol; - gpr_mu_lock(&p->mu); - grpc_connectivity_state_notify_on_state_change(exec_ctx, &p->state_tracker, - current, notify); - gpr_mu_unlock(&p->mu); -} - -void pf_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, - grpc_closure *closure) { - pick_first_lb_policy *p = (pick_first_lb_policy *)pol; - grpc_connected_subchannel *selected = GET_SELECTED(p); - if (selected) { - grpc_connected_subchannel_ping(exec_ctx, selected, closure); - } else { - grpc_exec_ctx_enqueue(exec_ctx, closure, false, NULL); - } -} - -static const grpc_lb_policy_vtable pick_first_lb_policy_vtable = { - pf_destroy, - pf_shutdown, - pf_pick, - pf_cancel_pick, - pf_ping_one, - pf_exit_idle, - pf_check_connectivity, - pf_notify_on_state_change}; - -static void pick_first_factory_ref(grpc_lb_policy_factory *factory) {} - -static void pick_first_factory_unref(grpc_lb_policy_factory *factory) {} - -static grpc_lb_policy *create_pick_first(grpc_lb_policy_factory *factory, - grpc_lb_policy_args *args) { - if (args->num_subchannels == 0) return NULL; - pick_first_lb_policy *p = gpr_malloc(sizeof(*p)); - memset(p, 0, sizeof(*p)); - grpc_lb_policy_init(&p->base, &pick_first_lb_policy_vtable); - p->subchannels = - gpr_malloc(sizeof(grpc_subchannel *) * args->num_subchannels); - p->num_subchannels = args->num_subchannels; - grpc_connectivity_state_init(&p->state_tracker, GRPC_CHANNEL_IDLE, - "pick_first"); - memcpy(p->subchannels, args->subchannels, - sizeof(grpc_subchannel *) * args->num_subchannels); - grpc_closure_init(&p->connectivity_changed, pf_connectivity_changed, p); - gpr_mu_init(&p->mu); - return &p->base; -} - -static const grpc_lb_policy_factory_vtable pick_first_factory_vtable = { - pick_first_factory_ref, pick_first_factory_unref, create_pick_first, - "pick_first"}; - -static grpc_lb_policy_factory pick_first_lb_policy_factory = { - &pick_first_factory_vtable}; - -grpc_lb_policy_factory *grpc_pick_first_lb_factory_create() { - return &pick_first_lb_policy_factory; -} diff --git a/src/core/client_config/lb_policies/pick_first.h b/src/core/client_config/lb_policies/pick_first.h deleted file mode 100644 index 3a3f195df5..0000000000 --- a/src/core/client_config/lb_policies/pick_first.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * - * Copyright 2015-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_CLIENT_CONFIG_LB_POLICIES_PICK_FIRST_H -#define GRPC_CORE_CLIENT_CONFIG_LB_POLICIES_PICK_FIRST_H - -#include "src/core/client_config/lb_policy_factory.h" - -/** Returns a load balancing factory for the pick first policy, which picks up - * the first subchannel from \a subchannels to succesfully connect */ -grpc_lb_policy_factory *grpc_pick_first_lb_factory_create(); - -#endif /* GRPC_CORE_CLIENT_CONFIG_LB_POLICIES_PICK_FIRST_H */ diff --git a/src/core/client_config/lb_policies/round_robin.c b/src/core/client_config/lb_policies/round_robin.c deleted file mode 100644 index 114ece6e4d..0000000000 --- a/src/core/client_config/lb_policies/round_robin.c +++ /dev/null @@ -1,542 +0,0 @@ -/* - * - * Copyright 2015-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/client_config/lb_policies/round_robin.h" - -#include - -#include -#include "src/core/transport/connectivity_state.h" - -typedef struct round_robin_lb_policy round_robin_lb_policy; - -int grpc_lb_round_robin_trace = 0; - -/** List of entities waiting for a pick. - * - * Once a pick is available, \a target is updated and \a on_complete called. */ -typedef struct pending_pick { - struct pending_pick *next; - grpc_pollset *pollset; - grpc_connected_subchannel **target; - grpc_closure *on_complete; -} pending_pick; - -/** List of subchannels in a connectivity READY state */ -typedef struct ready_list { - grpc_subchannel *subchannel; - struct ready_list *next; - struct ready_list *prev; -} ready_list; - -typedef struct { - /** index within policy->subchannels */ - size_t index; - /** backpointer to owning policy */ - round_robin_lb_policy *policy; - /** subchannel itself */ - grpc_subchannel *subchannel; - /** notification that connectivity has changed on subchannel */ - grpc_closure connectivity_changed_closure; - /** this subchannels current position in subchannel->ready_list */ - ready_list *ready_list_node; - /** last observed connectivity */ - grpc_connectivity_state connectivity_state; -} subchannel_data; - -struct round_robin_lb_policy { - /** base policy: must be first */ - grpc_lb_policy base; - - /** all our subchannels */ - size_t num_subchannels; - subchannel_data **subchannels; - - /** mutex protecting remaining members */ - gpr_mu mu; - /** have we started picking? */ - int started_picking; - /** are we shutting down? */ - int shutdown; - /** List of picks that are waiting on connectivity */ - pending_pick *pending_picks; - - /** our connectivity state tracker */ - grpc_connectivity_state_tracker state_tracker; - - /** (Dummy) root of the doubly linked list containing READY subchannels */ - ready_list ready_list; - /** Last pick from the ready list. */ - ready_list *ready_list_last_pick; -}; - -/** Returns the next subchannel from the connected list or NULL if the list is - * empty. - * - * Note that this function does *not* advance p->ready_list_last_pick. Use \a - * advance_last_picked_locked() for that. */ -static ready_list *peek_next_connected_locked(const round_robin_lb_policy *p) { - ready_list *selected; - selected = p->ready_list_last_pick->next; - - while (selected != NULL) { - if (selected == &p->ready_list) { - GPR_ASSERT(selected->subchannel == NULL); - /* skip dummy root */ - selected = selected->next; - } else { - GPR_ASSERT(selected->subchannel != NULL); - return selected; - } - } - return NULL; -} - -/** Advance the \a ready_list picking head. */ -static void advance_last_picked_locked(round_robin_lb_policy *p) { - if (p->ready_list_last_pick->next != NULL) { /* non-empty list */ - p->ready_list_last_pick = p->ready_list_last_pick->next; - if (p->ready_list_last_pick == &p->ready_list) { - /* skip dummy root */ - p->ready_list_last_pick = p->ready_list_last_pick->next; - } - } else { /* should be an empty list */ - GPR_ASSERT(p->ready_list_last_pick == &p->ready_list); - } - - if (grpc_lb_round_robin_trace) { - gpr_log(GPR_DEBUG, "[READYLIST] ADVANCED LAST PICK. NOW AT NODE %p (SC %p)", - p->ready_list_last_pick, p->ready_list_last_pick->subchannel); - } -} - -/** Prepends (relative to the root at p->ready_list) the connected subchannel \a - * csc to the list of ready subchannels. */ -static ready_list *add_connected_sc_locked(round_robin_lb_policy *p, - grpc_subchannel *sc) { - ready_list *new_elem = gpr_malloc(sizeof(ready_list)); - new_elem->subchannel = sc; - if (p->ready_list.prev == NULL) { - /* first element */ - new_elem->next = &p->ready_list; - new_elem->prev = &p->ready_list; - p->ready_list.next = new_elem; - p->ready_list.prev = new_elem; - } else { - new_elem->next = &p->ready_list; - new_elem->prev = p->ready_list.prev; - p->ready_list.prev->next = new_elem; - p->ready_list.prev = new_elem; - } - if (grpc_lb_round_robin_trace) { - gpr_log(GPR_DEBUG, "[READYLIST] ADDING NODE %p (SC %p)", new_elem, sc); - } - return new_elem; -} - -/** Removes \a node from the list of connected subchannels */ -static void remove_disconnected_sc_locked(round_robin_lb_policy *p, - ready_list *node) { - if (node == NULL) { - 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; - } - - /* removing last item */ - if (node->next == &p->ready_list && node->prev == &p->ready_list) { - GPR_ASSERT(p->ready_list.next == node); - GPR_ASSERT(p->ready_list.prev == node); - p->ready_list.next = NULL; - p->ready_list.prev = NULL; - } else { - node->prev->next = node->next; - node->next->prev = node->prev; - } - - if (grpc_lb_round_robin_trace) { - gpr_log(GPR_DEBUG, "[READYLIST] REMOVED NODE %p (SC %p)", node, - node->subchannel); - } - - node->next = NULL; - node->prev = NULL; - node->subchannel = NULL; - - gpr_free(node); -} - -void rr_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { - round_robin_lb_policy *p = (round_robin_lb_policy *)pol; - size_t i; - ready_list *elem; - for (i = 0; i < p->num_subchannels; i++) { - subchannel_data *sd = p->subchannels[i]; - GRPC_SUBCHANNEL_UNREF(exec_ctx, sd->subchannel, "round_robin"); - gpr_free(sd); - } - - grpc_connectivity_state_destroy(exec_ctx, &p->state_tracker); - gpr_free(p->subchannels); - gpr_mu_destroy(&p->mu); - - elem = p->ready_list.next; - while (elem != NULL && elem != &p->ready_list) { - ready_list *tmp; - tmp = elem->next; - elem->next = NULL; - elem->prev = NULL; - elem->subchannel = NULL; - gpr_free(elem); - elem = tmp; - } - gpr_free(p); -} - -void rr_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { - round_robin_lb_policy *p = (round_robin_lb_policy *)pol; - pending_pick *pp; - size_t i; - - gpr_mu_lock(&p->mu); - - p->shutdown = 1; - while ((pp = p->pending_picks)) { - p->pending_picks = pp->next; - *pp->target = NULL; - grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, false, NULL); - gpr_free(pp); - } - grpc_connectivity_state_set(exec_ctx, &p->state_tracker, - GRPC_CHANNEL_FATAL_FAILURE, "shutdown"); - for (i = 0; i < p->num_subchannels; i++) { - subchannel_data *sd = p->subchannels[i]; - grpc_subchannel_notify_on_state_change(exec_ctx, sd->subchannel, NULL, NULL, - &sd->connectivity_changed_closure); - } - gpr_mu_unlock(&p->mu); -} - -static void rr_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, - grpc_connected_subchannel **target) { - round_robin_lb_policy *p = (round_robin_lb_policy *)pol; - pending_pick *pp; - gpr_mu_lock(&p->mu); - pp = p->pending_picks; - p->pending_picks = NULL; - while (pp != NULL) { - pending_pick *next = pp->next; - if (pp->target == target) { - grpc_pollset_set_del_pollset(exec_ctx, p->base.interested_parties, - pp->pollset); - *target = NULL; - grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, false, NULL); - gpr_free(pp); - } else { - pp->next = p->pending_picks; - p->pending_picks = pp; - } - pp = next; - } - gpr_mu_unlock(&p->mu); -} - -static void start_picking(grpc_exec_ctx *exec_ctx, round_robin_lb_policy *p) { - size_t i; - p->started_picking = 1; - - gpr_log(GPR_DEBUG, "LB_POLICY: p=%p num_subchannels=%d", p, - p->num_subchannels); - - for (i = 0; i < p->num_subchannels; i++) { - subchannel_data *sd = p->subchannels[i]; - sd->connectivity_state = GRPC_CHANNEL_IDLE; - grpc_subchannel_notify_on_state_change( - exec_ctx, sd->subchannel, p->base.interested_parties, - &sd->connectivity_state, &sd->connectivity_changed_closure); - GRPC_LB_POLICY_WEAK_REF(&p->base, "round_robin_connectivity"); - } -} - -void rr_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { - round_robin_lb_policy *p = (round_robin_lb_policy *)pol; - gpr_mu_lock(&p->mu); - if (!p->started_picking) { - start_picking(exec_ctx, p); - } - gpr_mu_unlock(&p->mu); -} - -int rr_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, grpc_pollset *pollset, - grpc_metadata_batch *initial_metadata, - grpc_connected_subchannel **target, grpc_closure *on_complete) { - round_robin_lb_policy *p = (round_robin_lb_policy *)pol; - pending_pick *pp; - ready_list *selected; - gpr_mu_lock(&p->mu); - if ((selected = peek_next_connected_locked(p))) { - gpr_mu_unlock(&p->mu); - *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); - } - /* only advance the last picked pointer if the selection was used */ - advance_last_picked_locked(p); - return 1; - } else { - if (!p->started_picking) { - start_picking(exec_ctx, p); - } - grpc_pollset_set_add_pollset(exec_ctx, p->base.interested_parties, pollset); - pp = gpr_malloc(sizeof(*pp)); - pp->next = p->pending_picks; - pp->pollset = pollset; - pp->target = target; - pp->on_complete = on_complete; - p->pending_picks = pp; - gpr_mu_unlock(&p->mu); - return 0; - } -} - -static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg, - bool iomgr_success) { - subchannel_data *sd = arg; - round_robin_lb_policy *p = sd->policy; - pending_pick *pp; - ready_list *selected; - - int unref = 0; - - gpr_mu_lock(&p->mu); - - if (p->shutdown) { - unref = 1; - } else { - switch (sd->connectivity_state) { - case GRPC_CHANNEL_READY: - grpc_connectivity_state_set(exec_ctx, &p->state_tracker, - GRPC_CHANNEL_READY, "connecting_ready"); - /* add the newly connected subchannel to the list of connected ones. - * Note that it goes to the "end of the line". */ - sd->ready_list_node = add_connected_sc_locked(p, sd->subchannel); - /* at this point we know there's at least one suitable subchannel. Go - * ahead and pick one and notify the pending suitors in - * p->pending_picks. This preemtively replicates rr_pick()'s actions. */ - selected = peek_next_connected_locked(p); - if (p->pending_picks != NULL) { - /* if the selected subchannel is going to be used for the pending - * picks, update the last picked pointer */ - advance_last_picked_locked(p); - } - while ((pp = p->pending_picks)) { - p->pending_picks = pp->next; - *pp->target = - grpc_subchannel_get_connected_subchannel(selected->subchannel); - if (grpc_lb_round_robin_trace) { - gpr_log(GPR_DEBUG, - "[RR CONN CHANGED] TARGET <-- SUBCHANNEL %p (NODE %p)", - selected->subchannel, selected); - } - grpc_pollset_set_del_pollset(exec_ctx, p->base.interested_parties, - pp->pollset); - grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL); - gpr_free(pp); - } - grpc_subchannel_notify_on_state_change( - exec_ctx, sd->subchannel, p->base.interested_parties, - &sd->connectivity_state, &sd->connectivity_changed_closure); - break; - case GRPC_CHANNEL_CONNECTING: - case GRPC_CHANNEL_IDLE: - grpc_connectivity_state_set(exec_ctx, &p->state_tracker, - sd->connectivity_state, - "connecting_changed"); - grpc_subchannel_notify_on_state_change( - exec_ctx, sd->subchannel, p->base.interested_parties, - &sd->connectivity_state, &sd->connectivity_changed_closure); - break; - case GRPC_CHANNEL_TRANSIENT_FAILURE: - /* renew state notification */ - grpc_subchannel_notify_on_state_change( - exec_ctx, sd->subchannel, p->base.interested_parties, - &sd->connectivity_state, &sd->connectivity_changed_closure); - - /* remove from ready list if still present */ - if (sd->ready_list_node != NULL) { - remove_disconnected_sc_locked(p, sd->ready_list_node); - sd->ready_list_node = NULL; - } - grpc_connectivity_state_set(exec_ctx, &p->state_tracker, - GRPC_CHANNEL_TRANSIENT_FAILURE, - "connecting_transient_failure"); - break; - case GRPC_CHANNEL_FATAL_FAILURE: - if (sd->ready_list_node != NULL) { - remove_disconnected_sc_locked(p, sd->ready_list_node); - sd->ready_list_node = NULL; - } - - p->num_subchannels--; - GPR_SWAP(subchannel_data *, p->subchannels[sd->index], - p->subchannels[p->num_subchannels]); - GRPC_SUBCHANNEL_UNREF(exec_ctx, sd->subchannel, "round_robin"); - p->subchannels[sd->index]->index = sd->index; - gpr_free(sd); - - unref = 1; - if (p->num_subchannels == 0) { - grpc_connectivity_state_set(exec_ctx, &p->state_tracker, - GRPC_CHANNEL_FATAL_FAILURE, - "no_more_channels"); - while ((pp = p->pending_picks)) { - p->pending_picks = pp->next; - *pp->target = NULL; - grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL); - gpr_free(pp); - } - } else { - grpc_connectivity_state_set(exec_ctx, &p->state_tracker, - GRPC_CHANNEL_TRANSIENT_FAILURE, - "subchannel_failed"); - } - } /* switch */ - } /* !unref */ - - gpr_mu_unlock(&p->mu); - - if (unref) { - GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "round_robin_connectivity"); - } -} - -static grpc_connectivity_state rr_check_connectivity(grpc_exec_ctx *exec_ctx, - grpc_lb_policy *pol) { - round_robin_lb_policy *p = (round_robin_lb_policy *)pol; - grpc_connectivity_state st; - gpr_mu_lock(&p->mu); - st = grpc_connectivity_state_check(&p->state_tracker); - gpr_mu_unlock(&p->mu); - return st; -} - -static void rr_notify_on_state_change(grpc_exec_ctx *exec_ctx, - grpc_lb_policy *pol, - grpc_connectivity_state *current, - grpc_closure *notify) { - round_robin_lb_policy *p = (round_robin_lb_policy *)pol; - gpr_mu_lock(&p->mu); - grpc_connectivity_state_notify_on_state_change(exec_ctx, &p->state_tracker, - current, notify); - gpr_mu_unlock(&p->mu); -} - -static void rr_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, - grpc_closure *closure) { - round_robin_lb_policy *p = (round_robin_lb_policy *)pol; - ready_list *selected; - grpc_connected_subchannel *target; - gpr_mu_lock(&p->mu); - if ((selected = peek_next_connected_locked(p))) { - gpr_mu_unlock(&p->mu); - target = grpc_subchannel_get_connected_subchannel(selected->subchannel); - grpc_connected_subchannel_ping(exec_ctx, target, closure); - } else { - gpr_mu_unlock(&p->mu); - grpc_exec_ctx_enqueue(exec_ctx, closure, false, NULL); - } -} - -static const grpc_lb_policy_vtable round_robin_lb_policy_vtable = { - rr_destroy, - rr_shutdown, - rr_pick, - rr_cancel_pick, - rr_ping_one, - rr_exit_idle, - rr_check_connectivity, - rr_notify_on_state_change}; - -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_lb_policy_factory *factory, - grpc_lb_policy_args *args) { - size_t i; - round_robin_lb_policy *p = gpr_malloc(sizeof(*p)); - GPR_ASSERT(args->num_subchannels > 0); - memset(p, 0, sizeof(*p)); - grpc_lb_policy_init(&p->base, &round_robin_lb_policy_vtable); - p->num_subchannels = args->num_subchannels; - p->subchannels = gpr_malloc(sizeof(*p->subchannels) * p->num_subchannels); - memset(p->subchannels, 0, sizeof(*p->subchannels) * p->num_subchannels); - grpc_connectivity_state_init(&p->state_tracker, GRPC_CHANNEL_IDLE, - "round_robin"); - - gpr_mu_init(&p->mu); - for (i = 0; i < args->num_subchannels; i++) { - subchannel_data *sd = gpr_malloc(sizeof(*sd)); - memset(sd, 0, sizeof(*sd)); - p->subchannels[i] = sd; - sd->policy = p; - sd->index = i; - sd->subchannel = args->subchannels[i]; - grpc_closure_init(&sd->connectivity_changed_closure, - rr_connectivity_changed, sd); - } - - /* The (dummy node) root of the ready list */ - p->ready_list.subchannel = NULL; - p->ready_list.prev = NULL; - p->ready_list.next = NULL; - p->ready_list_last_pick = &p->ready_list; - - return &p->base; -} - -static const grpc_lb_policy_factory_vtable round_robin_factory_vtable = { - round_robin_factory_ref, round_robin_factory_unref, create_round_robin, - "round_robin"}; - -static grpc_lb_policy_factory round_robin_lb_policy_factory = { - &round_robin_factory_vtable}; - -grpc_lb_policy_factory *grpc_round_robin_lb_factory_create() { - return &round_robin_lb_policy_factory; -} diff --git a/src/core/client_config/lb_policies/round_robin.h b/src/core/client_config/lb_policies/round_robin.h deleted file mode 100644 index 7e6f1769e4..0000000000 --- a/src/core/client_config/lb_policies/round_robin.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * - * Copyright 2015-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_CLIENT_CONFIG_LB_POLICIES_ROUND_ROBIN_H -#define GRPC_CORE_CLIENT_CONFIG_LB_POLICIES_ROUND_ROBIN_H - -#include "src/core/client_config/lb_policy.h" - -extern int grpc_lb_round_robin_trace; - -#include "src/core/client_config/lb_policy_factory.h" - -/** Returns a load balancing factory for the round robin policy */ -grpc_lb_policy_factory *grpc_round_robin_lb_factory_create(); - -#endif /* GRPC_CORE_CLIENT_CONFIG_LB_POLICIES_ROUND_ROBIN_H */ diff --git a/src/core/client_config/lb_policy.c b/src/core/client_config/lb_policy.c deleted file mode 100644 index 0d8b007336..0000000000 --- a/src/core/client_config/lb_policy.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * - * Copyright 2015-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/client_config/lb_policy.h" - -#define WEAK_REF_BITS 16 - -void grpc_lb_policy_init(grpc_lb_policy *policy, - const grpc_lb_policy_vtable *vtable) { - policy->vtable = vtable; - gpr_atm_no_barrier_store(&policy->ref_pair, 1 << WEAK_REF_BITS); - policy->interested_parties = grpc_pollset_set_create(); -} - -#ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG -#define REF_FUNC_EXTRA_ARGS , const char *file, int line, const char *reason -#define REF_MUTATE_EXTRA_ARGS REF_FUNC_EXTRA_ARGS, const char *purpose -#define REF_FUNC_PASS_ARGS(new_reason) , file, line, new_reason -#define REF_MUTATE_PASS_ARGS(purpose) , file, line, reason, purpose -#else -#define REF_FUNC_EXTRA_ARGS -#define REF_MUTATE_EXTRA_ARGS -#define REF_FUNC_PASS_ARGS(new_reason) -#define REF_MUTATE_PASS_ARGS(x) -#endif - -static gpr_atm ref_mutate(grpc_lb_policy *c, gpr_atm delta, - int barrier REF_MUTATE_EXTRA_ARGS) { - gpr_atm old_val = barrier ? gpr_atm_full_fetch_add(&c->ref_pair, delta) - : gpr_atm_no_barrier_fetch_add(&c->ref_pair, delta); -#ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, - "LB_POLICY: %p % 12s 0x%08x -> 0x%08x [%s]", c, purpose, old_val, - old_val + delta, reason); -#endif - return old_val; -} - -void grpc_lb_policy_ref(grpc_lb_policy *policy REF_FUNC_EXTRA_ARGS) { - ref_mutate(policy, 1 << WEAK_REF_BITS, 0 REF_MUTATE_PASS_ARGS("STRONG_REF")); -} - -void grpc_lb_policy_unref(grpc_exec_ctx *exec_ctx, - grpc_lb_policy *policy REF_FUNC_EXTRA_ARGS) { - gpr_atm old_val = - ref_mutate(policy, (gpr_atm)1 - (gpr_atm)(1 << WEAK_REF_BITS), - 1 REF_MUTATE_PASS_ARGS("STRONG_UNREF")); - gpr_atm mask = ~(gpr_atm)((1 << WEAK_REF_BITS) - 1); - gpr_atm check = 1 << WEAK_REF_BITS; - if ((old_val & mask) == check) { - policy->vtable->shutdown(exec_ctx, policy); - } - grpc_lb_policy_weak_unref(exec_ctx, - policy REF_FUNC_PASS_ARGS("strong-unref")); -} - -void grpc_lb_policy_weak_ref(grpc_lb_policy *policy REF_FUNC_EXTRA_ARGS) { - ref_mutate(policy, 1, 0 REF_MUTATE_PASS_ARGS("WEAK_REF")); -} - -void grpc_lb_policy_weak_unref(grpc_exec_ctx *exec_ctx, - grpc_lb_policy *policy REF_FUNC_EXTRA_ARGS) { - gpr_atm old_val = - ref_mutate(policy, -(gpr_atm)1, 1 REF_MUTATE_PASS_ARGS("WEAK_UNREF")); - if (old_val == 1) { - grpc_pollset_set_destroy(policy->interested_parties); - policy->vtable->destroy(exec_ctx, policy); - } -} - -int grpc_lb_policy_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, - grpc_pollset *pollset, - grpc_metadata_batch *initial_metadata, - grpc_connected_subchannel **target, - grpc_closure *on_complete) { - return policy->vtable->pick(exec_ctx, policy, pollset, initial_metadata, - target, on_complete); -} - -void grpc_lb_policy_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, - grpc_connected_subchannel **target) { - policy->vtable->cancel_pick(exec_ctx, policy, target); -} - -void grpc_lb_policy_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy) { - policy->vtable->exit_idle(exec_ctx, policy); -} - -void grpc_lb_policy_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, - grpc_closure *closure) { - policy->vtable->ping_one(exec_ctx, policy, closure); -} - -void grpc_lb_policy_notify_on_state_change(grpc_exec_ctx *exec_ctx, - grpc_lb_policy *policy, - grpc_connectivity_state *state, - grpc_closure *closure) { - policy->vtable->notify_on_state_change(exec_ctx, policy, state, closure); -} - -grpc_connectivity_state grpc_lb_policy_check_connectivity( - grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy) { - return policy->vtable->check_connectivity(exec_ctx, policy); -} diff --git a/src/core/client_config/lb_policy.h b/src/core/client_config/lb_policy.h deleted file mode 100644 index ffebc2a69c..0000000000 --- a/src/core/client_config/lb_policy.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * - * Copyright 2015-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_CLIENT_CONFIG_LB_POLICY_H -#define GRPC_CORE_CLIENT_CONFIG_LB_POLICY_H - -#include "src/core/client_config/subchannel.h" -#include "src/core/transport/connectivity_state.h" - -/** A load balancing policy: specified by a vtable and a struct (which - is expected to be extended to contain some parameters) */ -typedef struct grpc_lb_policy grpc_lb_policy; -typedef struct grpc_lb_policy_vtable grpc_lb_policy_vtable; - -typedef void (*grpc_lb_completion)(void *cb_arg, grpc_subchannel *subchannel, - grpc_status_code status, const char *errmsg); - -struct grpc_lb_policy { - const grpc_lb_policy_vtable *vtable; - gpr_atm ref_pair; - /* owned pointer to interested parties in load balancing decisions */ - grpc_pollset_set *interested_parties; -}; - -struct grpc_lb_policy_vtable { - void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy); - - void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy); - - /** implement grpc_lb_policy_pick */ - int (*pick)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, - grpc_pollset *pollset, grpc_metadata_batch *initial_metadata, - grpc_connected_subchannel **target, grpc_closure *on_complete); - void (*cancel_pick)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, - grpc_connected_subchannel **target); - - void (*ping_one)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, - grpc_closure *closure); - - /** try to enter a READY connectivity state */ - void (*exit_idle)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy); - - /** check the current connectivity of the lb_policy */ - grpc_connectivity_state (*check_connectivity)(grpc_exec_ctx *exec_ctx, - grpc_lb_policy *policy); - - /** call notify when the connectivity state of a channel changes from *state. - Updates *state with the new state of the policy */ - void (*notify_on_state_change)(grpc_exec_ctx *exec_ctx, - grpc_lb_policy *policy, - grpc_connectivity_state *state, - grpc_closure *closure); -}; - -/*#define GRPC_LB_POLICY_REFCOUNT_DEBUG*/ -#ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG -#define GRPC_LB_POLICY_REF(p, r) \ - grpc_lb_policy_ref((p), __FILE__, __LINE__, (r)) -#define GRPC_LB_POLICY_UNREF(exec_ctx, p, r) \ - grpc_lb_policy_unref((exec_ctx), (p), __FILE__, __LINE__, (r)) -#define GRPC_LB_POLICY_WEAK_REF(p, r) \ - grpc_lb_policy_weak_ref((p), __FILE__, __LINE__, (r)) -#define GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, p, r) \ - grpc_lb_policy_weak_unref((exec_ctx), (p), __FILE__, __LINE__, (r)) -void grpc_lb_policy_ref(grpc_lb_policy *policy, const char *file, int line, - const char *reason); -void grpc_lb_policy_unref(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, - const char *file, int line, const char *reason); -void grpc_lb_policy_weak_ref(grpc_lb_policy *policy, const char *file, int line, - const char *reason); -void grpc_lb_policy_weak_unref(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, - const char *file, int line, const char *reason); -#else -#define GRPC_LB_POLICY_REF(p, r) grpc_lb_policy_ref((p)) -#define GRPC_LB_POLICY_UNREF(cl, p, r) grpc_lb_policy_unref((cl), (p)) -#define GRPC_LB_POLICY_WEAK_REF(p, r) grpc_lb_policy_weak_ref((p)) -#define GRPC_LB_POLICY_WEAK_UNREF(cl, p, r) grpc_lb_policy_weak_unref((cl), (p)) -void grpc_lb_policy_ref(grpc_lb_policy *policy); -void grpc_lb_policy_unref(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy); -void grpc_lb_policy_weak_ref(grpc_lb_policy *policy); -void grpc_lb_policy_weak_unref(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy); -#endif - -/** called by concrete implementations to initialize the base struct */ -void grpc_lb_policy_init(grpc_lb_policy *policy, - const grpc_lb_policy_vtable *vtable); - -/** Given initial metadata in \a initial_metadata, find an appropriate - target for this rpc, and 'return' it by calling \a on_complete after setting - \a target. - Picking can be asynchronous. Any IO should be done under \a pollset. */ -int grpc_lb_policy_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, - grpc_pollset *pollset, - grpc_metadata_batch *initial_metadata, - grpc_connected_subchannel **target, - grpc_closure *on_complete); - -void grpc_lb_policy_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, - grpc_closure *closure); - -void grpc_lb_policy_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, - grpc_connected_subchannel **target); - -void grpc_lb_policy_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy); - -void grpc_lb_policy_notify_on_state_change(grpc_exec_ctx *exec_ctx, - grpc_lb_policy *policy, - grpc_connectivity_state *state, - grpc_closure *closure); - -grpc_connectivity_state grpc_lb_policy_check_connectivity( - grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy); - -#endif /* GRPC_CORE_CLIENT_CONFIG_LB_POLICY_H */ diff --git a/src/core/client_config/lb_policy_factory.c b/src/core/client_config/lb_policy_factory.c deleted file mode 100644 index e49de544e3..0000000000 --- a/src/core/client_config/lb_policy_factory.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/client_config/lb_policy_factory.h" - -void grpc_lb_policy_factory_ref(grpc_lb_policy_factory* factory) { - factory->vtable->ref(factory); -} - -void grpc_lb_policy_factory_unref(grpc_lb_policy_factory* factory) { - factory->vtable->unref(factory); -} - -grpc_lb_policy* grpc_lb_policy_factory_create_lb_policy( - grpc_lb_policy_factory* factory, grpc_lb_policy_args* args) { - if (factory == NULL) return NULL; - return factory->vtable->create_lb_policy(factory, args); -} diff --git a/src/core/client_config/lb_policy_factory.h b/src/core/client_config/lb_policy_factory.h deleted file mode 100644 index 842ba96098..0000000000 --- a/src/core/client_config/lb_policy_factory.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * - * Copyright 2015-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_CLIENT_CONFIG_LB_POLICY_FACTORY_H -#define GRPC_CORE_CLIENT_CONFIG_LB_POLICY_FACTORY_H - -#include "src/core/client_config/lb_policy.h" -#include "src/core/client_config/subchannel.h" - -typedef struct grpc_lb_policy_factory grpc_lb_policy_factory; -typedef struct grpc_lb_policy_factory_vtable grpc_lb_policy_factory_vtable; - -/** grpc_lb_policy provides grpc_client_config objects to grpc_channel - objects */ -struct grpc_lb_policy_factory { - const grpc_lb_policy_factory_vtable *vtable; -}; - -typedef struct grpc_lb_policy_args { - grpc_subchannel **subchannels; - size_t num_subchannels; -} grpc_lb_policy_args; - -struct grpc_lb_policy_factory_vtable { - void (*ref)(grpc_lb_policy_factory *factory); - void (*unref)(grpc_lb_policy_factory *factory); - - /** Implementation of grpc_lb_policy_factory_create_lb_policy */ - grpc_lb_policy *(*create_lb_policy)(grpc_lb_policy_factory *factory, - grpc_lb_policy_args *args); - - /** Name for the LB policy this factory implements */ - const char *name; -}; - -void grpc_lb_policy_factory_ref(grpc_lb_policy_factory *factory); -void grpc_lb_policy_factory_unref(grpc_lb_policy_factory *factory); - -/** Create a lb_policy instance. */ -grpc_lb_policy *grpc_lb_policy_factory_create_lb_policy( - grpc_lb_policy_factory *factory, grpc_lb_policy_args *args); - -#endif /* GRPC_CORE_CLIENT_CONFIG_LB_POLICY_FACTORY_H */ diff --git a/src/core/client_config/lb_policy_registry.c b/src/core/client_config/lb_policy_registry.c deleted file mode 100644 index fc302e82d7..0000000000 --- a/src/core/client_config/lb_policy_registry.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/client_config/lb_policy_registry.h" - -#include - -#define MAX_POLICIES 10 - -static grpc_lb_policy_factory *g_all_of_the_lb_policies[MAX_POLICIES]; -static int g_number_of_lb_policies = 0; - -static grpc_lb_policy_factory *g_default_lb_policy_factory; - -void grpc_lb_policy_registry_init(grpc_lb_policy_factory *default_factory) { - g_number_of_lb_policies = 0; - g_default_lb_policy_factory = default_factory; -} - -void grpc_lb_policy_registry_shutdown(void) { - int i; - for (i = 0; i < g_number_of_lb_policies; i++) { - grpc_lb_policy_factory_unref(g_all_of_the_lb_policies[i]); - } -} - -void grpc_register_lb_policy(grpc_lb_policy_factory *factory) { - int i; - for (i = 0; i < g_number_of_lb_policies; i++) { - GPR_ASSERT(0 != strcmp(factory->vtable->name, - g_all_of_the_lb_policies[i]->vtable->name)); - } - GPR_ASSERT(g_number_of_lb_policies != MAX_POLICIES); - grpc_lb_policy_factory_ref(factory); - g_all_of_the_lb_policies[g_number_of_lb_policies++] = factory; -} - -static grpc_lb_policy_factory *lookup_factory(const char *name) { - int i; - - if (name == NULL) return NULL; - - for (i = 0; i < g_number_of_lb_policies; i++) { - if (0 == strcmp(name, g_all_of_the_lb_policies[i]->vtable->name)) { - return g_all_of_the_lb_policies[i]; - } - } - - return NULL; -} - -grpc_lb_policy *grpc_lb_policy_create(const char *name, - grpc_lb_policy_args *args) { - grpc_lb_policy_factory *factory = lookup_factory(name); - grpc_lb_policy *lb_policy = - grpc_lb_policy_factory_create_lb_policy(factory, args); - return lb_policy; -} diff --git a/src/core/client_config/lb_policy_registry.h b/src/core/client_config/lb_policy_registry.h deleted file mode 100644 index f3a08a3558..0000000000 --- a/src/core/client_config/lb_policy_registry.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * - * Copyright 2015-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_CLIENT_CONFIG_LB_POLICY_REGISTRY_H -#define GRPC_CORE_CLIENT_CONFIG_LB_POLICY_REGISTRY_H - -#include "src/core/client_config/lb_policy_factory.h" - -/** Initialize the registry and set \a default_factory as the factory to be - * returned when no name is provided in a lookup */ -void grpc_lb_policy_registry_init(grpc_lb_policy_factory *default_factory); -void grpc_lb_policy_registry_shutdown(void); - -/** Register a LB policy factory. */ -void grpc_register_lb_policy(grpc_lb_policy_factory *factory); - -/** Create a \a grpc_lb_policy instance. - * - * If \a name is NULL, the default factory from \a grpc_lb_policy_registry_init - * will be returned. */ -grpc_lb_policy *grpc_lb_policy_create(const char *name, - grpc_lb_policy_args *args); - -#endif /* GRPC_CORE_CLIENT_CONFIG_LB_POLICY_REGISTRY_H */ diff --git a/src/core/client_config/resolver.c b/src/core/client_config/resolver.c deleted file mode 100644 index eda01e72ba..0000000000 --- a/src/core/client_config/resolver.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/client_config/resolver.h" - -void grpc_resolver_init(grpc_resolver *resolver, - const grpc_resolver_vtable *vtable) { - resolver->vtable = vtable; - gpr_ref_init(&resolver->refs, 1); -} - -#ifdef GRPC_RESOLVER_REFCOUNT_DEBUG -void grpc_resolver_ref(grpc_resolver *resolver, grpc_closure_list *closure_list, - const char *file, int line, const char *reason) { - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "RESOLVER:%p ref %d -> %d %s", - resolver, (int)resolver->refs.count, (int)resolver->refs.count + 1, - reason); -#else -void grpc_resolver_ref(grpc_resolver *resolver) { -#endif - gpr_ref(&resolver->refs); -} - -#ifdef GRPC_RESOLVER_REFCOUNT_DEBUG -void grpc_resolver_unref(grpc_resolver *resolver, - grpc_closure_list *closure_list, const char *file, - int line, const char *reason) { - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "RESOLVER:%p unref %d -> %d %s", - resolver, (int)resolver->refs.count, (int)resolver->refs.count - 1, - reason); -#else -void grpc_resolver_unref(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver) { -#endif - if (gpr_unref(&resolver->refs)) { - resolver->vtable->destroy(exec_ctx, resolver); - } -} - -void grpc_resolver_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver) { - resolver->vtable->shutdown(exec_ctx, resolver); -} - -void grpc_resolver_channel_saw_error(grpc_exec_ctx *exec_ctx, - grpc_resolver *resolver) { - resolver->vtable->channel_saw_error(exec_ctx, resolver); -} - -void grpc_resolver_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver, - grpc_client_config **target_config, - grpc_closure *on_complete) { - resolver->vtable->next(exec_ctx, resolver, target_config, on_complete); -} diff --git a/src/core/client_config/resolver.h b/src/core/client_config/resolver.h deleted file mode 100644 index 96f88fef84..0000000000 --- a/src/core/client_config/resolver.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * - * Copyright 2015-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_CLIENT_CONFIG_RESOLVER_H -#define GRPC_CORE_CLIENT_CONFIG_RESOLVER_H - -#include "src/core/client_config/client_config.h" -#include "src/core/client_config/subchannel.h" -#include "src/core/iomgr/iomgr.h" - -typedef struct grpc_resolver grpc_resolver; -typedef struct grpc_resolver_vtable grpc_resolver_vtable; - -/** grpc_resolver provides grpc_client_config objects to grpc_channel - objects */ -struct grpc_resolver { - const grpc_resolver_vtable *vtable; - gpr_refcount refs; -}; - -struct grpc_resolver_vtable { - void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver); - void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver); - void (*channel_saw_error)(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver); - void (*next)(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver, - grpc_client_config **target_config, grpc_closure *on_complete); -}; - -#ifdef GRPC_RESOLVER_REFCOUNT_DEBUG -#define GRPC_RESOLVER_REF(p, r) grpc_resolver_ref((p), __FILE__, __LINE__, (r)) -#define GRPC_RESOLVER_UNREF(cl, p, r) \ - grpc_resolver_unref((cl), (p), __FILE__, __LINE__, (r)) -void grpc_resolver_ref(grpc_resolver *policy, const char *file, int line, - const char *reason); -void grpc_resolver_unref(grpc_resolver *policy, grpc_closure_list *closure_list, - const char *file, int line, const char *reason); -#else -#define GRPC_RESOLVER_REF(p, r) grpc_resolver_ref((p)) -#define GRPC_RESOLVER_UNREF(cl, p, r) grpc_resolver_unref((cl), (p)) -void grpc_resolver_ref(grpc_resolver *policy); -void grpc_resolver_unref(grpc_exec_ctx *exec_ctx, grpc_resolver *policy); -#endif - -void grpc_resolver_init(grpc_resolver *resolver, - const grpc_resolver_vtable *vtable); - -void grpc_resolver_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver); - -/** Notification that the channel has seen an error on some address. - Can be used as a hint that re-resolution is desirable soon. */ -void grpc_resolver_channel_saw_error(grpc_exec_ctx *exec_ctx, - grpc_resolver *resolver); - -/** Get the next client config. Called by the channel to fetch a new - configuration. Expected to set *target_config with a new configuration, - and then schedule on_complete for execution. - - If resolution is fatally broken, set *target_config to NULL and - schedule on_complete. */ -void grpc_resolver_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver, - grpc_client_config **target_config, - grpc_closure *on_complete); - -#endif /* GRPC_CORE_CLIENT_CONFIG_RESOLVER_H */ diff --git a/src/core/client_config/resolver_factory.c b/src/core/client_config/resolver_factory.c deleted file mode 100644 index e7e9196ac4..0000000000 --- a/src/core/client_config/resolver_factory.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/client_config/resolver_factory.h" - -void grpc_resolver_factory_ref(grpc_resolver_factory* factory) { - factory->vtable->ref(factory); -} - -void grpc_resolver_factory_unref(grpc_resolver_factory* factory) { - factory->vtable->unref(factory); -} - -/** Create a resolver instance for a name */ -grpc_resolver* grpc_resolver_factory_create_resolver( - grpc_resolver_factory* factory, grpc_resolver_args* args) { - if (factory == NULL) return NULL; - return factory->vtable->create_resolver(factory, args); -} - -char* grpc_resolver_factory_get_default_authority( - grpc_resolver_factory* factory, grpc_uri* uri) { - if (factory == NULL) return NULL; - return factory->vtable->get_default_authority(factory, uri); -} diff --git a/src/core/client_config/resolver_factory.h b/src/core/client_config/resolver_factory.h deleted file mode 100644 index 477f8db7f7..0000000000 --- a/src/core/client_config/resolver_factory.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * - * Copyright 2015-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_CLIENT_CONFIG_RESOLVER_FACTORY_H -#define GRPC_CORE_CLIENT_CONFIG_RESOLVER_FACTORY_H - -#include "src/core/client_config/resolver.h" -#include "src/core/client_config/subchannel_factory.h" -#include "src/core/client_config/uri_parser.h" - -typedef struct grpc_resolver_factory grpc_resolver_factory; -typedef struct grpc_resolver_factory_vtable grpc_resolver_factory_vtable; - -/** grpc_resolver provides grpc_client_config objects to grpc_channel - objects */ -struct grpc_resolver_factory { - const grpc_resolver_factory_vtable *vtable; -}; - -typedef struct grpc_resolver_args { - grpc_uri *uri; - grpc_subchannel_factory *subchannel_factory; -} grpc_resolver_args; - -struct grpc_resolver_factory_vtable { - void (*ref)(grpc_resolver_factory *factory); - void (*unref)(grpc_resolver_factory *factory); - - /** Implementation of grpc_resolver_factory_create_resolver */ - grpc_resolver *(*create_resolver)(grpc_resolver_factory *factory, - grpc_resolver_args *args); - - /** Implementation of grpc_resolver_factory_get_default_authority */ - char *(*get_default_authority)(grpc_resolver_factory *factory, grpc_uri *uri); - - /** URI scheme that this factory implements */ - const char *scheme; -}; - -void grpc_resolver_factory_ref(grpc_resolver_factory *resolver); -void grpc_resolver_factory_unref(grpc_resolver_factory *resolver); - -/** Create a resolver instance for a name */ -grpc_resolver *grpc_resolver_factory_create_resolver( - grpc_resolver_factory *factory, grpc_resolver_args *args); - -/** Return a (freshly allocated with gpr_malloc) string representing - the default authority to use for this scheme. */ -char *grpc_resolver_factory_get_default_authority( - grpc_resolver_factory *factory, grpc_uri *uri); - -#endif /* GRPC_CORE_CLIENT_CONFIG_RESOLVER_FACTORY_H */ diff --git a/src/core/client_config/resolver_registry.c b/src/core/client_config/resolver_registry.c deleted file mode 100644 index 89a945c2d3..0000000000 --- a/src/core/client_config/resolver_registry.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/client_config/resolver_registry.h" - -#include - -#include -#include -#include - -#define MAX_RESOLVERS 10 - -static grpc_resolver_factory *g_all_of_the_resolvers[MAX_RESOLVERS]; -static int g_number_of_resolvers = 0; - -static char *g_default_resolver_prefix; - -void grpc_resolver_registry_init(const char *default_resolver_prefix) { - g_number_of_resolvers = 0; - g_default_resolver_prefix = gpr_strdup(default_resolver_prefix); -} - -void grpc_resolver_registry_shutdown(void) { - int i; - for (i = 0; i < g_number_of_resolvers; i++) { - grpc_resolver_factory_unref(g_all_of_the_resolvers[i]); - } - gpr_free(g_default_resolver_prefix); -} - -void grpc_register_resolver_type(grpc_resolver_factory *factory) { - int i; - for (i = 0; i < g_number_of_resolvers; i++) { - GPR_ASSERT(0 != strcmp(factory->vtable->scheme, - g_all_of_the_resolvers[i]->vtable->scheme)); - } - GPR_ASSERT(g_number_of_resolvers != MAX_RESOLVERS); - grpc_resolver_factory_ref(factory); - g_all_of_the_resolvers[g_number_of_resolvers++] = factory; -} - -static grpc_resolver_factory *lookup_factory(grpc_uri *uri) { - int i; - - /* handling NULL uri's here simplifies grpc_resolver_create */ - if (!uri) return NULL; - - for (i = 0; i < g_number_of_resolvers; i++) { - if (0 == strcmp(uri->scheme, g_all_of_the_resolvers[i]->vtable->scheme)) { - return g_all_of_the_resolvers[i]; - } - } - - return NULL; -} - -static grpc_resolver_factory *resolve_factory(const char *target, - grpc_uri **uri) { - char *tmp; - grpc_resolver_factory *factory = NULL; - - GPR_ASSERT(uri != NULL); - *uri = grpc_uri_parse(target, 1); - factory = lookup_factory(*uri); - if (factory == NULL) { - if (g_default_resolver_prefix != NULL) { - grpc_uri_destroy(*uri); - gpr_asprintf(&tmp, "%s%s", g_default_resolver_prefix, target); - *uri = grpc_uri_parse(tmp, 1); - factory = lookup_factory(*uri); - if (factory == NULL) { - grpc_uri_destroy(grpc_uri_parse(target, 0)); - grpc_uri_destroy(grpc_uri_parse(tmp, 0)); - gpr_log(GPR_ERROR, "don't know how to resolve '%s' or '%s'", target, - tmp); - } - gpr_free(tmp); - } else { - grpc_uri_destroy(grpc_uri_parse(target, 0)); - gpr_log(GPR_ERROR, "don't know how to resolve '%s'", target); - } - } - return factory; -} - -grpc_resolver *grpc_resolver_create( - const char *target, grpc_subchannel_factory *subchannel_factory) { - grpc_uri *uri = NULL; - grpc_resolver_factory *factory = resolve_factory(target, &uri); - grpc_resolver *resolver; - grpc_resolver_args args; - memset(&args, 0, sizeof(args)); - args.uri = uri; - args.subchannel_factory = subchannel_factory; - resolver = grpc_resolver_factory_create_resolver(factory, &args); - grpc_uri_destroy(uri); - return resolver; -} - -char *grpc_get_default_authority(const char *target) { - grpc_uri *uri = NULL; - grpc_resolver_factory *factory = resolve_factory(target, &uri); - char *authority = grpc_resolver_factory_get_default_authority(factory, uri); - grpc_uri_destroy(uri); - return authority; -} diff --git a/src/core/client_config/resolver_registry.h b/src/core/client_config/resolver_registry.h deleted file mode 100644 index 1e4cebee0b..0000000000 --- a/src/core/client_config/resolver_registry.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * - * Copyright 2015-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_CLIENT_CONFIG_RESOLVER_REGISTRY_H -#define GRPC_CORE_CLIENT_CONFIG_RESOLVER_REGISTRY_H - -#include "src/core/client_config/resolver_factory.h" - -void grpc_resolver_registry_init(const char *default_prefix); -void grpc_resolver_registry_shutdown(void); - -/** Register a resolver type. - URI's of \a scheme will be resolved with the given resolver. - If \a priority is greater than zero, then the resolver will be eligible - to resolve names that are passed in with no scheme. Higher priority - resolvers will be tried before lower priority schemes. */ -void grpc_register_resolver_type(grpc_resolver_factory *factory); - -/** Create a resolver given \a target. - First tries to parse \a target as a URI. If this succeeds, tries - to locate a registered resolver factory based on the URI scheme. - If parsing or location fails, prefixes default_prefix from - grpc_resolver_registry_init to target, and tries again (if default_prefix - was not NULL). - If a resolver factory was found, use it to instantiate a resolver and - return it. - If a resolver factory was not found, return NULL. */ -grpc_resolver *grpc_resolver_create( - const char *target, grpc_subchannel_factory *subchannel_factory); - -/** Given a target, return a (freshly allocated with gpr_malloc) string - representing the default authority to pass from a client. */ -char *grpc_get_default_authority(const char *target); - -#endif /* GRPC_CORE_CLIENT_CONFIG_RESOLVER_REGISTRY_H */ diff --git a/src/core/client_config/resolvers/dns_resolver.c b/src/core/client_config/resolvers/dns_resolver.c deleted file mode 100644 index 2b2ee97e12..0000000000 --- a/src/core/client_config/resolvers/dns_resolver.c +++ /dev/null @@ -1,309 +0,0 @@ -/* - * - * Copyright 2015-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/client_config/resolvers/dns_resolver.h" - -#include - -#include -#include -#include - -#include "src/core/client_config/lb_policy_registry.h" -#include "src/core/iomgr/resolve_address.h" -#include "src/core/iomgr/timer.h" -#include "src/core/support/backoff.h" -#include "src/core/support/string.h" - -#define BACKOFF_MULTIPLIER 1.6 -#define BACKOFF_JITTER 0.2 -#define BACKOFF_MIN_SECONDS 1 -#define BACKOFF_MAX_SECONDS 120 - -typedef struct { - /** base class: must be first */ - grpc_resolver base; - /** refcount */ - gpr_refcount refs; - /** name to resolve */ - char *name; - /** default port to use */ - char *default_port; - /** subchannel factory */ - grpc_subchannel_factory *subchannel_factory; - /** load balancing policy name */ - char *lb_policy_name; - - /** mutex guarding the rest of the state */ - gpr_mu mu; - /** are we currently resolving? */ - int resolving; - /** which version of resolved_config have we published? */ - int published_version; - /** which version of resolved_config is current? */ - int resolved_version; - /** pending next completion, or NULL */ - grpc_closure *next_completion; - /** target config address for next completion */ - grpc_client_config **target_config; - /** current (fully resolved) config */ - grpc_client_config *resolved_config; - /** retry timer */ - bool have_retry_timer; - grpc_timer retry_timer; - /** retry backoff state */ - gpr_backoff backoff_state; -} dns_resolver; - -static void dns_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *r); - -static void dns_start_resolving_locked(dns_resolver *r); -static void dns_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx, - dns_resolver *r); - -static void dns_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *r); -static void dns_channel_saw_error(grpc_exec_ctx *exec_ctx, grpc_resolver *r); -static void dns_next(grpc_exec_ctx *exec_ctx, grpc_resolver *r, - grpc_client_config **target_config, - grpc_closure *on_complete); - -static const grpc_resolver_vtable dns_resolver_vtable = { - dns_destroy, dns_shutdown, dns_channel_saw_error, dns_next}; - -static void dns_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver) { - dns_resolver *r = (dns_resolver *)resolver; - gpr_mu_lock(&r->mu); - if (r->have_retry_timer) { - grpc_timer_cancel(exec_ctx, &r->retry_timer); - } - if (r->next_completion != NULL) { - *r->target_config = NULL; - grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, true, NULL); - r->next_completion = NULL; - } - gpr_mu_unlock(&r->mu); -} - -static void dns_channel_saw_error(grpc_exec_ctx *exec_ctx, - grpc_resolver *resolver) { - dns_resolver *r = (dns_resolver *)resolver; - gpr_mu_lock(&r->mu); - if (!r->resolving) { - gpr_backoff_reset(&r->backoff_state); - dns_start_resolving_locked(r); - } - gpr_mu_unlock(&r->mu); -} - -static void dns_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver, - grpc_client_config **target_config, - grpc_closure *on_complete) { - dns_resolver *r = (dns_resolver *)resolver; - gpr_mu_lock(&r->mu); - GPR_ASSERT(!r->next_completion); - r->next_completion = on_complete; - r->target_config = target_config; - if (r->resolved_version == 0 && !r->resolving) { - gpr_backoff_reset(&r->backoff_state); - dns_start_resolving_locked(r); - } else { - dns_maybe_finish_next_locked(exec_ctx, r); - } - gpr_mu_unlock(&r->mu); -} - -static void dns_on_retry_timer(grpc_exec_ctx *exec_ctx, void *arg, - bool success) { - dns_resolver *r = arg; - - gpr_mu_lock(&r->mu); - r->have_retry_timer = false; - if (success) { - if (!r->resolving) { - dns_start_resolving_locked(r); - } - } - gpr_mu_unlock(&r->mu); - - GRPC_RESOLVER_UNREF(exec_ctx, &r->base, "retry-timer"); -} - -static void dns_on_resolved(grpc_exec_ctx *exec_ctx, void *arg, - grpc_resolved_addresses *addresses) { - dns_resolver *r = arg; - grpc_client_config *config = NULL; - grpc_subchannel **subchannels; - grpc_subchannel_args args; - grpc_lb_policy *lb_policy; - size_t i; - gpr_mu_lock(&r->mu); - GPR_ASSERT(r->resolving); - r->resolving = 0; - if (addresses != NULL) { - grpc_lb_policy_args lb_policy_args; - config = grpc_client_config_create(); - subchannels = gpr_malloc(sizeof(grpc_subchannel *) * addresses->naddrs); - size_t naddrs = 0; - for (i = 0; i < addresses->naddrs; i++) { - memset(&args, 0, sizeof(args)); - args.addr = (struct sockaddr *)(addresses->addrs[i].addr); - args.addr_len = (size_t)addresses->addrs[i].len; - grpc_subchannel *subchannel = grpc_subchannel_factory_create_subchannel( - exec_ctx, r->subchannel_factory, &args); - if (subchannel != NULL) { - subchannels[naddrs++] = subchannel; - } - } - memset(&lb_policy_args, 0, sizeof(lb_policy_args)); - lb_policy_args.subchannels = subchannels; - lb_policy_args.num_subchannels = naddrs; - lb_policy = grpc_lb_policy_create(r->lb_policy_name, &lb_policy_args); - if (lb_policy != NULL) { - grpc_client_config_set_lb_policy(config, lb_policy); - GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "construction"); - } - grpc_resolved_addresses_destroy(addresses); - gpr_free(subchannels); - } else { - 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", - timeout.tv_sec, timeout.tv_nsec); - GPR_ASSERT(!r->have_retry_timer); - r->have_retry_timer = true; - GRPC_RESOLVER_REF(&r->base, "retry-timer"); - grpc_timer_init(exec_ctx, &r->retry_timer, next_try, dns_on_retry_timer, r, - now); - } - if (r->resolved_config) { - grpc_client_config_unref(exec_ctx, r->resolved_config); - } - r->resolved_config = config; - r->resolved_version++; - dns_maybe_finish_next_locked(exec_ctx, r); - gpr_mu_unlock(&r->mu); - - GRPC_RESOLVER_UNREF(exec_ctx, &r->base, "dns-resolving"); -} - -static void dns_start_resolving_locked(dns_resolver *r) { - GRPC_RESOLVER_REF(&r->base, "dns-resolving"); - GPR_ASSERT(!r->resolving); - r->resolving = 1; - grpc_resolve_address(r->name, r->default_port, dns_on_resolved, r); -} - -static void dns_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx, - dns_resolver *r) { - if (r->next_completion != NULL && - r->resolved_version != r->published_version) { - *r->target_config = r->resolved_config; - if (r->resolved_config) { - grpc_client_config_ref(r->resolved_config); - } - grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, true, NULL); - r->next_completion = NULL; - r->published_version = r->resolved_version; - } -} - -static void dns_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *gr) { - dns_resolver *r = (dns_resolver *)gr; - gpr_mu_destroy(&r->mu); - if (r->resolved_config) { - grpc_client_config_unref(exec_ctx, r->resolved_config); - } - grpc_subchannel_factory_unref(exec_ctx, r->subchannel_factory); - gpr_free(r->name); - gpr_free(r->default_port); - gpr_free(r->lb_policy_name); - gpr_free(r); -} - -static grpc_resolver *dns_create(grpc_resolver_args *args, - const char *default_port, - const char *lb_policy_name) { - dns_resolver *r; - const char *path = args->uri->path; - - if (0 != strcmp(args->uri->authority, "")) { - gpr_log(GPR_ERROR, "authority based dns uri's not supported"); - return NULL; - } - - if (path[0] == '/') ++path; - - r = gpr_malloc(sizeof(dns_resolver)); - memset(r, 0, sizeof(*r)); - gpr_ref_init(&r->refs, 1); - gpr_mu_init(&r->mu); - grpc_resolver_init(&r->base, &dns_resolver_vtable); - r->name = gpr_strdup(path); - r->default_port = gpr_strdup(default_port); - r->subchannel_factory = args->subchannel_factory; - gpr_backoff_init(&r->backoff_state, BACKOFF_MULTIPLIER, BACKOFF_JITTER, - BACKOFF_MIN_SECONDS * 1000, BACKOFF_MAX_SECONDS * 1000); - grpc_subchannel_factory_ref(r->subchannel_factory); - r->lb_policy_name = gpr_strdup(lb_policy_name); - return &r->base; -} - -/* - * FACTORY - */ - -static void dns_factory_ref(grpc_resolver_factory *factory) {} - -static void dns_factory_unref(grpc_resolver_factory *factory) {} - -static grpc_resolver *dns_factory_create_resolver( - grpc_resolver_factory *factory, grpc_resolver_args *args) { - return dns_create(args, "https", "pick_first"); -} - -char *dns_factory_get_default_host_name(grpc_resolver_factory *factory, - grpc_uri *uri) { - const char *path = uri->path; - if (path[0] == '/') ++path; - return gpr_strdup(path); -} - -static const grpc_resolver_factory_vtable dns_factory_vtable = { - dns_factory_ref, dns_factory_unref, dns_factory_create_resolver, - dns_factory_get_default_host_name, "dns"}; -static grpc_resolver_factory dns_resolver_factory = {&dns_factory_vtable}; - -grpc_resolver_factory *grpc_dns_resolver_factory_create() { - return &dns_resolver_factory; -} diff --git a/src/core/client_config/resolvers/dns_resolver.h b/src/core/client_config/resolvers/dns_resolver.h deleted file mode 100644 index b24280b507..0000000000 --- a/src/core/client_config/resolvers/dns_resolver.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * - * Copyright 2015-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_CLIENT_CONFIG_RESOLVERS_DNS_RESOLVER_H -#define GRPC_CORE_CLIENT_CONFIG_RESOLVERS_DNS_RESOLVER_H - -#include "src/core/client_config/resolver_factory.h" - -/** Create a dns resolver factory */ -grpc_resolver_factory *grpc_dns_resolver_factory_create(void); - -#endif /* GRPC_CORE_CLIENT_CONFIG_RESOLVERS_DNS_RESOLVER_H */ diff --git a/src/core/client_config/resolvers/sockaddr_resolver.c b/src/core/client_config/resolvers/sockaddr_resolver.c deleted file mode 100644 index 3cb7d79b67..0000000000 --- a/src/core/client_config/resolvers/sockaddr_resolver.c +++ /dev/null @@ -1,372 +0,0 @@ -/* - * - * Copyright 2015-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 - -#include "src/core/client_config/resolvers/sockaddr_resolver.h" - -#include -#include - -#include -#include -#include - -#include "src/core/client_config/lb_policy_registry.h" -#include "src/core/iomgr/resolve_address.h" -#include "src/core/iomgr/unix_sockets_posix.h" -#include "src/core/support/string.h" - -typedef struct { - /** base class: must be first */ - grpc_resolver base; - /** refcount */ - gpr_refcount refs; - /** subchannel factory */ - grpc_subchannel_factory *subchannel_factory; - /** load balancing policy name */ - char *lb_policy_name; - - /** the addresses that we've 'resolved' */ - struct sockaddr_storage *addrs; - /** the corresponding length of the addresses */ - size_t *addrs_len; - /** how many elements in \a addrs */ - size_t num_addrs; - - /** mutex guarding the rest of the state */ - gpr_mu mu; - /** have we published? */ - int published; - /** pending next completion, or NULL */ - grpc_closure *next_completion; - /** target config address for next completion */ - grpc_client_config **target_config; -} sockaddr_resolver; - -static void sockaddr_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *r); - -static void sockaddr_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx, - sockaddr_resolver *r); - -static void sockaddr_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *r); -static void sockaddr_channel_saw_error(grpc_exec_ctx *exec_ctx, - grpc_resolver *r); -static void sockaddr_next(grpc_exec_ctx *exec_ctx, grpc_resolver *r, - grpc_client_config **target_config, - grpc_closure *on_complete); - -static const grpc_resolver_vtable sockaddr_resolver_vtable = { - sockaddr_destroy, sockaddr_shutdown, sockaddr_channel_saw_error, - sockaddr_next}; - -static void sockaddr_shutdown(grpc_exec_ctx *exec_ctx, - grpc_resolver *resolver) { - sockaddr_resolver *r = (sockaddr_resolver *)resolver; - gpr_mu_lock(&r->mu); - if (r->next_completion != NULL) { - *r->target_config = NULL; - grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, true, NULL); - r->next_completion = NULL; - } - gpr_mu_unlock(&r->mu); -} - -static void sockaddr_channel_saw_error(grpc_exec_ctx *exec_ctx, - grpc_resolver *resolver) { - sockaddr_resolver *r = (sockaddr_resolver *)resolver; - gpr_mu_lock(&r->mu); - r->published = 0; - sockaddr_maybe_finish_next_locked(exec_ctx, r); - gpr_mu_unlock(&r->mu); -} - -static void sockaddr_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver, - grpc_client_config **target_config, - grpc_closure *on_complete) { - sockaddr_resolver *r = (sockaddr_resolver *)resolver; - gpr_mu_lock(&r->mu); - GPR_ASSERT(!r->next_completion); - r->next_completion = on_complete; - r->target_config = target_config; - sockaddr_maybe_finish_next_locked(exec_ctx, r); - gpr_mu_unlock(&r->mu); -} - -static void sockaddr_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx, - sockaddr_resolver *r) { - grpc_client_config *cfg; - grpc_lb_policy *lb_policy; - grpc_lb_policy_args lb_policy_args; - grpc_subchannel **subchannels; - grpc_subchannel_args args; - - if (r->next_completion != NULL && !r->published) { - size_t i; - cfg = grpc_client_config_create(); - subchannels = gpr_malloc(sizeof(grpc_subchannel *) * r->num_addrs); - for (i = 0; i < r->num_addrs; i++) { - memset(&args, 0, sizeof(args)); - args.addr = (struct sockaddr *)&r->addrs[i]; - args.addr_len = r->addrs_len[i]; - subchannels[i] = grpc_subchannel_factory_create_subchannel( - exec_ctx, r->subchannel_factory, &args); - } - memset(&lb_policy_args, 0, sizeof(lb_policy_args)); - lb_policy_args.subchannels = subchannels; - lb_policy_args.num_subchannels = r->num_addrs; - lb_policy = grpc_lb_policy_create(r->lb_policy_name, &lb_policy_args); - gpr_free(subchannels); - grpc_client_config_set_lb_policy(cfg, lb_policy); - GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "sockaddr"); - r->published = 1; - *r->target_config = cfg; - grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, true, NULL); - r->next_completion = NULL; - } -} - -static void sockaddr_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *gr) { - sockaddr_resolver *r = (sockaddr_resolver *)gr; - gpr_mu_destroy(&r->mu); - grpc_subchannel_factory_unref(exec_ctx, r->subchannel_factory); - gpr_free(r->addrs); - gpr_free(r->addrs_len); - gpr_free(r->lb_policy_name); - gpr_free(r); -} - -static char *ip_get_default_authority(grpc_uri *uri) { - const char *path = uri->path; - if (path[0] == '/') ++path; - return gpr_strdup(path); -} - -static char *ipv4_get_default_authority(grpc_resolver_factory *factory, - grpc_uri *uri) { - return ip_get_default_authority(uri); -} - -static char *ipv6_get_default_authority(grpc_resolver_factory *factory, - grpc_uri *uri) { - return ip_get_default_authority(uri); -} - -static int parse_ipv4(grpc_uri *uri, struct sockaddr_storage *addr, - size_t *len) { - const char *host_port = uri->path; - char *host; - char *port; - int port_num; - int result = 0; - struct sockaddr_in *in = (struct sockaddr_in *)addr; - - if (*host_port == '/') ++host_port; - if (!gpr_split_host_port(host_port, &host, &port)) { - return 0; - } - - memset(in, 0, sizeof(*in)); - *len = sizeof(*in); - in->sin_family = AF_INET; - if (inet_pton(AF_INET, host, &in->sin_addr) == 0) { - gpr_log(GPR_ERROR, "invalid ipv4 address: '%s'", host); - goto done; - } - - if (port != NULL) { - if (sscanf(port, "%d", &port_num) != 1 || port_num < 0 || - port_num > 65535) { - gpr_log(GPR_ERROR, "invalid ipv4 port: '%s'", port); - goto done; - } - in->sin_port = htons((uint16_t)port_num); - } else { - gpr_log(GPR_ERROR, "no port given for ipv4 scheme"); - goto done; - } - - result = 1; -done: - gpr_free(host); - gpr_free(port); - return result; -} - -static int parse_ipv6(grpc_uri *uri, struct sockaddr_storage *addr, - size_t *len) { - const char *host_port = uri->path; - char *host; - char *port; - int port_num; - int result = 0; - struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)addr; - - if (*host_port == '/') ++host_port; - if (!gpr_split_host_port(host_port, &host, &port)) { - return 0; - } - - memset(in6, 0, sizeof(*in6)); - *len = sizeof(*in6); - in6->sin6_family = AF_INET6; - if (inet_pton(AF_INET6, host, &in6->sin6_addr) == 0) { - gpr_log(GPR_ERROR, "invalid ipv6 address: '%s'", host); - goto done; - } - - if (port != NULL) { - if (sscanf(port, "%d", &port_num) != 1 || port_num < 0 || - port_num > 65535) { - gpr_log(GPR_ERROR, "invalid ipv6 port: '%s'", port); - goto done; - } - in6->sin6_port = htons((uint16_t)port_num); - } else { - gpr_log(GPR_ERROR, "no port given for ipv6 scheme"); - goto done; - } - - result = 1; -done: - gpr_free(host); - gpr_free(port); - return result; -} - -static void do_nothing(void *ignored) {} - -static grpc_resolver *sockaddr_create( - grpc_resolver_args *args, const char *default_lb_policy_name, - int parse(grpc_uri *uri, struct sockaddr_storage *dst, size_t *len)) { - size_t i; - int errors_found = 0; /* GPR_FALSE */ - sockaddr_resolver *r; - gpr_slice path_slice; - gpr_slice_buffer path_parts; - - if (0 != strcmp(args->uri->authority, "")) { - gpr_log(GPR_ERROR, "authority based uri's not supported by the %s scheme", - args->uri->scheme); - return NULL; - } - - r = gpr_malloc(sizeof(sockaddr_resolver)); - memset(r, 0, sizeof(*r)); - - r->lb_policy_name = NULL; - if (0 != strcmp(args->uri->query, "")) { - gpr_slice query_slice; - gpr_slice_buffer query_parts; - - query_slice = - gpr_slice_new(args->uri->query, strlen(args->uri->query), do_nothing); - gpr_slice_buffer_init(&query_parts); - gpr_slice_split(query_slice, "=", &query_parts); - GPR_ASSERT(query_parts.count == 2); - if (0 == gpr_slice_str_cmp(query_parts.slices[0], "lb_policy")) { - r->lb_policy_name = gpr_dump_slice(query_parts.slices[1], GPR_DUMP_ASCII); - } - gpr_slice_buffer_destroy(&query_parts); - gpr_slice_unref(query_slice); - } - if (r->lb_policy_name == NULL) { - r->lb_policy_name = gpr_strdup(default_lb_policy_name); - } - - path_slice = - gpr_slice_new(args->uri->path, strlen(args->uri->path), do_nothing); - gpr_slice_buffer_init(&path_parts); - - gpr_slice_split(path_slice, ",", &path_parts); - r->num_addrs = path_parts.count; - r->addrs = gpr_malloc(sizeof(struct sockaddr_storage) * r->num_addrs); - r->addrs_len = gpr_malloc(sizeof(*r->addrs_len) * r->num_addrs); - - for (i = 0; i < r->num_addrs; i++) { - grpc_uri ith_uri = *args->uri; - char *part_str = gpr_dump_slice(path_parts.slices[i], GPR_DUMP_ASCII); - ith_uri.path = part_str; - if (!parse(&ith_uri, &r->addrs[i], &r->addrs_len[i])) { - errors_found = 1; /* GPR_TRUE */ - } - gpr_free(part_str); - if (errors_found) break; - } - - gpr_slice_buffer_destroy(&path_parts); - gpr_slice_unref(path_slice); - if (errors_found) { - gpr_free(r->lb_policy_name); - gpr_free(r->addrs); - gpr_free(r->addrs_len); - gpr_free(r); - return NULL; - } - - gpr_ref_init(&r->refs, 1); - gpr_mu_init(&r->mu); - grpc_resolver_init(&r->base, &sockaddr_resolver_vtable); - r->subchannel_factory = args->subchannel_factory; - grpc_subchannel_factory_ref(r->subchannel_factory); - - return &r->base; -} - -/* - * FACTORY - */ - -static void sockaddr_factory_ref(grpc_resolver_factory *factory) {} - -static void sockaddr_factory_unref(grpc_resolver_factory *factory) {} - -#define DECL_FACTORY(name, prefix) \ - static grpc_resolver *name##_factory_create_resolver( \ - grpc_resolver_factory *factory, grpc_resolver_args *args) { \ - return sockaddr_create(args, "pick_first", prefix##parse_##name); \ - } \ - static const grpc_resolver_factory_vtable name##_factory_vtable = { \ - sockaddr_factory_ref, sockaddr_factory_unref, \ - name##_factory_create_resolver, prefix##name##_get_default_authority, \ - #name}; \ - static grpc_resolver_factory name##_resolver_factory = { \ - &name##_factory_vtable}; \ - grpc_resolver_factory *grpc_##name##_resolver_factory_create() { \ - return &name##_resolver_factory; \ - } - -#ifdef GPR_HAVE_UNIX_SOCKET -DECL_FACTORY(unix, grpc_) -#endif -DECL_FACTORY(ipv4, ) DECL_FACTORY(ipv6, ) diff --git a/src/core/client_config/resolvers/sockaddr_resolver.h b/src/core/client_config/resolvers/sockaddr_resolver.h deleted file mode 100644 index f050329431..0000000000 --- a/src/core/client_config/resolvers/sockaddr_resolver.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * - * Copyright 2015-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_CLIENT_CONFIG_RESOLVERS_SOCKADDR_RESOLVER_H -#define GRPC_CORE_CLIENT_CONFIG_RESOLVERS_SOCKADDR_RESOLVER_H - -#include - -#include "src/core/client_config/resolver_factory.h" - -grpc_resolver_factory *grpc_ipv4_resolver_factory_create(void); - -grpc_resolver_factory *grpc_ipv6_resolver_factory_create(void); - -#ifdef GPR_POSIX_SOCKET -/** Create a unix resolver factory */ -grpc_resolver_factory *grpc_unix_resolver_factory_create(void); -#endif - -#endif /* GRPC_CORE_CLIENT_CONFIG_RESOLVERS_SOCKADDR_RESOLVER_H */ diff --git a/src/core/client_config/resolvers/zookeeper_resolver.c b/src/core/client_config/resolvers/zookeeper_resolver.c deleted file mode 100644 index e0e18792a2..0000000000 --- a/src/core/client_config/resolvers/zookeeper_resolver.c +++ /dev/null @@ -1,520 +0,0 @@ -/* - * - * Copyright 2015-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/client_config/resolvers/zookeeper_resolver.h" - -#include - -#include -#include - -#include -#include - -#include "src/core/client_config/lb_policy_registry.h" -#include "src/core/client_config/resolver_registry.h" -#include "src/core/iomgr/resolve_address.h" -#include "src/core/json/json.h" -#include "src/core/support/string.h" -#include "src/core/surface/api_trace.h" - -/** Zookeeper session expiration time in milliseconds */ -#define GRPC_ZOOKEEPER_SESSION_TIMEOUT 15000 - -typedef struct { - /** base class: must be first */ - grpc_resolver base; - /** refcount */ - gpr_refcount refs; - /** name to resolve */ - char *name; - /** subchannel factory */ - grpc_subchannel_factory *subchannel_factory; - /** load balancing policy name */ - char *lb_policy_name; - - /** mutex guarding the rest of the state */ - gpr_mu mu; - /** are we currently resolving? */ - int resolving; - /** which version of resolved_config have we published? */ - int published_version; - /** which version of resolved_config is current? */ - int resolved_version; - /** pending next completion, or NULL */ - grpc_closure *next_completion; - /** target config address for next completion */ - grpc_client_config **target_config; - /** current (fully resolved) config */ - grpc_client_config *resolved_config; - - /** zookeeper handle */ - zhandle_t *zookeeper_handle; - /** zookeeper resolved addresses */ - grpc_resolved_addresses *resolved_addrs; - /** total number of addresses to be resolved */ - int resolved_total; - /** number of addresses resolved */ - int resolved_num; -} zookeeper_resolver; - -static void zookeeper_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *r); - -static void zookeeper_start_resolving_locked(zookeeper_resolver *r); -static void zookeeper_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx, - zookeeper_resolver *r); - -static void zookeeper_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *r); -static void zookeeper_channel_saw_error(grpc_exec_ctx *exec_ctx, - grpc_resolver *r); -static void zookeeper_next(grpc_exec_ctx *exec_ctx, grpc_resolver *r, - grpc_client_config **target_config, - grpc_closure *on_complete); - -static const grpc_resolver_vtable zookeeper_resolver_vtable = { - zookeeper_destroy, zookeeper_shutdown, zookeeper_channel_saw_error, - zookeeper_next}; - -static void zookeeper_shutdown(grpc_exec_ctx *exec_ctx, - grpc_resolver *resolver) { - zookeeper_resolver *r = (zookeeper_resolver *)resolver; - grpc_closure *call = NULL; - gpr_mu_lock(&r->mu); - if (r->next_completion != NULL) { - *r->target_config = NULL; - call = r->next_completion; - r->next_completion = NULL; - } - zookeeper_close(r->zookeeper_handle); - gpr_mu_unlock(&r->mu); - if (call != NULL) { - call->cb(exec_ctx, call->cb_arg, 1); - } -} - -static void zookeeper_channel_saw_error(grpc_exec_ctx *exec_ctx, - grpc_resolver *resolver) { - zookeeper_resolver *r = (zookeeper_resolver *)resolver; - gpr_mu_lock(&r->mu); - if (r->resolving == 0) { - zookeeper_start_resolving_locked(r); - } - gpr_mu_unlock(&r->mu); -} - -static void zookeeper_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver, - grpc_client_config **target_config, - grpc_closure *on_complete) { - zookeeper_resolver *r = (zookeeper_resolver *)resolver; - gpr_mu_lock(&r->mu); - GPR_ASSERT(r->next_completion == NULL); - r->next_completion = on_complete; - r->target_config = target_config; - if (r->resolved_version == 0 && r->resolving == 0) { - zookeeper_start_resolving_locked(r); - } else { - zookeeper_maybe_finish_next_locked(exec_ctx, r); - } - gpr_mu_unlock(&r->mu); -} - -/** Zookeeper global watcher for connection management - TODO: better connection management besides logs */ -static void zookeeper_global_watcher(zhandle_t *zookeeper_handle, int type, - int state, const char *path, - void *watcher_ctx) { - if (type == ZOO_SESSION_EVENT) { - if (state == ZOO_EXPIRED_SESSION_STATE) { - gpr_log(GPR_ERROR, "Zookeeper session expired"); - } else if (state == ZOO_AUTH_FAILED_STATE) { - gpr_log(GPR_ERROR, "Zookeeper authentication failed"); - } - } -} - -/** Zookeeper watcher triggered by changes to watched nodes - Once triggered, it tries to resolve again to get updated addresses */ -static void zookeeper_watcher(zhandle_t *zookeeper_handle, int type, int state, - const char *path, void *watcher_ctx) { - if (watcher_ctx != NULL) { - zookeeper_resolver *r = (zookeeper_resolver *)watcher_ctx; - if (state == ZOO_CONNECTED_STATE) { - gpr_mu_lock(&r->mu); - if (r->resolving == 0) { - zookeeper_start_resolving_locked(r); - } - gpr_mu_unlock(&r->mu); - } - } -} - -/** Callback function after getting all resolved addresses - Creates a subchannel for each address */ -static void zookeeper_on_resolved(grpc_exec_ctx *exec_ctx, void *arg, - grpc_resolved_addresses *addresses) { - zookeeper_resolver *r = arg; - grpc_client_config *config = NULL; - grpc_subchannel **subchannels; - grpc_subchannel_args args; - grpc_lb_policy *lb_policy; - size_t i; - if (addresses != NULL) { - grpc_lb_policy_args lb_policy_args; - config = grpc_client_config_create(); - subchannels = gpr_malloc(sizeof(grpc_subchannel *) * addresses->naddrs); - for (i = 0; i < addresses->naddrs; i++) { - memset(&args, 0, sizeof(args)); - args.addr = (struct sockaddr *)(addresses->addrs[i].addr); - args.addr_len = addresses->addrs[i].len; - subchannels[i] = grpc_subchannel_factory_create_subchannel( - exec_ctx, r->subchannel_factory, &args); - } - lb_policy_args.subchannels = subchannels; - lb_policy_args.num_subchannels = addresses->naddrs; - lb_policy = grpc_lb_policy_create(r->lb_policy_name, &lb_policy_args); - grpc_client_config_set_lb_policy(config, lb_policy); - GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "construction"); - grpc_resolved_addresses_destroy(addresses); - gpr_free(subchannels); - } - gpr_mu_lock(&r->mu); - GPR_ASSERT(r->resolving == 1); - r->resolving = 0; - if (r->resolved_config != NULL) { - grpc_client_config_unref(exec_ctx, r->resolved_config); - } - r->resolved_config = config; - r->resolved_version++; - zookeeper_maybe_finish_next_locked(exec_ctx, r); - gpr_mu_unlock(&r->mu); - - GRPC_RESOLVER_UNREF(exec_ctx, &r->base, "zookeeper-resolving"); -} - -/** Callback function for each DNS resolved address */ -static void zookeeper_dns_resolved(grpc_exec_ctx *exec_ctx, void *arg, - grpc_resolved_addresses *addresses) { - size_t i; - zookeeper_resolver *r = arg; - int resolve_done = 0; - - gpr_mu_lock(&r->mu); - r->resolved_num++; - r->resolved_addrs->addrs = - gpr_realloc(r->resolved_addrs->addrs, - sizeof(grpc_resolved_address) * - (r->resolved_addrs->naddrs + addresses->naddrs)); - for (i = 0; i < addresses->naddrs; i++) { - memcpy(r->resolved_addrs->addrs[i + r->resolved_addrs->naddrs].addr, - addresses->addrs[i].addr, addresses->addrs[i].len); - r->resolved_addrs->addrs[i + r->resolved_addrs->naddrs].len = - addresses->addrs[i].len; - } - - r->resolved_addrs->naddrs += addresses->naddrs; - grpc_resolved_addresses_destroy(addresses); - - /** Wait for all addresses to be resolved */ - resolve_done = (r->resolved_num == r->resolved_total); - gpr_mu_unlock(&r->mu); - if (resolve_done) { - zookeeper_on_resolved(exec_ctx, r, r->resolved_addrs); - } -} - -/** Parses JSON format address of a zookeeper node */ -static char *zookeeper_parse_address(const char *value, size_t value_len) { - grpc_json *json; - grpc_json *cur; - const char *host; - const char *port; - char *buffer; - char *address = NULL; - - buffer = gpr_malloc(value_len); - memcpy(buffer, value, value_len); - json = grpc_json_parse_string_with_len(buffer, value_len); - if (json != NULL) { - host = NULL; - port = NULL; - for (cur = json->child; cur != NULL; cur = cur->next) { - if (!strcmp(cur->key, "host")) { - host = cur->value; - if (port != NULL) { - break; - } - } else if (!strcmp(cur->key, "port")) { - port = cur->value; - if (host != NULL) { - break; - } - } - } - if (host != NULL && port != NULL) { - gpr_asprintf(&address, "%s:%s", host, port); - } - grpc_json_destroy(json); - } - gpr_free(buffer); - - return address; -} - -static void zookeeper_get_children_node_completion(int rc, const char *value, - int value_len, - const struct Stat *stat, - const void *arg) { - char *address = NULL; - zookeeper_resolver *r = (zookeeper_resolver *)arg; - int resolve_done = 0; - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - - if (rc != 0) { - gpr_log(GPR_ERROR, "Error in getting a child node of %s", r->name); - grpc_exec_ctx_finish(&exec_ctx); - return; - } - - address = zookeeper_parse_address(value, (size_t)value_len); - if (address != NULL) { - /** Further resolves address by DNS */ - grpc_resolve_address(address, NULL, zookeeper_dns_resolved, r); - gpr_free(address); - } else { - gpr_log(GPR_ERROR, "Error in resolving a child node of %s", r->name); - gpr_mu_lock(&r->mu); - r->resolved_total--; - resolve_done = (r->resolved_num == r->resolved_total); - gpr_mu_unlock(&r->mu); - if (resolve_done) { - zookeeper_on_resolved(&exec_ctx, r, r->resolved_addrs); - } - } - - grpc_exec_ctx_finish(&exec_ctx); -} - -static void zookeeper_get_children_completion( - int rc, const struct String_vector *children, const void *arg) { - char *path; - int status; - int i; - zookeeper_resolver *r = (zookeeper_resolver *)arg; - - if (rc != 0) { - gpr_log(GPR_ERROR, "Error in getting zookeeper children of %s", r->name); - return; - } - - if (children->count == 0) { - gpr_log(GPR_ERROR, "Error in resolving zookeeper address %s", r->name); - return; - } - - r->resolved_addrs = gpr_malloc(sizeof(grpc_resolved_addresses)); - r->resolved_addrs->addrs = NULL; - r->resolved_addrs->naddrs = 0; - r->resolved_total = children->count; - - /** TODO: Replace expensive heap allocation with stack - if we can get maximum length of zookeeper path */ - for (i = 0; i < children->count; i++) { - gpr_asprintf(&path, "%s/%s", r->name, children->data[i]); - status = zoo_awget(r->zookeeper_handle, path, zookeeper_watcher, r, - zookeeper_get_children_node_completion, r); - gpr_free(path); - if (status != 0) { - gpr_log(GPR_ERROR, "Error in getting zookeeper node %s", path); - } - } -} - -static void zookeeper_get_node_completion(int rc, const char *value, - int value_len, - const struct Stat *stat, - const void *arg) { - int status; - char *address = NULL; - zookeeper_resolver *r = (zookeeper_resolver *)arg; - r->resolved_addrs = NULL; - r->resolved_total = 0; - r->resolved_num = 0; - - if (rc != 0) { - gpr_log(GPR_ERROR, "Error in getting zookeeper node %s", r->name); - return; - } - - /** If zookeeper node of path r->name does not have address - (i.e. service node), get its children */ - address = zookeeper_parse_address(value, (size_t)value_len); - if (address != NULL) { - r->resolved_addrs = gpr_malloc(sizeof(grpc_resolved_addresses)); - r->resolved_addrs->addrs = NULL; - r->resolved_addrs->naddrs = 0; - r->resolved_total = 1; - /** Further resolves address by DNS */ - grpc_resolve_address(address, NULL, zookeeper_dns_resolved, r); - gpr_free(address); - return; - } - - status = zoo_awget_children(r->zookeeper_handle, r->name, zookeeper_watcher, - r, zookeeper_get_children_completion, r); - if (status != 0) { - gpr_log(GPR_ERROR, "Error in getting zookeeper children of %s", r->name); - } -} - -static void zookeeper_resolve_address(zookeeper_resolver *r) { - int status; - status = zoo_awget(r->zookeeper_handle, r->name, zookeeper_watcher, r, - zookeeper_get_node_completion, r); - if (status != 0) { - gpr_log(GPR_ERROR, "Error in getting zookeeper node %s", r->name); - } -} - -static void zookeeper_start_resolving_locked(zookeeper_resolver *r) { - GRPC_RESOLVER_REF(&r->base, "zookeeper-resolving"); - GPR_ASSERT(r->resolving == 0); - r->resolving = 1; - zookeeper_resolve_address(r); -} - -static void zookeeper_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx, - zookeeper_resolver *r) { - if (r->next_completion != NULL && - r->resolved_version != r->published_version) { - *r->target_config = r->resolved_config; - if (r->resolved_config != NULL) { - grpc_client_config_ref(r->resolved_config); - } - grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, true, NULL); - r->next_completion = NULL; - r->published_version = r->resolved_version; - } -} - -static void zookeeper_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *gr) { - zookeeper_resolver *r = (zookeeper_resolver *)gr; - gpr_mu_destroy(&r->mu); - if (r->resolved_config != NULL) { - grpc_client_config_unref(exec_ctx, r->resolved_config); - } - grpc_subchannel_factory_unref(exec_ctx, r->subchannel_factory); - gpr_free(r->name); - gpr_free(r->lb_policy_name); - gpr_free(r); -} - -static grpc_resolver *zookeeper_create(grpc_resolver_args *args, - const char *lb_policy_name) { - zookeeper_resolver *r; - size_t length; - char *path = args->uri->path; - - if (0 == strcmp(args->uri->authority, "")) { - gpr_log(GPR_ERROR, "No authority specified in zookeeper uri"); - return NULL; - } - - /** Removes the trailing slash if exists */ - length = strlen(path); - if (length > 1 && path[length - 1] == '/') { - path[length - 1] = 0; - } - - r = gpr_malloc(sizeof(zookeeper_resolver)); - memset(r, 0, sizeof(*r)); - gpr_ref_init(&r->refs, 1); - gpr_mu_init(&r->mu); - grpc_resolver_init(&r->base, &zookeeper_resolver_vtable); - r->name = gpr_strdup(path); - - r->subchannel_factory = args->subchannel_factory; - grpc_subchannel_factory_ref(r->subchannel_factory); - - r->lb_policy_name = gpr_strdup(lb_policy_name); - - /** Initializes zookeeper client */ - zoo_set_debug_level(ZOO_LOG_LEVEL_WARN); - r->zookeeper_handle = - zookeeper_init(args->uri->authority, zookeeper_global_watcher, - GRPC_ZOOKEEPER_SESSION_TIMEOUT, 0, 0, 0); - if (r->zookeeper_handle == NULL) { - gpr_log(GPR_ERROR, "Unable to connect to zookeeper server"); - return NULL; - } - - return &r->base; -} - -static void zookeeper_plugin_init() { - grpc_register_resolver_type(grpc_zookeeper_resolver_factory_create()); -} - -void grpc_zookeeper_register() { - GRPC_API_TRACE("grpc_zookeeper_register(void)", 0, ()); - grpc_register_plugin(zookeeper_plugin_init, NULL); -} - -/* - * FACTORY - */ - -static void zookeeper_factory_ref(grpc_resolver_factory *factory) {} - -static void zookeeper_factory_unref(grpc_resolver_factory *factory) {} - -static char *zookeeper_factory_get_default_hostname( - grpc_resolver_factory *factory, grpc_uri *uri) { - return NULL; -} - -static grpc_resolver *zookeeper_factory_create_resolver( - grpc_resolver_factory *factory, grpc_resolver_args *args) { - return zookeeper_create(args, "pick_first"); -} - -static const grpc_resolver_factory_vtable zookeeper_factory_vtable = { - zookeeper_factory_ref, zookeeper_factory_unref, - zookeeper_factory_create_resolver, zookeeper_factory_get_default_hostname, - "zookeeper"}; - -static grpc_resolver_factory zookeeper_resolver_factory = { - &zookeeper_factory_vtable}; - -grpc_resolver_factory *grpc_zookeeper_resolver_factory_create() { - return &zookeeper_resolver_factory; -} diff --git a/src/core/client_config/resolvers/zookeeper_resolver.h b/src/core/client_config/resolvers/zookeeper_resolver.h deleted file mode 100644 index 04bd3ca875..0000000000 --- a/src/core/client_config/resolvers/zookeeper_resolver.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * - * Copyright 2015-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_CLIENT_CONFIG_RESOLVERS_ZOOKEEPER_RESOLVER_H -#define GRPC_CORE_CLIENT_CONFIG_RESOLVERS_ZOOKEEPER_RESOLVER_H - -#include "src/core/client_config/resolver_factory.h" - -/** Create a zookeeper resolver factory */ -grpc_resolver_factory *grpc_zookeeper_resolver_factory_create(void); - -#endif /* GRPC_CORE_CLIENT_CONFIG_RESOLVERS_ZOOKEEPER_RESOLVER_H */ diff --git a/src/core/client_config/subchannel.c b/src/core/client_config/subchannel.c deleted file mode 100644 index c5cd504929..0000000000 --- a/src/core/client_config/subchannel.c +++ /dev/null @@ -1,678 +0,0 @@ -/* - * - * Copyright 2015-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/client_config/subchannel.h" - -#include - -#include -#include - -#include "src/core/channel/channel_args.h" -#include "src/core/channel/client_channel.h" -#include "src/core/channel/connected_channel.h" -#include "src/core/client_config/initial_connect_string.h" -#include "src/core/client_config/subchannel_index.h" -#include "src/core/iomgr/timer.h" -#include "src/core/profiling/timers.h" -#include "src/core/support/backoff.h" -#include "src/core/surface/channel.h" -#include "src/core/surface/channel_init.h" -#include "src/core/transport/connectivity_state.h" - -#define INTERNAL_REF_BITS 16 -#define STRONG_REF_MASK (~(gpr_atm)((1 << INTERNAL_REF_BITS) - 1)) - -#define GRPC_SUBCHANNEL_MIN_CONNECT_TIMEOUT_SECONDS 20 -#define GRPC_SUBCHANNEL_INITIAL_CONNECT_BACKOFF_SECONDS 1 -#define GRPC_SUBCHANNEL_RECONNECT_BACKOFF_MULTIPLIER 1.6 -#define GRPC_SUBCHANNEL_RECONNECT_MAX_BACKOFF_SECONDS 120 -#define GRPC_SUBCHANNEL_RECONNECT_JITTER 0.2 - -#define GET_CONNECTED_SUBCHANNEL(subchannel, barrier) \ - ((grpc_connected_subchannel *)(gpr_atm_##barrier##_load( \ - &(subchannel)->connected_subchannel))) - -typedef struct { - grpc_closure closure; - grpc_subchannel *subchannel; - grpc_connectivity_state connectivity_state; -} state_watcher; - -typedef struct external_state_watcher { - grpc_subchannel *subchannel; - grpc_pollset_set *pollset_set; - grpc_closure *notify; - grpc_closure closure; - struct external_state_watcher *next; - struct external_state_watcher *prev; -} external_state_watcher; - -struct grpc_subchannel { - grpc_connector *connector; - - /** refcount - - lower INTERNAL_REF_BITS bits are for internal references: - these do not keep the subchannel open. - - upper remaining bits are for public references: these do - keep the subchannel open */ - gpr_atm ref_pair; - - /** non-transport related channel filters */ - const grpc_channel_filter **filters; - size_t num_filters; - /** channel arguments */ - grpc_channel_args *args; - /** address to connect to */ - struct sockaddr *addr; - size_t addr_len; - - grpc_subchannel_key *key; - - /** initial string to send to peer */ - gpr_slice initial_connect_string; - - /** set during connection */ - grpc_connect_out_args connecting_result; - - /** callback for connection finishing */ - grpc_closure connected; - - /** pollset_set tracking who's interested in a connection - being setup */ - grpc_pollset_set *pollset_set; - - /** active connection, or null; of type grpc_connected_subchannel */ - gpr_atm connected_subchannel; - - /** mutex protecting remaining elements */ - gpr_mu mu; - - /** have we seen a disconnection? */ - int disconnected; - /** are we connecting */ - int connecting; - /** connectivity state tracking */ - grpc_connectivity_state_tracker state_tracker; - - external_state_watcher root_external_state_watcher; - - /** next connect attempt time */ - gpr_timespec next_attempt; - /** backoff state */ - gpr_backoff backoff_state; - /** do we have an active alarm? */ - int have_alarm; - /** our alarm */ - grpc_timer alarm; - /** current random value */ - uint32_t random; -}; - -struct grpc_subchannel_call { - grpc_connected_subchannel *connection; -}; - -#define SUBCHANNEL_CALL_TO_CALL_STACK(call) ((grpc_call_stack *)((call) + 1)) -#define CHANNEL_STACK_FROM_CONNECTION(con) ((grpc_channel_stack *)(con)) -#define CALLSTACK_TO_SUBCHANNEL_CALL(callstack) \ - (((grpc_subchannel_call *)(callstack)) - 1) - -static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *subchannel, - bool iomgr_success); - -#ifdef GRPC_STREAM_REFCOUNT_DEBUG -#define REF_REASON reason -#define REF_LOG(name, p) \ - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "%s: %p ref %d -> %d %s", \ - (name), (p), (p)->refs.count, (p)->refs.count + 1, reason) -#define UNREF_LOG(name, p) \ - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "%s: %p unref %d -> %d %s", \ - (name), (p), (p)->refs.count, (p)->refs.count - 1, reason) -#define REF_MUTATE_EXTRA_ARGS \ - GRPC_SUBCHANNEL_REF_EXTRA_ARGS, const char *purpose -#define REF_MUTATE_PURPOSE(x) , file, line, reason, x -#else -#define REF_REASON "" -#define REF_LOG(name, p) \ - do { \ - } while (0) -#define UNREF_LOG(name, p) \ - do { \ - } while (0) -#define REF_MUTATE_EXTRA_ARGS -#define REF_MUTATE_PURPOSE(x) -#endif - -/* - * connection implementation - */ - -static void connection_destroy(grpc_exec_ctx *exec_ctx, void *arg, - bool success) { - grpc_connected_subchannel *c = arg; - grpc_channel_stack_destroy(exec_ctx, CHANNEL_STACK_FROM_CONNECTION(c)); - gpr_free(c); -} - -void grpc_connected_subchannel_ref( - grpc_connected_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { - GRPC_CHANNEL_STACK_REF(CHANNEL_STACK_FROM_CONNECTION(c), REF_REASON); -} - -void grpc_connected_subchannel_unref(grpc_exec_ctx *exec_ctx, - grpc_connected_subchannel *c - GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { - GRPC_CHANNEL_STACK_UNREF(exec_ctx, CHANNEL_STACK_FROM_CONNECTION(c), - REF_REASON); -} - -/* - * grpc_subchannel implementation - */ - -static void subchannel_destroy(grpc_exec_ctx *exec_ctx, void *arg, - bool success) { - grpc_subchannel *c = arg; - gpr_free((void *)c->filters); - grpc_channel_args_destroy(c->args); - gpr_free(c->addr); - gpr_slice_unref(c->initial_connect_string); - grpc_connectivity_state_destroy(exec_ctx, &c->state_tracker); - grpc_connector_unref(exec_ctx, c->connector); - grpc_pollset_set_destroy(c->pollset_set); - grpc_subchannel_key_destroy(exec_ctx, c->key); - gpr_free(c); -} - -static gpr_atm ref_mutate(grpc_subchannel *c, gpr_atm delta, - int barrier REF_MUTATE_EXTRA_ARGS) { - gpr_atm old_val = barrier ? gpr_atm_full_fetch_add(&c->ref_pair, delta) - : gpr_atm_no_barrier_fetch_add(&c->ref_pair, delta); -#ifdef GRPC_STREAM_REFCOUNT_DEBUG - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, - "SUBCHANNEL: %p % 12s 0x%08x -> 0x%08x [%s]", c, purpose, old_val, - old_val + delta, reason); -#endif - return old_val; -} - -grpc_subchannel *grpc_subchannel_ref( - grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { - gpr_atm old_refs; - old_refs = ref_mutate(c, (1 << INTERNAL_REF_BITS), - 0 REF_MUTATE_PURPOSE("STRONG_REF")); - GPR_ASSERT((old_refs & STRONG_REF_MASK) != 0); - return c; -} - -grpc_subchannel *grpc_subchannel_weak_ref( - grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { - gpr_atm old_refs; - old_refs = ref_mutate(c, 1, 0 REF_MUTATE_PURPOSE("WEAK_REF")); - GPR_ASSERT(old_refs != 0); - return c; -} - -grpc_subchannel *grpc_subchannel_ref_from_weak_ref( - grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { - if (!c) return NULL; - for (;;) { - gpr_atm old_refs = gpr_atm_acq_load(&c->ref_pair); - if (old_refs >= (1 << INTERNAL_REF_BITS)) { - gpr_atm new_refs = old_refs + (1 << INTERNAL_REF_BITS); - if (gpr_atm_rel_cas(&c->ref_pair, old_refs, new_refs)) { - return c; - } - } else { - return NULL; - } - } -} - -static void disconnect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) { - grpc_connected_subchannel *con; - grpc_subchannel_index_unregister(exec_ctx, c->key, c); - gpr_mu_lock(&c->mu); - GPR_ASSERT(!c->disconnected); - c->disconnected = 1; - grpc_connector_shutdown(exec_ctx, c->connector); - con = GET_CONNECTED_SUBCHANNEL(c, no_barrier); - if (con != NULL) { - GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, con, "connection"); - gpr_atm_no_barrier_store(&c->connected_subchannel, 0xdeadbeef); - } - gpr_mu_unlock(&c->mu); -} - -void grpc_subchannel_unref(grpc_exec_ctx *exec_ctx, - grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { - gpr_atm old_refs; - old_refs = ref_mutate(c, (gpr_atm)1 - (gpr_atm)(1 << INTERNAL_REF_BITS), - 1 REF_MUTATE_PURPOSE("STRONG_UNREF")); - if ((old_refs & STRONG_REF_MASK) == (1 << INTERNAL_REF_BITS)) { - disconnect(exec_ctx, c); - } - GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "strong-unref"); -} - -void grpc_subchannel_weak_unref(grpc_exec_ctx *exec_ctx, - grpc_subchannel *c - GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { - gpr_atm old_refs; - old_refs = ref_mutate(c, -(gpr_atm)1, 1 REF_MUTATE_PURPOSE("WEAK_UNREF")); - if (old_refs == 1) { - grpc_exec_ctx_enqueue(exec_ctx, grpc_closure_create(subchannel_destroy, c), - true, NULL); - } -} - -static uint32_t random_seed() { - return (uint32_t)(gpr_time_to_millis(gpr_now(GPR_CLOCK_MONOTONIC))); -} - -grpc_subchannel *grpc_subchannel_create(grpc_exec_ctx *exec_ctx, - grpc_connector *connector, - grpc_subchannel_args *args) { - grpc_subchannel_key *key = grpc_subchannel_key_create(connector, args); - grpc_subchannel *c = grpc_subchannel_index_find(exec_ctx, key); - if (c) { - grpc_subchannel_key_destroy(exec_ctx, key); - return c; - } - - c = gpr_malloc(sizeof(*c)); - memset(c, 0, sizeof(*c)); - c->key = key; - gpr_atm_no_barrier_store(&c->ref_pair, 1 << INTERNAL_REF_BITS); - c->connector = connector; - grpc_connector_ref(c->connector); - c->num_filters = args->filter_count; - if (c->num_filters > 0) { - c->filters = gpr_malloc(sizeof(grpc_channel_filter *) * c->num_filters); - memcpy((void *)c->filters, args->filters, - sizeof(grpc_channel_filter *) * c->num_filters); - } else { - c->filters = NULL; - } - c->addr = gpr_malloc(args->addr_len); - memcpy(c->addr, args->addr, args->addr_len); - c->pollset_set = grpc_pollset_set_create(); - c->addr_len = args->addr_len; - grpc_set_initial_connect_string(&c->addr, &c->addr_len, - &c->initial_connect_string); - c->args = grpc_channel_args_copy(args->args); - c->random = random_seed(); - c->root_external_state_watcher.next = c->root_external_state_watcher.prev = - &c->root_external_state_watcher; - grpc_closure_init(&c->connected, subchannel_connected, c); - grpc_connectivity_state_init(&c->state_tracker, GRPC_CHANNEL_IDLE, - "subchannel"); - gpr_backoff_init(&c->backoff_state, - GRPC_SUBCHANNEL_RECONNECT_BACKOFF_MULTIPLIER, - GRPC_SUBCHANNEL_RECONNECT_JITTER, - GRPC_SUBCHANNEL_INITIAL_CONNECT_BACKOFF_SECONDS * 1000, - GRPC_SUBCHANNEL_RECONNECT_MAX_BACKOFF_SECONDS * 1000); - if (c->args) { - for (size_t i = 0; i < c->args->num_args; i++) { - if (0 == strcmp(c->args->args[i].key, - "grpc.testing.fixed_reconnect_backoff")) { - GPR_ASSERT(c->args->args[i].type == GRPC_ARG_INTEGER); - gpr_backoff_init(&c->backoff_state, 1.0, 0.0, - c->args->args[i].value.integer, - c->args->args[i].value.integer); - } - } - } - gpr_mu_init(&c->mu); - - return grpc_subchannel_index_register(exec_ctx, key, c); -} - -static void continue_connect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) { - grpc_connect_in_args args; - - args.interested_parties = c->pollset_set; - args.addr = c->addr; - args.addr_len = c->addr_len; - args.deadline = c->next_attempt; - args.channel_args = c->args; - args.initial_connect_string = c->initial_connect_string; - - grpc_connectivity_state_set(exec_ctx, &c->state_tracker, - GRPC_CHANNEL_CONNECTING, "state_change"); - grpc_connector_connect(exec_ctx, c->connector, &args, &c->connecting_result, - &c->connected); -} - -static void start_connect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) { - c->next_attempt = - gpr_backoff_begin(&c->backoff_state, gpr_now(GPR_CLOCK_MONOTONIC)); - continue_connect(exec_ctx, c); -} - -grpc_connectivity_state grpc_subchannel_check_connectivity(grpc_subchannel *c) { - grpc_connectivity_state state; - gpr_mu_lock(&c->mu); - state = grpc_connectivity_state_check(&c->state_tracker); - gpr_mu_unlock(&c->mu); - return state; -} - -static void on_external_state_watcher_done(grpc_exec_ctx *exec_ctx, void *arg, - bool success) { - external_state_watcher *w = arg; - grpc_closure *follow_up = w->notify; - if (w->pollset_set != NULL) { - grpc_pollset_set_del_pollset_set(exec_ctx, w->subchannel->pollset_set, - w->pollset_set); - } - gpr_mu_lock(&w->subchannel->mu); - w->next->prev = w->prev; - w->prev->next = w->next; - gpr_mu_unlock(&w->subchannel->mu); - GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, w->subchannel, "external_state_watcher"); - gpr_free(w); - follow_up->cb(exec_ctx, follow_up->cb_arg, success); -} - -void grpc_subchannel_notify_on_state_change( - grpc_exec_ctx *exec_ctx, grpc_subchannel *c, - grpc_pollset_set *interested_parties, grpc_connectivity_state *state, - grpc_closure *notify) { - external_state_watcher *w; - - if (state == NULL) { - gpr_mu_lock(&c->mu); - for (w = c->root_external_state_watcher.next; - w != &c->root_external_state_watcher; w = w->next) { - if (w->notify == notify) { - grpc_connectivity_state_notify_on_state_change( - exec_ctx, &c->state_tracker, NULL, &w->closure); - } - } - gpr_mu_unlock(&c->mu); - } else { - w = gpr_malloc(sizeof(*w)); - w->subchannel = c; - w->pollset_set = interested_parties; - w->notify = notify; - grpc_closure_init(&w->closure, on_external_state_watcher_done, w); - if (interested_parties != NULL) { - grpc_pollset_set_add_pollset_set(exec_ctx, c->pollset_set, - interested_parties); - } - GRPC_SUBCHANNEL_WEAK_REF(c, "external_state_watcher"); - gpr_mu_lock(&c->mu); - w->next = &c->root_external_state_watcher; - w->prev = w->next->prev; - w->next->prev = w->prev->next = w; - if (grpc_connectivity_state_notify_on_state_change( - exec_ctx, &c->state_tracker, state, &w->closure)) { - c->connecting = 1; - /* released by connection */ - GRPC_SUBCHANNEL_WEAK_REF(c, "connecting"); - start_connect(exec_ctx, c); - } - gpr_mu_unlock(&c->mu); - } -} - -void grpc_connected_subchannel_process_transport_op( - grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *con, - grpc_transport_op *op) { - grpc_channel_stack *channel_stack = CHANNEL_STACK_FROM_CONNECTION(con); - grpc_channel_element *top_elem = grpc_channel_stack_element(channel_stack, 0); - top_elem->filter->start_transport_op(exec_ctx, top_elem, op); -} - -static void subchannel_on_child_state_changed(grpc_exec_ctx *exec_ctx, void *p, - bool iomgr_success) { - state_watcher *sw = p; - grpc_subchannel *c = sw->subchannel; - gpr_mu *mu = &c->mu; - - gpr_mu_lock(mu); - - /* if we failed just leave this closure */ - if (iomgr_success) { - if (sw->connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) { - /* any errors on a subchannel ==> we're done, create a new one */ - sw->connectivity_state = GRPC_CHANNEL_FATAL_FAILURE; - } - grpc_connectivity_state_set(exec_ctx, &c->state_tracker, - sw->connectivity_state, "reflect_child"); - if (sw->connectivity_state != GRPC_CHANNEL_FATAL_FAILURE) { - grpc_connected_subchannel_notify_on_state_change( - exec_ctx, GET_CONNECTED_SUBCHANNEL(c, no_barrier), NULL, - &sw->connectivity_state, &sw->closure); - GRPC_SUBCHANNEL_WEAK_REF(c, "state_watcher"); - sw = NULL; - } - } - - gpr_mu_unlock(mu); - GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "state_watcher"); - gpr_free(sw); -} - -static void connected_subchannel_state_op(grpc_exec_ctx *exec_ctx, - grpc_connected_subchannel *con, - grpc_pollset_set *interested_parties, - grpc_connectivity_state *state, - grpc_closure *closure) { - grpc_transport_op op; - grpc_channel_element *elem; - memset(&op, 0, sizeof(op)); - op.connectivity_state = state; - op.on_connectivity_state_change = closure; - op.bind_pollset_set = interested_parties; - elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CONNECTION(con), 0); - elem->filter->start_transport_op(exec_ctx, elem, &op); -} - -void grpc_connected_subchannel_notify_on_state_change( - grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *con, - grpc_pollset_set *interested_parties, grpc_connectivity_state *state, - grpc_closure *closure) { - connected_subchannel_state_op(exec_ctx, con, interested_parties, state, - closure); -} - -void grpc_connected_subchannel_ping(grpc_exec_ctx *exec_ctx, - grpc_connected_subchannel *con, - grpc_closure *closure) { - grpc_transport_op op; - grpc_channel_element *elem; - memset(&op, 0, sizeof(op)); - op.send_ping = closure; - elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CONNECTION(con), 0); - elem->filter->start_transport_op(exec_ctx, elem, &op); -} - -static void publish_transport_locked(grpc_exec_ctx *exec_ctx, - grpc_subchannel *c) { - grpc_connected_subchannel *con; - grpc_channel_stack *stk; - state_watcher *sw_subchannel; - - /* construct channel stack */ - con = grpc_channel_init_create_stack( - exec_ctx, GRPC_CLIENT_SUBCHANNEL, 0, c->connecting_result.channel_args, 1, - connection_destroy, NULL, c->connecting_result.transport); - stk = CHANNEL_STACK_FROM_CONNECTION(con); - memset(&c->connecting_result, 0, sizeof(c->connecting_result)); - - /* initialize state watcher */ - sw_subchannel = gpr_malloc(sizeof(*sw_subchannel)); - sw_subchannel->subchannel = c; - sw_subchannel->connectivity_state = GRPC_CHANNEL_READY; - grpc_closure_init(&sw_subchannel->closure, subchannel_on_child_state_changed, - sw_subchannel); - - if (c->disconnected) { - gpr_free(sw_subchannel); - grpc_channel_stack_destroy(exec_ctx, stk); - gpr_free(con); - GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting"); - return; - } - - /* publish */ - /* TODO(ctiller): this full barrier seems to clear up a TSAN failure. - I'd have expected the rel_cas below to be enough, but - seemingly it's not. - Re-evaluate if we really need this. */ - gpr_atm_full_barrier(); - GPR_ASSERT(gpr_atm_rel_cas(&c->connected_subchannel, 0, (gpr_atm)con)); - c->connecting = 0; - - /* setup subchannel watching connected subchannel for changes; subchannel ref - for connecting is donated - to the state watcher */ - GRPC_SUBCHANNEL_WEAK_REF(c, "state_watcher"); - GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting"); - grpc_connected_subchannel_notify_on_state_change( - exec_ctx, con, c->pollset_set, &sw_subchannel->connectivity_state, - &sw_subchannel->closure); - - /* signal completion */ - grpc_connectivity_state_set(exec_ctx, &c->state_tracker, GRPC_CHANNEL_READY, - "connected"); -} - -static void on_alarm(grpc_exec_ctx *exec_ctx, void *arg, bool iomgr_success) { - grpc_subchannel *c = arg; - gpr_mu_lock(&c->mu); - c->have_alarm = 0; - if (c->disconnected) { - iomgr_success = 0; - } - if (iomgr_success) { - c->next_attempt = - gpr_backoff_step(&c->backoff_state, gpr_now(GPR_CLOCK_MONOTONIC)); - continue_connect(exec_ctx, c); - gpr_mu_unlock(&c->mu); - } else { - gpr_mu_unlock(&c->mu); - GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting"); - } -} - -static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *arg, - bool iomgr_success) { - grpc_subchannel *c = arg; - - GRPC_SUBCHANNEL_WEAK_REF(c, "connected"); - gpr_mu_lock(&c->mu); - if (c->connecting_result.transport != NULL) { - publish_transport_locked(exec_ctx, c); - } else if (c->disconnected) { - GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting"); - } else { - gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); - GPR_ASSERT(!c->have_alarm); - c->have_alarm = 1; - grpc_connectivity_state_set(exec_ctx, &c->state_tracker, - GRPC_CHANNEL_TRANSIENT_FAILURE, - "connect_failed"); - grpc_timer_init(exec_ctx, &c->alarm, c->next_attempt, on_alarm, c, now); - } - gpr_mu_unlock(&c->mu); - GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting"); -} - -/* - * grpc_subchannel_call implementation - */ - -static void subchannel_call_destroy(grpc_exec_ctx *exec_ctx, void *call, - bool success) { - grpc_subchannel_call *c = call; - GPR_TIMER_BEGIN("grpc_subchannel_call_unref.destroy", 0); - grpc_call_stack_destroy(exec_ctx, SUBCHANNEL_CALL_TO_CALL_STACK(c)); - GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, c->connection, "subchannel_call"); - gpr_free(c); - GPR_TIMER_END("grpc_subchannel_call_unref.destroy", 0); -} - -void grpc_subchannel_call_ref( - grpc_subchannel_call *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { - GRPC_CALL_STACK_REF(SUBCHANNEL_CALL_TO_CALL_STACK(c), REF_REASON); -} - -void grpc_subchannel_call_unref(grpc_exec_ctx *exec_ctx, - grpc_subchannel_call *c - GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { - GRPC_CALL_STACK_UNREF(exec_ctx, SUBCHANNEL_CALL_TO_CALL_STACK(c), REF_REASON); -} - -char *grpc_subchannel_call_get_peer(grpc_exec_ctx *exec_ctx, - grpc_subchannel_call *call) { - grpc_call_stack *call_stack = SUBCHANNEL_CALL_TO_CALL_STACK(call); - grpc_call_element *top_elem = grpc_call_stack_element(call_stack, 0); - return top_elem->filter->get_peer(exec_ctx, top_elem); -} - -void grpc_subchannel_call_process_op(grpc_exec_ctx *exec_ctx, - grpc_subchannel_call *call, - grpc_transport_stream_op *op) { - grpc_call_stack *call_stack = SUBCHANNEL_CALL_TO_CALL_STACK(call); - grpc_call_element *top_elem = grpc_call_stack_element(call_stack, 0); - top_elem->filter->start_transport_stream_op(exec_ctx, top_elem, op); -} - -grpc_connected_subchannel *grpc_subchannel_get_connected_subchannel( - grpc_subchannel *c) { - return GET_CONNECTED_SUBCHANNEL(c, acq); -} - -grpc_subchannel_call *grpc_connected_subchannel_create_call( - grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *con, - grpc_pollset *pollset) { - grpc_channel_stack *chanstk = CHANNEL_STACK_FROM_CONNECTION(con); - grpc_subchannel_call *call = - gpr_malloc(sizeof(grpc_subchannel_call) + chanstk->call_stack_size); - grpc_call_stack *callstk = SUBCHANNEL_CALL_TO_CALL_STACK(call); - call->connection = con; - GRPC_CONNECTED_SUBCHANNEL_REF(con, "subchannel_call"); - grpc_call_stack_init(exec_ctx, chanstk, 1, subchannel_call_destroy, call, - NULL, NULL, callstk); - grpc_call_stack_set_pollset(exec_ctx, callstk, pollset); - return call; -} - -grpc_call_stack *grpc_subchannel_call_get_call_stack( - grpc_subchannel_call *subchannel_call) { - return SUBCHANNEL_CALL_TO_CALL_STACK(subchannel_call); -} diff --git a/src/core/client_config/subchannel.h b/src/core/client_config/subchannel.h deleted file mode 100644 index 83e1c58a4c..0000000000 --- a/src/core/client_config/subchannel.h +++ /dev/null @@ -1,174 +0,0 @@ -/* - * - * Copyright 2015-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_CLIENT_CONFIG_SUBCHANNEL_H -#define GRPC_CORE_CLIENT_CONFIG_SUBCHANNEL_H - -#include "src/core/channel/channel_stack.h" -#include "src/core/client_config/connector.h" -#include "src/core/transport/connectivity_state.h" - -/** A (sub-)channel that knows how to connect to exactly one target - address. Provides a target for load balancing. */ -typedef struct grpc_subchannel grpc_subchannel; -typedef struct grpc_connected_subchannel grpc_connected_subchannel; -typedef struct grpc_subchannel_call grpc_subchannel_call; -typedef struct grpc_subchannel_args grpc_subchannel_args; - -#ifdef GRPC_STREAM_REFCOUNT_DEBUG -#define GRPC_SUBCHANNEL_REF(p, r) \ - grpc_subchannel_ref((p), __FILE__, __LINE__, (r)) -#define GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(p, r) \ - grpc_subchannel_ref_from_weak_ref((p), __FILE__, __LINE__, (r)) -#define GRPC_SUBCHANNEL_UNREF(cl, p, r) \ - grpc_subchannel_unref((cl), (p), __FILE__, __LINE__, (r)) -#define GRPC_SUBCHANNEL_WEAK_REF(p, r) \ - grpc_subchannel_weak_ref((p), __FILE__, __LINE__, (r)) -#define GRPC_SUBCHANNEL_WEAK_UNREF(cl, p, r) \ - grpc_subchannel_weak_unref((cl), (p), __FILE__, __LINE__, (r)) -#define GRPC_CONNECTED_SUBCHANNEL_REF(p, r) \ - grpc_connected_subchannel_ref((p), __FILE__, __LINE__, (r)) -#define GRPC_CONNECTED_SUBCHANNEL_UNREF(cl, p, r) \ - grpc_connected_subchannel_unref((cl), (p), __FILE__, __LINE__, (r)) -#define GRPC_SUBCHANNEL_CALL_REF(p, r) \ - grpc_subchannel_call_ref((p), __FILE__, __LINE__, (r)) -#define GRPC_SUBCHANNEL_CALL_UNREF(cl, p, r) \ - grpc_subchannel_call_unref((cl), (p), __FILE__, __LINE__, (r)) -#define GRPC_SUBCHANNEL_REF_EXTRA_ARGS \ - , const char *file, int line, const char *reason -#else -#define GRPC_SUBCHANNEL_REF(p, r) grpc_subchannel_ref((p)) -#define GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(p, r) \ - grpc_subchannel_ref_from_weak_ref((p)) -#define GRPC_SUBCHANNEL_UNREF(cl, p, r) grpc_subchannel_unref((cl), (p)) -#define GRPC_SUBCHANNEL_WEAK_REF(p, r) grpc_subchannel_weak_ref((p)) -#define GRPC_SUBCHANNEL_WEAK_UNREF(cl, p, r) \ - grpc_subchannel_weak_unref((cl), (p)) -#define GRPC_CONNECTED_SUBCHANNEL_REF(p, r) grpc_connected_subchannel_ref((p)) -#define GRPC_CONNECTED_SUBCHANNEL_UNREF(cl, p, r) \ - grpc_connected_subchannel_unref((cl), (p)) -#define GRPC_SUBCHANNEL_CALL_REF(p, r) grpc_subchannel_call_ref((p)) -#define GRPC_SUBCHANNEL_CALL_UNREF(cl, p, r) \ - grpc_subchannel_call_unref((cl), (p)) -#define GRPC_SUBCHANNEL_REF_EXTRA_ARGS -#endif - -grpc_subchannel *grpc_subchannel_ref( - grpc_subchannel *channel GRPC_SUBCHANNEL_REF_EXTRA_ARGS); -grpc_subchannel *grpc_subchannel_ref_from_weak_ref( - grpc_subchannel *channel GRPC_SUBCHANNEL_REF_EXTRA_ARGS); -void grpc_subchannel_unref(grpc_exec_ctx *exec_ctx, - grpc_subchannel *channel - GRPC_SUBCHANNEL_REF_EXTRA_ARGS); -grpc_subchannel *grpc_subchannel_weak_ref( - grpc_subchannel *channel GRPC_SUBCHANNEL_REF_EXTRA_ARGS); -void grpc_subchannel_weak_unref(grpc_exec_ctx *exec_ctx, - grpc_subchannel *channel - GRPC_SUBCHANNEL_REF_EXTRA_ARGS); -void grpc_connected_subchannel_ref( - grpc_connected_subchannel *channel GRPC_SUBCHANNEL_REF_EXTRA_ARGS); -void grpc_connected_subchannel_unref(grpc_exec_ctx *exec_ctx, - grpc_connected_subchannel *channel - GRPC_SUBCHANNEL_REF_EXTRA_ARGS); -void grpc_subchannel_call_ref( - grpc_subchannel_call *call GRPC_SUBCHANNEL_REF_EXTRA_ARGS); -void grpc_subchannel_call_unref(grpc_exec_ctx *exec_ctx, - grpc_subchannel_call *call - GRPC_SUBCHANNEL_REF_EXTRA_ARGS); - -/** construct a subchannel call */ -grpc_subchannel_call *grpc_connected_subchannel_create_call( - grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *connected_subchannel, - grpc_pollset *pollset); - -/** process a transport level op */ -void grpc_connected_subchannel_process_transport_op( - grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *subchannel, - grpc_transport_op *op); - -/** poll the current connectivity state of a channel */ -grpc_connectivity_state grpc_subchannel_check_connectivity( - grpc_subchannel *channel); - -/** call notify when the connectivity state of a channel changes from *state. - Updates *state with the new state of the channel */ -void grpc_subchannel_notify_on_state_change( - grpc_exec_ctx *exec_ctx, grpc_subchannel *channel, - grpc_pollset_set *interested_parties, grpc_connectivity_state *state, - grpc_closure *notify); -void grpc_connected_subchannel_notify_on_state_change( - grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *channel, - grpc_pollset_set *interested_parties, grpc_connectivity_state *state, - grpc_closure *notify); -void grpc_connected_subchannel_ping(grpc_exec_ctx *exec_ctx, - grpc_connected_subchannel *channel, - grpc_closure *notify); - -/** retrieve the grpc_connected_subchannel - or NULL if called before - the subchannel becomes connected */ -grpc_connected_subchannel *grpc_subchannel_get_connected_subchannel( - grpc_subchannel *subchannel); - -/** continue processing a transport op */ -void grpc_subchannel_call_process_op(grpc_exec_ctx *exec_ctx, - grpc_subchannel_call *subchannel_call, - grpc_transport_stream_op *op); - -/** continue querying for peer */ -char *grpc_subchannel_call_get_peer(grpc_exec_ctx *exec_ctx, - grpc_subchannel_call *subchannel_call); - -grpc_call_stack *grpc_subchannel_call_get_call_stack( - grpc_subchannel_call *subchannel_call); - -struct grpc_subchannel_args { - /* When updating this struct, also update subchannel_index.c */ - - /** Channel filters for this channel - wrapped factories will likely - want to mutate this */ - const grpc_channel_filter **filters; - /** The number of filters in the above array */ - size_t filter_count; - /** Channel arguments to be supplied to the newly created channel */ - const grpc_channel_args *args; - /** Address to connect to */ - struct sockaddr *addr; - size_t addr_len; -}; - -/** create a subchannel given a connector */ -grpc_subchannel *grpc_subchannel_create(grpc_exec_ctx *exec_ctx, - grpc_connector *connector, - grpc_subchannel_args *args); - -#endif /* GRPC_CORE_CLIENT_CONFIG_SUBCHANNEL_H */ diff --git a/src/core/client_config/subchannel_factory.c b/src/core/client_config/subchannel_factory.c deleted file mode 100644 index 2c64219e8b..0000000000 --- a/src/core/client_config/subchannel_factory.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/client_config/subchannel_factory.h" - -void grpc_subchannel_factory_ref(grpc_subchannel_factory* factory) { - factory->vtable->ref(factory); -} - -void grpc_subchannel_factory_unref(grpc_exec_ctx* exec_ctx, - grpc_subchannel_factory* factory) { - factory->vtable->unref(exec_ctx, factory); -} - -grpc_subchannel* grpc_subchannel_factory_create_subchannel( - grpc_exec_ctx* exec_ctx, grpc_subchannel_factory* factory, - grpc_subchannel_args* args) { - return factory->vtable->create_subchannel(exec_ctx, factory, args); -} diff --git a/src/core/client_config/subchannel_factory.h b/src/core/client_config/subchannel_factory.h deleted file mode 100644 index c638f377a6..0000000000 --- a/src/core/client_config/subchannel_factory.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * - * Copyright 2015-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_CLIENT_CONFIG_SUBCHANNEL_FACTORY_H -#define GRPC_CORE_CLIENT_CONFIG_SUBCHANNEL_FACTORY_H - -#include "src/core/channel/channel_stack.h" -#include "src/core/client_config/subchannel.h" - -typedef struct grpc_subchannel_factory grpc_subchannel_factory; -typedef struct grpc_subchannel_factory_vtable grpc_subchannel_factory_vtable; - -/** Constructor for new configured channels. - Creating decorators around this type is encouraged to adapt behavior. */ -struct grpc_subchannel_factory { - const grpc_subchannel_factory_vtable *vtable; -}; - -struct grpc_subchannel_factory_vtable { - void (*ref)(grpc_subchannel_factory *factory); - void (*unref)(grpc_exec_ctx *exec_ctx, grpc_subchannel_factory *factory); - grpc_subchannel *(*create_subchannel)(grpc_exec_ctx *exec_ctx, - grpc_subchannel_factory *factory, - grpc_subchannel_args *args); -}; - -void grpc_subchannel_factory_ref(grpc_subchannel_factory *factory); -void grpc_subchannel_factory_unref(grpc_exec_ctx *exec_ctx, - grpc_subchannel_factory *factory); - -/** Create a new grpc_subchannel */ -grpc_subchannel *grpc_subchannel_factory_create_subchannel( - grpc_exec_ctx *exec_ctx, grpc_subchannel_factory *factory, - grpc_subchannel_args *args); - -#endif /* GRPC_CORE_CLIENT_CONFIG_SUBCHANNEL_FACTORY_H */ diff --git a/src/core/client_config/subchannel_index.c b/src/core/client_config/subchannel_index.c deleted file mode 100644 index 24cc76cf22..0000000000 --- a/src/core/client_config/subchannel_index.c +++ /dev/null @@ -1,262 +0,0 @@ -// -// -// 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/client_config/subchannel_index.h" - -#include -#include - -#include -#include -#include - -#include "src/core/channel/channel_args.h" - -// a map of subchannel_key --> subchannel, used for detecting connections -// to the same destination in order to share them -static gpr_avl g_subchannel_index; - -static gpr_mu g_mu; - -struct grpc_subchannel_key { - grpc_connector *connector; - grpc_subchannel_args args; -}; - -GPR_TLS_DECL(subchannel_index_exec_ctx); - -static void enter_ctx(grpc_exec_ctx *exec_ctx) { - GPR_ASSERT(gpr_tls_get(&subchannel_index_exec_ctx) == 0); - gpr_tls_set(&subchannel_index_exec_ctx, (intptr_t)exec_ctx); -} - -static void leave_ctx(grpc_exec_ctx *exec_ctx) { - GPR_ASSERT(gpr_tls_get(&subchannel_index_exec_ctx) == (intptr_t)exec_ctx); - gpr_tls_set(&subchannel_index_exec_ctx, 0); -} - -static grpc_exec_ctx *current_ctx() { - grpc_exec_ctx *c = (grpc_exec_ctx *)gpr_tls_get(&subchannel_index_exec_ctx); - GPR_ASSERT(c != NULL); - return c; -} - -static grpc_subchannel_key *create_key( - grpc_connector *connector, grpc_subchannel_args *args, - grpc_channel_args *(*copy_channel_args)(const grpc_channel_args *args)) { - grpc_subchannel_key *k = gpr_malloc(sizeof(*k)); - k->connector = grpc_connector_ref(connector); - k->args.filter_count = args->filter_count; - k->args.filters = gpr_malloc(sizeof(*k->args.filters) * k->args.filter_count); - memcpy((grpc_channel_filter *)k->args.filters, args->filters, - sizeof(*k->args.filters) * k->args.filter_count); - k->args.addr_len = args->addr_len; - k->args.addr = gpr_malloc(args->addr_len); - memcpy(k->args.addr, args->addr, k->args.addr_len); - k->args.args = copy_channel_args(args->args); - return k; -} - -grpc_subchannel_key *grpc_subchannel_key_create(grpc_connector *connector, - grpc_subchannel_args *args) { - return create_key(connector, args, grpc_channel_args_normalize); -} - -static grpc_subchannel_key *subchannel_key_copy(grpc_subchannel_key *k) { - return create_key(k->connector, &k->args, grpc_channel_args_copy); -} - -static int subchannel_key_compare(grpc_subchannel_key *a, - grpc_subchannel_key *b) { - int c = GPR_ICMP(a->connector, b->connector); - if (c != 0) return c; - c = GPR_ICMP(a->args.addr_len, b->args.addr_len); - if (c != 0) return c; - c = GPR_ICMP(a->args.filter_count, b->args.filter_count); - if (c != 0) return c; - c = memcmp(a->args.addr, b->args.addr, a->args.addr_len); - if (c != 0) return c; - c = memcmp(a->args.filters, b->args.filters, - a->args.filter_count * sizeof(*a->args.filters)); - if (c != 0) return c; - return grpc_channel_args_compare(a->args.args, b->args.args); -} - -void grpc_subchannel_key_destroy(grpc_exec_ctx *exec_ctx, - grpc_subchannel_key *k) { - grpc_connector_unref(exec_ctx, k->connector); - gpr_free(k->args.addr); - gpr_free((grpc_channel_args *)k->args.filters); - grpc_channel_args_destroy((grpc_channel_args *)k->args.args); - gpr_free(k); -} - -static void sck_avl_destroy(void *p) { - grpc_subchannel_key_destroy(current_ctx(), p); -} - -static void *sck_avl_copy(void *p) { return subchannel_key_copy(p); } - -static long sck_avl_compare(void *a, void *b) { - return subchannel_key_compare(a, b); -} - -static void scv_avl_destroy(void *p) { - GRPC_SUBCHANNEL_WEAK_UNREF(current_ctx(), p, "subchannel_index"); -} - -static void *scv_avl_copy(void *p) { - GRPC_SUBCHANNEL_WEAK_REF(p, "subchannel_index"); - return p; -} - -static const gpr_avl_vtable subchannel_avl_vtable = { - .destroy_key = sck_avl_destroy, - .copy_key = sck_avl_copy, - .compare_keys = sck_avl_compare, - .destroy_value = scv_avl_destroy, - .copy_value = scv_avl_copy}; - -void grpc_subchannel_index_init(void) { - g_subchannel_index = gpr_avl_create(&subchannel_avl_vtable); - gpr_mu_init(&g_mu); - gpr_tls_init(&subchannel_index_exec_ctx); -} - -void grpc_subchannel_index_shutdown(void) { - gpr_mu_destroy(&g_mu); - gpr_avl_unref(g_subchannel_index); - gpr_tls_destroy(&subchannel_index_exec_ctx); -} - -grpc_subchannel *grpc_subchannel_index_find(grpc_exec_ctx *exec_ctx, - grpc_subchannel_key *key) { - enter_ctx(exec_ctx); - - // Lock, and take a reference to the subchannel index. - // We don't need to do the search under a lock as avl's are immutable. - gpr_mu_lock(&g_mu); - gpr_avl index = gpr_avl_ref(g_subchannel_index); - gpr_mu_unlock(&g_mu); - - grpc_subchannel *c = - GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(gpr_avl_get(index, key), "index_find"); - gpr_avl_unref(index); - - leave_ctx(exec_ctx); - return c; -} - -grpc_subchannel *grpc_subchannel_index_register(grpc_exec_ctx *exec_ctx, - grpc_subchannel_key *key, - grpc_subchannel *constructed) { - enter_ctx(exec_ctx); - - grpc_subchannel *c = NULL; - - while (c == NULL) { - // Compare and swap loop: - // - take a reference to the current index - gpr_mu_lock(&g_mu); - gpr_avl index = gpr_avl_ref(g_subchannel_index); - gpr_mu_unlock(&g_mu); - - // - Check to see if a subchannel already exists - c = gpr_avl_get(index, key); - if (c != NULL) { - // yes -> we're done - GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, constructed, "index_register"); - } else { - // no -> update the avl and compare/swap - gpr_avl updated = - gpr_avl_add(gpr_avl_ref(index), subchannel_key_copy(key), - GRPC_SUBCHANNEL_WEAK_REF(constructed, "index_register")); - - // it may happen (but it's expected to be unlikely) - // that some other thread has changed the index: - // compare/swap here to check that, and retry as necessary - gpr_mu_lock(&g_mu); - if (index.root == g_subchannel_index.root) { - GPR_SWAP(gpr_avl, updated, g_subchannel_index); - c = constructed; - } - gpr_mu_unlock(&g_mu); - - gpr_avl_unref(updated); - } - gpr_avl_unref(index); - } - - leave_ctx(exec_ctx); - - return c; -} - -void grpc_subchannel_index_unregister(grpc_exec_ctx *exec_ctx, - grpc_subchannel_key *key, - grpc_subchannel *constructed) { - enter_ctx(exec_ctx); - - bool done = false; - while (!done) { - // Compare and swap loop: - // - take a reference to the current index - gpr_mu_lock(&g_mu); - gpr_avl index = gpr_avl_ref(g_subchannel_index); - gpr_mu_unlock(&g_mu); - - // Check to see if this key still refers to the previously - // registered subchannel - grpc_subchannel *c = gpr_avl_get(index, key); - if (c != constructed) { - gpr_avl_unref(index); - break; - } - - // compare and swap the update (some other thread may have - // mutated the index behind us) - gpr_avl updated = gpr_avl_remove(gpr_avl_ref(index), key); - - gpr_mu_lock(&g_mu); - if (index.root == g_subchannel_index.root) { - GPR_SWAP(gpr_avl, updated, g_subchannel_index); - done = true; - } - gpr_mu_unlock(&g_mu); - - gpr_avl_unref(updated); - gpr_avl_unref(index); - } - - leave_ctx(exec_ctx); -} diff --git a/src/core/client_config/subchannel_index.h b/src/core/client_config/subchannel_index.h deleted file mode 100644 index 3cd5d12349..0000000000 --- a/src/core/client_config/subchannel_index.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * - * 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_CLIENT_CONFIG_SUBCHANNEL_INDEX_H -#define GRPC_CORE_CLIENT_CONFIG_SUBCHANNEL_INDEX_H - -#include "src/core/client_config/connector.h" -#include "src/core/client_config/subchannel.h" - -/** \file Provides an index of active subchannels so that they can be - shared amongst channels */ - -typedef struct grpc_subchannel_key grpc_subchannel_key; - -/** Create a key that can be used to uniquely identify a subchannel */ -grpc_subchannel_key *grpc_subchannel_key_create(grpc_connector *con, - grpc_subchannel_args *args); - -/** Destroy a subchannel key */ -void grpc_subchannel_key_destroy(grpc_exec_ctx *exec_ctx, - grpc_subchannel_key *key); - -/** Given a subchannel key, find the subchannel registered for it. - Returns NULL if no such channel exists. - Thread-safe. */ -grpc_subchannel *grpc_subchannel_index_find(grpc_exec_ctx *exec_ctx, - grpc_subchannel_key *key); - -/** Register a subchannel against a key. - Takes ownership of \a constructed. - Returns the registered subchannel. This may be different from - \a constructed in the case of a registration race. */ -grpc_subchannel *grpc_subchannel_index_register(grpc_exec_ctx *exec_ctx, - grpc_subchannel_key *key, - grpc_subchannel *constructed); - -/** Remove \a constructed as the registered subchannel for \a key. */ -void grpc_subchannel_index_unregister(grpc_exec_ctx *exec_ctx, - grpc_subchannel_key *key, - grpc_subchannel *constructed); - -/** Initialize the subchannel index (global) */ -void grpc_subchannel_index_init(void); -/** Shutdown the subchannel index (global) */ -void grpc_subchannel_index_shutdown(void); - -#endif /* GRPC_CORE_CLIENT_CONFIG_SUBCHANNEL_INDEX_H */ diff --git a/src/core/client_config/uri_parser.c b/src/core/client_config/uri_parser.c deleted file mode 100644 index cbdfffcf8e..0000000000 --- a/src/core/client_config/uri_parser.c +++ /dev/null @@ -1,242 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/client_config/uri_parser.h" - -#include - -#include -#include -#include -#include - -/** a size_t default value... maps to all 1's */ -#define NOT_SET (~(size_t)0) - -static grpc_uri *bad_uri(const char *uri_text, size_t pos, const char *section, - int suppress_errors) { - char *line_prefix; - size_t pfx_len; - - if (!suppress_errors) { - gpr_asprintf(&line_prefix, "bad uri.%s: '", section); - pfx_len = strlen(line_prefix) + pos; - gpr_log(GPR_ERROR, "%s%s'", line_prefix, uri_text); - gpr_free(line_prefix); - - line_prefix = gpr_malloc(pfx_len + 1); - memset(line_prefix, ' ', pfx_len); - line_prefix[pfx_len] = 0; - gpr_log(GPR_ERROR, "%s^ here", line_prefix); - gpr_free(line_prefix); - } - - return NULL; -} - -/** Returns a copy of \a src[begin, end) */ -static char *copy_component(const char *src, size_t begin, size_t end) { - char *out = gpr_malloc(end - begin + 1); - memcpy(out, src + begin, end - begin); - out[end - begin] = 0; - return out; -} - -/** Returns how many chars to advance if \a uri_text[i] begins a valid \a pchar - * production. If \a uri_text[i] introduces an invalid \a pchar (such as percent - * sign not followed by two hex digits), NOT_SET is returned. */ -static size_t parse_pchar(const char *uri_text, size_t i) { - /* pchar = unreserved / pct-encoded / sub-delims / ":" / "@" - * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" - * pct-encoded = "%" HEXDIG HEXDIG - * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" - / "*" / "+" / "," / ";" / "=" */ - char c = uri_text[i]; - if (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) || - ((c >= '0') && (c <= '9')) || - (c == '-' || c == '.' || c == '_' || c == '~') || /* unreserved */ - (c == '!' || c == '$' || c == '&' || c == '\'' || c == '$' || c == '&' || - c == '(' || c == ')' || c == '*' || c == '+' || c == ',' || c == ';' || - c == '=') /* sub-delims */) { - return 1; - } - if (c == '%') { /* pct-encoded */ - size_t j; - if (uri_text[i + 1] == 0 || uri_text[i + 2] == 0) { - return NOT_SET; - } - for (j = i + 1; j < 2; j++) { - c = uri_text[j]; - if (!(((c >= '0') && (c <= '9')) || ((c >= 'a') && (c <= 'f')) || - ((c >= 'A') && (c <= 'F')))) { - return NOT_SET; - } - } - return 2; - } - return 0; -} - -/* *( pchar / "?" / "/" ) */ -static int parse_fragment_or_query(const char *uri_text, size_t *i) { - char c; - while ((c = uri_text[*i]) != 0) { - const size_t advance = parse_pchar(uri_text, *i); /* pchar */ - switch (advance) { - case 0: /* uri_text[i] isn't in pchar */ - /* maybe it's ? or / */ - if (uri_text[*i] == '?' || uri_text[*i] == '/') { - (*i)++; - break; - } else { - return 1; - } - GPR_UNREACHABLE_CODE(return 0); - default: - (*i) += advance; - break; - case NOT_SET: /* uri_text[i] introduces an invalid URI */ - return 0; - } - } - /* *i is the first uri_text position past the \a query production, maybe \0 */ - return 1; -} - -grpc_uri *grpc_uri_parse(const char *uri_text, int suppress_errors) { - grpc_uri *uri; - size_t scheme_begin = 0; - size_t scheme_end = NOT_SET; - size_t authority_begin = NOT_SET; - size_t authority_end = NOT_SET; - size_t path_begin = NOT_SET; - size_t path_end = NOT_SET; - size_t query_begin = NOT_SET; - size_t query_end = NOT_SET; - size_t fragment_begin = NOT_SET; - size_t fragment_end = NOT_SET; - size_t i; - - for (i = scheme_begin; uri_text[i] != 0; i++) { - if (uri_text[i] == ':') { - scheme_end = i; - break; - } - if (uri_text[i] >= 'a' && uri_text[i] <= 'z') continue; - if (uri_text[i] >= 'A' && uri_text[i] <= 'Z') continue; - if (i != scheme_begin) { - if (uri_text[i] >= '0' && uri_text[i] <= '9') continue; - if (uri_text[i] == '+') continue; - if (uri_text[i] == '-') continue; - if (uri_text[i] == '.') continue; - } - break; - } - if (scheme_end == NOT_SET) { - return bad_uri(uri_text, i, "scheme", suppress_errors); - } - - if (uri_text[scheme_end + 1] == '/' && uri_text[scheme_end + 2] == '/') { - authority_begin = scheme_end + 3; - for (i = authority_begin; uri_text[i] != 0 && authority_end == NOT_SET; - i++) { - if (uri_text[i] == '/' || uri_text[i] == '?' || uri_text[i] == '#') { - authority_end = i; - } - } - if (authority_end == NOT_SET && uri_text[i] == 0) { - authority_end = i; - } - if (authority_end == NOT_SET) { - return bad_uri(uri_text, i, "authority", suppress_errors); - } - /* TODO(ctiller): parse the authority correctly */ - path_begin = authority_end; - } else { - path_begin = scheme_end + 1; - } - - for (i = path_begin; uri_text[i] != 0; i++) { - if (uri_text[i] == '?' || uri_text[i] == '#') { - path_end = i; - break; - } - } - if (path_end == NOT_SET && uri_text[i] == 0) { - path_end = i; - } - if (path_end == NOT_SET) { - return bad_uri(uri_text, i, "path", suppress_errors); - } - - if (uri_text[i] == '?') { - query_begin = ++i; - if (!parse_fragment_or_query(uri_text, &i)) { - return bad_uri(uri_text, i, "query", suppress_errors); - } else if (uri_text[i] != 0 && uri_text[i] != '#') { - /* We must be at the end or at the beginning of a fragment */ - return bad_uri(uri_text, i, "query", suppress_errors); - } - query_end = i; - } - if (uri_text[i] == '#') { - fragment_begin = ++i; - if (!parse_fragment_or_query(uri_text, &i)) { - return bad_uri(uri_text, i - fragment_end, "fragment", suppress_errors); - } else if (uri_text[i] != 0) { - /* We must be at the end */ - return bad_uri(uri_text, i, "fragment", suppress_errors); - } - fragment_end = i; - } - - uri = gpr_malloc(sizeof(*uri)); - memset(uri, 0, sizeof(*uri)); - uri->scheme = copy_component(uri_text, scheme_begin, scheme_end); - uri->authority = copy_component(uri_text, authority_begin, authority_end); - uri->path = copy_component(uri_text, path_begin, path_end); - uri->query = copy_component(uri_text, query_begin, query_end); - uri->fragment = copy_component(uri_text, fragment_begin, fragment_end); - - return uri; -} - -void grpc_uri_destroy(grpc_uri *uri) { - if (!uri) return; - gpr_free(uri->scheme); - gpr_free(uri->authority); - gpr_free(uri->path); - gpr_free(uri->query); - gpr_free(uri->fragment); - gpr_free(uri); -} diff --git a/src/core/client_config/uri_parser.h b/src/core/client_config/uri_parser.h deleted file mode 100644 index af013d8cac..0000000000 --- a/src/core/client_config/uri_parser.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * - * Copyright 2015-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_CLIENT_CONFIG_URI_PARSER_H -#define GRPC_CORE_CLIENT_CONFIG_URI_PARSER_H - -typedef struct { - char *scheme; - char *authority; - char *path; - char *query; - char *fragment; -} grpc_uri; - -/** parse a uri, return NULL on failure */ -grpc_uri *grpc_uri_parse(const char *uri_text, int suppress_errors); - -/** destroy a uri */ -void grpc_uri_destroy(grpc_uri *uri); - -#endif /* GRPC_CORE_CLIENT_CONFIG_URI_PARSER_H */ diff --git a/src/core/compression/algorithm_metadata.h b/src/core/compression/algorithm_metadata.h deleted file mode 100644 index 34abf1dba2..0000000000 --- a/src/core/compression/algorithm_metadata.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * - * Copyright 2015-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_COMPRESSION_ALGORITHM_METADATA_H -#define GRPC_CORE_COMPRESSION_ALGORITHM_METADATA_H - -#include -#include "src/core/transport/metadata.h" - -/** Return compression algorithm based metadata value */ -grpc_mdstr *grpc_compression_algorithm_mdstr( - grpc_compression_algorithm algorithm); - -/** Return compression algorithm based metadata element (grpc-encoding: xxx) */ -grpc_mdelem *grpc_compression_encoding_mdelem( - grpc_compression_algorithm algorithm); - -/** Find compression algorithm based on passed in mdstr - returns - * GRPC_COMPRESS_ALGORITHM_COUNT on failure */ -grpc_compression_algorithm grpc_compression_algorithm_from_mdstr( - grpc_mdstr *str); - -#endif /* GRPC_CORE_COMPRESSION_ALGORITHM_METADATA_H */ diff --git a/src/core/compression/compression_algorithm.c b/src/core/compression/compression_algorithm.c deleted file mode 100644 index 2810a38b68..0000000000 --- a/src/core/compression/compression_algorithm.c +++ /dev/null @@ -1,203 +0,0 @@ -/* - * - * Copyright 2015-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 -#include - -#include -#include - -#include "src/core/compression/algorithm_metadata.h" -#include "src/core/surface/api_trace.h" -#include "src/core/transport/static_metadata.h" - -int grpc_compression_algorithm_parse(const char *name, size_t name_length, - grpc_compression_algorithm *algorithm) { - /* we use strncmp not only because it's safer (even though in this case it - * doesn't matter, given that we are comparing against string literals, but - * because this way we needn't have "name" nil-terminated (useful for slice - * data, for example) */ - GRPC_API_TRACE( - "grpc_compression_algorithm_parse(" - "name=%*.*s, name_length=%lu, algorithm=%p)", - 5, ((int)name_length, (int)name_length, name, (unsigned long)name_length, - algorithm)); - if (name_length == 0) { - return 0; - } - if (strncmp(name, "identity", name_length) == 0) { - *algorithm = GRPC_COMPRESS_NONE; - } else if (strncmp(name, "gzip", name_length) == 0) { - *algorithm = GRPC_COMPRESS_GZIP; - } else if (strncmp(name, "deflate", name_length) == 0) { - *algorithm = GRPC_COMPRESS_DEFLATE; - } else { - return 0; - } - return 1; -} - -int grpc_compression_algorithm_name(grpc_compression_algorithm algorithm, - char **name) { - GRPC_API_TRACE("grpc_compression_algorithm_parse(algorithm=%d, name=%p)", 2, - ((int)algorithm, name)); - switch (algorithm) { - case GRPC_COMPRESS_NONE: - *name = "identity"; - return 1; - case GRPC_COMPRESS_DEFLATE: - *name = "deflate"; - return 1; - case GRPC_COMPRESS_GZIP: - *name = "gzip"; - return 1; - case GRPC_COMPRESS_ALGORITHMS_COUNT: - return 0; - } - return 0; -} - -grpc_compression_algorithm grpc_compression_algorithm_from_mdstr( - grpc_mdstr *str) { - if (str == GRPC_MDSTR_IDENTITY) return GRPC_COMPRESS_NONE; - if (str == GRPC_MDSTR_DEFLATE) return GRPC_COMPRESS_DEFLATE; - if (str == GRPC_MDSTR_GZIP) return GRPC_COMPRESS_GZIP; - return GRPC_COMPRESS_ALGORITHMS_COUNT; -} - -grpc_mdstr *grpc_compression_algorithm_mdstr( - grpc_compression_algorithm algorithm) { - switch (algorithm) { - case GRPC_COMPRESS_NONE: - return GRPC_MDSTR_IDENTITY; - case GRPC_COMPRESS_DEFLATE: - return GRPC_MDSTR_DEFLATE; - case GRPC_COMPRESS_GZIP: - return GRPC_MDSTR_GZIP; - case GRPC_COMPRESS_ALGORITHMS_COUNT: - return NULL; - } - return NULL; -} - -grpc_mdelem *grpc_compression_encoding_mdelem( - grpc_compression_algorithm algorithm) { - switch (algorithm) { - case GRPC_COMPRESS_NONE: - return GRPC_MDELEM_GRPC_ENCODING_IDENTITY; - case GRPC_COMPRESS_DEFLATE: - return GRPC_MDELEM_GRPC_ENCODING_DEFLATE; - case GRPC_COMPRESS_GZIP: - return GRPC_MDELEM_GRPC_ENCODING_GZIP; - default: - break; - } - return NULL; -} - -/* TODO(dgq): Add the ability to specify parameters to the individual - * compression algorithms */ -grpc_compression_algorithm grpc_compression_algorithm_for_level( - grpc_compression_level level, uint32_t accepted_encodings) { - GRPC_API_TRACE("grpc_compression_algorithm_for_level(level=%d)", 1, - ((int)level)); - if (level > GRPC_COMPRESS_LEVEL_HIGH) { - gpr_log(GPR_ERROR, "Unknown compression level %d.", (int)level); - abort(); - } - - const size_t num_supported = - GPR_BITCOUNT(accepted_encodings) - 1; /* discard NONE */ - if (level == GRPC_COMPRESS_LEVEL_NONE || num_supported == 0) { - return GRPC_COMPRESS_NONE; - } - - GPR_ASSERT(level > 0); - - /* Establish a "ranking" or compression algorithms in increasing order of - * compression. - * This is simplistic and we will probably want to introduce other dimensions - * in the future (cpu/memory cost, etc). */ - const grpc_compression_algorithm algos_ranking[] = {GRPC_COMPRESS_GZIP, - GRPC_COMPRESS_DEFLATE}; - - /* intersect algos_ranking with the supported ones keeping the ranked order */ - grpc_compression_algorithm - sorted_supported_algos[GRPC_COMPRESS_ALGORITHMS_COUNT]; - size_t algos_supported_idx = 0; - for (size_t i = 0; i < GPR_ARRAY_SIZE(algos_ranking); i++) { - const grpc_compression_algorithm alg = algos_ranking[i]; - for (size_t j = 0; j < num_supported; j++) { - if (GPR_BITGET(accepted_encodings, alg) == 1) { - /* if \a alg in supported */ - sorted_supported_algos[algos_supported_idx++] = alg; - break; - } - } - if (algos_supported_idx == num_supported) break; - } - - switch (level) { - case GRPC_COMPRESS_LEVEL_NONE: - abort(); /* should have been handled already */ - case GRPC_COMPRESS_LEVEL_LOW: - return sorted_supported_algos[0]; - case GRPC_COMPRESS_LEVEL_MED: - return sorted_supported_algos[num_supported / 2]; - case GRPC_COMPRESS_LEVEL_HIGH: - return sorted_supported_algos[num_supported - 1]; - default: - 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) { - return GPR_BITGET(opts->enabled_algorithms_bitset, algorithm); -} diff --git a/src/core/compression/message_compress.c b/src/core/compression/message_compress.c deleted file mode 100644 index edc21a9eb7..0000000000 --- a/src/core/compression/message_compress.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/compression/message_compress.h" - -#include - -#include -#include - -#include - -#define OUTPUT_BLOCK_SIZE 1024 - -static int zlib_body(z_stream* zs, gpr_slice_buffer* input, - gpr_slice_buffer* output, - int (*flate)(z_stream* zs, int flush)) { - int r; - int flush; - size_t i; - gpr_slice outbuf = gpr_slice_malloc(OUTPUT_BLOCK_SIZE); - const uInt uint_max = ~(uInt)0; - - GPR_ASSERT(GPR_SLICE_LENGTH(outbuf) <= uint_max); - zs->avail_out = (uInt)GPR_SLICE_LENGTH(outbuf); - zs->next_out = GPR_SLICE_START_PTR(outbuf); - flush = Z_NO_FLUSH; - for (i = 0; i < input->count; i++) { - if (i == input->count - 1) flush = Z_FINISH; - GPR_ASSERT(GPR_SLICE_LENGTH(input->slices[i]) <= uint_max); - zs->avail_in = (uInt)GPR_SLICE_LENGTH(input->slices[i]); - zs->next_in = GPR_SLICE_START_PTR(input->slices[i]); - do { - if (zs->avail_out == 0) { - gpr_slice_buffer_add_indexed(output, outbuf); - outbuf = gpr_slice_malloc(OUTPUT_BLOCK_SIZE); - GPR_ASSERT(GPR_SLICE_LENGTH(outbuf) <= uint_max); - zs->avail_out = (uInt)GPR_SLICE_LENGTH(outbuf); - zs->next_out = GPR_SLICE_START_PTR(outbuf); - } - r = flate(zs, flush); - if (r < 0 && r != Z_BUF_ERROR /* not fatal */) { - gpr_log(GPR_INFO, "zlib error (%d)", r); - goto error; - } - } while (zs->avail_out == 0); - if (zs->avail_in) { - gpr_log(GPR_INFO, "zlib: not all input consumed"); - goto error; - } - } - - GPR_ASSERT(outbuf.refcount); - outbuf.data.refcounted.length -= zs->avail_out; - gpr_slice_buffer_add_indexed(output, outbuf); - - return 1; - -error: - gpr_slice_unref(outbuf); - return 0; -} - -static void* zalloc_gpr(void* opaque, unsigned int items, unsigned int size) { - return gpr_malloc(items * size); -} - -static void zfree_gpr(void* opaque, void* address) { gpr_free(address); } - -static int zlib_compress(gpr_slice_buffer* input, gpr_slice_buffer* output, - int gzip) { - z_stream zs; - int r; - size_t i; - size_t count_before = output->count; - size_t length_before = output->length; - memset(&zs, 0, sizeof(zs)); - zs.zalloc = zalloc_gpr; - zs.zfree = zfree_gpr; - r = deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 | (gzip ? 16 : 0), - 8, Z_DEFAULT_STRATEGY); - GPR_ASSERT(r == Z_OK); - r = zlib_body(&zs, input, output, deflate) && output->length < input->length; - if (!r) { - for (i = count_before; i < output->count; i++) { - gpr_slice_unref(output->slices[i]); - } - output->count = count_before; - output->length = length_before; - } - deflateEnd(&zs); - return r; -} - -static int zlib_decompress(gpr_slice_buffer* input, gpr_slice_buffer* output, - int gzip) { - z_stream zs; - int r; - size_t i; - size_t count_before = output->count; - size_t length_before = output->length; - memset(&zs, 0, sizeof(zs)); - zs.zalloc = zalloc_gpr; - zs.zfree = zfree_gpr; - r = inflateInit2(&zs, 15 | (gzip ? 16 : 0)); - GPR_ASSERT(r == Z_OK); - r = zlib_body(&zs, input, output, inflate); - if (!r) { - for (i = count_before; i < output->count; i++) { - gpr_slice_unref(output->slices[i]); - } - output->count = count_before; - output->length = length_before; - } - inflateEnd(&zs); - return r; -} - -static int copy(gpr_slice_buffer* input, gpr_slice_buffer* output) { - size_t i; - for (i = 0; i < input->count; i++) { - gpr_slice_buffer_add(output, gpr_slice_ref(input->slices[i])); - } - return 1; -} - -static int compress_inner(grpc_compression_algorithm algorithm, - gpr_slice_buffer* input, gpr_slice_buffer* output) { - switch (algorithm) { - case GRPC_COMPRESS_NONE: - /* the fallback path always needs to be send uncompressed: we simply - rely on that here */ - return 0; - case GRPC_COMPRESS_DEFLATE: - return zlib_compress(input, output, 0); - case GRPC_COMPRESS_GZIP: - return zlib_compress(input, output, 1); - case GRPC_COMPRESS_ALGORITHMS_COUNT: - break; - } - gpr_log(GPR_ERROR, "invalid compression algorithm %d", algorithm); - return 0; -} - -int grpc_msg_compress(grpc_compression_algorithm algorithm, - gpr_slice_buffer* input, gpr_slice_buffer* output) { - if (!compress_inner(algorithm, input, output)) { - copy(input, output); - return 0; - } - return 1; -} - -int grpc_msg_decompress(grpc_compression_algorithm algorithm, - gpr_slice_buffer* input, gpr_slice_buffer* output) { - switch (algorithm) { - case GRPC_COMPRESS_NONE: - return copy(input, output); - case GRPC_COMPRESS_DEFLATE: - return zlib_decompress(input, output, 0); - case GRPC_COMPRESS_GZIP: - return zlib_decompress(input, output, 1); - case GRPC_COMPRESS_ALGORITHMS_COUNT: - break; - } - gpr_log(GPR_ERROR, "invalid compression algorithm %d", algorithm); - return 0; -} diff --git a/src/core/compression/message_compress.h b/src/core/compression/message_compress.h deleted file mode 100644 index 20b78c063b..0000000000 --- a/src/core/compression/message_compress.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * - * Copyright 2015-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_COMPRESSION_MESSAGE_COMPRESS_H -#define GRPC_CORE_COMPRESSION_MESSAGE_COMPRESS_H - -#include -#include - -/* compress 'input' to 'output' using 'algorithm'. - On success, appends compressed slices to output and returns 1. - On failure, appends uncompressed slices to output and returns 0. */ -int grpc_msg_compress(grpc_compression_algorithm algorithm, - gpr_slice_buffer* input, gpr_slice_buffer* output); - -/* decompress 'input' to 'output' using 'algorithm'. - On success, appends slices to output and returns 1. - On failure, output is unchanged, and returns 0. */ -int grpc_msg_decompress(grpc_compression_algorithm algorithm, - gpr_slice_buffer* input, gpr_slice_buffer* output); - -#endif /* GRPC_CORE_COMPRESSION_MESSAGE_COMPRESS_H */ diff --git a/src/core/debug/trace.c b/src/core/debug/trace.c deleted file mode 100644 index 3b35d81cd8..0000000000 --- a/src/core/debug/trace.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/debug/trace.h" - -#include - -#include -#include -#include -#include "src/core/support/env.h" - -typedef struct tracer { - const char *name; - int *flag; - struct tracer *next; -} tracer; -static tracer *tracers; - -void grpc_register_tracer(const char *name, int *flag) { - tracer *t = gpr_malloc(sizeof(*t)); - t->name = name; - t->flag = flag; - t->next = tracers; - *flag = 0; - tracers = t; -} - -static void add(const char *beg, const char *end, char ***ss, size_t *ns) { - size_t n = *ns; - size_t np = n + 1; - char *s; - size_t len; - GPR_ASSERT(end >= beg); - len = (size_t)(end - beg); - s = gpr_malloc(len + 1); - memcpy(s, beg, len); - s[len] = 0; - *ss = gpr_realloc(*ss, sizeof(char **) * np); - (*ss)[n] = s; - *ns = np; -} - -static void split(const char *s, char ***ss, size_t *ns) { - const char *c = strchr(s, ','); - if (c == NULL) { - add(s, s + strlen(s), ss, ns); - } else { - add(s, c, ss, ns); - split(c + 1, ss, ns); - } -} - -static void parse(const char *s) { - char **strings = NULL; - size_t nstrings = 0; - size_t i; - split(s, &strings, &nstrings); - - for (i = 0; i < nstrings; i++) { - grpc_tracer_set_enabled(strings[i], 1); - } - - for (i = 0; i < nstrings; i++) { - gpr_free(strings[i]); - } - gpr_free(strings); -} - -void grpc_tracer_init(const char *env_var) { - char *e = gpr_getenv(env_var); - if (e != NULL) { - parse(e); - gpr_free(e); - } -} - -void grpc_tracer_shutdown(void) { - while (tracers) { - tracer *t = tracers; - tracers = t->next; - gpr_free(t); - } -} - -int grpc_tracer_set_enabled(const char *name, int enabled) { - tracer *t; - if (0 == strcmp(name, "all")) { - for (t = tracers; t; t = t->next) { - *t->flag = 1; - } - } else { - int found = 0; - for (t = tracers; t; t = t->next) { - if (0 == strcmp(name, t->name)) { - *t->flag = enabled; - found = 1; - } - } - if (!found) { - gpr_log(GPR_ERROR, "Unknown trace var: '%s'", name); - return 0; /* early return */ - } - } - return 1; -} diff --git a/src/core/debug/trace.h b/src/core/debug/trace.h deleted file mode 100644 index 91ec14052e..0000000000 --- a/src/core/debug/trace.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * - * Copyright 2015-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_DEBUG_TRACE_H -#define GRPC_CORE_DEBUG_TRACE_H - -#include - -void grpc_register_tracer(const char *name, int *flag); -void grpc_tracer_init(const char *env_var_name); -void grpc_tracer_shutdown(void); - -#endif /* GRPC_CORE_DEBUG_TRACE_H */ diff --git a/src/core/http/format_request.c b/src/core/http/format_request.c deleted file mode 100644 index ac9bb8aeb8..0000000000 --- a/src/core/http/format_request.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * - * Copyright 2015-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/http/format_request.h" - -#include -#include -#include - -#include -#include -#include -#include -#include "src/core/support/string.h" - -static void fill_common_header(const grpc_httpcli_request *request, - gpr_strvec *buf) { - size_t i; - gpr_strvec_add(buf, gpr_strdup(request->http.path)); - gpr_strvec_add(buf, gpr_strdup(" HTTP/1.0\r\n")); - /* just in case some crazy server really expects HTTP/1.1 */ - gpr_strvec_add(buf, gpr_strdup("Host: ")); - gpr_strvec_add(buf, gpr_strdup(request->host)); - gpr_strvec_add(buf, gpr_strdup("\r\n")); - gpr_strvec_add(buf, gpr_strdup("Connection: close\r\n")); - gpr_strvec_add(buf, - gpr_strdup("User-Agent: " GRPC_HTTPCLI_USER_AGENT "\r\n")); - /* user supplied headers */ - for (i = 0; i < request->http.hdr_count; i++) { - gpr_strvec_add(buf, gpr_strdup(request->http.hdrs[i].key)); - gpr_strvec_add(buf, gpr_strdup(": ")); - gpr_strvec_add(buf, gpr_strdup(request->http.hdrs[i].value)); - gpr_strvec_add(buf, gpr_strdup("\r\n")); - } -} - -gpr_slice grpc_httpcli_format_get_request(const grpc_httpcli_request *request) { - gpr_strvec out; - char *flat; - size_t flat_len; - - gpr_strvec_init(&out); - gpr_strvec_add(&out, gpr_strdup("GET ")); - fill_common_header(request, &out); - gpr_strvec_add(&out, gpr_strdup("\r\n")); - - flat = gpr_strvec_flatten(&out, &flat_len); - gpr_strvec_destroy(&out); - - return gpr_slice_new(flat, flat_len, gpr_free); -} - -gpr_slice grpc_httpcli_format_post_request(const grpc_httpcli_request *request, - const char *body_bytes, - size_t body_size) { - gpr_strvec out; - char *tmp; - size_t out_len; - size_t i; - - gpr_strvec_init(&out); - - gpr_strvec_add(&out, gpr_strdup("POST ")); - fill_common_header(request, &out); - if (body_bytes) { - uint8_t has_content_type = 0; - for (i = 0; i < request->http.hdr_count; i++) { - if (strcmp(request->http.hdrs[i].key, "Content-Type") == 0) { - has_content_type = 1; - break; - } - } - if (!has_content_type) { - gpr_strvec_add(&out, gpr_strdup("Content-Type: text/plain\r\n")); - } - gpr_asprintf(&tmp, "Content-Length: %lu\r\n", (unsigned long)body_size); - gpr_strvec_add(&out, tmp); - } - gpr_strvec_add(&out, gpr_strdup("\r\n")); - tmp = gpr_strvec_flatten(&out, &out_len); - gpr_strvec_destroy(&out); - - if (body_bytes) { - tmp = gpr_realloc(tmp, out_len + body_size); - memcpy(tmp + out_len, body_bytes, body_size); - out_len += body_size; - } - - return gpr_slice_new(tmp, out_len, gpr_free); -} diff --git a/src/core/http/format_request.h b/src/core/http/format_request.h deleted file mode 100644 index dfd6fadbde..0000000000 --- a/src/core/http/format_request.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * - * Copyright 2015-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_HTTP_FORMAT_REQUEST_H -#define GRPC_CORE_HTTP_FORMAT_REQUEST_H - -#include -#include "src/core/http/httpcli.h" - -gpr_slice grpc_httpcli_format_get_request(const grpc_httpcli_request *request); -gpr_slice grpc_httpcli_format_post_request(const grpc_httpcli_request *request, - const char *body_bytes, - size_t body_size); - -#endif /* GRPC_CORE_HTTP_FORMAT_REQUEST_H */ diff --git a/src/core/http/httpcli.c b/src/core/http/httpcli.c deleted file mode 100644 index 1c0d3336ea..0000000000 --- a/src/core/http/httpcli.c +++ /dev/null @@ -1,293 +0,0 @@ -/* - * - * Copyright 2015-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/http/httpcli.h" -#include "src/core/iomgr/sockaddr.h" - -#include - -#include -#include -#include - -#include "src/core/http/format_request.h" -#include "src/core/http/parser.h" -#include "src/core/iomgr/endpoint.h" -#include "src/core/iomgr/iomgr_internal.h" -#include "src/core/iomgr/resolve_address.h" -#include "src/core/iomgr/tcp_client.h" -#include "src/core/support/string.h" - -typedef struct { - gpr_slice request_text; - grpc_http_parser parser; - grpc_resolved_addresses *addresses; - size_t next_address; - grpc_endpoint *ep; - char *host; - char *ssl_host_override; - gpr_timespec deadline; - int have_read_byte; - const grpc_httpcli_handshaker *handshaker; - grpc_httpcli_response_cb on_response; - void *user_data; - grpc_httpcli_context *context; - grpc_pollset *pollset; - grpc_iomgr_object iomgr_obj; - gpr_slice_buffer incoming; - gpr_slice_buffer outgoing; - grpc_closure on_read; - grpc_closure done_write; - grpc_closure connected; -} internal_request; - -static grpc_httpcli_get_override g_get_override = NULL; -static grpc_httpcli_post_override g_post_override = NULL; - -static void plaintext_handshake(grpc_exec_ctx *exec_ctx, void *arg, - grpc_endpoint *endpoint, const char *host, - void (*on_done)(grpc_exec_ctx *exec_ctx, - void *arg, - grpc_endpoint *endpoint)) { - on_done(exec_ctx, arg, endpoint); -} - -const grpc_httpcli_handshaker grpc_httpcli_plaintext = {"http", - plaintext_handshake}; - -void grpc_httpcli_context_init(grpc_httpcli_context *context) { - context->pollset_set = grpc_pollset_set_create(); -} - -void grpc_httpcli_context_destroy(grpc_httpcli_context *context) { - grpc_pollset_set_destroy(context->pollset_set); -} - -static void next_address(grpc_exec_ctx *exec_ctx, internal_request *req); - -static void finish(grpc_exec_ctx *exec_ctx, internal_request *req, - int success) { - grpc_pollset_set_del_pollset(exec_ctx, req->context->pollset_set, - req->pollset); - req->on_response(exec_ctx, req->user_data, - success ? &req->parser.http.response : NULL); - grpc_http_parser_destroy(&req->parser); - if (req->addresses != NULL) { - grpc_resolved_addresses_destroy(req->addresses); - } - if (req->ep != NULL) { - grpc_endpoint_destroy(exec_ctx, req->ep); - } - gpr_slice_unref(req->request_text); - gpr_free(req->host); - gpr_free(req->ssl_host_override); - grpc_iomgr_unregister_object(&req->iomgr_obj); - gpr_slice_buffer_destroy(&req->incoming); - gpr_slice_buffer_destroy(&req->outgoing); - gpr_free(req); -} - -static void on_read(grpc_exec_ctx *exec_ctx, void *user_data, bool success); - -static void do_read(grpc_exec_ctx *exec_ctx, internal_request *req) { - grpc_endpoint_read(exec_ctx, req->ep, &req->incoming, &req->on_read); -} - -static void on_read(grpc_exec_ctx *exec_ctx, void *user_data, bool success) { - internal_request *req = user_data; - size_t i; - - for (i = 0; i < req->incoming.count; i++) { - if (GPR_SLICE_LENGTH(req->incoming.slices[i])) { - req->have_read_byte = 1; - if (!grpc_http_parser_parse(&req->parser, req->incoming.slices[i])) { - finish(exec_ctx, req, 0); - return; - } - } - } - - if (success) { - do_read(exec_ctx, req); - } else if (!req->have_read_byte) { - next_address(exec_ctx, req); - } else { - int parse_success = grpc_http_parser_eof(&req->parser); - if (parse_success && (req->parser.type != GRPC_HTTP_RESPONSE)) { - parse_success = 0; - } - finish(exec_ctx, req, parse_success); - } -} - -static void on_written(grpc_exec_ctx *exec_ctx, internal_request *req) { - do_read(exec_ctx, req); -} - -static void done_write(grpc_exec_ctx *exec_ctx, void *arg, bool success) { - internal_request *req = arg; - if (success) { - on_written(exec_ctx, req); - } else { - next_address(exec_ctx, req); - } -} - -static void start_write(grpc_exec_ctx *exec_ctx, internal_request *req) { - gpr_slice_ref(req->request_text); - gpr_slice_buffer_add(&req->outgoing, req->request_text); - grpc_endpoint_write(exec_ctx, req->ep, &req->outgoing, &req->done_write); -} - -static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg, - grpc_endpoint *ep) { - internal_request *req = arg; - - if (!ep) { - next_address(exec_ctx, req); - return; - } - - req->ep = ep; - start_write(exec_ctx, req); -} - -static void on_connected(grpc_exec_ctx *exec_ctx, void *arg, bool success) { - internal_request *req = arg; - - if (!req->ep) { - next_address(exec_ctx, req); - return; - } - req->handshaker->handshake( - exec_ctx, req, req->ep, - req->ssl_host_override ? req->ssl_host_override : req->host, - on_handshake_done); -} - -static void next_address(grpc_exec_ctx *exec_ctx, internal_request *req) { - grpc_resolved_address *addr; - if (req->next_address == req->addresses->naddrs) { - finish(exec_ctx, req, 0); - return; - } - addr = &req->addresses->addrs[req->next_address++]; - grpc_closure_init(&req->connected, on_connected, req); - grpc_tcp_client_connect( - exec_ctx, &req->connected, &req->ep, req->context->pollset_set, - (struct sockaddr *)&addr->addr, addr->len, req->deadline); -} - -static void on_resolved(grpc_exec_ctx *exec_ctx, void *arg, - grpc_resolved_addresses *addresses) { - internal_request *req = arg; - if (!addresses) { - finish(exec_ctx, req, 0); - return; - } - req->addresses = addresses; - req->next_address = 0; - next_address(exec_ctx, req); -} - -static void internal_request_begin( - grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context, - grpc_pollset *pollset, const grpc_httpcli_request *request, - gpr_timespec deadline, grpc_httpcli_response_cb on_response, - void *user_data, const char *name, gpr_slice request_text) { - internal_request *req = gpr_malloc(sizeof(internal_request)); - memset(req, 0, sizeof(*req)); - req->request_text = request_text; - grpc_http_parser_init(&req->parser); - req->on_response = on_response; - req->user_data = user_data; - req->deadline = deadline; - req->handshaker = - request->handshaker ? request->handshaker : &grpc_httpcli_plaintext; - req->context = context; - req->pollset = pollset; - grpc_closure_init(&req->on_read, on_read, req); - grpc_closure_init(&req->done_write, done_write, req); - gpr_slice_buffer_init(&req->incoming); - gpr_slice_buffer_init(&req->outgoing); - grpc_iomgr_register_object(&req->iomgr_obj, name); - req->host = gpr_strdup(request->host); - req->ssl_host_override = gpr_strdup(request->ssl_host_override); - - grpc_pollset_set_add_pollset(exec_ctx, req->context->pollset_set, - req->pollset); - grpc_resolve_address(request->host, req->handshaker->default_port, - on_resolved, req); -} - -void grpc_httpcli_get(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context, - grpc_pollset *pollset, - const grpc_httpcli_request *request, - gpr_timespec deadline, - grpc_httpcli_response_cb on_response, void *user_data) { - char *name; - if (g_get_override && - g_get_override(exec_ctx, request, deadline, on_response, user_data)) { - return; - } - gpr_asprintf(&name, "HTTP:GET:%s:%s", request->host, request->http.path); - internal_request_begin(exec_ctx, context, pollset, request, deadline, - on_response, user_data, name, - grpc_httpcli_format_get_request(request)); - gpr_free(name); -} - -void grpc_httpcli_post(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context, - grpc_pollset *pollset, - const grpc_httpcli_request *request, - const char *body_bytes, size_t body_size, - gpr_timespec deadline, - grpc_httpcli_response_cb on_response, void *user_data) { - char *name; - if (g_post_override && - g_post_override(exec_ctx, request, body_bytes, body_size, deadline, - on_response, user_data)) { - return; - } - gpr_asprintf(&name, "HTTP:POST:%s:%s", request->host, request->http.path); - internal_request_begin( - exec_ctx, context, pollset, request, deadline, on_response, user_data, - name, grpc_httpcli_format_post_request(request, body_bytes, body_size)); - gpr_free(name); -} - -void grpc_httpcli_set_override(grpc_httpcli_get_override get, - grpc_httpcli_post_override post) { - g_get_override = get; - g_post_override = post; -} diff --git a/src/core/http/httpcli.h b/src/core/http/httpcli.h deleted file mode 100644 index 0bf4f2f445..0000000000 --- a/src/core/http/httpcli.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * - * Copyright 2015-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_HTTP_HTTPCLI_H -#define GRPC_CORE_HTTP_HTTPCLI_H - -#include - -#include - -#include "src/core/http/parser.h" -#include "src/core/iomgr/endpoint.h" -#include "src/core/iomgr/iomgr_internal.h" -#include "src/core/iomgr/pollset_set.h" - -/* User agent this library reports */ -#define GRPC_HTTPCLI_USER_AGENT "grpc-httpcli/0.0" - -/* Tracks in-progress http requests - TODO(ctiller): allow caching and capturing multiple requests for the - same content and combining them */ -typedef struct grpc_httpcli_context { - grpc_pollset_set *pollset_set; -} grpc_httpcli_context; - -typedef struct { - const char *default_port; - void (*handshake)(grpc_exec_ctx *exec_ctx, void *arg, grpc_endpoint *endpoint, - const char *host, - void (*on_done)(grpc_exec_ctx *exec_ctx, void *arg, - grpc_endpoint *endpoint)); -} grpc_httpcli_handshaker; - -extern const grpc_httpcli_handshaker grpc_httpcli_plaintext; -extern const grpc_httpcli_handshaker grpc_httpcli_ssl; - -/* A request */ -typedef struct grpc_httpcli_request { - /* The host name to connect to */ - char *host; - /* The host to verify in the SSL handshake (or NULL) */ - char *ssl_host_override; - /* The main part of the request - The following headers are supplied automatically and MUST NOT be set here: - Host, Connection, User-Agent */ - grpc_http_request http; - /* handshaker to use ssl for the request */ - const grpc_httpcli_handshaker *handshaker; -} grpc_httpcli_request; - -/* Expose the parser response type as a httpcli response too */ -typedef struct grpc_http_response grpc_httpcli_response; - -/* Callback for grpc_httpcli_get and grpc_httpcli_post. */ -typedef void (*grpc_httpcli_response_cb)(grpc_exec_ctx *exec_ctx, - void *user_data, - const grpc_http_response *response); - -void grpc_httpcli_context_init(grpc_httpcli_context *context); -void grpc_httpcli_context_destroy(grpc_httpcli_context *context); - -/* Asynchronously perform a HTTP GET. - 'context' specifies the http context under which to do the get - 'pollset' indicates a grpc_pollset that is interested in the result - of the get - work on this pollset may be used to progress the get - operation - 'request' contains request parameters - these are caller owned and can be - destroyed once the call returns - 'deadline' contains a deadline for the request (or gpr_inf_future) - 'on_response' is a callback to report results to (and 'user_data' is a user - supplied pointer to pass to said call) */ -void grpc_httpcli_get(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context, - grpc_pollset *pollset, - const grpc_httpcli_request *request, - gpr_timespec deadline, - grpc_httpcli_response_cb on_response, void *user_data); - -/* Asynchronously perform a HTTP POST. - 'context' specifies the http context under which to do the post - 'pollset' indicates a grpc_pollset that is interested in the result - of the post - work on this pollset may be used to progress the post - operation - 'request' contains request parameters - these are caller owned and can be - destroyed once the call returns - 'body_bytes' and 'body_size' specify the payload for the post. - When there is no body, pass in NULL as body_bytes. - 'deadline' contains a deadline for the request (or gpr_inf_future) - 'em' points to a caller owned event manager that must be alive for the - lifetime of the request - 'on_response' is a callback to report results to (and 'user_data' is a user - supplied pointer to pass to said call) - Does not support ?var1=val1&var2=val2 in the path. */ -void grpc_httpcli_post(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context, - grpc_pollset *pollset, - const grpc_httpcli_request *request, - const char *body_bytes, size_t body_size, - gpr_timespec deadline, - grpc_httpcli_response_cb on_response, void *user_data); - -/* override functions return 1 if they handled the request, 0 otherwise */ -typedef int (*grpc_httpcli_get_override)(grpc_exec_ctx *exec_ctx, - const grpc_httpcli_request *request, - gpr_timespec deadline, - grpc_httpcli_response_cb on_response, - void *user_data); -typedef int (*grpc_httpcli_post_override)( - grpc_exec_ctx *exec_ctx, const grpc_httpcli_request *request, - const char *body_bytes, size_t body_size, gpr_timespec deadline, - grpc_httpcli_response_cb on_response, void *user_data); - -void grpc_httpcli_set_override(grpc_httpcli_get_override get, - grpc_httpcli_post_override post); - -#endif /* GRPC_CORE_HTTP_HTTPCLI_H */ diff --git a/src/core/http/httpcli_security_connector.c b/src/core/http/httpcli_security_connector.c deleted file mode 100644 index a1a32f7558..0000000000 --- a/src/core/http/httpcli_security_connector.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - * - * Copyright 2015-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/http/httpcli.h" - -#include - -#include -#include -#include -#include "src/core/security/handshake.h" -#include "src/core/support/string.h" -#include "src/core/tsi/ssl_transport_security.h" - -typedef struct { - grpc_channel_security_connector base; - tsi_ssl_handshaker_factory *handshaker_factory; - char *secure_peer_name; -} grpc_httpcli_ssl_channel_security_connector; - -static void httpcli_ssl_destroy(grpc_security_connector *sc) { - grpc_httpcli_ssl_channel_security_connector *c = - (grpc_httpcli_ssl_channel_security_connector *)sc; - if (c->handshaker_factory != NULL) { - tsi_ssl_handshaker_factory_destroy(c->handshaker_factory); - } - if (c->secure_peer_name != NULL) gpr_free(c->secure_peer_name); - gpr_free(sc); -} - -static void httpcli_ssl_do_handshake(grpc_exec_ctx *exec_ctx, - grpc_channel_security_connector *sc, - grpc_endpoint *nonsecure_endpoint, - grpc_security_handshake_done_cb cb, - void *user_data) { - grpc_httpcli_ssl_channel_security_connector *c = - (grpc_httpcli_ssl_channel_security_connector *)sc; - tsi_result result = TSI_OK; - tsi_handshaker *handshaker; - if (c->handshaker_factory == NULL) { - cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL); - return; - } - result = tsi_ssl_handshaker_factory_create_handshaker( - c->handshaker_factory, c->secure_peer_name, &handshaker); - if (result != TSI_OK) { - gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.", - tsi_result_to_string(result)); - cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL); - } else { - grpc_do_security_handshake(exec_ctx, handshaker, &sc->base, true, - nonsecure_endpoint, cb, user_data); - } -} - -static void httpcli_ssl_check_peer(grpc_exec_ctx *exec_ctx, - grpc_security_connector *sc, tsi_peer peer, - grpc_security_peer_check_cb cb, - void *user_data) { - grpc_httpcli_ssl_channel_security_connector *c = - (grpc_httpcli_ssl_channel_security_connector *)sc; - grpc_security_status status = GRPC_SECURITY_OK; - - /* Check the peer name. */ - if (c->secure_peer_name != NULL && - !tsi_ssl_peer_matches_name(&peer, c->secure_peer_name)) { - gpr_log(GPR_ERROR, "Peer name %s is not in peer certificate", - c->secure_peer_name); - status = GRPC_SECURITY_ERROR; - } - cb(exec_ctx, user_data, status, NULL); - tsi_peer_destruct(&peer); -} - -static grpc_security_connector_vtable httpcli_ssl_vtable = { - httpcli_ssl_destroy, httpcli_ssl_check_peer}; - -static grpc_security_status httpcli_ssl_channel_security_connector_create( - const unsigned char *pem_root_certs, size_t pem_root_certs_size, - const char *secure_peer_name, grpc_channel_security_connector **sc) { - tsi_result result = TSI_OK; - grpc_httpcli_ssl_channel_security_connector *c; - - if (secure_peer_name != NULL && pem_root_certs == NULL) { - gpr_log(GPR_ERROR, - "Cannot assert a secure peer name without a trust root."); - return GRPC_SECURITY_ERROR; - } - - c = gpr_malloc(sizeof(grpc_httpcli_ssl_channel_security_connector)); - memset(c, 0, sizeof(grpc_httpcli_ssl_channel_security_connector)); - - gpr_ref_init(&c->base.base.refcount, 1); - c->base.base.vtable = &httpcli_ssl_vtable; - if (secure_peer_name != NULL) { - c->secure_peer_name = gpr_strdup(secure_peer_name); - } - result = tsi_create_ssl_client_handshaker_factory( - NULL, 0, NULL, 0, pem_root_certs, pem_root_certs_size, NULL, NULL, NULL, - 0, &c->handshaker_factory); - if (result != TSI_OK) { - gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.", - tsi_result_to_string(result)); - httpcli_ssl_destroy(&c->base.base); - *sc = NULL; - return GRPC_SECURITY_ERROR; - } - c->base.do_handshake = httpcli_ssl_do_handshake; - *sc = &c->base; - return GRPC_SECURITY_OK; -} - -/* handshaker */ - -typedef struct { - void (*func)(grpc_exec_ctx *exec_ctx, void *arg, grpc_endpoint *endpoint); - void *arg; -} on_done_closure; - -static void on_secure_transport_setup_done(grpc_exec_ctx *exec_ctx, void *rp, - grpc_security_status status, - grpc_endpoint *secure_endpoint, - grpc_auth_context *auth_context) { - on_done_closure *c = rp; - if (status != GRPC_SECURITY_OK) { - gpr_log(GPR_ERROR, "Secure transport setup failed with error %d.", status); - c->func(exec_ctx, c->arg, NULL); - } else { - c->func(exec_ctx, c->arg, secure_endpoint); - } - gpr_free(c); -} - -static void ssl_handshake(grpc_exec_ctx *exec_ctx, void *arg, - grpc_endpoint *tcp, const char *host, - void (*on_done)(grpc_exec_ctx *exec_ctx, void *arg, - grpc_endpoint *endpoint)) { - grpc_channel_security_connector *sc = NULL; - const unsigned char *pem_root_certs = NULL; - on_done_closure *c = gpr_malloc(sizeof(*c)); - size_t pem_root_certs_size = grpc_get_default_ssl_roots(&pem_root_certs); - if (pem_root_certs == NULL || pem_root_certs_size == 0) { - gpr_log(GPR_ERROR, "Could not get default pem root certs."); - on_done(exec_ctx, arg, NULL); - gpr_free(c); - return; - } - c->func = on_done; - c->arg = arg; - GPR_ASSERT(httpcli_ssl_channel_security_connector_create( - pem_root_certs, pem_root_certs_size, host, &sc) == - GRPC_SECURITY_OK); - grpc_channel_security_connector_do_handshake( - exec_ctx, sc, tcp, on_secure_transport_setup_done, c); - GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "httpcli"); -} - -const grpc_httpcli_handshaker grpc_httpcli_ssl = {"https", ssl_handshake}; diff --git a/src/core/http/parser.c b/src/core/http/parser.c deleted file mode 100644 index ebec8a5157..0000000000 --- a/src/core/http/parser.c +++ /dev/null @@ -1,313 +0,0 @@ -/* - * - * Copyright 2015-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/http/parser.h" - -#include - -#include -#include -#include - -static char *buf2str(void *buffer, size_t length) { - char *out = gpr_malloc(length + 1); - memcpy(out, buffer, length); - out[length] = 0; - return out; -} - -static int handle_response_line(grpc_http_parser *parser) { - uint8_t *beg = parser->cur_line; - uint8_t *cur = beg; - uint8_t *end = beg + parser->cur_line_length; - - if (cur == end || *cur++ != 'H') goto error; - if (cur == end || *cur++ != 'T') goto error; - if (cur == end || *cur++ != 'T') goto error; - if (cur == end || *cur++ != 'P') goto error; - if (cur == end || *cur++ != '/') goto error; - if (cur == end || *cur++ != '1') goto error; - if (cur == end || *cur++ != '.') goto error; - if (cur == end || *cur < '0' || *cur++ > '1') goto error; - if (cur == end || *cur++ != ' ') goto error; - if (cur == end || *cur < '1' || *cur++ > '9') goto error; - if (cur == end || *cur < '0' || *cur++ > '9') goto error; - if (cur == end || *cur < '0' || *cur++ > '9') goto error; - parser->http.response.status = - (cur[-3] - '0') * 100 + (cur[-2] - '0') * 10 + (cur[-1] - '0'); - if (cur == end || *cur++ != ' ') goto error; - - /* we don't really care about the status code message */ - - return 1; - -error: - gpr_log(GPR_ERROR, "Failed parsing response line"); - return 0; -} - -static int handle_request_line(grpc_http_parser *parser) { - uint8_t *beg = parser->cur_line; - uint8_t *cur = beg; - uint8_t *end = beg + parser->cur_line_length; - uint8_t vers_major = 0; - uint8_t vers_minor = 0; - - while (cur != end && *cur++ != ' ') - ; - if (cur == end) goto error; - parser->http.request.method = buf2str(beg, (size_t)(cur - beg - 1)); - - beg = cur; - while (cur != end && *cur++ != ' ') - ; - if (cur == end) goto error; - parser->http.request.path = buf2str(beg, (size_t)(cur - beg - 1)); - - if (cur == end || *cur++ != 'H') goto error; - if (cur == end || *cur++ != 'T') goto error; - if (cur == end || *cur++ != 'T') goto error; - if (cur == end || *cur++ != 'P') goto error; - if (cur == end || *cur++ != '/') goto error; - vers_major = (uint8_t)(*cur++ - '1' + 1); - ++cur; - if (cur == end) goto error; - vers_minor = (uint8_t)(*cur++ - '1' + 1); - - if (vers_major == 1) { - if (vers_minor == 0) { - parser->http.request.version = GRPC_HTTP_HTTP10; - } else if (vers_minor == 1) { - parser->http.request.version = GRPC_HTTP_HTTP11; - } else { - goto error; - } - } else if (vers_major == 2) { - if (vers_minor == 0) { - parser->http.request.version = GRPC_HTTP_HTTP20; - } else { - goto error; - } - } else { - goto error; - } - - return 1; - -error: - gpr_log(GPR_ERROR, "Failed parsing request line"); - return 0; -} - -static int handle_first_line(grpc_http_parser *parser) { - if (parser->cur_line[0] == 'H') { - parser->type = GRPC_HTTP_RESPONSE; - return handle_response_line(parser); - } else { - parser->type = GRPC_HTTP_REQUEST; - return handle_request_line(parser); - } -} - -static int add_header(grpc_http_parser *parser) { - uint8_t *beg = parser->cur_line; - uint8_t *cur = beg; - uint8_t *end = beg + parser->cur_line_length; - size_t *hdr_count = NULL; - grpc_http_header **hdrs = NULL; - grpc_http_header hdr = {NULL, NULL}; - - GPR_ASSERT(cur != end); - - if (*cur == ' ' || *cur == '\t') { - gpr_log(GPR_ERROR, "Continued header lines not supported yet"); - goto error; - } - - while (cur != end && *cur != ':') { - cur++; - } - if (cur == end) { - gpr_log(GPR_ERROR, "Didn't find ':' in header string"); - goto error; - } - GPR_ASSERT(cur >= beg); - hdr.key = buf2str(beg, (size_t)(cur - beg)); - cur++; /* skip : */ - - while (cur != end && (*cur == ' ' || *cur == '\t')) { - cur++; - } - GPR_ASSERT(end - cur >= 2); - hdr.value = buf2str(cur, (size_t)(end - cur) - 2); - - if (parser->type == GRPC_HTTP_RESPONSE) { - hdr_count = &parser->http.response.hdr_count; - hdrs = &parser->http.response.hdrs; - } else if (parser->type == GRPC_HTTP_REQUEST) { - hdr_count = &parser->http.request.hdr_count; - hdrs = &parser->http.request.hdrs; - } else { - return 0; - } - - if (*hdr_count == parser->hdr_capacity) { - parser->hdr_capacity = - GPR_MAX(parser->hdr_capacity + 1, parser->hdr_capacity * 3 / 2); - *hdrs = gpr_realloc(*hdrs, parser->hdr_capacity * sizeof(**hdrs)); - } - (*hdrs)[(*hdr_count)++] = hdr; - return 1; - -error: - gpr_free(hdr.key); - gpr_free(hdr.value); - return 0; -} - -static int finish_line(grpc_http_parser *parser) { - switch (parser->state) { - case GRPC_HTTP_FIRST_LINE: - if (!handle_first_line(parser)) { - return 0; - } - parser->state = GRPC_HTTP_HEADERS; - break; - case GRPC_HTTP_HEADERS: - if (parser->cur_line_length == 2) { - parser->state = GRPC_HTTP_BODY; - break; - } - if (!add_header(parser)) { - return 0; - } - break; - case GRPC_HTTP_BODY: - GPR_UNREACHABLE_CODE(return 0); - } - - parser->cur_line_length = 0; - return 1; -} - -static int addbyte_body(grpc_http_parser *parser, uint8_t byte) { - size_t *body_length = NULL; - char **body = NULL; - - if (parser->type == GRPC_HTTP_RESPONSE) { - body_length = &parser->http.response.body_length; - body = &parser->http.response.body; - } else if (parser->type == GRPC_HTTP_REQUEST) { - body_length = &parser->http.request.body_length; - body = &parser->http.request.body; - } else { - return 0; - } - - if (*body_length == parser->body_capacity) { - parser->body_capacity = GPR_MAX(8, parser->body_capacity * 3 / 2); - *body = gpr_realloc((void *)*body, parser->body_capacity); - } - (*body)[*body_length] = (char)byte; - (*body_length)++; - - return 1; -} - -static int addbyte(grpc_http_parser *parser, uint8_t byte) { - switch (parser->state) { - case GRPC_HTTP_FIRST_LINE: - case GRPC_HTTP_HEADERS: - if (parser->cur_line_length >= GRPC_HTTP_PARSER_MAX_HEADER_LENGTH) { - gpr_log(GPR_ERROR, "HTTP client max line length (%d) exceeded", - GRPC_HTTP_PARSER_MAX_HEADER_LENGTH); - return 0; - } - parser->cur_line[parser->cur_line_length] = byte; - parser->cur_line_length++; - if (parser->cur_line_length >= 2 && - parser->cur_line[parser->cur_line_length - 2] == '\r' && - parser->cur_line[parser->cur_line_length - 1] == '\n') { - return finish_line(parser); - } else { - return 1; - } - GPR_UNREACHABLE_CODE(return 0); - case GRPC_HTTP_BODY: - return addbyte_body(parser, byte); - } - GPR_UNREACHABLE_CODE(return 0); -} - -void grpc_http_parser_init(grpc_http_parser *parser) { - memset(parser, 0, sizeof(*parser)); - parser->state = GRPC_HTTP_FIRST_LINE; - parser->type = GRPC_HTTP_UNKNOWN; -} - -void grpc_http_parser_destroy(grpc_http_parser *parser) { - size_t i; - if (parser->type == GRPC_HTTP_RESPONSE) { - gpr_free(parser->http.response.body); - for (i = 0; i < parser->http.response.hdr_count; i++) { - gpr_free(parser->http.response.hdrs[i].key); - gpr_free(parser->http.response.hdrs[i].value); - } - gpr_free(parser->http.response.hdrs); - } else if (parser->type == GRPC_HTTP_REQUEST) { - gpr_free(parser->http.request.body); - for (i = 0; i < parser->http.request.hdr_count; i++) { - gpr_free(parser->http.request.hdrs[i].key); - gpr_free(parser->http.request.hdrs[i].value); - } - gpr_free(parser->http.request.hdrs); - gpr_free(parser->http.request.method); - gpr_free(parser->http.request.path); - } -} - -int grpc_http_parser_parse(grpc_http_parser *parser, gpr_slice slice) { - size_t i; - - for (i = 0; i < GPR_SLICE_LENGTH(slice); i++) { - if (!addbyte(parser, GPR_SLICE_START_PTR(slice)[i])) { - return 0; - } - } - - return 1; -} - -int grpc_http_parser_eof(grpc_http_parser *parser) { - return parser->state == GRPC_HTTP_BODY; -} diff --git a/src/core/http/parser.h b/src/core/http/parser.h deleted file mode 100644 index 39517e485a..0000000000 --- a/src/core/http/parser.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * - * Copyright 2015-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_HTTP_PARSER_H -#define GRPC_CORE_HTTP_PARSER_H - -#include -#include - -/* Maximum length of a header string of the form 'Key: Value\r\n' */ -#define GRPC_HTTP_PARSER_MAX_HEADER_LENGTH 4096 - -/* A single header to be passed in a request */ -typedef struct grpc_http_header { - char *key; - char *value; -} grpc_http_header; - -typedef enum { - GRPC_HTTP_FIRST_LINE, - GRPC_HTTP_HEADERS, - GRPC_HTTP_BODY -} grpc_http_parser_state; - -typedef enum { - GRPC_HTTP_HTTP10, - GRPC_HTTP_HTTP11, - GRPC_HTTP_HTTP20, -} grpc_http_version; - -typedef enum { - GRPC_HTTP_RESPONSE, - GRPC_HTTP_REQUEST, - GRPC_HTTP_UNKNOWN -} grpc_http_type; - -/* A request */ -typedef struct grpc_http_request { - /* Method of the request (e.g. GET, POST) */ - char *method; - /* The path of the resource to fetch */ - char *path; - /* HTTP version to use */ - grpc_http_version version; - /* Headers attached to the request */ - size_t hdr_count; - grpc_http_header *hdrs; - /* Body: length and contents; contents are NOT null-terminated */ - size_t body_length; - char *body; -} grpc_http_request; - -/* A response */ -typedef struct grpc_http_response { - /* HTTP status code */ - int status; - /* Headers: count and key/values */ - size_t hdr_count; - grpc_http_header *hdrs; - /* Body: length and contents; contents are NOT null-terminated */ - size_t body_length; - char *body; -} grpc_http_response; - -typedef struct { - grpc_http_parser_state state; - grpc_http_type type; - - union { - grpc_http_response response; - grpc_http_request request; - } http; - size_t body_capacity; - size_t hdr_capacity; - - uint8_t cur_line[GRPC_HTTP_PARSER_MAX_HEADER_LENGTH]; - size_t cur_line_length; -} grpc_http_parser; - -void grpc_http_parser_init(grpc_http_parser *parser); -void grpc_http_parser_destroy(grpc_http_parser *parser); - -int grpc_http_parser_parse(grpc_http_parser *parser, gpr_slice slice); -int grpc_http_parser_eof(grpc_http_parser *parser); - -#endif /* GRPC_CORE_HTTP_PARSER_H */ diff --git a/src/core/iomgr/closure.c b/src/core/iomgr/closure.c deleted file mode 100644 index 3a96f7385f..0000000000 --- a/src/core/iomgr/closure.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - * - * Copyright 2015-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/iomgr/closure.h" - -#include - -void grpc_closure_init(grpc_closure *closure, grpc_iomgr_cb_func cb, - void *cb_arg) { - closure->cb = cb; - closure->cb_arg = cb_arg; - closure->final_data = 0; -} - -void grpc_closure_list_add(grpc_closure_list *closure_list, - grpc_closure *closure, bool success) { - if (closure == NULL) return; - closure->final_data = (success != 0); - if (closure_list->head == NULL) { - closure_list->head = closure; - } else { - closure_list->tail->final_data |= (uintptr_t)closure; - } - closure_list->tail = closure; -} - -bool grpc_closure_list_empty(grpc_closure_list closure_list) { - return closure_list.head == NULL; -} - -void grpc_closure_list_move(grpc_closure_list *src, grpc_closure_list *dst) { - if (src->head == NULL) { - return; - } - if (dst->head == NULL) { - *dst = *src; - } else { - dst->tail->final_data |= (uintptr_t)src->head; - dst->tail = src->tail; - } - src->head = src->tail = NULL; -} - -typedef struct { - grpc_iomgr_cb_func cb; - void *cb_arg; - grpc_closure wrapper; -} wrapped_closure; - -static void closure_wrapper(grpc_exec_ctx *exec_ctx, void *arg, bool success) { - wrapped_closure *wc = arg; - grpc_iomgr_cb_func cb = wc->cb; - void *cb_arg = wc->cb_arg; - gpr_free(wc); - cb(exec_ctx, cb_arg, success); -} - -grpc_closure *grpc_closure_create(grpc_iomgr_cb_func cb, void *cb_arg) { - wrapped_closure *wc = gpr_malloc(sizeof(*wc)); - wc->cb = cb; - wc->cb_arg = cb_arg; - grpc_closure_init(&wc->wrapper, closure_wrapper, wc); - return &wc->wrapper; -} - -grpc_closure *grpc_closure_next(grpc_closure *closure) { - return (grpc_closure *)(closure->final_data & ~(uintptr_t)1); -} diff --git a/src/core/iomgr/closure.h b/src/core/iomgr/closure.h deleted file mode 100644 index d5e1f455b9..0000000000 --- a/src/core/iomgr/closure.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * - * Copyright 2015-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_IOMGR_CLOSURE_H -#define GRPC_CORE_IOMGR_CLOSURE_H - -#include -#include - -struct grpc_closure; -typedef struct grpc_closure grpc_closure; - -/* forward declaration for exec_ctx.h */ -struct grpc_exec_ctx; -typedef struct grpc_exec_ctx grpc_exec_ctx; - -typedef struct grpc_closure_list { - grpc_closure *head; - grpc_closure *tail; -} grpc_closure_list; - -/** gRPC Callback definition. - * - * \param arg Arbitrary input. - * \param success An indication on the state of the iomgr. On false, cleanup - * actions should be taken (eg, shutdown). */ -typedef void (*grpc_iomgr_cb_func)(grpc_exec_ctx *exec_ctx, void *arg, - bool success); - -/** A closure over a grpc_iomgr_cb_func. */ -struct grpc_closure { - /** Bound callback. */ - grpc_iomgr_cb_func cb; - - /** Arguments to be passed to "cb". */ - void *cb_arg; - - /** Once enqueued, contains in the lower bit the success of the closure, - and in the upper bits the pointer to the next closure in the list. - Before enqueing for execution, this is usable for scratch data. */ - uintptr_t final_data; -}; - -/** Initializes \a closure with \a cb and \a cb_arg. */ -void grpc_closure_init(grpc_closure *closure, grpc_iomgr_cb_func cb, - void *cb_arg); - -/* Create a heap allocated closure: try to avoid except for very rare events */ -grpc_closure *grpc_closure_create(grpc_iomgr_cb_func cb, void *cb_arg); - -#define GRPC_CLOSURE_LIST_INIT \ - { NULL, NULL } - -/** add \a closure to the end of \a list and set \a closure's success to \a - * success */ -void grpc_closure_list_add(grpc_closure_list *list, grpc_closure *closure, - bool success); - -/** append all closures from \a src to \a dst and empty \a src. */ -void grpc_closure_list_move(grpc_closure_list *src, grpc_closure_list *dst); - -/** return whether \a list is empty. */ -bool grpc_closure_list_empty(grpc_closure_list list); - -/** return the next pointer for a queued closure list */ -grpc_closure *grpc_closure_next(grpc_closure *closure); - -#endif /* GRPC_CORE_IOMGR_CLOSURE_H */ diff --git a/src/core/iomgr/endpoint.c b/src/core/iomgr/endpoint.c deleted file mode 100644 index bd64707669..0000000000 --- a/src/core/iomgr/endpoint.c +++ /dev/null @@ -1,67 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/iomgr/endpoint.h" - -void grpc_endpoint_read(grpc_exec_ctx* exec_ctx, grpc_endpoint* ep, - gpr_slice_buffer* slices, grpc_closure* cb) { - ep->vtable->read(exec_ctx, ep, slices, cb); -} - -void grpc_endpoint_write(grpc_exec_ctx* exec_ctx, grpc_endpoint* ep, - gpr_slice_buffer* slices, grpc_closure* cb) { - ep->vtable->write(exec_ctx, ep, slices, cb); -} - -void grpc_endpoint_add_to_pollset(grpc_exec_ctx* exec_ctx, grpc_endpoint* ep, - grpc_pollset* pollset) { - ep->vtable->add_to_pollset(exec_ctx, ep, pollset); -} - -void grpc_endpoint_add_to_pollset_set(grpc_exec_ctx* exec_ctx, - grpc_endpoint* ep, - grpc_pollset_set* pollset_set) { - ep->vtable->add_to_pollset_set(exec_ctx, ep, pollset_set); -} - -void grpc_endpoint_shutdown(grpc_exec_ctx* exec_ctx, grpc_endpoint* ep) { - ep->vtable->shutdown(exec_ctx, ep); -} - -void grpc_endpoint_destroy(grpc_exec_ctx* exec_ctx, grpc_endpoint* ep) { - ep->vtable->destroy(exec_ctx, ep); -} - -char* grpc_endpoint_get_peer(grpc_endpoint* ep) { - return ep->vtable->get_peer(ep); -} diff --git a/src/core/iomgr/endpoint.h b/src/core/iomgr/endpoint.h deleted file mode 100644 index b4be852e33..0000000000 --- a/src/core/iomgr/endpoint.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * - * Copyright 2015-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_IOMGR_ENDPOINT_H -#define GRPC_CORE_IOMGR_ENDPOINT_H - -#include -#include -#include -#include "src/core/iomgr/pollset.h" -#include "src/core/iomgr/pollset_set.h" - -/* An endpoint caps a streaming channel between two communicating processes. - Examples may be: a tcp socket, , or some shared memory. */ - -typedef struct grpc_endpoint grpc_endpoint; -typedef struct grpc_endpoint_vtable grpc_endpoint_vtable; - -struct grpc_endpoint_vtable { - void (*read)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, - gpr_slice_buffer *slices, grpc_closure *cb); - void (*write)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, - gpr_slice_buffer *slices, grpc_closure *cb); - void (*add_to_pollset)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, - grpc_pollset *pollset); - void (*add_to_pollset_set)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, - grpc_pollset_set *pollset); - void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep); - void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep); - char *(*get_peer)(grpc_endpoint *ep); -}; - -/* When data is available on the connection, calls the callback with slices. - Callback success indicates that the endpoint can accept more reads, failure - indicates the endpoint is closed. - Valid slices may be placed into \a slices even on callback success == 0. */ -void grpc_endpoint_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, - gpr_slice_buffer *slices, grpc_closure *cb); - -char *grpc_endpoint_get_peer(grpc_endpoint *ep); - -/* Write slices out to the socket. - - If the connection is ready for more data after the end of the call, it - returns GRPC_ENDPOINT_DONE. - Otherwise it returns GRPC_ENDPOINT_PENDING and calls cb when the - connection is ready for more data. - \a slices may be mutated at will by the endpoint until cb is called. - No guarantee is made to the content of slices after a write EXCEPT that - it is a valid slice buffer. - */ -void grpc_endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, - gpr_slice_buffer *slices, grpc_closure *cb); - -/* Causes any pending read/write callbacks to run immediately with - success==0 */ -void grpc_endpoint_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep); -void grpc_endpoint_destroy(grpc_exec_ctx *exec_ctx, 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_exec_ctx *exec_ctx, grpc_endpoint *ep, - grpc_pollset *pollset); -void grpc_endpoint_add_to_pollset_set(grpc_exec_ctx *exec_ctx, - grpc_endpoint *ep, - grpc_pollset_set *pollset_set); - -struct grpc_endpoint { - const grpc_endpoint_vtable *vtable; -}; - -#endif /* GRPC_CORE_IOMGR_ENDPOINT_H */ diff --git a/src/core/iomgr/endpoint_pair.h b/src/core/iomgr/endpoint_pair.h deleted file mode 100644 index 59015d8ffb..0000000000 --- a/src/core/iomgr/endpoint_pair.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * - * Copyright 2015-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_IOMGR_ENDPOINT_PAIR_H -#define GRPC_CORE_IOMGR_ENDPOINT_PAIR_H - -#include "src/core/iomgr/endpoint.h" - -typedef struct { - grpc_endpoint *client; - grpc_endpoint *server; -} grpc_endpoint_pair; - -grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name, - size_t read_slice_size); - -#endif /* GRPC_CORE_IOMGR_ENDPOINT_PAIR_H */ diff --git a/src/core/iomgr/endpoint_pair_posix.c b/src/core/iomgr/endpoint_pair_posix.c deleted file mode 100644 index 66d19a486c..0000000000 --- a/src/core/iomgr/endpoint_pair_posix.c +++ /dev/null @@ -1,83 +0,0 @@ -/* - * - * 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 - -#ifdef GPR_POSIX_SOCKET - -#include "src/core/iomgr/endpoint_pair.h" -#include "src/core/iomgr/socket_utils_posix.h" -#include "src/core/iomgr/unix_sockets_posix.h" - -#include -#include -#include -#include -#include - -#include -#include -#include -#include "src/core/iomgr/tcp_posix.h" -#include "src/core/support/string.h" - -static void create_sockets(int sv[2]) { - int flags; - grpc_create_socketpair_if_unix(sv); - flags = fcntl(sv[0], F_GETFL, 0); - GPR_ASSERT(fcntl(sv[0], F_SETFL, flags | O_NONBLOCK) == 0); - flags = fcntl(sv[1], F_GETFL, 0); - GPR_ASSERT(fcntl(sv[1], F_SETFL, flags | O_NONBLOCK) == 0); - GPR_ASSERT(grpc_set_socket_no_sigpipe_if_possible(sv[0])); - GPR_ASSERT(grpc_set_socket_no_sigpipe_if_possible(sv[1])); -} - -grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name, - size_t read_slice_size) { - int sv[2]; - grpc_endpoint_pair p; - char *final_name; - create_sockets(sv); - - gpr_asprintf(&final_name, "%s:client", name); - p.client = grpc_tcp_create(grpc_fd_create(sv[1], final_name), read_slice_size, - "socketpair-server"); - gpr_free(final_name); - gpr_asprintf(&final_name, "%s:server", name); - p.server = grpc_tcp_create(grpc_fd_create(sv[0], final_name), read_slice_size, - "socketpair-client"); - gpr_free(final_name); - return p; -} - -#endif diff --git a/src/core/iomgr/endpoint_pair_windows.c b/src/core/iomgr/endpoint_pair_windows.c deleted file mode 100644 index 2024f58143..0000000000 --- a/src/core/iomgr/endpoint_pair_windows.c +++ /dev/null @@ -1,97 +0,0 @@ -/* - * - * Copyright 2015-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 - -#ifdef GPR_WINSOCK_SOCKET -#include "src/core/iomgr/endpoint_pair.h" -#include "src/core/iomgr/sockaddr_utils.h" - -#include -#include -#include - -#include -#include "src/core/iomgr/socket_windows.h" -#include "src/core/iomgr/tcp_windows.h" - -static void create_sockets(SOCKET sv[2]) { - SOCKET svr_sock = INVALID_SOCKET; - SOCKET lst_sock = INVALID_SOCKET; - SOCKET cli_sock = INVALID_SOCKET; - SOCKADDR_IN addr; - int addr_len = sizeof(addr); - - lst_sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, - WSA_FLAG_OVERLAPPED); - GPR_ASSERT(lst_sock != INVALID_SOCKET); - - memset(&addr, 0, sizeof(addr)); - addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - addr.sin_family = AF_INET; - GPR_ASSERT(bind(lst_sock, (struct sockaddr *)&addr, sizeof(addr)) != - SOCKET_ERROR); - GPR_ASSERT(listen(lst_sock, SOMAXCONN) != SOCKET_ERROR); - GPR_ASSERT(getsockname(lst_sock, (struct sockaddr *)&addr, &addr_len) != - SOCKET_ERROR); - - cli_sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, - WSA_FLAG_OVERLAPPED); - GPR_ASSERT(cli_sock != INVALID_SOCKET); - - GPR_ASSERT(WSAConnect(cli_sock, (struct sockaddr *)&addr, addr_len, NULL, - NULL, NULL, NULL) == 0); - svr_sock = accept(lst_sock, (struct sockaddr *)&addr, &addr_len); - GPR_ASSERT(svr_sock != INVALID_SOCKET); - - closesocket(lst_sock); - grpc_tcp_prepare_socket(cli_sock); - grpc_tcp_prepare_socket(svr_sock); - - sv[1] = cli_sock; - sv[0] = svr_sock; -} - -grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name, - size_t read_slice_size) { - SOCKET sv[2]; - grpc_endpoint_pair p; - create_sockets(sv); - p.client = grpc_tcp_create(grpc_winsocket_create(sv[1], "endpoint:client"), - "endpoint:server"); - p.server = grpc_tcp_create(grpc_winsocket_create(sv[0], "endpoint:server"), - "endpoint:client"); - return p; -} - -#endif diff --git a/src/core/iomgr/exec_ctx.c b/src/core/iomgr/exec_ctx.c deleted file mode 100644 index 893fe4515c..0000000000 --- a/src/core/iomgr/exec_ctx.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * - * Copyright 2015-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/iomgr/exec_ctx.h" - -#include -#include -#include - -#include "src/core/profiling/timers.h" - -#ifndef GRPC_EXECUTION_CONTEXT_SANITIZER -bool grpc_exec_ctx_flush(grpc_exec_ctx *exec_ctx) { - bool did_something = 0; - GPR_TIMER_BEGIN("grpc_exec_ctx_flush", 0); - while (!grpc_closure_list_empty(exec_ctx->closure_list)) { - grpc_closure *c = exec_ctx->closure_list.head; - exec_ctx->closure_list.head = exec_ctx->closure_list.tail = NULL; - while (c != NULL) { - bool success = (bool)(c->final_data & 1); - grpc_closure *next = (grpc_closure *)(c->final_data & ~(uintptr_t)1); - did_something = true; - GPR_TIMER_BEGIN("grpc_exec_ctx_flush.cb", 0); - c->cb(exec_ctx, c->cb_arg, success); - GPR_TIMER_END("grpc_exec_ctx_flush.cb", 0); - c = next; - } - } - GPR_TIMER_END("grpc_exec_ctx_flush", 0); - return did_something; -} - -void grpc_exec_ctx_finish(grpc_exec_ctx *exec_ctx) { - grpc_exec_ctx_flush(exec_ctx); -} - -void grpc_exec_ctx_enqueue(grpc_exec_ctx *exec_ctx, grpc_closure *closure, - bool success, - grpc_workqueue *offload_target_or_null) { - GPR_ASSERT(offload_target_or_null == NULL); - grpc_closure_list_add(&exec_ctx->closure_list, closure, success); -} - -void grpc_exec_ctx_enqueue_list(grpc_exec_ctx *exec_ctx, - grpc_closure_list *list, - grpc_workqueue *offload_target_or_null) { - GPR_ASSERT(offload_target_or_null == NULL); - grpc_closure_list_move(list, &exec_ctx->closure_list); -} - -void grpc_exec_ctx_global_init(void) {} -void grpc_exec_ctx_global_shutdown(void) {} -#else -static gpr_mu g_mu; -static gpr_cv g_cv; -static int g_threads = 0; - -static void run_closure(void *arg) { - grpc_closure *closure = arg; - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - closure->cb(&exec_ctx, closure->cb_arg, (closure->final_data & 1) != 0); - grpc_exec_ctx_finish(&exec_ctx); - gpr_mu_lock(&g_mu); - if (--g_threads == 0) { - gpr_cv_signal(&g_cv); - } - gpr_mu_unlock(&g_mu); -} - -static void start_closure(grpc_closure *closure) { - gpr_thd_id id; - gpr_mu_lock(&g_mu); - g_threads++; - gpr_mu_unlock(&g_mu); - gpr_thd_new(&id, run_closure, closure, NULL); -} - -bool grpc_exec_ctx_flush(grpc_exec_ctx *exec_ctx) { return false; } - -void grpc_exec_ctx_finish(grpc_exec_ctx *exec_ctx) {} - -void grpc_exec_ctx_enqueue(grpc_exec_ctx *exec_ctx, grpc_closure *closure, - bool success, - grpc_workqueue *offload_target_or_null) { - GPR_ASSERT(offload_target_or_null == NULL); - if (closure == NULL) return; - closure->final_data = success; - start_closure(closure); -} - -void grpc_exec_ctx_enqueue_list(grpc_exec_ctx *exec_ctx, - grpc_closure_list *list, - grpc_workqueue *offload_target_or_null) { - GPR_ASSERT(offload_target_or_null == NULL); - if (list == NULL) return; - grpc_closure *p = list->head; - while (p) { - grpc_closure *start = p; - p = grpc_closure_next(start); - start_closure(start); - } - grpc_closure_list r = GRPC_CLOSURE_LIST_INIT; - *list = r; -} - -void grpc_exec_ctx_global_init(void) { - gpr_mu_init(&g_mu); - gpr_cv_init(&g_cv); -} - -void grpc_exec_ctx_global_shutdown(void) { - gpr_mu_lock(&g_mu); - while (g_threads != 0) { - gpr_cv_wait(&g_cv, &g_mu, gpr_inf_future(GPR_CLOCK_REALTIME)); - } - gpr_mu_unlock(&g_mu); - - gpr_mu_destroy(&g_mu); - gpr_cv_destroy(&g_cv); -} -#endif diff --git a/src/core/iomgr/exec_ctx.h b/src/core/iomgr/exec_ctx.h deleted file mode 100644 index 07b54a0ab8..0000000000 --- a/src/core/iomgr/exec_ctx.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * - * Copyright 2015-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_IOMGR_EXEC_CTX_H -#define GRPC_CORE_IOMGR_EXEC_CTX_H - -#include "src/core/iomgr/closure.h" - -/* #define GRPC_EXECUTION_CONTEXT_SANITIZER 1 */ - -/** A workqueue represents a list of work to be executed asynchronously. - Forward declared here to avoid a circular dependency with workqueue.h. */ -struct grpc_workqueue; -typedef struct grpc_workqueue grpc_workqueue; - -#ifndef GRPC_EXECUTION_CONTEXT_SANITIZER -/** Execution context. - * A bag of data that collects information along a callstack. - * Generally created at public API entry points, and passed down as - * pointer to child functions that manipulate it. - * - * Specific responsibilities (this may grow in the future): - * - track a list of work that needs to be delayed until the top of the - * call stack (this provides a convenient mechanism to run callbacks - * without worrying about locking issues) - * - * CONVENTIONS: - * Instance of this must ALWAYS be constructed on the stack, never - * heap allocated. Instances and pointers to them must always be called - * exec_ctx. Instances are always passed as the first argument - * to a function that takes it, and always as a pointer (grpc_exec_ctx - * is never copied). - */ -struct grpc_exec_ctx { - grpc_closure_list closure_list; -}; - -#define GRPC_EXEC_CTX_INIT \ - { GRPC_CLOSURE_LIST_INIT } -#else -struct grpc_exec_ctx { - int unused; -}; -#define GRPC_EXEC_CTX_INIT \ - { 0 } -#endif - -/** Flush any work that has been enqueued onto this grpc_exec_ctx. - * Caller must guarantee that no interfering locks are held. - * Returns true if work was performed, false otherwise. */ -bool grpc_exec_ctx_flush(grpc_exec_ctx *exec_ctx); -/** Finish any pending work for a grpc_exec_ctx. Must be called before - * the instance is destroyed, or work may be lost. */ -void grpc_exec_ctx_finish(grpc_exec_ctx *exec_ctx); -/** Add a closure to be executed at the next flush/finish point */ -void grpc_exec_ctx_enqueue(grpc_exec_ctx *exec_ctx, grpc_closure *closure, - bool success, - grpc_workqueue *offload_target_or_null); -/** Add a list of closures to be executed at the next flush/finish point. - * Leaves \a list empty. */ -void grpc_exec_ctx_enqueue_list(grpc_exec_ctx *exec_ctx, - grpc_closure_list *list, - grpc_workqueue *offload_target_or_null); - -void grpc_exec_ctx_global_init(void); -void grpc_exec_ctx_global_shutdown(void); - -#endif /* GRPC_CORE_IOMGR_EXEC_CTX_H */ diff --git a/src/core/iomgr/executor.c b/src/core/iomgr/executor.c deleted file mode 100644 index f22d8f30ac..0000000000 --- a/src/core/iomgr/executor.c +++ /dev/null @@ -1,143 +0,0 @@ -/* - * - * Copyright 2015-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/iomgr/executor.h" - -#include - -#include -#include -#include -#include -#include "src/core/iomgr/exec_ctx.h" - -typedef struct grpc_executor_data { - int busy; /**< is the thread currently running? */ - int shutting_down; /**< has \a grpc_shutdown() been invoked? */ - int pending_join; /**< has the thread finished but not been joined? */ - grpc_closure_list closures; /**< collection of pending work */ - gpr_thd_id tid; /**< thread id of the thread, only valid if \a busy or \a - pending_join are true */ - gpr_thd_options options; - gpr_mu mu; -} grpc_executor; - -static grpc_executor g_executor; - -void grpc_executor_init() { - memset(&g_executor, 0, sizeof(grpc_executor)); - gpr_mu_init(&g_executor.mu); - g_executor.options = gpr_thd_options_default(); - gpr_thd_options_set_joinable(&g_executor.options); -} - -/* thread body */ -static void closure_exec_thread_func(void *ignored) { - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - while (1) { - gpr_mu_lock(&g_executor.mu); - if (g_executor.shutting_down != 0) { - gpr_mu_unlock(&g_executor.mu); - break; - } - if (grpc_closure_list_empty(g_executor.closures)) { - /* no more work, time to die */ - GPR_ASSERT(g_executor.busy == 1); - g_executor.busy = 0; - gpr_mu_unlock(&g_executor.mu); - break; - } else { - grpc_exec_ctx_enqueue_list(&exec_ctx, &g_executor.closures, NULL); - } - gpr_mu_unlock(&g_executor.mu); - grpc_exec_ctx_flush(&exec_ctx); - } - grpc_exec_ctx_finish(&exec_ctx); -} - -/* Spawn the thread if new work has arrived a no thread is up */ -static void maybe_spawn_locked() { - if (grpc_closure_list_empty(g_executor.closures) == 1) { - return; - } - if (g_executor.shutting_down == 1) { - return; - } - - if (g_executor.busy != 0) { - /* Thread still working. New work will be picked up by already running - * thread. Not spawning anything. */ - return; - } else if (g_executor.pending_join != 0) { - /* Pickup the remains of the previous incarnations of the thread. */ - gpr_thd_join(g_executor.tid); - g_executor.pending_join = 0; - } - - /* All previous instances of the thread should have been joined at this point. - * Spawn time! */ - g_executor.busy = 1; - gpr_thd_new(&g_executor.tid, closure_exec_thread_func, NULL, - &g_executor.options); - g_executor.pending_join = 1; -} - -void grpc_executor_enqueue(grpc_closure *closure, bool success) { - gpr_mu_lock(&g_executor.mu); - if (g_executor.shutting_down == 0) { - grpc_closure_list_add(&g_executor.closures, closure, success); - maybe_spawn_locked(); - } - gpr_mu_unlock(&g_executor.mu); -} - -void grpc_executor_shutdown() { - int pending_join; - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - - gpr_mu_lock(&g_executor.mu); - pending_join = g_executor.pending_join; - g_executor.shutting_down = 1; - gpr_mu_unlock(&g_executor.mu); - /* we can release the lock at this point despite the access to the closure - * list below because we aren't accepting new work */ - - /* Execute pending callbacks, some may be performing cleanups */ - grpc_exec_ctx_enqueue_list(&exec_ctx, &g_executor.closures, NULL); - grpc_exec_ctx_finish(&exec_ctx); - GPR_ASSERT(grpc_closure_list_empty(g_executor.closures)); - if (pending_join) { - gpr_thd_join(g_executor.tid); - } - gpr_mu_destroy(&g_executor.mu); -} diff --git a/src/core/iomgr/executor.h b/src/core/iomgr/executor.h deleted file mode 100644 index f66b3560e3..0000000000 --- a/src/core/iomgr/executor.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * - * Copyright 2015-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_IOMGR_EXECUTOR_H -#define GRPC_CORE_IOMGR_EXECUTOR_H - -#include "src/core/iomgr/closure.h" - -/** Initialize the global executor. - * - * This mechanism is meant to outsource work (grpc_closure instances) to a - * thread, for those cases where blocking isn't an option but there isn't a - * non-blocking solution available. */ -void grpc_executor_init(); - -/** Enqueue \a closure for its eventual execution of \a f(arg) on a separate - * thread */ -void grpc_executor_enqueue(grpc_closure *closure, bool success); - -/** Shutdown the executor, running all pending work as part of the call */ -void grpc_executor_shutdown(); - -#endif /* GRPC_CORE_IOMGR_EXECUTOR_H */ diff --git a/src/core/iomgr/fd_posix.c b/src/core/iomgr/fd_posix.c deleted file mode 100644 index b4d038a3a1..0000000000 --- a/src/core/iomgr/fd_posix.c +++ /dev/null @@ -1,454 +0,0 @@ -/* - * - * Copyright 2015-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 - -#ifdef GPR_POSIX_SOCKET - -#include "src/core/iomgr/fd_posix.h" - -#include -#include -#include - -#include -#include -#include -#include - -#include "src/core/iomgr/pollset_posix.h" - -#define CLOSURE_NOT_READY ((grpc_closure *)0) -#define CLOSURE_READY ((grpc_closure *)1) - -/* We need to keep a freelist not because of any concerns of malloc performance - * but instead so that implementations with multiple threads in (for example) - * epoll_wait deal with the race between pollset removal and incoming poll - * notifications. - * - * The problem is that the poller ultimately holds a reference to this - * object, so it is very difficult to know when is safe to free it, at least - * without some expensive synchronization. - * - * If we keep the object freelisted, in the worst case losing this race just - * becomes a spurious read notification on a reused fd. - */ -/* TODO(klempner): We could use some form of polling generation count to know - * when these are safe to free. */ -/* TODO(klempner): Consider disabling freelisting if we don't have multiple - * threads in poll on the same fd */ -/* TODO(klempner): Batch these allocations to reduce fragmentation */ -static grpc_fd *fd_freelist = NULL; -static gpr_mu fd_freelist_mu; - -static void freelist_fd(grpc_fd *fd) { - gpr_mu_lock(&fd_freelist_mu); - fd->freelist_next = fd_freelist; - fd_freelist = fd; - grpc_iomgr_unregister_object(&fd->iomgr_object); - gpr_mu_unlock(&fd_freelist_mu); -} - -static grpc_fd *alloc_fd(int fd) { - grpc_fd *r = NULL; - gpr_mu_lock(&fd_freelist_mu); - if (fd_freelist != NULL) { - r = fd_freelist; - fd_freelist = fd_freelist->freelist_next; - } - gpr_mu_unlock(&fd_freelist_mu); - if (r == NULL) { - r = gpr_malloc(sizeof(grpc_fd)); - gpr_mu_init(&r->mu); - } - - gpr_mu_lock(&r->mu); - r->shutdown = 0; - r->read_closure = CLOSURE_NOT_READY; - r->write_closure = CLOSURE_NOT_READY; - r->fd = fd; - r->inactive_watcher_root.next = r->inactive_watcher_root.prev = - &r->inactive_watcher_root; - r->freelist_next = NULL; - r->read_watcher = r->write_watcher = NULL; - r->on_done_closure = NULL; - r->closed = 0; - r->released = 0; - gpr_atm_rel_store(&r->refst, 1); - gpr_mu_unlock(&r->mu); - - return r; -} - -static void destroy(grpc_fd *fd) { - gpr_mu_destroy(&fd->mu); - gpr_free(fd); -} - -#ifdef GRPC_FD_REF_COUNT_DEBUG -#define REF_BY(fd, n, reason) ref_by(fd, n, reason, __FILE__, __LINE__) -#define UNREF_BY(fd, n, reason) unref_by(fd, n, reason, __FILE__, __LINE__) -static void ref_by(grpc_fd *fd, int n, const char *reason, const char *file, - int line) { - gpr_log(GPR_DEBUG, "FD %d %p ref %d %d -> %d [%s; %s:%d]", fd->fd, fd, n, - gpr_atm_no_barrier_load(&fd->refst), - gpr_atm_no_barrier_load(&fd->refst) + n, reason, file, line); -#else -#define REF_BY(fd, n, reason) ref_by(fd, n) -#define UNREF_BY(fd, n, reason) unref_by(fd, n) -static void ref_by(grpc_fd *fd, int n) { -#endif - GPR_ASSERT(gpr_atm_no_barrier_fetch_add(&fd->refst, n) > 0); -} - -#ifdef GRPC_FD_REF_COUNT_DEBUG -static void unref_by(grpc_fd *fd, int n, const char *reason, const char *file, - int line) { - gpr_atm old; - gpr_log(GPR_DEBUG, "FD %d %p unref %d %d -> %d [%s; %s:%d]", fd->fd, fd, n, - gpr_atm_no_barrier_load(&fd->refst), - gpr_atm_no_barrier_load(&fd->refst) - n, reason, file, line); -#else -static void unref_by(grpc_fd *fd, int n) { - gpr_atm old; -#endif - old = gpr_atm_full_fetch_add(&fd->refst, -n); - if (old == n) { - freelist_fd(fd); - } else { - GPR_ASSERT(old > n); - } -} - -void grpc_fd_global_init(void) { gpr_mu_init(&fd_freelist_mu); } - -void grpc_fd_global_shutdown(void) { - gpr_mu_lock(&fd_freelist_mu); - gpr_mu_unlock(&fd_freelist_mu); - while (fd_freelist != NULL) { - grpc_fd *fd = fd_freelist; - fd_freelist = fd_freelist->freelist_next; - destroy(fd); - } - gpr_mu_destroy(&fd_freelist_mu); -} - -grpc_fd *grpc_fd_create(int fd, const char *name) { - grpc_fd *r = alloc_fd(fd); - char *name2; - gpr_asprintf(&name2, "%s fd=%d", name, fd); - grpc_iomgr_register_object(&r->iomgr_object, name2); - gpr_free(name2); -#ifdef GRPC_FD_REF_COUNT_DEBUG - gpr_log(GPR_DEBUG, "FD %d %p create %s", fd, r, name); -#endif - return r; -} - -int grpc_fd_is_orphaned(grpc_fd *fd) { - return (gpr_atm_acq_load(&fd->refst) & 1) == 0; -} - -static void pollset_kick_locked(grpc_fd_watcher *watcher) { - gpr_mu_lock(&watcher->pollset->mu); - GPR_ASSERT(watcher->worker); - grpc_pollset_kick_ext(watcher->pollset, watcher->worker, - GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP); - gpr_mu_unlock(&watcher->pollset->mu); -} - -static void maybe_wake_one_watcher_locked(grpc_fd *fd) { - if (fd->inactive_watcher_root.next != &fd->inactive_watcher_root) { - pollset_kick_locked(fd->inactive_watcher_root.next); - } else if (fd->read_watcher) { - pollset_kick_locked(fd->read_watcher); - } else if (fd->write_watcher) { - pollset_kick_locked(fd->write_watcher); - } -} - -static void wake_all_watchers_locked(grpc_fd *fd) { - grpc_fd_watcher *watcher; - for (watcher = fd->inactive_watcher_root.next; - watcher != &fd->inactive_watcher_root; watcher = watcher->next) { - pollset_kick_locked(watcher); - } - if (fd->read_watcher) { - pollset_kick_locked(fd->read_watcher); - } - if (fd->write_watcher && fd->write_watcher != fd->read_watcher) { - pollset_kick_locked(fd->write_watcher); - } -} - -static int has_watchers(grpc_fd *fd) { - return fd->read_watcher != NULL || fd->write_watcher != NULL || - fd->inactive_watcher_root.next != &fd->inactive_watcher_root; -} - -static void close_fd_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd) { - fd->closed = 1; - if (!fd->released) { - close(fd->fd); - } else { - grpc_remove_fd_from_all_epoll_sets(fd->fd); - } - grpc_exec_ctx_enqueue(exec_ctx, fd->on_done_closure, true, NULL); -} - -int grpc_fd_wrapped_fd(grpc_fd *fd) { - if (fd->released || fd->closed) { - return -1; - } else { - return fd->fd; - } -} - -void grpc_fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *on_done, - int *release_fd, const char *reason) { - fd->on_done_closure = on_done; - fd->released = release_fd != NULL; - if (!fd->released) { - shutdown(fd->fd, SHUT_RDWR); - } else { - *release_fd = fd->fd; - } - gpr_mu_lock(&fd->mu); - REF_BY(fd, 1, reason); /* remove active status, but keep referenced */ - if (!has_watchers(fd)) { - close_fd_locked(exec_ctx, fd); - } else { - wake_all_watchers_locked(fd); - } - gpr_mu_unlock(&fd->mu); - UNREF_BY(fd, 2, reason); /* drop the reference */ -} - -/* increment refcount by two to avoid changing the orphan bit */ -#ifdef GRPC_FD_REF_COUNT_DEBUG -void grpc_fd_ref(grpc_fd *fd, const char *reason, const char *file, int line) { - ref_by(fd, 2, reason, file, line); -} - -void grpc_fd_unref(grpc_fd *fd, const char *reason, const char *file, - int line) { - unref_by(fd, 2, reason, file, line); -} -#else -void grpc_fd_ref(grpc_fd *fd) { ref_by(fd, 2); } - -void grpc_fd_unref(grpc_fd *fd) { unref_by(fd, 2); } -#endif - -static void notify_on_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd, - grpc_closure **st, grpc_closure *closure) { - if (*st == CLOSURE_NOT_READY) { - /* not ready ==> switch to a waiting state by setting the closure */ - *st = closure; - } else if (*st == CLOSURE_READY) { - /* already ready ==> queue the closure to run immediately */ - *st = CLOSURE_NOT_READY; - grpc_exec_ctx_enqueue(exec_ctx, closure, !fd->shutdown, NULL); - maybe_wake_one_watcher_locked(fd); - } else { - /* upcallptr was set to a different closure. This is an error! */ - gpr_log(GPR_ERROR, - "User called a notify_on function with a previous callback still " - "pending"); - abort(); - } -} - -/* returns 1 if state becomes not ready */ -static int set_ready_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd, - grpc_closure **st) { - if (*st == CLOSURE_READY) { - /* duplicate ready ==> ignore */ - return 0; - } else if (*st == CLOSURE_NOT_READY) { - /* not ready, and not waiting ==> flag ready */ - *st = CLOSURE_READY; - return 0; - } else { - /* waiting ==> queue closure */ - grpc_exec_ctx_enqueue(exec_ctx, *st, !fd->shutdown, NULL); - *st = CLOSURE_NOT_READY; - return 1; - } -} - -static void set_ready(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure **st) { - /* only one set_ready can be active at once (but there may be a racing - notify_on) */ - gpr_mu_lock(&fd->mu); - set_ready_locked(exec_ctx, fd, st); - gpr_mu_unlock(&fd->mu); -} - -void grpc_fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd) { - gpr_mu_lock(&fd->mu); - GPR_ASSERT(!fd->shutdown); - fd->shutdown = 1; - set_ready_locked(exec_ctx, fd, &fd->read_closure); - set_ready_locked(exec_ctx, fd, &fd->write_closure); - gpr_mu_unlock(&fd->mu); -} - -void grpc_fd_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_fd *fd, - grpc_closure *closure) { - gpr_mu_lock(&fd->mu); - notify_on_locked(exec_ctx, fd, &fd->read_closure, closure); - gpr_mu_unlock(&fd->mu); -} - -void grpc_fd_notify_on_write(grpc_exec_ctx *exec_ctx, grpc_fd *fd, - grpc_closure *closure) { - gpr_mu_lock(&fd->mu); - notify_on_locked(exec_ctx, fd, &fd->write_closure, closure); - gpr_mu_unlock(&fd->mu); -} - -uint32_t grpc_fd_begin_poll(grpc_fd *fd, grpc_pollset *pollset, - grpc_pollset_worker *worker, uint32_t read_mask, - uint32_t write_mask, grpc_fd_watcher *watcher) { - uint32_t mask = 0; - grpc_closure *cur; - int requested; - /* keep track of pollers that have requested our events, in case they change - */ - GRPC_FD_REF(fd, "poll"); - - gpr_mu_lock(&fd->mu); - - /* if we are shutdown, then don't add to the watcher set */ - if (fd->shutdown) { - watcher->fd = NULL; - watcher->pollset = NULL; - watcher->worker = NULL; - gpr_mu_unlock(&fd->mu); - GRPC_FD_UNREF(fd, "poll"); - return 0; - } - - /* if there is nobody polling for read, but we need to, then start doing so */ - cur = fd->read_closure; - requested = cur != CLOSURE_READY; - if (read_mask && fd->read_watcher == NULL && requested) { - fd->read_watcher = watcher; - mask |= read_mask; - } - /* if there is nobody polling for write, but we need to, then start doing so - */ - cur = fd->write_closure; - requested = cur != CLOSURE_READY; - if (write_mask && fd->write_watcher == NULL && requested) { - fd->write_watcher = watcher; - mask |= write_mask; - } - /* if not polling, remember this watcher in case we need someone to later */ - if (mask == 0 && worker != NULL) { - watcher->next = &fd->inactive_watcher_root; - watcher->prev = watcher->next->prev; - watcher->next->prev = watcher->prev->next = watcher; - } - watcher->pollset = pollset; - watcher->worker = worker; - watcher->fd = fd; - gpr_mu_unlock(&fd->mu); - - return mask; -} - -void grpc_fd_end_poll(grpc_exec_ctx *exec_ctx, grpc_fd_watcher *watcher, - int got_read, int got_write) { - int was_polling = 0; - int kick = 0; - grpc_fd *fd = watcher->fd; - - if (fd == NULL) { - return; - } - - gpr_mu_lock(&fd->mu); - - if (watcher == fd->read_watcher) { - /* remove read watcher, kick if we still need a read */ - was_polling = 1; - if (!got_read) { - kick = 1; - } - fd->read_watcher = NULL; - } - if (watcher == fd->write_watcher) { - /* remove write watcher, kick if we still need a write */ - was_polling = 1; - if (!got_write) { - kick = 1; - } - fd->write_watcher = NULL; - } - if (!was_polling && watcher->worker != NULL) { - /* remove from inactive list */ - watcher->next->prev = watcher->prev; - watcher->prev->next = watcher->next; - } - if (got_read) { - if (set_ready_locked(exec_ctx, fd, &fd->read_closure)) { - kick = 1; - } - } - if (got_write) { - if (set_ready_locked(exec_ctx, fd, &fd->write_closure)) { - kick = 1; - } - } - if (kick) { - maybe_wake_one_watcher_locked(fd); - } - if (grpc_fd_is_orphaned(fd) && !has_watchers(fd) && !fd->closed) { - close_fd_locked(exec_ctx, fd); - } - gpr_mu_unlock(&fd->mu); - - GRPC_FD_UNREF(fd, "poll"); -} - -void grpc_fd_become_readable(grpc_exec_ctx *exec_ctx, grpc_fd *fd) { - set_ready(exec_ctx, fd, &fd->read_closure); -} - -void grpc_fd_become_writable(grpc_exec_ctx *exec_ctx, grpc_fd *fd) { - set_ready(exec_ctx, fd, &fd->write_closure); -} - -#endif diff --git a/src/core/iomgr/fd_posix.h b/src/core/iomgr/fd_posix.h deleted file mode 100644 index 1993ada79f..0000000000 --- a/src/core/iomgr/fd_posix.h +++ /dev/null @@ -1,192 +0,0 @@ -/* - * - * Copyright 2015-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_IOMGR_FD_POSIX_H -#define GRPC_CORE_IOMGR_FD_POSIX_H - -#include -#include -#include -#include "src/core/iomgr/iomgr_internal.h" -#include "src/core/iomgr/pollset.h" - -typedef struct grpc_fd grpc_fd; - -typedef struct grpc_fd_watcher { - struct grpc_fd_watcher *next; - struct grpc_fd_watcher *prev; - grpc_pollset *pollset; - grpc_pollset_worker *worker; - grpc_fd *fd; -} grpc_fd_watcher; - -struct grpc_fd { - int fd; - /* refst format: - bit0: 1=active/0=orphaned - bit1-n: refcount - meaning that mostly we ref by two to avoid altering the orphaned bit, - and just unref by 1 when we're ready to flag the object as orphaned */ - gpr_atm refst; - - gpr_mu mu; - int shutdown; - int closed; - int released; - - /* The watcher list. - - The following watcher related fields are protected by watcher_mu. - - An fd_watcher is an ephemeral object created when an fd wants to - begin polling, and destroyed after the poll. - - It denotes the fd's interest in whether to read poll or write poll - or both or neither on this fd. - - If a watcher is asked to poll for reads or writes, the read_watcher - or write_watcher fields are set respectively. A watcher may be asked - to poll for both, in which case both fields will be set. - - read_watcher and write_watcher may be NULL if no watcher has been - asked to poll for reads or writes. - - If an fd_watcher is not asked to poll for reads or writes, it's added - to a linked list of inactive watchers, rooted at inactive_watcher_root. - If at a later time there becomes need of a poller to poll, one of - the inactive pollers may be kicked out of their poll loops to take - that responsibility. */ - grpc_fd_watcher inactive_watcher_root; - grpc_fd_watcher *read_watcher; - grpc_fd_watcher *write_watcher; - - grpc_closure *read_closure; - grpc_closure *write_closure; - - struct grpc_fd *freelist_next; - - grpc_closure *on_done_closure; - - grpc_iomgr_object iomgr_object; -}; - -/* Create a wrapped file descriptor. - Requires fd is a non-blocking file descriptor. - This takes ownership of closing fd. */ -grpc_fd *grpc_fd_create(int fd, const char *name); - -/* Return the wrapped fd, or -1 if it has been released or closed. */ -int grpc_fd_wrapped_fd(grpc_fd *fd); - -/* Releases fd to be asynchronously destroyed. - on_done is called when the underlying file descriptor is definitely close()d. - If on_done is NULL, no callback will be made. - If release_fd is not NULL, it's set to fd and fd will not be closed. - Requires: *fd initialized; no outstanding notify_on_read or - notify_on_write. - MUST NOT be called with a pollset lock taken */ -void grpc_fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *on_done, - int *release_fd, const char *reason); - -/* Begin polling on an fd. - Registers that the given pollset is interested in this fd - so that if read - or writability interest changes, the pollset can be kicked to pick up that - new interest. - Return value is: - (fd_needs_read? read_mask : 0) | (fd_needs_write? write_mask : 0) - i.e. a combination of read_mask and write_mask determined by the fd's current - interest in said events. - Polling strategies that do not need to alter their behavior depending on the - fd's current interest (such as epoll) do not need to call this function. - MUST NOT be called with a pollset lock taken */ -uint32_t grpc_fd_begin_poll(grpc_fd *fd, grpc_pollset *pollset, - grpc_pollset_worker *worker, uint32_t read_mask, - uint32_t write_mask, grpc_fd_watcher *rec); -/* Complete polling previously started with grpc_fd_begin_poll - MUST NOT be called with a pollset lock taken - if got_read or got_write are 1, also does the become_{readable,writable} as - appropriate. */ -void grpc_fd_end_poll(grpc_exec_ctx *exec_ctx, grpc_fd_watcher *rec, - int got_read, int got_write); - -/* Return 1 if this fd is orphaned, 0 otherwise */ -int grpc_fd_is_orphaned(grpc_fd *fd); - -/* Cause any current callbacks to error out with GRPC_CALLBACK_CANCELLED. */ -void grpc_fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd); - -/* Register read interest, causing read_cb to be called once when fd becomes - readable, on deadline specified by deadline, or on shutdown triggered by - grpc_fd_shutdown. - read_cb will be called with read_cb_arg when *fd becomes readable. - read_cb is Called with status of GRPC_CALLBACK_SUCCESS if readable, - GRPC_CALLBACK_TIMED_OUT if the call timed out, - and CANCELLED if the call was cancelled. - - Requires:This method must not be called before the read_cb for any previous - call runs. Edge triggered events are used whenever they are supported by the - underlying platform. This means that users must drain fd in read_cb before - calling notify_on_read again. Users are also expected to handle spurious - events, i.e read_cb is called while nothing can be readable from fd */ -void grpc_fd_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_fd *fd, - grpc_closure *closure); - -/* Exactly the same semantics as above, except based on writable events. */ -void grpc_fd_notify_on_write(grpc_exec_ctx *exec_ctx, grpc_fd *fd, - grpc_closure *closure); - -/* Notification from the poller to an fd that it has become readable or - writable. - If allow_synchronous_callback is 1, allow running the fd callback inline - in this callstack, otherwise register an asynchronous callback and return */ -void grpc_fd_become_readable(grpc_exec_ctx *exec_ctx, grpc_fd *fd); -void grpc_fd_become_writable(grpc_exec_ctx *exec_ctx, grpc_fd *fd); - -/* Reference counting for fds */ -/*#define GRPC_FD_REF_COUNT_DEBUG*/ -#ifdef GRPC_FD_REF_COUNT_DEBUG -void grpc_fd_ref(grpc_fd *fd, const char *reason, const char *file, int line); -void grpc_fd_unref(grpc_fd *fd, const char *reason, const char *file, int line); -#define GRPC_FD_REF(fd, reason) grpc_fd_ref(fd, reason, __FILE__, __LINE__) -#define GRPC_FD_UNREF(fd, reason) grpc_fd_unref(fd, reason, __FILE__, __LINE__) -#else -void grpc_fd_ref(grpc_fd *fd); -void grpc_fd_unref(grpc_fd *fd); -#define GRPC_FD_REF(fd, reason) grpc_fd_ref(fd) -#define GRPC_FD_UNREF(fd, reason) grpc_fd_unref(fd) -#endif - -void grpc_fd_global_init(void); -void grpc_fd_global_shutdown(void); - -#endif /* GRPC_CORE_IOMGR_FD_POSIX_H */ diff --git a/src/core/iomgr/iocp_windows.c b/src/core/iomgr/iocp_windows.c deleted file mode 100644 index 37e277dcc1..0000000000 --- a/src/core/iomgr/iocp_windows.c +++ /dev/null @@ -1,208 +0,0 @@ -/* - * - * Copyright 2015-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 - -#ifdef GPR_WINSOCK_SOCKET - -#include - -#include -#include -#include -#include - -#include "src/core/iomgr/iocp_windows.h" -#include "src/core/iomgr/iomgr_internal.h" -#include "src/core/iomgr/socket_windows.h" -#include "src/core/iomgr/timer.h" - -static ULONG g_iocp_kick_token; -static OVERLAPPED g_iocp_custom_overlap; - -static gpr_atm g_custom_events = 0; - -static HANDLE g_iocp; - -static DWORD deadline_to_millis_timeout(gpr_timespec deadline, - gpr_timespec now) { - gpr_timespec timeout; - static const int64_t max_spin_polling_us = 10; - if (gpr_time_cmp(deadline, gpr_inf_future(deadline.clock_type)) == 0) { - return INFINITE; - } - if (gpr_time_cmp(deadline, gpr_time_add(now, gpr_time_from_micros( - max_spin_polling_us, - GPR_TIMESPAN))) <= 0) { - return 0; - } - timeout = gpr_time_sub(deadline, now); - return (DWORD)gpr_time_to_millis(gpr_time_add( - timeout, gpr_time_from_nanos(GPR_NS_PER_MS - 1, GPR_TIMESPAN))); -} - -grpc_iocp_work_status grpc_iocp_work(grpc_exec_ctx *exec_ctx, - gpr_timespec deadline) { - BOOL success; - DWORD bytes = 0; - DWORD flags = 0; - ULONG_PTR completion_key; - LPOVERLAPPED overlapped; - grpc_winsocket *socket; - grpc_winsocket_callback_info *info; - grpc_closure *closure = NULL; - success = GetQueuedCompletionStatus( - g_iocp, &bytes, &completion_key, &overlapped, - deadline_to_millis_timeout(deadline, gpr_now(deadline.clock_type))); - if (success == 0 && overlapped == NULL) { - return GRPC_IOCP_WORK_TIMEOUT; - } - GPR_ASSERT(completion_key && overlapped); - if (overlapped == &g_iocp_custom_overlap) { - gpr_atm_full_fetch_add(&g_custom_events, -1); - if (completion_key == (ULONG_PTR)&g_iocp_kick_token) { - /* We were awoken from a kick. */ - return GRPC_IOCP_WORK_KICK; - } - gpr_log(GPR_ERROR, "Unknown custom completion key."); - abort(); - } - - socket = (grpc_winsocket *)completion_key; - if (overlapped == &socket->write_info.overlapped) { - info = &socket->write_info; - } else if (overlapped == &socket->read_info.overlapped) { - info = &socket->read_info; - } else { - gpr_log(GPR_ERROR, "Unknown IOCP operation"); - abort(); - } - success = WSAGetOverlappedResult(socket->socket, &info->overlapped, &bytes, - FALSE, &flags); - info->bytes_transfered = bytes; - info->wsa_error = success ? 0 : WSAGetLastError(); - GPR_ASSERT(overlapped == &info->overlapped); - GPR_ASSERT(!info->has_pending_iocp); - gpr_mu_lock(&socket->state_mu); - if (info->closure) { - closure = info->closure; - info->closure = NULL; - } else { - info->has_pending_iocp = 1; - } - gpr_mu_unlock(&socket->state_mu); - grpc_exec_ctx_enqueue(exec_ctx, closure, true, NULL); - return GRPC_IOCP_WORK_WORK; -} - -void grpc_iocp_init(void) { - g_iocp = - CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, (ULONG_PTR)NULL, 0); - GPR_ASSERT(g_iocp); -} - -void grpc_iocp_kick(void) { - BOOL success; - - gpr_atm_full_fetch_add(&g_custom_events, 1); - success = PostQueuedCompletionStatus(g_iocp, 0, (ULONG_PTR)&g_iocp_kick_token, - &g_iocp_custom_overlap); - GPR_ASSERT(success); -} - -void grpc_iocp_flush(void) { - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_iocp_work_status work_status; - - do { - work_status = grpc_iocp_work(&exec_ctx, gpr_inf_past(GPR_CLOCK_MONOTONIC)); - } while (work_status == GRPC_IOCP_WORK_KICK || - grpc_exec_ctx_flush(&exec_ctx)); -} - -void grpc_iocp_shutdown(void) { - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - while (gpr_atm_acq_load(&g_custom_events)) { - grpc_iocp_work(&exec_ctx, gpr_inf_future(GPR_CLOCK_MONOTONIC)); - grpc_exec_ctx_flush(&exec_ctx); - } - grpc_exec_ctx_finish(&exec_ctx); - GPR_ASSERT(CloseHandle(g_iocp)); -} - -void grpc_iocp_add_socket(grpc_winsocket *socket) { - HANDLE ret; - if (socket->added_to_iocp) return; - ret = CreateIoCompletionPort((HANDLE)socket->socket, g_iocp, - (uintptr_t)socket, 0); - if (!ret) { - char *utf8_message = gpr_format_message(WSAGetLastError()); - gpr_log(GPR_ERROR, "Unable to add socket to iocp: %s", utf8_message); - gpr_free(utf8_message); - __debugbreak(); - abort(); - } - socket->added_to_iocp = 1; - GPR_ASSERT(ret == g_iocp); -} - -/* Calling notify_on_read or write means either of two things: - -) The IOCP already completed in the background, and we need to call - the callback now. - -) The IOCP hasn't completed yet, and we're queuing it for later. */ -static void socket_notify_on_iocp(grpc_exec_ctx *exec_ctx, - grpc_winsocket *socket, grpc_closure *closure, - grpc_winsocket_callback_info *info) { - GPR_ASSERT(info->closure == NULL); - gpr_mu_lock(&socket->state_mu); - if (info->has_pending_iocp) { - info->has_pending_iocp = 0; - grpc_exec_ctx_enqueue(exec_ctx, closure, true, NULL); - } else { - info->closure = closure; - } - gpr_mu_unlock(&socket->state_mu); -} - -void grpc_socket_notify_on_write(grpc_exec_ctx *exec_ctx, - grpc_winsocket *socket, - grpc_closure *closure) { - socket_notify_on_iocp(exec_ctx, socket, closure, &socket->write_info); -} - -void grpc_socket_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_winsocket *socket, - grpc_closure *closure) { - socket_notify_on_iocp(exec_ctx, socket, closure, &socket->read_info); -} - -#endif /* GPR_WINSOCK_SOCKET */ diff --git a/src/core/iomgr/iocp_windows.h b/src/core/iomgr/iocp_windows.h deleted file mode 100644 index 570b8925aa..0000000000 --- a/src/core/iomgr/iocp_windows.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * - * Copyright 2015-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_IOMGR_IOCP_WINDOWS_H -#define GRPC_CORE_IOMGR_IOCP_WINDOWS_H - -#include - -#include "src/core/iomgr/socket_windows.h" - -typedef enum { - GRPC_IOCP_WORK_WORK, - GRPC_IOCP_WORK_TIMEOUT, - GRPC_IOCP_WORK_KICK -} grpc_iocp_work_status; - -grpc_iocp_work_status grpc_iocp_work(grpc_exec_ctx *exec_ctx, - gpr_timespec deadline); -void grpc_iocp_init(void); -void grpc_iocp_kick(void); -void grpc_iocp_flush(void); -void grpc_iocp_shutdown(void); -void grpc_iocp_add_socket(grpc_winsocket *); - -void grpc_socket_notify_on_write(grpc_exec_ctx *exec_ctx, - grpc_winsocket *winsocket, - grpc_closure *closure); - -void grpc_socket_notify_on_read(grpc_exec_ctx *exec_ctx, - grpc_winsocket *winsocket, - grpc_closure *closure); - -#endif /* GRPC_CORE_IOMGR_IOCP_WINDOWS_H */ diff --git a/src/core/iomgr/iomgr.c b/src/core/iomgr/iomgr.c deleted file mode 100644 index 3ab4430668..0000000000 --- a/src/core/iomgr/iomgr.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * - * Copyright 2015-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/iomgr/iomgr.h" - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "src/core/iomgr/exec_ctx.h" -#include "src/core/iomgr/iomgr_internal.h" -#include "src/core/iomgr/timer.h" -#include "src/core/support/env.h" -#include "src/core/support/string.h" - -static gpr_mu g_mu; -static gpr_cv g_rcv; -static int g_shutdown; -static grpc_iomgr_object g_root_object; - -void grpc_iomgr_init(void) { - g_shutdown = 0; - gpr_mu_init(&g_mu); - gpr_cv_init(&g_rcv); - grpc_exec_ctx_global_init(); - grpc_timer_list_init(gpr_now(GPR_CLOCK_MONOTONIC)); - g_root_object.next = g_root_object.prev = &g_root_object; - g_root_object.name = "root"; - grpc_iomgr_platform_init(); - grpc_pollset_global_init(); -} - -static size_t count_objects(void) { - grpc_iomgr_object *obj; - size_t n = 0; - for (obj = g_root_object.next; obj != &g_root_object; obj = obj->next) { - n++; - } - return n; -} - -static void dump_objects(const char *kind) { - grpc_iomgr_object *obj; - for (obj = g_root_object.next; obj != &g_root_object; obj = obj->next) { - gpr_log(GPR_DEBUG, "%s OBJECT: %s %p", kind, obj->name, obj); - } -} - -void grpc_iomgr_shutdown(void) { - gpr_timespec shutdown_deadline = gpr_time_add( - gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_seconds(10, GPR_TIMESPAN)); - gpr_timespec last_warning_time = gpr_now(GPR_CLOCK_REALTIME); - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - - grpc_iomgr_platform_flush(); - - gpr_mu_lock(&g_mu); - g_shutdown = 1; - while (g_root_object.next != &g_root_object) { - if (gpr_time_cmp( - gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), last_warning_time), - gpr_time_from_seconds(1, GPR_TIMESPAN)) >= 0) { - if (g_root_object.next != &g_root_object) { - gpr_log(GPR_DEBUG, "Waiting for %d iomgr objects to be destroyed", - count_objects()); - } - last_warning_time = gpr_now(GPR_CLOCK_REALTIME); - } - if (grpc_timer_check(&exec_ctx, gpr_inf_future(GPR_CLOCK_MONOTONIC), - NULL)) { - gpr_mu_unlock(&g_mu); - grpc_exec_ctx_flush(&exec_ctx); - gpr_mu_lock(&g_mu); - continue; - } - if (g_root_object.next != &g_root_object) { - gpr_timespec short_deadline = gpr_time_add( - gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_millis(100, GPR_TIMESPAN)); - if (gpr_cv_wait(&g_rcv, &g_mu, short_deadline)) { - 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", - count_objects()); - dump_objects("LEAKED"); - if (grpc_iomgr_abort_on_leaks()) { - abort(); - } - } - break; - } - } - } - } - gpr_mu_unlock(&g_mu); - - grpc_timer_list_shutdown(&exec_ctx); - grpc_exec_ctx_finish(&exec_ctx); - - /* ensure all threads have left g_mu */ - gpr_mu_lock(&g_mu); - gpr_mu_unlock(&g_mu); - - grpc_pollset_global_shutdown(); - grpc_iomgr_platform_shutdown(); - grpc_exec_ctx_global_shutdown(); - gpr_mu_destroy(&g_mu); - gpr_cv_destroy(&g_rcv); -} - -void grpc_iomgr_register_object(grpc_iomgr_object *obj, const char *name) { - obj->name = gpr_strdup(name); - gpr_mu_lock(&g_mu); - obj->next = &g_root_object; - obj->prev = g_root_object.prev; - obj->next->prev = obj->prev->next = obj; - gpr_mu_unlock(&g_mu); -} - -void grpc_iomgr_unregister_object(grpc_iomgr_object *obj) { - gpr_mu_lock(&g_mu); - obj->next->prev = obj->prev; - obj->prev->next = obj->next; - gpr_cv_signal(&g_rcv); - gpr_mu_unlock(&g_mu); - gpr_free(obj->name); -} - -bool grpc_iomgr_abort_on_leaks(void) { - char *env = gpr_getenv("GRPC_ABORT_ON_LEAKS"); - if (env == NULL) return false; - static const char *truthy[] = {"yes", "Yes", "YES", "true", - "True", "TRUE", "1"}; - for (size_t i = 0; i < GPR_ARRAY_SIZE(truthy); i++) { - if (0 == strcmp(env, truthy[i])) return true; - } - return false; -} diff --git a/src/core/iomgr/iomgr.h b/src/core/iomgr/iomgr.h deleted file mode 100644 index e1237a4533..0000000000 --- a/src/core/iomgr/iomgr.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * - * Copyright 2015-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_IOMGR_IOMGR_H -#define GRPC_CORE_IOMGR_IOMGR_H - -/** Initializes the iomgr. */ -void grpc_iomgr_init(void); - -/** Signals the intention to shutdown the iomgr. */ -void grpc_iomgr_shutdown(void); - -#endif /* GRPC_CORE_IOMGR_IOMGR_H */ diff --git a/src/core/iomgr/iomgr_internal.h b/src/core/iomgr/iomgr_internal.h deleted file mode 100644 index 1cad3182ec..0000000000 --- a/src/core/iomgr/iomgr_internal.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * - * Copyright 2015-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_IOMGR_IOMGR_INTERNAL_H -#define GRPC_CORE_IOMGR_IOMGR_INTERNAL_H - -#include - -#include -#include "src/core/iomgr/iomgr.h" - -typedef struct grpc_iomgr_object { - char *name; - struct grpc_iomgr_object *next; - struct grpc_iomgr_object *prev; -} grpc_iomgr_object; - -void grpc_pollset_global_init(void); -void grpc_pollset_global_shutdown(void); - -void grpc_iomgr_register_object(grpc_iomgr_object *obj, const char *name); -void grpc_iomgr_unregister_object(grpc_iomgr_object *obj); - -void grpc_iomgr_platform_init(void); -/** flush any globally queued work from iomgr */ -void grpc_iomgr_platform_flush(void); -/** tear down all platform specific global iomgr structures */ -void grpc_iomgr_platform_shutdown(void); - -bool grpc_iomgr_abort_on_leaks(void); - -#endif /* GRPC_CORE_IOMGR_IOMGR_INTERNAL_H */ diff --git a/src/core/iomgr/iomgr_posix.c b/src/core/iomgr/iomgr_posix.c deleted file mode 100644 index 2f7f34746b..0000000000 --- a/src/core/iomgr/iomgr_posix.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * - * Copyright 2015-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 - -#ifdef GPR_POSIX_SOCKET - -#include "src/core/debug/trace.h" -#include "src/core/iomgr/fd_posix.h" -#include "src/core/iomgr/iomgr_posix.h" -#include "src/core/iomgr/tcp_posix.h" - -void grpc_iomgr_platform_init(void) { - grpc_fd_global_init(); - grpc_register_tracer("tcp", &grpc_tcp_trace); -} - -void grpc_iomgr_platform_flush(void) {} - -void grpc_iomgr_platform_shutdown(void) { grpc_fd_global_shutdown(); } - -#endif /* GRPC_POSIX_SOCKET */ diff --git a/src/core/iomgr/iomgr_posix.h b/src/core/iomgr/iomgr_posix.h deleted file mode 100644 index 698fb6aee7..0000000000 --- a/src/core/iomgr/iomgr_posix.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * - * Copyright 2015-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_IOMGR_IOMGR_POSIX_H -#define GRPC_CORE_IOMGR_IOMGR_POSIX_H - -#include "src/core/iomgr/iomgr_internal.h" - -#endif /* GRPC_CORE_IOMGR_IOMGR_POSIX_H */ diff --git a/src/core/iomgr/iomgr_windows.c b/src/core/iomgr/iomgr_windows.c deleted file mode 100644 index 2d104130f7..0000000000 --- a/src/core/iomgr/iomgr_windows.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * - * Copyright 2015-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 - -#ifdef GPR_WINSOCK_SOCKET - -#include "src/core/iomgr/sockaddr_win32.h" - -#include - -#include "src/core/iomgr/iocp_windows.h" -#include "src/core/iomgr/iomgr.h" -#include "src/core/iomgr/socket_windows.h" - -/* Windows' io manager is going to be fully designed using IO completion - ports. All of what we're doing here is basically make sure that - Windows sockets are initialized in and out. */ - -static void winsock_init(void) { - WSADATA wsaData; - int status = WSAStartup(MAKEWORD(2, 0), &wsaData); - GPR_ASSERT(status == 0); -} - -static void winsock_shutdown(void) { - int status = WSACleanup(); - GPR_ASSERT(status == 0); -} - -void grpc_iomgr_platform_init(void) { - winsock_init(); - grpc_iocp_init(); -} - -void grpc_iomgr_platform_flush(void) { grpc_iocp_flush(); } - -void grpc_iomgr_platform_shutdown(void) { - grpc_iocp_shutdown(); - winsock_shutdown(); -} - -#endif /* GRPC_WINSOCK_SOCKET */ diff --git a/src/core/iomgr/pollset.h b/src/core/iomgr/pollset.h deleted file mode 100644 index 9500b1a73a..0000000000 --- a/src/core/iomgr/pollset.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * - * Copyright 2015-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_IOMGR_POLLSET_H -#define GRPC_CORE_IOMGR_POLLSET_H - -#include -#include -#include - -#include "src/core/iomgr/exec_ctx.h" - -#define GRPC_POLLSET_KICK_BROADCAST ((grpc_pollset_worker *)1) - -/* A grpc_pollset is a set of file descriptors that a higher level item is - interested in. For example: - - a server will typically keep a pollset containing all connected channels, - so that it can find new calls to service - - a completion queue might keep a pollset with an entry for each transport - that is servicing a call that it's tracking */ - -typedef struct grpc_pollset grpc_pollset; -typedef struct grpc_pollset_worker grpc_pollset_worker; - -size_t grpc_pollset_size(void); -void grpc_pollset_init(grpc_pollset *pollset, gpr_mu **mu); -/* Begin shutting down the pollset, and call closure when done. - * pollset's mutex must be held */ -void grpc_pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, - grpc_closure *closure); -/** Reset the pollset to its initial state (perhaps with some cached objects); - * must have been previously shutdown */ -void grpc_pollset_reset(grpc_pollset *pollset); -void grpc_pollset_destroy(grpc_pollset *pollset); - -/* Do some work on a pollset. - May involve invoking asynchronous callbacks, or actually polling file - descriptors. - Requires pollset's mutex locked. - May unlock its mutex during its execution. - - worker is a (platform-specific) handle that can be used to wake up - from grpc_pollset_work before any events are received and before the timeout - has expired. It is both initialized and destroyed by grpc_pollset_work. - Initialization of worker is guaranteed to occur BEFORE the - pollset's mutex is released for the first time by grpc_pollset_work - and it is guaranteed that it will not be released by grpc_pollset_work - AFTER worker has been destroyed. - - Tries not to block past deadline. - May call grpc_closure_list_run on grpc_closure_list, without holding the - pollset - lock */ -void grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, - grpc_pollset_worker **worker, gpr_timespec now, - gpr_timespec deadline); - -/* Break one polling thread out of polling work for this pollset. - If specific_worker is GRPC_POLLSET_KICK_BROADCAST, kick ALL the workers. - Otherwise, if specific_worker is non-NULL, then kick that worker. */ -void grpc_pollset_kick(grpc_pollset *pollset, - grpc_pollset_worker *specific_worker); - -#endif /* GRPC_CORE_IOMGR_POLLSET_H */ diff --git a/src/core/iomgr/pollset_multipoller_with_epoll.c b/src/core/iomgr/pollset_multipoller_with_epoll.c deleted file mode 100644 index 2e0f27fab8..0000000000 --- a/src/core/iomgr/pollset_multipoller_with_epoll.c +++ /dev/null @@ -1,324 +0,0 @@ -/* - * - * Copyright 2015-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 - -#ifdef GPR_LINUX_MULTIPOLL_WITH_EPOLL - -#include -#include -#include -#include -#include - -#include -#include -#include -#include "src/core/iomgr/fd_posix.h" -#include "src/core/iomgr/pollset_posix.h" -#include "src/core/profiling/timers.h" -#include "src/core/support/block_annotate.h" - -struct epoll_fd_list { - int *epoll_fds; - size_t count; - size_t capacity; -}; - -static struct epoll_fd_list epoll_fd_global_list; -static gpr_once init_epoll_fd_list_mu = GPR_ONCE_INIT; -static gpr_mu epoll_fd_list_mu; - -static void init_mu(void) { gpr_mu_init(&epoll_fd_list_mu); } - -static void add_epoll_fd_to_global_list(int epoll_fd) { - gpr_once_init(&init_epoll_fd_list_mu, init_mu); - - gpr_mu_lock(&epoll_fd_list_mu); - if (epoll_fd_global_list.count == epoll_fd_global_list.capacity) { - epoll_fd_global_list.capacity = - GPR_MAX((size_t)8, epoll_fd_global_list.capacity * 2); - epoll_fd_global_list.epoll_fds = - gpr_realloc(epoll_fd_global_list.epoll_fds, - epoll_fd_global_list.capacity * sizeof(int)); - } - epoll_fd_global_list.epoll_fds[epoll_fd_global_list.count++] = epoll_fd; - gpr_mu_unlock(&epoll_fd_list_mu); -} - -static void remove_epoll_fd_from_global_list(int epoll_fd) { - gpr_mu_lock(&epoll_fd_list_mu); - GPR_ASSERT(epoll_fd_global_list.count > 0); - for (size_t i = 0; i < epoll_fd_global_list.count; i++) { - if (epoll_fd == epoll_fd_global_list.epoll_fds[i]) { - epoll_fd_global_list.epoll_fds[i] = - epoll_fd_global_list.epoll_fds[--(epoll_fd_global_list.count)]; - break; - } - } - gpr_mu_unlock(&epoll_fd_list_mu); -} - -void grpc_remove_fd_from_all_epoll_sets(int fd) { - int err; - gpr_once_init(&init_epoll_fd_list_mu, init_mu); - gpr_mu_lock(&epoll_fd_list_mu); - if (epoll_fd_global_list.count == 0) { - gpr_mu_unlock(&epoll_fd_list_mu); - return; - } - for (size_t i = 0; i < epoll_fd_global_list.count; i++) { - err = epoll_ctl(epoll_fd_global_list.epoll_fds[i], EPOLL_CTL_DEL, fd, NULL); - if (err < 0 && errno != ENOENT) { - gpr_log(GPR_ERROR, "epoll_ctl del for %d failed: %s", fd, - strerror(errno)); - } - } - gpr_mu_unlock(&epoll_fd_list_mu); -} - -typedef struct { - grpc_pollset *pollset; - grpc_fd *fd; - grpc_closure closure; -} delayed_add; - -typedef struct { int epoll_fd; } pollset_hdr; - -static void finally_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, - grpc_fd *fd) { - pollset_hdr *h = pollset->data.ptr; - struct epoll_event ev; - int err; - grpc_fd_watcher watcher; - - /* We pretend to be polling whilst adding an fd to keep the fd from being - closed during the add. This may result in a spurious wakeup being assigned - to this pollset whilst adding, but that should be benign. */ - GPR_ASSERT(grpc_fd_begin_poll(fd, pollset, NULL, 0, 0, &watcher) == 0); - if (watcher.fd != NULL) { - ev.events = (uint32_t)(EPOLLIN | EPOLLOUT | EPOLLET); - ev.data.ptr = fd; - err = epoll_ctl(h->epoll_fd, EPOLL_CTL_ADD, fd->fd, &ev); - if (err < 0) { - /* FDs may be added to a pollset multiple times, so EEXIST is normal. */ - if (errno != EEXIST) { - gpr_log(GPR_ERROR, "epoll_ctl add for %d failed: %s", fd->fd, - strerror(errno)); - } - } - } - grpc_fd_end_poll(exec_ctx, &watcher, 0, 0); -} - -static void perform_delayed_add(grpc_exec_ctx *exec_ctx, void *arg, - bool iomgr_status) { - delayed_add *da = arg; - - if (!grpc_fd_is_orphaned(da->fd)) { - finally_add_fd(exec_ctx, da->pollset, da->fd); - } - - gpr_mu_lock(&da->pollset->mu); - da->pollset->in_flight_cbs--; - if (da->pollset->shutting_down) { - /* We don't care about this pollset anymore. */ - if (da->pollset->in_flight_cbs == 0 && !da->pollset->called_shutdown) { - da->pollset->called_shutdown = 1; - grpc_exec_ctx_enqueue(exec_ctx, da->pollset->shutdown_done, true, NULL); - } - } - gpr_mu_unlock(&da->pollset->mu); - - GRPC_FD_UNREF(da->fd, "delayed_add"); - - gpr_free(da); -} - -static void multipoll_with_epoll_pollset_add_fd(grpc_exec_ctx *exec_ctx, - grpc_pollset *pollset, - grpc_fd *fd, - int and_unlock_pollset) { - if (and_unlock_pollset) { - gpr_mu_unlock(&pollset->mu); - finally_add_fd(exec_ctx, pollset, fd); - } else { - delayed_add *da = gpr_malloc(sizeof(*da)); - da->pollset = pollset; - da->fd = fd; - GRPC_FD_REF(fd, "delayed_add"); - grpc_closure_init(&da->closure, perform_delayed_add, da); - pollset->in_flight_cbs++; - grpc_exec_ctx_enqueue(exec_ctx, &da->closure, true, NULL); - } -} - -/* TODO(klempner): We probably want to turn this down a bit */ -#define GRPC_EPOLL_MAX_EVENTS 1000 - -static void multipoll_with_epoll_pollset_maybe_work_and_unlock( - grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker *worker, - gpr_timespec deadline, gpr_timespec now) { - struct epoll_event ep_ev[GRPC_EPOLL_MAX_EVENTS]; - int ep_rv; - int poll_rv; - pollset_hdr *h = pollset->data.ptr; - int timeout_ms; - struct pollfd pfds[2]; - - /* If you want to ignore epoll's ability to sanely handle parallel pollers, - * for a more apples-to-apples performance comparison with poll, add a - * if (pollset->counter != 0) { return 0; } - * here. - */ - - gpr_mu_unlock(&pollset->mu); - - timeout_ms = grpc_poll_deadline_to_millis_timeout(deadline, now); - - pfds[0].fd = GRPC_WAKEUP_FD_GET_READ_FD(&worker->wakeup_fd->fd); - pfds[0].events = POLLIN; - pfds[0].revents = 0; - pfds[1].fd = h->epoll_fd; - pfds[1].events = POLLIN; - pfds[1].revents = 0; - - /* TODO(vpai): Consider first doing a 0 timeout poll here to avoid - even going into the blocking annotation if possible */ - GPR_TIMER_BEGIN("poll", 0); - GRPC_SCHEDULING_START_BLOCKING_REGION; - poll_rv = grpc_poll_function(pfds, 2, timeout_ms); - GRPC_SCHEDULING_END_BLOCKING_REGION; - GPR_TIMER_END("poll", 0); - - if (poll_rv < 0) { - if (errno != EINTR) { - gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno)); - } - } else if (poll_rv == 0) { - /* do nothing */ - } else { - if (pfds[0].revents) { - grpc_wakeup_fd_consume_wakeup(&worker->wakeup_fd->fd); - } - if (pfds[1].revents) { - do { - /* The following epoll_wait never blocks; it has a timeout of 0 */ - ep_rv = epoll_wait(h->epoll_fd, ep_ev, GRPC_EPOLL_MAX_EVENTS, 0); - if (ep_rv < 0) { - if (errno != EINTR) { - gpr_log(GPR_ERROR, "epoll_wait() failed: %s", strerror(errno)); - } - } else { - int i; - for (i = 0; i < ep_rv; ++i) { - grpc_fd *fd = ep_ev[i].data.ptr; - /* TODO(klempner): We might want to consider making err and pri - * separate events */ - int cancel = ep_ev[i].events & (EPOLLERR | EPOLLHUP); - int read_ev = ep_ev[i].events & (EPOLLIN | EPOLLPRI); - int write_ev = ep_ev[i].events & EPOLLOUT; - if (fd == NULL) { - grpc_wakeup_fd_consume_wakeup(&grpc_global_wakeup_fd); - } else { - if (read_ev || cancel) { - grpc_fd_become_readable(exec_ctx, fd); - } - if (write_ev || cancel) { - grpc_fd_become_writable(exec_ctx, fd); - } - } - } - } - } while (ep_rv == GRPC_EPOLL_MAX_EVENTS); - } - } -} - -static void multipoll_with_epoll_pollset_finish_shutdown( - grpc_pollset *pollset) {} - -static void multipoll_with_epoll_pollset_destroy(grpc_pollset *pollset) { - pollset_hdr *h = pollset->data.ptr; - close(h->epoll_fd); - remove_epoll_fd_from_global_list(h->epoll_fd); - gpr_free(h); -} - -static const grpc_pollset_vtable multipoll_with_epoll_pollset = { - multipoll_with_epoll_pollset_add_fd, - multipoll_with_epoll_pollset_maybe_work_and_unlock, - multipoll_with_epoll_pollset_finish_shutdown, - multipoll_with_epoll_pollset_destroy}; - -static void epoll_become_multipoller(grpc_exec_ctx *exec_ctx, - grpc_pollset *pollset, grpc_fd **fds, - size_t nfds) { - size_t i; - pollset_hdr *h = gpr_malloc(sizeof(pollset_hdr)); - struct epoll_event ev; - int err; - - pollset->vtable = &multipoll_with_epoll_pollset; - pollset->data.ptr = h; - h->epoll_fd = epoll_create1(EPOLL_CLOEXEC); - if (h->epoll_fd < 0) { - /* TODO(klempner): Fall back to poll here, especially on ENOSYS */ - gpr_log(GPR_ERROR, "epoll_create1 failed: %s", strerror(errno)); - abort(); - } - add_epoll_fd_to_global_list(h->epoll_fd); - - ev.events = (uint32_t)(EPOLLIN | EPOLLET); - ev.data.ptr = NULL; - err = epoll_ctl(h->epoll_fd, EPOLL_CTL_ADD, - GRPC_WAKEUP_FD_GET_READ_FD(&grpc_global_wakeup_fd), &ev); - if (err < 0) { - gpr_log(GPR_ERROR, "epoll_ctl add for %d failed: %s", - GRPC_WAKEUP_FD_GET_READ_FD(&grpc_global_wakeup_fd), - strerror(errno)); - } - - for (i = 0; i < nfds; i++) { - multipoll_with_epoll_pollset_add_fd(exec_ctx, pollset, fds[i], 0); - } -} - -grpc_platform_become_multipoller_type grpc_platform_become_multipoller = - epoll_become_multipoller; - -#else /* GPR_LINUX_MULTIPOLL_WITH_EPOLL */ - -void grpc_remove_fd_from_all_epoll_sets(int fd) {} - -#endif /* GPR_LINUX_MULTIPOLL_WITH_EPOLL */ diff --git a/src/core/iomgr/pollset_multipoller_with_poll_posix.c b/src/core/iomgr/pollset_multipoller_with_poll_posix.c deleted file mode 100644 index 92d6fb7241..0000000000 --- a/src/core/iomgr/pollset_multipoller_with_poll_posix.c +++ /dev/null @@ -1,234 +0,0 @@ -/* - * - * Copyright 2015-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 - -#ifdef GPR_POSIX_SOCKET - -#include "src/core/iomgr/pollset_posix.h" - -#include -#include -#include -#include - -#include -#include -#include - -#include "src/core/iomgr/fd_posix.h" -#include "src/core/iomgr/iomgr_internal.h" -#include "src/core/iomgr/pollset_posix.h" -#include "src/core/support/block_annotate.h" - -typedef struct { - /* all polled fds */ - size_t fd_count; - size_t fd_capacity; - grpc_fd **fds; - /* fds that have been removed from the pollset explicitly */ - size_t del_count; - size_t del_capacity; - grpc_fd **dels; -} pollset_hdr; - -static void multipoll_with_poll_pollset_add_fd(grpc_exec_ctx *exec_ctx, - grpc_pollset *pollset, - grpc_fd *fd, - int and_unlock_pollset) { - size_t i; - pollset_hdr *h = pollset->data.ptr; - /* TODO(ctiller): this is O(num_fds^2); maybe switch to a hash set here */ - for (i = 0; i < h->fd_count; i++) { - if (h->fds[i] == fd) goto exit; - } - if (h->fd_count == h->fd_capacity) { - h->fd_capacity = GPR_MAX(h->fd_capacity + 8, h->fd_count * 3 / 2); - h->fds = gpr_realloc(h->fds, sizeof(grpc_fd *) * h->fd_capacity); - } - h->fds[h->fd_count++] = fd; - GRPC_FD_REF(fd, "multipoller"); -exit: - if (and_unlock_pollset) { - gpr_mu_unlock(&pollset->mu); - } -} - -static void multipoll_with_poll_pollset_maybe_work_and_unlock( - grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker *worker, - gpr_timespec deadline, gpr_timespec now) { -#define POLLOUT_CHECK (POLLOUT | POLLHUP | POLLERR) -#define POLLIN_CHECK (POLLIN | POLLHUP | POLLERR) - - int timeout; - int r; - size_t i, j, fd_count; - nfds_t pfd_count; - pollset_hdr *h; - /* TODO(ctiller): inline some elements to avoid an allocation */ - grpc_fd_watcher *watchers; - struct pollfd *pfds; - - h = pollset->data.ptr; - timeout = grpc_poll_deadline_to_millis_timeout(deadline, now); - /* TODO(ctiller): perform just one malloc here if we exceed the inline case */ - pfds = gpr_malloc(sizeof(*pfds) * (h->fd_count + 2)); - watchers = gpr_malloc(sizeof(*watchers) * (h->fd_count + 2)); - fd_count = 0; - pfd_count = 2; - pfds[0].fd = GRPC_WAKEUP_FD_GET_READ_FD(&grpc_global_wakeup_fd); - pfds[0].events = POLLIN; - pfds[0].revents = 0; - pfds[1].fd = GRPC_WAKEUP_FD_GET_READ_FD(&worker->wakeup_fd->fd); - pfds[1].events = POLLIN; - pfds[1].revents = 0; - for (i = 0; i < h->fd_count; i++) { - int remove = grpc_fd_is_orphaned(h->fds[i]); - for (j = 0; !remove && j < h->del_count; j++) { - if (h->fds[i] == h->dels[j]) remove = 1; - } - if (remove) { - GRPC_FD_UNREF(h->fds[i], "multipoller"); - } else { - h->fds[fd_count++] = h->fds[i]; - watchers[pfd_count].fd = h->fds[i]; - GRPC_FD_REF(watchers[pfd_count].fd, "multipoller_start"); - pfds[pfd_count].fd = h->fds[i]->fd; - pfds[pfd_count].revents = 0; - pfd_count++; - } - } - for (j = 0; j < h->del_count; j++) { - GRPC_FD_UNREF(h->dels[j], "multipoller_del"); - } - h->del_count = 0; - h->fd_count = fd_count; - gpr_mu_unlock(&pollset->mu); - - for (i = 2; i < pfd_count; i++) { - grpc_fd *fd = watchers[i].fd; - pfds[i].events = (short)grpc_fd_begin_poll(fd, pollset, worker, POLLIN, - POLLOUT, &watchers[i]); - GRPC_FD_UNREF(fd, "multipoller_start"); - } - - /* TODO(vpai): Consider first doing a 0 timeout poll here to avoid - even going into the blocking annotation if possible */ - GRPC_SCHEDULING_START_BLOCKING_REGION; - r = grpc_poll_function(pfds, pfd_count, timeout); - GRPC_SCHEDULING_END_BLOCKING_REGION; - - if (r < 0) { - if (errno != EINTR) { - gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno)); - } - for (i = 2; i < pfd_count; i++) { - grpc_fd_end_poll(exec_ctx, &watchers[i], 0, 0); - } - } else if (r == 0) { - for (i = 2; i < pfd_count; i++) { - grpc_fd_end_poll(exec_ctx, &watchers[i], 0, 0); - } - } else { - if (pfds[0].revents & POLLIN_CHECK) { - grpc_wakeup_fd_consume_wakeup(&grpc_global_wakeup_fd); - } - if (pfds[1].revents & POLLIN_CHECK) { - grpc_wakeup_fd_consume_wakeup(&worker->wakeup_fd->fd); - } - for (i = 2; i < pfd_count; i++) { - if (watchers[i].fd == NULL) { - grpc_fd_end_poll(exec_ctx, &watchers[i], 0, 0); - continue; - } - grpc_fd_end_poll(exec_ctx, &watchers[i], pfds[i].revents & POLLIN_CHECK, - pfds[i].revents & POLLOUT_CHECK); - } - } - - gpr_free(pfds); - gpr_free(watchers); -} - -static void multipoll_with_poll_pollset_finish_shutdown(grpc_pollset *pollset) { - size_t i; - pollset_hdr *h = pollset->data.ptr; - for (i = 0; i < h->fd_count; i++) { - GRPC_FD_UNREF(h->fds[i], "multipoller"); - } - for (i = 0; i < h->del_count; i++) { - GRPC_FD_UNREF(h->dels[i], "multipoller_del"); - } - h->fd_count = 0; - h->del_count = 0; -} - -static void multipoll_with_poll_pollset_destroy(grpc_pollset *pollset) { - pollset_hdr *h = pollset->data.ptr; - multipoll_with_poll_pollset_finish_shutdown(pollset); - gpr_free(h->fds); - gpr_free(h->dels); - gpr_free(h); -} - -static const grpc_pollset_vtable multipoll_with_poll_pollset = { - multipoll_with_poll_pollset_add_fd, - multipoll_with_poll_pollset_maybe_work_and_unlock, - multipoll_with_poll_pollset_finish_shutdown, - multipoll_with_poll_pollset_destroy}; - -void grpc_poll_become_multipoller(grpc_exec_ctx *exec_ctx, - grpc_pollset *pollset, grpc_fd **fds, - size_t nfds) { - size_t i; - pollset_hdr *h = gpr_malloc(sizeof(pollset_hdr)); - pollset->vtable = &multipoll_with_poll_pollset; - pollset->data.ptr = h; - h->fd_count = nfds; - h->fd_capacity = nfds; - h->fds = gpr_malloc(nfds * sizeof(grpc_fd *)); - h->del_count = 0; - h->del_capacity = 0; - h->dels = NULL; - for (i = 0; i < nfds; i++) { - h->fds[i] = fds[i]; - GRPC_FD_REF(fds[i], "multipoller"); - } -} - -#endif /* GPR_POSIX_SOCKET */ - -#ifdef GPR_POSIX_MULTIPOLL_WITH_POLL -grpc_platform_become_multipoller_type grpc_platform_become_multipoller = - grpc_poll_become_multipoller; -#endif diff --git a/src/core/iomgr/pollset_posix.c b/src/core/iomgr/pollset_posix.c deleted file mode 100644 index e895a77884..0000000000 --- a/src/core/iomgr/pollset_posix.c +++ /dev/null @@ -1,633 +0,0 @@ -/* - * - * Copyright 2015-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 - -#ifdef GPR_POSIX_SOCKET - -#include "src/core/iomgr/pollset_posix.h" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include "src/core/iomgr/fd_posix.h" -#include "src/core/iomgr/iomgr_internal.h" -#include "src/core/iomgr/socket_utils_posix.h" -#include "src/core/profiling/timers.h" -#include "src/core/support/block_annotate.h" - -GPR_TLS_DECL(g_current_thread_poller); -GPR_TLS_DECL(g_current_thread_worker); - -/** Default poll() function - a pointer so that it can be overridden by some - * tests */ -grpc_poll_function_type grpc_poll_function = poll; - -/** The alarm system needs to be able to wakeup 'some poller' sometimes - * (specifically when a new alarm needs to be triggered earlier than the next - * alarm 'epoch'). - * This wakeup_fd gives us something to alert on when such a case occurs. */ -grpc_wakeup_fd grpc_global_wakeup_fd; - -static void remove_worker(grpc_pollset *p, grpc_pollset_worker *worker) { - worker->prev->next = worker->next; - worker->next->prev = worker->prev; -} - -int grpc_pollset_has_workers(grpc_pollset *p) { - return p->root_worker.next != &p->root_worker; -} - -static grpc_pollset_worker *pop_front_worker(grpc_pollset *p) { - if (grpc_pollset_has_workers(p)) { - grpc_pollset_worker *w = p->root_worker.next; - remove_worker(p, w); - return w; - } else { - return NULL; - } -} - -static void push_back_worker(grpc_pollset *p, grpc_pollset_worker *worker) { - worker->next = &p->root_worker; - worker->prev = worker->next->prev; - worker->prev->next = worker->next->prev = worker; -} - -static void push_front_worker(grpc_pollset *p, grpc_pollset_worker *worker) { - worker->prev = &p->root_worker; - worker->next = worker->prev->next; - worker->prev->next = worker->next->prev = worker; -} - -size_t grpc_pollset_size(void) { return sizeof(grpc_pollset); } - -void grpc_pollset_kick_ext(grpc_pollset *p, - grpc_pollset_worker *specific_worker, - uint32_t flags) { - GPR_TIMER_BEGIN("grpc_pollset_kick_ext", 0); - - /* pollset->mu already held */ - if (specific_worker != NULL) { - if (specific_worker == GRPC_POLLSET_KICK_BROADCAST) { - GPR_TIMER_BEGIN("grpc_pollset_kick_ext.broadcast", 0); - GPR_ASSERT((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) == 0); - for (specific_worker = p->root_worker.next; - specific_worker != &p->root_worker; - specific_worker = specific_worker->next) { - grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd); - } - p->kicked_without_pollers = 1; - GPR_TIMER_END("grpc_pollset_kick_ext.broadcast", 0); - } else if (gpr_tls_get(&g_current_thread_worker) != - (intptr_t)specific_worker) { - GPR_TIMER_MARK("different_thread_worker", 0); - if ((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) != 0) { - specific_worker->reevaluate_polling_on_wakeup = 1; - } - specific_worker->kicked_specifically = 1; - grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd); - } else if ((flags & GRPC_POLLSET_CAN_KICK_SELF) != 0) { - GPR_TIMER_MARK("kick_yoself", 0); - if ((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) != 0) { - specific_worker->reevaluate_polling_on_wakeup = 1; - } - specific_worker->kicked_specifically = 1; - grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd); - } - } else if (gpr_tls_get(&g_current_thread_poller) != (intptr_t)p) { - GPR_ASSERT((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) == 0); - GPR_TIMER_MARK("kick_anonymous", 0); - specific_worker = pop_front_worker(p); - if (specific_worker != NULL) { - if (gpr_tls_get(&g_current_thread_worker) == (intptr_t)specific_worker) { - GPR_TIMER_MARK("kick_anonymous_not_self", 0); - push_back_worker(p, specific_worker); - specific_worker = pop_front_worker(p); - if ((flags & GRPC_POLLSET_CAN_KICK_SELF) == 0 && - gpr_tls_get(&g_current_thread_worker) == - (intptr_t)specific_worker) { - push_back_worker(p, specific_worker); - specific_worker = NULL; - } - } - if (specific_worker != NULL) { - GPR_TIMER_MARK("finally_kick", 0); - push_back_worker(p, specific_worker); - grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd); - } - } else { - GPR_TIMER_MARK("kicked_no_pollers", 0); - p->kicked_without_pollers = 1; - } - } - - GPR_TIMER_END("grpc_pollset_kick_ext", 0); -} - -void grpc_pollset_kick(grpc_pollset *p, grpc_pollset_worker *specific_worker) { - grpc_pollset_kick_ext(p, specific_worker, 0); -} - -/* global state management */ - -void grpc_pollset_global_init(void) { - gpr_tls_init(&g_current_thread_poller); - gpr_tls_init(&g_current_thread_worker); - grpc_wakeup_fd_global_init(); - grpc_wakeup_fd_init(&grpc_global_wakeup_fd); -} - -void grpc_pollset_global_shutdown(void) { - grpc_wakeup_fd_destroy(&grpc_global_wakeup_fd); - gpr_tls_destroy(&g_current_thread_poller); - gpr_tls_destroy(&g_current_thread_worker); - grpc_wakeup_fd_global_destroy(); -} - -void grpc_kick_poller(void) { grpc_wakeup_fd_wakeup(&grpc_global_wakeup_fd); } - -/* main interface */ - -static void become_basic_pollset(grpc_pollset *pollset, grpc_fd *fd_or_null); - -void grpc_pollset_init(grpc_pollset *pollset, gpr_mu **mu) { - gpr_mu_init(&pollset->mu); - *mu = &pollset->mu; - pollset->root_worker.next = pollset->root_worker.prev = &pollset->root_worker; - pollset->in_flight_cbs = 0; - pollset->shutting_down = 0; - pollset->called_shutdown = 0; - pollset->kicked_without_pollers = 0; - pollset->idle_jobs.head = pollset->idle_jobs.tail = NULL; - pollset->local_wakeup_cache = NULL; - pollset->kicked_without_pollers = 0; - become_basic_pollset(pollset, NULL); -} - -void grpc_pollset_destroy(grpc_pollset *pollset) { - GPR_ASSERT(pollset->in_flight_cbs == 0); - GPR_ASSERT(!grpc_pollset_has_workers(pollset)); - GPR_ASSERT(pollset->idle_jobs.head == pollset->idle_jobs.tail); - pollset->vtable->destroy(pollset); - while (pollset->local_wakeup_cache) { - grpc_cached_wakeup_fd *next = pollset->local_wakeup_cache->next; - grpc_wakeup_fd_destroy(&pollset->local_wakeup_cache->fd); - gpr_free(pollset->local_wakeup_cache); - pollset->local_wakeup_cache = next; - } -} - -void grpc_pollset_reset(grpc_pollset *pollset) { - GPR_ASSERT(pollset->shutting_down); - GPR_ASSERT(pollset->in_flight_cbs == 0); - GPR_ASSERT(!grpc_pollset_has_workers(pollset)); - GPR_ASSERT(pollset->idle_jobs.head == pollset->idle_jobs.tail); - pollset->vtable->destroy(pollset); - pollset->shutting_down = 0; - pollset->called_shutdown = 0; - pollset->kicked_without_pollers = 0; - become_basic_pollset(pollset, NULL); -} - -void grpc_pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, - grpc_fd *fd) { - gpr_mu_lock(&pollset->mu); - pollset->vtable->add_fd(exec_ctx, pollset, fd, 1); -/* the following (enabled only in debug) will reacquire and then release - our lock - meaning that if the unlocking flag passed to add_fd above is - not respected, the code will deadlock (in a way that we have a chance of - debugging) */ -#ifndef NDEBUG - gpr_mu_lock(&pollset->mu); - gpr_mu_unlock(&pollset->mu); -#endif -} - -static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) { - GPR_ASSERT(grpc_closure_list_empty(pollset->idle_jobs)); - pollset->vtable->finish_shutdown(pollset); - grpc_exec_ctx_enqueue(exec_ctx, pollset->shutdown_done, true, NULL); -} - -void grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, - grpc_pollset_worker **worker_hdl, gpr_timespec now, - gpr_timespec deadline) { - grpc_pollset_worker worker; - *worker_hdl = &worker; - - /* pollset->mu already held */ - int added_worker = 0; - int locked = 1; - int queued_work = 0; - int keep_polling = 0; - GPR_TIMER_BEGIN("grpc_pollset_work", 0); - /* this must happen before we (potentially) drop pollset->mu */ - worker.next = worker.prev = NULL; - worker.reevaluate_polling_on_wakeup = 0; - if (pollset->local_wakeup_cache != NULL) { - worker.wakeup_fd = pollset->local_wakeup_cache; - pollset->local_wakeup_cache = worker.wakeup_fd->next; - } else { - worker.wakeup_fd = gpr_malloc(sizeof(*worker.wakeup_fd)); - grpc_wakeup_fd_init(&worker.wakeup_fd->fd); - } - worker.kicked_specifically = 0; - /* If there's work waiting for the pollset to be idle, and the - pollset is idle, then do that work */ - if (!grpc_pollset_has_workers(pollset) && - !grpc_closure_list_empty(pollset->idle_jobs)) { - GPR_TIMER_MARK("grpc_pollset_work.idle_jobs", 0); - grpc_exec_ctx_enqueue_list(exec_ctx, &pollset->idle_jobs, NULL); - goto done; - } - /* If we're shutting down then we don't execute any extended work */ - if (pollset->shutting_down) { - GPR_TIMER_MARK("grpc_pollset_work.shutting_down", 0); - goto done; - } - /* Give do_promote priority so we don't starve it out */ - if (pollset->in_flight_cbs) { - GPR_TIMER_MARK("grpc_pollset_work.in_flight_cbs", 0); - gpr_mu_unlock(&pollset->mu); - locked = 0; - goto done; - } - /* Start polling, and keep doing so while we're being asked to - re-evaluate our pollers (this allows poll() based pollers to - ensure they don't miss wakeups) */ - keep_polling = 1; - while (keep_polling) { - keep_polling = 0; - if (!pollset->kicked_without_pollers) { - if (!added_worker) { - push_front_worker(pollset, &worker); - added_worker = 1; - gpr_tls_set(&g_current_thread_worker, (intptr_t)&worker); - } - gpr_tls_set(&g_current_thread_poller, (intptr_t)pollset); - GPR_TIMER_BEGIN("maybe_work_and_unlock", 0); - pollset->vtable->maybe_work_and_unlock(exec_ctx, pollset, &worker, - deadline, now); - GPR_TIMER_END("maybe_work_and_unlock", 0); - locked = 0; - gpr_tls_set(&g_current_thread_poller, 0); - } else { - GPR_TIMER_MARK("grpc_pollset_work.kicked_without_pollers", 0); - pollset->kicked_without_pollers = 0; - } - /* Finished execution - start cleaning up. - Note that we may arrive here from outside the enclosing while() loop. - In that case we won't loop though as we haven't added worker to the - worker list, which means nobody could ask us to re-evaluate polling). */ - done: - if (!locked) { - queued_work |= grpc_exec_ctx_flush(exec_ctx); - gpr_mu_lock(&pollset->mu); - locked = 1; - } - /* If we're forced to re-evaluate polling (via grpc_pollset_kick with - GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) then we land here and force - a loop */ - if (worker.reevaluate_polling_on_wakeup) { - worker.reevaluate_polling_on_wakeup = 0; - pollset->kicked_without_pollers = 0; - if (queued_work || worker.kicked_specifically) { - /* If there's queued work on the list, then set the deadline to be - immediate so we get back out of the polling loop quickly */ - deadline = gpr_inf_past(GPR_CLOCK_MONOTONIC); - } - keep_polling = 1; - } - } - if (added_worker) { - remove_worker(pollset, &worker); - gpr_tls_set(&g_current_thread_worker, 0); - } - /* release wakeup fd to the local pool */ - worker.wakeup_fd->next = pollset->local_wakeup_cache; - pollset->local_wakeup_cache = worker.wakeup_fd; - /* check shutdown conditions */ - if (pollset->shutting_down) { - if (grpc_pollset_has_workers(pollset)) { - grpc_pollset_kick(pollset, NULL); - } else if (!pollset->called_shutdown && pollset->in_flight_cbs == 0) { - pollset->called_shutdown = 1; - gpr_mu_unlock(&pollset->mu); - finish_shutdown(exec_ctx, pollset); - grpc_exec_ctx_flush(exec_ctx); - /* Continuing to access pollset here is safe -- it is the caller's - * responsibility to not destroy when it has outstanding calls to - * grpc_pollset_work. - * TODO(dklempner): Can we refactor the shutdown logic to avoid this? */ - gpr_mu_lock(&pollset->mu); - } else if (!grpc_closure_list_empty(pollset->idle_jobs)) { - grpc_exec_ctx_enqueue_list(exec_ctx, &pollset->idle_jobs, NULL); - gpr_mu_unlock(&pollset->mu); - grpc_exec_ctx_flush(exec_ctx); - gpr_mu_lock(&pollset->mu); - } - } - *worker_hdl = NULL; - GPR_TIMER_END("grpc_pollset_work", 0); -} - -void grpc_pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, - grpc_closure *closure) { - GPR_ASSERT(!pollset->shutting_down); - pollset->shutting_down = 1; - pollset->shutdown_done = closure; - grpc_pollset_kick(pollset, GRPC_POLLSET_KICK_BROADCAST); - if (!grpc_pollset_has_workers(pollset)) { - grpc_exec_ctx_enqueue_list(exec_ctx, &pollset->idle_jobs, NULL); - } - if (!pollset->called_shutdown && pollset->in_flight_cbs == 0 && - !grpc_pollset_has_workers(pollset)) { - pollset->called_shutdown = 1; - finish_shutdown(exec_ctx, pollset); - } -} - -int grpc_poll_deadline_to_millis_timeout(gpr_timespec deadline, - gpr_timespec now) { - gpr_timespec timeout; - static const int64_t max_spin_polling_us = 10; - if (gpr_time_cmp(deadline, gpr_inf_future(deadline.clock_type)) == 0) { - return -1; - } - if (gpr_time_cmp(deadline, gpr_time_add(now, gpr_time_from_micros( - max_spin_polling_us, - GPR_TIMESPAN))) <= 0) { - return 0; - } - timeout = gpr_time_sub(deadline, now); - return gpr_time_to_millis(gpr_time_add( - timeout, gpr_time_from_nanos(GPR_NS_PER_MS - 1, GPR_TIMESPAN))); -} - -/* - * basic_pollset - a vtable that provides polling for zero or one file - * descriptor via poll() - */ - -typedef struct grpc_unary_promote_args { - const grpc_pollset_vtable *original_vtable; - grpc_pollset *pollset; - grpc_fd *fd; - grpc_closure promotion_closure; -} grpc_unary_promote_args; - -static void basic_do_promote(grpc_exec_ctx *exec_ctx, void *args, - bool success) { - grpc_unary_promote_args *up_args = args; - const grpc_pollset_vtable *original_vtable = up_args->original_vtable; - grpc_pollset *pollset = up_args->pollset; - grpc_fd *fd = up_args->fd; - - /* - * This is quite tricky. There are a number of cases to keep in mind here: - * 1. fd may have been orphaned - * 2. The pollset may no longer be a unary poller (and we can't let case #1 - * leak to other pollset types!) - * 3. pollset's fd (which may have changed) may have been orphaned - * 4. The pollset may be shutting down. - */ - - gpr_mu_lock(&pollset->mu); - /* First we need to ensure that nobody is polling concurrently */ - GPR_ASSERT(!grpc_pollset_has_workers(pollset)); - - gpr_free(up_args); - /* At this point the pollset may no longer be a unary poller. In that case - * we should just call the right add function and be done. */ - /* TODO(klempner): If we're not careful this could cause infinite recursion. - * That's not a problem for now because empty_pollset has a trivial poller - * and we don't have any mechanism to unbecome multipoller. */ - pollset->in_flight_cbs--; - if (pollset->shutting_down) { - /* We don't care about this pollset anymore. */ - if (pollset->in_flight_cbs == 0 && !pollset->called_shutdown) { - pollset->called_shutdown = 1; - finish_shutdown(exec_ctx, pollset); - } - } else if (grpc_fd_is_orphaned(fd)) { - /* Don't try to add it to anything, we'll drop our ref on it below */ - } else if (pollset->vtable != original_vtable) { - pollset->vtable->add_fd(exec_ctx, pollset, fd, 0); - } else if (fd != pollset->data.ptr) { - grpc_fd *fds[2]; - fds[0] = pollset->data.ptr; - fds[1] = fd; - - if (fds[0] && !grpc_fd_is_orphaned(fds[0])) { - grpc_platform_become_multipoller(exec_ctx, pollset, fds, - GPR_ARRAY_SIZE(fds)); - GRPC_FD_UNREF(fds[0], "basicpoll"); - } else { - /* old fd is orphaned and we haven't cleaned it up until now, so remain a - * unary poller */ - /* Note that it is possible that fds[1] is also orphaned at this point. - * That's okay, we'll correct it at the next add or poll. */ - if (fds[0]) GRPC_FD_UNREF(fds[0], "basicpoll"); - pollset->data.ptr = fd; - GRPC_FD_REF(fd, "basicpoll"); - } - } - - gpr_mu_unlock(&pollset->mu); - - /* Matching ref in basic_pollset_add_fd */ - GRPC_FD_UNREF(fd, "basicpoll_add"); -} - -static void basic_pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, - grpc_fd *fd, int and_unlock_pollset) { - grpc_unary_promote_args *up_args; - GPR_ASSERT(fd); - if (fd == pollset->data.ptr) goto exit; - - if (!grpc_pollset_has_workers(pollset)) { - /* Fast path -- no in flight cbs */ - /* TODO(klempner): Comment this out and fix any test failures or establish - * they are due to timing issues */ - grpc_fd *fds[2]; - fds[0] = pollset->data.ptr; - fds[1] = fd; - - if (fds[0] == NULL) { - pollset->data.ptr = fd; - GRPC_FD_REF(fd, "basicpoll"); - } else if (!grpc_fd_is_orphaned(fds[0])) { - grpc_platform_become_multipoller(exec_ctx, pollset, fds, - GPR_ARRAY_SIZE(fds)); - GRPC_FD_UNREF(fds[0], "basicpoll"); - } else { - /* old fd is orphaned and we haven't cleaned it up until now, so remain a - * unary poller */ - GRPC_FD_UNREF(fds[0], "basicpoll"); - pollset->data.ptr = fd; - GRPC_FD_REF(fd, "basicpoll"); - } - goto exit; - } - - /* Now we need to promote. This needs to happen when we're not polling. Since - * this may be called from poll, the wait needs to happen asynchronously. */ - GRPC_FD_REF(fd, "basicpoll_add"); - pollset->in_flight_cbs++; - up_args = gpr_malloc(sizeof(*up_args)); - up_args->fd = fd; - up_args->original_vtable = pollset->vtable; - up_args->pollset = pollset; - up_args->promotion_closure.cb = basic_do_promote; - up_args->promotion_closure.cb_arg = up_args; - - grpc_closure_list_add(&pollset->idle_jobs, &up_args->promotion_closure, 1); - grpc_pollset_kick(pollset, GRPC_POLLSET_KICK_BROADCAST); - -exit: - if (and_unlock_pollset) { - gpr_mu_unlock(&pollset->mu); - } -} - -static void basic_pollset_maybe_work_and_unlock(grpc_exec_ctx *exec_ctx, - grpc_pollset *pollset, - grpc_pollset_worker *worker, - gpr_timespec deadline, - gpr_timespec now) { -#define POLLOUT_CHECK (POLLOUT | POLLHUP | POLLERR) -#define POLLIN_CHECK (POLLIN | POLLHUP | POLLERR) - - struct pollfd pfd[3]; - grpc_fd *fd; - grpc_fd_watcher fd_watcher; - int timeout; - int r; - nfds_t nfds; - - fd = pollset->data.ptr; - if (fd && grpc_fd_is_orphaned(fd)) { - GRPC_FD_UNREF(fd, "basicpoll"); - fd = pollset->data.ptr = NULL; - } - timeout = grpc_poll_deadline_to_millis_timeout(deadline, now); - pfd[0].fd = GRPC_WAKEUP_FD_GET_READ_FD(&grpc_global_wakeup_fd); - pfd[0].events = POLLIN; - pfd[0].revents = 0; - pfd[1].fd = GRPC_WAKEUP_FD_GET_READ_FD(&worker->wakeup_fd->fd); - pfd[1].events = POLLIN; - pfd[1].revents = 0; - nfds = 2; - if (fd) { - pfd[2].fd = fd->fd; - pfd[2].revents = 0; - GRPC_FD_REF(fd, "basicpoll_begin"); - gpr_mu_unlock(&pollset->mu); - pfd[2].events = (short)grpc_fd_begin_poll(fd, pollset, worker, POLLIN, - POLLOUT, &fd_watcher); - if (pfd[2].events != 0) { - nfds++; - } - } else { - gpr_mu_unlock(&pollset->mu); - } - - /* TODO(vpai): Consider first doing a 0 timeout poll here to avoid - even going into the blocking annotation if possible */ - /* poll fd count (argument 2) is shortened by one if we have no events - to poll on - such that it only includes the kicker */ - GPR_TIMER_BEGIN("poll", 0); - GRPC_SCHEDULING_START_BLOCKING_REGION; - r = grpc_poll_function(pfd, nfds, timeout); - GRPC_SCHEDULING_END_BLOCKING_REGION; - GPR_TIMER_END("poll", 0); - - if (r < 0) { - if (errno != EINTR) { - gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno)); - } - if (fd) { - grpc_fd_end_poll(exec_ctx, &fd_watcher, 0, 0); - } - } else if (r == 0) { - if (fd) { - grpc_fd_end_poll(exec_ctx, &fd_watcher, 0, 0); - } - } else { - if (pfd[0].revents & POLLIN_CHECK) { - grpc_wakeup_fd_consume_wakeup(&grpc_global_wakeup_fd); - } - if (pfd[1].revents & POLLIN_CHECK) { - grpc_wakeup_fd_consume_wakeup(&worker->wakeup_fd->fd); - } - if (nfds > 2) { - grpc_fd_end_poll(exec_ctx, &fd_watcher, pfd[2].revents & POLLIN_CHECK, - pfd[2].revents & POLLOUT_CHECK); - } else if (fd) { - grpc_fd_end_poll(exec_ctx, &fd_watcher, 0, 0); - } - } - - if (fd) { - GRPC_FD_UNREF(fd, "basicpoll_begin"); - } -} - -static void basic_pollset_destroy(grpc_pollset *pollset) { - if (pollset->data.ptr != NULL) { - GRPC_FD_UNREF(pollset->data.ptr, "basicpoll"); - pollset->data.ptr = NULL; - } -} - -static const grpc_pollset_vtable basic_pollset = { - basic_pollset_add_fd, basic_pollset_maybe_work_and_unlock, - basic_pollset_destroy, basic_pollset_destroy}; - -static void become_basic_pollset(grpc_pollset *pollset, grpc_fd *fd_or_null) { - pollset->vtable = &basic_pollset; - pollset->data.ptr = fd_or_null; - if (fd_or_null != NULL) { - GRPC_FD_REF(fd_or_null, "basicpoll"); - } -} - -#endif /* GPR_POSIX_POLLSET */ diff --git a/src/core/iomgr/pollset_posix.h b/src/core/iomgr/pollset_posix.h deleted file mode 100644 index e0cfc44395..0000000000 --- a/src/core/iomgr/pollset_posix.h +++ /dev/null @@ -1,153 +0,0 @@ -/* - * - * Copyright 2015-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_IOMGR_POLLSET_POSIX_H -#define GRPC_CORE_IOMGR_POLLSET_POSIX_H - -#include - -#include - -#include "src/core/iomgr/exec_ctx.h" -#include "src/core/iomgr/iomgr.h" -#include "src/core/iomgr/pollset.h" -#include "src/core/iomgr/wakeup_fd_posix.h" - -typedef struct grpc_pollset_vtable grpc_pollset_vtable; - -/* forward declare only in this file to avoid leaking impl details via - pollset.h; real users of grpc_fd should always include 'fd_posix.h' and not - use the struct tag */ -struct grpc_fd; - -typedef struct grpc_cached_wakeup_fd { - grpc_wakeup_fd fd; - struct grpc_cached_wakeup_fd *next; -} grpc_cached_wakeup_fd; - -struct grpc_pollset_worker { - grpc_cached_wakeup_fd *wakeup_fd; - int reevaluate_polling_on_wakeup; - int kicked_specifically; - struct grpc_pollset_worker *next; - struct grpc_pollset_worker *prev; -}; - -struct grpc_pollset { - /* pollsets under posix can mutate representation as fds are added and - removed. - For example, we may choose a poll() based implementation on linux for - few fds, and an epoll() based implementation for many fds */ - const grpc_pollset_vtable *vtable; - gpr_mu mu; - grpc_pollset_worker root_worker; - int in_flight_cbs; - int shutting_down; - int called_shutdown; - int kicked_without_pollers; - grpc_closure *shutdown_done; - grpc_closure_list idle_jobs; - union { - int fd; - void *ptr; - } data; - /* Local cache of eventfds for workers */ - grpc_cached_wakeup_fd *local_wakeup_cache; -}; - -struct grpc_pollset_vtable { - void (*add_fd)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, - struct grpc_fd *fd, int and_unlock_pollset); - void (*maybe_work_and_unlock)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, - grpc_pollset_worker *worker, - gpr_timespec deadline, gpr_timespec now); - void (*finish_shutdown)(grpc_pollset *pollset); - void (*destroy)(grpc_pollset *pollset); -}; - -/* Add an fd to a pollset */ -void grpc_pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, - struct grpc_fd *fd); - -/* Returns the fd to listen on for kicks */ -int grpc_kick_read_fd(grpc_pollset *p); -/* Call after polling has been kicked to leave the kicked state */ -void grpc_kick_drain(grpc_pollset *p); - -/* Convert a timespec to milliseconds: - - very small or negative poll times are clamped to zero to do a - non-blocking poll (which becomes spin polling) - - other small values are rounded up to one millisecond - - longer than a millisecond polls are rounded up to the next nearest - millisecond to avoid spinning - - infinite timeouts are converted to -1 */ -int grpc_poll_deadline_to_millis_timeout(gpr_timespec deadline, - gpr_timespec now); - -/* Allow kick to wakeup the currently polling worker */ -#define GRPC_POLLSET_CAN_KICK_SELF 1 -/* Force the wakee to repoll when awoken */ -#define GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP 2 -/* As per grpc_pollset_kick, with an extended set of flags (defined above) - -- mostly for fd_posix's use. */ -void grpc_pollset_kick_ext(grpc_pollset *p, - grpc_pollset_worker *specific_worker, - uint32_t flags); - -/* turn a pollset into a multipoller: platform specific */ -typedef void (*grpc_platform_become_multipoller_type)(grpc_exec_ctx *exec_ctx, - grpc_pollset *pollset, - struct grpc_fd **fds, - size_t fd_count); -extern grpc_platform_become_multipoller_type grpc_platform_become_multipoller; - -void grpc_poll_become_multipoller(grpc_exec_ctx *exec_ctx, - grpc_pollset *pollset, struct grpc_fd **fds, - size_t fd_count); - -/* Return 1 if the pollset has active threads in grpc_pollset_work (pollset must - * be locked) */ -int grpc_pollset_has_workers(grpc_pollset *pollset); - -void grpc_remove_fd_from_all_epoll_sets(int fd); - -/* override to allow tests to hook poll() usage */ -/* NOTE: Any changes to grpc_poll_function must take place when the gRPC - is certainly not doing any polling anywhere. - Otherwise, there might be a race between changing the variable and actually - doing a polling operation */ -typedef int (*grpc_poll_function_type)(struct pollfd *, nfds_t, int); -extern grpc_poll_function_type grpc_poll_function; -extern grpc_wakeup_fd grpc_global_wakeup_fd; - -#endif /* GRPC_CORE_IOMGR_POLLSET_POSIX_H */ diff --git a/src/core/iomgr/pollset_set.h b/src/core/iomgr/pollset_set.h deleted file mode 100644 index 204c625933..0000000000 --- a/src/core/iomgr/pollset_set.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * - * Copyright 2015-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_IOMGR_POLLSET_SET_H -#define GRPC_CORE_IOMGR_POLLSET_SET_H - -#include "src/core/iomgr/pollset.h" - -/* A grpc_pollset_set is a set of pollsets that are interested in an - action. Adding a pollset to a pollset_set automatically adds any - fd's (etc) that have been registered with the set_set to that pollset. - Registering fd's automatically adds them to all current pollsets. */ - -typedef struct grpc_pollset_set grpc_pollset_set; - -grpc_pollset_set *grpc_pollset_set_create(void); -void grpc_pollset_set_destroy(grpc_pollset_set *pollset_set); -void grpc_pollset_set_add_pollset(grpc_exec_ctx *exec_ctx, - grpc_pollset_set *pollset_set, - grpc_pollset *pollset); -void grpc_pollset_set_del_pollset(grpc_exec_ctx *exec_ctx, - grpc_pollset_set *pollset_set, - grpc_pollset *pollset); -void grpc_pollset_set_add_pollset_set(grpc_exec_ctx *exec_ctx, - grpc_pollset_set *bag, - grpc_pollset_set *item); -void grpc_pollset_set_del_pollset_set(grpc_exec_ctx *exec_ctx, - grpc_pollset_set *bag, - grpc_pollset_set *item); - -#endif /* GRPC_CORE_IOMGR_POLLSET_SET_H */ diff --git a/src/core/iomgr/pollset_set_posix.c b/src/core/iomgr/pollset_set_posix.c deleted file mode 100644 index 9dc9aff4a8..0000000000 --- a/src/core/iomgr/pollset_set_posix.c +++ /dev/null @@ -1,202 +0,0 @@ -/* - * - * Copyright 2015-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 - -#ifdef GPR_POSIX_SOCKET - -#include -#include - -#include -#include - -#include "src/core/iomgr/pollset_posix.h" -#include "src/core/iomgr/pollset_set_posix.h" - -struct grpc_pollset_set { - gpr_mu mu; - - size_t pollset_count; - size_t pollset_capacity; - grpc_pollset **pollsets; - - size_t pollset_set_count; - size_t pollset_set_capacity; - struct grpc_pollset_set **pollset_sets; - - size_t fd_count; - size_t fd_capacity; - grpc_fd **fds; -}; - -grpc_pollset_set *grpc_pollset_set_create(void) { - grpc_pollset_set *pollset_set = gpr_malloc(sizeof(*pollset_set)); - memset(pollset_set, 0, sizeof(*pollset_set)); - gpr_mu_init(&pollset_set->mu); - return pollset_set; -} - -void grpc_pollset_set_destroy(grpc_pollset_set *pollset_set) { - size_t i; - gpr_mu_destroy(&pollset_set->mu); - for (i = 0; i < pollset_set->fd_count; i++) { - GRPC_FD_UNREF(pollset_set->fds[i], "pollset_set"); - } - gpr_free(pollset_set->pollsets); - gpr_free(pollset_set->pollset_sets); - gpr_free(pollset_set->fds); - gpr_free(pollset_set); -} - -void grpc_pollset_set_add_pollset(grpc_exec_ctx *exec_ctx, - grpc_pollset_set *pollset_set, - grpc_pollset *pollset) { - size_t i, j; - gpr_mu_lock(&pollset_set->mu); - if (pollset_set->pollset_count == pollset_set->pollset_capacity) { - pollset_set->pollset_capacity = - GPR_MAX(8, 2 * pollset_set->pollset_capacity); - pollset_set->pollsets = - gpr_realloc(pollset_set->pollsets, pollset_set->pollset_capacity * - sizeof(*pollset_set->pollsets)); - } - pollset_set->pollsets[pollset_set->pollset_count++] = pollset; - for (i = 0, j = 0; i < pollset_set->fd_count; i++) { - if (grpc_fd_is_orphaned(pollset_set->fds[i])) { - GRPC_FD_UNREF(pollset_set->fds[i], "pollset_set"); - } else { - grpc_pollset_add_fd(exec_ctx, pollset, pollset_set->fds[i]); - pollset_set->fds[j++] = pollset_set->fds[i]; - } - } - pollset_set->fd_count = j; - gpr_mu_unlock(&pollset_set->mu); -} - -void grpc_pollset_set_del_pollset(grpc_exec_ctx *exec_ctx, - grpc_pollset_set *pollset_set, - grpc_pollset *pollset) { - size_t i; - gpr_mu_lock(&pollset_set->mu); - for (i = 0; i < pollset_set->pollset_count; i++) { - if (pollset_set->pollsets[i] == pollset) { - pollset_set->pollset_count--; - GPR_SWAP(grpc_pollset *, pollset_set->pollsets[i], - pollset_set->pollsets[pollset_set->pollset_count]); - break; - } - } - gpr_mu_unlock(&pollset_set->mu); -} - -void grpc_pollset_set_add_pollset_set(grpc_exec_ctx *exec_ctx, - grpc_pollset_set *bag, - grpc_pollset_set *item) { - size_t i, j; - gpr_mu_lock(&bag->mu); - if (bag->pollset_set_count == bag->pollset_set_capacity) { - bag->pollset_set_capacity = GPR_MAX(8, 2 * bag->pollset_set_capacity); - bag->pollset_sets = - gpr_realloc(bag->pollset_sets, - bag->pollset_set_capacity * sizeof(*bag->pollset_sets)); - } - bag->pollset_sets[bag->pollset_set_count++] = item; - for (i = 0, j = 0; i < bag->fd_count; i++) { - if (grpc_fd_is_orphaned(bag->fds[i])) { - GRPC_FD_UNREF(bag->fds[i], "pollset_set"); - } else { - grpc_pollset_set_add_fd(exec_ctx, item, bag->fds[i]); - bag->fds[j++] = bag->fds[i]; - } - } - bag->fd_count = j; - gpr_mu_unlock(&bag->mu); -} - -void grpc_pollset_set_del_pollset_set(grpc_exec_ctx *exec_ctx, - grpc_pollset_set *bag, - grpc_pollset_set *item) { - size_t i; - gpr_mu_lock(&bag->mu); - for (i = 0; i < bag->pollset_set_count; i++) { - if (bag->pollset_sets[i] == item) { - bag->pollset_set_count--; - GPR_SWAP(grpc_pollset_set *, bag->pollset_sets[i], - bag->pollset_sets[bag->pollset_set_count]); - break; - } - } - gpr_mu_unlock(&bag->mu); -} - -void grpc_pollset_set_add_fd(grpc_exec_ctx *exec_ctx, - grpc_pollset_set *pollset_set, grpc_fd *fd) { - size_t i; - gpr_mu_lock(&pollset_set->mu); - if (pollset_set->fd_count == pollset_set->fd_capacity) { - pollset_set->fd_capacity = GPR_MAX(8, 2 * pollset_set->fd_capacity); - pollset_set->fds = gpr_realloc( - pollset_set->fds, pollset_set->fd_capacity * sizeof(*pollset_set->fds)); - } - GRPC_FD_REF(fd, "pollset_set"); - pollset_set->fds[pollset_set->fd_count++] = fd; - for (i = 0; i < pollset_set->pollset_count; i++) { - grpc_pollset_add_fd(exec_ctx, pollset_set->pollsets[i], fd); - } - for (i = 0; i < pollset_set->pollset_set_count; i++) { - grpc_pollset_set_add_fd(exec_ctx, pollset_set->pollset_sets[i], fd); - } - gpr_mu_unlock(&pollset_set->mu); -} - -void grpc_pollset_set_del_fd(grpc_exec_ctx *exec_ctx, - grpc_pollset_set *pollset_set, grpc_fd *fd) { - size_t i; - gpr_mu_lock(&pollset_set->mu); - for (i = 0; i < pollset_set->fd_count; i++) { - if (pollset_set->fds[i] == fd) { - pollset_set->fd_count--; - GPR_SWAP(grpc_fd *, pollset_set->fds[i], - pollset_set->fds[pollset_set->fd_count]); - GRPC_FD_UNREF(fd, "pollset_set"); - break; - } - } - for (i = 0; i < pollset_set->pollset_set_count; i++) { - grpc_pollset_set_del_fd(exec_ctx, pollset_set->pollset_sets[i], fd); - } - gpr_mu_unlock(&pollset_set->mu); -} - -#endif /* GPR_POSIX_SOCKET */ diff --git a/src/core/iomgr/pollset_set_posix.h b/src/core/iomgr/pollset_set_posix.h deleted file mode 100644 index 80f487718e..0000000000 --- a/src/core/iomgr/pollset_set_posix.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * - * Copyright 2015-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_IOMGR_POLLSET_SET_POSIX_H -#define GRPC_CORE_IOMGR_POLLSET_SET_POSIX_H - -#include "src/core/iomgr/fd_posix.h" -#include "src/core/iomgr/pollset_set.h" - -void grpc_pollset_set_add_fd(grpc_exec_ctx *exec_ctx, - grpc_pollset_set *pollset_set, grpc_fd *fd); -void grpc_pollset_set_del_fd(grpc_exec_ctx *exec_ctx, - grpc_pollset_set *pollset_set, grpc_fd *fd); - -#endif /* GRPC_CORE_IOMGR_POLLSET_SET_POSIX_H */ diff --git a/src/core/iomgr/pollset_set_windows.c b/src/core/iomgr/pollset_set_windows.c deleted file mode 100644 index 3b8eca28e6..0000000000 --- a/src/core/iomgr/pollset_set_windows.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * - * Copyright 2015-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 - -#ifdef GPR_WINSOCK_SOCKET - -#include "src/core/iomgr/pollset_set_windows.h" - -grpc_pollset_set* grpc_pollset_set_create(pollset_set) { return NULL; } - -void grpc_pollset_set_destroy(grpc_pollset_set* pollset_set) {} - -void grpc_pollset_set_add_pollset(grpc_exec_ctx* exec_ctx, - grpc_pollset_set* pollset_set, - grpc_pollset* pollset) {} - -void grpc_pollset_set_del_pollset(grpc_exec_ctx* exec_ctx, - grpc_pollset_set* pollset_set, - grpc_pollset* pollset) {} - -void grpc_pollset_set_add_pollset_set(grpc_exec_ctx* exec_ctx, - grpc_pollset_set* bag, - grpc_pollset_set* item) {} - -void grpc_pollset_set_del_pollset_set(grpc_exec_ctx* exec_ctx, - grpc_pollset_set* bag, - grpc_pollset_set* item) {} - -#endif /* GPR_WINSOCK_SOCKET */ diff --git a/src/core/iomgr/pollset_set_windows.h b/src/core/iomgr/pollset_set_windows.h deleted file mode 100644 index 0f040fef82..0000000000 --- a/src/core/iomgr/pollset_set_windows.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * - * Copyright 2015-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_IOMGR_POLLSET_SET_WINDOWS_H -#define GRPC_CORE_IOMGR_POLLSET_SET_WINDOWS_H - -#include "src/core/iomgr/pollset_set.h" - -#endif /* GRPC_CORE_IOMGR_POLLSET_SET_WINDOWS_H */ diff --git a/src/core/iomgr/pollset_windows.c b/src/core/iomgr/pollset_windows.c deleted file mode 100644 index 1a99224c80..0000000000 --- a/src/core/iomgr/pollset_windows.c +++ /dev/null @@ -1,240 +0,0 @@ -/* - * - * Copyright 2015-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 - -#ifdef GPR_WINSOCK_SOCKET - -#include -#include - -#include "src/core/iomgr/iocp_windows.h" -#include "src/core/iomgr/iomgr_internal.h" -#include "src/core/iomgr/pollset.h" -#include "src/core/iomgr/pollset_windows.h" - -gpr_mu grpc_polling_mu; -static grpc_pollset_worker *g_active_poller; -static grpc_pollset_worker g_global_root_worker; - -void grpc_pollset_global_init() { - gpr_mu_init(&grpc_polling_mu); - g_active_poller = NULL; - g_global_root_worker.links[GRPC_POLLSET_WORKER_LINK_GLOBAL].next = - g_global_root_worker.links[GRPC_POLLSET_WORKER_LINK_GLOBAL].prev = - &g_global_root_worker; -} - -void grpc_pollset_global_shutdown() { gpr_mu_destroy(&grpc_polling_mu); } - -static void remove_worker(grpc_pollset_worker *worker, - grpc_pollset_worker_link_type type) { - worker->links[type].prev->links[type].next = worker->links[type].next; - worker->links[type].next->links[type].prev = worker->links[type].prev; - worker->links[type].next = worker->links[type].prev = worker; -} - -static int has_workers(grpc_pollset_worker *root, - grpc_pollset_worker_link_type type) { - return root->links[type].next != root; -} - -static grpc_pollset_worker *pop_front_worker( - grpc_pollset_worker *root, grpc_pollset_worker_link_type type) { - if (has_workers(root, type)) { - grpc_pollset_worker *w = root->links[type].next; - remove_worker(w, type); - return w; - } else { - return NULL; - } -} - -static void push_front_worker(grpc_pollset_worker *root, - grpc_pollset_worker_link_type type, - grpc_pollset_worker *worker) { - worker->links[type].prev = root; - worker->links[type].next = worker->links[type].prev->links[type].next; - worker->links[type].prev->links[type].next = - worker->links[type].next->links[type].prev = worker; -} - -size_t grpc_pollset_size(void) { return sizeof(grpc_pollset); } - -/* There isn't really any such thing as a pollset under Windows, due to the - nature of the IO completion ports. We're still going to provide a minimal - set of features for the sake of the rest of grpc. But grpc_pollset_work - won't actually do any polling, and return as quickly as possible. */ - -void grpc_pollset_init(grpc_pollset *pollset, gpr_mu **mu) { - *mu = &grpc_polling_mu; - memset(pollset, 0, sizeof(*pollset)); - pollset->root_worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].next = - pollset->root_worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].prev = - &pollset->root_worker; -} - -void grpc_pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, - grpc_closure *closure) { - pollset->shutting_down = 1; - grpc_pollset_kick(pollset, GRPC_POLLSET_KICK_BROADCAST); - if (!pollset->is_iocp_worker) { - grpc_exec_ctx_enqueue(exec_ctx, closure, true, NULL); - } else { - pollset->on_shutdown = closure; - } -} - -void grpc_pollset_destroy(grpc_pollset *pollset) {} - -void grpc_pollset_reset(grpc_pollset *pollset) { - GPR_ASSERT(pollset->shutting_down); - GPR_ASSERT( - !has_workers(&pollset->root_worker, GRPC_POLLSET_WORKER_LINK_POLLSET)); - pollset->shutting_down = 0; - pollset->is_iocp_worker = 0; - pollset->kicked_without_pollers = 0; - pollset->on_shutdown = NULL; -} - -void grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, - grpc_pollset_worker **worker_hdl, gpr_timespec now, - gpr_timespec deadline) { - grpc_pollset_worker worker; - *worker_hdl = &worker; - - int added_worker = 0; - worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].next = - worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].prev = - worker.links[GRPC_POLLSET_WORKER_LINK_GLOBAL].next = - worker.links[GRPC_POLLSET_WORKER_LINK_GLOBAL].prev = NULL; - worker.kicked = 0; - worker.pollset = pollset; - gpr_cv_init(&worker.cv); - if (!pollset->kicked_without_pollers && !pollset->shutting_down) { - if (g_active_poller == NULL) { - grpc_pollset_worker *next_worker; - /* become poller */ - pollset->is_iocp_worker = 1; - g_active_poller = &worker; - gpr_mu_unlock(&grpc_polling_mu); - grpc_iocp_work(exec_ctx, deadline); - grpc_exec_ctx_flush(exec_ctx); - gpr_mu_lock(&grpc_polling_mu); - pollset->is_iocp_worker = 0; - g_active_poller = NULL; - /* try to get a worker from this pollsets worker list */ - next_worker = pop_front_worker(&pollset->root_worker, - GRPC_POLLSET_WORKER_LINK_POLLSET); - if (next_worker == NULL) { - /* try to get a worker from the global list */ - next_worker = pop_front_worker(&g_global_root_worker, - GRPC_POLLSET_WORKER_LINK_GLOBAL); - } - if (next_worker != NULL) { - next_worker->kicked = 1; - gpr_cv_signal(&next_worker->cv); - } - - if (pollset->shutting_down && pollset->on_shutdown != NULL) { - grpc_exec_ctx_enqueue(exec_ctx, pollset->on_shutdown, true, NULL); - pollset->on_shutdown = NULL; - } - goto done; - } - push_front_worker(&g_global_root_worker, GRPC_POLLSET_WORKER_LINK_GLOBAL, - &worker); - push_front_worker(&pollset->root_worker, GRPC_POLLSET_WORKER_LINK_POLLSET, - &worker); - added_worker = 1; - while (!worker.kicked) { - if (gpr_cv_wait(&worker.cv, &grpc_polling_mu, deadline)) { - break; - } - } - } else { - pollset->kicked_without_pollers = 0; - } -done: - if (!grpc_closure_list_empty(exec_ctx->closure_list)) { - gpr_mu_unlock(&grpc_polling_mu); - grpc_exec_ctx_flush(exec_ctx); - gpr_mu_lock(&grpc_polling_mu); - } - if (added_worker) { - remove_worker(&worker, GRPC_POLLSET_WORKER_LINK_GLOBAL); - remove_worker(&worker, GRPC_POLLSET_WORKER_LINK_POLLSET); - } - gpr_cv_destroy(&worker.cv); - *worker_hdl = NULL; -} - -void grpc_pollset_kick(grpc_pollset *p, grpc_pollset_worker *specific_worker) { - if (specific_worker != NULL) { - if (specific_worker == GRPC_POLLSET_KICK_BROADCAST) { - for (specific_worker = - p->root_worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].next; - specific_worker != &p->root_worker; - specific_worker = - specific_worker->links[GRPC_POLLSET_WORKER_LINK_POLLSET].next) { - specific_worker->kicked = 1; - gpr_cv_signal(&specific_worker->cv); - } - p->kicked_without_pollers = 1; - if (p->is_iocp_worker) { - grpc_iocp_kick(); - } - } else { - if (p->is_iocp_worker && g_active_poller == specific_worker) { - grpc_iocp_kick(); - } else { - specific_worker->kicked = 1; - gpr_cv_signal(&specific_worker->cv); - } - } - } else { - specific_worker = - pop_front_worker(&p->root_worker, GRPC_POLLSET_WORKER_LINK_POLLSET); - if (specific_worker != NULL) { - grpc_pollset_kick(p, specific_worker); - } else if (p->is_iocp_worker) { - grpc_iocp_kick(); - } else { - p->kicked_without_pollers = 1; - } - } -} - -void grpc_kick_poller(void) { grpc_iocp_kick(); } - -#endif /* GPR_WINSOCK_SOCKET */ diff --git a/src/core/iomgr/pollset_windows.h b/src/core/iomgr/pollset_windows.h deleted file mode 100644 index f1d1585922..0000000000 --- a/src/core/iomgr/pollset_windows.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * - * Copyright 2015-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_IOMGR_POLLSET_WINDOWS_H -#define GRPC_CORE_IOMGR_POLLSET_WINDOWS_H - -#include - -#include "src/core/iomgr/socket_windows.h" - -/* There isn't really any such thing as a pollset under Windows, due to the - nature of the IO completion ports. A Windows "pollset" is merely a mutex - used to synchronize with the IOCP, and workers are condition variables - used to block threads until work is ready. */ - -typedef enum { - GRPC_POLLSET_WORKER_LINK_POLLSET = 0, - GRPC_POLLSET_WORKER_LINK_GLOBAL, - GRPC_POLLSET_WORKER_LINK_TYPES -} grpc_pollset_worker_link_type; - -typedef struct grpc_pollset_worker_link { - struct grpc_pollset_worker *next; - struct grpc_pollset_worker *prev; -} grpc_pollset_worker_link; - -struct grpc_pollset; -typedef struct grpc_pollset grpc_pollset; - -typedef struct grpc_pollset_worker { - gpr_cv cv; - int kicked; - struct grpc_pollset *pollset; - grpc_pollset_worker_link links[GRPC_POLLSET_WORKER_LINK_TYPES]; -} grpc_pollset_worker; - -struct grpc_pollset { - int shutting_down; - int kicked_without_pollers; - int is_iocp_worker; - grpc_pollset_worker root_worker; - grpc_closure *on_shutdown; -}; - -#endif /* GRPC_CORE_IOMGR_POLLSET_WINDOWS_H */ diff --git a/src/core/iomgr/resolve_address.h b/src/core/iomgr/resolve_address.h deleted file mode 100644 index aa0d7d194b..0000000000 --- a/src/core/iomgr/resolve_address.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * - * Copyright 2015-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_IOMGR_RESOLVE_ADDRESS_H -#define GRPC_CORE_IOMGR_RESOLVE_ADDRESS_H - -#include -#include "src/core/iomgr/exec_ctx.h" -#include "src/core/iomgr/iomgr.h" - -#define GRPC_MAX_SOCKADDR_SIZE 128 - -typedef struct { - char addr[GRPC_MAX_SOCKADDR_SIZE]; - size_t len; -} grpc_resolved_address; - -typedef struct { - size_t naddrs; - grpc_resolved_address *addrs; -} grpc_resolved_addresses; - -/* Async result callback: - On success: addresses is the result, and the callee must call - grpc_resolved_addresses_destroy when it's done with them - On failure: addresses is NULL */ -typedef void (*grpc_resolve_cb)(grpc_exec_ctx *exec_ctx, void *arg, - grpc_resolved_addresses *addresses); -/* Asynchronously resolve addr. Use default_port if a port isn't designated - in addr, otherwise use the port in addr. */ -/* TODO(ctiller): add a timeout here */ -void grpc_resolve_address(const char *addr, const char *default_port, - grpc_resolve_cb cb, void *arg); -/* Destroy resolved addresses */ -void grpc_resolved_addresses_destroy(grpc_resolved_addresses *addresses); - -/* Resolve addr in a blocking fashion. Returns NULL on failure. On success, - result must be freed with grpc_resolved_addresses_destroy. */ -extern grpc_resolved_addresses *(*grpc_blocking_resolve_address)( - const char *name, const char *default_port); - -#endif /* GRPC_CORE_IOMGR_RESOLVE_ADDRESS_H */ diff --git a/src/core/iomgr/resolve_address_posix.c b/src/core/iomgr/resolve_address_posix.c deleted file mode 100644 index 26b3aa8189..0000000000 --- a/src/core/iomgr/resolve_address_posix.c +++ /dev/null @@ -1,178 +0,0 @@ -/* - * - * Copyright 2015-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 -#ifdef GPR_POSIX_SOCKET - -#include "src/core/iomgr/resolve_address.h" -#include "src/core/iomgr/sockaddr.h" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include "src/core/iomgr/executor.h" -#include "src/core/iomgr/iomgr_internal.h" -#include "src/core/iomgr/sockaddr_utils.h" -#include "src/core/iomgr/unix_sockets_posix.h" -#include "src/core/support/block_annotate.h" -#include "src/core/support/string.h" - -typedef struct { - char *name; - char *default_port; - grpc_resolve_cb cb; - grpc_closure request_closure; - void *arg; -} request; - -static grpc_resolved_addresses *blocking_resolve_address_impl( - const char *name, const char *default_port) { - struct addrinfo hints; - struct addrinfo *result = NULL, *resp; - char *host; - char *port; - int s; - size_t i; - grpc_resolved_addresses *addrs = NULL; - - if (name[0] == 'u' && name[1] == 'n' && name[2] == 'i' && name[3] == 'x' && - name[4] == ':' && name[5] != 0) { - return grpc_resolve_unix_domain_address(name + 5); - } - - /* parse name, splitting it into host and port parts */ - gpr_split_host_port(name, &host, &port); - if (host == NULL) { - gpr_log(GPR_ERROR, "unparseable host:port: '%s'", name); - goto done; - } - if (port == NULL) { - if (default_port == NULL) { - gpr_log(GPR_ERROR, "no port in name '%s'", name); - goto done; - } - port = gpr_strdup(default_port); - } - - /* Call getaddrinfo */ - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; /* ipv4 or ipv6 */ - hints.ai_socktype = SOCK_STREAM; /* stream socket */ - hints.ai_flags = AI_PASSIVE; /* for wildcard IP address */ - - GRPC_SCHEDULING_START_BLOCKING_REGION; - s = getaddrinfo(host, port, &hints, &result); - GRPC_SCHEDULING_END_BLOCKING_REGION; - - if (s != 0) { - /* Retry if well-known service name is recognized */ - char *svc[][2] = {{"http", "80"}, {"https", "443"}}; - for (i = 0; i < GPR_ARRAY_SIZE(svc); i++) { - if (strcmp(port, svc[i][0]) == 0) { - GRPC_SCHEDULING_START_BLOCKING_REGION; - s = getaddrinfo(host, svc[i][1], &hints, &result); - GRPC_SCHEDULING_END_BLOCKING_REGION; - break; - } - } - } - - if (s != 0) { - gpr_log(GPR_ERROR, "getaddrinfo: %s", gai_strerror(s)); - goto done; - } - - /* Success path: set addrs non-NULL, fill it in */ - addrs = gpr_malloc(sizeof(grpc_resolved_addresses)); - addrs->naddrs = 0; - for (resp = result; resp != NULL; resp = resp->ai_next) { - addrs->naddrs++; - } - addrs->addrs = gpr_malloc(sizeof(grpc_resolved_address) * addrs->naddrs); - i = 0; - for (resp = result; resp != NULL; resp = resp->ai_next) { - memcpy(&addrs->addrs[i].addr, resp->ai_addr, resp->ai_addrlen); - addrs->addrs[i].len = resp->ai_addrlen; - i++; - } - -done: - gpr_free(host); - gpr_free(port); - if (result) { - freeaddrinfo(result); - } - return addrs; -} - -grpc_resolved_addresses *(*grpc_blocking_resolve_address)( - const char *name, const char *default_port) = blocking_resolve_address_impl; - -/* Callback to be passed to grpc_executor to asynch-ify - * grpc_blocking_resolve_address */ -static void do_request_thread(grpc_exec_ctx *exec_ctx, void *rp, bool success) { - request *r = rp; - grpc_resolved_addresses *resolved = - grpc_blocking_resolve_address(r->name, r->default_port); - void *arg = r->arg; - grpc_resolve_cb cb = r->cb; - gpr_free(r->name); - gpr_free(r->default_port); - cb(exec_ctx, arg, resolved); - gpr_free(r); -} - -void grpc_resolved_addresses_destroy(grpc_resolved_addresses *addrs) { - gpr_free(addrs->addrs); - gpr_free(addrs); -} - -void grpc_resolve_address(const char *name, const char *default_port, - grpc_resolve_cb cb, void *arg) { - request *r = gpr_malloc(sizeof(request)); - grpc_closure_init(&r->request_closure, do_request_thread, r); - r->name = gpr_strdup(name); - r->default_port = gpr_strdup(default_port); - r->cb = cb; - r->arg = arg; - grpc_executor_enqueue(&r->request_closure, 1); -} - -#endif diff --git a/src/core/iomgr/resolve_address_windows.c b/src/core/iomgr/resolve_address_windows.c deleted file mode 100644 index 472e797163..0000000000 --- a/src/core/iomgr/resolve_address_windows.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * - * Copyright 2015-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 -#ifdef GPR_WINSOCK_SOCKET - -#include "src/core/iomgr/resolve_address.h" -#include "src/core/iomgr/sockaddr.h" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include "src/core/iomgr/executor.h" -#include "src/core/iomgr/iomgr_internal.h" -#include "src/core/iomgr/sockaddr_utils.h" -#include "src/core/support/block_annotate.h" -#include "src/core/support/string.h" - -typedef struct { - char *name; - char *default_port; - grpc_resolve_cb cb; - grpc_closure request_closure; - void *arg; -} request; - -static grpc_resolved_addresses *blocking_resolve_address_impl( - const char *name, const char *default_port) { - struct addrinfo hints; - struct addrinfo *result = NULL, *resp; - char *host; - char *port; - int s; - size_t i; - grpc_resolved_addresses *addrs = NULL; - - /* parse name, splitting it into host and port parts */ - gpr_split_host_port(name, &host, &port); - if (host == NULL) { - gpr_log(GPR_ERROR, "unparseable host:port: '%s'", name); - goto done; - } - if (port == NULL) { - if (default_port == NULL) { - gpr_log(GPR_ERROR, "no port in name '%s'", name); - goto done; - } - port = gpr_strdup(default_port); - } - - /* Call getaddrinfo */ - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; /* ipv4 or ipv6 */ - hints.ai_socktype = SOCK_STREAM; /* stream socket */ - hints.ai_flags = AI_PASSIVE; /* for wildcard IP address */ - - GRPC_SCHEDULING_START_BLOCKING_REGION; - s = getaddrinfo(host, port, &hints, &result); - GRPC_SCHEDULING_END_BLOCKING_REGION; - if (s != 0) { - char *error_message = gpr_format_message(s); - gpr_log(GPR_ERROR, "getaddrinfo: %s", error_message); - gpr_free(error_message); - goto done; - } - - /* Success path: set addrs non-NULL, fill it in */ - addrs = gpr_malloc(sizeof(grpc_resolved_addresses)); - addrs->naddrs = 0; - for (resp = result; resp != NULL; resp = resp->ai_next) { - addrs->naddrs++; - } - addrs->addrs = gpr_malloc(sizeof(grpc_resolved_address) * addrs->naddrs); - i = 0; - for (resp = result; resp != NULL; resp = resp->ai_next) { - memcpy(&addrs->addrs[i].addr, resp->ai_addr, resp->ai_addrlen); - addrs->addrs[i].len = resp->ai_addrlen; - i++; - } - - { - for (i = 0; i < addrs->naddrs; i++) { - char *buf; - grpc_sockaddr_to_string(&buf, (struct sockaddr *)&addrs->addrs[i].addr, - 0); - gpr_free(buf); - } - } - -done: - gpr_free(host); - gpr_free(port); - if (result) { - freeaddrinfo(result); - } - return addrs; -} - -grpc_resolved_addresses *(*grpc_blocking_resolve_address)( - const char *name, const char *default_port) = blocking_resolve_address_impl; - -/* Callback to be passed to grpc_executor to asynch-ify - * grpc_blocking_resolve_address */ -static void do_request_thread(grpc_exec_ctx *exec_ctx, void *rp, bool success) { - request *r = rp; - grpc_resolved_addresses *resolved = - grpc_blocking_resolve_address(r->name, r->default_port); - void *arg = r->arg; - grpc_resolve_cb cb = r->cb; - gpr_free(r->name); - gpr_free(r->default_port); - cb(exec_ctx, arg, resolved); - gpr_free(r); -} - -void grpc_resolved_addresses_destroy(grpc_resolved_addresses *addrs) { - gpr_free(addrs->addrs); - gpr_free(addrs); -} - -void grpc_resolve_address(const char *name, const char *default_port, - grpc_resolve_cb cb, void *arg) { - request *r = gpr_malloc(sizeof(request)); - grpc_closure_init(&r->request_closure, do_request_thread, r); - r->name = gpr_strdup(name); - r->default_port = gpr_strdup(default_port); - r->cb = cb; - r->arg = arg; - grpc_executor_enqueue(&r->request_closure, 1); -} - -#endif diff --git a/src/core/iomgr/sockaddr.h b/src/core/iomgr/sockaddr.h deleted file mode 100644 index 68241bdd55..0000000000 --- a/src/core/iomgr/sockaddr.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * - * Copyright 2015-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_IOMGR_SOCKADDR_H -#define GRPC_CORE_IOMGR_SOCKADDR_H - -#include - -#ifdef GPR_WIN32 -#include "src/core/iomgr/sockaddr_win32.h" -#endif - -#ifdef GPR_POSIX_SOCKETADDR -#include "src/core/iomgr/sockaddr_posix.h" -#endif - -#endif /* GRPC_CORE_IOMGR_SOCKADDR_H */ diff --git a/src/core/iomgr/sockaddr_posix.h b/src/core/iomgr/sockaddr_posix.h deleted file mode 100644 index a398096837..0000000000 --- a/src/core/iomgr/sockaddr_posix.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * - * Copyright 2015-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_IOMGR_SOCKADDR_POSIX_H -#define GRPC_CORE_IOMGR_SOCKADDR_POSIX_H - -#include -#include -#include -#include -#include -#include - -#endif /* GRPC_CORE_IOMGR_SOCKADDR_POSIX_H */ diff --git a/src/core/iomgr/sockaddr_utils.c b/src/core/iomgr/sockaddr_utils.c deleted file mode 100644 index a3c3a874c1..0000000000 --- a/src/core/iomgr/sockaddr_utils.c +++ /dev/null @@ -1,227 +0,0 @@ -/* - * - * 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/iomgr/sockaddr_utils.h" - -#include -#include - -#include -#include -#include -#include -#include - -#include "src/core/iomgr/unix_sockets_posix.h" -#include "src/core/support/string.h" - -static const uint8_t kV4MappedPrefix[] = {0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0xff, 0xff}; - -int grpc_sockaddr_is_v4mapped(const struct sockaddr *addr, - struct sockaddr_in *addr4_out) { - GPR_ASSERT(addr != (struct sockaddr *)addr4_out); - if (addr->sa_family == AF_INET6) { - const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr; - if (memcmp(addr6->sin6_addr.s6_addr, kV4MappedPrefix, - sizeof(kV4MappedPrefix)) == 0) { - if (addr4_out != NULL) { - /* Normalize ::ffff:0.0.0.0/96 to IPv4. */ - memset(addr4_out, 0, sizeof(*addr4_out)); - addr4_out->sin_family = AF_INET; - /* s6_addr32 would be nice, but it's non-standard. */ - memcpy(&addr4_out->sin_addr, &addr6->sin6_addr.s6_addr[12], 4); - addr4_out->sin_port = addr6->sin6_port; - } - return 1; - } - } - return 0; -} - -int grpc_sockaddr_to_v4mapped(const struct sockaddr *addr, - struct sockaddr_in6 *addr6_out) { - GPR_ASSERT(addr != (struct sockaddr *)addr6_out); - if (addr->sa_family == AF_INET) { - const struct sockaddr_in *addr4 = (const struct sockaddr_in *)addr; - memset(addr6_out, 0, sizeof(*addr6_out)); - addr6_out->sin6_family = AF_INET6; - memcpy(&addr6_out->sin6_addr.s6_addr[0], kV4MappedPrefix, 12); - memcpy(&addr6_out->sin6_addr.s6_addr[12], &addr4->sin_addr, 4); - addr6_out->sin6_port = addr4->sin_port; - return 1; - } - return 0; -} - -int grpc_sockaddr_is_wildcard(const struct sockaddr *addr, int *port_out) { - struct sockaddr_in addr4_normalized; - if (grpc_sockaddr_is_v4mapped(addr, &addr4_normalized)) { - addr = (struct sockaddr *)&addr4_normalized; - } - if (addr->sa_family == AF_INET) { - /* Check for 0.0.0.0 */ - const struct sockaddr_in *addr4 = (const struct sockaddr_in *)addr; - if (addr4->sin_addr.s_addr != 0) { - return 0; - } - *port_out = ntohs(addr4->sin_port); - return 1; - } else if (addr->sa_family == AF_INET6) { - /* Check for :: */ - const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr; - int i; - for (i = 0; i < 16; i++) { - if (addr6->sin6_addr.s6_addr[i] != 0) { - return 0; - } - } - *port_out = ntohs(addr6->sin6_port); - return 1; - } else { - return 0; - } -} - -void grpc_sockaddr_make_wildcards(int port, struct sockaddr_in *wild4_out, - struct sockaddr_in6 *wild6_out) { - grpc_sockaddr_make_wildcard4(port, wild4_out); - grpc_sockaddr_make_wildcard6(port, wild6_out); -} - -void grpc_sockaddr_make_wildcard4(int port, struct sockaddr_in *wild_out) { - GPR_ASSERT(port >= 0 && port < 65536); - memset(wild_out, 0, sizeof(*wild_out)); - wild_out->sin_family = AF_INET; - wild_out->sin_port = htons((uint16_t)port); -} - -void grpc_sockaddr_make_wildcard6(int port, struct sockaddr_in6 *wild_out) { - GPR_ASSERT(port >= 0 && port < 65536); - memset(wild_out, 0, sizeof(*wild_out)); - wild_out->sin6_family = AF_INET6; - wild_out->sin6_port = htons((uint16_t)port); -} - -int grpc_sockaddr_to_string(char **out, const struct sockaddr *addr, - int normalize) { - const int save_errno = errno; - struct sockaddr_in addr_normalized; - char ntop_buf[INET6_ADDRSTRLEN]; - const void *ip = NULL; - int port; - int ret; - - *out = NULL; - if (normalize && grpc_sockaddr_is_v4mapped(addr, &addr_normalized)) { - addr = (const struct sockaddr *)&addr_normalized; - } - if (addr->sa_family == AF_INET) { - const struct sockaddr_in *addr4 = (const struct sockaddr_in *)addr; - ip = &addr4->sin_addr; - port = ntohs(addr4->sin_port); - } else if (addr->sa_family == AF_INET6) { - const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr; - ip = &addr6->sin6_addr; - port = ntohs(addr6->sin6_port); - } - /* Windows inet_ntop wants a mutable ip pointer */ - if (ip != NULL && - inet_ntop(addr->sa_family, (void *)ip, ntop_buf, sizeof(ntop_buf)) != - NULL) { - ret = gpr_join_host_port(out, ntop_buf, port); - } else { - ret = gpr_asprintf(out, "(sockaddr family=%d)", addr->sa_family); - } - /* This is probably redundant, but we wouldn't want to log the wrong error. */ - errno = save_errno; - return ret; -} - -char *grpc_sockaddr_to_uri(const struct sockaddr *addr) { - char *temp; - char *result; - struct sockaddr_in addr_normalized; - - if (grpc_sockaddr_is_v4mapped(addr, &addr_normalized)) { - addr = (const struct sockaddr *)&addr_normalized; - } - - switch (addr->sa_family) { - case AF_INET: - grpc_sockaddr_to_string(&temp, addr, 0); - gpr_asprintf(&result, "ipv4:%s", temp); - gpr_free(temp); - return result; - case AF_INET6: - grpc_sockaddr_to_string(&temp, addr, 0); - gpr_asprintf(&result, "ipv6:%s", temp); - gpr_free(temp); - return result; - default: - return grpc_sockaddr_to_uri_unix_if_possible(addr); - } -} - -int grpc_sockaddr_get_port(const struct sockaddr *addr) { - switch (addr->sa_family) { - case AF_INET: - return ntohs(((struct sockaddr_in *)addr)->sin_port); - case AF_INET6: - return ntohs(((struct sockaddr_in6 *)addr)->sin6_port); - default: - if (grpc_is_unix_socket(addr)) { - return 1; - } - gpr_log(GPR_ERROR, "Unknown socket family %d in grpc_sockaddr_get_port", - addr->sa_family); - return 0; - } -} - -int grpc_sockaddr_set_port(const struct sockaddr *addr, int port) { - switch (addr->sa_family) { - case AF_INET: - GPR_ASSERT(port >= 0 && port < 65536); - ((struct sockaddr_in *)addr)->sin_port = htons((uint16_t)port); - return 1; - case AF_INET6: - GPR_ASSERT(port >= 0 && port < 65536); - ((struct sockaddr_in6 *)addr)->sin6_port = htons((uint16_t)port); - return 1; - default: - gpr_log(GPR_ERROR, "Unknown socket family %d in grpc_sockaddr_set_port", - addr->sa_family); - return 0; - } -} diff --git a/src/core/iomgr/sockaddr_utils.h b/src/core/iomgr/sockaddr_utils.h deleted file mode 100644 index 43dc7a45ec..0000000000 --- a/src/core/iomgr/sockaddr_utils.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * - * Copyright 2015-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_IOMGR_SOCKADDR_UTILS_H -#define GRPC_CORE_IOMGR_SOCKADDR_UTILS_H - -#include "src/core/iomgr/sockaddr.h" - -/* Returns true if addr is an IPv4-mapped IPv6 address within the - ::ffff:0.0.0.0/96 range, or false otherwise. - - If addr4_out is non-NULL, the inner IPv4 address will be copied here when - returning true. */ -int grpc_sockaddr_is_v4mapped(const struct sockaddr *addr, - struct sockaddr_in *addr4_out); - -/* If addr is an AF_INET address, writes the corresponding ::ffff:0.0.0.0/96 - address to addr6_out and returns true. Otherwise returns false. */ -int grpc_sockaddr_to_v4mapped(const struct sockaddr *addr, - struct sockaddr_in6 *addr6_out); - -/* If addr is ::, 0.0.0.0, or ::ffff:0.0.0.0, writes the port number to - *port_out (if not NULL) and returns true, otherwise returns false. */ -int grpc_sockaddr_is_wildcard(const struct sockaddr *addr, int *port_out); - -/* Writes 0.0.0.0:port and [::]:port to separate sockaddrs. */ -void grpc_sockaddr_make_wildcards(int port, struct sockaddr_in *wild4_out, - struct sockaddr_in6 *wild6_out); - -/* Writes 0.0.0.0:port. */ -void grpc_sockaddr_make_wildcard4(int port, struct sockaddr_in *wild_out); - -/* Writes [::]:port. */ -void grpc_sockaddr_make_wildcard6(int port, struct sockaddr_in6 *wild_out); - -/* Return the IP port number of a sockaddr */ -int grpc_sockaddr_get_port(const struct sockaddr *addr); - -/* Set IP port number of a sockaddr */ -int grpc_sockaddr_set_port(const struct sockaddr *addr, int port); - -/* Converts a sockaddr into a newly-allocated human-readable string. - - Currently, only the AF_INET and AF_INET6 families are recognized. - If the normalize flag is enabled, ::ffff:0.0.0.0/96 IPv6 addresses are - displayed as plain IPv4. - - Usage is similar to gpr_asprintf: returns the number of bytes written - (excluding the final '\0'), and *out points to a string which must later be - destroyed using gpr_free(). - - In the unlikely event of an error, returns -1 and sets *out to NULL. - The existing value of errno is always preserved. */ -int grpc_sockaddr_to_string(char **out, const struct sockaddr *addr, - int normalize); - -char *grpc_sockaddr_to_uri(const struct sockaddr *addr); - -#endif /* GRPC_CORE_IOMGR_SOCKADDR_UTILS_H */ diff --git a/src/core/iomgr/sockaddr_win32.h b/src/core/iomgr/sockaddr_win32.h deleted file mode 100644 index ef306e3cc3..0000000000 --- a/src/core/iomgr/sockaddr_win32.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * - * Copyright 2015-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_IOMGR_SOCKADDR_WIN32_H -#define GRPC_CORE_IOMGR_SOCKADDR_WIN32_H - -#include -#include - -// must be included after the above -#include - -#endif /* GRPC_CORE_IOMGR_SOCKADDR_WIN32_H */ diff --git a/src/core/iomgr/socket_utils_common_posix.c b/src/core/iomgr/socket_utils_common_posix.c deleted file mode 100644 index 570daccc9e..0000000000 --- a/src/core/iomgr/socket_utils_common_posix.c +++ /dev/null @@ -1,208 +0,0 @@ -/* - * - * Copyright 2015-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 - -#ifdef GPR_POSIX_SOCKET - -#include "src/core/iomgr/socket_utils_posix.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include "src/core/iomgr/sockaddr_utils.h" -#include "src/core/support/string.h" - -/* set a socket to non blocking mode */ -int grpc_set_socket_nonblocking(int fd, int non_blocking) { - int oldflags = fcntl(fd, F_GETFL, 0); - if (oldflags < 0) { - return 0; - } - - if (non_blocking) { - oldflags |= O_NONBLOCK; - } else { - oldflags &= ~O_NONBLOCK; - } - - if (fcntl(fd, F_SETFL, oldflags) != 0) { - return 0; - } - - return 1; -} - -int grpc_set_socket_no_sigpipe_if_possible(int fd) { -#ifdef GPR_HAVE_SO_NOSIGPIPE - int val = 1; - int newval; - socklen_t intlen = sizeof(newval); - return 0 == setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(val)) && - 0 == getsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &newval, &intlen) && - (newval != 0) == val; -#else - return 1; -#endif -} - -/* set a socket to close on exec */ -int grpc_set_socket_cloexec(int fd, int close_on_exec) { - int oldflags = fcntl(fd, F_GETFD, 0); - if (oldflags < 0) { - return 0; - } - - if (close_on_exec) { - oldflags |= FD_CLOEXEC; - } else { - oldflags &= ~FD_CLOEXEC; - } - - if (fcntl(fd, F_SETFD, oldflags) != 0) { - return 0; - } - - return 1; -} - -/* set a socket to reuse old addresses */ -int grpc_set_socket_reuse_addr(int fd, int reuse) { - int val = (reuse != 0); - int newval; - socklen_t intlen = sizeof(newval); - return 0 == setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) && - 0 == getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &newval, &intlen) && - (newval != 0) == val; -} - -/* disable nagle */ -int grpc_set_socket_low_latency(int fd, int low_latency) { - int val = (low_latency != 0); - int newval; - socklen_t intlen = sizeof(newval); - return 0 == setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) && - 0 == getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &newval, &intlen) && - (newval != 0) == val; -} - -static gpr_once g_probe_ipv6_once = GPR_ONCE_INIT; -static int g_ipv6_loopback_available; - -static void probe_ipv6_once(void) { - int fd = socket(AF_INET6, SOCK_STREAM, 0); - g_ipv6_loopback_available = 0; - if (fd < 0) { - gpr_log(GPR_INFO, "Disabling AF_INET6 sockets because socket() failed."); - } else { - struct sockaddr_in6 addr; - memset(&addr, 0, sizeof(addr)); - addr.sin6_family = AF_INET6; - addr.sin6_addr.s6_addr[15] = 1; /* [::1]:0 */ - if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == 0) { - g_ipv6_loopback_available = 1; - } else { - gpr_log(GPR_INFO, - "Disabling AF_INET6 sockets because ::1 is not available."); - } - close(fd); - } -} - -int grpc_ipv6_loopback_available(void) { - gpr_once_init(&g_probe_ipv6_once, probe_ipv6_once); - return g_ipv6_loopback_available; -} - -/* This should be 0 in production, but it may be enabled for testing or - debugging purposes, to simulate an environment where IPv6 sockets can't - also speak IPv4. */ -int grpc_forbid_dualstack_sockets_for_testing = 0; - -static int set_socket_dualstack(int fd) { - if (!grpc_forbid_dualstack_sockets_for_testing) { - const int off = 0; - return 0 == setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &off, sizeof(off)); - } else { - /* Force an IPv6-only socket, for testing purposes. */ - const int on = 1; - setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)); - return 0; - } -} - -int grpc_create_dualstack_socket(const struct sockaddr *addr, int type, - int protocol, grpc_dualstack_mode *dsmode) { - int family = addr->sa_family; - if (family == AF_INET6) { - int fd; - if (grpc_ipv6_loopback_available()) { - fd = socket(family, type, protocol); - } else { - fd = -1; - errno = EAFNOSUPPORT; - } - /* Check if we've got a valid dualstack socket. */ - if (fd >= 0 && set_socket_dualstack(fd)) { - *dsmode = GRPC_DSMODE_DUALSTACK; - return fd; - } - /* If this isn't an IPv4 address, then return whatever we've got. */ - if (!grpc_sockaddr_is_v4mapped(addr, NULL)) { - *dsmode = GRPC_DSMODE_IPV6; - return fd; - } - /* Fall back to AF_INET. */ - if (fd >= 0) { - close(fd); - } - family = AF_INET; - } - *dsmode = family == AF_INET ? GRPC_DSMODE_IPV4 : GRPC_DSMODE_NONE; - return socket(family, type, protocol); -} - -#endif diff --git a/src/core/iomgr/socket_utils_linux.c b/src/core/iomgr/socket_utils_linux.c deleted file mode 100644 index e16885f231..0000000000 --- a/src/core/iomgr/socket_utils_linux.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * - * Copyright 2015-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 - -#ifdef GPR_LINUX_SOCKETUTILS - -#include "src/core/iomgr/socket_utils_posix.h" - -#include -#include - -int grpc_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, - int nonblock, int cloexec) { - int flags = 0; - flags |= nonblock ? SOCK_NONBLOCK : 0; - flags |= cloexec ? SOCK_CLOEXEC : 0; - return accept4(sockfd, addr, addrlen, flags); -} - -#endif diff --git a/src/core/iomgr/socket_utils_posix.c b/src/core/iomgr/socket_utils_posix.c deleted file mode 100644 index 3c56b46744..0000000000 --- a/src/core/iomgr/socket_utils_posix.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include - -#ifdef GPR_POSIX_SOCKETUTILS - -#include "src/core/iomgr/socket_utils_posix.h" - -#include -#include -#include - -#include - -int grpc_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, - int nonblock, int cloexec) { - int fd, flags; - - fd = accept(sockfd, addr, addrlen); - if (fd >= 0) { - if (nonblock) { - flags = fcntl(fd, F_GETFL, 0); - if (flags < 0) goto close_and_error; - if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) goto close_and_error; - } - if (cloexec) { - flags = fcntl(fd, F_GETFD, 0); - if (flags < 0) goto close_and_error; - if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) != 0) goto close_and_error; - } - } - return fd; - -close_and_error: - close(fd); - return -1; -} - -#endif /* GPR_POSIX_SOCKETUTILS */ diff --git a/src/core/iomgr/socket_utils_posix.h b/src/core/iomgr/socket_utils_posix.h deleted file mode 100644 index 3908550380..0000000000 --- a/src/core/iomgr/socket_utils_posix.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * - * Copyright 2015-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_IOMGR_SOCKET_UTILS_POSIX_H -#define GRPC_CORE_IOMGR_SOCKET_UTILS_POSIX_H - -#include -#include - -/* a wrapper for accept or accept4 */ -int grpc_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, - int nonblock, int cloexec); - -/* set a socket to non blocking mode */ -int grpc_set_socket_nonblocking(int fd, int non_blocking); - -/* set a socket to close on exec */ -int grpc_set_socket_cloexec(int fd, int close_on_exec); - -/* set a socket to reuse old addresses */ -int grpc_set_socket_reuse_addr(int fd, int reuse); - -/* disable nagle */ -int grpc_set_socket_low_latency(int fd, int low_latency); - -/* Returns true if this system can create AF_INET6 sockets bound to ::1. - The value is probed once, and cached for the life of the process. - - This is more restrictive than checking for socket(AF_INET6) to succeed, - because Linux with "net.ipv6.conf.all.disable_ipv6 = 1" is able to create - and bind IPv6 sockets, but cannot connect to a getsockname() of [::]:port - without a valid loopback interface. Rather than expose this half-broken - state to library users, we turn off IPv6 sockets. */ -int grpc_ipv6_loopback_available(void); - -/* Tries to set SO_NOSIGPIPE if available on this platform. - Returns 1 on success, 0 on failure. - If SO_NO_SIGPIPE is not available, returns 1. */ -int grpc_set_socket_no_sigpipe_if_possible(int fd); - -/* An enum to keep track of IPv4/IPv6 socket modes. - - Currently, this information is only used when a socket is first created, but - in the future we may wish to store it alongside the fd. This would let calls - like sendto() know which family to use without asking the kernel first. */ -typedef enum grpc_dualstack_mode { - /* Uninitialized, or a non-IP socket. */ - GRPC_DSMODE_NONE, - /* AF_INET only. */ - GRPC_DSMODE_IPV4, - /* AF_INET6 only, because IPV6_V6ONLY could not be cleared. */ - GRPC_DSMODE_IPV6, - /* AF_INET6, which also supports ::ffff-mapped IPv4 addresses. */ - GRPC_DSMODE_DUALSTACK -} grpc_dualstack_mode; - -/* Only tests should use this flag. */ -extern int grpc_forbid_dualstack_sockets_for_testing; - -/* Creates a new socket for connecting to (or listening on) an address. - - If addr is AF_INET6, this creates an IPv6 socket first. If that fails, - and addr is within ::ffff:0.0.0.0/96, then it automatically falls back to - an IPv4 socket. - - If addr is AF_INET, AF_UNIX, or anything else, then this is similar to - calling socket() directly. - - Returns an fd on success, otherwise returns -1 with errno set to the result - of a failed socket() call. - - The *dsmode output indicates which address family was actually created. - The recommended way to use this is: - - First convert to IPv6 using grpc_sockaddr_to_v4mapped(). - - Create the socket. - - If *dsmode is IPV4, use grpc_sockaddr_is_v4mapped() to convert back to - IPv4, so that bind() or connect() see the correct family. - Also, it's important to distinguish between DUALSTACK and IPV6 when - listening on the [::] wildcard address. */ -int grpc_create_dualstack_socket(const struct sockaddr *addr, int type, - int protocol, grpc_dualstack_mode *dsmode); - -#endif /* GRPC_CORE_IOMGR_SOCKET_UTILS_POSIX_H */ diff --git a/src/core/iomgr/socket_windows.c b/src/core/iomgr/socket_windows.c deleted file mode 100644 index c1f419e273..0000000000 --- a/src/core/iomgr/socket_windows.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * - * Copyright 2015-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 - -#ifdef GPR_WINSOCK_SOCKET - -#include - -// must be included after winsock2.h -#include - -#include -#include -#include -#include - -#include "src/core/iomgr/iocp_windows.h" -#include "src/core/iomgr/iomgr_internal.h" -#include "src/core/iomgr/pollset.h" -#include "src/core/iomgr/pollset_windows.h" -#include "src/core/iomgr/socket_windows.h" - -grpc_winsocket *grpc_winsocket_create(SOCKET socket, const char *name) { - char *final_name; - grpc_winsocket *r = gpr_malloc(sizeof(grpc_winsocket)); - memset(r, 0, sizeof(grpc_winsocket)); - r->socket = socket; - gpr_mu_init(&r->state_mu); - gpr_asprintf(&final_name, "%s:socket=0x%p", name, r); - grpc_iomgr_register_object(&r->iomgr_object, final_name); - gpr_free(final_name); - grpc_iocp_add_socket(r); - return r; -} - -/* Schedule a shutdown of the socket operations. Will call the pending - operations to abort them. We need to do that this way because of the - various callsites of that function, which happens to be in various - mutex hold states, and that'd be unsafe to call them directly. */ -void grpc_winsocket_shutdown(grpc_winsocket *winsocket) { - /* Grab the function pointer for DisconnectEx for that specific socket. - It may change depending on the interface. */ - int status; - GUID guid = WSAID_DISCONNECTEX; - LPFN_DISCONNECTEX DisconnectEx; - DWORD ioctl_num_bytes; - - status = WSAIoctl(winsocket->socket, SIO_GET_EXTENSION_FUNCTION_POINTER, - &guid, sizeof(guid), &DisconnectEx, sizeof(DisconnectEx), - &ioctl_num_bytes, NULL, NULL); - - if (status == 0) { - DisconnectEx(winsocket->socket, NULL, 0, 0); - } else { - char *utf8_message = gpr_format_message(WSAGetLastError()); - gpr_log(GPR_ERROR, "Unable to retrieve DisconnectEx pointer : %s", - utf8_message); - gpr_free(utf8_message); - } - closesocket(winsocket->socket); -} - -void grpc_winsocket_destroy(grpc_winsocket *winsocket) { - grpc_iomgr_unregister_object(&winsocket->iomgr_object); - gpr_mu_destroy(&winsocket->state_mu); - gpr_free(winsocket); -} - -#endif /* GPR_WINSOCK_SOCKET */ diff --git a/src/core/iomgr/socket_windows.h b/src/core/iomgr/socket_windows.h deleted file mode 100644 index 6fe3c6e080..0000000000 --- a/src/core/iomgr/socket_windows.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * - * Copyright 2015-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_IOMGR_SOCKET_WINDOWS_H -#define GRPC_CORE_IOMGR_SOCKET_WINDOWS_H - -#include -#include - -#include -#include - -#include "src/core/iomgr/exec_ctx.h" -#include "src/core/iomgr/iomgr_internal.h" - -/* This holds the data for an outstanding read or write on a socket. - The mutex to protect the concurrent access to that data is the one - inside the winsocket wrapper. */ -typedef struct grpc_winsocket_callback_info { - /* This is supposed to be a WSAOVERLAPPED, but in order to get that - definition, we need to include ws2tcpip.h, which needs to be included - from the top, otherwise it'll clash with a previous inclusion of - windows.h that in turns includes winsock.h. If anyone knows a way - to do it properly, feel free to send a patch. */ - OVERLAPPED overlapped; - /* The callback information for the pending operation. May be empty if the - caller hasn't registered a callback yet. */ - grpc_closure *closure; - /* A boolean to describe if the IO Completion Port got a notification for - that operation. This will happen if the operation completed before the - called had time to register a callback. We could avoid that behavior - altogether by forcing the caller to always register its callback before - proceeding queue an operation, but it is frequent for an IO Completion - Port to trigger quickly. This way we avoid a context switch for calling - the callback. We also simplify the read / write operations to avoid having - to hold a mutex for a long amount of time. */ - int has_pending_iocp; - /* The results of the overlapped operation. */ - DWORD bytes_transfered; - int wsa_error; -} grpc_winsocket_callback_info; - -/* This is a wrapper to a Windows socket. A socket can have one outstanding - read, and one outstanding write. Doing an asynchronous accept means waiting - for a read operation. Doing an asynchronous connect means waiting for a - write operation. These are completely arbitrary ties between the operation - and the kind of event, because we can have one overlapped per pending - operation, whichever its nature is. So we could have more dedicated pending - operation callbacks for connect and listen. But given the scope of listen - and accept, we don't need to go to that extent and waste memory. Also, this - is closer to what happens in posix world. */ -typedef struct grpc_winsocket { - SOCKET socket; - - grpc_winsocket_callback_info write_info; - grpc_winsocket_callback_info read_info; - - gpr_mu state_mu; - - /* You can't add the same socket twice to the same IO Completion Port. - This prevents that. */ - int added_to_iocp; - - grpc_closure shutdown_closure; - - /* A label for iomgr to track outstanding objects */ - grpc_iomgr_object iomgr_object; -} grpc_winsocket; - -/* Create a wrapped windows handle. This takes ownership of it, meaning that - it will be responsible for closing it. */ -grpc_winsocket *grpc_winsocket_create(SOCKET socket, const char *name); - -/* Initiate an asynchronous shutdown of the socket. Will call off any pending - operation to cancel them. */ -void grpc_winsocket_shutdown(grpc_winsocket *socket); - -/* Destroy a socket. Should only be called if there's no pending operation. */ -void grpc_winsocket_destroy(grpc_winsocket *socket); - -#endif /* GRPC_CORE_IOMGR_SOCKET_WINDOWS_H */ diff --git a/src/core/iomgr/tcp_client.h b/src/core/iomgr/tcp_client.h deleted file mode 100644 index c36f8de713..0000000000 --- a/src/core/iomgr/tcp_client.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * - * Copyright 2015-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_IOMGR_TCP_CLIENT_H -#define GRPC_CORE_IOMGR_TCP_CLIENT_H - -#include -#include "src/core/iomgr/endpoint.h" -#include "src/core/iomgr/pollset_set.h" -#include "src/core/iomgr/sockaddr.h" - -/* Asynchronously connect to an address (specified as (addr, len)), and call - cb with arg and the completed connection when done (or call cb with arg and - NULL on failure). - interested_parties points to a set of pollsets that would be interested - in this connection being established (in order to continue their work) */ -void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *on_connect, - grpc_endpoint **endpoint, - grpc_pollset_set *interested_parties, - const struct sockaddr *addr, size_t addr_len, - gpr_timespec deadline); - -#endif /* GRPC_CORE_IOMGR_TCP_CLIENT_H */ diff --git a/src/core/iomgr/tcp_client_posix.c b/src/core/iomgr/tcp_client_posix.c deleted file mode 100644 index 1d3f9b6555..0000000000 --- a/src/core/iomgr/tcp_client_posix.c +++ /dev/null @@ -1,306 +0,0 @@ -/* - * - * Copyright 2015-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 - -#ifdef GPR_POSIX_SOCKET - -#include "src/core/iomgr/tcp_client.h" - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "src/core/iomgr/iomgr_posix.h" -#include "src/core/iomgr/pollset_posix.h" -#include "src/core/iomgr/pollset_set_posix.h" -#include "src/core/iomgr/sockaddr_utils.h" -#include "src/core/iomgr/socket_utils_posix.h" -#include "src/core/iomgr/tcp_posix.h" -#include "src/core/iomgr/timer.h" -#include "src/core/iomgr/unix_sockets_posix.h" -#include "src/core/support/string.h" - -extern int grpc_tcp_trace; - -typedef struct { - gpr_mu mu; - grpc_fd *fd; - gpr_timespec deadline; - grpc_timer alarm; - int refs; - grpc_closure write_closure; - grpc_pollset_set *interested_parties; - char *addr_str; - grpc_endpoint **ep; - grpc_closure *closure; -} async_connect; - -static int prepare_socket(const struct sockaddr *addr, int fd) { - if (fd < 0) { - goto error; - } - - if (!grpc_set_socket_nonblocking(fd, 1) || !grpc_set_socket_cloexec(fd, 1) || - (!grpc_is_unix_socket(addr) && !grpc_set_socket_low_latency(fd, 1)) || - !grpc_set_socket_no_sigpipe_if_possible(fd)) { - gpr_log(GPR_ERROR, "Unable to configure socket %d: %s", fd, - strerror(errno)); - goto error; - } - return 1; - -error: - if (fd >= 0) { - close(fd); - } - return 0; -} - -static void tc_on_alarm(grpc_exec_ctx *exec_ctx, void *acp, bool success) { - int done; - async_connect *ac = acp; - if (grpc_tcp_trace) { - gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: on_alarm: success=%d", ac->addr_str, - success); - } - gpr_mu_lock(&ac->mu); - if (ac->fd != NULL) { - grpc_fd_shutdown(exec_ctx, ac->fd); - } - done = (--ac->refs == 0); - gpr_mu_unlock(&ac->mu); - if (done) { - gpr_mu_destroy(&ac->mu); - gpr_free(ac->addr_str); - gpr_free(ac); - } -} - -static void on_writable(grpc_exec_ctx *exec_ctx, void *acp, bool success) { - async_connect *ac = acp; - int so_error = 0; - socklen_t so_error_size; - int err; - int done; - grpc_endpoint **ep = ac->ep; - grpc_closure *closure = ac->closure; - grpc_fd *fd; - - if (grpc_tcp_trace) { - gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: on_writable: success=%d", - ac->addr_str, success); - } - - gpr_mu_lock(&ac->mu); - GPR_ASSERT(ac->fd); - fd = ac->fd; - ac->fd = NULL; - gpr_mu_unlock(&ac->mu); - - grpc_timer_cancel(exec_ctx, &ac->alarm); - - gpr_mu_lock(&ac->mu); - if (success) { - do { - so_error_size = sizeof(so_error); - err = getsockopt(fd->fd, SOL_SOCKET, SO_ERROR, &so_error, &so_error_size); - } while (err < 0 && errno == EINTR); - if (err < 0) { - gpr_log(GPR_ERROR, "failed to connect to '%s': getsockopt(ERROR): %s", - ac->addr_str, strerror(errno)); - goto finish; - } else if (so_error != 0) { - if (so_error == ENOBUFS) { - /* We will get one of these errors if we have run out of - memory in the kernel for the data structures allocated - when you connect a socket. If this happens it is very - likely that if we wait a little bit then try again the - connection will work (since other programs or this - program will close their network connections and free up - memory). This does _not_ indicate that there is anything - wrong with the server we are connecting to, this is a - local problem. - - If you are looking at this code, then chances are that - your program or another program on the same computer - opened too many network connections. The "easy" fix: - don't do that! */ - gpr_log(GPR_ERROR, "kernel out of buffers"); - gpr_mu_unlock(&ac->mu); - grpc_fd_notify_on_write(exec_ctx, fd, &ac->write_closure); - return; - } else { - switch (so_error) { - case ECONNREFUSED: - gpr_log( - GPR_ERROR, - "failed to connect to '%s': socket error: connection refused", - ac->addr_str); - break; - default: - gpr_log(GPR_ERROR, "failed to connect to '%s': socket error: %d", - ac->addr_str, so_error); - break; - } - goto finish; - } - } else { - grpc_pollset_set_del_fd(exec_ctx, ac->interested_parties, fd); - *ep = grpc_tcp_create(fd, GRPC_TCP_DEFAULT_READ_SLICE_SIZE, ac->addr_str); - fd = NULL; - goto finish; - } - } else { - gpr_log(GPR_ERROR, "failed to connect to '%s': timeout occurred", - ac->addr_str); - goto finish; - } - - GPR_UNREACHABLE_CODE(return ); - -finish: - if (fd != NULL) { - grpc_pollset_set_del_fd(exec_ctx, ac->interested_parties, fd); - grpc_fd_orphan(exec_ctx, fd, NULL, NULL, "tcp_client_orphan"); - fd = NULL; - } - done = (--ac->refs == 0); - gpr_mu_unlock(&ac->mu); - if (done) { - gpr_mu_destroy(&ac->mu); - gpr_free(ac->addr_str); - gpr_free(ac); - } - grpc_exec_ctx_enqueue(exec_ctx, closure, *ep != NULL, NULL); -} - -void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *closure, - grpc_endpoint **ep, - grpc_pollset_set *interested_parties, - const struct sockaddr *addr, size_t addr_len, - gpr_timespec deadline) { - int fd; - grpc_dualstack_mode dsmode; - int err; - async_connect *ac; - struct sockaddr_in6 addr6_v4mapped; - struct sockaddr_in addr4_copy; - grpc_fd *fdobj; - char *name; - char *addr_str; - - *ep = NULL; - - /* Use dualstack sockets where available. */ - if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) { - addr = (const struct sockaddr *)&addr6_v4mapped; - addr_len = sizeof(addr6_v4mapped); - } - - fd = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode); - if (fd < 0) { - gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno)); - } - if (dsmode == GRPC_DSMODE_IPV4) { - /* If we got an AF_INET socket, map the address back to IPv4. */ - GPR_ASSERT(grpc_sockaddr_is_v4mapped(addr, &addr4_copy)); - addr = (struct sockaddr *)&addr4_copy; - addr_len = sizeof(addr4_copy); - } - if (!prepare_socket(addr, fd)) { - grpc_exec_ctx_enqueue(exec_ctx, closure, false, NULL); - return; - } - - do { - GPR_ASSERT(addr_len < ~(socklen_t)0); - err = connect(fd, addr, (socklen_t)addr_len); - } while (err < 0 && errno == EINTR); - - addr_str = grpc_sockaddr_to_uri(addr); - gpr_asprintf(&name, "tcp-client:%s", addr_str); - - fdobj = grpc_fd_create(fd, name); - - if (err >= 0) { - *ep = grpc_tcp_create(fdobj, GRPC_TCP_DEFAULT_READ_SLICE_SIZE, addr_str); - grpc_exec_ctx_enqueue(exec_ctx, closure, true, NULL); - goto done; - } - - if (errno != EWOULDBLOCK && errno != EINPROGRESS) { - gpr_log(GPR_ERROR, "connect error to '%s': %s", addr_str, strerror(errno)); - grpc_fd_orphan(exec_ctx, fdobj, NULL, NULL, "tcp_client_connect_error"); - grpc_exec_ctx_enqueue(exec_ctx, closure, false, NULL); - goto done; - } - - grpc_pollset_set_add_fd(exec_ctx, interested_parties, fdobj); - - ac = gpr_malloc(sizeof(async_connect)); - ac->closure = closure; - ac->ep = ep; - ac->fd = fdobj; - ac->interested_parties = interested_parties; - ac->addr_str = addr_str; - addr_str = NULL; - gpr_mu_init(&ac->mu); - ac->refs = 2; - ac->write_closure.cb = on_writable; - ac->write_closure.cb_arg = ac; - - if (grpc_tcp_trace) { - gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: asynchronously connecting", - ac->addr_str); - } - - gpr_mu_lock(&ac->mu); - grpc_timer_init(exec_ctx, &ac->alarm, - gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC), - tc_on_alarm, ac, gpr_now(GPR_CLOCK_MONOTONIC)); - grpc_fd_notify_on_write(exec_ctx, ac->fd, &ac->write_closure); - gpr_mu_unlock(&ac->mu); - -done: - gpr_free(name); - gpr_free(addr_str); -} - -#endif diff --git a/src/core/iomgr/tcp_client_windows.c b/src/core/iomgr/tcp_client_windows.c deleted file mode 100644 index da83f7b79c..0000000000 --- a/src/core/iomgr/tcp_client_windows.c +++ /dev/null @@ -1,221 +0,0 @@ -/* - * - * Copyright 2015-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 - -#ifdef GPR_WINSOCK_SOCKET - -#include "src/core/iomgr/sockaddr_win32.h" - -#include -#include -#include -#include -#include - -#include "src/core/iomgr/iocp_windows.h" -#include "src/core/iomgr/sockaddr.h" -#include "src/core/iomgr/sockaddr_utils.h" -#include "src/core/iomgr/socket_windows.h" -#include "src/core/iomgr/tcp_client.h" -#include "src/core/iomgr/tcp_windows.h" -#include "src/core/iomgr/timer.h" - -typedef struct { - grpc_closure *on_done; - gpr_mu mu; - grpc_winsocket *socket; - gpr_timespec deadline; - grpc_timer alarm; - char *addr_name; - int refs; - grpc_closure on_connect; - grpc_endpoint **endpoint; -} async_connect; - -static void async_connect_unlock_and_cleanup(async_connect *ac) { - int done = (--ac->refs == 0); - gpr_mu_unlock(&ac->mu); - if (done) { - if (ac->socket != NULL) grpc_winsocket_destroy(ac->socket); - gpr_mu_destroy(&ac->mu); - gpr_free(ac->addr_name); - gpr_free(ac); - } -} - -static void on_alarm(grpc_exec_ctx *exec_ctx, void *acp, bool occured) { - async_connect *ac = acp; - gpr_mu_lock(&ac->mu); - /* If the alarm didn't occur, it got cancelled. */ - if (ac->socket != NULL && occured) { - grpc_winsocket_shutdown(ac->socket); - } - async_connect_unlock_and_cleanup(ac); -} - -static void on_connect(grpc_exec_ctx *exec_ctx, void *acp, bool from_iocp) { - async_connect *ac = acp; - SOCKET sock = ac->socket->socket; - grpc_endpoint **ep = ac->endpoint; - grpc_winsocket_callback_info *info = &ac->socket->write_info; - grpc_closure *on_done = ac->on_done; - - grpc_timer_cancel(exec_ctx, &ac->alarm); - - gpr_mu_lock(&ac->mu); - - if (from_iocp) { - DWORD transfered_bytes = 0; - DWORD flags; - BOOL wsa_success = WSAGetOverlappedResult(sock, &info->overlapped, - &transfered_bytes, FALSE, &flags); - GPR_ASSERT(transfered_bytes == 0); - if (!wsa_success) { - char *utf8_message = gpr_format_message(WSAGetLastError()); - gpr_log(GPR_ERROR, "on_connect error: %s", utf8_message); - gpr_free(utf8_message); - } else { - *ep = grpc_tcp_create(ac->socket, ac->addr_name); - ac->socket = NULL; - } - } - - async_connect_unlock_and_cleanup(ac); - /* If the connection was aborted, the callback was already called when - the deadline was met. */ - on_done->cb(exec_ctx, on_done->cb_arg, *ep != NULL); -} - -/* Tries to issue one async connection, then schedules both an IOCP - notification request for the connection, and one timeout alert. */ -void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *on_done, - grpc_endpoint **endpoint, - grpc_pollset_set *interested_parties, - const struct sockaddr *addr, size_t addr_len, - gpr_timespec deadline) { - SOCKET sock = INVALID_SOCKET; - BOOL success; - int status; - struct sockaddr_in6 addr6_v4mapped; - struct sockaddr_in6 local_address; - async_connect *ac; - grpc_winsocket *socket = NULL; - LPFN_CONNECTEX ConnectEx; - GUID guid = WSAID_CONNECTEX; - DWORD ioctl_num_bytes; - const char *message = NULL; - char *utf8_message; - grpc_winsocket_callback_info *info; - - *endpoint = NULL; - - /* Use dualstack sockets where available. */ - if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) { - addr = (const struct sockaddr *)&addr6_v4mapped; - addr_len = sizeof(addr6_v4mapped); - } - - sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0, - WSA_FLAG_OVERLAPPED); - if (sock == INVALID_SOCKET) { - message = "Unable to create socket: %s"; - goto failure; - } - - if (!grpc_tcp_prepare_socket(sock)) { - message = "Unable to set socket options: %s"; - goto failure; - } - - /* Grab the function pointer for ConnectEx for that specific socket. - It may change depending on the interface. */ - status = - WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid), - &ConnectEx, sizeof(ConnectEx), &ioctl_num_bytes, NULL, NULL); - - if (status != 0) { - message = "Unable to retrieve ConnectEx pointer: %s"; - goto failure; - } - - grpc_sockaddr_make_wildcard6(0, &local_address); - - status = bind(sock, (struct sockaddr *)&local_address, sizeof(local_address)); - if (status != 0) { - message = "Unable to bind socket: %s"; - goto failure; - } - - socket = grpc_winsocket_create(sock, "client"); - info = &socket->write_info; - success = - ConnectEx(sock, addr, (int)addr_len, NULL, 0, NULL, &info->overlapped); - - /* It wouldn't be unusual to get a success immediately. But we'll still get - an IOCP notification, so let's ignore it. */ - if (!success) { - int error = WSAGetLastError(); - if (error != ERROR_IO_PENDING) { - message = "ConnectEx failed: %s"; - goto failure; - } - } - - ac = gpr_malloc(sizeof(async_connect)); - ac->on_done = on_done; - ac->socket = socket; - gpr_mu_init(&ac->mu); - ac->refs = 2; - ac->addr_name = grpc_sockaddr_to_uri(addr); - ac->endpoint = endpoint; - grpc_closure_init(&ac->on_connect, on_connect, ac); - - grpc_timer_init(exec_ctx, &ac->alarm, deadline, on_alarm, ac, - gpr_now(GPR_CLOCK_MONOTONIC)); - grpc_socket_notify_on_write(exec_ctx, socket, &ac->on_connect); - return; - -failure: - utf8_message = gpr_format_message(WSAGetLastError()); - gpr_log(GPR_ERROR, message, utf8_message); - gpr_free(utf8_message); - if (socket != NULL) { - grpc_winsocket_destroy(socket); - } else if (sock != INVALID_SOCKET) { - closesocket(sock); - } - grpc_exec_ctx_enqueue(exec_ctx, on_done, false, NULL); -} - -#endif /* GPR_WINSOCK_SOCKET */ diff --git a/src/core/iomgr/tcp_posix.c b/src/core/iomgr/tcp_posix.c deleted file mode 100644 index e8f73811ce..0000000000 --- a/src/core/iomgr/tcp_posix.c +++ /dev/null @@ -1,493 +0,0 @@ -/* - * - * Copyright 2015-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 - -#ifdef GPR_POSIX_SOCKET - -#include "src/core/iomgr/tcp_posix.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "src/core/debug/trace.h" -#include "src/core/iomgr/pollset_posix.h" -#include "src/core/iomgr/pollset_set_posix.h" -#include "src/core/profiling/timers.h" -#include "src/core/support/string.h" - -#ifdef GPR_HAVE_MSG_NOSIGNAL -#define SENDMSG_FLAGS MSG_NOSIGNAL -#else -#define SENDMSG_FLAGS 0 -#endif - -#ifdef GPR_MSG_IOVLEN_TYPE -typedef GPR_MSG_IOVLEN_TYPE msg_iovlen_type; -#else -typedef size_t msg_iovlen_type; -#endif - -int grpc_tcp_trace = 0; - -typedef struct { - grpc_endpoint base; - grpc_fd *em_fd; - int fd; - int finished_edge; - msg_iovlen_type iov_size; /* Number of slices to allocate per read attempt */ - size_t slice_size; - gpr_refcount refcount; - - /* garbage after the last read */ - gpr_slice_buffer last_read_buffer; - - gpr_slice_buffer *incoming_buffer; - gpr_slice_buffer *outgoing_buffer; - /** slice within outgoing_buffer to write next */ - size_t outgoing_slice_idx; - /** byte within outgoing_buffer->slices[outgoing_slice_idx] to write next */ - size_t outgoing_byte_idx; - - grpc_closure *read_cb; - grpc_closure *write_cb; - grpc_closure *release_fd_cb; - int *release_fd; - - grpc_closure read_closure; - grpc_closure write_closure; - - char *peer_string; -} grpc_tcp; - -static void tcp_handle_read(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */, - bool success); -static void tcp_handle_write(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */, - bool success); - -static void tcp_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) { - grpc_tcp *tcp = (grpc_tcp *)ep; - grpc_fd_shutdown(exec_ctx, tcp->em_fd); -} - -static void tcp_free(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) { - grpc_fd_orphan(exec_ctx, tcp->em_fd, tcp->release_fd_cb, tcp->release_fd, - "tcp_unref_orphan"); - gpr_slice_buffer_destroy(&tcp->last_read_buffer); - gpr_free(tcp->peer_string); - gpr_free(tcp); -} - -/*#define GRPC_TCP_REFCOUNT_DEBUG*/ -#ifdef GRPC_TCP_REFCOUNT_DEBUG -#define TCP_UNREF(cl, tcp, reason) \ - tcp_unref((cl), (tcp), (reason), __FILE__, __LINE__) -#define TCP_REF(tcp, reason) tcp_ref((tcp), (reason), __FILE__, __LINE__) -static void tcp_unref(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp, - const char *reason, const char *file, int line) { - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP unref %p : %s %d -> %d", tcp, - reason, tcp->refcount.count, tcp->refcount.count - 1); - if (gpr_unref(&tcp->refcount)) { - tcp_free(exec_ctx, tcp); - } -} - -static void tcp_ref(grpc_tcp *tcp, const char *reason, const char *file, - int line) { - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP ref %p : %s %d -> %d", tcp, - reason, tcp->refcount.count, tcp->refcount.count + 1); - gpr_ref(&tcp->refcount); -} -#else -#define TCP_UNREF(cl, tcp, reason) tcp_unref((cl), (tcp)) -#define TCP_REF(tcp, reason) tcp_ref((tcp)) -static void tcp_unref(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) { - if (gpr_unref(&tcp->refcount)) { - tcp_free(exec_ctx, tcp); - } -} - -static void tcp_ref(grpc_tcp *tcp) { gpr_ref(&tcp->refcount); } -#endif - -static void tcp_destroy(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) { - grpc_tcp *tcp = (grpc_tcp *)ep; - TCP_UNREF(exec_ctx, tcp, "destroy"); -} - -static void call_read_cb(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp, int success) { - grpc_closure *cb = tcp->read_cb; - - if (grpc_tcp_trace) { - size_t i; - gpr_log(GPR_DEBUG, "read: success=%d", success); - for (i = 0; i < tcp->incoming_buffer->count; i++) { - char *dump = gpr_dump_slice(tcp->incoming_buffer->slices[i], - GPR_DUMP_HEX | GPR_DUMP_ASCII); - gpr_log(GPR_DEBUG, "READ %p: %s", tcp, dump); - gpr_free(dump); - } - } - - tcp->read_cb = NULL; - tcp->incoming_buffer = NULL; - cb->cb(exec_ctx, cb->cb_arg, success); -} - -#define MAX_READ_IOVEC 4 -static void tcp_continue_read(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) { - struct msghdr msg; - struct iovec iov[MAX_READ_IOVEC]; - ssize_t read_bytes; - size_t i; - - GPR_ASSERT(!tcp->finished_edge); - GPR_ASSERT(tcp->iov_size <= MAX_READ_IOVEC); - GPR_ASSERT(tcp->incoming_buffer->count <= MAX_READ_IOVEC); - GPR_TIMER_BEGIN("tcp_continue_read", 0); - - while (tcp->incoming_buffer->count < (size_t)tcp->iov_size) { - gpr_slice_buffer_add_indexed(tcp->incoming_buffer, - gpr_slice_malloc(tcp->slice_size)); - } - for (i = 0; i < tcp->incoming_buffer->count; i++) { - iov[i].iov_base = GPR_SLICE_START_PTR(tcp->incoming_buffer->slices[i]); - iov[i].iov_len = GPR_SLICE_LENGTH(tcp->incoming_buffer->slices[i]); - } - - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = iov; - msg.msg_iovlen = tcp->iov_size; - msg.msg_control = NULL; - msg.msg_controllen = 0; - msg.msg_flags = 0; - - GPR_TIMER_BEGIN("recvmsg", 1); - do { - read_bytes = recvmsg(tcp->fd, &msg, 0); - } while (read_bytes < 0 && errno == EINTR); - GPR_TIMER_END("recvmsg", 0); - - if (read_bytes < 0) { - /* NB: After calling call_read_cb a parallel call of the read handler may - * be running. */ - if (errno == EAGAIN) { - if (tcp->iov_size > 1) { - tcp->iov_size /= 2; - } - /* We've consumed the edge, request a new one */ - grpc_fd_notify_on_read(exec_ctx, tcp->em_fd, &tcp->read_closure); - } else { - /* TODO(klempner): Log interesting errors */ - gpr_slice_buffer_reset_and_unref(tcp->incoming_buffer); - call_read_cb(exec_ctx, tcp, 0); - TCP_UNREF(exec_ctx, tcp, "read"); - } - } else if (read_bytes == 0) { - /* 0 read size ==> end of stream */ - gpr_slice_buffer_reset_and_unref(tcp->incoming_buffer); - call_read_cb(exec_ctx, tcp, 0); - TCP_UNREF(exec_ctx, tcp, "read"); - } else { - GPR_ASSERT((size_t)read_bytes <= tcp->incoming_buffer->length); - if ((size_t)read_bytes < tcp->incoming_buffer->length) { - gpr_slice_buffer_trim_end( - tcp->incoming_buffer, - tcp->incoming_buffer->length - (size_t)read_bytes, - &tcp->last_read_buffer); - } else if (tcp->iov_size < MAX_READ_IOVEC) { - ++tcp->iov_size; - } - GPR_ASSERT((size_t)read_bytes == tcp->incoming_buffer->length); - call_read_cb(exec_ctx, tcp, 1); - TCP_UNREF(exec_ctx, tcp, "read"); - } - - GPR_TIMER_END("tcp_continue_read", 0); -} - -static void tcp_handle_read(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */, - bool success) { - grpc_tcp *tcp = (grpc_tcp *)arg; - GPR_ASSERT(!tcp->finished_edge); - - if (!success) { - gpr_slice_buffer_reset_and_unref(tcp->incoming_buffer); - call_read_cb(exec_ctx, tcp, 0); - TCP_UNREF(exec_ctx, tcp, "read"); - } else { - tcp_continue_read(exec_ctx, tcp); - } -} - -static void tcp_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, - gpr_slice_buffer *incoming_buffer, grpc_closure *cb) { - grpc_tcp *tcp = (grpc_tcp *)ep; - GPR_ASSERT(tcp->read_cb == NULL); - tcp->read_cb = cb; - tcp->incoming_buffer = incoming_buffer; - gpr_slice_buffer_reset_and_unref(incoming_buffer); - gpr_slice_buffer_swap(incoming_buffer, &tcp->last_read_buffer); - TCP_REF(tcp, "read"); - if (tcp->finished_edge) { - tcp->finished_edge = 0; - grpc_fd_notify_on_read(exec_ctx, tcp->em_fd, &tcp->read_closure); - } else { - grpc_exec_ctx_enqueue(exec_ctx, &tcp->read_closure, true, NULL); - } -} - -typedef enum { FLUSH_DONE, FLUSH_PENDING, FLUSH_ERROR } flush_result; - -#define MAX_WRITE_IOVEC 16 -static flush_result tcp_flush(grpc_tcp *tcp) { - struct msghdr msg; - struct iovec iov[MAX_WRITE_IOVEC]; - msg_iovlen_type iov_size; - ssize_t sent_length; - size_t sending_length; - size_t trailing; - size_t unwind_slice_idx; - size_t unwind_byte_idx; - - for (;;) { - sending_length = 0; - unwind_slice_idx = tcp->outgoing_slice_idx; - unwind_byte_idx = tcp->outgoing_byte_idx; - for (iov_size = 0; tcp->outgoing_slice_idx != tcp->outgoing_buffer->count && - iov_size != MAX_WRITE_IOVEC; - iov_size++) { - iov[iov_size].iov_base = - GPR_SLICE_START_PTR( - tcp->outgoing_buffer->slices[tcp->outgoing_slice_idx]) + - tcp->outgoing_byte_idx; - iov[iov_size].iov_len = - GPR_SLICE_LENGTH( - tcp->outgoing_buffer->slices[tcp->outgoing_slice_idx]) - - tcp->outgoing_byte_idx; - sending_length += iov[iov_size].iov_len; - tcp->outgoing_slice_idx++; - tcp->outgoing_byte_idx = 0; - } - GPR_ASSERT(iov_size > 0); - - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = iov; - msg.msg_iovlen = iov_size; - msg.msg_control = NULL; - msg.msg_controllen = 0; - msg.msg_flags = 0; - - GPR_TIMER_BEGIN("sendmsg", 1); - do { - /* TODO(klempner): Cork if this is a partial write */ - sent_length = sendmsg(tcp->fd, &msg, SENDMSG_FLAGS); - } while (sent_length < 0 && errno == EINTR); - GPR_TIMER_END("sendmsg", 0); - - if (sent_length < 0) { - if (errno == EAGAIN) { - tcp->outgoing_slice_idx = unwind_slice_idx; - tcp->outgoing_byte_idx = unwind_byte_idx; - return FLUSH_PENDING; - } else { - /* TODO(klempner): Log some of these */ - return FLUSH_ERROR; - } - } - - GPR_ASSERT(tcp->outgoing_byte_idx == 0); - trailing = sending_length - (size_t)sent_length; - while (trailing > 0) { - size_t slice_length; - - tcp->outgoing_slice_idx--; - slice_length = GPR_SLICE_LENGTH( - tcp->outgoing_buffer->slices[tcp->outgoing_slice_idx]); - if (slice_length > trailing) { - tcp->outgoing_byte_idx = slice_length - trailing; - break; - } else { - trailing -= slice_length; - } - } - - if (tcp->outgoing_slice_idx == tcp->outgoing_buffer->count) { - return FLUSH_DONE; - } - }; -} - -static void tcp_handle_write(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */, - bool success) { - grpc_tcp *tcp = (grpc_tcp *)arg; - flush_result status; - grpc_closure *cb; - - if (!success) { - cb = tcp->write_cb; - tcp->write_cb = NULL; - cb->cb(exec_ctx, cb->cb_arg, 0); - TCP_UNREF(exec_ctx, tcp, "write"); - return; - } - - status = tcp_flush(tcp); - if (status == FLUSH_PENDING) { - grpc_fd_notify_on_write(exec_ctx, tcp->em_fd, &tcp->write_closure); - } else { - cb = tcp->write_cb; - tcp->write_cb = NULL; - GPR_TIMER_BEGIN("tcp_handle_write.cb", 0); - cb->cb(exec_ctx, cb->cb_arg, status == FLUSH_DONE); - GPR_TIMER_END("tcp_handle_write.cb", 0); - TCP_UNREF(exec_ctx, tcp, "write"); - } -} - -static void tcp_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, - gpr_slice_buffer *buf, grpc_closure *cb) { - grpc_tcp *tcp = (grpc_tcp *)ep; - flush_result status; - - if (grpc_tcp_trace) { - size_t i; - - for (i = 0; i < buf->count; i++) { - char *data = - gpr_dump_slice(buf->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII); - gpr_log(GPR_DEBUG, "WRITE %p: %s", tcp, data); - gpr_free(data); - } - } - - GPR_TIMER_BEGIN("tcp_write", 0); - GPR_ASSERT(tcp->write_cb == NULL); - - if (buf->length == 0) { - GPR_TIMER_END("tcp_write", 0); - grpc_exec_ctx_enqueue(exec_ctx, cb, true, NULL); - return; - } - tcp->outgoing_buffer = buf; - tcp->outgoing_slice_idx = 0; - tcp->outgoing_byte_idx = 0; - - status = tcp_flush(tcp); - if (status == FLUSH_PENDING) { - TCP_REF(tcp, "write"); - tcp->write_cb = cb; - grpc_fd_notify_on_write(exec_ctx, tcp->em_fd, &tcp->write_closure); - } else { - grpc_exec_ctx_enqueue(exec_ctx, cb, status == FLUSH_DONE, NULL); - } - - GPR_TIMER_END("tcp_write", 0); -} - -static void tcp_add_to_pollset(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, - grpc_pollset *pollset) { - grpc_tcp *tcp = (grpc_tcp *)ep; - grpc_pollset_add_fd(exec_ctx, pollset, tcp->em_fd); -} - -static void tcp_add_to_pollset_set(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, - grpc_pollset_set *pollset_set) { - grpc_tcp *tcp = (grpc_tcp *)ep; - grpc_pollset_set_add_fd(exec_ctx, pollset_set, tcp->em_fd); -} - -static char *tcp_get_peer(grpc_endpoint *ep) { - grpc_tcp *tcp = (grpc_tcp *)ep; - return gpr_strdup(tcp->peer_string); -} - -static const grpc_endpoint_vtable vtable = { - tcp_read, tcp_write, tcp_add_to_pollset, tcp_add_to_pollset_set, - tcp_shutdown, tcp_destroy, tcp_get_peer}; - -grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd, size_t slice_size, - const char *peer_string) { - grpc_tcp *tcp = (grpc_tcp *)gpr_malloc(sizeof(grpc_tcp)); - tcp->base.vtable = &vtable; - tcp->peer_string = gpr_strdup(peer_string); - tcp->fd = em_fd->fd; - tcp->read_cb = NULL; - tcp->write_cb = NULL; - tcp->release_fd_cb = NULL; - tcp->release_fd = NULL; - tcp->incoming_buffer = NULL; - tcp->slice_size = slice_size; - tcp->iov_size = 1; - tcp->finished_edge = 1; - /* paired with unref in grpc_tcp_destroy */ - gpr_ref_init(&tcp->refcount, 1); - tcp->em_fd = em_fd; - tcp->read_closure.cb = tcp_handle_read; - tcp->read_closure.cb_arg = tcp; - tcp->write_closure.cb = tcp_handle_write; - tcp->write_closure.cb_arg = tcp; - gpr_slice_buffer_init(&tcp->last_read_buffer); - - return &tcp->base; -} - -int grpc_tcp_fd(grpc_endpoint *ep) { - grpc_tcp *tcp = (grpc_tcp *)ep; - GPR_ASSERT(ep->vtable == &vtable); - return grpc_fd_wrapped_fd(tcp->em_fd); -} - -void grpc_tcp_destroy_and_release_fd(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, - int *fd, grpc_closure *done) { - grpc_tcp *tcp = (grpc_tcp *)ep; - GPR_ASSERT(ep->vtable == &vtable); - tcp->release_fd = fd; - tcp->release_fd_cb = done; - TCP_UNREF(exec_ctx, tcp, "destroy"); -} - -#endif diff --git a/src/core/iomgr/tcp_posix.h b/src/core/iomgr/tcp_posix.h deleted file mode 100644 index d846ec570f..0000000000 --- a/src/core/iomgr/tcp_posix.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * - * Copyright 2015-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_IOMGR_TCP_POSIX_H -#define GRPC_CORE_IOMGR_TCP_POSIX_H -/* - Low level TCP "bottom half" implementation, for use by transports built on - top of a TCP connection. - - Note that this file does not (yet) include APIs for creating the socket in - the first place. - - All calls passing slice transfer ownership of a slice refcount unless - otherwise specified. -*/ - -#include "src/core/iomgr/endpoint.h" -#include "src/core/iomgr/fd_posix.h" - -#define GRPC_TCP_DEFAULT_READ_SLICE_SIZE 8192 - -extern int grpc_tcp_trace; - -/* Create a tcp endpoint given a file desciptor and a read slice size. - Takes ownership of fd. */ -grpc_endpoint *grpc_tcp_create(grpc_fd *fd, size_t read_slice_size, - const char *peer_string); - -/* Return the tcp endpoint's fd, or -1 if this is not available. Does not - release the fd. - Requires: ep must be a tcp endpoint. - */ -int grpc_tcp_fd(grpc_endpoint *ep); - -/* Destroy the tcp endpoint without closing its fd. *fd will be set and done - * will be called when the endpoint is destroyed. - * Requires: ep must be a tcp endpoint and fd must not be NULL. */ -void grpc_tcp_destroy_and_release_fd(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, - int *fd, grpc_closure *done); - -#endif /* GRPC_CORE_IOMGR_TCP_POSIX_H */ diff --git a/src/core/iomgr/tcp_server.h b/src/core/iomgr/tcp_server.h deleted file mode 100644 index 93247e9e4e..0000000000 --- a/src/core/iomgr/tcp_server.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * - * Copyright 2015-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_IOMGR_TCP_SERVER_H -#define GRPC_CORE_IOMGR_TCP_SERVER_H - -#include "src/core/iomgr/closure.h" -#include "src/core/iomgr/endpoint.h" - -/* Forward decl of grpc_tcp_server */ -typedef struct grpc_tcp_server grpc_tcp_server; - -typedef struct grpc_tcp_server_acceptor { - /* grpc_tcp_server_cb functions share a ref on from_server that is valid - until the function returns. */ - grpc_tcp_server *from_server; - /* Indices that may be passed to grpc_tcp_server_port_fd(). */ - unsigned port_index; - unsigned fd_index; -} grpc_tcp_server_acceptor; - -/* Called for newly connected TCP connections. */ -typedef void (*grpc_tcp_server_cb)(grpc_exec_ctx *exec_ctx, void *arg, - grpc_endpoint *ep, - grpc_tcp_server_acceptor *acceptor); - -/* Create a server, initially not bound to any ports. The caller owns one ref. - If shutdown_complete is not NULL, it will be used by - grpc_tcp_server_unref() when the ref count reaches zero. */ -grpc_tcp_server *grpc_tcp_server_create(grpc_closure *shutdown_complete); - -/* Start listening to bound ports */ -void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *server, - grpc_pollset **pollsets, size_t pollset_count, - grpc_tcp_server_cb on_accept_cb, void *cb_arg); - -/* Add a port to the server, returning the newly allocated port on success, or - -1 on failure. - - The :: and 0.0.0.0 wildcard addresses are treated identically, accepting - both IPv4 and IPv6 connections, but :: is the preferred style. This usually - creates one socket, but possibly two on systems which support IPv6, - but not dualstack sockets. */ -/* TODO(ctiller): deprecate this, and make grpc_tcp_server_add_ports to handle - all of the multiple socket port matching logic in one place */ -int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr, - size_t addr_len); - -/* Number of fds at the given port_index, or 0 if port_index is out of - bounds. */ -unsigned grpc_tcp_server_port_fd_count(grpc_tcp_server *s, unsigned port_index); - -/* Returns the file descriptor of the Mth (fd_index) listening socket of the Nth - (port_index) call to add_port() on this server, or -1 if the indices are out - of bounds. The file descriptor remains owned by the server, and will be - cleaned up when the ref count reaches zero. */ -int grpc_tcp_server_port_fd(grpc_tcp_server *s, unsigned port_index, - unsigned fd_index); - -/* Ref s and return s. */ -grpc_tcp_server *grpc_tcp_server_ref(grpc_tcp_server *s); - -/* shutdown_starting is called when ref count has reached zero and the server is - about to be destroyed. The server will be deleted after it returns. Calling - grpc_tcp_server_ref() from it has no effect. */ -void grpc_tcp_server_shutdown_starting_add(grpc_tcp_server *s, - grpc_closure *shutdown_starting); - -/* If the refcount drops to zero, delete s, and call (exec_ctx==NULL) or enqueue - a call (exec_ctx!=NULL) to shutdown_complete. */ -void grpc_tcp_server_unref(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s); - -#endif /* GRPC_CORE_IOMGR_TCP_SERVER_H */ diff --git a/src/core/iomgr/tcp_server_posix.c b/src/core/iomgr/tcp_server_posix.c deleted file mode 100644 index 74ee68a6f1..0000000000 --- a/src/core/iomgr/tcp_server_posix.c +++ /dev/null @@ -1,607 +0,0 @@ -/* - * - * Copyright 2015-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. - * - */ - -/* FIXME: "posix" files shouldn't be depending on _GNU_SOURCE */ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include - -#ifdef GPR_POSIX_SOCKET - -#include "src/core/iomgr/tcp_server.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include "src/core/iomgr/pollset_posix.h" -#include "src/core/iomgr/resolve_address.h" -#include "src/core/iomgr/sockaddr_utils.h" -#include "src/core/iomgr/socket_utils_posix.h" -#include "src/core/iomgr/tcp_posix.h" -#include "src/core/iomgr/unix_sockets_posix.h" -#include "src/core/support/string.h" - -#define MIN_SAFE_ACCEPT_QUEUE_SIZE 100 - -static gpr_once s_init_max_accept_queue_size; -static int s_max_accept_queue_size; - -/* one listening port */ -typedef struct grpc_tcp_listener grpc_tcp_listener; -struct grpc_tcp_listener { - int fd; - grpc_fd *emfd; - grpc_tcp_server *server; - union { - uint8_t untyped[GRPC_MAX_SOCKADDR_SIZE]; - struct sockaddr sockaddr; - } addr; - size_t addr_len; - int port; - unsigned port_index; - unsigned fd_index; - grpc_closure read_closure; - grpc_closure destroyed_closure; - struct grpc_tcp_listener *next; - /* When we add a listener, more than one can be created, mainly because of - IPv6. A sibling will still be in the normal list, but will be flagged - as such. Any action, such as ref or unref, will affect all of the - siblings in the list. */ - struct grpc_tcp_listener *sibling; - int is_sibling; -}; - -/* the overall server */ -struct grpc_tcp_server { - gpr_refcount refs; - /* Called whenever accept() succeeds on a server port. */ - grpc_tcp_server_cb on_accept_cb; - void *on_accept_cb_arg; - - gpr_mu mu; - - /* active port count: how many ports are actually still listening */ - size_t active_ports; - /* destroyed port count: how many ports are completely destroyed */ - size_t destroyed_ports; - - /* is this server shutting down? (boolean) */ - int shutdown; - - /* linked list of server ports */ - grpc_tcp_listener *head; - grpc_tcp_listener *tail; - unsigned nports; - - /* List of closures passed to shutdown_starting_add(). */ - grpc_closure_list shutdown_starting; - - /* shutdown callback */ - grpc_closure *shutdown_complete; - - /* all pollsets interested in new connections */ - grpc_pollset **pollsets; - /* number of pollsets in the pollsets array */ - size_t pollset_count; -}; - -grpc_tcp_server *grpc_tcp_server_create(grpc_closure *shutdown_complete) { - grpc_tcp_server *s = gpr_malloc(sizeof(grpc_tcp_server)); - gpr_ref_init(&s->refs, 1); - gpr_mu_init(&s->mu); - s->active_ports = 0; - s->destroyed_ports = 0; - s->shutdown = 0; - s->shutdown_starting.head = NULL; - s->shutdown_starting.tail = NULL; - s->shutdown_complete = shutdown_complete; - s->on_accept_cb = NULL; - s->on_accept_cb_arg = NULL; - s->head = NULL; - s->tail = NULL; - s->nports = 0; - return s; -} - -static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { - if (s->shutdown_complete != NULL) { - grpc_exec_ctx_enqueue(exec_ctx, s->shutdown_complete, true, NULL); - } - - gpr_mu_destroy(&s->mu); - - while (s->head) { - grpc_tcp_listener *sp = s->head; - s->head = sp->next; - gpr_free(sp); - } - - gpr_free(s); -} - -static void destroyed_port(grpc_exec_ctx *exec_ctx, void *server, - bool success) { - grpc_tcp_server *s = server; - gpr_mu_lock(&s->mu); - s->destroyed_ports++; - if (s->destroyed_ports == s->nports) { - gpr_mu_unlock(&s->mu); - finish_shutdown(exec_ctx, s); - } else { - GPR_ASSERT(s->destroyed_ports < s->nports); - gpr_mu_unlock(&s->mu); - } -} - -/* called when all listening endpoints have been shutdown, so no further - events will be received on them - at this point it's safe to destroy - things */ -static void deactivated_all_ports(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { - /* delete ALL the things */ - gpr_mu_lock(&s->mu); - - if (!s->shutdown) { - gpr_mu_unlock(&s->mu); - return; - } - - if (s->head) { - grpc_tcp_listener *sp; - for (sp = s->head; sp; sp = sp->next) { - grpc_unlink_if_unix_domain_socket(&sp->addr.sockaddr); - sp->destroyed_closure.cb = destroyed_port; - sp->destroyed_closure.cb_arg = s; - grpc_fd_orphan(exec_ctx, sp->emfd, &sp->destroyed_closure, NULL, - "tcp_listener_shutdown"); - } - gpr_mu_unlock(&s->mu); - } else { - gpr_mu_unlock(&s->mu); - finish_shutdown(exec_ctx, s); - } -} - -static void tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { - gpr_mu_lock(&s->mu); - - GPR_ASSERT(!s->shutdown); - s->shutdown = 1; - - /* shutdown all fd's */ - if (s->active_ports) { - grpc_tcp_listener *sp; - for (sp = s->head; sp; sp = sp->next) { - grpc_fd_shutdown(exec_ctx, sp->emfd); - } - gpr_mu_unlock(&s->mu); - } else { - gpr_mu_unlock(&s->mu); - deactivated_all_ports(exec_ctx, s); - } -} - -/* get max listen queue size on linux */ -static void init_max_accept_queue_size(void) { - int n = SOMAXCONN; - char buf[64]; - FILE *fp = fopen("/proc/sys/net/core/somaxconn", "r"); - if (fp == NULL) { - /* 2.4 kernel. */ - s_max_accept_queue_size = SOMAXCONN; - return; - } - if (fgets(buf, sizeof buf, fp)) { - char *end; - long i = strtol(buf, &end, 10); - if (i > 0 && i <= INT_MAX && end && *end == 0) { - n = (int)i; - } - } - fclose(fp); - s_max_accept_queue_size = n; - - if (s_max_accept_queue_size < MIN_SAFE_ACCEPT_QUEUE_SIZE) { - gpr_log(GPR_INFO, - "Suspiciously small accept queue (%d) will probably lead to " - "connection drops", - s_max_accept_queue_size); - } -} - -static int get_max_accept_queue_size(void) { - gpr_once_init(&s_init_max_accept_queue_size, init_max_accept_queue_size); - return s_max_accept_queue_size; -} - -/* Prepare a recently-created socket for listening. */ -static int prepare_socket(int fd, const struct sockaddr *addr, - size_t addr_len) { - struct sockaddr_storage sockname_temp; - socklen_t sockname_len; - - if (fd < 0) { - goto error; - } - - if (!grpc_set_socket_nonblocking(fd, 1) || !grpc_set_socket_cloexec(fd, 1) || - (!grpc_is_unix_socket(addr) && (!grpc_set_socket_low_latency(fd, 1) || - !grpc_set_socket_reuse_addr(fd, 1))) || - !grpc_set_socket_no_sigpipe_if_possible(fd)) { - gpr_log(GPR_ERROR, "Unable to configure socket %d: %s", fd, - strerror(errno)); - goto error; - } - - GPR_ASSERT(addr_len < ~(socklen_t)0); - if (bind(fd, addr, (socklen_t)addr_len) < 0) { - char *addr_str; - grpc_sockaddr_to_string(&addr_str, addr, 0); - gpr_log(GPR_ERROR, "bind addr=%s: %s", addr_str, strerror(errno)); - gpr_free(addr_str); - goto error; - } - - if (listen(fd, get_max_accept_queue_size()) < 0) { - gpr_log(GPR_ERROR, "listen: %s", strerror(errno)); - goto error; - } - - sockname_len = sizeof(sockname_temp); - if (getsockname(fd, (struct sockaddr *)&sockname_temp, &sockname_len) < 0) { - goto error; - } - - return grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp); - -error: - if (fd >= 0) { - close(fd); - } - return -1; -} - -/* event manager callback when reads are ready */ -static void on_read(grpc_exec_ctx *exec_ctx, void *arg, bool success) { - grpc_tcp_listener *sp = arg; - grpc_tcp_server_acceptor acceptor = {sp->server, sp->port_index, - sp->fd_index}; - grpc_fd *fdobj; - size_t i; - - if (!success) { - goto error; - } - - /* loop until accept4 returns EAGAIN, and then re-arm notification */ - for (;;) { - struct sockaddr_storage addr; - socklen_t addrlen = sizeof(addr); - char *addr_str; - char *name; - /* Note: If we ever decide to return this address to the user, remember to - strip off the ::ffff:0.0.0.0/96 prefix first. */ - int fd = grpc_accept4(sp->fd, (struct sockaddr *)&addr, &addrlen, 1, 1); - if (fd < 0) { - switch (errno) { - case EINTR: - continue; - case EAGAIN: - grpc_fd_notify_on_read(exec_ctx, sp->emfd, &sp->read_closure); - return; - default: - gpr_log(GPR_ERROR, "Failed accept4: %s", strerror(errno)); - goto error; - } - } - - grpc_set_socket_no_sigpipe_if_possible(fd); - - addr_str = grpc_sockaddr_to_uri((struct sockaddr *)&addr); - gpr_asprintf(&name, "tcp-server-connection:%s", addr_str); - - if (grpc_tcp_trace) { - gpr_log(GPR_DEBUG, "SERVER_CONNECT: incoming connection: %s", addr_str); - } - - fdobj = grpc_fd_create(fd, name); - /* TODO(ctiller): revise this when we have server-side sharding - of channels -- we certainly should not be automatically adding every - incoming channel to every pollset owned by the server */ - for (i = 0; i < sp->server->pollset_count; i++) { - grpc_pollset_add_fd(exec_ctx, sp->server->pollsets[i], fdobj); - } - sp->server->on_accept_cb( - exec_ctx, sp->server->on_accept_cb_arg, - grpc_tcp_create(fdobj, GRPC_TCP_DEFAULT_READ_SLICE_SIZE, addr_str), - &acceptor); - - gpr_free(name); - gpr_free(addr_str); - } - - GPR_UNREACHABLE_CODE(return ); - -error: - gpr_mu_lock(&sp->server->mu); - if (0 == --sp->server->active_ports) { - gpr_mu_unlock(&sp->server->mu); - deactivated_all_ports(exec_ctx, sp->server); - } else { - gpr_mu_unlock(&sp->server->mu); - } -} - -static grpc_tcp_listener *add_socket_to_server(grpc_tcp_server *s, int fd, - const struct sockaddr *addr, - size_t addr_len, - unsigned port_index, - unsigned fd_index) { - grpc_tcp_listener *sp = NULL; - int port; - char *addr_str; - char *name; - - port = prepare_socket(fd, addr, addr_len); - if (port >= 0) { - grpc_sockaddr_to_string(&addr_str, (struct sockaddr *)&addr, 1); - gpr_asprintf(&name, "tcp-server-listener:%s", addr_str); - gpr_mu_lock(&s->mu); - s->nports++; - GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server"); - sp = gpr_malloc(sizeof(grpc_tcp_listener)); - sp->next = NULL; - if (s->head == NULL) { - s->head = sp; - } else { - s->tail->next = sp; - } - s->tail = sp; - sp->server = s; - sp->fd = fd; - sp->emfd = grpc_fd_create(fd, name); - memcpy(sp->addr.untyped, addr, addr_len); - sp->addr_len = addr_len; - sp->port = port; - sp->port_index = port_index; - sp->fd_index = fd_index; - sp->is_sibling = 0; - sp->sibling = NULL; - GPR_ASSERT(sp->emfd); - gpr_mu_unlock(&s->mu); - gpr_free(addr_str); - gpr_free(name); - } - - return sp; -} - -int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr, - size_t addr_len) { - grpc_tcp_listener *sp; - grpc_tcp_listener *sp2 = NULL; - int fd; - grpc_dualstack_mode dsmode; - struct sockaddr_in6 addr6_v4mapped; - struct sockaddr_in wild4; - struct sockaddr_in6 wild6; - struct sockaddr_in addr4_copy; - struct sockaddr *allocated_addr = NULL; - struct sockaddr_storage sockname_temp; - socklen_t sockname_len; - int port; - unsigned port_index = 0; - unsigned fd_index = 0; - if (s->tail != NULL) { - port_index = s->tail->port_index + 1; - } - grpc_unlink_if_unix_domain_socket((struct sockaddr *)addr); - - /* Check if this is a wildcard port, and if so, try to keep the port the same - as some previously created listener. */ - if (grpc_sockaddr_get_port(addr) == 0) { - for (sp = s->head; sp; sp = sp->next) { - sockname_len = sizeof(sockname_temp); - if (0 == getsockname(sp->fd, (struct sockaddr *)&sockname_temp, - &sockname_len)) { - port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp); - if (port > 0) { - allocated_addr = malloc(addr_len); - memcpy(allocated_addr, addr, addr_len); - grpc_sockaddr_set_port(allocated_addr, port); - addr = allocated_addr; - break; - } - } - } - } - - sp = NULL; - - if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) { - addr = (const struct sockaddr *)&addr6_v4mapped; - addr_len = sizeof(addr6_v4mapped); - } - - /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */ - if (grpc_sockaddr_is_wildcard(addr, &port)) { - grpc_sockaddr_make_wildcards(port, &wild4, &wild6); - - /* Try listening on IPv6 first. */ - addr = (struct sockaddr *)&wild6; - addr_len = sizeof(wild6); - fd = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode); - sp = add_socket_to_server(s, fd, addr, addr_len, port_index, fd_index); - if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) { - goto done; - } - if (sp != NULL) { - ++fd_index; - } - /* If we didn't get a dualstack socket, also listen on 0.0.0.0. */ - if (port == 0 && sp != NULL) { - grpc_sockaddr_set_port((struct sockaddr *)&wild4, sp->port); - } - addr = (struct sockaddr *)&wild4; - addr_len = sizeof(wild4); - } - - fd = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode); - if (fd < 0) { - gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno)); - } else { - if (dsmode == GRPC_DSMODE_IPV4 && - grpc_sockaddr_is_v4mapped(addr, &addr4_copy)) { - addr = (struct sockaddr *)&addr4_copy; - addr_len = sizeof(addr4_copy); - } - sp2 = sp; - sp = add_socket_to_server(s, fd, addr, addr_len, port_index, fd_index); - if (sp2 != NULL && sp != NULL) { - sp2->sibling = sp; - sp->is_sibling = 1; - } - } - -done: - gpr_free(allocated_addr); - if (sp != NULL) { - return sp->port; - } else { - return -1; - } -} - -unsigned grpc_tcp_server_port_fd_count(grpc_tcp_server *s, - unsigned port_index) { - unsigned num_fds = 0; - grpc_tcp_listener *sp; - for (sp = s->head; sp && port_index != 0; sp = sp->next) { - if (!sp->is_sibling) { - --port_index; - } - } - for (; sp; sp = sp->sibling, ++num_fds) - ; - return num_fds; -} - -int grpc_tcp_server_port_fd(grpc_tcp_server *s, unsigned port_index, - unsigned fd_index) { - grpc_tcp_listener *sp; - for (sp = s->head; sp && port_index != 0; sp = sp->next) { - if (!sp->is_sibling) { - --port_index; - } - } - for (; sp && fd_index != 0; sp = sp->sibling, --fd_index) - ; - if (sp) { - return sp->fd; - } else { - return -1; - } -} - -void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s, - grpc_pollset **pollsets, size_t pollset_count, - grpc_tcp_server_cb on_accept_cb, - void *on_accept_cb_arg) { - size_t i; - grpc_tcp_listener *sp; - GPR_ASSERT(on_accept_cb); - gpr_mu_lock(&s->mu); - GPR_ASSERT(!s->on_accept_cb); - GPR_ASSERT(s->active_ports == 0); - s->on_accept_cb = on_accept_cb; - s->on_accept_cb_arg = on_accept_cb_arg; - s->pollsets = pollsets; - s->pollset_count = pollset_count; - for (sp = s->head; sp; sp = sp->next) { - for (i = 0; i < pollset_count; i++) { - grpc_pollset_add_fd(exec_ctx, pollsets[i], sp->emfd); - } - sp->read_closure.cb = on_read; - sp->read_closure.cb_arg = sp; - grpc_fd_notify_on_read(exec_ctx, sp->emfd, &sp->read_closure); - s->active_ports++; - } - gpr_mu_unlock(&s->mu); -} - -grpc_tcp_server *grpc_tcp_server_ref(grpc_tcp_server *s) { - gpr_ref(&s->refs); - return s; -} - -void grpc_tcp_server_shutdown_starting_add(grpc_tcp_server *s, - grpc_closure *shutdown_starting) { - gpr_mu_lock(&s->mu); - grpc_closure_list_add(&s->shutdown_starting, shutdown_starting, 1); - gpr_mu_unlock(&s->mu); -} - -void grpc_tcp_server_unref(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { - if (gpr_unref(&s->refs)) { - /* Complete shutdown_starting work before destroying. */ - grpc_exec_ctx local_exec_ctx = GRPC_EXEC_CTX_INIT; - gpr_mu_lock(&s->mu); - grpc_exec_ctx_enqueue_list(&local_exec_ctx, &s->shutdown_starting, NULL); - gpr_mu_unlock(&s->mu); - if (exec_ctx == NULL) { - grpc_exec_ctx_flush(&local_exec_ctx); - tcp_server_destroy(&local_exec_ctx, s); - grpc_exec_ctx_finish(&local_exec_ctx); - } else { - grpc_exec_ctx_finish(&local_exec_ctx); - tcp_server_destroy(exec_ctx, s); - } - } -} - -#endif diff --git a/src/core/iomgr/tcp_server_windows.c b/src/core/iomgr/tcp_server_windows.c deleted file mode 100644 index a4abc5b974..0000000000 --- a/src/core/iomgr/tcp_server_windows.c +++ /dev/null @@ -1,557 +0,0 @@ -/* - * - * Copyright 2015-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 - -#ifdef GPR_WINSOCK_SOCKET - -#include - -#include "src/core/iomgr/sockaddr_utils.h" - -#include -#include -#include -#include -#include -#include - -#include "src/core/iomgr/iocp_windows.h" -#include "src/core/iomgr/pollset_windows.h" -#include "src/core/iomgr/socket_windows.h" -#include "src/core/iomgr/tcp_server.h" -#include "src/core/iomgr/tcp_windows.h" - -#define MIN_SAFE_ACCEPT_QUEUE_SIZE 100 - -/* one listening port */ -typedef struct grpc_tcp_listener grpc_tcp_listener; -struct grpc_tcp_listener { - /* This seemingly magic number comes from AcceptEx's documentation. each - address buffer needs to have at least 16 more bytes at their end. */ - uint8_t addresses[(sizeof(struct sockaddr_in6) + 16) * 2]; - /* This will hold the socket for the next accept. */ - SOCKET new_socket; - /* The listener winsocket. */ - grpc_winsocket *socket; - /* The actual TCP port number. */ - int port; - unsigned port_index; - grpc_tcp_server *server; - /* The cached AcceptEx for that port. */ - LPFN_ACCEPTEX AcceptEx; - int shutting_down; - /* closure for socket notification of accept being ready */ - grpc_closure on_accept; - /* linked list */ - struct grpc_tcp_listener *next; -}; - -/* the overall server */ -struct grpc_tcp_server { - gpr_refcount refs; - /* Called whenever accept() succeeds on a server port. */ - grpc_tcp_server_cb on_accept_cb; - void *on_accept_cb_arg; - - gpr_mu mu; - - /* active port count: how many ports are actually still listening */ - int active_ports; - - /* linked list of server ports */ - grpc_tcp_listener *head; - grpc_tcp_listener *tail; - - /* List of closures passed to shutdown_starting_add(). */ - grpc_closure_list shutdown_starting; - - /* shutdown callback */ - grpc_closure *shutdown_complete; -}; - -/* Public function. Allocates the proper data structures to hold a - grpc_tcp_server. */ -grpc_tcp_server *grpc_tcp_server_create(grpc_closure *shutdown_complete) { - grpc_tcp_server *s = gpr_malloc(sizeof(grpc_tcp_server)); - gpr_ref_init(&s->refs, 1); - gpr_mu_init(&s->mu); - s->active_ports = 0; - s->on_accept_cb = NULL; - s->on_accept_cb_arg = NULL; - s->head = NULL; - s->tail = NULL; - s->shutdown_starting.head = NULL; - s->shutdown_starting.tail = NULL; - s->shutdown_complete = shutdown_complete; - return s; -} - -static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { - if (s->shutdown_complete != NULL) { - grpc_exec_ctx_enqueue(exec_ctx, s->shutdown_complete, true, NULL); - } - - /* Now that the accepts have been aborted, we can destroy the sockets. - The IOCP won't get notified on these, so we can flag them as already - closed by the system. */ - while (s->head) { - grpc_tcp_listener *sp = s->head; - s->head = sp->next; - sp->next = NULL; - grpc_winsocket_destroy(sp->socket); - gpr_free(sp); - } - gpr_free(s); -} - -grpc_tcp_server *grpc_tcp_server_ref(grpc_tcp_server *s) { - gpr_ref(&s->refs); - return s; -} - -void grpc_tcp_server_shutdown_starting_add(grpc_tcp_server *s, - grpc_closure *shutdown_starting) { - gpr_mu_lock(&s->mu); - grpc_closure_list_add(&s->shutdown_starting, shutdown_starting, 1); - gpr_mu_unlock(&s->mu); -} - -static void tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { - int immediately_done = 0; - grpc_tcp_listener *sp; - gpr_mu_lock(&s->mu); - - /* First, shutdown all fd's. This will queue abortion calls for all - of the pending accepts due to the normal operation mechanism. */ - if (s->active_ports == 0) { - immediately_done = 1; - } - for (sp = s->head; sp; sp = sp->next) { - sp->shutting_down = 1; - grpc_winsocket_shutdown(sp->socket); - } - gpr_mu_unlock(&s->mu); - - if (immediately_done) { - finish_shutdown(exec_ctx, s); - } -} - -void grpc_tcp_server_unref(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { - if (gpr_unref(&s->refs)) { - /* Complete shutdown_starting work before destroying. */ - grpc_exec_ctx local_exec_ctx = GRPC_EXEC_CTX_INIT; - gpr_mu_lock(&s->mu); - grpc_exec_ctx_enqueue_list(&local_exec_ctx, &s->shutdown_starting, NULL); - gpr_mu_unlock(&s->mu); - if (exec_ctx == NULL) { - grpc_exec_ctx_flush(&local_exec_ctx); - tcp_server_destroy(&local_exec_ctx, s); - grpc_exec_ctx_finish(&local_exec_ctx); - } else { - grpc_exec_ctx_finish(&local_exec_ctx); - tcp_server_destroy(exec_ctx, s); - } - } -} - -/* Prepare (bind) a recently-created socket for listening. */ -static int prepare_socket(SOCKET sock, const struct sockaddr *addr, - size_t addr_len) { - struct sockaddr_storage sockname_temp; - socklen_t sockname_len; - - if (sock == INVALID_SOCKET) goto error; - - if (!grpc_tcp_prepare_socket(sock)) { - char *utf8_message = gpr_format_message(WSAGetLastError()); - gpr_log(GPR_ERROR, "Unable to prepare socket: %s", utf8_message); - gpr_free(utf8_message); - goto error; - } - - if (bind(sock, addr, (int)addr_len) == SOCKET_ERROR) { - char *addr_str; - char *utf8_message = gpr_format_message(WSAGetLastError()); - grpc_sockaddr_to_string(&addr_str, addr, 0); - gpr_log(GPR_ERROR, "bind addr=%s: %s", addr_str, utf8_message); - gpr_free(utf8_message); - gpr_free(addr_str); - goto error; - } - - if (listen(sock, SOMAXCONN) == SOCKET_ERROR) { - char *utf8_message = gpr_format_message(WSAGetLastError()); - gpr_log(GPR_ERROR, "listen: %s", utf8_message); - gpr_free(utf8_message); - goto error; - } - - sockname_len = sizeof(sockname_temp); - if (getsockname(sock, (struct sockaddr *)&sockname_temp, &sockname_len) == - SOCKET_ERROR) { - char *utf8_message = gpr_format_message(WSAGetLastError()); - gpr_log(GPR_ERROR, "getsockname: %s", utf8_message); - gpr_free(utf8_message); - goto error; - } - - return grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp); - -error: - if (sock != INVALID_SOCKET) closesocket(sock); - return -1; -} - -static void decrement_active_ports_and_notify(grpc_exec_ctx *exec_ctx, - grpc_tcp_listener *sp) { - int notify = 0; - sp->shutting_down = 0; - gpr_mu_lock(&sp->server->mu); - GPR_ASSERT(sp->server->active_ports > 0); - if (0 == --sp->server->active_ports) { - notify = 1; - } - gpr_mu_unlock(&sp->server->mu); - if (notify) { - finish_shutdown(exec_ctx, sp->server); - } -} - -/* In order to do an async accept, we need to create a socket first which - will be the one assigned to the new incoming connection. */ -static void start_accept(grpc_exec_ctx *exec_ctx, grpc_tcp_listener *port) { - SOCKET sock = INVALID_SOCKET; - char *message; - char *utf8_message; - BOOL success; - DWORD addrlen = sizeof(struct sockaddr_in6) + 16; - DWORD bytes_received = 0; - - sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0, - WSA_FLAG_OVERLAPPED); - - if (sock == INVALID_SOCKET) { - message = "Unable to create socket: %s"; - goto failure; - } - - if (!grpc_tcp_prepare_socket(sock)) { - message = "Unable to prepare socket: %s"; - goto failure; - } - - /* Start the "accept" asynchronously. */ - success = port->AcceptEx(port->socket->socket, sock, port->addresses, 0, - addrlen, addrlen, &bytes_received, - &port->socket->read_info.overlapped); - - /* It is possible to get an accept immediately without delay. However, we - will still get an IOCP notification for it. So let's just ignore it. */ - if (!success) { - int error = WSAGetLastError(); - if (error != ERROR_IO_PENDING) { - message = "AcceptEx failed: %s"; - goto failure; - } - } - - /* We're ready to do the accept. Calling grpc_socket_notify_on_read may - immediately process an accept that happened in the meantime. */ - port->new_socket = sock; - grpc_socket_notify_on_read(exec_ctx, port->socket, &port->on_accept); - return; - -failure: - if (port->shutting_down) { - /* We are abandoning the listener port, take that into account to prevent - occasional hangs on shutdown. The hang happens when sp->shutting_down - change is not seen by on_accept and we proceed to trying new accept, - but we fail there because the listening port has been closed in the - meantime. */ - decrement_active_ports_and_notify(exec_ctx, port); - return; - } - utf8_message = gpr_format_message(WSAGetLastError()); - gpr_log(GPR_ERROR, message, utf8_message); - gpr_free(utf8_message); - if (sock != INVALID_SOCKET) closesocket(sock); -} - -/* Event manager callback when reads are ready. */ -static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, bool from_iocp) { - grpc_tcp_listener *sp = arg; - grpc_tcp_server_acceptor acceptor = {sp->server, sp->port_index, 0}; - SOCKET sock = sp->new_socket; - grpc_winsocket_callback_info *info = &sp->socket->read_info; - grpc_endpoint *ep = NULL; - struct sockaddr_storage peer_name; - char *peer_name_string; - char *fd_name; - int peer_name_len = sizeof(peer_name); - DWORD transfered_bytes; - DWORD flags; - BOOL wsa_success; - int err; - - /* The general mechanism for shutting down is to queue abortion calls. While - this is necessary in the read/write case, it's useless for the accept - case. We only need to adjust the pending callback count */ - if (!from_iocp) { - return; - } - - /* The IOCP notified us of a completed operation. Let's grab the results, - and act accordingly. */ - transfered_bytes = 0; - wsa_success = WSAGetOverlappedResult(sock, &info->overlapped, - &transfered_bytes, FALSE, &flags); - if (!wsa_success) { - if (sp->shutting_down) { - /* During the shutdown case, we ARE expecting an error. So that's well, - and we can wake up the shutdown thread. */ - decrement_active_ports_and_notify(exec_ctx, sp); - return; - } else { - char *utf8_message = gpr_format_message(WSAGetLastError()); - gpr_log(GPR_ERROR, "on_accept error: %s", utf8_message); - gpr_free(utf8_message); - closesocket(sock); - } - } else { - if (!sp->shutting_down) { - peer_name_string = NULL; - err = setsockopt(sock, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, - (char *)&sp->socket->socket, sizeof(sp->socket->socket)); - if (err) { - char *utf8_message = gpr_format_message(WSAGetLastError()); - gpr_log(GPR_ERROR, "setsockopt error: %s", utf8_message); - gpr_free(utf8_message); - } - err = getpeername(sock, (struct sockaddr *)&peer_name, &peer_name_len); - if (!err) { - peer_name_string = grpc_sockaddr_to_uri((struct sockaddr *)&peer_name); - } else { - char *utf8_message = gpr_format_message(WSAGetLastError()); - gpr_log(GPR_ERROR, "getpeername error: %s", utf8_message); - gpr_free(utf8_message); - } - gpr_asprintf(&fd_name, "tcp_server:%s", peer_name_string); - ep = grpc_tcp_create(grpc_winsocket_create(sock, fd_name), - peer_name_string); - gpr_free(fd_name); - gpr_free(peer_name_string); - } else { - closesocket(sock); - } - } - - /* The only time we should call our callback, is where we successfully - managed to accept a connection, and created an endpoint. */ - if (ep) - sp->server->on_accept_cb(exec_ctx, sp->server->on_accept_cb_arg, ep, - &acceptor); - /* As we were notified from the IOCP of one and exactly one accept, - the former socked we created has now either been destroy or assigned - to the new connection. We need to create a new one for the next - connection. */ - start_accept(exec_ctx, sp); -} - -static grpc_tcp_listener *add_socket_to_server(grpc_tcp_server *s, SOCKET sock, - const struct sockaddr *addr, - size_t addr_len, - unsigned port_index) { - grpc_tcp_listener *sp = NULL; - int port; - int status; - GUID guid = WSAID_ACCEPTEX; - DWORD ioctl_num_bytes; - LPFN_ACCEPTEX AcceptEx; - - if (sock == INVALID_SOCKET) return NULL; - - /* We need to grab the AcceptEx pointer for that port, as it may be - interface-dependent. We'll cache it to avoid doing that again. */ - status = - WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid), - &AcceptEx, sizeof(AcceptEx), &ioctl_num_bytes, NULL, NULL); - - if (status != 0) { - char *utf8_message = gpr_format_message(WSAGetLastError()); - gpr_log(GPR_ERROR, "on_connect error: %s", utf8_message); - gpr_free(utf8_message); - closesocket(sock); - return NULL; - } - - port = prepare_socket(sock, addr, addr_len); - if (port >= 0) { - gpr_mu_lock(&s->mu); - GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server"); - sp = gpr_malloc(sizeof(grpc_tcp_listener)); - sp->next = NULL; - if (s->head == NULL) { - s->head = sp; - } else { - s->tail->next = sp; - } - s->tail = sp; - sp->server = s; - sp->socket = grpc_winsocket_create(sock, "listener"); - sp->shutting_down = 0; - sp->AcceptEx = AcceptEx; - sp->new_socket = INVALID_SOCKET; - sp->port = port; - sp->port_index = port_index; - grpc_closure_init(&sp->on_accept, on_accept, sp); - GPR_ASSERT(sp->socket); - gpr_mu_unlock(&s->mu); - } - - return sp; -} - -int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr, - size_t addr_len) { - grpc_tcp_listener *sp; - SOCKET sock; - struct sockaddr_in6 addr6_v4mapped; - struct sockaddr_in6 wildcard; - struct sockaddr *allocated_addr = NULL; - struct sockaddr_storage sockname_temp; - socklen_t sockname_len; - int port; - unsigned port_index = 0; - if (s->tail != NULL) { - port_index = s->tail->port_index + 1; - } - - /* Check if this is a wildcard port, and if so, try to keep the port the same - as some previously created listener. */ - if (grpc_sockaddr_get_port(addr) == 0) { - for (sp = s->head; sp; sp = sp->next) { - sockname_len = sizeof(sockname_temp); - if (0 == getsockname(sp->socket->socket, - (struct sockaddr *)&sockname_temp, &sockname_len)) { - port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp); - if (port > 0) { - allocated_addr = malloc(addr_len); - memcpy(allocated_addr, addr, addr_len); - grpc_sockaddr_set_port(allocated_addr, port); - addr = allocated_addr; - break; - } - } - } - } - - if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) { - addr = (const struct sockaddr *)&addr6_v4mapped; - addr_len = sizeof(addr6_v4mapped); - } - - /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */ - if (grpc_sockaddr_is_wildcard(addr, &port)) { - grpc_sockaddr_make_wildcard6(port, &wildcard); - - addr = (struct sockaddr *)&wildcard; - addr_len = sizeof(wildcard); - } - - sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0, - WSA_FLAG_OVERLAPPED); - if (sock == INVALID_SOCKET) { - char *utf8_message = gpr_format_message(WSAGetLastError()); - gpr_log(GPR_ERROR, "unable to create socket: %s", utf8_message); - gpr_free(utf8_message); - } - - sp = add_socket_to_server(s, sock, addr, addr_len, port_index); - gpr_free(allocated_addr); - - if (sp) { - return sp->port; - } else { - return -1; - } -} - -unsigned grpc_tcp_server_port_fd_count(grpc_tcp_server *s, - unsigned port_index) { - grpc_tcp_listener *sp; - for (sp = s->head; sp && port_index != 0; sp = sp->next, --port_index) - ; - if (sp) { - return 1; - } else { - return 0; - } -} - -int grpc_tcp_server_port_fd(grpc_tcp_server *s, unsigned port_index, - unsigned fd_index) { - grpc_tcp_listener *sp; - if (fd_index != 0) { - /* Windows implementation has only one fd per port_index. */ - return -1; - } - for (sp = s->head; sp && port_index != 0; sp = sp->next, --port_index) - ; - if (sp) { - return _open_osfhandle((intptr_t)sp->socket->socket, 0); - } else { - return -1; - } -} - -void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s, - grpc_pollset **pollset, size_t pollset_count, - grpc_tcp_server_cb on_accept_cb, - void *on_accept_cb_arg) { - grpc_tcp_listener *sp; - GPR_ASSERT(on_accept_cb); - gpr_mu_lock(&s->mu); - GPR_ASSERT(!s->on_accept_cb); - GPR_ASSERT(s->active_ports == 0); - s->on_accept_cb = on_accept_cb; - s->on_accept_cb_arg = on_accept_cb_arg; - for (sp = s->head; sp; sp = sp->next) { - start_accept(exec_ctx, sp); - s->active_ports++; - } - gpr_mu_unlock(&s->mu); -} - -#endif /* GPR_WINSOCK_SOCKET */ diff --git a/src/core/iomgr/tcp_windows.c b/src/core/iomgr/tcp_windows.c deleted file mode 100644 index 9b1db5fa7e..0000000000 --- a/src/core/iomgr/tcp_windows.c +++ /dev/null @@ -1,402 +0,0 @@ -/* - * - * Copyright 2015-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 - -#ifdef GPR_WINSOCK_SOCKET - -#include "src/core/iomgr/sockaddr_win32.h" - -#include -#include -#include -#include -#include -#include - -#include "src/core/iomgr/iocp_windows.h" -#include "src/core/iomgr/sockaddr.h" -#include "src/core/iomgr/sockaddr_utils.h" -#include "src/core/iomgr/socket_windows.h" -#include "src/core/iomgr/tcp_client.h" -#include "src/core/iomgr/timer.h" - -static int set_non_block(SOCKET sock) { - int status; - unsigned long param = 1; - DWORD ret; - status = - WSAIoctl(sock, FIONBIO, ¶m, sizeof(param), NULL, 0, &ret, NULL, NULL); - return status == 0; -} - -static int set_dualstack(SOCKET sock) { - int status; - unsigned long param = 0; - status = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)¶m, - sizeof(param)); - return status == 0; -} - -int grpc_tcp_prepare_socket(SOCKET sock) { - if (!set_non_block(sock)) return 0; - if (!set_dualstack(sock)) return 0; - return 1; -} - -typedef struct grpc_tcp { - /* This is our C++ class derivation emulation. */ - grpc_endpoint base; - /* The one socket this endpoint is using. */ - grpc_winsocket *socket; - /* Refcounting how many operations are in progress. */ - gpr_refcount refcount; - - grpc_closure on_read; - grpc_closure on_write; - - grpc_closure *read_cb; - grpc_closure *write_cb; - gpr_slice read_slice; - gpr_slice_buffer *write_slices; - gpr_slice_buffer *read_slices; - - /* The IO Completion Port runs from another thread. We need some mechanism - to protect ourselves when requesting a shutdown. */ - gpr_mu mu; - int shutting_down; - - char *peer_string; -} grpc_tcp; - -static void tcp_free(grpc_tcp *tcp) { - grpc_winsocket_destroy(tcp->socket); - gpr_mu_destroy(&tcp->mu); - gpr_free(tcp->peer_string); - gpr_free(tcp); -} - -/*#define GRPC_TCP_REFCOUNT_DEBUG*/ -#ifdef GRPC_TCP_REFCOUNT_DEBUG -#define TCP_UNREF(tcp, reason) tcp_unref((tcp), (reason), __FILE__, __LINE__) -#define TCP_REF(tcp, reason) tcp_ref((tcp), (reason), __FILE__, __LINE__) -static void tcp_unref(grpc_tcp *tcp, const char *reason, const char *file, - int line) { - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP unref %p : %s %d -> %d", tcp, - reason, tcp->refcount.count, tcp->refcount.count - 1); - if (gpr_unref(&tcp->refcount)) { - tcp_free(tcp); - } -} - -static void tcp_ref(grpc_tcp *tcp, const char *reason, const char *file, - int line) { - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP ref %p : %s %d -> %d", tcp, - reason, tcp->refcount.count, tcp->refcount.count + 1); - gpr_ref(&tcp->refcount); -} -#else -#define TCP_UNREF(tcp, reason) tcp_unref((tcp)) -#define TCP_REF(tcp, reason) tcp_ref((tcp)) -static void tcp_unref(grpc_tcp *tcp) { - if (gpr_unref(&tcp->refcount)) { - tcp_free(tcp); - } -} - -static void tcp_ref(grpc_tcp *tcp) { gpr_ref(&tcp->refcount); } -#endif - -/* Asynchronous callback from the IOCP, or the background thread. */ -static void on_read(grpc_exec_ctx *exec_ctx, void *tcpp, bool success) { - grpc_tcp *tcp = tcpp; - grpc_closure *cb = tcp->read_cb; - grpc_winsocket *socket = tcp->socket; - gpr_slice sub; - grpc_winsocket_callback_info *info = &socket->read_info; - - if (success) { - if (info->wsa_error != 0 && !tcp->shutting_down) { - if (info->wsa_error != WSAECONNRESET) { - char *utf8_message = gpr_format_message(info->wsa_error); - gpr_log(GPR_ERROR, "ReadFile overlapped error: %s", utf8_message); - gpr_free(utf8_message); - } - success = 0; - gpr_slice_unref(tcp->read_slice); - } else { - if (info->bytes_transfered != 0 && !tcp->shutting_down) { - sub = gpr_slice_sub_no_ref(tcp->read_slice, 0, info->bytes_transfered); - gpr_slice_buffer_add(tcp->read_slices, sub); - success = 1; - } else { - gpr_slice_unref(tcp->read_slice); - success = 0; - } - } - } - - tcp->read_cb = NULL; - TCP_UNREF(tcp, "read"); - if (cb) { - cb->cb(exec_ctx, cb->cb_arg, success); - } -} - -static void win_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, - gpr_slice_buffer *read_slices, grpc_closure *cb) { - grpc_tcp *tcp = (grpc_tcp *)ep; - grpc_winsocket *handle = tcp->socket; - grpc_winsocket_callback_info *info = &handle->read_info; - int status; - DWORD bytes_read = 0; - DWORD flags = 0; - WSABUF buffer; - - if (tcp->shutting_down) { - grpc_exec_ctx_enqueue(exec_ctx, cb, false, NULL); - return; - } - - tcp->read_cb = cb; - tcp->read_slices = read_slices; - gpr_slice_buffer_reset_and_unref(read_slices); - - tcp->read_slice = gpr_slice_malloc(8192); - - buffer.len = (ULONG)GPR_SLICE_LENGTH( - tcp->read_slice); // we know slice size fits in 32bit. - buffer.buf = (char *)GPR_SLICE_START_PTR(tcp->read_slice); - - TCP_REF(tcp, "read"); - - /* First let's try a synchronous, non-blocking read. */ - status = - WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags, NULL, NULL); - info->wsa_error = status == 0 ? 0 : WSAGetLastError(); - - /* Did we get data immediately ? Yay. */ - if (info->wsa_error != WSAEWOULDBLOCK) { - info->bytes_transfered = bytes_read; - grpc_exec_ctx_enqueue(exec_ctx, &tcp->on_read, true, NULL); - return; - } - - /* Otherwise, let's retry, by queuing a read. */ - memset(&tcp->socket->read_info.overlapped, 0, sizeof(OVERLAPPED)); - status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags, - &info->overlapped, NULL); - - if (status != 0) { - int wsa_error = WSAGetLastError(); - if (wsa_error != WSA_IO_PENDING) { - info->wsa_error = wsa_error; - grpc_exec_ctx_enqueue(exec_ctx, &tcp->on_read, false, NULL); - return; - } - } - - grpc_socket_notify_on_read(exec_ctx, tcp->socket, &tcp->on_read); -} - -/* Asynchronous callback from the IOCP, or the background thread. */ -static void on_write(grpc_exec_ctx *exec_ctx, void *tcpp, bool success) { - grpc_tcp *tcp = (grpc_tcp *)tcpp; - grpc_winsocket *handle = tcp->socket; - grpc_winsocket_callback_info *info = &handle->write_info; - grpc_closure *cb; - - gpr_mu_lock(&tcp->mu); - cb = tcp->write_cb; - tcp->write_cb = NULL; - gpr_mu_unlock(&tcp->mu); - - if (success) { - if (info->wsa_error != 0) { - if (info->wsa_error != WSAECONNRESET) { - char *utf8_message = gpr_format_message(info->wsa_error); - gpr_log(GPR_ERROR, "WSASend overlapped error: %s", utf8_message); - gpr_free(utf8_message); - } - success = 0; - } else { - GPR_ASSERT(info->bytes_transfered == tcp->write_slices->length); - } - } - - TCP_UNREF(tcp, "write"); - cb->cb(exec_ctx, cb->cb_arg, success); -} - -/* Initiates a write. */ -static void win_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, - gpr_slice_buffer *slices, grpc_closure *cb) { - grpc_tcp *tcp = (grpc_tcp *)ep; - grpc_winsocket *socket = tcp->socket; - grpc_winsocket_callback_info *info = &socket->write_info; - unsigned i; - DWORD bytes_sent; - int status; - WSABUF local_buffers[16]; - WSABUF *allocated = NULL; - WSABUF *buffers = local_buffers; - size_t len; - - if (tcp->shutting_down) { - grpc_exec_ctx_enqueue(exec_ctx, cb, false, NULL); - return; - } - - tcp->write_cb = cb; - tcp->write_slices = slices; - GPR_ASSERT(tcp->write_slices->count <= UINT_MAX); - if (tcp->write_slices->count > GPR_ARRAY_SIZE(local_buffers)) { - buffers = (WSABUF *)gpr_malloc(sizeof(WSABUF) * tcp->write_slices->count); - allocated = buffers; - } - - for (i = 0; i < tcp->write_slices->count; i++) { - len = GPR_SLICE_LENGTH(tcp->write_slices->slices[i]); - GPR_ASSERT(len <= ULONG_MAX); - buffers[i].len = (ULONG)len; - buffers[i].buf = (char *)GPR_SLICE_START_PTR(tcp->write_slices->slices[i]); - } - - /* First, let's try a synchronous, non-blocking write. */ - status = WSASend(socket->socket, buffers, (DWORD)tcp->write_slices->count, - &bytes_sent, 0, NULL, NULL); - info->wsa_error = status == 0 ? 0 : WSAGetLastError(); - - /* We would kind of expect to get a WSAEWOULDBLOCK here, especially on a busy - connection that has its send queue filled up. But if we don't, then we can - avoid doing an async write operation at all. */ - if (info->wsa_error != WSAEWOULDBLOCK) { - bool ok = false; - if (status == 0) { - ok = true; - GPR_ASSERT(bytes_sent == tcp->write_slices->length); - } else { - if (info->wsa_error != WSAECONNRESET) { - char *utf8_message = gpr_format_message(info->wsa_error); - gpr_log(GPR_ERROR, "WSASend error: %s", utf8_message); - gpr_free(utf8_message); - } - } - if (allocated) gpr_free(allocated); - grpc_exec_ctx_enqueue(exec_ctx, cb, ok, NULL); - return; - } - - TCP_REF(tcp, "write"); - - /* If we got a WSAEWOULDBLOCK earlier, then we need to re-do the same - operation, this time asynchronously. */ - memset(&socket->write_info.overlapped, 0, sizeof(OVERLAPPED)); - status = WSASend(socket->socket, buffers, (DWORD)tcp->write_slices->count, - &bytes_sent, 0, &socket->write_info.overlapped, NULL); - if (allocated) gpr_free(allocated); - - if (status != 0) { - int wsa_error = WSAGetLastError(); - if (wsa_error != WSA_IO_PENDING) { - TCP_UNREF(tcp, "write"); - grpc_exec_ctx_enqueue(exec_ctx, cb, false, NULL); - return; - } - } - - /* As all is now setup, we can now ask for the IOCP notification. It may - trigger the callback immediately however, but no matter. */ - grpc_socket_notify_on_write(exec_ctx, socket, &tcp->on_write); -} - -static void win_add_to_pollset(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, - grpc_pollset *ps) { - grpc_tcp *tcp; - (void)ps; - tcp = (grpc_tcp *)ep; - grpc_iocp_add_socket(tcp->socket); -} - -static void win_add_to_pollset_set(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, - grpc_pollset_set *pss) { - grpc_tcp *tcp; - (void)pss; - tcp = (grpc_tcp *)ep; - grpc_iocp_add_socket(tcp->socket); -} - -/* Initiates a shutdown of the TCP endpoint. This will queue abort callbacks - for the potential read and write operations. It is up to the caller to - guarantee this isn't called in parallel to a read or write request, so - we're not going to protect against these. However the IO Completion Port - callback will happen from another thread, so we need to protect against - concurrent access of the data structure in that regard. */ -static void win_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) { - grpc_tcp *tcp = (grpc_tcp *)ep; - gpr_mu_lock(&tcp->mu); - /* At that point, what may happen is that we're already inside the IOCP - callback. See the comments in on_read and on_write. */ - tcp->shutting_down = 1; - grpc_winsocket_shutdown(tcp->socket); - gpr_mu_unlock(&tcp->mu); -} - -static void win_destroy(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) { - grpc_tcp *tcp = (grpc_tcp *)ep; - TCP_UNREF(tcp, "destroy"); -} - -static char *win_get_peer(grpc_endpoint *ep) { - grpc_tcp *tcp = (grpc_tcp *)ep; - return gpr_strdup(tcp->peer_string); -} - -static grpc_endpoint_vtable vtable = { - win_read, win_write, win_add_to_pollset, win_add_to_pollset_set, - win_shutdown, win_destroy, win_get_peer}; - -grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket, char *peer_string) { - grpc_tcp *tcp = (grpc_tcp *)gpr_malloc(sizeof(grpc_tcp)); - memset(tcp, 0, sizeof(grpc_tcp)); - tcp->base.vtable = &vtable; - tcp->socket = socket; - gpr_mu_init(&tcp->mu); - gpr_ref_init(&tcp->refcount, 1); - grpc_closure_init(&tcp->on_read, on_read, tcp); - grpc_closure_init(&tcp->on_write, on_write, tcp); - tcp->peer_string = gpr_strdup(peer_string); - return &tcp->base; -} - -#endif /* GPR_WINSOCK_SOCKET */ diff --git a/src/core/iomgr/tcp_windows.h b/src/core/iomgr/tcp_windows.h deleted file mode 100644 index 78bc13389a..0000000000 --- a/src/core/iomgr/tcp_windows.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * - * Copyright 2015-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_IOMGR_TCP_WINDOWS_H -#define GRPC_CORE_IOMGR_TCP_WINDOWS_H -/* - Low level TCP "bottom half" implementation, for use by transports built on - top of a TCP connection. - - Note that this file does not (yet) include APIs for creating the socket in - the first place. - - All calls passing slice transfer ownership of a slice refcount unless - otherwise specified. -*/ - -#include "src/core/iomgr/endpoint.h" -#include "src/core/iomgr/socket_windows.h" - -/* Create a tcp endpoint given a winsock handle. - * Takes ownership of the handle. - */ -grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket, char *peer_string); - -int grpc_tcp_prepare_socket(SOCKET sock); - -#endif /* GRPC_CORE_IOMGR_TCP_WINDOWS_H */ diff --git a/src/core/iomgr/time_averaged_stats.c b/src/core/iomgr/time_averaged_stats.c deleted file mode 100644 index e075db4373..0000000000 --- a/src/core/iomgr/time_averaged_stats.c +++ /dev/null @@ -1,77 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/iomgr/time_averaged_stats.h" - -void grpc_time_averaged_stats_init(grpc_time_averaged_stats* stats, - double init_avg, double regress_weight, - double persistence_factor) { - stats->init_avg = init_avg; - stats->regress_weight = regress_weight; - stats->persistence_factor = persistence_factor; - stats->batch_total_value = 0; - stats->batch_num_samples = 0; - stats->aggregate_total_weight = 0; - stats->aggregate_weighted_avg = init_avg; -} - -void grpc_time_averaged_stats_add_sample(grpc_time_averaged_stats* stats, - double value) { - stats->batch_total_value += value; - ++stats->batch_num_samples; -} - -double grpc_time_averaged_stats_update_average( - grpc_time_averaged_stats* stats) { - /* Start with the current batch: */ - double weighted_sum = stats->batch_total_value; - double total_weight = stats->batch_num_samples; - if (stats->regress_weight > 0) { - /* Add in the regression towards init_avg_: */ - weighted_sum += stats->regress_weight * stats->init_avg; - total_weight += stats->regress_weight; - } - if (stats->persistence_factor > 0) { - /* Add in the persistence: */ - const double prev_sample_weight = - stats->persistence_factor * stats->aggregate_total_weight; - weighted_sum += prev_sample_weight * stats->aggregate_weighted_avg; - total_weight += prev_sample_weight; - } - stats->aggregate_weighted_avg = - (total_weight > 0) ? (weighted_sum / total_weight) : stats->init_avg; - stats->aggregate_total_weight = total_weight; - stats->batch_num_samples = 0; - stats->batch_total_value = 0; - return stats->aggregate_weighted_avg; -} diff --git a/src/core/iomgr/time_averaged_stats.h b/src/core/iomgr/time_averaged_stats.h deleted file mode 100644 index 048e244bcc..0000000000 --- a/src/core/iomgr/time_averaged_stats.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * - * Copyright 2015-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_IOMGR_TIME_AVERAGED_STATS_H -#define GRPC_CORE_IOMGR_TIME_AVERAGED_STATS_H - -/* This tracks a time-decaying weighted average. It works by collecting - batches of samples and then mixing their average into a time-decaying - weighted mean. It is designed for batch operations where we do many adds - before updating the average. */ - -typedef struct { - /* The initial average value. This is the reported average until the first - grpc_time_averaged_stats_update_average call. If a positive regress_weight - is used, we also regress towards this value on each update. */ - double init_avg; - /* The sample weight of "init_avg" that is mixed in with each call to - grpc_time_averaged_stats_update_average. If the calls to - grpc_time_averaged_stats_add_sample stop, this will cause the average to - regress back to the mean. This should be non-negative. Set it to 0 to - disable the bias. A value of 1 has the effect of adding in 1 bonus sample - with value init_avg to each sample period. */ - double regress_weight; - /* This determines the rate of decay of the time-averaging from one period - to the next by scaling the aggregate_total_weight of samples from prior - periods when combining with the latest period. It should be in the range - [0,1]. A higher value adapts more slowly. With a value of 0.5, if the - batches each have k samples, the samples_in_avg_ will grow to 2 k, so the - weighting of the time average will eventually be 1/3 new batch and 2/3 - old average. */ - double persistence_factor; - - /* The total value of samples since the last UpdateAverage(). */ - double batch_total_value; - /* The number of samples since the last UpdateAverage(). */ - double batch_num_samples; - /* The time-decayed sum of batch_num_samples_ over previous batches. This is - the "weight" of the old aggregate_weighted_avg_ when updating the - average. */ - double aggregate_total_weight; - /* A time-decayed average of the (batch_total_value_ / batch_num_samples_), - computed by decaying the samples_in_avg_ weight in the weighted average. */ - double aggregate_weighted_avg; -} grpc_time_averaged_stats; - -/* See the comments on the members above for an explanation of init_avg, - regress_weight, and persistence_factor. */ -void grpc_time_averaged_stats_init(grpc_time_averaged_stats* stats, - double init_avg, double regress_weight, - double persistence_factor); -/* Add a sample to the current batch. */ -void grpc_time_averaged_stats_add_sample(grpc_time_averaged_stats* stats, - double value); -/* Complete a batch and compute the new estimate of the average sample - value. */ -double grpc_time_averaged_stats_update_average(grpc_time_averaged_stats* stats); - -#endif /* GRPC_CORE_IOMGR_TIME_AVERAGED_STATS_H */ diff --git a/src/core/iomgr/timer.c b/src/core/iomgr/timer.c deleted file mode 100644 index f444643428..0000000000 --- a/src/core/iomgr/timer.c +++ /dev/null @@ -1,356 +0,0 @@ -/* - * - * Copyright 2015-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/iomgr/timer.h" - -#include -#include -#include -#include "src/core/iomgr/time_averaged_stats.h" -#include "src/core/iomgr/timer_heap.h" - -#define INVALID_HEAP_INDEX 0xffffffffu - -#define LOG2_NUM_SHARDS 5 -#define NUM_SHARDS (1 << LOG2_NUM_SHARDS) -#define ADD_DEADLINE_SCALE 0.33 -#define MIN_QUEUE_WINDOW_DURATION 0.01 -#define MAX_QUEUE_WINDOW_DURATION 1 - -typedef struct { - gpr_mu mu; - grpc_time_averaged_stats stats; - /* All and only timers with deadlines <= this will be in the heap. */ - gpr_timespec queue_deadline_cap; - gpr_timespec min_deadline; - /* Index in the g_shard_queue */ - uint32_t shard_queue_index; - /* This holds all timers with deadlines < queue_deadline_cap. Timers in this - list have the top bit of their deadline set to 0. */ - grpc_timer_heap heap; - /* This holds timers whose deadline is >= queue_deadline_cap. */ - grpc_timer list; -} shard_type; - -/* Protects g_shard_queue */ -static gpr_mu g_mu; -/* Allow only one run_some_expired_timers at once */ -static gpr_mu g_checker_mu; -static gpr_clock_type g_clock_type; -static shard_type g_shards[NUM_SHARDS]; -/* Protected by g_mu */ -static shard_type *g_shard_queue[NUM_SHARDS]; - -static int run_some_expired_timers(grpc_exec_ctx *exec_ctx, gpr_timespec now, - gpr_timespec *next, int success); - -static gpr_timespec compute_min_deadline(shard_type *shard) { - return grpc_timer_heap_is_empty(&shard->heap) - ? shard->queue_deadline_cap - : grpc_timer_heap_top(&shard->heap)->deadline; -} - -void grpc_timer_list_init(gpr_timespec now) { - uint32_t i; - - gpr_mu_init(&g_mu); - gpr_mu_init(&g_checker_mu); - g_clock_type = now.clock_type; - - for (i = 0; i < NUM_SHARDS; i++) { - shard_type *shard = &g_shards[i]; - gpr_mu_init(&shard->mu); - grpc_time_averaged_stats_init(&shard->stats, 1.0 / ADD_DEADLINE_SCALE, 0.1, - 0.5); - shard->queue_deadline_cap = now; - shard->shard_queue_index = i; - grpc_timer_heap_init(&shard->heap); - shard->list.next = shard->list.prev = &shard->list; - shard->min_deadline = compute_min_deadline(shard); - g_shard_queue[i] = shard; - } -} - -void grpc_timer_list_shutdown(grpc_exec_ctx *exec_ctx) { - int i; - run_some_expired_timers(exec_ctx, gpr_inf_future(g_clock_type), NULL, 0); - for (i = 0; i < NUM_SHARDS; i++) { - shard_type *shard = &g_shards[i]; - gpr_mu_destroy(&shard->mu); - grpc_timer_heap_destroy(&shard->heap); - } - gpr_mu_destroy(&g_mu); - gpr_mu_destroy(&g_checker_mu); -} - -/* This is a cheap, but good enough, pointer hash for sharding the tasks: */ -static size_t shard_idx(const grpc_timer *info) { - size_t x = (size_t)info; - return ((x >> 4) ^ (x >> 9) ^ (x >> 14)) & (NUM_SHARDS - 1); -} - -static double ts_to_dbl(gpr_timespec ts) { - return (double)ts.tv_sec + 1e-9 * ts.tv_nsec; -} - -static gpr_timespec dbl_to_ts(double d) { - gpr_timespec ts; - ts.tv_sec = (int64_t)d; - ts.tv_nsec = (int32_t)(1e9 * (d - (double)ts.tv_sec)); - ts.clock_type = GPR_TIMESPAN; - return ts; -} - -static void list_join(grpc_timer *head, grpc_timer *timer) { - timer->next = head; - timer->prev = head->prev; - timer->next->prev = timer->prev->next = timer; -} - -static void list_remove(grpc_timer *timer) { - timer->next->prev = timer->prev; - timer->prev->next = timer->next; -} - -static void swap_adjacent_shards_in_queue(uint32_t first_shard_queue_index) { - shard_type *temp; - temp = g_shard_queue[first_shard_queue_index]; - g_shard_queue[first_shard_queue_index] = - g_shard_queue[first_shard_queue_index + 1]; - g_shard_queue[first_shard_queue_index + 1] = temp; - g_shard_queue[first_shard_queue_index]->shard_queue_index = - first_shard_queue_index; - g_shard_queue[first_shard_queue_index + 1]->shard_queue_index = - first_shard_queue_index + 1; -} - -static void note_deadline_change(shard_type *shard) { - while (shard->shard_queue_index > 0 && - gpr_time_cmp( - shard->min_deadline, - g_shard_queue[shard->shard_queue_index - 1]->min_deadline) < 0) { - swap_adjacent_shards_in_queue(shard->shard_queue_index - 1); - } - while (shard->shard_queue_index < NUM_SHARDS - 1 && - gpr_time_cmp( - shard->min_deadline, - g_shard_queue[shard->shard_queue_index + 1]->min_deadline) > 0) { - swap_adjacent_shards_in_queue(shard->shard_queue_index); - } -} - -void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer, - gpr_timespec deadline, grpc_iomgr_cb_func timer_cb, - void *timer_cb_arg, gpr_timespec now) { - int is_first_timer = 0; - shard_type *shard = &g_shards[shard_idx(timer)]; - GPR_ASSERT(deadline.clock_type == g_clock_type); - GPR_ASSERT(now.clock_type == g_clock_type); - grpc_closure_init(&timer->closure, timer_cb, timer_cb_arg); - timer->deadline = deadline; - timer->triggered = 0; - - /* TODO(ctiller): check deadline expired */ - - gpr_mu_lock(&shard->mu); - grpc_time_averaged_stats_add_sample(&shard->stats, - ts_to_dbl(gpr_time_sub(deadline, now))); - if (gpr_time_cmp(deadline, shard->queue_deadline_cap) < 0) { - is_first_timer = grpc_timer_heap_add(&shard->heap, timer); - } else { - timer->heap_index = INVALID_HEAP_INDEX; - list_join(&shard->list, timer); - } - gpr_mu_unlock(&shard->mu); - - /* Deadline may have decreased, we need to adjust the master queue. Note - that there is a potential racy unlocked region here. There could be a - reordering of multiple grpc_timer_init calls, at this point, but the < test - below should ensure that we err on the side of caution. There could - also be a race with grpc_timer_check, which might beat us to the lock. In - that case, it is possible that the timer that we added will have already - run by the time we hold the lock, but that too is a safe error. - Finally, it's possible that the grpc_timer_check that intervened failed to - trigger the new timer because the min_deadline hadn't yet been reduced. - In that case, the timer will simply have to wait for the next - grpc_timer_check. */ - if (is_first_timer) { - gpr_mu_lock(&g_mu); - if (gpr_time_cmp(deadline, shard->min_deadline) < 0) { - gpr_timespec old_min_deadline = g_shard_queue[0]->min_deadline; - shard->min_deadline = deadline; - note_deadline_change(shard); - if (shard->shard_queue_index == 0 && - gpr_time_cmp(deadline, old_min_deadline) < 0) { - grpc_kick_poller(); - } - } - gpr_mu_unlock(&g_mu); - } -} - -void grpc_timer_cancel(grpc_exec_ctx *exec_ctx, grpc_timer *timer) { - shard_type *shard = &g_shards[shard_idx(timer)]; - gpr_mu_lock(&shard->mu); - if (!timer->triggered) { - grpc_exec_ctx_enqueue(exec_ctx, &timer->closure, false, NULL); - timer->triggered = 1; - if (timer->heap_index == INVALID_HEAP_INDEX) { - list_remove(timer); - } else { - grpc_timer_heap_remove(&shard->heap, timer); - } - } - gpr_mu_unlock(&shard->mu); -} - -/* This is called when the queue is empty and "now" has reached the - queue_deadline_cap. We compute a new queue deadline and then scan the map - for timers that fall at or under it. Returns true if the queue is no - longer empty. - REQUIRES: shard->mu locked */ -static int refill_queue(shard_type *shard, gpr_timespec now) { - /* Compute the new queue window width and bound by the limits: */ - double computed_deadline_delta = - grpc_time_averaged_stats_update_average(&shard->stats) * - ADD_DEADLINE_SCALE; - double deadline_delta = - GPR_CLAMP(computed_deadline_delta, MIN_QUEUE_WINDOW_DURATION, - MAX_QUEUE_WINDOW_DURATION); - grpc_timer *timer, *next; - - /* Compute the new cap and put all timers under it into the queue: */ - shard->queue_deadline_cap = gpr_time_add( - gpr_time_max(now, shard->queue_deadline_cap), dbl_to_ts(deadline_delta)); - for (timer = shard->list.next; timer != &shard->list; timer = next) { - next = timer->next; - - if (gpr_time_cmp(timer->deadline, shard->queue_deadline_cap) < 0) { - list_remove(timer); - grpc_timer_heap_add(&shard->heap, timer); - } - } - return !grpc_timer_heap_is_empty(&shard->heap); -} - -/* This pops the next non-cancelled timer with deadline <= now from the queue, - or returns NULL if there isn't one. - REQUIRES: shard->mu locked */ -static grpc_timer *pop_one(shard_type *shard, gpr_timespec now) { - grpc_timer *timer; - for (;;) { - if (grpc_timer_heap_is_empty(&shard->heap)) { - if (gpr_time_cmp(now, shard->queue_deadline_cap) < 0) return NULL; - if (!refill_queue(shard, now)) return NULL; - } - timer = grpc_timer_heap_top(&shard->heap); - if (gpr_time_cmp(timer->deadline, now) > 0) return NULL; - timer->triggered = 1; - grpc_timer_heap_pop(&shard->heap); - return timer; - } -} - -/* REQUIRES: shard->mu unlocked */ -static size_t pop_timers(grpc_exec_ctx *exec_ctx, shard_type *shard, - gpr_timespec now, gpr_timespec *new_min_deadline, - int success) { - size_t n = 0; - grpc_timer *timer; - gpr_mu_lock(&shard->mu); - while ((timer = pop_one(shard, now))) { - grpc_exec_ctx_enqueue(exec_ctx, &timer->closure, success, NULL); - n++; - } - *new_min_deadline = compute_min_deadline(shard); - gpr_mu_unlock(&shard->mu); - return n; -} - -static int run_some_expired_timers(grpc_exec_ctx *exec_ctx, gpr_timespec now, - gpr_timespec *next, int success) { - size_t n = 0; - - /* TODO(ctiller): verify that there are any timers (atomically) here */ - - if (gpr_mu_trylock(&g_checker_mu)) { - gpr_mu_lock(&g_mu); - - while (gpr_time_cmp(g_shard_queue[0]->min_deadline, now) < 0) { - gpr_timespec new_min_deadline; - - /* For efficiency, we pop as many available timers as we can from the - shard. This may violate perfect timer deadline ordering, but that - shouldn't be a big deal because we don't make ordering guarantees. */ - n += pop_timers(exec_ctx, g_shard_queue[0], now, &new_min_deadline, - success); - - /* An grpc_timer_init() on the shard could intervene here, adding a new - timer that is earlier than new_min_deadline. However, - grpc_timer_init() will block on the master_lock before it can call - set_min_deadline, so this one will complete first and then the Addtimer - will reduce the min_deadline (perhaps unnecessarily). */ - g_shard_queue[0]->min_deadline = new_min_deadline; - note_deadline_change(g_shard_queue[0]); - } - - if (next) { - *next = gpr_time_min(*next, g_shard_queue[0]->min_deadline); - } - - gpr_mu_unlock(&g_mu); - gpr_mu_unlock(&g_checker_mu); - } else if (next != NULL) { - /* TODO(ctiller): this forces calling code to do an short poll, and - then retry the timer check (because this time through the timer list was - contended). - - We could reduce the cost here dramatically by keeping a count of how many - currently active pollers got through the uncontended case above - successfully, and waking up other pollers IFF that count drops to zero. - - Once that count is in place, this entire else branch could disappear. */ - *next = gpr_time_min( - *next, gpr_time_add(now, gpr_time_from_millis(1, GPR_TIMESPAN))); - } - - return (int)n; -} - -bool grpc_timer_check(grpc_exec_ctx *exec_ctx, gpr_timespec now, - gpr_timespec *next) { - GPR_ASSERT(now.clock_type == g_clock_type); - return run_some_expired_timers( - exec_ctx, now, next, - gpr_time_cmp(now, gpr_inf_future(now.clock_type)) != 0); -} diff --git a/src/core/iomgr/timer.h b/src/core/iomgr/timer.h deleted file mode 100644 index 1e2d1cbfbd..0000000000 --- a/src/core/iomgr/timer.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * - * Copyright 2015-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_IOMGR_TIMER_H -#define GRPC_CORE_IOMGR_TIMER_H - -#include -#include -#include "src/core/iomgr/exec_ctx.h" -#include "src/core/iomgr/iomgr.h" - -typedef struct grpc_timer { - gpr_timespec deadline; - uint32_t heap_index; /* INVALID_HEAP_INDEX if not in heap */ - int triggered; - struct grpc_timer *next; - struct grpc_timer *prev; - grpc_closure closure; -} grpc_timer; - -/* Initialize *timer. When expired or canceled, timer_cb will be called with - *timer_cb_arg and status to indicate if it expired (SUCCESS) or was - canceled (CANCELLED). timer_cb is guaranteed to be called exactly once, - and application code should check the status to determine how it was - invoked. The application callback is also responsible for maintaining - information about when to free up any user-level state. */ -void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer, - gpr_timespec deadline, grpc_iomgr_cb_func timer_cb, - void *timer_cb_arg, gpr_timespec now); - -/* Note that there is no timer destroy function. This is because the - timer is a one-time occurrence with a guarantee that the callback will - be called exactly once, either at expiration or cancellation. Thus, all - the internal timer event management state is destroyed just before - that callback is invoked. If the user has additional state associated with - the timer, the user is responsible for determining when it is safe to - destroy that state. */ - -/* Cancel an *timer. - There are three cases: - 1. We normally cancel the timer - 2. The timer has already run - 3. We can't cancel the timer because it is "in flight". - - In all of these cases, the cancellation is still considered successful. - They are essentially distinguished in that the timer_cb will be run - exactly once from either the cancellation (with status CANCELLED) - or from the activation (with status SUCCESS) - - Note carefully that the callback function MAY occur in the same callstack - as grpc_timer_cancel. It's expected that most timers will be cancelled (their - primary use is to implement deadlines), and so this code is optimized such - that cancellation costs as little as possible. Making callbacks run inline - matches this aim. - - Requires: cancel() must happen after add() on a given timer */ -void grpc_timer_cancel(grpc_exec_ctx *exec_ctx, grpc_timer *timer); - -/* iomgr internal api for dealing with timers */ - -/* Check for timers to be run, and run them. - Return true if timer callbacks were executed. - Drops drop_mu if it is non-null before executing callbacks. - If next is non-null, TRY to update *next with the next running timer - IF that timer occurs before *next current value. - *next is never guaranteed to be updated on any given execution; however, - with high probability at least one thread in the system will see an update - at any time slice. */ -bool grpc_timer_check(grpc_exec_ctx *exec_ctx, gpr_timespec now, - gpr_timespec *next); -void grpc_timer_list_init(gpr_timespec now); -void grpc_timer_list_shutdown(grpc_exec_ctx *exec_ctx); - -/* the following must be implemented by each iomgr implementation */ - -void grpc_kick_poller(void); - -#endif /* GRPC_CORE_IOMGR_TIMER_H */ diff --git a/src/core/iomgr/timer_heap.c b/src/core/iomgr/timer_heap.c deleted file mode 100644 index b5df566c45..0000000000 --- a/src/core/iomgr/timer_heap.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * - * Copyright 2015-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/iomgr/timer_heap.h" - -#include - -#include -#include - -/* Adjusts a heap so as to move a hole at position i closer to the root, - until a suitable position is found for element t. Then, copies t into that - position. This functor is called each time immediately after modifying a - value in the underlying container, with the offset of the modified element as - its argument. */ -static void adjust_upwards(grpc_timer **first, uint32_t i, grpc_timer *t) { - while (i > 0) { - uint32_t parent = (uint32_t)(((int)i - 1) / 2); - if (gpr_time_cmp(first[parent]->deadline, t->deadline) <= 0) break; - first[i] = first[parent]; - first[i]->heap_index = i; - i = parent; - } - first[i] = t; - t->heap_index = i; -} - -/* Adjusts a heap so as to move a hole at position i farther away from the root, - until a suitable position is found for element t. Then, copies t into that - position. */ -static void adjust_downwards(grpc_timer **first, uint32_t i, uint32_t length, - grpc_timer *t) { - for (;;) { - uint32_t left_child = 1u + 2u * i; - if (left_child >= length) break; - uint32_t right_child = left_child + 1; - uint32_t next_i = right_child < length && - gpr_time_cmp(first[left_child]->deadline, - first[right_child]->deadline) > 0 - ? right_child - : left_child; - if (gpr_time_cmp(t->deadline, first[next_i]->deadline) <= 0) break; - first[i] = first[next_i]; - first[i]->heap_index = i; - i = next_i; - } - first[i] = t; - t->heap_index = i; -} - -#define SHRINK_MIN_ELEMS 8 -#define SHRINK_FULLNESS_FACTOR 2 - -static void maybe_shrink(grpc_timer_heap *heap) { - if (heap->timer_count >= 8 && - heap->timer_count <= heap->timer_capacity / SHRINK_FULLNESS_FACTOR / 2) { - heap->timer_capacity = heap->timer_count * SHRINK_FULLNESS_FACTOR; - heap->timers = - gpr_realloc(heap->timers, heap->timer_capacity * sizeof(grpc_timer *)); - } -} - -static void note_changed_priority(grpc_timer_heap *heap, grpc_timer *timer) { - uint32_t i = timer->heap_index; - uint32_t parent = (uint32_t)(((int)i - 1) / 2); - if (gpr_time_cmp(heap->timers[parent]->deadline, timer->deadline) > 0) { - adjust_upwards(heap->timers, i, timer); - } else { - adjust_downwards(heap->timers, i, heap->timer_count, timer); - } -} - -void grpc_timer_heap_init(grpc_timer_heap *heap) { - memset(heap, 0, sizeof(*heap)); -} - -void grpc_timer_heap_destroy(grpc_timer_heap *heap) { gpr_free(heap->timers); } - -int grpc_timer_heap_add(grpc_timer_heap *heap, grpc_timer *timer) { - if (heap->timer_count == heap->timer_capacity) { - heap->timer_capacity = - GPR_MAX(heap->timer_capacity + 1, heap->timer_capacity * 3 / 2); - heap->timers = - gpr_realloc(heap->timers, heap->timer_capacity * sizeof(grpc_timer *)); - } - timer->heap_index = heap->timer_count; - adjust_upwards(heap->timers, heap->timer_count, timer); - heap->timer_count++; - return timer->heap_index == 0; -} - -void grpc_timer_heap_remove(grpc_timer_heap *heap, grpc_timer *timer) { - uint32_t i = timer->heap_index; - if (i == heap->timer_count - 1) { - heap->timer_count--; - maybe_shrink(heap); - return; - } - heap->timers[i] = heap->timers[heap->timer_count - 1]; - heap->timers[i]->heap_index = i; - heap->timer_count--; - maybe_shrink(heap); - note_changed_priority(heap, heap->timers[i]); -} - -int grpc_timer_heap_is_empty(grpc_timer_heap *heap) { - return heap->timer_count == 0; -} - -grpc_timer *grpc_timer_heap_top(grpc_timer_heap *heap) { - return heap->timers[0]; -} - -void grpc_timer_heap_pop(grpc_timer_heap *heap) { - grpc_timer_heap_remove(heap, grpc_timer_heap_top(heap)); -} diff --git a/src/core/iomgr/timer_heap.h b/src/core/iomgr/timer_heap.h deleted file mode 100644 index c2912ef45d..0000000000 --- a/src/core/iomgr/timer_heap.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * - * Copyright 2015-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_IOMGR_TIMER_HEAP_H -#define GRPC_CORE_IOMGR_TIMER_HEAP_H - -#include "src/core/iomgr/timer.h" - -typedef struct { - grpc_timer **timers; - uint32_t timer_count; - uint32_t timer_capacity; -} grpc_timer_heap; - -/* return 1 if the new timer is the first timer in the heap */ -int grpc_timer_heap_add(grpc_timer_heap *heap, grpc_timer *timer); - -void grpc_timer_heap_init(grpc_timer_heap *heap); -void grpc_timer_heap_destroy(grpc_timer_heap *heap); - -void grpc_timer_heap_remove(grpc_timer_heap *heap, grpc_timer *timer); -grpc_timer *grpc_timer_heap_top(grpc_timer_heap *heap); -void grpc_timer_heap_pop(grpc_timer_heap *heap); - -int grpc_timer_heap_is_empty(grpc_timer_heap *heap); - -#endif /* GRPC_CORE_IOMGR_TIMER_HEAP_H */ diff --git a/src/core/iomgr/udp_server.c b/src/core/iomgr/udp_server.c deleted file mode 100644 index 174159170f..0000000000 --- a/src/core/iomgr/udp_server.c +++ /dev/null @@ -1,418 +0,0 @@ -/* - * - * Copyright 2015-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. - * - */ - -/* FIXME: "posix" files shouldn't be depending on _GNU_SOURCE */ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include - -#ifdef GRPC_NEED_UDP -#ifdef GPR_POSIX_SOCKET - -#include "src/core/iomgr/udp_server.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include "src/core/iomgr/fd_posix.h" -#include "src/core/iomgr/pollset_posix.h" -#include "src/core/iomgr/resolve_address.h" -#include "src/core/iomgr/sockaddr_utils.h" -#include "src/core/iomgr/socket_utils_posix.h" -#include "src/core/iomgr/unix_sockets_posix.h" -#include "src/core/support/string.h" - -#define INIT_PORT_CAP 2 - -/* one listening port */ -typedef struct { - int fd; - grpc_fd *emfd; - grpc_udp_server *server; - union { - uint8_t untyped[GRPC_MAX_SOCKADDR_SIZE]; - struct sockaddr sockaddr; - } addr; - size_t addr_len; - grpc_closure read_closure; - grpc_closure destroyed_closure; - grpc_udp_server_read_cb read_cb; -} server_port; - -/* the overall server */ -struct grpc_udp_server { - gpr_mu mu; - gpr_cv cv; - - /* active port count: how many ports are actually still listening */ - size_t active_ports; - /* destroyed port count: how many ports are completely destroyed */ - size_t destroyed_ports; - - /* is this server shutting down? (boolean) */ - int shutdown; - - /* all listening ports */ - server_port *ports; - size_t nports; - size_t port_capacity; - - /* shutdown callback */ - grpc_closure *shutdown_complete; - - /* all pollsets interested in new connections */ - grpc_pollset **pollsets; - /* number of pollsets in the pollsets array */ - size_t pollset_count; - /* The parent grpc server */ - grpc_server *grpc_server; -}; - -grpc_udp_server *grpc_udp_server_create(void) { - grpc_udp_server *s = gpr_malloc(sizeof(grpc_udp_server)); - gpr_mu_init(&s->mu); - gpr_cv_init(&s->cv); - s->active_ports = 0; - s->destroyed_ports = 0; - s->shutdown = 0; - s->ports = gpr_malloc(sizeof(server_port) * INIT_PORT_CAP); - s->nports = 0; - s->port_capacity = INIT_PORT_CAP; - - return s; -} - -static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_udp_server *s) { - grpc_exec_ctx_enqueue(exec_ctx, s->shutdown_complete, 1, NULL); - - gpr_mu_destroy(&s->mu); - gpr_cv_destroy(&s->cv); - - gpr_free(s->ports); - gpr_free(s); -} - -static void destroyed_port(grpc_exec_ctx *exec_ctx, void *server, - bool success) { - grpc_udp_server *s = server; - gpr_mu_lock(&s->mu); - s->destroyed_ports++; - if (s->destroyed_ports == s->nports) { - gpr_mu_unlock(&s->mu); - finish_shutdown(exec_ctx, s); - } else { - gpr_mu_unlock(&s->mu); - } -} - -/* called when all listening endpoints have been shutdown, so no further - events will be received on them - at this point it's safe to destroy - things */ -static void deactivated_all_ports(grpc_exec_ctx *exec_ctx, grpc_udp_server *s) { - size_t i; - - /* delete ALL the things */ - gpr_mu_lock(&s->mu); - - if (!s->shutdown) { - gpr_mu_unlock(&s->mu); - return; - } - - if (s->nports) { - for (i = 0; i < s->nports; i++) { - server_port *sp = &s->ports[i]; - grpc_unlink_if_unix_domain_socket(&sp->addr.sockaddr); - sp->destroyed_closure.cb = destroyed_port; - sp->destroyed_closure.cb_arg = s; - grpc_fd_orphan(exec_ctx, sp->emfd, &sp->destroyed_closure, NULL, - "udp_listener_shutdown"); - } - gpr_mu_unlock(&s->mu); - } else { - gpr_mu_unlock(&s->mu); - finish_shutdown(exec_ctx, s); - } -} - -void grpc_udp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_udp_server *s, - grpc_closure *on_done) { - size_t i; - gpr_mu_lock(&s->mu); - - GPR_ASSERT(!s->shutdown); - s->shutdown = 1; - - s->shutdown_complete = on_done; - - /* shutdown all fd's */ - if (s->active_ports) { - for (i = 0; i < s->nports; i++) { - grpc_fd_shutdown(exec_ctx, s->ports[i].emfd); - } - gpr_mu_unlock(&s->mu); - } else { - gpr_mu_unlock(&s->mu); - deactivated_all_ports(exec_ctx, s); - } -} - -/* Prepare a recently-created socket for listening. */ -static int prepare_socket(int fd, const struct sockaddr *addr, - size_t addr_len) { - struct sockaddr_storage sockname_temp; - socklen_t sockname_len; - int get_local_ip; - int rc; - - if (fd < 0) { - goto error; - } - - if (!grpc_set_socket_nonblocking(fd, 1) || !grpc_set_socket_cloexec(fd, 1)) { - gpr_log(GPR_ERROR, "Unable to configure socket %d: %s", fd, - strerror(errno)); - } - - get_local_ip = 1; - rc = setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &get_local_ip, - sizeof(get_local_ip)); - if (rc == 0 && addr->sa_family == AF_INET6) { -#if !defined(__APPLE__) - rc = setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &get_local_ip, - sizeof(get_local_ip)); -#endif - } - - GPR_ASSERT(addr_len < ~(socklen_t)0); - if (bind(fd, addr, (socklen_t)addr_len) < 0) { - char *addr_str; - grpc_sockaddr_to_string(&addr_str, addr, 0); - gpr_log(GPR_ERROR, "bind addr=%s: %s", addr_str, strerror(errno)); - gpr_free(addr_str); - goto error; - } - - sockname_len = sizeof(sockname_temp); - if (getsockname(fd, (struct sockaddr *)&sockname_temp, &sockname_len) < 0) { - goto error; - } - - return grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp); - -error: - if (fd >= 0) { - close(fd); - } - return -1; -} - -/* event manager callback when reads are ready */ -static void on_read(grpc_exec_ctx *exec_ctx, void *arg, bool success) { - server_port *sp = arg; - - if (!success) { - gpr_mu_lock(&sp->server->mu); - if (0 == --sp->server->active_ports) { - gpr_mu_unlock(&sp->server->mu); - deactivated_all_ports(exec_ctx, sp->server); - } else { - gpr_mu_unlock(&sp->server->mu); - } - return; - } - - /* Tell the registered callback that data is available to read. */ - GPR_ASSERT(sp->read_cb); - sp->read_cb(exec_ctx, sp->emfd, sp->server->grpc_server); - - /* Re-arm the notification event so we get another chance to read. */ - grpc_fd_notify_on_read(exec_ctx, sp->emfd, &sp->read_closure); -} - -static int add_socket_to_server(grpc_udp_server *s, int fd, - const struct sockaddr *addr, size_t addr_len, - grpc_udp_server_read_cb read_cb) { - server_port *sp; - int port; - char *addr_str; - char *name; - - port = prepare_socket(fd, addr, addr_len); - if (port >= 0) { - grpc_sockaddr_to_string(&addr_str, (struct sockaddr *)&addr, 1); - gpr_asprintf(&name, "udp-server-listener:%s", addr_str); - gpr_free(addr_str); - gpr_mu_lock(&s->mu); - /* append it to the list under a lock */ - if (s->nports == s->port_capacity) { - s->port_capacity *= 2; - s->ports = gpr_realloc(s->ports, sizeof(server_port) * s->port_capacity); - } - sp = &s->ports[s->nports++]; - sp->server = s; - sp->fd = fd; - sp->emfd = grpc_fd_create(fd, name); - memcpy(sp->addr.untyped, addr, addr_len); - sp->addr_len = addr_len; - sp->read_cb = read_cb; - GPR_ASSERT(sp->emfd); - gpr_mu_unlock(&s->mu); - gpr_free(name); - } - - return port; -} - -int grpc_udp_server_add_port(grpc_udp_server *s, const void *addr, - size_t addr_len, grpc_udp_server_read_cb read_cb) { - int allocated_port1 = -1; - int allocated_port2 = -1; - unsigned i; - int fd; - grpc_dualstack_mode dsmode; - struct sockaddr_in6 addr6_v4mapped; - struct sockaddr_in wild4; - struct sockaddr_in6 wild6; - struct sockaddr_in addr4_copy; - struct sockaddr *allocated_addr = NULL; - struct sockaddr_storage sockname_temp; - socklen_t sockname_len; - int port; - - grpc_unlink_if_unix_domain_socket((struct sockaddr *)addr); - - /* Check if this is a wildcard port, and if so, try to keep the port the same - as some previously created listener. */ - if (grpc_sockaddr_get_port(addr) == 0) { - for (i = 0; i < s->nports; i++) { - sockname_len = sizeof(sockname_temp); - if (0 == getsockname(s->ports[i].fd, (struct sockaddr *)&sockname_temp, - &sockname_len)) { - port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp); - if (port > 0) { - allocated_addr = malloc(addr_len); - memcpy(allocated_addr, addr, addr_len); - grpc_sockaddr_set_port(allocated_addr, port); - addr = allocated_addr; - break; - } - } - } - } - - if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) { - addr = (const struct sockaddr *)&addr6_v4mapped; - addr_len = sizeof(addr6_v4mapped); - } - - /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */ - if (grpc_sockaddr_is_wildcard(addr, &port)) { - grpc_sockaddr_make_wildcards(port, &wild4, &wild6); - - /* Try listening on IPv6 first. */ - addr = (struct sockaddr *)&wild6; - addr_len = sizeof(wild6); - fd = grpc_create_dualstack_socket(addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode); - allocated_port1 = add_socket_to_server(s, fd, addr, addr_len, read_cb); - if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) { - goto done; - } - - /* If we didn't get a dualstack socket, also listen on 0.0.0.0. */ - if (port == 0 && allocated_port1 > 0) { - grpc_sockaddr_set_port((struct sockaddr *)&wild4, allocated_port1); - } - addr = (struct sockaddr *)&wild4; - addr_len = sizeof(wild4); - } - - fd = grpc_create_dualstack_socket(addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode); - if (fd < 0) { - gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno)); - } - if (dsmode == GRPC_DSMODE_IPV4 && - grpc_sockaddr_is_v4mapped(addr, &addr4_copy)) { - addr = (struct sockaddr *)&addr4_copy; - addr_len = sizeof(addr4_copy); - } - allocated_port2 = add_socket_to_server(s, fd, addr, addr_len, read_cb); - -done: - gpr_free(allocated_addr); - return allocated_port1 >= 0 ? allocated_port1 : allocated_port2; -} - -int grpc_udp_server_get_fd(grpc_udp_server *s, unsigned port_index) { - return (port_index < s->nports) ? s->ports[port_index].fd : -1; -} - -void grpc_udp_server_start(grpc_exec_ctx *exec_ctx, grpc_udp_server *s, - grpc_pollset **pollsets, size_t pollset_count, - grpc_server *server) { - size_t i, j; - gpr_mu_lock(&s->mu); - GPR_ASSERT(s->active_ports == 0); - s->pollsets = pollsets; - s->grpc_server = server; - for (i = 0; i < s->nports; i++) { - for (j = 0; j < pollset_count; j++) { - grpc_pollset_add_fd(exec_ctx, pollsets[j], s->ports[i].emfd); - } - s->ports[i].read_closure.cb = on_read; - s->ports[i].read_closure.cb_arg = &s->ports[i]; - grpc_fd_notify_on_read(exec_ctx, s->ports[i].emfd, - &s->ports[i].read_closure); - s->active_ports++; - } - gpr_mu_unlock(&s->mu); -} - -#endif -#endif diff --git a/src/core/iomgr/udp_server.h b/src/core/iomgr/udp_server.h deleted file mode 100644 index 148c04fa9b..0000000000 --- a/src/core/iomgr/udp_server.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * - * Copyright 2015-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_IOMGR_UDP_SERVER_H -#define GRPC_CORE_IOMGR_UDP_SERVER_H - -#include "src/core/iomgr/endpoint.h" -#include "src/core/iomgr/fd_posix.h" - -/* Forward decl of struct grpc_server */ -/* This is not typedef'ed to avoid a typedef-redefinition error */ -struct grpc_server; - -/* Forward decl of grpc_udp_server */ -typedef struct grpc_udp_server grpc_udp_server; - -/* Called when data is available to read from the socket. */ -typedef void (*grpc_udp_server_read_cb)(grpc_exec_ctx *exec_ctx, grpc_fd *emfd, - struct grpc_server *server); - -/* Create a server, initially not bound to any ports */ -grpc_udp_server *grpc_udp_server_create(void); - -/* Start listening to bound ports */ -void grpc_udp_server_start(grpc_exec_ctx *exec_ctx, grpc_udp_server *udp_server, - grpc_pollset **pollsets, size_t pollset_count, - struct grpc_server *server); - -int grpc_udp_server_get_fd(grpc_udp_server *s, unsigned index); - -/* Add a port to the server, returning port number on success, or negative - on failure. - - The :: and 0.0.0.0 wildcard addresses are treated identically, accepting - both IPv4 and IPv6 connections, but :: is the preferred style. This usually - creates one socket, but possibly two on systems which support IPv6, - but not dualstack sockets. */ - -/* TODO(ctiller): deprecate this, and make grpc_udp_server_add_ports to handle - all of the multiple socket port matching logic in one place */ -int grpc_udp_server_add_port(grpc_udp_server *s, const void *addr, - size_t addr_len, grpc_udp_server_read_cb read_cb); - -void grpc_udp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_udp_server *server, - grpc_closure *on_done); - -#endif /* GRPC_CORE_IOMGR_UDP_SERVER_H */ diff --git a/src/core/iomgr/unix_sockets_posix.c b/src/core/iomgr/unix_sockets_posix.c deleted file mode 100644 index 174a7e7abf..0000000000 --- a/src/core/iomgr/unix_sockets_posix.c +++ /dev/null @@ -1,103 +0,0 @@ -/* - * - * 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/iomgr/unix_sockets_posix.h" - -#ifdef GPR_HAVE_UNIX_SOCKET - -#include -#include -#include -#include - -#include - -void grpc_create_socketpair_if_unix(int sv[2]) { - GPR_ASSERT(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0); -} - -grpc_resolved_addresses *grpc_resolve_unix_domain_address(const char *name) { - struct sockaddr_un *un; - - grpc_resolved_addresses *addrs = gpr_malloc(sizeof(grpc_resolved_addresses)); - addrs->naddrs = 1; - addrs->addrs = gpr_malloc(sizeof(grpc_resolved_address)); - un = (struct sockaddr_un *)addrs->addrs->addr; - un->sun_family = AF_UNIX; - strcpy(un->sun_path, name); - addrs->addrs->len = strlen(un->sun_path) + sizeof(un->sun_family) + 1; - return addrs; -} - -int grpc_is_unix_socket(const struct sockaddr *addr) { - return addr->sa_family == AF_UNIX; -} - -void grpc_unlink_if_unix_domain_socket(const struct sockaddr *addr) { - if (addr->sa_family != AF_UNIX) { - return; - } - struct sockaddr_un *un = (struct sockaddr_un *)addr; - struct stat st; - - if (stat(un->sun_path, &st) == 0 && (st.st_mode & S_IFMT) == S_IFSOCK) { - unlink(un->sun_path); - } -} - -int grpc_parse_unix(grpc_uri *uri, struct sockaddr_storage *addr, size_t *len) { - struct sockaddr_un *un = (struct sockaddr_un *)addr; - - un->sun_family = AF_UNIX; - strcpy(un->sun_path, uri->path); - *len = strlen(un->sun_path) + sizeof(un->sun_family) + 1; - - return 1; -} - -char *grpc_unix_get_default_authority(grpc_resolver_factory *factory, - grpc_uri *uri) { - return gpr_strdup("localhost"); -} - -char *grpc_sockaddr_to_uri_unix_if_possible(const struct sockaddr *addr) { - if (addr->sa_family != AF_UNIX) { - return NULL; - } - - char *result; - gpr_asprintf(&result, "unix:%s", ((struct sockaddr_un *)addr)->sun_path); - return result; -} - -#endif diff --git a/src/core/iomgr/unix_sockets_posix.h b/src/core/iomgr/unix_sockets_posix.h deleted file mode 100644 index e842ba3770..0000000000 --- a/src/core/iomgr/unix_sockets_posix.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * - * 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_IOMGR_UNIX_SOCKETS_POSIX_H -#define GRPC_CORE_IOMGR_UNIX_SOCKETS_POSIX_H - -#include - -#include - -#include "src/core/client_config/resolver_factory.h" -#include "src/core/client_config/uri_parser.h" -#include "src/core/iomgr/resolve_address.h" -#include "src/core/iomgr/sockaddr.h" - -void grpc_create_socketpair_if_unix(int sv[2]); - -grpc_resolved_addresses *grpc_resolve_unix_domain_address(const char *name); - -int grpc_is_unix_socket(const struct sockaddr *addr); - -void grpc_unlink_if_unix_domain_socket(const struct sockaddr *addr); - -int grpc_parse_unix(grpc_uri *uri, struct sockaddr_storage *addr, size_t *len); - -char *grpc_unix_get_default_authority(grpc_resolver_factory *factory, - grpc_uri *uri); - -char *grpc_sockaddr_to_uri_unix_if_possible(const struct sockaddr *addr); - -#endif /* GRPC_CORE_IOMGR_UNIX_SOCKETS_POSIX_H */ diff --git a/src/core/iomgr/unix_sockets_posix_noop.c b/src/core/iomgr/unix_sockets_posix_noop.c deleted file mode 100644 index 045467bea4..0000000000 --- a/src/core/iomgr/unix_sockets_posix_noop.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * - * 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/iomgr/unix_sockets_posix.h" - -#ifndef GPR_HAVE_UNIX_SOCKET - -void grpc_create_socketpair_if_unix(int sv[2]) {} - -grpc_resolved_addresses *grpc_resolve_unix_domain_address(const char *name) { - return NULL; -} - -int grpc_is_unix_socket(const struct sockaddr *addr) { return false; } - -void grpc_unlink_if_unix_domain_socket(const struct sockaddr *addr) {} - -int grpc_parse_unix(grpc_uri *uri, struct sockaddr_storage *addr, size_t *len) { - return 0; -} - -char *grpc_unix_get_default_authority(grpc_resolver_factory *factory, - grpc_uri *uri) { - return NULL; -} - -char *grpc_sockaddr_to_uri_unix_if_possible(const struct sockaddr *addr) { - return NULL; -} - -#endif diff --git a/src/core/iomgr/wakeup_fd_eventfd.c b/src/core/iomgr/wakeup_fd_eventfd.c deleted file mode 100644 index f67379e4fc..0000000000 --- a/src/core/iomgr/wakeup_fd_eventfd.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include - -#ifdef GPR_LINUX_EVENTFD - -#include -#include -#include - -#include - -#include "src/core/iomgr/wakeup_fd_posix.h" -#include "src/core/profiling/timers.h" - -static void eventfd_create(grpc_wakeup_fd* fd_info) { - int efd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); - /* TODO(klempner): Handle failure more gracefully */ - GPR_ASSERT(efd >= 0); - fd_info->read_fd = efd; - fd_info->write_fd = -1; -} - -static void eventfd_consume(grpc_wakeup_fd* fd_info) { - eventfd_t value; - int err; - do { - err = eventfd_read(fd_info->read_fd, &value); - } while (err < 0 && errno == EINTR); -} - -static void eventfd_wakeup(grpc_wakeup_fd* fd_info) { - int err; - GPR_TIMER_BEGIN("eventfd_wakeup", 0); - do { - err = eventfd_write(fd_info->read_fd, 1); - } while (err < 0 && errno == EINTR); - GPR_TIMER_END("eventfd_wakeup", 0); -} - -static void eventfd_destroy(grpc_wakeup_fd* fd_info) { - if (fd_info->read_fd != 0) close(fd_info->read_fd); -} - -static int eventfd_check_availability(void) { - /* TODO(klempner): Actually check if eventfd is available */ - return 1; -} - -const grpc_wakeup_fd_vtable grpc_specialized_wakeup_fd_vtable = { - eventfd_create, eventfd_consume, eventfd_wakeup, eventfd_destroy, - eventfd_check_availability}; - -#endif /* GPR_LINUX_EVENTFD */ diff --git a/src/core/iomgr/wakeup_fd_nospecial.c b/src/core/iomgr/wakeup_fd_nospecial.c deleted file mode 100644 index 7b2be9ed52..0000000000 --- a/src/core/iomgr/wakeup_fd_nospecial.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * - * Copyright 2015-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. - * - */ - -/* - * This is a dummy file to provide an invalid specialized_wakeup_fd_vtable on - * systems without anything better than pipe. - */ - -#include - -#ifdef GPR_POSIX_NO_SPECIAL_WAKEUP_FD - -#include -#include "src/core/iomgr/wakeup_fd_posix.h" - -static int check_availability_invalid(void) { return 0; } - -const grpc_wakeup_fd_vtable grpc_specialized_wakeup_fd_vtable = { - NULL, NULL, NULL, NULL, check_availability_invalid}; - -#endif /* GPR_POSIX_NO_SPECIAL_WAKEUP_FD */ diff --git a/src/core/iomgr/wakeup_fd_pipe.c b/src/core/iomgr/wakeup_fd_pipe.c deleted file mode 100644 index dd2fd1f057..0000000000 --- a/src/core/iomgr/wakeup_fd_pipe.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - * - * Copyright 2015-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 - -#ifdef GPR_POSIX_WAKEUP_FD - -#include "src/core/iomgr/wakeup_fd_posix.h" - -#include -#include -#include - -#include - -#include "src/core/iomgr/socket_utils_posix.h" - -static void pipe_init(grpc_wakeup_fd* fd_info) { - int pipefd[2]; - /* TODO(klempner): Make this nonfatal */ - int r = pipe(pipefd); - if (0 != r) { - gpr_log(GPR_ERROR, "pipe creation failed (%d): %s", errno, strerror(errno)); - abort(); - } - GPR_ASSERT(grpc_set_socket_nonblocking(pipefd[0], 1)); - GPR_ASSERT(grpc_set_socket_nonblocking(pipefd[1], 1)); - fd_info->read_fd = pipefd[0]; - fd_info->write_fd = pipefd[1]; -} - -static void pipe_consume(grpc_wakeup_fd* fd_info) { - char buf[128]; - ssize_t r; - - for (;;) { - r = read(fd_info->read_fd, buf, sizeof(buf)); - if (r > 0) continue; - if (r == 0) return; - switch (errno) { - case EAGAIN: - return; - case EINTR: - continue; - default: - gpr_log(GPR_ERROR, "error reading pipe: %s", strerror(errno)); - return; - } - } -} - -static void pipe_wakeup(grpc_wakeup_fd* fd_info) { - char c = 0; - while (write(fd_info->write_fd, &c, 1) != 1 && errno == EINTR) - ; -} - -static void pipe_destroy(grpc_wakeup_fd* fd_info) { - if (fd_info->read_fd != 0) close(fd_info->read_fd); - if (fd_info->write_fd != 0) close(fd_info->write_fd); -} - -static int pipe_check_availability(void) { - /* Assume that pipes are always available. */ - return 1; -} - -const grpc_wakeup_fd_vtable grpc_pipe_wakeup_fd_vtable = { - pipe_init, pipe_consume, pipe_wakeup, pipe_destroy, - pipe_check_availability}; - -#endif /* GPR_POSIX_WAKUP_FD */ diff --git a/src/core/iomgr/wakeup_fd_pipe.h b/src/core/iomgr/wakeup_fd_pipe.h deleted file mode 100644 index eb3e02b482..0000000000 --- a/src/core/iomgr/wakeup_fd_pipe.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * - * Copyright 2015-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_IOMGR_WAKEUP_FD_PIPE_H -#define GRPC_CORE_IOMGR_WAKEUP_FD_PIPE_H - -#include "src/core/iomgr/wakeup_fd_posix.h" - -extern grpc_wakeup_fd_vtable grpc_pipe_wakeup_fd_vtable; - -#endif /* GRPC_CORE_IOMGR_WAKEUP_FD_PIPE_H */ diff --git a/src/core/iomgr/wakeup_fd_posix.c b/src/core/iomgr/wakeup_fd_posix.c deleted file mode 100644 index 07778c408e..0000000000 --- a/src/core/iomgr/wakeup_fd_posix.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - * - * Copyright 2015-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 - -#ifdef GPR_POSIX_WAKEUP_FD - -#include -#include "src/core/iomgr/wakeup_fd_pipe.h" -#include "src/core/iomgr/wakeup_fd_posix.h" - -static const grpc_wakeup_fd_vtable *wakeup_fd_vtable = NULL; -int grpc_allow_specialized_wakeup_fd = 1; - -void grpc_wakeup_fd_global_init(void) { - if (grpc_allow_specialized_wakeup_fd && - grpc_specialized_wakeup_fd_vtable.check_availability()) { - wakeup_fd_vtable = &grpc_specialized_wakeup_fd_vtable; - } else { - wakeup_fd_vtable = &grpc_pipe_wakeup_fd_vtable; - } -} - -void grpc_wakeup_fd_global_destroy(void) { wakeup_fd_vtable = NULL; } - -void grpc_wakeup_fd_init(grpc_wakeup_fd *fd_info) { - wakeup_fd_vtable->init(fd_info); -} - -void grpc_wakeup_fd_consume_wakeup(grpc_wakeup_fd *fd_info) { - wakeup_fd_vtable->consume(fd_info); -} - -void grpc_wakeup_fd_wakeup(grpc_wakeup_fd *fd_info) { - wakeup_fd_vtable->wakeup(fd_info); -} - -void grpc_wakeup_fd_destroy(grpc_wakeup_fd *fd_info) { - wakeup_fd_vtable->destroy(fd_info); -} - -#endif /* GPR_POSIX_WAKEUP_FD */ diff --git a/src/core/iomgr/wakeup_fd_posix.h b/src/core/iomgr/wakeup_fd_posix.h deleted file mode 100644 index d7e3cf4673..0000000000 --- a/src/core/iomgr/wakeup_fd_posix.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * - * Copyright 2015-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. - * - */ - -/* - * wakeup_fd abstracts the concept of a file descriptor for the purpose of - * waking up a thread in select()/poll()/epoll_wait()/etc. - - * The poll() family of system calls provide a way for a thread to block until - * there is activity on one (or more) of a set of file descriptors. An - * application may wish to wake up this thread to do non file related work. The - * typical way to do this is to add a pipe to the set of file descriptors, then - * write to the pipe to wake up the thread in poll(). - * - * Linux has a lighter weight eventfd specifically designed for this purpose. - * wakeup_fd abstracts the difference between the two. - * - * Setup: - * 1. Before calling anything, call global_init() at least once. - * 1. Call grpc_wakeup_fd_create() to get a wakeup_fd. - * 2. Add the result of GRPC_WAKEUP_FD_FD to the set of monitored file - * descriptors for the poll() style API you are using. Monitor the file - * descriptor for readability. - * 3. To tear down, call grpc_wakeup_fd_destroy(). This closes the underlying - * file descriptor. - * - * Usage: - * 1. To wake up a polling thread, call grpc_wakeup_fd_wakeup() on a wakeup_fd - * it is monitoring. - * 2. If the polling thread was awakened by a wakeup_fd event, call - * grpc_wakeup_fd_consume_wakeup() on it. - */ -#ifndef GRPC_CORE_IOMGR_WAKEUP_FD_POSIX_H -#define GRPC_CORE_IOMGR_WAKEUP_FD_POSIX_H - -void grpc_wakeup_fd_global_init(void); -void grpc_wakeup_fd_global_destroy(void); - -/* Force using the fallback implementation. This is intended for testing - * purposes only.*/ -void grpc_wakeup_fd_global_init_force_fallback(void); - -typedef struct grpc_wakeup_fd grpc_wakeup_fd; - -typedef struct grpc_wakeup_fd_vtable { - void (*init)(grpc_wakeup_fd* fd_info); - void (*consume)(grpc_wakeup_fd* fd_info); - void (*wakeup)(grpc_wakeup_fd* fd_info); - void (*destroy)(grpc_wakeup_fd* fd_info); - /* Must be called before calling any other functions */ - int (*check_availability)(void); -} grpc_wakeup_fd_vtable; - -struct grpc_wakeup_fd { - int read_fd; - int write_fd; -}; - -extern int grpc_allow_specialized_wakeup_fd; - -#define GRPC_WAKEUP_FD_GET_READ_FD(fd_info) ((fd_info)->read_fd) - -void grpc_wakeup_fd_init(grpc_wakeup_fd* fd_info); -void grpc_wakeup_fd_consume_wakeup(grpc_wakeup_fd* fd_info); -void grpc_wakeup_fd_wakeup(grpc_wakeup_fd* fd_info); -void grpc_wakeup_fd_destroy(grpc_wakeup_fd* fd_info); - -/* Defined in some specialized implementation's .c file, or by - * wakeup_fd_nospecial.c if no such implementation exists. */ -extern const grpc_wakeup_fd_vtable grpc_specialized_wakeup_fd_vtable; - -#endif /* GRPC_CORE_IOMGR_WAKEUP_FD_POSIX_H */ diff --git a/src/core/iomgr/workqueue.h b/src/core/iomgr/workqueue.h deleted file mode 100644 index 2b923ba152..0000000000 --- a/src/core/iomgr/workqueue.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * - * Copyright 2015-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_IOMGR_WORKQUEUE_H -#define GRPC_CORE_IOMGR_WORKQUEUE_H - -#include "src/core/iomgr/closure.h" -#include "src/core/iomgr/exec_ctx.h" -#include "src/core/iomgr/iomgr.h" -#include "src/core/iomgr/pollset.h" - -#ifdef GPR_POSIX_SOCKET -#include "src/core/iomgr/workqueue_posix.h" -#endif - -#ifdef GPR_WIN32 -#include "src/core/iomgr/workqueue_windows.h" -#endif - -/* grpc_workqueue is forward declared in exec_ctx.h */ - -/** Create a work queue */ -grpc_workqueue *grpc_workqueue_create(grpc_exec_ctx *exec_ctx); - -void grpc_workqueue_flush(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue); - -#define GRPC_WORKQUEUE_REFCOUNT_DEBUG -#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG -#define GRPC_WORKQUEUE_REF(p, r) \ - grpc_workqueue_ref((p), __FILE__, __LINE__, (r)) -#define GRPC_WORKQUEUE_UNREF(cl, p, r) \ - grpc_workqueue_unref((cl), (p), __FILE__, __LINE__, (r)) -void grpc_workqueue_ref(grpc_workqueue *workqueue, const char *file, int line, - const char *reason); -void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue, - const char *file, int line, const char *reason); -#else -#define GRPC_WORKQUEUE_REF(p, r) grpc_workqueue_ref((p)) -#define GRPC_WORKQUEUE_UNREF(cl, p, r) grpc_workqueue_unref((cl), (p)) -void grpc_workqueue_ref(grpc_workqueue *workqueue); -void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue); -#endif - -/** Bind this workqueue to a pollset */ -void grpc_workqueue_add_to_pollset(grpc_exec_ctx *exec_ctx, - grpc_workqueue *workqueue, - grpc_pollset *pollset); - -/** Add a work item to a workqueue */ -void grpc_workqueue_push(grpc_workqueue *workqueue, grpc_closure *closure, - int success); - -#endif /* GRPC_CORE_IOMGR_WORKQUEUE_H */ diff --git a/src/core/iomgr/workqueue_posix.c b/src/core/iomgr/workqueue_posix.c deleted file mode 100644 index 2b42e6d4fb..0000000000 --- a/src/core/iomgr/workqueue_posix.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * - * Copyright 2015-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 - -#ifdef GPR_POSIX_SOCKET - -#include "src/core/iomgr/workqueue.h" - -#include - -#include -#include -#include - -#include "src/core/iomgr/fd_posix.h" -#include "src/core/iomgr/pollset_posix.h" - -static void on_readable(grpc_exec_ctx *exec_ctx, void *arg, bool success); - -grpc_workqueue *grpc_workqueue_create(grpc_exec_ctx *exec_ctx) { - char name[32]; - grpc_workqueue *workqueue = gpr_malloc(sizeof(grpc_workqueue)); - gpr_ref_init(&workqueue->refs, 1); - gpr_mu_init(&workqueue->mu); - workqueue->closure_list.head = workqueue->closure_list.tail = NULL; - grpc_wakeup_fd_init(&workqueue->wakeup_fd); - sprintf(name, "workqueue:%p", (void *)workqueue); - workqueue->wakeup_read_fd = - grpc_fd_create(GRPC_WAKEUP_FD_GET_READ_FD(&workqueue->wakeup_fd), name); - grpc_closure_init(&workqueue->read_closure, on_readable, workqueue); - grpc_fd_notify_on_read(exec_ctx, workqueue->wakeup_read_fd, - &workqueue->read_closure); - return workqueue; -} - -static void workqueue_destroy(grpc_exec_ctx *exec_ctx, - grpc_workqueue *workqueue) { - GPR_ASSERT(grpc_closure_list_empty(workqueue->closure_list)); - grpc_fd_shutdown(exec_ctx, workqueue->wakeup_read_fd); -} - -#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG -void grpc_workqueue_ref(grpc_workqueue *workqueue, const char *file, int line, - const char *reason) { - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "WORKQUEUE:%p ref %d -> %d %s", - workqueue, (int)workqueue->refs.count, (int)workqueue->refs.count + 1, - reason); -#else -void grpc_workqueue_ref(grpc_workqueue *workqueue) { -#endif - gpr_ref(&workqueue->refs); -} - -#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG -void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue, - const char *file, int line, const char *reason) { - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "WORKQUEUE:%p unref %d -> %d %s", - workqueue, (int)workqueue->refs.count, (int)workqueue->refs.count - 1, - reason); -#else -void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) { -#endif - if (gpr_unref(&workqueue->refs)) { - workqueue_destroy(exec_ctx, workqueue); - } -} - -void grpc_workqueue_add_to_pollset(grpc_exec_ctx *exec_ctx, - grpc_workqueue *workqueue, - grpc_pollset *pollset) { - grpc_pollset_add_fd(exec_ctx, pollset, workqueue->wakeup_read_fd); -} - -void grpc_workqueue_flush(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) { - gpr_mu_lock(&workqueue->mu); - if (grpc_closure_list_empty(workqueue->closure_list)) { - grpc_wakeup_fd_wakeup(&workqueue->wakeup_fd); - } - grpc_exec_ctx_enqueue_list(exec_ctx, &workqueue->closure_list, NULL); - gpr_mu_unlock(&workqueue->mu); -} - -static void on_readable(grpc_exec_ctx *exec_ctx, void *arg, bool success) { - grpc_workqueue *workqueue = arg; - - if (!success) { - gpr_mu_destroy(&workqueue->mu); - /* HACK: let wakeup_fd code know that we stole the fd */ - workqueue->wakeup_fd.read_fd = 0; - grpc_wakeup_fd_destroy(&workqueue->wakeup_fd); - grpc_fd_orphan(exec_ctx, workqueue->wakeup_read_fd, NULL, NULL, "destroy"); - gpr_free(workqueue); - } else { - gpr_mu_lock(&workqueue->mu); - grpc_exec_ctx_enqueue_list(exec_ctx, &workqueue->closure_list, NULL); - grpc_wakeup_fd_consume_wakeup(&workqueue->wakeup_fd); - gpr_mu_unlock(&workqueue->mu); - grpc_fd_notify_on_read(exec_ctx, workqueue->wakeup_read_fd, - &workqueue->read_closure); - } -} - -void grpc_workqueue_push(grpc_workqueue *workqueue, grpc_closure *closure, - int success) { - gpr_mu_lock(&workqueue->mu); - if (grpc_closure_list_empty(workqueue->closure_list)) { - grpc_wakeup_fd_wakeup(&workqueue->wakeup_fd); - } - grpc_closure_list_add(&workqueue->closure_list, closure, success); - gpr_mu_unlock(&workqueue->mu); -} - -#endif /* GPR_POSIX_SOCKET */ diff --git a/src/core/iomgr/workqueue_posix.h b/src/core/iomgr/workqueue_posix.h deleted file mode 100644 index 89937b1ea8..0000000000 --- a/src/core/iomgr/workqueue_posix.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * - * Copyright 2015-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_IOMGR_WORKQUEUE_POSIX_H -#define GRPC_CORE_IOMGR_WORKQUEUE_POSIX_H - -#include "src/core/iomgr/wakeup_fd_posix.h" - -struct grpc_fd; - -struct grpc_workqueue { - gpr_refcount refs; - - gpr_mu mu; - grpc_closure_list closure_list; - - grpc_wakeup_fd wakeup_fd; - struct grpc_fd *wakeup_read_fd; - - grpc_closure read_closure; -}; - -#endif /* GRPC_CORE_IOMGR_WORKQUEUE_POSIX_H */ diff --git a/src/core/iomgr/workqueue_windows.c b/src/core/iomgr/workqueue_windows.c deleted file mode 100644 index f9ca57557b..0000000000 --- a/src/core/iomgr/workqueue_windows.c +++ /dev/null @@ -1,40 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include - -#ifdef GPR_WIN32 - -#include "src/core/iomgr/workqueue.h" - -#endif /* GPR_WIN32 */ diff --git a/src/core/iomgr/workqueue_windows.h b/src/core/iomgr/workqueue_windows.h deleted file mode 100644 index 7e8186921e..0000000000 --- a/src/core/iomgr/workqueue_windows.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * - * Copyright 2015-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_IOMGR_WORKQUEUE_WINDOWS_H -#define GRPC_CORE_IOMGR_WORKQUEUE_WINDOWS_H - -#endif /* GRPC_CORE_IOMGR_WORKQUEUE_WINDOWS_H */ diff --git a/src/core/json/json.c b/src/core/json/json.c deleted file mode 100644 index 96e11eebb1..0000000000 --- a/src/core/json/json.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include - -#include - -#include "src/core/json/json.h" - -grpc_json *grpc_json_create(grpc_json_type type) { - grpc_json *json = gpr_malloc(sizeof(*json)); - memset(json, 0, sizeof(*json)); - json->type = type; - - return json; -} - -void grpc_json_destroy(grpc_json *json) { - while (json->child) { - grpc_json_destroy(json->child); - } - - if (json->next) { - json->next->prev = json->prev; - } - - if (json->prev) { - json->prev->next = json->next; - } else if (json->parent) { - json->parent->child = json->next; - } - - gpr_free(json); -} diff --git a/src/core/json/json.h b/src/core/json/json.h deleted file mode 100644 index aea9d5dadb..0000000000 --- a/src/core/json/json.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * - * Copyright 2015-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_JSON_JSON_H -#define GRPC_CORE_JSON_JSON_H - -#include - -#include "src/core/json/json_common.h" - -/* A tree-like structure to hold json values. The key and value pointers - * are not owned by it. - */ -typedef struct grpc_json { - struct grpc_json *next; - struct grpc_json *prev; - struct grpc_json *child; - struct grpc_json *parent; - - grpc_json_type type; - const char *key; - const char *value; -} grpc_json; - -/* The next two functions are going to parse the input string, and - * modify it in the process, in order to use its space to store - * all of the keys and values for the returned object tree. - * - * They assume UTF-8 input stream, and will output UTF-8 encoded - * strings in the tree. The input stream's UTF-8 isn't validated, - * as in, what you input is what you get as an output. - * - * All the keys and values in the grpc_json objects will be strings - * pointing at your input buffer. - * - * Delete the allocated tree afterward using grpc_json_destroy(). - */ -grpc_json *grpc_json_parse_string_with_len(char *input, size_t size); -grpc_json *grpc_json_parse_string(char *input); - -/* This function will create a new string using gpr_realloc, and will - * deserialize the grpc_json tree into it. It'll be zero-terminated, - * but will be allocated in chunks of 256 bytes. - * - * The indent parameter controls the way the output is formatted. - * If indent is 0, then newlines will be suppressed as well, and the - * output will be condensed at its maximum. - */ -char *grpc_json_dump_to_string(grpc_json *json, int indent); - -/* Use these to create or delete a grpc_json object. - * Deletion is recursive. We will not attempt to free any of the strings - * in any of the objects of that tree. - */ -grpc_json *grpc_json_create(grpc_json_type type); -void grpc_json_destroy(grpc_json *json); - -#endif /* GRPC_CORE_JSON_JSON_H */ diff --git a/src/core/json/json_common.h b/src/core/json/json_common.h deleted file mode 100644 index 7205a94685..0000000000 --- a/src/core/json/json_common.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * - * Copyright 2015-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_JSON_JSON_COMMON_H -#define GRPC_CORE_JSON_JSON_COMMON_H - -/* The various json types. */ -typedef enum { - GRPC_JSON_OBJECT, - GRPC_JSON_ARRAY, - GRPC_JSON_STRING, - GRPC_JSON_NUMBER, - GRPC_JSON_TRUE, - GRPC_JSON_FALSE, - GRPC_JSON_NULL, - GRPC_JSON_TOP_LEVEL -} grpc_json_type; - -#endif /* GRPC_CORE_JSON_JSON_COMMON_H */ diff --git a/src/core/json/json_reader.c b/src/core/json/json_reader.c deleted file mode 100644 index 30da6f28f3..0000000000 --- a/src/core/json/json_reader.c +++ /dev/null @@ -1,659 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include - -#include - -#include - -#include "src/core/json/json_reader.h" - -static void json_reader_string_clear(grpc_json_reader *reader) { - reader->vtable->string_clear(reader->userdata); -} - -static void json_reader_string_add_char(grpc_json_reader *reader, uint32_t c) { - reader->vtable->string_add_char(reader->userdata, c); -} - -static void json_reader_string_add_utf32(grpc_json_reader *reader, - uint32_t utf32) { - reader->vtable->string_add_utf32(reader->userdata, utf32); -} - -static uint32_t grpc_json_reader_read_char(grpc_json_reader *reader) { - return reader->vtable->read_char(reader->userdata); -} - -static void json_reader_container_begins(grpc_json_reader *reader, - grpc_json_type type) { - reader->vtable->container_begins(reader->userdata, type); -} - -static grpc_json_type grpc_json_reader_container_ends( - grpc_json_reader *reader) { - return reader->vtable->container_ends(reader->userdata); -} - -static void json_reader_set_key(grpc_json_reader *reader) { - reader->vtable->set_key(reader->userdata); -} - -static void json_reader_set_string(grpc_json_reader *reader) { - reader->vtable->set_string(reader->userdata); -} - -static int json_reader_set_number(grpc_json_reader *reader) { - return reader->vtable->set_number(reader->userdata); -} - -static void json_reader_set_true(grpc_json_reader *reader) { - reader->vtable->set_true(reader->userdata); -} - -static void json_reader_set_false(grpc_json_reader *reader) { - reader->vtable->set_false(reader->userdata); -} - -static void json_reader_set_null(grpc_json_reader *reader) { - reader->vtable->set_null(reader->userdata); -} - -/* Call this function to initialize the reader structure. */ -void grpc_json_reader_init(grpc_json_reader *reader, - grpc_json_reader_vtable *vtable, void *userdata) { - memset(reader, 0, sizeof(*reader)); - reader->vtable = vtable; - reader->userdata = userdata; - json_reader_string_clear(reader); - reader->state = GRPC_JSON_STATE_VALUE_BEGIN; -} - -int grpc_json_reader_is_complete(grpc_json_reader *reader) { - return ((reader->depth == 0) && - ((reader->state == GRPC_JSON_STATE_END) || - (reader->state == GRPC_JSON_STATE_VALUE_END))); -} - -grpc_json_reader_status grpc_json_reader_run(grpc_json_reader *reader) { - uint32_t c, success; - - /* This state-machine is a strict implementation of ECMA-404 */ - for (;;) { - c = grpc_json_reader_read_char(reader); - switch (c) { - /* Let's process the error cases first. */ - case GRPC_JSON_READ_CHAR_ERROR: - return GRPC_JSON_READ_ERROR; - - case GRPC_JSON_READ_CHAR_EAGAIN: - return GRPC_JSON_EAGAIN; - - case GRPC_JSON_READ_CHAR_EOF: - if (grpc_json_reader_is_complete(reader)) { - return GRPC_JSON_DONE; - } else { - return GRPC_JSON_PARSE_ERROR; - } - break; - - /* Processing whitespaces. */ - case ' ': - case '\t': - case '\n': - case '\r': - switch (reader->state) { - case GRPC_JSON_STATE_OBJECT_KEY_BEGIN: - case GRPC_JSON_STATE_OBJECT_KEY_END: - case GRPC_JSON_STATE_VALUE_BEGIN: - case GRPC_JSON_STATE_VALUE_END: - case GRPC_JSON_STATE_END: - break; - - case GRPC_JSON_STATE_OBJECT_KEY_STRING: - case GRPC_JSON_STATE_VALUE_STRING: - if (c != ' ') return GRPC_JSON_PARSE_ERROR; - if (reader->unicode_high_surrogate != 0) - return GRPC_JSON_PARSE_ERROR; - json_reader_string_add_char(reader, c); - break; - - case GRPC_JSON_STATE_VALUE_NUMBER: - case GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL: - case GRPC_JSON_STATE_VALUE_NUMBER_ZERO: - case GRPC_JSON_STATE_VALUE_NUMBER_EPM: - success = (uint32_t)json_reader_set_number(reader); - if (!success) return GRPC_JSON_PARSE_ERROR; - json_reader_string_clear(reader); - reader->state = GRPC_JSON_STATE_VALUE_END; - break; - - default: - return GRPC_JSON_PARSE_ERROR; - } - break; - - /* Value, object or array terminations. */ - case ',': - case '}': - case ']': - switch (reader->state) { - case GRPC_JSON_STATE_OBJECT_KEY_STRING: - case GRPC_JSON_STATE_VALUE_STRING: - if (reader->unicode_high_surrogate != 0) - return GRPC_JSON_PARSE_ERROR; - json_reader_string_add_char(reader, c); - break; - - case GRPC_JSON_STATE_VALUE_NUMBER: - case GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL: - case GRPC_JSON_STATE_VALUE_NUMBER_ZERO: - case GRPC_JSON_STATE_VALUE_NUMBER_EPM: - success = (uint32_t)json_reader_set_number(reader); - if (!success) return GRPC_JSON_PARSE_ERROR; - json_reader_string_clear(reader); - reader->state = GRPC_JSON_STATE_VALUE_END; - /* The missing break here is intentional. */ - - case GRPC_JSON_STATE_VALUE_END: - case GRPC_JSON_STATE_OBJECT_KEY_BEGIN: - case GRPC_JSON_STATE_VALUE_BEGIN: - if (c == ',') { - if (reader->state != GRPC_JSON_STATE_VALUE_END) { - return GRPC_JSON_PARSE_ERROR; - } - if (reader->in_object) { - reader->state = GRPC_JSON_STATE_OBJECT_KEY_BEGIN; - } else { - reader->state = GRPC_JSON_STATE_VALUE_BEGIN; - } - } else { - if (reader->depth-- == 0) return GRPC_JSON_PARSE_ERROR; - if ((c == '}') && !reader->in_object) { - return GRPC_JSON_PARSE_ERROR; - } - if ((c == '}') && - (reader->state == GRPC_JSON_STATE_OBJECT_KEY_BEGIN) && - !reader->container_just_begun) { - return GRPC_JSON_PARSE_ERROR; - } - if ((c == ']') && !reader->in_array) return GRPC_JSON_PARSE_ERROR; - if ((c == ']') && - (reader->state == GRPC_JSON_STATE_VALUE_BEGIN) && - !reader->container_just_begun) { - return GRPC_JSON_PARSE_ERROR; - } - reader->state = GRPC_JSON_STATE_VALUE_END; - switch (grpc_json_reader_container_ends(reader)) { - case GRPC_JSON_OBJECT: - reader->in_object = 1; - reader->in_array = 0; - break; - case GRPC_JSON_ARRAY: - reader->in_object = 0; - reader->in_array = 1; - break; - case GRPC_JSON_TOP_LEVEL: - GPR_ASSERT(reader->depth == 0); - reader->in_object = 0; - reader->in_array = 0; - reader->state = GRPC_JSON_STATE_END; - break; - default: - GPR_UNREACHABLE_CODE(return GRPC_JSON_INTERNAL_ERROR); - } - } - break; - - default: - return GRPC_JSON_PARSE_ERROR; - } - break; - - /* In-string escaping. */ - case '\\': - switch (reader->state) { - case GRPC_JSON_STATE_OBJECT_KEY_STRING: - reader->escaped_string_was_key = 1; - reader->state = GRPC_JSON_STATE_STRING_ESCAPE; - break; - - case GRPC_JSON_STATE_VALUE_STRING: - reader->escaped_string_was_key = 0; - reader->state = GRPC_JSON_STATE_STRING_ESCAPE; - break; - - /* This is the \\ case. */ - case GRPC_JSON_STATE_STRING_ESCAPE: - if (reader->unicode_high_surrogate != 0) - return GRPC_JSON_PARSE_ERROR; - json_reader_string_add_char(reader, '\\'); - if (reader->escaped_string_was_key) { - reader->state = GRPC_JSON_STATE_OBJECT_KEY_STRING; - } else { - reader->state = GRPC_JSON_STATE_VALUE_STRING; - } - break; - - default: - return GRPC_JSON_PARSE_ERROR; - } - break; - - default: - reader->container_just_begun = 0; - switch (reader->state) { - case GRPC_JSON_STATE_OBJECT_KEY_BEGIN: - if (c != '"') return GRPC_JSON_PARSE_ERROR; - reader->state = GRPC_JSON_STATE_OBJECT_KEY_STRING; - break; - - case GRPC_JSON_STATE_OBJECT_KEY_STRING: - GPR_ASSERT(reader->unicode_high_surrogate == 0); - if (c == '"') { - reader->state = GRPC_JSON_STATE_OBJECT_KEY_END; - json_reader_set_key(reader); - json_reader_string_clear(reader); - } else { - if (c <= 0x001f) return GRPC_JSON_PARSE_ERROR; - json_reader_string_add_char(reader, c); - } - break; - - case GRPC_JSON_STATE_VALUE_STRING: - if (reader->unicode_high_surrogate != 0) - return GRPC_JSON_PARSE_ERROR; - if (c == '"') { - reader->state = GRPC_JSON_STATE_VALUE_END; - json_reader_set_string(reader); - json_reader_string_clear(reader); - } else { - if (c < 32) return GRPC_JSON_PARSE_ERROR; - json_reader_string_add_char(reader, c); - } - break; - - case GRPC_JSON_STATE_OBJECT_KEY_END: - if (c != ':') return GRPC_JSON_PARSE_ERROR; - reader->state = GRPC_JSON_STATE_VALUE_BEGIN; - break; - - case GRPC_JSON_STATE_VALUE_BEGIN: - switch (c) { - case 't': - reader->state = GRPC_JSON_STATE_VALUE_TRUE_R; - break; - - case 'f': - reader->state = GRPC_JSON_STATE_VALUE_FALSE_A; - break; - - case 'n': - reader->state = GRPC_JSON_STATE_VALUE_NULL_U; - break; - - case '"': - reader->state = GRPC_JSON_STATE_VALUE_STRING; - break; - - case '0': - json_reader_string_add_char(reader, c); - reader->state = GRPC_JSON_STATE_VALUE_NUMBER_ZERO; - break; - - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '-': - json_reader_string_add_char(reader, c); - reader->state = GRPC_JSON_STATE_VALUE_NUMBER; - break; - - case '{': - reader->container_just_begun = 1; - json_reader_container_begins(reader, GRPC_JSON_OBJECT); - reader->depth++; - reader->state = GRPC_JSON_STATE_OBJECT_KEY_BEGIN; - reader->in_object = 1; - reader->in_array = 0; - break; - - case '[': - reader->container_just_begun = 1; - json_reader_container_begins(reader, GRPC_JSON_ARRAY); - reader->depth++; - reader->in_object = 0; - reader->in_array = 1; - break; - } - break; - - case GRPC_JSON_STATE_STRING_ESCAPE: - if (reader->escaped_string_was_key) { - reader->state = GRPC_JSON_STATE_OBJECT_KEY_STRING; - } else { - reader->state = GRPC_JSON_STATE_VALUE_STRING; - } - if (reader->unicode_high_surrogate && c != 'u') - return GRPC_JSON_PARSE_ERROR; - switch (c) { - case '"': - case '/': - json_reader_string_add_char(reader, c); - break; - case 'b': - json_reader_string_add_char(reader, '\b'); - break; - case 'f': - json_reader_string_add_char(reader, '\f'); - break; - case 'n': - json_reader_string_add_char(reader, '\n'); - break; - case 'r': - json_reader_string_add_char(reader, '\r'); - break; - case 't': - json_reader_string_add_char(reader, '\t'); - break; - case 'u': - reader->state = GRPC_JSON_STATE_STRING_ESCAPE_U1; - reader->unicode_char = 0; - break; - default: - return GRPC_JSON_PARSE_ERROR; - } - break; - - case GRPC_JSON_STATE_STRING_ESCAPE_U1: - case GRPC_JSON_STATE_STRING_ESCAPE_U2: - case GRPC_JSON_STATE_STRING_ESCAPE_U3: - case GRPC_JSON_STATE_STRING_ESCAPE_U4: - if ((c >= '0') && (c <= '9')) { - c -= '0'; - } else if ((c >= 'A') && (c <= 'F')) { - c -= 'A' - 10; - } else if ((c >= 'a') && (c <= 'f')) { - c -= 'a' - 10; - } else { - return GRPC_JSON_PARSE_ERROR; - } - reader->unicode_char = (uint16_t)(reader->unicode_char << 4); - reader->unicode_char = (uint16_t)(reader->unicode_char | c); - - switch (reader->state) { - case GRPC_JSON_STATE_STRING_ESCAPE_U1: - reader->state = GRPC_JSON_STATE_STRING_ESCAPE_U2; - break; - case GRPC_JSON_STATE_STRING_ESCAPE_U2: - reader->state = GRPC_JSON_STATE_STRING_ESCAPE_U3; - break; - case GRPC_JSON_STATE_STRING_ESCAPE_U3: - reader->state = GRPC_JSON_STATE_STRING_ESCAPE_U4; - break; - case GRPC_JSON_STATE_STRING_ESCAPE_U4: - /* See grpc_json_writer_escape_string to have a description - * of what's going on here. - */ - if ((reader->unicode_char & 0xfc00) == 0xd800) { - /* high surrogate utf-16 */ - if (reader->unicode_high_surrogate != 0) - return GRPC_JSON_PARSE_ERROR; - reader->unicode_high_surrogate = reader->unicode_char; - } else if ((reader->unicode_char & 0xfc00) == 0xdc00) { - /* low surrogate utf-16 */ - uint32_t utf32; - if (reader->unicode_high_surrogate == 0) - return GRPC_JSON_PARSE_ERROR; - utf32 = 0x10000; - utf32 += (uint32_t)( - (reader->unicode_high_surrogate - 0xd800) * 0x400); - utf32 += (uint32_t)(reader->unicode_char - 0xdc00); - json_reader_string_add_utf32(reader, utf32); - reader->unicode_high_surrogate = 0; - } else { - /* anything else */ - if (reader->unicode_high_surrogate != 0) - return GRPC_JSON_PARSE_ERROR; - json_reader_string_add_utf32(reader, reader->unicode_char); - } - if (reader->escaped_string_was_key) { - reader->state = GRPC_JSON_STATE_OBJECT_KEY_STRING; - } else { - reader->state = GRPC_JSON_STATE_VALUE_STRING; - } - break; - default: - GPR_UNREACHABLE_CODE(return GRPC_JSON_INTERNAL_ERROR); - } - break; - - case GRPC_JSON_STATE_VALUE_NUMBER: - json_reader_string_add_char(reader, c); - switch (c) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - break; - case 'e': - case 'E': - reader->state = GRPC_JSON_STATE_VALUE_NUMBER_E; - break; - case '.': - reader->state = GRPC_JSON_STATE_VALUE_NUMBER_DOT; - break; - default: - return GRPC_JSON_PARSE_ERROR; - } - break; - - case GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL: - json_reader_string_add_char(reader, c); - switch (c) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - break; - case 'e': - case 'E': - reader->state = GRPC_JSON_STATE_VALUE_NUMBER_E; - break; - default: - return GRPC_JSON_PARSE_ERROR; - } - break; - - case GRPC_JSON_STATE_VALUE_NUMBER_ZERO: - if (c != '.') return GRPC_JSON_PARSE_ERROR; - json_reader_string_add_char(reader, c); - reader->state = GRPC_JSON_STATE_VALUE_NUMBER_DOT; - break; - - case GRPC_JSON_STATE_VALUE_NUMBER_DOT: - json_reader_string_add_char(reader, c); - switch (c) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - reader->state = GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL; - break; - default: - return GRPC_JSON_PARSE_ERROR; - } - break; - - case GRPC_JSON_STATE_VALUE_NUMBER_E: - json_reader_string_add_char(reader, c); - switch (c) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '+': - case '-': - reader->state = GRPC_JSON_STATE_VALUE_NUMBER_EPM; - break; - default: - return GRPC_JSON_PARSE_ERROR; - } - break; - - case GRPC_JSON_STATE_VALUE_NUMBER_EPM: - json_reader_string_add_char(reader, c); - switch (c) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - break; - default: - return GRPC_JSON_PARSE_ERROR; - } - break; - - case GRPC_JSON_STATE_VALUE_TRUE_R: - if (c != 'r') return GRPC_JSON_PARSE_ERROR; - reader->state = GRPC_JSON_STATE_VALUE_TRUE_U; - break; - - case GRPC_JSON_STATE_VALUE_TRUE_U: - if (c != 'u') return GRPC_JSON_PARSE_ERROR; - reader->state = GRPC_JSON_STATE_VALUE_TRUE_E; - break; - - case GRPC_JSON_STATE_VALUE_TRUE_E: - if (c != 'e') return GRPC_JSON_PARSE_ERROR; - json_reader_set_true(reader); - reader->state = GRPC_JSON_STATE_VALUE_END; - break; - - case GRPC_JSON_STATE_VALUE_FALSE_A: - if (c != 'a') return GRPC_JSON_PARSE_ERROR; - reader->state = GRPC_JSON_STATE_VALUE_FALSE_L; - break; - - case GRPC_JSON_STATE_VALUE_FALSE_L: - if (c != 'l') return GRPC_JSON_PARSE_ERROR; - reader->state = GRPC_JSON_STATE_VALUE_FALSE_S; - break; - - case GRPC_JSON_STATE_VALUE_FALSE_S: - if (c != 's') return GRPC_JSON_PARSE_ERROR; - reader->state = GRPC_JSON_STATE_VALUE_FALSE_E; - break; - - case GRPC_JSON_STATE_VALUE_FALSE_E: - if (c != 'e') return GRPC_JSON_PARSE_ERROR; - json_reader_set_false(reader); - reader->state = GRPC_JSON_STATE_VALUE_END; - break; - - case GRPC_JSON_STATE_VALUE_NULL_U: - if (c != 'u') return GRPC_JSON_PARSE_ERROR; - reader->state = GRPC_JSON_STATE_VALUE_NULL_L1; - break; - - case GRPC_JSON_STATE_VALUE_NULL_L1: - if (c != 'l') return GRPC_JSON_PARSE_ERROR; - reader->state = GRPC_JSON_STATE_VALUE_NULL_L2; - break; - - case GRPC_JSON_STATE_VALUE_NULL_L2: - if (c != 'l') return GRPC_JSON_PARSE_ERROR; - json_reader_set_null(reader); - reader->state = GRPC_JSON_STATE_VALUE_END; - break; - - /* All of the VALUE_END cases are handled in the specialized case - * above. */ - case GRPC_JSON_STATE_VALUE_END: - switch (c) { - case ',': - case '}': - case ']': - GPR_UNREACHABLE_CODE(return GRPC_JSON_INTERNAL_ERROR); - break; - - default: - return GRPC_JSON_PARSE_ERROR; - } - break; - - case GRPC_JSON_STATE_END: - return GRPC_JSON_PARSE_ERROR; - } - } - } - - GPR_UNREACHABLE_CODE(return GRPC_JSON_INTERNAL_ERROR); -} diff --git a/src/core/json/json_reader.h b/src/core/json/json_reader.h deleted file mode 100644 index f25f44b2ef..0000000000 --- a/src/core/json/json_reader.h +++ /dev/null @@ -1,160 +0,0 @@ -/* - * - * Copyright 2015-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_JSON_JSON_READER_H -#define GRPC_CORE_JSON_JSON_READER_H - -#include -#include "src/core/json/json_common.h" - -typedef enum { - GRPC_JSON_STATE_OBJECT_KEY_BEGIN, - GRPC_JSON_STATE_OBJECT_KEY_STRING, - GRPC_JSON_STATE_OBJECT_KEY_END, - GRPC_JSON_STATE_VALUE_BEGIN, - GRPC_JSON_STATE_VALUE_STRING, - GRPC_JSON_STATE_STRING_ESCAPE, - GRPC_JSON_STATE_STRING_ESCAPE_U1, - GRPC_JSON_STATE_STRING_ESCAPE_U2, - GRPC_JSON_STATE_STRING_ESCAPE_U3, - GRPC_JSON_STATE_STRING_ESCAPE_U4, - GRPC_JSON_STATE_VALUE_NUMBER, - GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL, - GRPC_JSON_STATE_VALUE_NUMBER_ZERO, - GRPC_JSON_STATE_VALUE_NUMBER_DOT, - GRPC_JSON_STATE_VALUE_NUMBER_E, - GRPC_JSON_STATE_VALUE_NUMBER_EPM, - GRPC_JSON_STATE_VALUE_TRUE_R, - GRPC_JSON_STATE_VALUE_TRUE_U, - GRPC_JSON_STATE_VALUE_TRUE_E, - GRPC_JSON_STATE_VALUE_FALSE_A, - GRPC_JSON_STATE_VALUE_FALSE_L, - GRPC_JSON_STATE_VALUE_FALSE_S, - GRPC_JSON_STATE_VALUE_FALSE_E, - GRPC_JSON_STATE_VALUE_NULL_U, - GRPC_JSON_STATE_VALUE_NULL_L1, - GRPC_JSON_STATE_VALUE_NULL_L2, - GRPC_JSON_STATE_VALUE_END, - GRPC_JSON_STATE_END -} grpc_json_reader_state; - -enum { - /* The first non-unicode value is 0x110000. But let's pick - * a value high enough to start our error codes from. These - * values are safe to return from the read_char function. - */ - GRPC_JSON_READ_CHAR_EOF = 0x7ffffff0, - GRPC_JSON_READ_CHAR_EAGAIN, - GRPC_JSON_READ_CHAR_ERROR -}; - -struct grpc_json_reader; - -typedef struct grpc_json_reader_vtable { - /* Clears your internal string scratchpad. */ - void (*string_clear)(void *userdata); - /* Adds a char to the string scratchpad. */ - void (*string_add_char)(void *userdata, uint32_t c); - /* Adds a utf32 char to the string scratchpad. */ - void (*string_add_utf32)(void *userdata, uint32_t c); - /* Reads a character from your input. May be utf-8, 16 or 32. */ - uint32_t (*read_char)(void *userdata); - /* Starts a container of type GRPC_JSON_ARRAY or GRPC_JSON_OBJECT. */ - void (*container_begins)(void *userdata, grpc_json_type type); - /* Ends the current container. Must return the type of its parent. */ - grpc_json_type (*container_ends)(void *userdata); - /* Your internal string scratchpad is an object's key. */ - void (*set_key)(void *userdata); - /* Your internal string scratchpad is a string value. */ - void (*set_string)(void *userdata); - /* Your internal string scratchpad is a numerical value. Return 1 if valid. */ - int (*set_number)(void *userdata); - /* Sets the values true, false or null. */ - void (*set_true)(void *userdata); - void (*set_false)(void *userdata); - void (*set_null)(void *userdata); -} grpc_json_reader_vtable; - -typedef struct grpc_json_reader { - /* That structure is fully private, and initialized by grpc_json_reader_init. - * The definition is public so you can put it on your stack. - */ - - void *userdata; - grpc_json_reader_vtable *vtable; - int depth; - int in_object; - int in_array; - int escaped_string_was_key; - int container_just_begun; - uint16_t unicode_char, unicode_high_surrogate; - grpc_json_reader_state state; -} grpc_json_reader; - -/* The return type of the parser. */ -typedef enum { - GRPC_JSON_DONE, /* The parser finished successfully. */ - GRPC_JSON_EAGAIN, /* The parser yields to get more data. */ - GRPC_JSON_READ_ERROR, /* The parser passes through a read error. */ - GRPC_JSON_PARSE_ERROR, /* The parser found an error in the json stream. */ - GRPC_JSON_INTERNAL_ERROR /* The parser got an internal error. */ -} grpc_json_reader_status; - -/* Call this function to start parsing the input. It will return the following: - * . GRPC_JSON_DONE if the input got eof, and the parsing finished - * successfully. - * . GRPC_JSON_EAGAIN if the read_char function returned again. Call the - * parser again as needed. It is okay to call the parser in polling mode, - * although a bit dull. - * . GRPC_JSON_READ_ERROR if the read_char function returned an error. The - * state isn't broken however, and the function can be called again if the - * error has been corrected. But please use the EAGAIN feature instead for - * consistency. - * . GRPC_JSON_PARSE_ERROR if the input was somehow invalid. - * . GRPC_JSON_INTERNAL_ERROR if the parser somehow ended into an invalid - * internal state. - */ -grpc_json_reader_status grpc_json_reader_run(grpc_json_reader *reader); - -/* Call this function to initialize the reader structure. */ -void grpc_json_reader_init(grpc_json_reader *reader, - grpc_json_reader_vtable *vtable, void *userdata); - -/* You may call this from the read_char callback if you don't know where is the - * end of your input stream, and you'd like the json reader to hint you that it - * has completed reading its input, so you can return an EOF to it. Note that - * there might still be trailing whitespaces after that point. - */ -int grpc_json_reader_is_complete(grpc_json_reader *reader); - -#endif /* GRPC_CORE_JSON_JSON_READER_H */ diff --git a/src/core/json/json_string.c b/src/core/json/json_string.c deleted file mode 100644 index d4ebce18e1..0000000000 --- a/src/core/json/json_string.c +++ /dev/null @@ -1,379 +0,0 @@ -/* - * - * Copyright 2015-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 -#include - -#include -#include - -#include "src/core/json/json.h" -#include "src/core/json/json_reader.h" -#include "src/core/json/json_writer.h" - -/* The json reader will construct a bunch of grpc_json objects and - * link them all up together in a tree-like structure that will represent - * the json data in memory. - * - * It also uses its own input as a scratchpad to store all of the decoded, - * unescaped strings. So we need to keep track of all these pointers in - * that opaque structure the reader will carry for us. - * - * Note that this works because the act of parsing json always reduces its - * input size, and never expands it. - */ -typedef struct { - grpc_json *top; - grpc_json *current_container; - grpc_json *current_value; - uint8_t *input; - uint8_t *key; - uint8_t *string; - uint8_t *string_ptr; - size_t remaining_input; -} json_reader_userdata; - -/* This json writer will put everything in a big string. - * The point is that we allocate that string in chunks of 256 bytes. - */ -typedef struct { - char *output; - size_t free_space; - size_t string_len; - size_t allocated; -} json_writer_userdata; - -/* This function checks if there's enough space left in the output buffer, - * and will enlarge it if necessary. We're only allocating chunks of 256 - * bytes at a time (or multiples thereof). - */ -static void json_writer_output_check(void *userdata, size_t needed) { - json_writer_userdata *state = userdata; - if (state->free_space >= needed) return; - needed -= state->free_space; - /* Round up by 256 bytes. */ - needed = (needed + 0xff) & ~0xffU; - state->output = gpr_realloc(state->output, state->allocated + needed); - state->free_space += needed; - state->allocated += needed; -} - -/* These are needed by the writer's implementation. */ -static void json_writer_output_char(void *userdata, char c) { - json_writer_userdata *state = userdata; - json_writer_output_check(userdata, 1); - state->output[state->string_len++] = c; - state->free_space--; -} - -static void json_writer_output_string_with_len(void *userdata, const char *str, - size_t len) { - json_writer_userdata *state = userdata; - json_writer_output_check(userdata, len); - memcpy(state->output + state->string_len, str, len); - state->string_len += len; - state->free_space -= len; -} - -static void json_writer_output_string(void *userdata, const char *str) { - size_t len = strlen(str); - json_writer_output_string_with_len(userdata, str, len); -} - -/* The reader asks us to clear our scratchpad. In our case, we'll simply mark - * the end of the current string, and advance our output pointer. - */ -static void json_reader_string_clear(void *userdata) { - json_reader_userdata *state = userdata; - if (state->string) { - GPR_ASSERT(state->string_ptr < state->input); - *state->string_ptr++ = 0; - } - state->string = state->string_ptr; -} - -static void json_reader_string_add_char(void *userdata, uint32_t c) { - json_reader_userdata *state = userdata; - GPR_ASSERT(state->string_ptr < state->input); - GPR_ASSERT(c <= 0xff); - *state->string_ptr++ = (uint8_t)c; -} - -/* We are converting a UTF-32 character into UTF-8 here, - * as described by RFC3629. - */ -static void json_reader_string_add_utf32(void *userdata, uint32_t c) { - if (c <= 0x7f) { - json_reader_string_add_char(userdata, c); - } else if (c <= 0x7ff) { - uint32_t b1 = 0xc0 | ((c >> 6) & 0x1f); - uint32_t b2 = 0x80 | (c & 0x3f); - json_reader_string_add_char(userdata, b1); - json_reader_string_add_char(userdata, b2); - } else if (c <= 0xffff) { - uint32_t b1 = 0xe0 | ((c >> 12) & 0x0f); - uint32_t b2 = 0x80 | ((c >> 6) & 0x3f); - uint32_t b3 = 0x80 | (c & 0x3f); - json_reader_string_add_char(userdata, b1); - json_reader_string_add_char(userdata, b2); - json_reader_string_add_char(userdata, b3); - } else if (c <= 0x1fffff) { - uint32_t b1 = 0xf0 | ((c >> 18) & 0x07); - uint32_t b2 = 0x80 | ((c >> 12) & 0x3f); - uint32_t b3 = 0x80 | ((c >> 6) & 0x3f); - uint32_t b4 = 0x80 | (c & 0x3f); - json_reader_string_add_char(userdata, b1); - json_reader_string_add_char(userdata, b2); - json_reader_string_add_char(userdata, b3); - json_reader_string_add_char(userdata, b4); - } -} - -/* We consider that the input may be a zero-terminated string. So we - * can end up hitting eof before the end of the alleged string length. - */ -static uint32_t json_reader_read_char(void *userdata) { - uint32_t r; - json_reader_userdata *state = userdata; - - if (state->remaining_input == 0) return GRPC_JSON_READ_CHAR_EOF; - - r = *state->input++; - state->remaining_input--; - - if (r == 0) { - state->remaining_input = 0; - return GRPC_JSON_READ_CHAR_EOF; - } - - return r; -} - -/* Helper function to create a new grpc_json object and link it into - * our tree-in-progress inside our opaque structure. - */ -static grpc_json *json_create_and_link(void *userdata, grpc_json_type type) { - json_reader_userdata *state = userdata; - grpc_json *json = grpc_json_create(type); - - json->parent = state->current_container; - json->prev = state->current_value; - state->current_value = json; - - if (json->prev) { - json->prev->next = json; - } - if (json->parent) { - if (!json->parent->child) { - json->parent->child = json; - } - if (json->parent->type == GRPC_JSON_OBJECT) { - json->key = (char *)state->key; - } - } - if (!state->top) { - state->top = json; - } - - return json; -} - -static void json_reader_container_begins(void *userdata, grpc_json_type type) { - json_reader_userdata *state = userdata; - grpc_json *container; - - GPR_ASSERT(type == GRPC_JSON_ARRAY || type == GRPC_JSON_OBJECT); - - container = json_create_and_link(userdata, type); - state->current_container = container; - state->current_value = NULL; -} - -/* It's important to remember that the reader is mostly stateless, so it - * isn't trying to remember what the container was prior the one that just - * ends. Since we're keeping track of these for our own purpose, we are - * able to return that information back, which is useful for it to validate - * the input json stream. - * - * Also note that if we're at the top of the tree, and the last container - * ends, we have to return GRPC_JSON_TOP_LEVEL. - */ -static grpc_json_type json_reader_container_ends(void *userdata) { - grpc_json_type container_type = GRPC_JSON_TOP_LEVEL; - json_reader_userdata *state = userdata; - - GPR_ASSERT(state->current_container); - - state->current_value = state->current_container; - state->current_container = state->current_container->parent; - - if (state->current_container) { - container_type = state->current_container->type; - } - - return container_type; -} - -/* The next 3 functions basically are the reader asking us to use our string - * scratchpad for one of these 3 purposes. - * - * Note that in the set_number case, we're not going to try interpreting it. - * We'll keep it as a string, and leave it to the caller to evaluate it. - */ -static void json_reader_set_key(void *userdata) { - json_reader_userdata *state = userdata; - state->key = state->string; -} - -static void json_reader_set_string(void *userdata) { - json_reader_userdata *state = userdata; - grpc_json *json = json_create_and_link(userdata, GRPC_JSON_STRING); - json->value = (char *)state->string; -} - -static int json_reader_set_number(void *userdata) { - json_reader_userdata *state = userdata; - grpc_json *json = json_create_and_link(userdata, GRPC_JSON_NUMBER); - json->value = (char *)state->string; - return 1; -} - -/* The object types true, false and null are self-sufficient, and don't need - * any more information beside their type. - */ -static void json_reader_set_true(void *userdata) { - json_create_and_link(userdata, GRPC_JSON_TRUE); -} - -static void json_reader_set_false(void *userdata) { - json_create_and_link(userdata, GRPC_JSON_FALSE); -} - -static void json_reader_set_null(void *userdata) { - json_create_and_link(userdata, GRPC_JSON_NULL); -} - -static grpc_json_reader_vtable reader_vtable = { - json_reader_string_clear, json_reader_string_add_char, - json_reader_string_add_utf32, json_reader_read_char, - json_reader_container_begins, json_reader_container_ends, - json_reader_set_key, json_reader_set_string, - json_reader_set_number, json_reader_set_true, - json_reader_set_false, json_reader_set_null}; - -/* And finally, let's define our public API. */ -grpc_json *grpc_json_parse_string_with_len(char *input, size_t size) { - grpc_json_reader reader; - json_reader_userdata state; - grpc_json *json = NULL; - grpc_json_reader_status status; - - if (!input) return NULL; - - state.top = state.current_container = state.current_value = NULL; - state.string = state.key = NULL; - state.string_ptr = state.input = (uint8_t *)input; - state.remaining_input = size; - grpc_json_reader_init(&reader, &reader_vtable, &state); - - status = grpc_json_reader_run(&reader); - json = state.top; - - if ((status != GRPC_JSON_DONE) && json) { - grpc_json_destroy(json); - json = NULL; - } - - return json; -} - -#define UNBOUND_JSON_STRING_LENGTH 0x7fffffff - -grpc_json *grpc_json_parse_string(char *input) { - return grpc_json_parse_string_with_len(input, UNBOUND_JSON_STRING_LENGTH); -} - -static void json_dump_recursive(grpc_json_writer *writer, grpc_json *json, - int in_object) { - while (json) { - if (in_object) grpc_json_writer_object_key(writer, json->key); - - switch (json->type) { - case GRPC_JSON_OBJECT: - case GRPC_JSON_ARRAY: - grpc_json_writer_container_begins(writer, json->type); - if (json->child) - json_dump_recursive(writer, json->child, - json->type == GRPC_JSON_OBJECT); - grpc_json_writer_container_ends(writer, json->type); - break; - case GRPC_JSON_STRING: - grpc_json_writer_value_string(writer, json->value); - break; - case GRPC_JSON_NUMBER: - grpc_json_writer_value_raw(writer, json->value); - break; - case GRPC_JSON_TRUE: - grpc_json_writer_value_raw_with_len(writer, "true", 4); - break; - case GRPC_JSON_FALSE: - grpc_json_writer_value_raw_with_len(writer, "false", 5); - break; - case GRPC_JSON_NULL: - grpc_json_writer_value_raw_with_len(writer, "null", 4); - break; - default: - GPR_UNREACHABLE_CODE(abort()); - } - json = json->next; - } -} - -static grpc_json_writer_vtable writer_vtable = { - json_writer_output_char, json_writer_output_string, - json_writer_output_string_with_len}; - -char *grpc_json_dump_to_string(grpc_json *json, int indent) { - grpc_json_writer writer; - json_writer_userdata state; - - state.output = NULL; - state.free_space = state.string_len = state.allocated = 0; - grpc_json_writer_init(&writer, indent, &writer_vtable, &state); - - json_dump_recursive(&writer, json, 0); - - json_writer_output_char(&state, 0); - - return state.output; -} diff --git a/src/core/json/json_writer.c b/src/core/json/json_writer.c deleted file mode 100644 index 326ec2d431..0000000000 --- a/src/core/json/json_writer.c +++ /dev/null @@ -1,258 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include - -#include - -#include "src/core/json/json_writer.h" - -static void json_writer_output_char(grpc_json_writer *writer, char c) { - writer->vtable->output_char(writer->userdata, c); -} - -static void json_writer_output_string(grpc_json_writer *writer, - const char *str) { - writer->vtable->output_string(writer->userdata, str); -} - -static void json_writer_output_string_with_len(grpc_json_writer *writer, - const char *str, size_t len) { - writer->vtable->output_string_with_len(writer->userdata, str, len); -} - -void grpc_json_writer_init(grpc_json_writer *writer, int indent, - grpc_json_writer_vtable *vtable, void *userdata) { - memset(writer, 0, sizeof(*writer)); - writer->container_empty = 1; - writer->indent = indent; - writer->vtable = vtable; - writer->userdata = userdata; -} - -static void json_writer_output_indent(grpc_json_writer *writer) { - static const char spacesstr[] = - " " - " " - " " - " "; - - unsigned spaces = (unsigned)(writer->depth * writer->indent); - - if (writer->indent == 0) return; - - if (writer->got_key) { - json_writer_output_char(writer, ' '); - return; - } - - while (spaces >= (sizeof(spacesstr) - 1)) { - json_writer_output_string_with_len(writer, spacesstr, - sizeof(spacesstr) - 1); - spaces -= (unsigned)(sizeof(spacesstr) - 1); - } - - if (spaces == 0) return; - - json_writer_output_string_with_len( - writer, spacesstr + sizeof(spacesstr) - 1 - spaces, spaces); -} - -static void json_writer_value_end(grpc_json_writer *writer) { - if (writer->container_empty) { - writer->container_empty = 0; - if ((writer->indent == 0) || (writer->depth == 0)) return; - json_writer_output_char(writer, '\n'); - } else { - json_writer_output_char(writer, ','); - if (writer->indent == 0) return; - json_writer_output_char(writer, '\n'); - } -} - -static void json_writer_escape_utf16(grpc_json_writer *writer, uint16_t utf16) { - static const char hex[] = "0123456789abcdef"; - - json_writer_output_string_with_len(writer, "\\u", 2); - json_writer_output_char(writer, hex[(utf16 >> 12) & 0x0f]); - json_writer_output_char(writer, hex[(utf16 >> 8) & 0x0f]); - json_writer_output_char(writer, hex[(utf16 >> 4) & 0x0f]); - json_writer_output_char(writer, hex[(utf16)&0x0f]); -} - -static void json_writer_escape_string(grpc_json_writer *writer, - const char *string) { - json_writer_output_char(writer, '"'); - - for (;;) { - uint8_t c = (uint8_t)*string++; - if (c == 0) { - break; - } else if ((c >= 32) && (c <= 126)) { - if ((c == '\\') || (c == '"')) json_writer_output_char(writer, '\\'); - json_writer_output_char(writer, (char)c); - } else if ((c < 32) || (c == 127)) { - switch (c) { - case '\b': - json_writer_output_string_with_len(writer, "\\b", 2); - break; - case '\f': - json_writer_output_string_with_len(writer, "\\f", 2); - break; - case '\n': - json_writer_output_string_with_len(writer, "\\n", 2); - break; - case '\r': - json_writer_output_string_with_len(writer, "\\r", 2); - break; - case '\t': - json_writer_output_string_with_len(writer, "\\t", 2); - break; - default: - json_writer_escape_utf16(writer, c); - break; - } - } else { - uint32_t utf32 = 0; - int extra = 0; - int i; - int valid = 1; - if ((c & 0xe0) == 0xc0) { - utf32 = c & 0x1f; - extra = 1; - } else if ((c & 0xf0) == 0xe0) { - utf32 = c & 0x0f; - extra = 2; - } else if ((c & 0xf8) == 0xf0) { - utf32 = c & 0x07; - extra = 3; - } else { - break; - } - for (i = 0; i < extra; i++) { - utf32 <<= 6; - c = (uint8_t)(*string++); - /* Breaks out and bail on any invalid UTF-8 sequence, including \0. */ - if ((c & 0xc0) != 0x80) { - valid = 0; - break; - } - utf32 |= c & 0x3f; - } - if (!valid) break; - /* The range 0xd800 - 0xdfff is reserved by the surrogates ad vitam. - * Any other range is technically reserved for future usage, so if we - * don't want the software to break in the future, we have to allow - * anything else. The first non-unicode character is 0x110000. */ - if (((utf32 >= 0xd800) && (utf32 <= 0xdfff)) || (utf32 >= 0x110000)) - break; - if (utf32 >= 0x10000) { - /* If utf32 contains a character that is above 0xffff, it needs to be - * broken down into a utf-16 surrogate pair. A surrogate pair is first - * a high surrogate, followed by a low surrogate. Each surrogate holds - * 10 bits of usable data, thus allowing a total of 20 bits of data. - * The high surrogate marker is 0xd800, while the low surrogate marker - * is 0xdc00. The low 10 bits of each will be the usable data. - * - * After re-combining the 20 bits of data, one has to add 0x10000 to - * the resulting value, in order to obtain the original character. - * This is obviously because the range 0x0000 - 0xffff can be written - * without any special trick. - * - * Since 0x10ffff is the highest allowed character, we're working in - * the range 0x00000 - 0xfffff after we decrement it by 0x10000. - * That range is exactly 20 bits. - */ - utf32 -= 0x10000; - json_writer_escape_utf16(writer, (uint16_t)(0xd800 | (utf32 >> 10))); - json_writer_escape_utf16(writer, (uint16_t)(0xdc00 | (utf32 & 0x3ff))); - } else { - json_writer_escape_utf16(writer, (uint16_t)utf32); - } - } - } - - json_writer_output_char(writer, '"'); -} - -void grpc_json_writer_container_begins(grpc_json_writer *writer, - grpc_json_type type) { - if (!writer->got_key) json_writer_value_end(writer); - json_writer_output_indent(writer); - json_writer_output_char(writer, type == GRPC_JSON_OBJECT ? '{' : '['); - writer->container_empty = 1; - writer->got_key = 0; - writer->depth++; -} - -void grpc_json_writer_container_ends(grpc_json_writer *writer, - grpc_json_type type) { - if (writer->indent && !writer->container_empty) - json_writer_output_char(writer, '\n'); - writer->depth--; - if (!writer->container_empty) json_writer_output_indent(writer); - json_writer_output_char(writer, type == GRPC_JSON_OBJECT ? '}' : ']'); - writer->container_empty = 0; - writer->got_key = 0; -} - -void grpc_json_writer_object_key(grpc_json_writer *writer, const char *string) { - json_writer_value_end(writer); - json_writer_output_indent(writer); - json_writer_escape_string(writer, string); - json_writer_output_char(writer, ':'); - writer->got_key = 1; -} - -void grpc_json_writer_value_raw(grpc_json_writer *writer, const char *string) { - if (!writer->got_key) json_writer_value_end(writer); - json_writer_output_indent(writer); - json_writer_output_string(writer, string); - writer->got_key = 0; -} - -void grpc_json_writer_value_raw_with_len(grpc_json_writer *writer, - const char *string, size_t len) { - if (!writer->got_key) json_writer_value_end(writer); - json_writer_output_indent(writer); - json_writer_output_string_with_len(writer, string, len); - writer->got_key = 0; -} - -void grpc_json_writer_value_string(grpc_json_writer *writer, - const char *string) { - if (!writer->got_key) json_writer_value_end(writer); - json_writer_output_indent(writer); - json_writer_escape_string(writer, string); - writer->got_key = 0; -} diff --git a/src/core/json/json_writer.h b/src/core/json/json_writer.h deleted file mode 100644 index c392126950..0000000000 --- a/src/core/json/json_writer.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * - * Copyright 2015-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. - * - */ - -/* The idea of the writer is basically symmetrical of the reader. While the - * reader emits various calls to your code, the writer takes basically the - * same calls and emit json out of it. It doesn't try to make any check on - * the order of the calls you do on it. Meaning you can theorically force - * it to generate invalid json. - * - * Also, unlike the reader, the writer expects UTF-8 encoded input strings. - * These strings will be UTF-8 validated, and any invalid character will - * cut the conversion short, before any invalid UTF-8 sequence, thus forming - * a valid UTF-8 string overall. - */ - -#ifndef GRPC_CORE_JSON_JSON_WRITER_H -#define GRPC_CORE_JSON_JSON_WRITER_H - -#include - -#include "src/core/json/json_common.h" - -typedef struct grpc_json_writer_vtable { - /* Adds a character to the output stream. */ - void (*output_char)(void *userdata, char); - /* Adds a zero-terminated string to the output stream. */ - void (*output_string)(void *userdata, const char *str); - /* Adds a fixed-length string to the output stream. */ - void (*output_string_with_len)(void *userdata, const char *str, size_t len); - -} grpc_json_writer_vtable; - -typedef struct grpc_json_writer { - void *userdata; - grpc_json_writer_vtable *vtable; - int indent; - int depth; - int container_empty; - int got_key; -} grpc_json_writer; - -/* Call this to initialize your writer structure. The indent parameter is - * specifying the number of spaces to use for indenting the output. If you - * use indent=0, then the output will not have any newlines either, thus - * emitting a condensed json output. - */ -void grpc_json_writer_init(grpc_json_writer *writer, int indent, - grpc_json_writer_vtable *vtable, void *userdata); - -/* Signals the beginning of a container. */ -void grpc_json_writer_container_begins(grpc_json_writer *writer, - grpc_json_type type); -/* Signals the end of a container. */ -void grpc_json_writer_container_ends(grpc_json_writer *writer, - grpc_json_type type); -/* Writes down an object key for the next value. */ -void grpc_json_writer_object_key(grpc_json_writer *writer, const char *string); -/* Sets a raw value. Useful for numbers. */ -void grpc_json_writer_value_raw(grpc_json_writer *writer, const char *string); -/* Sets a raw value with its length. Useful for values like true or false. */ -void grpc_json_writer_value_raw_with_len(grpc_json_writer *writer, - const char *string, size_t len); -/* Sets a string value. It'll be escaped, and utf-8 validated. */ -void grpc_json_writer_value_string(grpc_json_writer *writer, - const char *string); - -#endif /* GRPC_CORE_JSON_JSON_WRITER_H */ diff --git a/src/core/lib/census/README.md b/src/core/lib/census/README.md new file mode 100644 index 0000000000..fb615a2194 --- /dev/null +++ b/src/core/lib/census/README.md @@ -0,0 +1,76 @@ + + +# Census - a resource measurement and tracing system + +This directory contains code for Census, which will ultimately provide the +following features for any gRPC-using system: +* A [dapper](http://research.google.com/pubs/pub36356.html)-like tracing + system, enabling tracing across a distributed infrastructure. +* RPC statistics and measurements for key metrics, such as latency, bytes + transferred, number of errors etc. +* Resource measurement framework which can be used for measuring custom + metrics. Through the use of [tags](#Tags), these can be broken down across + the entire distributed stack. +* Easy integration of the above with + [Google Cloud Trace](https://cloud.google.com/tools/cloud-trace) and + [Google Cloud Monitoring](https://cloud.google.com/monitoring/). + +## Concepts + +### Context + +### Operations + +### Tags + +### Metrics + +## API + +### Internal/RPC API + +### External/Client API + +### RPC API + +## Files in this directory + +Note that files and functions in this directory can be split into two +categories: +* Files that define core census library functions. Functions etc. in these + files are named census\_\*, and constitute the core census library + functionality. At some time in the future, these will become a standalone + library. +* Files that define functions etc. that provide a convenient interface between + grpc and the core census functionality. These files are all named + grpc\_\*.{c,h}, and define function names beginning with grpc\_census\_\*. + diff --git a/src/core/lib/census/aggregation.h b/src/core/lib/census/aggregation.h new file mode 100644 index 0000000000..e0ef9630c9 --- /dev/null +++ b/src/core/lib/census/aggregation.h @@ -0,0 +1,66 @@ +/* + * + * Copyright 2015-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 + +#ifndef GRPC_CORE_CENSUS_AGGREGATION_H +#define GRPC_CORE_CENSUS_AGGREGATION_H + +/** Structure used to describe an aggregation type. */ +struct census_aggregation_ops { + /* Create a new aggregation. The pointer returned can be used in future calls + to clone(), free(), record(), data() and reset(). */ + void *(*create)(const void *create_arg); + /* Make a copy of an aggregation created by create() */ + void *(*clone)(const void *aggregation); + /* Destroy an aggregation created by create() */ + void (*free)(void *aggregation); + /* Record a new value against aggregation. */ + void (*record)(void *aggregation, double value); + /* Return current aggregation data. The caller must cast this object into + the correct type for the aggregation result. The object returned can be + freed by using free_data(). */ + void *(*data)(const void *aggregation); + /* free data returned by data() */ + void (*free_data)(void *data); + /* Reset an aggregation to default (zero) values. */ + void (*reset)(void *aggregation); + /* Merge 'from' aggregation into 'to'. Both aggregations must be compatible */ + void (*merge)(void *to, const void *from); + /* Fill buffer with printable string version of aggregation contents. For + debugging only. Returns the number of bytes added to buffer (a value == n + implies the buffer was of insufficient size). */ + size_t (*print)(const void *aggregation, char *buffer, size_t n); +}; + +#endif /* GRPC_CORE_CENSUS_AGGREGATION_H */ diff --git a/src/core/lib/census/context.c b/src/core/lib/census/context.c new file mode 100644 index 0000000000..89b8ee0b39 --- /dev/null +++ b/src/core/lib/census/context.c @@ -0,0 +1,509 @@ +/* + * + * Copyright 2015-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 +#include +#include +#include +#include +#include +#include +#include "src/core/support/string.h" + +// Functions in this file support the public context API, including +// encoding/decoding as part of context propagation across RPC's. The overall +// requirements (in approximate priority order) for the +// context representation: +// 1. Efficient conversion to/from wire format +// 2. Minimal bytes used on-wire +// 3. Efficient context creation +// 4. Efficient lookup of tag value for a key +// 5. Efficient iteration over tags +// 6. Minimal memory footprint +// +// Notes on tradeoffs/decisions: +// * tag includes 1 byte length of key, as well as nil-terminating byte. These +// are to aid in efficient parsing and the ability to directly return key +// strings. This is more important than saving a single byte/tag on the wire. +// * The wire encoding uses only single byte values. This eliminates the need +// to handle endian-ness conversions. It also means there is a hard upper +// limit of 255 for both CENSUS_MAX_TAG_KV_LEN and CENSUS_MAX_PROPAGATED_TAGS. +// * Keep all tag information (keys/values/flags) in a single memory buffer, +// that can be directly copied to the wire. + +// min and max valid chars in tag keys and values. All printable ASCII is OK. +#define MIN_VALID_TAG_CHAR 32 // ' ' +#define MAX_VALID_TAG_CHAR 126 // '~' + +// Structure representing a set of tags. Essentially a count of number of tags +// present, and pointer to a chunk of memory that contains the per-tag details. +struct tag_set { + int ntags; // number of tags. + int ntags_alloc; // ntags + number of deleted tags (total number of tags + // in all of kvm). This will always be == ntags, except during the process + // of building a new tag set. + size_t kvm_size; // number of bytes allocated for key/value storage. + size_t kvm_used; // number of bytes of used key/value memory + char *kvm; // key/value memory. Consists of repeated entries of: + // Offset Size Description + // 0 1 Key length, including trailing 0. (K) + // 1 1 Value length, including trailing 0 (V) + // 2 1 Flags + // 3 K Key bytes + // 3 + K V Value bytes + // + // We refer to the first 3 entries as the 'tag header'. If extra values are + // introduced in the header, you will need to modify the TAG_HEADER_SIZE + // constant, the raw_tag structure (and everything that uses it) and the + // encode/decode functions appropriately. +}; + +// Number of bytes in tag header. +#define TAG_HEADER_SIZE 3 // key length (1) + value length (1) + flags (1) +// Offsets to tag header entries. +#define KEY_LEN_OFFSET 0 +#define VALUE_LEN_OFFSET 1 +#define FLAG_OFFSET 2 + +// raw_tag represents the raw-storage form of a tag in the kvm of a tag_set. +struct raw_tag { + uint8_t key_len; + uint8_t value_len; + uint8_t flags; + char *key; + char *value; +}; + +// Use a reserved flag bit for indication of deleted tag. +#define CENSUS_TAG_DELETED CENSUS_TAG_RESERVED +#define CENSUS_TAG_IS_DELETED(flags) (flags & CENSUS_TAG_DELETED) + +// Primary representation of a context. Composed of 2 underlying tag_set +// structs, one each for propagated and local (non-propagated) tags. This is +// to efficiently support tag encoding/decoding. +// TODO(aveitch): need to add tracing id's/structure. +struct census_context { + struct tag_set tags[2]; + census_context_status status; +}; + +// Indices into the tags member of census_context +#define PROPAGATED_TAGS 0 +#define LOCAL_TAGS 1 + +// Validate (check all characters are in range and size is less than limit) a +// key or value string. Returns 0 if the string is invalid, or the length +// (including terminator) if valid. +static size_t validate_tag(const char *kv) { + size_t len = 1; + char ch; + while ((ch = *kv++) != 0) { + if (ch < MIN_VALID_TAG_CHAR || ch > MAX_VALID_TAG_CHAR) { + return 0; + } + len++; + } + if (len > CENSUS_MAX_TAG_KV_LEN) { + return 0; + } + return len; +} + +// Extract a raw tag given a pointer (raw) to the tag header. Allow for some +// extra bytes in the tag header (see encode/decode functions for usage: this +// allows for future expansion of the tag header). +static char *decode_tag(struct raw_tag *tag, char *header, int offset) { + tag->key_len = (uint8_t)(*header++); + tag->value_len = (uint8_t)(*header++); + tag->flags = (uint8_t)(*header++); + header += offset; + tag->key = header; + header += tag->key_len; + tag->value = header; + return header + tag->value_len; +} + +// Make a copy (in 'to') of an existing tag_set. +static void tag_set_copy(struct tag_set *to, const struct tag_set *from) { + memcpy(to, from, sizeof(struct tag_set)); + to->kvm = gpr_malloc(to->kvm_size); + memcpy(to->kvm, from->kvm, from->kvm_used); +} + +// Delete a tag from a tag_set, if it exists (returns true if it did). +static bool tag_set_delete_tag(struct tag_set *tags, const char *key, + size_t key_len) { + char *kvp = tags->kvm; + for (int i = 0; i < tags->ntags_alloc; i++) { + uint8_t *flags = (uint8_t *)(kvp + FLAG_OFFSET); + struct raw_tag tag; + kvp = decode_tag(&tag, kvp, 0); + if (CENSUS_TAG_IS_DELETED(tag.flags)) continue; + if ((key_len == tag.key_len) && (memcmp(key, tag.key, key_len) == 0)) { + *flags |= CENSUS_TAG_DELETED; + tags->ntags--; + return true; + } + } + return false; +} + +// Delete a tag from a context, return true if it existed. +static bool context_delete_tag(census_context *context, const census_tag *tag, + size_t key_len) { + return ( + tag_set_delete_tag(&context->tags[LOCAL_TAGS], tag->key, key_len) || + tag_set_delete_tag(&context->tags[PROPAGATED_TAGS], tag->key, key_len)); +} + +// Add a tag to a tag_set. Return true on success, false if the tag could +// not be added because of constraints on tag set size. This function should +// not be called if the tag may already exist (in a non-deleted state) in +// the tag_set, as that would result in two tags with the same key. +static bool tag_set_add_tag(struct tag_set *tags, const census_tag *tag, + size_t key_len, size_t value_len) { + if (tags->ntags == CENSUS_MAX_PROPAGATED_TAGS) { + return false; + } + const size_t tag_size = key_len + value_len + TAG_HEADER_SIZE; + if (tags->kvm_used + tag_size > tags->kvm_size) { + // allocate new memory if needed + tags->kvm_size += 2 * CENSUS_MAX_TAG_KV_LEN + TAG_HEADER_SIZE; + char *new_kvm = gpr_malloc(tags->kvm_size); + memcpy(new_kvm, tags->kvm, tags->kvm_used); + gpr_free(tags->kvm); + tags->kvm = new_kvm; + } + char *kvp = tags->kvm + tags->kvm_used; + *kvp++ = (char)key_len; + *kvp++ = (char)value_len; + // ensure reserved flags are not used. + *kvp++ = (char)(tag->flags & (CENSUS_TAG_PROPAGATE | CENSUS_TAG_STATS)); + memcpy(kvp, tag->key, key_len); + kvp += key_len; + memcpy(kvp, tag->value, value_len); + tags->kvm_used += tag_size; + tags->ntags++; + tags->ntags_alloc++; + return true; +} + +// Add/modify/delete a tag to/in a context. Caller must validate that tag key +// etc. are valid. +static void context_modify_tag(census_context *context, const census_tag *tag, + size_t key_len, size_t value_len) { + // First delete the tag if it is already present. + bool deleted = context_delete_tag(context, tag, key_len); + bool added = false; + if (CENSUS_TAG_IS_PROPAGATED(tag->flags)) { + added = tag_set_add_tag(&context->tags[PROPAGATED_TAGS], tag, key_len, + value_len); + } else { + added = + tag_set_add_tag(&context->tags[LOCAL_TAGS], tag, key_len, value_len); + } + + if (deleted) { + context->status.n_modified_tags++; + } else { + if (added) { + context->status.n_added_tags++; + } else { + context->status.n_ignored_tags++; + } + } +} + +// Remove memory used for deleted tags from a tag set. Basic algorithm: +// 1) Walk through tag set to find first deleted tag. Record where it is. +// 2) Find the next not-deleted tag. Copy all of kvm from there to the end +// "over" the deleted tags +// 3) repeat #1 and #2 until we have seen all tags +// 4) if we are still looking for a not-deleted tag, then all the end portion +// of the kvm is deleted. Just reduce the used amount of memory by the +// appropriate amount. +static void tag_set_flatten(struct tag_set *tags) { + if (tags->ntags == tags->ntags_alloc) return; + bool found_deleted = false; // found a deleted tag. + char *kvp = tags->kvm; + char *dbase = NULL; // record location of deleted tag + for (int i = 0; i < tags->ntags_alloc; i++) { + struct raw_tag tag; + char *next_kvp = decode_tag(&tag, kvp, 0); + if (found_deleted) { + if (!CENSUS_TAG_IS_DELETED(tag.flags)) { + ptrdiff_t reduce = kvp - dbase; // #bytes in deleted tags + GPR_ASSERT(reduce > 0); + ptrdiff_t copy_size = tags->kvm + tags->kvm_used - kvp; + GPR_ASSERT(copy_size > 0); + memmove(dbase, kvp, (size_t)copy_size); + tags->kvm_used -= (size_t)reduce; + next_kvp -= reduce; + found_deleted = false; + } + } else { + if (CENSUS_TAG_IS_DELETED(tag.flags)) { + dbase = kvp; + found_deleted = true; + } + } + kvp = next_kvp; + } + if (found_deleted) { + GPR_ASSERT(dbase > tags->kvm); + tags->kvm_used = (size_t)(dbase - tags->kvm); + } + tags->ntags_alloc = tags->ntags; +} + +census_context *census_context_create(const census_context *base, + const census_tag *tags, int ntags, + census_context_status const **status) { + census_context *context = gpr_malloc(sizeof(census_context)); + // If we are given a base, copy it into our new tag set. Otherwise set it + // to zero/NULL everything. + if (base == NULL) { + memset(context, 0, sizeof(census_context)); + } else { + tag_set_copy(&context->tags[PROPAGATED_TAGS], &base->tags[PROPAGATED_TAGS]); + tag_set_copy(&context->tags[LOCAL_TAGS], &base->tags[LOCAL_TAGS]); + memset(&context->status, 0, sizeof(context->status)); + } + // Walk over the additional tags and, for those that aren't invalid, modify + // the context to add/replace/delete as required. + for (int i = 0; i < ntags; i++) { + const census_tag *tag = &tags[i]; + size_t key_len = validate_tag(tag->key); + // ignore the tag if it is invalid or too short. + if (key_len <= 1) { + context->status.n_invalid_tags++; + } else { + if (tag->value != NULL) { + size_t value_len = validate_tag(tag->value); + if (value_len != 0) { + context_modify_tag(context, tag, key_len, value_len); + } else { + context->status.n_invalid_tags++; + } + } else { + if (context_delete_tag(context, tag, key_len)) { + context->status.n_deleted_tags++; + } + } + } + } + // Remove any deleted tags, update status if needed, and return. + tag_set_flatten(&context->tags[PROPAGATED_TAGS]); + tag_set_flatten(&context->tags[LOCAL_TAGS]); + context->status.n_propagated_tags = context->tags[PROPAGATED_TAGS].ntags; + context->status.n_local_tags = context->tags[LOCAL_TAGS].ntags; + if (status) { + *status = &context->status; + } + return context; +} + +const census_context_status *census_context_get_status( + const census_context *context) { + return &context->status; +} + +void census_context_destroy(census_context *context) { + gpr_free(context->tags[PROPAGATED_TAGS].kvm); + gpr_free(context->tags[LOCAL_TAGS].kvm); + gpr_free(context); +} + +void census_context_initialize_iterator(const census_context *context, + census_context_iterator *iterator) { + iterator->context = context; + iterator->index = 0; + if (context->tags[PROPAGATED_TAGS].ntags != 0) { + iterator->base = PROPAGATED_TAGS; + iterator->kvm = context->tags[PROPAGATED_TAGS].kvm; + } else if (context->tags[LOCAL_TAGS].ntags != 0) { + iterator->base = LOCAL_TAGS; + iterator->kvm = context->tags[LOCAL_TAGS].kvm; + } else { + iterator->base = -1; + } +} + +int census_context_next_tag(census_context_iterator *iterator, + census_tag *tag) { + if (iterator->base < 0) { + return 0; + } + struct raw_tag raw; + iterator->kvm = decode_tag(&raw, iterator->kvm, 0); + tag->key = raw.key; + tag->value = raw.value; + tag->flags = raw.flags; + if (++iterator->index == iterator->context->tags[iterator->base].ntags) { + do { + if (iterator->base == LOCAL_TAGS) { + iterator->base = -1; + return 1; + } + } while (iterator->context->tags[++iterator->base].ntags == 0); + iterator->index = 0; + iterator->kvm = iterator->context->tags[iterator->base].kvm; + } + return 1; +} + +// Find a tag in a tag_set by key. Return true if found, false otherwise. +static bool tag_set_get_tag(const struct tag_set *tags, const char *key, + size_t key_len, census_tag *tag) { + char *kvp = tags->kvm; + for (int i = 0; i < tags->ntags; i++) { + struct raw_tag raw; + kvp = decode_tag(&raw, kvp, 0); + if (key_len == raw.key_len && memcmp(raw.key, key, key_len) == 0) { + tag->key = raw.key; + tag->value = raw.value; + tag->flags = raw.flags; + return true; + } + } + return false; +} + +int census_context_get_tag(const census_context *context, const char *key, + census_tag *tag) { + size_t key_len = strlen(key) + 1; + if (key_len == 1) { + return 0; + } + if (tag_set_get_tag(&context->tags[PROPAGATED_TAGS], key, key_len, tag) || + tag_set_get_tag(&context->tags[LOCAL_TAGS], key, key_len, tag)) { + return 1; + } + return 0; +} + +// Context encoding and decoding functions. +// +// Wire format for tag_set's on the wire: +// +// First, a tag set header: +// +// offset bytes description +// 0 1 version number +// 1 1 number of bytes in this header. This allows for future +// expansion. +// 2 1 number of bytes in each tag header. +// 3 1 ntags value from tag set. +// +// This is followed by the key/value memory from struct tag_set. + +#define ENCODED_VERSION 0 // Version number +#define ENCODED_HEADER_SIZE 4 // size of tag set header + +// Encode a tag set. Returns 0 if buffer is too small. +static size_t tag_set_encode(const struct tag_set *tags, char *buffer, + size_t buf_size) { + if (buf_size < ENCODED_HEADER_SIZE + tags->kvm_used) { + return 0; + } + buf_size -= ENCODED_HEADER_SIZE; + *buffer++ = (char)ENCODED_VERSION; + *buffer++ = (char)ENCODED_HEADER_SIZE; + *buffer++ = (char)TAG_HEADER_SIZE; + *buffer++ = (char)tags->ntags; + if (tags->ntags == 0) { + return ENCODED_HEADER_SIZE; + } + memcpy(buffer, tags->kvm, tags->kvm_used); + return ENCODED_HEADER_SIZE + tags->kvm_used; +} + +size_t census_context_encode(const census_context *context, char *buffer, + size_t buf_size) { + return tag_set_encode(&context->tags[PROPAGATED_TAGS], buffer, buf_size); +} + +// Decode a tag set. +static void tag_set_decode(struct tag_set *tags, const char *buffer, + size_t size) { + uint8_t version = (uint8_t)(*buffer++); + uint8_t header_size = (uint8_t)(*buffer++); + uint8_t tag_header_size = (uint8_t)(*buffer++); + tags->ntags = tags->ntags_alloc = (int)(*buffer++); + if (tags->ntags == 0) { + tags->ntags_alloc = 0; + tags->kvm_size = 0; + tags->kvm_used = 0; + tags->kvm = NULL; + return; + } + if (header_size != ENCODED_HEADER_SIZE) { + GPR_ASSERT(version != ENCODED_VERSION); + GPR_ASSERT(ENCODED_HEADER_SIZE < header_size); + buffer += (header_size - ENCODED_HEADER_SIZE); + } + tags->kvm_used = size - header_size; + tags->kvm_size = tags->kvm_used + CENSUS_MAX_TAG_KV_LEN; + tags->kvm = gpr_malloc(tags->kvm_size); + if (tag_header_size != TAG_HEADER_SIZE) { + // something new in the tag information. I don't understand it, so + // don't copy it over. + GPR_ASSERT(version != ENCODED_VERSION); + GPR_ASSERT(tag_header_size > TAG_HEADER_SIZE); + char *kvp = tags->kvm; + for (int i = 0; i < tags->ntags; i++) { + memcpy(kvp, buffer, TAG_HEADER_SIZE); + kvp += header_size; + struct raw_tag raw; + buffer = + decode_tag(&raw, (char *)buffer, tag_header_size - TAG_HEADER_SIZE); + memcpy(kvp, raw.key, (size_t)raw.key_len + raw.value_len); + kvp += raw.key_len + raw.value_len; + } + } else { + memcpy(tags->kvm, buffer, tags->kvm_used); + } +} + +census_context *census_context_decode(const char *buffer, size_t size) { + census_context *context = gpr_malloc(sizeof(census_context)); + memset(&context->tags[LOCAL_TAGS], 0, sizeof(struct tag_set)); + if (buffer == NULL) { + memset(&context->tags[PROPAGATED_TAGS], 0, sizeof(struct tag_set)); + } else { + tag_set_decode(&context->tags[PROPAGATED_TAGS], buffer, size); + } + memset(&context->status, 0, sizeof(context->status)); + context->status.n_propagated_tags = context->tags[PROPAGATED_TAGS].ntags; + return context; +} diff --git a/src/core/lib/census/grpc_context.c b/src/core/lib/census/grpc_context.c new file mode 100644 index 0000000000..4b61382a2c --- /dev/null +++ b/src/core/lib/census/grpc_context.c @@ -0,0 +1,53 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include "src/core/surface/api_trace.h" +#include "src/core/surface/call.h" + +void grpc_census_call_set_context(grpc_call *call, census_context *context) { + GRPC_API_TRACE("grpc_census_call_set_context(call=%p, census_context=%p)", 2, + (call, context)); + if (census_enabled() == CENSUS_FEATURE_NONE) { + return; + } + if (context != NULL) { + grpc_call_context_set(call, GRPC_CONTEXT_TRACING, context, NULL); + } +} + +census_context *grpc_census_call_get_context(grpc_call *call) { + GRPC_API_TRACE("grpc_census_call_get_context(call=%p)", 1, (call)); + return (census_context *)grpc_call_context_get(call, GRPC_CONTEXT_TRACING); +} diff --git a/src/core/lib/census/grpc_filter.c b/src/core/lib/census/grpc_filter.c new file mode 100644 index 0000000000..11120a28d1 --- /dev/null +++ b/src/core/lib/census/grpc_filter.c @@ -0,0 +1,198 @@ +/* + * + * Copyright 2015-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/census/grpc_filter.h" + +#include +#include + +#include +#include +#include +#include +#include + +#include "src/core/channel/channel_stack.h" +#include "src/core/statistics/census_interface.h" +#include "src/core/statistics/census_rpc_stats.h" +#include "src/core/transport/static_metadata.h" + +typedef struct call_data { + census_op_id op_id; + census_context *ctxt; + gpr_timespec start_ts; + int error; + + /* recv callback */ + grpc_metadata_batch *recv_initial_metadata; + grpc_closure *on_done_recv; + grpc_closure finish_recv; +} call_data; + +typedef struct channel_data { uint8_t unused; } channel_data; + +static void extract_and_annotate_method_tag(grpc_metadata_batch *md, + call_data *calld, + channel_data *chand) { + grpc_linked_mdelem *m; + for (m = md->list.head; m != NULL; m = m->next) { + if (m->md->key == GRPC_MDSTR_PATH) { + gpr_log(GPR_DEBUG, "%s", + (const char *)GPR_SLICE_START_PTR(m->md->value->slice)); + /* Add method tag here */ + } + } +} + +static void client_mutate_op(grpc_call_element *elem, + grpc_transport_stream_op *op) { + call_data *calld = elem->call_data; + channel_data *chand = elem->channel_data; + if (op->send_initial_metadata) { + extract_and_annotate_method_tag(op->send_initial_metadata, calld, chand); + } +} + +static void client_start_transport_op(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + grpc_transport_stream_op *op) { + client_mutate_op(elem, op); + grpc_call_next_op(exec_ctx, elem, op); +} + +static void server_on_done_recv(grpc_exec_ctx *exec_ctx, void *ptr, + bool success) { + grpc_call_element *elem = ptr; + call_data *calld = elem->call_data; + channel_data *chand = elem->channel_data; + if (success) { + extract_and_annotate_method_tag(calld->recv_initial_metadata, calld, chand); + } + calld->on_done_recv->cb(exec_ctx, calld->on_done_recv->cb_arg, success); +} + +static void server_mutate_op(grpc_call_element *elem, + grpc_transport_stream_op *op) { + call_data *calld = elem->call_data; + if (op->recv_initial_metadata) { + /* substitute our callback for the op callback */ + calld->recv_initial_metadata = op->recv_initial_metadata; + calld->on_done_recv = op->recv_initial_metadata_ready; + op->recv_initial_metadata_ready = &calld->finish_recv; + } +} + +static void server_start_transport_op(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + grpc_transport_stream_op *op) { + /* TODO(ctiller): this code fails. I don't know why. I expect it's + incomplete, and someone should look at it soon. + + call_data *calld = elem->call_data; + GPR_ASSERT((calld->op_id.upper != 0) || (calld->op_id.lower != 0)); */ + server_mutate_op(elem, op); + grpc_call_next_op(exec_ctx, elem, op); +} + +static void client_init_call_elem(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + grpc_call_element_args *args) { + call_data *d = elem->call_data; + GPR_ASSERT(d != NULL); + memset(d, 0, sizeof(*d)); + d->start_ts = gpr_now(GPR_CLOCK_REALTIME); +} + +static void client_destroy_call_elem(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem) { + call_data *d = elem->call_data; + GPR_ASSERT(d != NULL); + /* TODO(hongyu): record rpc client stats and census_rpc_end_op here */ +} + +static void server_init_call_elem(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + grpc_call_element_args *args) { + call_data *d = elem->call_data; + GPR_ASSERT(d != NULL); + memset(d, 0, sizeof(*d)); + d->start_ts = gpr_now(GPR_CLOCK_REALTIME); + /* TODO(hongyu): call census_tracing_start_op here. */ + grpc_closure_init(&d->finish_recv, server_on_done_recv, elem); +} + +static void server_destroy_call_elem(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem) { + call_data *d = elem->call_data; + GPR_ASSERT(d != NULL); + /* TODO(hongyu): record rpc server stats and census_tracing_end_op here */ +} + +static void init_channel_elem(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem, + grpc_channel_element_args *args) { + channel_data *chand = elem->channel_data; + GPR_ASSERT(chand != NULL); +} + +static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem) { + channel_data *chand = elem->channel_data; + GPR_ASSERT(chand != NULL); +} + +const grpc_channel_filter grpc_client_census_filter = { + client_start_transport_op, + grpc_channel_next_op, + sizeof(call_data), + client_init_call_elem, + grpc_call_stack_ignore_set_pollset, + client_destroy_call_elem, + sizeof(channel_data), + init_channel_elem, + destroy_channel_elem, + grpc_call_next_get_peer, + "census-client"}; + +const grpc_channel_filter grpc_server_census_filter = { + server_start_transport_op, + grpc_channel_next_op, + sizeof(call_data), + server_init_call_elem, + grpc_call_stack_ignore_set_pollset, + server_destroy_call_elem, + sizeof(channel_data), + init_channel_elem, + destroy_channel_elem, + grpc_call_next_get_peer, + "census-server"}; diff --git a/src/core/lib/census/grpc_filter.h b/src/core/lib/census/grpc_filter.h new file mode 100644 index 0000000000..4699e4d692 --- /dev/null +++ b/src/core/lib/census/grpc_filter.h @@ -0,0 +1,44 @@ +/* + * + * Copyright 2015-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_CENSUS_GRPC_FILTER_H +#define GRPC_CORE_CENSUS_GRPC_FILTER_H + +#include "src/core/channel/channel_stack.h" + +/* Census filters: provides tracing and stats collection functionalities. It + needs to reside right below the surface filter in the channel stack. */ +extern const grpc_channel_filter grpc_client_census_filter; +extern const grpc_channel_filter grpc_server_census_filter; + +#endif /* GRPC_CORE_CENSUS_GRPC_FILTER_H */ diff --git a/src/core/lib/census/grpc_plugin.c b/src/core/lib/census/grpc_plugin.c new file mode 100644 index 0000000000..3ca9400f7e --- /dev/null +++ b/src/core/lib/census/grpc_plugin.c @@ -0,0 +1,70 @@ +/* + * + * Copyright 2015-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/census/grpc_plugin.h" + +#include + +#include + +#include "src/core/census/grpc_filter.h" +#include "src/core/channel/channel_stack_builder.h" +#include "src/core/surface/channel_init.h" + +static bool maybe_add_census_filter(grpc_channel_stack_builder *builder, + void *arg_must_be_null) { + const grpc_channel_args *args = + grpc_channel_stack_builder_get_channel_arguments(builder); + if (grpc_channel_args_is_census_enabled(args)) { + return grpc_channel_stack_builder_prepend_filter( + builder, &grpc_client_census_filter, NULL, NULL); + } + return true; +} + +void census_grpc_plugin_init(void) { + /* Only initialize census if no one else has and some features are + * available. */ + if (census_enabled() == CENSUS_FEATURE_NONE && + census_supported() != CENSUS_FEATURE_NONE) { + if (census_initialize(census_supported())) { /* enable all features. */ + gpr_log(GPR_ERROR, "Could not initialize census."); + } + } + grpc_channel_init_register_stage(GRPC_CLIENT_CHANNEL, INT_MAX, + maybe_add_census_filter, NULL); + grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX, + maybe_add_census_filter, NULL); +} + +void census_grpc_plugin_destroy(void) { census_shutdown(); } diff --git a/src/core/lib/census/grpc_plugin.h b/src/core/lib/census/grpc_plugin.h new file mode 100644 index 0000000000..9321c2c30f --- /dev/null +++ b/src/core/lib/census/grpc_plugin.h @@ -0,0 +1,40 @@ +/* + * + * Copyright 2015-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_CENSUS_GRPC_PLUGIN_H +#define GRPC_CORE_CENSUS_GRPC_PLUGIN_H + +void census_grpc_plugin_init(void); +void census_grpc_plugin_destroy(void); + +#endif /* GRPC_CORE_CENSUS_GRPC_PLUGIN_H */ diff --git a/src/core/lib/census/initialize.c b/src/core/lib/census/initialize.c new file mode 100644 index 0000000000..ce7ec09b89 --- /dev/null +++ b/src/core/lib/census/initialize.c @@ -0,0 +1,54 @@ +/* + * + * Copyright 2015-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 + +static int features_enabled = CENSUS_FEATURE_NONE; + +int census_initialize(int features) { + if (features_enabled != CENSUS_FEATURE_NONE) { + // Must have been a previous call to census_initialize; return error + return 1; + } + features_enabled = features; + return 0; +} + +void census_shutdown(void) { features_enabled = CENSUS_FEATURE_NONE; } + +int census_supported(void) { + /* TODO(aveitch): improve this as we implement features... */ + return CENSUS_FEATURE_NONE; +} + +int census_enabled(void) { return features_enabled; } diff --git a/src/core/lib/census/mlog.c b/src/core/lib/census/mlog.c new file mode 100644 index 0000000000..a2cc46d3f2 --- /dev/null +++ b/src/core/lib/census/mlog.c @@ -0,0 +1,600 @@ +/* + * + * Copyright 2015-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. + * + */ + +// Implements an efficient in-memory log, optimized for multiple writers and +// a single reader. Available log space is divided up in blocks of +// CENSUS_LOG_2_MAX_RECORD_SIZE bytes. A block can be in one of the following +// three data structures: +// - Free blocks (free_block_list) +// - Blocks with unread data (dirty_block_list) +// - Blocks currently attached to cores (core_local_blocks[]) +// +// census_log_start_write() moves a block from core_local_blocks[] to the end of +// dirty_block_list when block: +// - is out-of-space OR +// - has an incomplete record (an incomplete record occurs when a thread calls +// census_log_start_write() and is context-switched before calling +// census_log_end_write() +// So, blocks in dirty_block_list are ordered, from oldest to newest, by the +// time when block is detached from the core. +// +// census_log_read_next() first iterates over dirty_block_list and then +// core_local_blocks[]. It moves completely read blocks from dirty_block_list +// to free_block_list. Blocks in core_local_blocks[] are not freed, even when +// completely read. +// +// If the log is configured to discard old records and free_block_list is empty, +// census_log_start_write() iterates over dirty_block_list to allocate a +// new block. It moves the oldest available block (no pending read/write) to +// core_local_blocks[]. +// +// core_local_block_struct is used to implement a map from core id to the block +// associated with that core. This mapping is advisory. It is possible that the +// block returned by this mapping is no longer associated with that core. This +// mapping is updated, lazily, by census_log_start_write(). +// +// Locking in block struct: +// +// Exclusive g_log.lock must be held before calling any functions operating on +// block structs except census_log_start_write() and census_log_end_write(). +// +// Writes to a block are serialized via writer_lock. census_log_start_write() +// acquires this lock and census_log_end_write() releases it. On failure to +// acquire the lock, writer allocates a new block for the current core and +// updates core_local_block accordingly. +// +// Simultaneous read and write access is allowed. Readers can safely read up to +// committed bytes (bytes_committed). +// +// reader_lock protects the block, currently being read, from getting recycled. +// start_read() acquires reader_lock and end_read() releases the lock. +// +// Read/write access to a block is disabled via try_disable_access(). It returns +// with both writer_lock and reader_lock held. These locks are subsequently +// released by enable_access() to enable access to the block. +// +// A note on naming: Most function/struct names are prepended by cl_ +// (shorthand for census_log). Further, functions that manipulate structures +// include the name of the structure, which will be passed as the first +// argument. E.g. cl_block_initialize() will initialize a cl_block. + +#include "src/core/census/mlog.h" +#include +#include +#include +#include +#include +#include +#include +#include + +// End of platform specific code + +typedef struct census_log_block_list_struct { + struct census_log_block_list_struct* next; + struct census_log_block_list_struct* prev; + struct census_log_block* block; +} cl_block_list_struct; + +typedef struct census_log_block { + // Pointer to underlying buffer. + char* buffer; + gpr_atm writer_lock; + gpr_atm reader_lock; + // Keeps completely written bytes. Declared atomic because accessed + // simultaneously by reader and writer. + gpr_atm bytes_committed; + // Bytes already read. + size_t bytes_read; + // Links for list. + cl_block_list_struct link; +// We want this structure to be cacheline aligned. We assume the following +// sizes for the various parts on 32/64bit systems: +// type 32b size 64b size +// char* 4 8 +// 3x gpr_atm 12 24 +// size_t 4 8 +// cl_block_list_struct 12 24 +// TOTAL 32 64 +// +// Depending on the size of our cacheline and the architecture, we +// selectively add char buffering to this structure. The size is checked +// via assert in census_log_initialize(). +#if defined(GPR_ARCH_64) +#define CL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 64) +#else +#if defined(GPR_ARCH_32) +#define CL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 32) +#else +#error "Unknown architecture" +#endif +#endif +#if CL_BLOCK_PAD_SIZE > 0 + char padding[CL_BLOCK_PAD_SIZE]; +#endif +} cl_block; + +// A list of cl_blocks, doubly-linked through cl_block::link. +typedef struct census_log_block_list { + int32_t count; // Number of items in list. + cl_block_list_struct ht; // head/tail of linked list. +} cl_block_list; + +// Cacheline aligned block pointers to avoid false sharing. Block pointer must +// be initialized via set_block(), before calling other functions +typedef struct census_log_core_local_block { + gpr_atm block; +// Ensure cachline alignment: we assume sizeof(gpr_atm) == 4 or 8 +#if defined(GPR_ARCH_64) +#define CL_CORE_LOCAL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 8) +#else +#if defined(GPR_ARCH_32) +#define CL_CORE_LOCAL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 4) +#else +#error "Unknown architecture" +#endif +#endif +#if CL_CORE_LOCAL_BLOCK_PAD_SIZE > 0 + char padding[CL_CORE_LOCAL_BLOCK_PAD_SIZE]; +#endif +} cl_core_local_block; + +struct census_log { + int discard_old_records; + // Number of cores (aka hardware-contexts) + unsigned num_cores; + // number of CENSUS_LOG_2_MAX_RECORD_SIZE blocks in log + uint32_t num_blocks; + cl_block* blocks; // Block metadata. + cl_core_local_block* core_local_blocks; // Keeps core to block mappings. + gpr_mu lock; + int initialized; // has log been initialized? + // Keeps the state of the reader iterator. A value of 0 indicates that + // iterator has reached the end. census_log_init_reader() resets the value + // to num_core to restart iteration. + uint32_t read_iterator_state; + // Points to the block being read. If non-NULL, the block is locked for + // reading(block_being_read_->reader_lock is held). + cl_block* block_being_read; + char* buffer; + cl_block_list free_block_list; + cl_block_list dirty_block_list; + gpr_atm out_of_space_count; +}; + +// Single internal log. +static struct census_log g_log; + +// Functions that operate on an atomic memory location used as a lock. + +// Returns non-zero if lock is acquired. +static int cl_try_lock(gpr_atm* lock) { return gpr_atm_acq_cas(lock, 0, 1); } + +static void cl_unlock(gpr_atm* lock) { gpr_atm_rel_store(lock, 0); } + +// Functions that operate on cl_core_local_block's. + +static void cl_core_local_block_set_block(cl_core_local_block* clb, + cl_block* block) { + gpr_atm_rel_store(&clb->block, (gpr_atm)block); +} + +static cl_block* cl_core_local_block_get_block(cl_core_local_block* clb) { + return (cl_block*)gpr_atm_acq_load(&clb->block); +} + +// Functions that operate on cl_block_list_struct's. + +static void cl_block_list_struct_initialize(cl_block_list_struct* bls, + cl_block* block) { + bls->next = bls->prev = bls; + bls->block = block; +} + +// Functions that operate on cl_block_list's. + +static void cl_block_list_initialize(cl_block_list* list) { + list->count = 0; + cl_block_list_struct_initialize(&list->ht, NULL); +} + +// Returns head of *this, or NULL if empty. +static cl_block* cl_block_list_head(cl_block_list* list) { + return list->ht.next->block; +} + +// Insert element *e after *pos. +static void cl_block_list_insert(cl_block_list* list, cl_block_list_struct* pos, + cl_block_list_struct* e) { + list->count++; + e->next = pos->next; + e->prev = pos; + e->next->prev = e; + e->prev->next = e; +} + +// Insert block at the head of the list +static void cl_block_list_insert_at_head(cl_block_list* list, cl_block* block) { + cl_block_list_insert(list, &list->ht, &block->link); +} + +// Insert block at the tail of the list. +static void cl_block_list_insert_at_tail(cl_block_list* list, cl_block* block) { + cl_block_list_insert(list, list->ht.prev, &block->link); +} + +// Removes block *b. Requires *b be in the list. +static void cl_block_list_remove(cl_block_list* list, cl_block* b) { + list->count--; + b->link.next->prev = b->link.prev; + b->link.prev->next = b->link.next; +} + +// Functions that operate on cl_block's + +static void cl_block_initialize(cl_block* block, char* buffer) { + block->buffer = buffer; + gpr_atm_rel_store(&block->writer_lock, 0); + gpr_atm_rel_store(&block->reader_lock, 0); + gpr_atm_rel_store(&block->bytes_committed, 0); + block->bytes_read = 0; + cl_block_list_struct_initialize(&block->link, block); +} + +// Guards against exposing partially written buffer to the reader. +static void cl_block_set_bytes_committed(cl_block* block, + size_t bytes_committed) { + gpr_atm_rel_store(&block->bytes_committed, (gpr_atm)bytes_committed); +} + +static size_t cl_block_get_bytes_committed(cl_block* block) { + return (size_t)gpr_atm_acq_load(&block->bytes_committed); +} + +// Tries to disable future read/write access to this block. Succeeds if: +// - no in-progress write AND +// - no in-progress read AND +// - 'discard_data' set to true OR no unread data +// On success, clears the block state and returns with writer_lock_ and +// reader_lock_ held. These locks are released by a subsequent +// cl_block_access_enable() call. +static bool cl_block_try_disable_access(cl_block* block, int discard_data) { + if (!cl_try_lock(&block->writer_lock)) { + return false; + } + if (!cl_try_lock(&block->reader_lock)) { + cl_unlock(&block->writer_lock); + return false; + } + if (!discard_data && + (block->bytes_read != cl_block_get_bytes_committed(block))) { + cl_unlock(&block->reader_lock); + cl_unlock(&block->writer_lock); + return false; + } + cl_block_set_bytes_committed(block, 0); + block->bytes_read = 0; + return true; +} + +static void cl_block_enable_access(cl_block* block) { + cl_unlock(&block->reader_lock); + cl_unlock(&block->writer_lock); +} + +// Returns with writer_lock held. +static void* cl_block_start_write(cl_block* block, size_t size) { + if (!cl_try_lock(&block->writer_lock)) { + return NULL; + } + size_t bytes_committed = cl_block_get_bytes_committed(block); + if (bytes_committed + size > CENSUS_LOG_MAX_RECORD_SIZE) { + cl_unlock(&block->writer_lock); + return NULL; + } + return block->buffer + bytes_committed; +} + +// Releases writer_lock and increments committed bytes by 'bytes_written'. +// 'bytes_written' must be <= 'size' specified in the corresponding +// StartWrite() call. This function is thread-safe. +static void cl_block_end_write(cl_block* block, size_t bytes_written) { + cl_block_set_bytes_committed( + block, cl_block_get_bytes_committed(block) + bytes_written); + cl_unlock(&block->writer_lock); +} + +// Returns a pointer to the first unread byte in buffer. The number of bytes +// available are returned in 'bytes_available'. Acquires reader lock that is +// released by a subsequent cl_block_end_read() call. Returns NULL if: +// - read in progress +// - no data available +static void* cl_block_start_read(cl_block* block, size_t* bytes_available) { + if (!cl_try_lock(&block->reader_lock)) { + return NULL; + } + // bytes_committed may change from under us. Use bytes_available to update + // bytes_read below. + size_t bytes_committed = cl_block_get_bytes_committed(block); + GPR_ASSERT(bytes_committed >= block->bytes_read); + *bytes_available = bytes_committed - block->bytes_read; + if (*bytes_available == 0) { + cl_unlock(&block->reader_lock); + return NULL; + } + void* record = block->buffer + block->bytes_read; + block->bytes_read += *bytes_available; + return record; +} + +static void cl_block_end_read(cl_block* block) { + cl_unlock(&block->reader_lock); +} + +// Internal functions operating on g_log + +// Allocates a new free block (or recycles an available dirty block if log is +// configured to discard old records). Returns NULL if out-of-space. +static cl_block* cl_allocate_block(void) { + cl_block* block = cl_block_list_head(&g_log.free_block_list); + if (block != NULL) { + cl_block_list_remove(&g_log.free_block_list, block); + return block; + } + if (!g_log.discard_old_records) { + // No free block and log is configured to keep old records. + return NULL; + } + // Recycle dirty block. Start from the oldest. + for (block = cl_block_list_head(&g_log.dirty_block_list); block != NULL; + block = block->link.next->block) { + if (cl_block_try_disable_access(block, 1 /* discard data */)) { + cl_block_list_remove(&g_log.dirty_block_list, block); + return block; + } + } + return NULL; +} + +// Allocates a new block and updates core id => block mapping. 'old_block' +// points to the block that the caller thinks is attached to +// 'core_id'. 'old_block' may be NULL. Returns true if: +// - allocated a new block OR +// - 'core_id' => 'old_block' mapping changed (another thread allocated a +// block before lock was acquired). +static bool cl_allocate_core_local_block(uint32_t core_id, + cl_block* old_block) { + // Now that we have the lock, check if core-local mapping has changed. + cl_core_local_block* core_local_block = &g_log.core_local_blocks[core_id]; + cl_block* block = cl_core_local_block_get_block(core_local_block); + if ((block != NULL) && (block != old_block)) { + return true; + } + if (block != NULL) { + cl_core_local_block_set_block(core_local_block, NULL); + cl_block_list_insert_at_tail(&g_log.dirty_block_list, block); + } + block = cl_allocate_block(); + if (block == NULL) { + return false; + } + cl_core_local_block_set_block(core_local_block, block); + cl_block_enable_access(block); + return true; +} + +static cl_block* cl_get_block(void* record) { + uintptr_t p = (uintptr_t)((char*)record - g_log.buffer); + uintptr_t index = p >> CENSUS_LOG_2_MAX_RECORD_SIZE; + return &g_log.blocks[index]; +} + +// Gets the next block to read and tries to free 'prev' block (if not NULL). +// Returns NULL if reached the end. +static cl_block* cl_next_block_to_read(cl_block* prev) { + cl_block* block = NULL; + if (g_log.read_iterator_state == g_log.num_cores) { + // We are traversing dirty list; find the next dirty block. + if (prev != NULL) { + // Try to free the previous block if there is no unread data. This + // block + // may have unread data if previously incomplete record completed + // between + // read_next() calls. + block = prev->link.next->block; + if (cl_block_try_disable_access(prev, 0 /* do not discard data */)) { + cl_block_list_remove(&g_log.dirty_block_list, prev); + cl_block_list_insert_at_head(&g_log.free_block_list, prev); + } + } else { + block = cl_block_list_head(&g_log.dirty_block_list); + } + if (block != NULL) { + return block; + } + // We are done with the dirty list; moving on to core-local blocks. + } + while (g_log.read_iterator_state > 0) { + g_log.read_iterator_state--; + block = cl_core_local_block_get_block( + &g_log.core_local_blocks[g_log.read_iterator_state]); + if (block != NULL) { + return block; + } + } + return NULL; +} + +#define CL_LOG_2_MB 20 // 2^20 = 1MB + +// External functions: primary stats_log interface +void census_log_initialize(size_t size_in_mb, int discard_old_records) { + // Check cacheline alignment. + GPR_ASSERT(sizeof(cl_block) % GPR_CACHELINE_SIZE == 0); + GPR_ASSERT(sizeof(cl_core_local_block) % GPR_CACHELINE_SIZE == 0); + GPR_ASSERT(!g_log.initialized); + g_log.discard_old_records = discard_old_records; + g_log.num_cores = gpr_cpu_num_cores(); + // Ensure that we will not get any overflow in calaculating num_blocks + GPR_ASSERT(CL_LOG_2_MB >= CENSUS_LOG_2_MAX_RECORD_SIZE); + GPR_ASSERT(size_in_mb < 1000); + // Ensure at least 2x as many blocks as there are cores. + g_log.num_blocks = + (uint32_t)GPR_MAX(2 * g_log.num_cores, (size_in_mb << CL_LOG_2_MB) >> + CENSUS_LOG_2_MAX_RECORD_SIZE); + gpr_mu_init(&g_log.lock); + g_log.read_iterator_state = 0; + g_log.block_being_read = NULL; + g_log.core_local_blocks = (cl_core_local_block*)gpr_malloc_aligned( + g_log.num_cores * sizeof(cl_core_local_block), GPR_CACHELINE_SIZE_LOG); + memset(g_log.core_local_blocks, 0, + g_log.num_cores * sizeof(cl_core_local_block)); + g_log.blocks = (cl_block*)gpr_malloc_aligned( + g_log.num_blocks * sizeof(cl_block), GPR_CACHELINE_SIZE_LOG); + memset(g_log.blocks, 0, g_log.num_blocks * sizeof(cl_block)); + g_log.buffer = gpr_malloc(g_log.num_blocks * CENSUS_LOG_MAX_RECORD_SIZE); + memset(g_log.buffer, 0, g_log.num_blocks * CENSUS_LOG_MAX_RECORD_SIZE); + cl_block_list_initialize(&g_log.free_block_list); + cl_block_list_initialize(&g_log.dirty_block_list); + for (uint32_t i = 0; i < g_log.num_blocks; ++i) { + cl_block* block = g_log.blocks + i; + cl_block_initialize(block, g_log.buffer + (CENSUS_LOG_MAX_RECORD_SIZE * i)); + cl_block_try_disable_access(block, 1 /* discard data */); + cl_block_list_insert_at_tail(&g_log.free_block_list, block); + } + gpr_atm_rel_store(&g_log.out_of_space_count, 0); + g_log.initialized = 1; +} + +void census_log_shutdown(void) { + GPR_ASSERT(g_log.initialized); + gpr_mu_destroy(&g_log.lock); + gpr_free_aligned(g_log.core_local_blocks); + g_log.core_local_blocks = NULL; + gpr_free_aligned(g_log.blocks); + g_log.blocks = NULL; + gpr_free(g_log.buffer); + g_log.buffer = NULL; + g_log.initialized = 0; +} + +void* census_log_start_write(size_t size) { + // Used to bound number of times block allocation is attempted. + GPR_ASSERT(size > 0); + GPR_ASSERT(g_log.initialized); + if (size > CENSUS_LOG_MAX_RECORD_SIZE) { + return NULL; + } + uint32_t attempts_remaining = g_log.num_blocks; + uint32_t core_id = gpr_cpu_current_cpu(); + do { + void* record = NULL; + cl_block* block = + cl_core_local_block_get_block(&g_log.core_local_blocks[core_id]); + if (block && (record = cl_block_start_write(block, size))) { + return record; + } + // Need to allocate a new block. We are here if: + // - No block associated with the core OR + // - Write in-progress on the block OR + // - block is out of space + gpr_mu_lock(&g_log.lock); + bool allocated = cl_allocate_core_local_block(core_id, block); + gpr_mu_unlock(&g_log.lock); + if (!allocated) { + gpr_atm_no_barrier_fetch_add(&g_log.out_of_space_count, 1); + return NULL; + } + } while (attempts_remaining--); + // Give up. + gpr_atm_no_barrier_fetch_add(&g_log.out_of_space_count, 1); + return NULL; +} + +void census_log_end_write(void* record, size_t bytes_written) { + GPR_ASSERT(g_log.initialized); + cl_block_end_write(cl_get_block(record), bytes_written); +} + +void census_log_init_reader(void) { + GPR_ASSERT(g_log.initialized); + gpr_mu_lock(&g_log.lock); + // If a block is locked for reading unlock it. + if (g_log.block_being_read != NULL) { + cl_block_end_read(g_log.block_being_read); + g_log.block_being_read = NULL; + } + g_log.read_iterator_state = g_log.num_cores; + gpr_mu_unlock(&g_log.lock); +} + +const void* census_log_read_next(size_t* bytes_available) { + GPR_ASSERT(g_log.initialized); + gpr_mu_lock(&g_log.lock); + if (g_log.block_being_read != NULL) { + cl_block_end_read(g_log.block_being_read); + } + do { + g_log.block_being_read = cl_next_block_to_read(g_log.block_being_read); + if (g_log.block_being_read != NULL) { + void* record = + cl_block_start_read(g_log.block_being_read, bytes_available); + if (record != NULL) { + gpr_mu_unlock(&g_log.lock); + return record; + } + } + } while (g_log.block_being_read != NULL); + gpr_mu_unlock(&g_log.lock); + return NULL; +} + +size_t census_log_remaining_space(void) { + GPR_ASSERT(g_log.initialized); + size_t space = 0; + gpr_mu_lock(&g_log.lock); + if (g_log.discard_old_records) { + // Remaining space is not meaningful; just return the entire log space. + space = g_log.num_blocks << CENSUS_LOG_2_MAX_RECORD_SIZE; + } else { + GPR_ASSERT(g_log.free_block_list.count >= 0); + space = (size_t)g_log.free_block_list.count * CENSUS_LOG_MAX_RECORD_SIZE; + } + gpr_mu_unlock(&g_log.lock); + return space; +} + +int64_t census_log_out_of_space_count(void) { + GPR_ASSERT(g_log.initialized); + return gpr_atm_acq_load(&g_log.out_of_space_count); +} diff --git a/src/core/lib/census/mlog.h b/src/core/lib/census/mlog.h new file mode 100644 index 0000000000..bc6eaeaf28 --- /dev/null +++ b/src/core/lib/census/mlog.h @@ -0,0 +1,95 @@ +/* + * + * Copyright 2015-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. + * + */ + +/* A very fast in-memory log, optimized for multiple writers. */ + +#ifndef GRPC_CORE_CENSUS_MLOG_H +#define GRPC_CORE_CENSUS_MLOG_H + +#include +#include + +/* Maximum record size, in bytes. */ +#define CENSUS_LOG_2_MAX_RECORD_SIZE 14 /* 2^14 = 16KB */ +#define CENSUS_LOG_MAX_RECORD_SIZE (1 << CENSUS_LOG_2_MAX_RECORD_SIZE) + +/* Initialize the statistics logging subsystem with the given log size. A log + size of 0 will result in the smallest possible log for the platform + (approximately CENSUS_LOG_MAX_RECORD_SIZE * gpr_cpu_num_cores()). If + discard_old_records is non-zero, then new records will displace older ones + when the log is full. This function must be called before any other + census_log functions. +*/ +void census_log_initialize(size_t size_in_mb, int discard_old_records); + +/* Shutdown the logging subsystem. Caller must ensure that: + - no in progress or future call to any census_log functions + - no incomplete records +*/ +void census_log_shutdown(void); + +/* Allocates and returns a 'size' bytes record and marks it in use. A + subsequent census_log_end_write() marks the record complete. The + 'bytes_written' census_log_end_write() argument must be <= + 'size'. Returns NULL if out-of-space AND: + - log is configured to keep old records OR + - all blocks are pinned by incomplete records. +*/ +void* census_log_start_write(size_t size); + +void census_log_end_write(void* record, size_t bytes_written); + +void census_log_init_reader(void); + +/* census_log_read_next() iterates over blocks with data and for each block + returns a pointer to the first unread byte. The number of bytes that can be + read are returned in 'bytes_available'. Reader is expected to read all + available data. Reading the data consumes it i.e. it cannot be read again. + census_log_read_next() returns NULL if the end is reached i.e last block + is read. census_log_init_reader() starts the iteration or aborts the + current iteration. +*/ +const void* census_log_read_next(size_t* bytes_available); + +/* Returns estimated remaining space across all blocks, in bytes. If log is + configured to discard old records, returns total log space. Otherwise, + returns space available in empty blocks (partially filled blocks are + treated as full). +*/ +size_t census_log_remaining_space(void); + +/* Returns the number of times gprc_stats_log_start_write() failed due to + out-of-space. */ +int64_t census_log_out_of_space_count(void); + +#endif /* GRPC_CORE_CENSUS_MLOG_H */ diff --git a/src/core/lib/census/operation.c b/src/core/lib/census/operation.c new file mode 100644 index 0000000000..5c58704372 --- /dev/null +++ b/src/core/lib/census/operation.c @@ -0,0 +1,63 @@ +/* + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +/* TODO(aveitch): These are all placeholder implementations. */ + +census_timestamp census_start_rpc_op_timestamp(void) { + census_timestamp ct; + /* TODO(aveitch): assumes gpr_timespec implementation of census_timestamp. */ + ct.ts = gpr_now(GPR_CLOCK_MONOTONIC); + return ct; +} + +census_context *census_start_client_rpc_op( + const census_context *context, int64_t rpc_name_id, + const census_rpc_name_info *rpc_name_info, const char *peer, int trace_mask, + const census_timestamp *start_time) { + return NULL; +} + +census_context *census_start_server_rpc_op( + const char *buffer, int64_t rpc_name_id, + const census_rpc_name_info *rpc_name_info, const char *peer, int trace_mask, + census_timestamp *start_time) { + return NULL; +} + +census_context *census_start_op(census_context *context, const char *family, + const char *name, int trace_mask) { + return NULL; +} + +void census_end_op(census_context *context, int status) {} diff --git a/src/core/lib/census/placeholders.c b/src/core/lib/census/placeholders.c new file mode 100644 index 0000000000..fe23d13971 --- /dev/null +++ b/src/core/lib/census/placeholders.c @@ -0,0 +1,109 @@ +/* + * + * 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 + +#include + +/* Placeholders for the pending APIs */ + +int census_get_trace_record(census_trace_record *trace_record) { + (void)trace_record; + abort(); +} + +void census_record_values(census_context *context, census_value *values, + size_t nvalues) { + (void)context; + (void)values; + (void)nvalues; + abort(); +} + +void census_set_rpc_client_peer(census_context *context, const char *peer) { + (void)context; + (void)peer; + abort(); +} + +void census_trace_scan_end() { abort(); } + +int census_trace_scan_start(int consume) { + (void)consume; + abort(); +} + +const census_aggregation *census_view_aggregrations(const census_view *view) { + (void)view; + abort(); +} + +census_view *census_view_create(uint32_t metric_id, const census_context *tags, + const census_aggregation *aggregations, + size_t naggregations) { + (void)metric_id; + (void)tags; + (void)aggregations; + (void)naggregations; + abort(); +} + +const census_context *census_view_tags(const census_view *view) { + (void)view; + abort(); +} + +void census_view_delete(census_view *view) { + (void)view; + abort(); +} + +const census_view_data *census_view_get_data(const census_view *view) { + (void)view; + abort(); +} + +size_t census_view_metric(const census_view *view) { + (void)view; + abort(); +} + +size_t census_view_naggregations(const census_view *view) { + (void)view; + abort(); +} + +void census_view_reset(census_view *view) { + (void)view; + abort(); +} diff --git a/src/core/lib/census/rpc_metric_id.h b/src/core/lib/census/rpc_metric_id.h new file mode 100644 index 0000000000..f8d8dad0bf --- /dev/null +++ b/src/core/lib/census/rpc_metric_id.h @@ -0,0 +1,51 @@ +/* + * + * Copyright 2015-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_CENSUS_RPC_METRIC_ID_H +#define GRPC_CORE_CENSUS_RPC_METRIC_ID_H + +/* Metric ID's used for RPC measurements. */ +/* Count of client requests sent. */ +#define CENSUS_METRIC_RPC_CLIENT_REQUESTS ((uint32_t)0) +/* Count of server requests sent. */ +#define CENSUS_METRIC_RPC_SERVER_REQUESTS ((uint32_t)1) +/* Client error counts. */ +#define CENSUS_METRIC_RPC_CLIENT_ERRORS ((uint32_t)2) +/* Server error counts. */ +#define CENSUS_METRIC_RPC_SERVER_ERRORS ((uint32_t)3) +/* Client side request latency. */ +#define CENSUS_METRIC_RPC_CLIENT_LATENCY ((uint32_t)4) +/* Server side request latency. */ +#define CENSUS_METRIC_RPC_SERVER_LATENCY ((uint32_t)5) + +#endif /* GRPC_CORE_CENSUS_RPC_METRIC_ID_H */ diff --git a/src/core/lib/census/tracing.c b/src/core/lib/census/tracing.c new file mode 100644 index 0000000000..3b5d6dab2b --- /dev/null +++ b/src/core/lib/census/tracing.c @@ -0,0 +1,45 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +/* TODO(aveitch): These are all placeholder implementations. */ + +int census_trace_mask(const census_context *context) { + return CENSUS_TRACE_MASK_NONE; +} + +void census_set_trace_mask(int trace_mask) {} + +void census_trace_print(census_context *context, uint32_t type, + const char *buffer, size_t n) {} diff --git a/src/core/lib/channel/channel_args.c b/src/core/lib/channel/channel_args.c new file mode 100644 index 0000000000..e0382fa0d9 --- /dev/null +++ b/src/core/lib/channel/channel_args.c @@ -0,0 +1,271 @@ +/* + * + * Copyright 2015-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/channel/channel_args.h" +#include +#include "src/core/support/string.h" + +#include +#include +#include +#include +#include + +#include + +static grpc_arg copy_arg(const grpc_arg *src) { + grpc_arg dst; + dst.type = src->type; + dst.key = gpr_strdup(src->key); + switch (dst.type) { + case GRPC_ARG_STRING: + dst.value.string = gpr_strdup(src->value.string); + break; + case GRPC_ARG_INTEGER: + dst.value.integer = src->value.integer; + break; + case GRPC_ARG_POINTER: + dst.value.pointer = src->value.pointer; + dst.value.pointer.p = + src->value.pointer.vtable->copy(src->value.pointer.p); + break; + } + return dst; +} + +grpc_channel_args *grpc_channel_args_copy_and_add(const grpc_channel_args *src, + const grpc_arg *to_add, + size_t num_to_add) { + grpc_channel_args *dst = gpr_malloc(sizeof(grpc_channel_args)); + size_t i; + size_t src_num_args = (src == NULL) ? 0 : src->num_args; + if (!src && !to_add) { + dst->num_args = 0; + dst->args = NULL; + return dst; + } + dst->num_args = src_num_args + num_to_add; + dst->args = gpr_malloc(sizeof(grpc_arg) * dst->num_args); + for (i = 0; i < src_num_args; i++) { + dst->args[i] = copy_arg(&src->args[i]); + } + for (i = 0; i < num_to_add; i++) { + dst->args[i + src_num_args] = copy_arg(&to_add[i]); + } + return dst; +} + +grpc_channel_args *grpc_channel_args_copy(const grpc_channel_args *src) { + return grpc_channel_args_copy_and_add(src, NULL, 0); +} + +grpc_channel_args *grpc_channel_args_merge(const grpc_channel_args *a, + const grpc_channel_args *b) { + return grpc_channel_args_copy_and_add(a, b->args, b->num_args); +} + +static int cmp_arg(const grpc_arg *a, const grpc_arg *b) { + int c = GPR_ICMP(a->type, b->type); + if (c != 0) return c; + c = strcmp(a->key, b->key); + if (c != 0) return c; + switch (a->type) { + case GRPC_ARG_STRING: + return strcmp(a->value.string, b->value.string); + case GRPC_ARG_INTEGER: + return GPR_ICMP(a->value.integer, b->value.integer); + case GRPC_ARG_POINTER: + c = GPR_ICMP(a->value.pointer.p, b->value.pointer.p); + if (c != 0) { + c = GPR_ICMP(a->value.pointer.vtable, b->value.pointer.vtable); + if (c == 0) { + c = a->value.pointer.vtable->cmp(a->value.pointer.p, + b->value.pointer.p); + } + } + return c; + } + GPR_UNREACHABLE_CODE(return 0); +} + +/* stabilizing comparison function: since channel_args ordering matters for + * keys with the same name, we need to preserve that ordering */ +static int cmp_key_stable(const void *ap, const void *bp) { + const grpc_arg *const *a = ap; + const grpc_arg *const *b = bp; + int c = strcmp((*a)->key, (*b)->key); + if (c == 0) c = GPR_ICMP(*a, *b); + return c; +} + +grpc_channel_args *grpc_channel_args_normalize(const grpc_channel_args *a) { + grpc_arg **args = gpr_malloc(sizeof(grpc_arg *) * a->num_args); + for (size_t i = 0; i < a->num_args; i++) { + args[i] = &a->args[i]; + } + qsort(args, a->num_args, sizeof(grpc_arg *), cmp_key_stable); + + grpc_channel_args *b = gpr_malloc(sizeof(grpc_channel_args)); + b->num_args = a->num_args; + b->args = gpr_malloc(sizeof(grpc_arg) * b->num_args); + for (size_t i = 0; i < a->num_args; i++) { + b->args[i] = copy_arg(args[i]); + } + + gpr_free(args); + return b; +} + +void grpc_channel_args_destroy(grpc_channel_args *a) { + size_t i; + for (i = 0; i < a->num_args; i++) { + switch (a->args[i].type) { + case GRPC_ARG_STRING: + gpr_free(a->args[i].value.string); + break; + case GRPC_ARG_INTEGER: + break; + case GRPC_ARG_POINTER: + a->args[i].value.pointer.vtable->destroy(a->args[i].value.pointer.p); + break; + } + gpr_free(a->args[i].key); + } + gpr_free(a->args); + gpr_free(a); +} + +int grpc_channel_args_is_census_enabled(const grpc_channel_args *a) { + size_t i; + if (a == NULL) return 0; + for (i = 0; i < a->num_args; i++) { + if (0 == strcmp(a->args[i].key, GRPC_ARG_ENABLE_CENSUS)) { + return a->args[i].value.integer != 0 && census_enabled(); + } + } + return census_enabled(); +} + +grpc_compression_algorithm grpc_channel_args_get_compression_algorithm( + const grpc_channel_args *a) { + size_t i; + if (a == NULL) return 0; + for (i = 0; i < a->num_args; ++i) { + if (a->args[i].type == GRPC_ARG_INTEGER && + !strcmp(GRPC_COMPRESSION_ALGORITHM_ARG, a->args[i].key)) { + return (grpc_compression_algorithm)a->args[i].value.integer; + break; + } + } + return GRPC_COMPRESS_NONE; +} + +grpc_channel_args *grpc_channel_args_set_compression_algorithm( + grpc_channel_args *a, grpc_compression_algorithm algorithm) { + grpc_arg tmp; + tmp.type = GRPC_ARG_INTEGER; + tmp.key = GRPC_COMPRESSION_ALGORITHM_ARG; + tmp.value.integer = algorithm; + return grpc_channel_args_copy_and_add(a, &tmp, 1); +} + +/** Returns 1 if the argument for compression algorithm's enabled states bitset + * was found in \a a, returning the arg's value in \a states. Otherwise, returns + * 0. */ +static int find_compression_algorithm_states_bitset(const grpc_channel_args *a, + int **states_arg) { + if (a != NULL) { + size_t i; + for (i = 0; i < a->num_args; ++i) { + if (a->args[i].type == GRPC_ARG_INTEGER && + !strcmp(GRPC_COMPRESSION_ALGORITHM_STATE_ARG, a->args[i].key)) { + *states_arg = &a->args[i].value.integer; + return 1; /* GPR_TRUE */ + } + } + } + return 0; /* GPR_FALSE */ +} + +grpc_channel_args *grpc_channel_args_compression_algorithm_set_state( + grpc_channel_args **a, grpc_compression_algorithm algorithm, int state) { + int *states_arg; + grpc_channel_args *result = *a; + const int states_arg_found = + find_compression_algorithm_states_bitset(*a, &states_arg); + + if (states_arg_found) { + if (state != 0) { + GPR_BITSET((unsigned *)states_arg, algorithm); + } else { + GPR_BITCLEAR((unsigned *)states_arg, algorithm); + } + } else { + /* create a new arg */ + grpc_arg tmp; + tmp.type = GRPC_ARG_INTEGER; + tmp.key = GRPC_COMPRESSION_ALGORITHM_STATE_ARG; + /* all enabled by default */ + tmp.value.integer = (1u << GRPC_COMPRESS_ALGORITHMS_COUNT) - 1; + if (state != 0) { + GPR_BITSET((unsigned *)&tmp.value.integer, algorithm); + } else { + GPR_BITCLEAR((unsigned *)&tmp.value.integer, algorithm); + } + result = grpc_channel_args_copy_and_add(*a, &tmp, 1); + grpc_channel_args_destroy(*a); + *a = result; + } + return result; +} + +int grpc_channel_args_compression_algorithm_get_states( + const grpc_channel_args *a) { + int *states_arg; + if (find_compression_algorithm_states_bitset(a, &states_arg)) { + return *states_arg; + } else { + return (1u << GRPC_COMPRESS_ALGORITHMS_COUNT) - 1; /* All algs. enabled */ + } +} + +int grpc_channel_args_compare(const grpc_channel_args *a, + const grpc_channel_args *b) { + int c = GPR_ICMP(a->num_args, b->num_args); + if (c != 0) return c; + for (size_t i = 0; i < a->num_args; i++) { + c = cmp_arg(&a->args[i], &b->args[i]); + if (c != 0) return c; + } + return 0; +} diff --git a/src/core/lib/channel/channel_args.h b/src/core/lib/channel/channel_args.h new file mode 100644 index 0000000000..e19440f76f --- /dev/null +++ b/src/core/lib/channel/channel_args.h @@ -0,0 +1,94 @@ +/* + * + * Copyright 2015-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_CHANNEL_CHANNEL_ARGS_H +#define GRPC_CORE_CHANNEL_CHANNEL_ARGS_H + +#include +#include + +/* Copy some arguments */ +grpc_channel_args *grpc_channel_args_copy(const grpc_channel_args *src); + +/* Copy some arguments, stably sorting keys */ +grpc_channel_args *grpc_channel_args_normalize(const grpc_channel_args *a); + +/** Copy some arguments and add the to_add parameter in the end. + If to_add is NULL, it is equivalent to call grpc_channel_args_copy. */ +grpc_channel_args *grpc_channel_args_copy_and_add(const grpc_channel_args *src, + const grpc_arg *to_add, + size_t num_to_add); + +/** Copy args from a then args from b into a new channel args */ +grpc_channel_args *grpc_channel_args_merge(const grpc_channel_args *a, + const grpc_channel_args *b); + +/** Destroy arguments created by grpc_channel_args_copy */ +void grpc_channel_args_destroy(grpc_channel_args *a); + +/** Reads census_enabled settings from channel args. Returns 1 if census_enabled + * is specified in channel args, otherwise returns 0. */ +int grpc_channel_args_is_census_enabled(const grpc_channel_args *a); + +/** Returns the compression algorithm set in \a a. */ +grpc_compression_algorithm grpc_channel_args_get_compression_algorithm( + const grpc_channel_args *a); + +/** Returns a channel arg instance with compression enabled. If \a a is + * non-NULL, its args are copied. N.B. GRPC_COMPRESS_NONE disables compression + * for the channel. */ +grpc_channel_args *grpc_channel_args_set_compression_algorithm( + grpc_channel_args *a, grpc_compression_algorithm algorithm); + +/** Sets the support for the given compression algorithm. By default, all + * compression algorithms are enabled. It's an error to disable an algorithm set + * by grpc_channel_args_set_compression_algorithm. + * + * Returns an instance with the updated algorithm states. The \a a pointer is + * modified to point to the returned instance (which may be different from the + * input value of \a a). */ +grpc_channel_args *grpc_channel_args_compression_algorithm_set_state( + grpc_channel_args **a, grpc_compression_algorithm algorithm, int enabled); + +/** Returns the bitset representing the support state (true for enabled, false + * for disabled) for compression algorithms. + * + * The i-th bit of the returned bitset corresponds to the i-th entry in the + * grpc_compression_algorithm enum. */ +int grpc_channel_args_compression_algorithm_get_states( + const grpc_channel_args *a); + +int grpc_channel_args_compare(const grpc_channel_args *a, + const grpc_channel_args *b); + +#endif /* GRPC_CORE_CHANNEL_CHANNEL_ARGS_H */ diff --git a/src/core/lib/channel/channel_stack.c b/src/core/lib/channel/channel_stack.c new file mode 100644 index 0000000000..3e61688364 --- /dev/null +++ b/src/core/lib/channel/channel_stack.c @@ -0,0 +1,262 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/channel/channel_stack.h" +#include + +#include +#include + +int grpc_trace_channel = 0; + +/* Memory layouts. + + Channel stack is laid out as: { + grpc_channel_stack stk; + padding to GPR_MAX_ALIGNMENT + grpc_channel_element[stk.count]; + per-filter memory, aligned to GPR_MAX_ALIGNMENT + } + + Call stack is laid out as: { + grpc_call_stack stk; + padding to GPR_MAX_ALIGNMENT + grpc_call_element[stk.count]; + per-filter memory, aligned to GPR_MAX_ALIGNMENT + } */ + +/* Given a size, round up to the next multiple of sizeof(void*) */ +#define ROUND_UP_TO_ALIGNMENT_SIZE(x) \ + (((x) + GPR_MAX_ALIGNMENT - 1u) & ~(GPR_MAX_ALIGNMENT - 1u)) + +size_t grpc_channel_stack_size(const grpc_channel_filter **filters, + size_t filter_count) { + /* always need the header, and size for the channel elements */ + size_t size = + ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_channel_stack)) + + ROUND_UP_TO_ALIGNMENT_SIZE(filter_count * sizeof(grpc_channel_element)); + size_t i; + + GPR_ASSERT((GPR_MAX_ALIGNMENT & (GPR_MAX_ALIGNMENT - 1)) == 0 && + "GPR_MAX_ALIGNMENT must be a power of two"); + + /* add the size for each filter */ + for (i = 0; i < filter_count; i++) { + size += ROUND_UP_TO_ALIGNMENT_SIZE(filters[i]->sizeof_channel_data); + } + + return size; +} + +#define CHANNEL_ELEMS_FROM_STACK(stk) \ + ((grpc_channel_element *)((char *)(stk) + ROUND_UP_TO_ALIGNMENT_SIZE( \ + sizeof(grpc_channel_stack)))) + +#define CALL_ELEMS_FROM_STACK(stk) \ + ((grpc_call_element *)((char *)(stk) + \ + ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call_stack)))) + +grpc_channel_element *grpc_channel_stack_element( + grpc_channel_stack *channel_stack, size_t index) { + return CHANNEL_ELEMS_FROM_STACK(channel_stack) + index; +} + +grpc_channel_element *grpc_channel_stack_last_element( + grpc_channel_stack *channel_stack) { + return grpc_channel_stack_element(channel_stack, channel_stack->count - 1); +} + +grpc_call_element *grpc_call_stack_element(grpc_call_stack *call_stack, + size_t index) { + return CALL_ELEMS_FROM_STACK(call_stack) + index; +} + +void grpc_channel_stack_init(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 *channel_args, + const char *name, grpc_channel_stack *stack) { + size_t call_size = + ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call_stack)) + + ROUND_UP_TO_ALIGNMENT_SIZE(filter_count * sizeof(grpc_call_element)); + grpc_channel_element *elems; + grpc_channel_element_args args; + char *user_data; + size_t i; + + stack->count = filter_count; + GRPC_STREAM_REF_INIT(&stack->refcount, initial_refs, destroy, destroy_arg, + name); + elems = CHANNEL_ELEMS_FROM_STACK(stack); + user_data = + ((char *)elems) + + ROUND_UP_TO_ALIGNMENT_SIZE(filter_count * sizeof(grpc_channel_element)); + + /* init per-filter data */ + for (i = 0; i < filter_count; i++) { + args.channel_stack = stack; + args.channel_args = channel_args; + args.is_first = i == 0; + args.is_last = i == (filter_count - 1); + elems[i].filter = filters[i]; + elems[i].channel_data = user_data; + elems[i].filter->init_channel_elem(exec_ctx, &elems[i], &args); + user_data += ROUND_UP_TO_ALIGNMENT_SIZE(filters[i]->sizeof_channel_data); + call_size += ROUND_UP_TO_ALIGNMENT_SIZE(filters[i]->sizeof_call_data); + } + + GPR_ASSERT(user_data > (char *)stack); + GPR_ASSERT((uintptr_t)(user_data - (char *)stack) == + grpc_channel_stack_size(filters, filter_count)); + + stack->call_stack_size = call_size; +} + +void grpc_channel_stack_destroy(grpc_exec_ctx *exec_ctx, + grpc_channel_stack *stack) { + grpc_channel_element *channel_elems = CHANNEL_ELEMS_FROM_STACK(stack); + size_t count = stack->count; + size_t i; + + /* destroy per-filter data */ + for (i = 0; i < count; i++) { + channel_elems[i].filter->destroy_channel_elem(exec_ctx, &channel_elems[i]); + } +} + +void grpc_call_stack_init(grpc_exec_ctx *exec_ctx, + grpc_channel_stack *channel_stack, int initial_refs, + grpc_iomgr_cb_func destroy, void *destroy_arg, + grpc_call_context_element *context, + const void *transport_server_data, + grpc_call_stack *call_stack) { + grpc_channel_element *channel_elems = CHANNEL_ELEMS_FROM_STACK(channel_stack); + grpc_call_element_args args; + size_t count = channel_stack->count; + grpc_call_element *call_elems; + char *user_data; + size_t i; + + call_stack->count = count; + GRPC_STREAM_REF_INIT(&call_stack->refcount, initial_refs, destroy, + destroy_arg, "CALL_STACK"); + call_elems = CALL_ELEMS_FROM_STACK(call_stack); + user_data = ((char *)call_elems) + + ROUND_UP_TO_ALIGNMENT_SIZE(count * sizeof(grpc_call_element)); + + /* init per-filter data */ + for (i = 0; i < count; i++) { + args.call_stack = call_stack; + args.server_transport_data = transport_server_data; + args.context = context; + call_elems[i].filter = channel_elems[i].filter; + call_elems[i].channel_data = channel_elems[i].channel_data; + call_elems[i].call_data = user_data; + call_elems[i].filter->init_call_elem(exec_ctx, &call_elems[i], &args); + user_data += + ROUND_UP_TO_ALIGNMENT_SIZE(call_elems[i].filter->sizeof_call_data); + } +} + +void grpc_call_stack_set_pollset(grpc_exec_ctx *exec_ctx, + grpc_call_stack *call_stack, + grpc_pollset *pollset) { + size_t count = call_stack->count; + grpc_call_element *call_elems; + char *user_data; + size_t i; + + call_elems = CALL_ELEMS_FROM_STACK(call_stack); + user_data = ((char *)call_elems) + + ROUND_UP_TO_ALIGNMENT_SIZE(count * sizeof(grpc_call_element)); + + /* init per-filter data */ + for (i = 0; i < count; i++) { + call_elems[i].filter->set_pollset(exec_ctx, &call_elems[i], pollset); + user_data += + ROUND_UP_TO_ALIGNMENT_SIZE(call_elems[i].filter->sizeof_call_data); + } +} + +void grpc_call_stack_ignore_set_pollset(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + grpc_pollset *pollset) {} + +void grpc_call_stack_destroy(grpc_exec_ctx *exec_ctx, grpc_call_stack *stack) { + grpc_call_element *elems = CALL_ELEMS_FROM_STACK(stack); + size_t count = stack->count; + size_t i; + + /* destroy per-filter data */ + for (i = 0; i < count; i++) { + elems[i].filter->destroy_call_elem(exec_ctx, &elems[i]); + } +} + +void grpc_call_next_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + grpc_transport_stream_op *op) { + grpc_call_element *next_elem = elem + 1; + next_elem->filter->start_transport_stream_op(exec_ctx, next_elem, op); +} + +char *grpc_call_next_get_peer(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem) { + grpc_call_element *next_elem = elem + 1; + return next_elem->filter->get_peer(exec_ctx, next_elem); +} + +void grpc_channel_next_op(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, + grpc_transport_op *op) { + grpc_channel_element *next_elem = elem + 1; + next_elem->filter->start_transport_op(exec_ctx, next_elem, op); +} + +grpc_channel_stack *grpc_channel_stack_from_top_element( + grpc_channel_element *elem) { + return (grpc_channel_stack *)((char *)(elem)-ROUND_UP_TO_ALIGNMENT_SIZE( + sizeof(grpc_channel_stack))); +} + +grpc_call_stack *grpc_call_stack_from_top_element(grpc_call_element *elem) { + return (grpc_call_stack *)((char *)(elem)-ROUND_UP_TO_ALIGNMENT_SIZE( + sizeof(grpc_call_stack))); +} + +void grpc_call_element_send_cancel(grpc_exec_ctx *exec_ctx, + grpc_call_element *cur_elem) { + grpc_transport_stream_op op; + memset(&op, 0, sizeof(op)); + op.cancel_with_status = GRPC_STATUS_CANCELLED; + grpc_call_next_op(exec_ctx, cur_elem, &op); +} diff --git a/src/core/lib/channel/channel_stack.h b/src/core/lib/channel/channel_stack.h new file mode 100644 index 0000000000..52362f0b20 --- /dev/null +++ b/src/core/lib/channel/channel_stack.h @@ -0,0 +1,260 @@ +/* + * + * Copyright 2015-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_CHANNEL_CHANNEL_STACK_H +#define GRPC_CORE_CHANNEL_CHANNEL_STACK_H + +/* A channel filter defines how operations on a channel are implemented. + Channel filters are chained together to create full channels, and if those + chains are linear, then channel stacks provide a mechanism to minimize + allocations for that chain. + Call stacks are created by channel stacks and represent the per-call data + for that stack. */ + +#include + +#include +#include +#include "src/core/debug/trace.h" +#include "src/core/transport/transport.h" + +typedef struct grpc_channel_element grpc_channel_element; +typedef struct grpc_call_element grpc_call_element; + +typedef struct grpc_channel_stack grpc_channel_stack; +typedef struct grpc_call_stack grpc_call_stack; + +typedef struct { + grpc_channel_stack *channel_stack; + const grpc_channel_args *channel_args; + int is_first; + int is_last; +} grpc_channel_element_args; + +typedef struct { + grpc_call_stack *call_stack; + const void *server_transport_data; + grpc_call_context_element *context; +} grpc_call_element_args; + +/* Channel filters specify: + 1. the amount of memory needed in the channel & call (via the sizeof_XXX + members) + 2. functions to initialize and destroy channel & call data + (init_XXX, destroy_XXX) + 3. functions to implement call operations and channel operations (call_op, + channel_op) + 4. a name, which is useful when debugging + + Members are laid out in approximate frequency of use order. */ +typedef struct { + /* Called to eg. send/receive data on a call. + See grpc_call_next_op on how to call the next element in the stack */ + void (*start_transport_stream_op)(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + grpc_transport_stream_op *op); + /* Called to handle channel level operations - e.g. new calls, or transport + closure. + See grpc_channel_next_op on how to call the next element in the stack */ + void (*start_transport_op)(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem, grpc_transport_op *op); + + /* sizeof(per call data) */ + size_t sizeof_call_data; + /* Initialize per call data. + elem is initialized at the start of the call, and elem->call_data is what + needs initializing. + The filter does not need to do any chaining. + server_transport_data is an opaque pointer. If it is NULL, this call is + on a client; if it is non-NULL, then it points to memory owned by the + transport and is on the server. Most filters want to ignore this + argument. */ + void (*init_call_elem)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + grpc_call_element_args *args); + void (*set_pollset)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + grpc_pollset *pollset); + /* Destroy per call data. + The filter does not need to do any chaining */ + void (*destroy_call_elem)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem); + + /* sizeof(per channel data) */ + size_t sizeof_channel_data; + /* Initialize per-channel data. + elem is initialized at the start of the call, and elem->channel_data is + what needs initializing. + is_first, is_last designate this elements position in the stack, and are + useful for asserting correct configuration by upper layer code. + The filter does not need to do any chaining */ + void (*init_channel_elem)(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, + grpc_channel_element_args *args); + /* Destroy per channel data. + The filter does not need to do any chaining */ + void (*destroy_channel_elem)(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem); + + /* Implement grpc_call_get_peer() */ + char *(*get_peer)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem); + + /* The name of this filter */ + const char *name; +} grpc_channel_filter; + +/* A channel_element tracks its filter and the filter requested memory within + a channel allocation */ +struct grpc_channel_element { + const grpc_channel_filter *filter; + void *channel_data; +}; + +/* A call_element tracks its filter, the filter requested memory within + a channel allocation, and the filter requested memory within a call + allocation */ +struct grpc_call_element { + const grpc_channel_filter *filter; + void *channel_data; + void *call_data; +}; + +/* A channel stack tracks a set of related filters for one channel, and + guarantees they live within a single malloc() allocation */ +struct grpc_channel_stack { + grpc_stream_refcount refcount; + size_t count; + /* Memory required for a call stack (computed at channel stack + initialization) */ + size_t call_stack_size; +}; + +/* A call stack tracks a set of related filters for one call, and guarantees + they live within a single malloc() allocation */ +struct grpc_call_stack { + /* shared refcount for this channel stack. + MUST be the first element: the underlying code calls destroy + with the address of the refcount, but higher layers prefer to think + about the address of the call stack itself. */ + grpc_stream_refcount refcount; + size_t count; +}; + +/* Get a channel element given a channel stack and its index */ +grpc_channel_element *grpc_channel_stack_element(grpc_channel_stack *stack, + size_t i); +/* Get the last channel element in a channel stack */ +grpc_channel_element *grpc_channel_stack_last_element( + grpc_channel_stack *stack); +/* Get a call stack element given a call stack and an index */ +grpc_call_element *grpc_call_stack_element(grpc_call_stack *stack, size_t i); + +/* Determine memory required for a channel stack containing a set of filters */ +size_t grpc_channel_stack_size(const grpc_channel_filter **filters, + size_t filter_count); +/* Initialize a channel stack given some filters */ +void grpc_channel_stack_init(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, + const char *name, grpc_channel_stack *stack); +/* Destroy a channel stack */ +void grpc_channel_stack_destroy(grpc_exec_ctx *exec_ctx, + grpc_channel_stack *stack); + +/* Initialize a call stack given a channel stack. transport_server_data is + expected to be NULL on a client, or an opaque transport owned pointer on the + server. */ +void grpc_call_stack_init(grpc_exec_ctx *exec_ctx, + grpc_channel_stack *channel_stack, int initial_refs, + grpc_iomgr_cb_func destroy, void *destroy_arg, + grpc_call_context_element *context, + const void *transport_server_data, + grpc_call_stack *call_stack); +/* Set a pollset for a call stack: must occur before the first op is started */ +void grpc_call_stack_set_pollset(grpc_exec_ctx *exec_ctx, + grpc_call_stack *call_stack, + grpc_pollset *pollset); + +#ifdef GRPC_STREAM_REFCOUNT_DEBUG +#define GRPC_CALL_STACK_REF(call_stack, reason) \ + grpc_stream_ref(&(call_stack)->refcount, reason) +#define GRPC_CALL_STACK_UNREF(exec_ctx, call_stack, reason) \ + grpc_stream_unref(exec_ctx, &(call_stack)->refcount, reason) +#define GRPC_CHANNEL_STACK_REF(channel_stack, reason) \ + grpc_stream_ref(&(channel_stack)->refcount, reason) +#define GRPC_CHANNEL_STACK_UNREF(exec_ctx, channel_stack, reason) \ + grpc_stream_unref(exec_ctx, &(channel_stack)->refcount, reason) +#else +#define GRPC_CALL_STACK_REF(call_stack, reason) \ + grpc_stream_ref(&(call_stack)->refcount) +#define GRPC_CALL_STACK_UNREF(exec_ctx, call_stack, reason) \ + grpc_stream_unref(exec_ctx, &(call_stack)->refcount) +#define GRPC_CHANNEL_STACK_REF(channel_stack, reason) \ + grpc_stream_ref(&(channel_stack)->refcount) +#define GRPC_CHANNEL_STACK_UNREF(exec_ctx, channel_stack, reason) \ + grpc_stream_unref(exec_ctx, &(channel_stack)->refcount) +#endif + +/* Destroy a call stack */ +void grpc_call_stack_destroy(grpc_exec_ctx *exec_ctx, grpc_call_stack *stack); + +/* Ignore set pollset - used by filters to implement the set_pollset method + if they don't care about pollsets at all. Does nothing. */ +void grpc_call_stack_ignore_set_pollset(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + grpc_pollset *pollset); +/* Call the next operation in a call stack */ +void grpc_call_next_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + grpc_transport_stream_op *op); +/* Call the next operation (depending on call directionality) in a channel + stack */ +void grpc_channel_next_op(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, + grpc_transport_op *op); +/* Pass through a request to get_peer to the next child element */ +char *grpc_call_next_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem); + +/* Given the top element of a channel stack, get the channel stack itself */ +grpc_channel_stack *grpc_channel_stack_from_top_element( + grpc_channel_element *elem); +/* Given the top element of a call stack, get the call stack itself */ +grpc_call_stack *grpc_call_stack_from_top_element(grpc_call_element *elem); + +void grpc_call_log_op(char *file, int line, gpr_log_severity severity, + grpc_call_element *elem, grpc_transport_stream_op *op); + +void grpc_call_element_send_cancel(grpc_exec_ctx *exec_ctx, + grpc_call_element *cur_elem); + +extern int grpc_trace_channel; + +#define GRPC_CALL_LOG_OP(sev, elem, op) \ + if (grpc_trace_channel) grpc_call_log_op(sev, elem, op) + +#endif /* GRPC_CORE_CHANNEL_CHANNEL_STACK_H */ diff --git a/src/core/lib/channel/channel_stack_builder.c b/src/core/lib/channel/channel_stack_builder.c new file mode 100644 index 0000000000..1b1004e5f9 --- /dev/null +++ b/src/core/lib/channel/channel_stack_builder.c @@ -0,0 +1,258 @@ +/* + * + * 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/channel/channel_stack_builder.h" + +#include + +#include + +int grpc_trace_channel_stack_builder = 0; + +typedef struct filter_node { + struct filter_node *next; + struct filter_node *prev; + const grpc_channel_filter *filter; + grpc_post_filter_create_init_func init; + void *init_arg; +} filter_node; + +struct grpc_channel_stack_builder { + // sentinel nodes for filters that have been added + filter_node begin; + filter_node end; + // various set/get-able parameters + const grpc_channel_args *args; + grpc_transport *transport; + const char *name; +}; + +struct grpc_channel_stack_builder_iterator { + grpc_channel_stack_builder *builder; + filter_node *node; +}; + +grpc_channel_stack_builder *grpc_channel_stack_builder_create(void) { + grpc_channel_stack_builder *b = gpr_malloc(sizeof(*b)); + memset(b, 0, sizeof(*b)); + + b->begin.filter = NULL; + b->end.filter = NULL; + b->begin.next = &b->end; + b->begin.prev = &b->end; + b->end.next = &b->begin; + b->end.prev = &b->begin; + + return b; +} + +static grpc_channel_stack_builder_iterator *create_iterator_at_filter_node( + grpc_channel_stack_builder *builder, filter_node *node) { + grpc_channel_stack_builder_iterator *it = gpr_malloc(sizeof(*it)); + it->builder = builder; + it->node = node; + return it; +} + +void grpc_channel_stack_builder_iterator_destroy( + grpc_channel_stack_builder_iterator *it) { + gpr_free(it); +} + +grpc_channel_stack_builder_iterator * +grpc_channel_stack_builder_create_iterator_at_first( + grpc_channel_stack_builder *builder) { + return create_iterator_at_filter_node(builder, &builder->begin); +} + +grpc_channel_stack_builder_iterator * +grpc_channel_stack_builder_create_iterator_at_last( + grpc_channel_stack_builder *builder) { + return create_iterator_at_filter_node(builder, &builder->end); +} + +bool grpc_channel_stack_builder_move_next( + grpc_channel_stack_builder_iterator *iterator) { + if (iterator->node == &iterator->builder->end) return false; + iterator->node = iterator->node->next; + return true; +} + +bool grpc_channel_stack_builder_move_prev( + grpc_channel_stack_builder_iterator *iterator) { + if (iterator->node == &iterator->builder->begin) return false; + iterator->node = iterator->node->prev; + return true; +} + +bool grpc_channel_stack_builder_move_prev( + grpc_channel_stack_builder_iterator *iterator); + +void grpc_channel_stack_builder_set_name(grpc_channel_stack_builder *builder, + const char *name) { + GPR_ASSERT(builder->name == NULL); + builder->name = name; +} + +void grpc_channel_stack_builder_set_channel_arguments( + grpc_channel_stack_builder *builder, const grpc_channel_args *args) { + GPR_ASSERT(builder->args == NULL); + builder->args = args; +} + +void grpc_channel_stack_builder_set_transport( + grpc_channel_stack_builder *builder, grpc_transport *transport) { + GPR_ASSERT(builder->transport == NULL); + builder->transport = transport; +} + +grpc_transport *grpc_channel_stack_builder_get_transport( + grpc_channel_stack_builder *builder) { + return builder->transport; +} + +const grpc_channel_args *grpc_channel_stack_builder_get_channel_arguments( + grpc_channel_stack_builder *builder) { + return builder->args; +} + +bool grpc_channel_stack_builder_append_filter( + grpc_channel_stack_builder *builder, const grpc_channel_filter *filter, + grpc_post_filter_create_init_func post_init_func, void *user_data) { + grpc_channel_stack_builder_iterator *it = + grpc_channel_stack_builder_create_iterator_at_last(builder); + bool ok = grpc_channel_stack_builder_add_filter_before( + it, filter, post_init_func, user_data); + grpc_channel_stack_builder_iterator_destroy(it); + return ok; +} + +bool grpc_channel_stack_builder_prepend_filter( + grpc_channel_stack_builder *builder, const grpc_channel_filter *filter, + grpc_post_filter_create_init_func post_init_func, void *user_data) { + grpc_channel_stack_builder_iterator *it = + grpc_channel_stack_builder_create_iterator_at_first(builder); + bool ok = grpc_channel_stack_builder_add_filter_after( + it, filter, post_init_func, user_data); + grpc_channel_stack_builder_iterator_destroy(it); + return ok; +} + +static void add_after(filter_node *before, const grpc_channel_filter *filter, + grpc_post_filter_create_init_func post_init_func, + void *user_data) { + filter_node *new = gpr_malloc(sizeof(*new)); + new->next = before->next; + new->prev = before; + new->next->prev = new->prev->next = new; + new->filter = filter; + new->init = post_init_func; + new->init_arg = user_data; +} + +bool grpc_channel_stack_builder_add_filter_before( + grpc_channel_stack_builder_iterator *iterator, + const grpc_channel_filter *filter, + grpc_post_filter_create_init_func post_init_func, void *user_data) { + if (iterator->node == &iterator->builder->begin) return false; + add_after(iterator->node->prev, filter, post_init_func, user_data); + return true; +} + +bool grpc_channel_stack_builder_add_filter_after( + grpc_channel_stack_builder_iterator *iterator, + const grpc_channel_filter *filter, + grpc_post_filter_create_init_func post_init_func, void *user_data) { + if (iterator->node == &iterator->builder->end) return false; + add_after(iterator->node, filter, post_init_func, user_data); + return true; +} + +void grpc_channel_stack_builder_destroy(grpc_channel_stack_builder *builder) { + filter_node *p = builder->begin.next; + while (p != &builder->end) { + filter_node *next = p->next; + gpr_free(p); + p = next; + } + gpr_free(builder); +} + +void *grpc_channel_stack_builder_finish(grpc_exec_ctx *exec_ctx, + grpc_channel_stack_builder *builder, + size_t prefix_bytes, int initial_refs, + grpc_iomgr_cb_func destroy, + void *destroy_arg) { + // count the number of filters + size_t num_filters = 0; + for (filter_node *p = builder->begin.next; p != &builder->end; p = p->next) { + num_filters++; + } + + // create an array of filters + const grpc_channel_filter **filters = + gpr_malloc(sizeof(*filters) * num_filters); + size_t i = 0; + for (filter_node *p = builder->begin.next; p != &builder->end; p = p->next) { + filters[i++] = p->filter; + } + + // calculate the size of the channel stack + size_t channel_stack_size = grpc_channel_stack_size(filters, num_filters); + + // allocate memory, with prefix_bytes followed by channel_stack_size + char *result = gpr_malloc(prefix_bytes + channel_stack_size); + // fetch a pointer to the channel stack + grpc_channel_stack *channel_stack = + (grpc_channel_stack *)(result + prefix_bytes); + // 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); + + // run post-initialization functions + i = 0; + for (filter_node *p = builder->begin.next; p != &builder->end; p = p->next) { + if (p->init != NULL) { + p->init(channel_stack, grpc_channel_stack_element(channel_stack, i), + p->init_arg); + } + i++; + } + + grpc_channel_stack_builder_destroy(builder); + gpr_free((grpc_channel_filter **)filters); + + return result; +} diff --git a/src/core/lib/channel/channel_stack_builder.h b/src/core/lib/channel/channel_stack_builder.h new file mode 100644 index 0000000000..15f395e8b8 --- /dev/null +++ b/src/core/lib/channel/channel_stack_builder.h @@ -0,0 +1,155 @@ +/* + * + * 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_CHANNEL_CHANNEL_STACK_BUILDER_H +#define GRPC_CORE_CHANNEL_CHANNEL_STACK_BUILDER_H + +#include + +#include "src/core/channel/channel_args.h" +#include "src/core/channel/channel_stack.h" + +/// grpc_channel_stack_builder offers a programmatic interface to selected +/// and order channel filters +typedef struct grpc_channel_stack_builder grpc_channel_stack_builder; +typedef struct grpc_channel_stack_builder_iterator + grpc_channel_stack_builder_iterator; + +/// Create a new channel stack builder +grpc_channel_stack_builder *grpc_channel_stack_builder_create(void); + +/// Assign a name to the channel stack: \a name must be statically allocated +void grpc_channel_stack_builder_set_name(grpc_channel_stack_builder *builder, + const char *name); + +/// Attach \a transport to the builder (does not take ownership) +void grpc_channel_stack_builder_set_transport( + grpc_channel_stack_builder *builder, grpc_transport *transport); + +/// Fetch attached transport +grpc_transport *grpc_channel_stack_builder_get_transport( + grpc_channel_stack_builder *builder); + +/// Set channel arguments: \a args must continue to exist until after +/// grpc_channel_stack_builder_finish returns +void grpc_channel_stack_builder_set_channel_arguments( + grpc_channel_stack_builder *builder, const grpc_channel_args *args); + +/// Return a borrowed pointer to the channel arguments +const grpc_channel_args *grpc_channel_stack_builder_get_channel_arguments( + grpc_channel_stack_builder *builder); + +/// Begin iterating over already defined filters in the builder at the beginning +grpc_channel_stack_builder_iterator * +grpc_channel_stack_builder_create_iterator_at_first( + grpc_channel_stack_builder *builder); + +/// Begin iterating over already defined filters in the builder at the end +grpc_channel_stack_builder_iterator * +grpc_channel_stack_builder_create_iterator_at_last( + grpc_channel_stack_builder *builder); + +/// Is an iterator at the first element? +bool grpc_channel_stack_builder_iterator_is_first( + grpc_channel_stack_builder_iterator *iterator); + +/// Is an iterator at the end? +bool grpc_channel_stack_builder_iterator_is_end( + grpc_channel_stack_builder_iterator *iterator); + +/// Move an iterator to the next item +bool grpc_channel_stack_builder_move_next( + grpc_channel_stack_builder_iterator *iterator); + +/// Move an iterator to the previous item +bool grpc_channel_stack_builder_move_prev( + grpc_channel_stack_builder_iterator *iterator); + +typedef void (*grpc_post_filter_create_init_func)( + grpc_channel_stack *channel_stack, grpc_channel_element *elem, void *arg); + +/// Add \a filter to the stack, after \a iterator. +/// Call \a post_init_func(..., \a user_data) once the channel stack is +/// created. +bool grpc_channel_stack_builder_add_filter_after( + grpc_channel_stack_builder_iterator *iterator, + const grpc_channel_filter *filter, + grpc_post_filter_create_init_func post_init_func, + void *user_data) GRPC_MUST_USE_RESULT; + +/// Add \a filter to the stack, before \a iterator. +/// Call \a post_init_func(..., \a user_data) once the channel stack is +/// created. +bool grpc_channel_stack_builder_add_filter_before( + grpc_channel_stack_builder_iterator *iterator, + const grpc_channel_filter *filter, + grpc_post_filter_create_init_func post_init_func, + void *user_data) GRPC_MUST_USE_RESULT; + +/// Add \a filter to the beginning of the filter list. +/// Call \a post_init_func(..., \a user_data) once the channel stack is +/// created. +bool grpc_channel_stack_builder_prepend_filter( + grpc_channel_stack_builder *builder, const grpc_channel_filter *filter, + grpc_post_filter_create_init_func post_init_func, + void *user_data) GRPC_MUST_USE_RESULT; + +/// Add \a filter to the end of the filter list. +/// Call \a post_init_func(..., \a user_data) once the channel stack is +/// created. +bool grpc_channel_stack_builder_append_filter( + grpc_channel_stack_builder *builder, const grpc_channel_filter *filter, + grpc_post_filter_create_init_func post_init_func, + void *user_data) GRPC_MUST_USE_RESULT; + +/// Terminate iteration and destroy \a iterator +void grpc_channel_stack_builder_iterator_destroy( + grpc_channel_stack_builder_iterator *iterator); + +/// Destroy the builder, return the freshly minted channel stack +/// Allocates \a prefix_bytes bytes before the channel stack +/// Returns the base pointer of the allocated block +/// \a initial_refs, \a destroy, \a destroy_arg are as per +/// grpc_channel_stack_init +void *grpc_channel_stack_builder_finish(grpc_exec_ctx *exec_ctx, + grpc_channel_stack_builder *builder, + size_t prefix_bytes, int initial_refs, + grpc_iomgr_cb_func destroy, + void *destroy_arg); + +/// Destroy the builder without creating a channel stack +void grpc_channel_stack_builder_destroy(grpc_channel_stack_builder *builder); + +extern int grpc_trace_channel_stack_builder; + +#endif /* GRPC_CORE_CHANNEL_CHANNEL_STACK_BUILDER_H */ diff --git a/src/core/lib/channel/client_channel.c b/src/core/lib/channel/client_channel.c new file mode 100644 index 0000000000..ad1ded9ab7 --- /dev/null +++ b/src/core/lib/channel/client_channel.c @@ -0,0 +1,526 @@ +/* + * + * Copyright 2015-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/channel/client_channel.h" + +#include +#include + +#include +#include +#include +#include + +#include "src/core/channel/channel_args.h" +#include "src/core/channel/connected_channel.h" +#include "src/core/channel/subchannel_call_holder.h" +#include "src/core/iomgr/iomgr.h" +#include "src/core/profiling/timers.h" +#include "src/core/support/string.h" +#include "src/core/surface/channel.h" +#include "src/core/transport/connectivity_state.h" + +/* Client channel implementation */ + +typedef grpc_subchannel_call_holder call_data; + +typedef struct client_channel_channel_data { + /** resolver for this channel */ + grpc_resolver *resolver; + /** have we started resolving this channel */ + int started_resolving; + + /** mutex protecting client configuration, including all + variables below in this data structure */ + gpr_mu mu_config; + /** currently active load balancer - guarded by mu_config */ + grpc_lb_policy *lb_policy; + /** incoming configuration - set by resolver.next + guarded by mu_config */ + grpc_client_config *incoming_configuration; + /** a list of closures that are all waiting for config to come in */ + grpc_closure_list waiting_for_config_closures; + /** resolver callback */ + grpc_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; + /** owning stack */ + grpc_channel_stack *owning_stack; + /** interested parties (owned) */ + grpc_pollset_set *interested_parties; +} 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_closure on_changed; + grpc_connectivity_state state; + grpc_lb_policy *lb_policy; +} lb_policy_connectivity_watcher; + +typedef struct { + grpc_closure closure; + grpc_call_element *elem; +} waiting_call; + +static char *cc_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) { + return grpc_subchannel_call_holder_get_peer(exec_ctx, elem->call_data); +} + +static void cc_start_transport_stream_op(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + grpc_transport_stream_op *op) { + GRPC_CALL_LOG_OP(GPR_INFO, elem, op); + grpc_subchannel_call_holder_perform_op(exec_ctx, elem->call_data, op); +} + +static void watch_lb_policy(grpc_exec_ctx *exec_ctx, channel_data *chand, + grpc_lb_policy *lb_policy, + grpc_connectivity_state current_state); + +static void on_lb_policy_state_changed_locked( + grpc_exec_ctx *exec_ctx, lb_policy_connectivity_watcher *w) { + grpc_connectivity_state publish_state = w->state; + /* check if the notification is for a stale policy */ + if (w->lb_policy != w->chand->lb_policy) return; + + if (publish_state == GRPC_CHANNEL_FATAL_FAILURE && + w->chand->resolver != NULL) { + publish_state = GRPC_CHANNEL_TRANSIENT_FAILURE; + grpc_resolver_channel_saw_error(exec_ctx, w->chand->resolver); + GRPC_LB_POLICY_UNREF(exec_ctx, w->chand->lb_policy, "channel"); + w->chand->lb_policy = NULL; + } + grpc_connectivity_state_set(exec_ctx, &w->chand->state_tracker, publish_state, + "lb_changed"); + if (w->state != GRPC_CHANNEL_FATAL_FAILURE) { + watch_lb_policy(exec_ctx, w->chand, w->lb_policy, w->state); + } +} + +static void on_lb_policy_state_changed(grpc_exec_ctx *exec_ctx, void *arg, + bool iomgr_success) { + lb_policy_connectivity_watcher *w = arg; + + gpr_mu_lock(&w->chand->mu_config); + on_lb_policy_state_changed_locked(exec_ctx, w); + gpr_mu_unlock(&w->chand->mu_config); + + GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack, "watch_lb_policy"); + gpr_free(w); +} + +static void watch_lb_policy(grpc_exec_ctx *exec_ctx, channel_data *chand, + grpc_lb_policy *lb_policy, + grpc_connectivity_state current_state) { + lb_policy_connectivity_watcher *w = gpr_malloc(sizeof(*w)); + GRPC_CHANNEL_STACK_REF(chand->owning_stack, "watch_lb_policy"); + + w->chand = chand; + grpc_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(exec_ctx, lb_policy, &w->state, + &w->on_changed); +} + +static void cc_on_config_changed(grpc_exec_ctx *exec_ctx, void *arg, + bool iomgr_success) { + channel_data *chand = arg; + grpc_lb_policy *lb_policy = NULL; + grpc_lb_policy *old_lb_policy; + grpc_connectivity_state state = GRPC_CHANNEL_TRANSIENT_FAILURE; + int exit_idle = 0; + + if (chand->incoming_configuration != NULL) { + lb_policy = grpc_client_config_get_lb_policy(chand->incoming_configuration); + if (lb_policy != NULL) { + GRPC_LB_POLICY_REF(lb_policy, "channel"); + GRPC_LB_POLICY_REF(lb_policy, "config_change"); + state = grpc_lb_policy_check_connectivity(exec_ctx, lb_policy); + } + + grpc_client_config_unref(exec_ctx, chand->incoming_configuration); + } + + chand->incoming_configuration = NULL; + + if (lb_policy != NULL) { + grpc_pollset_set_add_pollset_set(exec_ctx, lb_policy->interested_parties, + chand->interested_parties); + } + + gpr_mu_lock(&chand->mu_config); + old_lb_policy = chand->lb_policy; + chand->lb_policy = lb_policy; + if (lb_policy != NULL || chand->resolver == NULL /* disconnected */) { + grpc_exec_ctx_enqueue_list(exec_ctx, &chand->waiting_for_config_closures, + NULL); + } + if (lb_policy != NULL && chand->exit_idle_when_lb_policy_arrives) { + GRPC_LB_POLICY_REF(lb_policy, "exit_idle"); + exit_idle = 1; + chand->exit_idle_when_lb_policy_arrives = 0; + } + + if (iomgr_success && chand->resolver) { + grpc_connectivity_state_set(exec_ctx, &chand->state_tracker, state, + "new_lb+resolver"); + if (lb_policy != NULL) { + watch_lb_policy(exec_ctx, chand, lb_policy, state); + } + GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver"); + grpc_resolver_next(exec_ctx, chand->resolver, + &chand->incoming_configuration, + &chand->on_config_changed); + gpr_mu_unlock(&chand->mu_config); + } else { + if (chand->resolver != NULL) { + grpc_resolver_shutdown(exec_ctx, chand->resolver); + GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel"); + chand->resolver = NULL; + } + grpc_connectivity_state_set(exec_ctx, &chand->state_tracker, + GRPC_CHANNEL_FATAL_FAILURE, "resolver_gone"); + gpr_mu_unlock(&chand->mu_config); + } + + if (exit_idle) { + grpc_lb_policy_exit_idle(exec_ctx, lb_policy); + GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "exit_idle"); + } + + if (old_lb_policy != NULL) { + grpc_pollset_set_del_pollset_set( + exec_ctx, old_lb_policy->interested_parties, chand->interested_parties); + GRPC_LB_POLICY_UNREF(exec_ctx, old_lb_policy, "channel"); + } + + if (lb_policy != NULL) { + GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "config_change"); + } + + GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->owning_stack, "resolver"); +} + +static void cc_start_transport_op(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem, + grpc_transport_op *op) { + channel_data *chand = elem->channel_data; + + grpc_exec_ctx_enqueue(exec_ctx, op->on_consumed, true, NULL); + + GPR_ASSERT(op->set_accept_stream == false); + if (op->bind_pollset != NULL) { + grpc_pollset_set_add_pollset(exec_ctx, chand->interested_parties, + op->bind_pollset); + } + + gpr_mu_lock(&chand->mu_config); + if (op->on_connectivity_state_change != NULL) { + grpc_connectivity_state_notify_on_state_change( + exec_ctx, &chand->state_tracker, op->connectivity_state, + op->on_connectivity_state_change); + op->on_connectivity_state_change = NULL; + op->connectivity_state = NULL; + } + + if (op->send_ping != NULL) { + if (chand->lb_policy == NULL) { + grpc_exec_ctx_enqueue(exec_ctx, op->send_ping, false, NULL); + } else { + grpc_lb_policy_ping_one(exec_ctx, chand->lb_policy, op->send_ping); + op->bind_pollset = NULL; + } + op->send_ping = NULL; + } + + if (op->disconnect && chand->resolver != NULL) { + grpc_connectivity_state_set(exec_ctx, &chand->state_tracker, + GRPC_CHANNEL_FATAL_FAILURE, "disconnect"); + grpc_resolver_shutdown(exec_ctx, chand->resolver); + GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel"); + chand->resolver = NULL; + if (chand->lb_policy != NULL) { + grpc_pollset_set_del_pollset_set(exec_ctx, + chand->lb_policy->interested_parties, + chand->interested_parties); + GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel"); + chand->lb_policy = NULL; + } + } + gpr_mu_unlock(&chand->mu_config); +} + +typedef struct { + grpc_metadata_batch *initial_metadata; + grpc_connected_subchannel **connected_subchannel; + grpc_closure *on_ready; + grpc_call_element *elem; + grpc_closure closure; +} continue_picking_args; + +static int cc_pick_subchannel(grpc_exec_ctx *exec_ctx, void *arg, + grpc_metadata_batch *initial_metadata, + grpc_connected_subchannel **connected_subchannel, + grpc_closure *on_ready); + +static void continue_picking(grpc_exec_ctx *exec_ctx, void *arg, bool success) { + continue_picking_args *cpa = arg; + if (!success) { + grpc_exec_ctx_enqueue(exec_ctx, cpa->on_ready, false, NULL); + } else if (cpa->connected_subchannel == NULL) { + /* cancelled, do nothing */ + } else if (cc_pick_subchannel(exec_ctx, cpa->elem, cpa->initial_metadata, + cpa->connected_subchannel, cpa->on_ready)) { + grpc_exec_ctx_enqueue(exec_ctx, cpa->on_ready, true, NULL); + } + gpr_free(cpa); +} + +static int cc_pick_subchannel(grpc_exec_ctx *exec_ctx, void *elemp, + grpc_metadata_batch *initial_metadata, + grpc_connected_subchannel **connected_subchannel, + grpc_closure *on_ready) { + grpc_call_element *elem = elemp; + channel_data *chand = elem->channel_data; + call_data *calld = elem->call_data; + continue_picking_args *cpa; + grpc_closure *closure; + + GPR_ASSERT(connected_subchannel); + + gpr_mu_lock(&chand->mu_config); + if (initial_metadata == NULL) { + if (chand->lb_policy != NULL) { + grpc_lb_policy_cancel_pick(exec_ctx, chand->lb_policy, + connected_subchannel); + } + for (closure = chand->waiting_for_config_closures.head; closure != NULL; + closure = grpc_closure_next(closure)) { + cpa = closure->cb_arg; + if (cpa->connected_subchannel == connected_subchannel) { + cpa->connected_subchannel = NULL; + grpc_exec_ctx_enqueue(exec_ctx, cpa->on_ready, false, NULL); + } + } + gpr_mu_unlock(&chand->mu_config); + return 1; + } + if (chand->lb_policy != NULL) { + grpc_lb_policy *lb_policy = chand->lb_policy; + int r; + GRPC_LB_POLICY_REF(lb_policy, "cc_pick_subchannel"); + gpr_mu_unlock(&chand->mu_config); + r = grpc_lb_policy_pick(exec_ctx, lb_policy, calld->pollset, + initial_metadata, connected_subchannel, on_ready); + GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "cc_pick_subchannel"); + return r; + } + if (chand->resolver != NULL && !chand->started_resolving) { + chand->started_resolving = 1; + GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver"); + grpc_resolver_next(exec_ctx, chand->resolver, + &chand->incoming_configuration, + &chand->on_config_changed); + } + cpa = gpr_malloc(sizeof(*cpa)); + cpa->initial_metadata = initial_metadata; + cpa->connected_subchannel = connected_subchannel; + cpa->on_ready = on_ready; + cpa->elem = elem; + grpc_closure_init(&cpa->closure, continue_picking, cpa); + grpc_closure_list_add(&chand->waiting_for_config_closures, &cpa->closure, 1); + gpr_mu_unlock(&chand->mu_config); + return 0; +} + +/* Constructor for call_data */ +static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + grpc_call_element_args *args) { + grpc_subchannel_call_holder_init(elem->call_data, cc_pick_subchannel, elem, + args->call_stack); +} + +/* Destructor for call_data */ +static void destroy_call_elem(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem) { + grpc_subchannel_call_holder_destroy(exec_ctx, elem->call_data); +} + +/* Constructor for channel_data */ +static void init_channel_elem(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem, + grpc_channel_element_args *args) { + channel_data *chand = elem->channel_data; + + memset(chand, 0, sizeof(*chand)); + + GPR_ASSERT(args->is_last); + GPR_ASSERT(elem->filter == &grpc_client_channel_filter); + + gpr_mu_init(&chand->mu_config); + grpc_closure_init(&chand->on_config_changed, cc_on_config_changed, chand); + chand->owning_stack = args->channel_stack; + + grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE, + "client_channel"); + chand->interested_parties = grpc_pollset_set_create(); +} + +/* Destructor for channel_data */ +static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem) { + channel_data *chand = elem->channel_data; + + if (chand->resolver != NULL) { + grpc_resolver_shutdown(exec_ctx, chand->resolver); + GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel"); + } + if (chand->lb_policy != NULL) { + grpc_pollset_set_del_pollset_set(exec_ctx, + chand->lb_policy->interested_parties, + chand->interested_parties); + GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel"); + } + grpc_connectivity_state_destroy(exec_ctx, &chand->state_tracker); + grpc_pollset_set_destroy(chand->interested_parties); + gpr_mu_destroy(&chand->mu_config); +} + +static void cc_set_pollset(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + grpc_pollset *pollset) { + call_data *calld = elem->call_data; + calld->pollset = pollset; +} + +const grpc_channel_filter grpc_client_channel_filter = { + cc_start_transport_stream_op, + cc_start_transport_op, + sizeof(call_data), + init_call_elem, + cc_set_pollset, + destroy_call_elem, + sizeof(channel_data), + init_channel_elem, + destroy_channel_elem, + cc_get_peer, + "client-channel", +}; + +void grpc_client_channel_set_resolver(grpc_exec_ctx *exec_ctx, + grpc_channel_stack *channel_stack, + grpc_resolver *resolver) { + /* post construction initialization: set the transport setup pointer */ + grpc_channel_element *elem = grpc_channel_stack_last_element(channel_stack); + channel_data *chand = elem->channel_data; + gpr_mu_lock(&chand->mu_config); + GPR_ASSERT(!chand->resolver); + chand->resolver = resolver; + GRPC_RESOLVER_REF(resolver, "channel"); + if (!grpc_closure_list_empty(chand->waiting_for_config_closures) || + chand->exit_idle_when_lb_policy_arrives) { + chand->started_resolving = 1; + GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver"); + grpc_resolver_next(exec_ctx, resolver, &chand->incoming_configuration, + &chand->on_config_changed); + } + gpr_mu_unlock(&chand->mu_config); +} + +grpc_connectivity_state grpc_client_channel_check_connectivity_state( + grpc_exec_ctx *exec_ctx, 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(exec_ctx, chand->lb_policy); + } else { + chand->exit_idle_when_lb_policy_arrives = 1; + if (!chand->started_resolving && chand->resolver != NULL) { + GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver"); + chand->started_resolving = 1; + grpc_resolver_next(exec_ctx, chand->resolver, + &chand->incoming_configuration, + &chand->on_config_changed); + } + } + } + gpr_mu_unlock(&chand->mu_config); + return out; +} + +typedef struct { + channel_data *chand; + grpc_pollset *pollset; + grpc_closure *on_complete; + grpc_closure my_closure; +} external_connectivity_watcher; + +static void on_external_watch_complete(grpc_exec_ctx *exec_ctx, void *arg, + bool iomgr_success) { + external_connectivity_watcher *w = arg; + grpc_closure *follow_up = w->on_complete; + grpc_pollset_set_del_pollset(exec_ctx, w->chand->interested_parties, + w->pollset); + GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack, + "external_connectivity_watcher"); + gpr_free(w); + follow_up->cb(exec_ctx, follow_up->cb_arg, iomgr_success); +} + +void grpc_client_channel_watch_connectivity_state( + grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_pollset *pollset, + grpc_connectivity_state *state, grpc_closure *on_complete) { + channel_data *chand = elem->channel_data; + external_connectivity_watcher *w = gpr_malloc(sizeof(*w)); + w->chand = chand; + w->pollset = pollset; + w->on_complete = on_complete; + grpc_pollset_set_add_pollset(exec_ctx, chand->interested_parties, pollset); + grpc_closure_init(&w->my_closure, on_external_watch_complete, w); + GRPC_CHANNEL_STACK_REF(w->chand->owning_stack, + "external_connectivity_watcher"); + gpr_mu_lock(&chand->mu_config); + grpc_connectivity_state_notify_on_state_change( + exec_ctx, &chand->state_tracker, state, &w->my_closure); + gpr_mu_unlock(&chand->mu_config); +} diff --git a/src/core/lib/channel/client_channel.h b/src/core/lib/channel/client_channel.h new file mode 100644 index 0000000000..422f7f8374 --- /dev/null +++ b/src/core/lib/channel/client_channel.h @@ -0,0 +1,63 @@ +/* + * + * Copyright 2015-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_CHANNEL_CLIENT_CHANNEL_H +#define GRPC_CORE_CHANNEL_CLIENT_CHANNEL_H + +#include "src/core/channel/channel_stack.h" +#include "src/core/client_config/resolver.h" + +/* A client channel is a channel that begins disconnected, and can connect + to some endpoint on demand. If that endpoint disconnects, it will be + connected to again later. + + Calls on a disconnected client channel are queued until a connection is + established. */ + +extern const grpc_channel_filter grpc_client_channel_filter; + +/* post-construction initializer to let the client channel know which + transport setup it should cancel upon destruction, or initiate when it needs + a connection */ +void grpc_client_channel_set_resolver(grpc_exec_ctx *exec_ctx, + grpc_channel_stack *channel_stack, + grpc_resolver *resolver); + +grpc_connectivity_state grpc_client_channel_check_connectivity_state( + grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, int try_to_connect); + +void grpc_client_channel_watch_connectivity_state( + grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_pollset *pollset, + grpc_connectivity_state *state, grpc_closure *on_complete); + +#endif /* GRPC_CORE_CHANNEL_CLIENT_CHANNEL_H */ diff --git a/src/core/lib/channel/compress_filter.c b/src/core/lib/channel/compress_filter.c new file mode 100644 index 0000000000..6f5a9740ad --- /dev/null +++ b/src/core/lib/channel/compress_filter.c @@ -0,0 +1,304 @@ +/* + * + * Copyright 2015-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 +#include + +#include +#include +#include +#include + +#include "src/core/channel/channel_args.h" +#include "src/core/channel/compress_filter.h" +#include "src/core/compression/algorithm_metadata.h" +#include "src/core/compression/message_compress.h" +#include "src/core/profiling/timers.h" +#include "src/core/support/string.h" +#include "src/core/transport/static_metadata.h" + +typedef struct call_data { + gpr_slice_buffer slices; /**< Buffers up input slices to be compressed */ + grpc_linked_mdelem compression_algorithm_storage; + grpc_linked_mdelem accept_encoding_storage; + uint32_t remaining_slice_bytes; + /** Compression algorithm we'll try to use. It may be given by incoming + * metadata, or by the channel's default compression settings. */ + grpc_compression_algorithm compression_algorithm; + /** If true, contents of \a compression_algorithm are authoritative */ + int has_compression_algorithm; + + grpc_transport_stream_op send_op; + uint32_t send_length; + uint32_t send_flags; + gpr_slice incoming_slice; + grpc_slice_buffer_stream replacement_stream; + grpc_closure *post_send; + grpc_closure send_done; + grpc_closure got_slice; +} 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; + /** Supported compression algorithms */ + uint32_t supported_compression_algorithms; +} channel_data; + +/** For each \a md element from the incoming metadata, filter out the entry for + * "grpc-encoding", using its value to populate the call data's + * compression_algorithm field. */ +static grpc_mdelem *compression_md_filter(void *user_data, grpc_mdelem *md) { + grpc_call_element *elem = user_data; + call_data *calld = elem->call_data; + channel_data *channeld = elem->channel_data; + + if (md->key == GRPC_MDSTR_GRPC_INTERNAL_ENCODING_REQUEST) { + const char *md_c_str = grpc_mdstr_as_c_string(md->value); + if (!grpc_compression_algorithm_parse(md_c_str, strlen(md_c_str), + &calld->compression_algorithm)) { + gpr_log(GPR_ERROR, + "Invalid compression algorithm: '%s' (unknown). Ignoring.", + md_c_str); + calld->compression_algorithm = GRPC_COMPRESS_NONE; + } + if (grpc_compression_options_is_algorithm_enabled( + &channeld->compression_options, calld->compression_algorithm) == + 0) { + gpr_log(GPR_ERROR, + "Invalid compression algorithm: '%s' (previously disabled). " + "Ignoring.", + md_c_str); + calld->compression_algorithm = GRPC_COMPRESS_NONE; + } + calld->has_compression_algorithm = 1; + return NULL; + } + + return md; +} + +static int skip_compression(grpc_call_element *elem) { + call_data *calld = elem->call_data; + channel_data *channeld = elem->channel_data; + if (calld->has_compression_algorithm) { + if (calld->compression_algorithm == GRPC_COMPRESS_NONE) { + return 1; + } + return 0; /* we have an actual call-specific algorithm */ + } + /* no per-call compression override */ + return channeld->default_compression_algorithm == GRPC_COMPRESS_NONE; +} + +/** Filter initial metadata */ +static void process_send_initial_metadata( + grpc_call_element *elem, grpc_metadata_batch *initial_metadata) { + call_data *calld = elem->call_data; + channel_data *channeld = elem->channel_data; + /* Parse incoming request for compression. If any, it'll be available + * at calld->compression_algorithm */ + grpc_metadata_batch_filter(initial_metadata, compression_md_filter, elem); + if (!calld->has_compression_algorithm) { + /* If no algorithm was found in the metadata and we aren't + * exceptionally skipping compression, fall back to the channel + * default */ + calld->compression_algorithm = channeld->default_compression_algorithm; + calld->has_compression_algorithm = 1; /* GPR_TRUE */ + } + /* hint compression algorithm */ + grpc_metadata_batch_add_tail( + initial_metadata, &calld->compression_algorithm_storage, + grpc_compression_encoding_mdelem(calld->compression_algorithm)); + + /* convey supported compression algorithms */ + grpc_metadata_batch_add_tail(initial_metadata, + &calld->accept_encoding_storage, + GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS( + channeld->supported_compression_algorithms)); +} + +static void continue_send_message(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem); + +static void send_done(grpc_exec_ctx *exec_ctx, void *elemp, bool success) { + grpc_call_element *elem = elemp; + call_data *calld = elem->call_data; + gpr_slice_buffer_reset_and_unref(&calld->slices); + calld->post_send->cb(exec_ctx, calld->post_send->cb_arg, success); +} + +static void finish_send_message(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem) { + call_data *calld = elem->call_data; + int did_compress; + gpr_slice_buffer tmp; + gpr_slice_buffer_init(&tmp); + did_compress = + grpc_msg_compress(calld->compression_algorithm, &calld->slices, &tmp); + if (did_compress) { + gpr_slice_buffer_swap(&calld->slices, &tmp); + calld->send_flags |= GRPC_WRITE_INTERNAL_COMPRESS; + } + gpr_slice_buffer_destroy(&tmp); + + grpc_slice_buffer_stream_init(&calld->replacement_stream, &calld->slices, + calld->send_flags); + calld->send_op.send_message = &calld->replacement_stream.base; + calld->post_send = calld->send_op.on_complete; + calld->send_op.on_complete = &calld->send_done; + + grpc_call_next_op(exec_ctx, elem, &calld->send_op); +} + +static void got_slice(grpc_exec_ctx *exec_ctx, void *elemp, bool success) { + grpc_call_element *elem = elemp; + call_data *calld = elem->call_data; + gpr_slice_buffer_add(&calld->slices, calld->incoming_slice); + if (calld->send_length == calld->slices.length) { + finish_send_message(exec_ctx, elem); + } else { + continue_send_message(exec_ctx, elem); + } +} + +static void continue_send_message(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem) { + call_data *calld = elem->call_data; + while (grpc_byte_stream_next(exec_ctx, calld->send_op.send_message, + &calld->incoming_slice, ~(size_t)0, + &calld->got_slice)) { + gpr_slice_buffer_add(&calld->slices, calld->incoming_slice); + if (calld->send_length == calld->slices.length) { + finish_send_message(exec_ctx, elem); + break; + } + } +} + +static void compress_start_transport_stream_op(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + grpc_transport_stream_op *op) { + call_data *calld = elem->call_data; + + GPR_TIMER_BEGIN("compress_start_transport_stream_op", 0); + + if (op->send_initial_metadata) { + process_send_initial_metadata(elem, op->send_initial_metadata); + } + if (op->send_message != NULL && !skip_compression(elem) && + 0 == (op->send_message->flags & GRPC_WRITE_NO_COMPRESS)) { + calld->send_op = *op; + calld->send_length = op->send_message->length; + calld->send_flags = op->send_message->flags; + continue_send_message(exec_ctx, elem); + } else { + /* pass control down the stack */ + grpc_call_next_op(exec_ctx, elem, op); + } + + GPR_TIMER_END("compress_start_transport_stream_op", 0); +} + +/* Constructor for call_data */ +static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + grpc_call_element_args *args) { + /* grab pointers to our data from the call element */ + call_data *calld = elem->call_data; + + /* initialize members */ + gpr_slice_buffer_init(&calld->slices); + calld->has_compression_algorithm = 0; + grpc_closure_init(&calld->got_slice, got_slice, elem); + grpc_closure_init(&calld->send_done, send_done, elem); +} + +/* Destructor for call_data */ +static void destroy_call_elem(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem) { + /* grab pointers to our data from the call element */ + call_data *calld = elem->call_data; + gpr_slice_buffer_destroy(&calld->slices); +} + +/* Constructor for channel_data */ +static void init_channel_elem(grpc_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->default_compression_algorithm = + grpc_channel_args_get_compression_algorithm(args->channel_args); + /* Make sure the default isn't disabled. */ + GPR_ASSERT(grpc_compression_options_is_algorithm_enabled( + &channeld->compression_options, channeld->default_compression_algorithm)); + 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) { + /* skip disabled algorithms */ + if (grpc_compression_options_is_algorithm_enabled( + &channeld->compression_options, algo_idx) == 0) { + continue; + } + channeld->supported_compression_algorithms |= 1u << algo_idx; + } + + GPR_ASSERT(!args->is_last); +} + +/* Destructor for channel data */ +static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem) {} + +const grpc_channel_filter grpc_compress_filter = { + compress_start_transport_stream_op, + grpc_channel_next_op, + sizeof(call_data), + init_call_elem, + grpc_call_stack_ignore_set_pollset, + destroy_call_elem, + sizeof(channel_data), + init_channel_elem, + destroy_channel_elem, + grpc_call_next_get_peer, + "compress"}; diff --git a/src/core/lib/channel/compress_filter.h b/src/core/lib/channel/compress_filter.h new file mode 100644 index 0000000000..8c208ac799 --- /dev/null +++ b/src/core/lib/channel/compress_filter.h @@ -0,0 +1,65 @@ +/* + * + * Copyright 2015-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_CHANNEL_COMPRESS_FILTER_H +#define GRPC_CORE_CHANNEL_COMPRESS_FILTER_H + +#include "src/core/channel/channel_stack.h" + +#define GRPC_COMPRESS_REQUEST_ALGORITHM_KEY "grpc-internal-encoding-request" + +/** Compression filter for outgoing data. + * + * See for the available compression settings. + * + * Compression settings may come from: + * - Channel configuration, as established at channel creation time. + * - The metadata accompanying the outgoing data to be compressed. This is + * taken as a request only. We may choose not to honor it. The metadata key + * is given by \a GRPC_COMPRESS_REQUEST_ALGORITHM_KEY. + * + * Compression can be disabled for concrete messages (for instance in order to + * prevent CRIME/BEAST type attacks) by having the GRPC_WRITE_NO_COMPRESS set in + * the BEGIN_MESSAGE flags. + * + * The attempted compression mechanism is added to the resulting initial + * metadata under the'grpc-encoding' key. + * + * If compression is actually performed, BEGIN_MESSAGE's flag is modified to + * incorporate GRPC_WRITE_INTERNAL_COMPRESS. Otherwise, and regardless of the + * aforementioned 'grpc-encoding' metadata value, data will pass through + * uncompressed. */ + +extern const grpc_channel_filter grpc_compress_filter; + +#endif /* GRPC_CORE_CHANNEL_COMPRESS_FILTER_H */ diff --git a/src/core/lib/channel/connected_channel.c b/src/core/lib/channel/connected_channel.c new file mode 100644 index 0000000000..df11d54297 --- /dev/null +++ b/src/core/lib/channel/connected_channel.c @@ -0,0 +1,176 @@ +/* + * + * Copyright 2015-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/channel/connected_channel.h" + +#include +#include +#include + +#include +#include +#include +#include +#include "src/core/profiling/timers.h" +#include "src/core/support/string.h" +#include "src/core/transport/transport.h" + +#define MAX_BUFFER_LENGTH 8192 + +typedef struct connected_channel_channel_data { + grpc_transport *transport; +} channel_data; + +typedef struct connected_channel_call_data { void *unused; } call_data; + +/* We perform a small hack to locate transport data alongside the connected + channel data in call allocations, to allow everything to be pulled in minimal + cache line requests */ +#define TRANSPORT_STREAM_FROM_CALL_DATA(calld) ((grpc_stream *)((calld) + 1)) +#define CALL_DATA_FROM_TRANSPORT_STREAM(transport_stream) \ + (((call_data *)(transport_stream)) - 1) + +/* Intercept a call operation and either push it directly up or translate it + into transport stream operations */ +static void con_start_transport_stream_op(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + grpc_transport_stream_op *op) { + call_data *calld = elem->call_data; + channel_data *chand = elem->channel_data; + GRPC_CALL_LOG_OP(GPR_INFO, elem, op); + + grpc_transport_perform_stream_op(exec_ctx, chand->transport, + TRANSPORT_STREAM_FROM_CALL_DATA(calld), op); +} + +static void con_start_transport_op(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem, + grpc_transport_op *op) { + channel_data *chand = elem->channel_data; + grpc_transport_perform_op(exec_ctx, chand->transport, op); +} + +/* Constructor for call_data */ +static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + grpc_call_element_args *args) { + call_data *calld = elem->call_data; + channel_data *chand = elem->channel_data; + int r; + + r = grpc_transport_init_stream( + exec_ctx, chand->transport, TRANSPORT_STREAM_FROM_CALL_DATA(calld), + &args->call_stack->refcount, args->server_transport_data); + GPR_ASSERT(r == 0); +} + +static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + grpc_pollset *pollset) { + call_data *calld = elem->call_data; + channel_data *chand = elem->channel_data; + grpc_transport_set_pollset(exec_ctx, chand->transport, + TRANSPORT_STREAM_FROM_CALL_DATA(calld), pollset); +} + +/* Destructor for call_data */ +static void destroy_call_elem(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem) { + call_data *calld = elem->call_data; + channel_data *chand = elem->channel_data; + grpc_transport_destroy_stream(exec_ctx, chand->transport, + TRANSPORT_STREAM_FROM_CALL_DATA(calld)); +} + +/* Constructor for channel_data */ +static void init_channel_elem(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem, + grpc_channel_element_args *args) { + channel_data *cd = (channel_data *)elem->channel_data; + GPR_ASSERT(args->is_last); + cd->transport = NULL; +} + +/* Destructor for channel_data */ +static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem) { + channel_data *cd = (channel_data *)elem->channel_data; + grpc_transport_destroy(exec_ctx, cd->transport); +} + +static char *con_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) { + channel_data *chand = elem->channel_data; + return grpc_transport_get_peer(exec_ctx, chand->transport); +} + +static const grpc_channel_filter connected_channel_filter = { + con_start_transport_stream_op, + con_start_transport_op, + sizeof(call_data), + init_call_elem, + set_pollset, + destroy_call_elem, + sizeof(channel_data), + init_channel_elem, + destroy_channel_elem, + con_get_peer, + "connected", +}; + +static void bind_transport(grpc_channel_stack *channel_stack, + grpc_channel_element *elem, void *t) { + channel_data *cd = (channel_data *)elem->channel_data; + GPR_ASSERT(elem->filter == &connected_channel_filter); + GPR_ASSERT(cd->transport == NULL); + cd->transport = t; + + /* HACK(ctiller): increase call stack size for the channel to make space + for channel data. We need a cleaner (but performant) way to do this, + and I'm not sure what that is yet. + This is only "safe" because call stacks place no additional data after + the last call element, and the last call element MUST be the connected + channel. */ + channel_stack->call_stack_size += grpc_transport_stream_size(t); +} + +bool grpc_add_connected_filter(grpc_channel_stack_builder *builder, + void *arg_must_be_null) { + GPR_ASSERT(arg_must_be_null == NULL); + grpc_transport *t = grpc_channel_stack_builder_get_transport(builder); + GPR_ASSERT(t != NULL); + return grpc_channel_stack_builder_append_filter( + builder, &connected_channel_filter, bind_transport, t); +} + +grpc_stream *grpc_connected_channel_get_stream(grpc_call_element *elem) { + call_data *calld = elem->call_data; + return TRANSPORT_STREAM_FROM_CALL_DATA(calld); +} diff --git a/src/core/lib/channel/connected_channel.h b/src/core/lib/channel/connected_channel.h new file mode 100644 index 0000000000..7c0c8359a4 --- /dev/null +++ b/src/core/lib/channel/connected_channel.h @@ -0,0 +1,42 @@ +/* + * + * Copyright 2015-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_CHANNEL_CONNECTED_CHANNEL_H +#define GRPC_CORE_CHANNEL_CONNECTED_CHANNEL_H + +#include "src/core/channel/channel_stack_builder.h" + +bool grpc_add_connected_filter(grpc_channel_stack_builder *builder, + void *arg_must_be_null); + +#endif /* GRPC_CORE_CHANNEL_CONNECTED_CHANNEL_H */ diff --git a/src/core/lib/channel/context.h b/src/core/lib/channel/context.h new file mode 100644 index 0000000000..db217dc133 --- /dev/null +++ b/src/core/lib/channel/context.h @@ -0,0 +1,49 @@ +/* + * + * Copyright 2015-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_CHANNEL_CONTEXT_H +#define GRPC_CORE_CHANNEL_CONTEXT_H + +/* Call object context pointers */ +typedef enum { + GRPC_CONTEXT_SECURITY = 0, + GRPC_CONTEXT_TRACING, + GRPC_CONTEXT_COUNT +} grpc_context_index; + +typedef struct { + void *value; + void (*destroy)(void *); +} grpc_call_context_element; + +#endif /* GRPC_CORE_CHANNEL_CONTEXT_H */ diff --git a/src/core/lib/channel/http_client_filter.c b/src/core/lib/channel/http_client_filter.c new file mode 100644 index 0000000000..582427daf9 --- /dev/null +++ b/src/core/lib/channel/http_client_filter.c @@ -0,0 +1,255 @@ +/* + * Copyright 2015-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/channel/http_client_filter.h" +#include +#include +#include +#include +#include "src/core/profiling/timers.h" +#include "src/core/support/string.h" +#include "src/core/transport/static_metadata.h" + +typedef struct call_data { + grpc_linked_mdelem method; + grpc_linked_mdelem scheme; + grpc_linked_mdelem authority; + grpc_linked_mdelem te_trailers; + grpc_linked_mdelem content_type; + grpc_linked_mdelem user_agent; + + grpc_metadata_batch *recv_initial_metadata; + + /** Closure to call when finished with the hc_on_recv hook */ + grpc_closure *on_done_recv; + /** Receive closures are chained: we inject this closure as the on_done_recv + up-call on transport_op, and remember to call our on_done_recv member + after handling it. */ + grpc_closure hc_on_recv; +} call_data; + +typedef struct channel_data { + grpc_mdelem *static_scheme; + grpc_mdelem *user_agent; +} channel_data; + +typedef struct { + grpc_call_element *elem; + grpc_exec_ctx *exec_ctx; +} client_recv_filter_args; + +static grpc_mdelem *client_recv_filter(void *user_data, grpc_mdelem *md) { + client_recv_filter_args *a = user_data; + if (md == GRPC_MDELEM_STATUS_200) { + return NULL; + } else if (md->key == GRPC_MDSTR_STATUS) { + grpc_call_element_send_cancel(a->exec_ctx, a->elem); + return NULL; + } else if (md->key == GRPC_MDSTR_CONTENT_TYPE) { + return NULL; + } + return md; +} + +static void hc_on_recv(grpc_exec_ctx *exec_ctx, void *user_data, bool success) { + grpc_call_element *elem = user_data; + call_data *calld = elem->call_data; + client_recv_filter_args a; + a.elem = elem; + a.exec_ctx = exec_ctx; + grpc_metadata_batch_filter(calld->recv_initial_metadata, client_recv_filter, + &a); + calld->on_done_recv->cb(exec_ctx, calld->on_done_recv->cb_arg, success); +} + +static grpc_mdelem *client_strip_filter(void *user_data, grpc_mdelem *md) { + /* eat the things we'd like to set ourselves */ + if (md->key == GRPC_MDSTR_METHOD) return NULL; + if (md->key == GRPC_MDSTR_SCHEME) return NULL; + if (md->key == GRPC_MDSTR_TE) return NULL; + if (md->key == GRPC_MDSTR_CONTENT_TYPE) return NULL; + if (md->key == GRPC_MDSTR_USER_AGENT) return NULL; + return md; +} + +static void hc_mutate_op(grpc_call_element *elem, + grpc_transport_stream_op *op) { + /* grab pointers to our data from the call element */ + call_data *calld = elem->call_data; + channel_data *channeld = elem->channel_data; + if (op->send_initial_metadata != NULL) { + grpc_metadata_batch_filter(op->send_initial_metadata, client_strip_filter, + elem); + /* Send : prefixed headers, which have to be before any application + layer headers. */ + grpc_metadata_batch_add_head(op->send_initial_metadata, &calld->method, + GRPC_MDELEM_METHOD_POST); + grpc_metadata_batch_add_head(op->send_initial_metadata, &calld->scheme, + channeld->static_scheme); + grpc_metadata_batch_add_tail(op->send_initial_metadata, &calld->te_trailers, + GRPC_MDELEM_TE_TRAILERS); + grpc_metadata_batch_add_tail( + op->send_initial_metadata, &calld->content_type, + GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC); + grpc_metadata_batch_add_tail(op->send_initial_metadata, &calld->user_agent, + GRPC_MDELEM_REF(channeld->user_agent)); + } + + if (op->recv_initial_metadata != NULL) { + /* substitute our callback for the higher callback */ + calld->recv_initial_metadata = op->recv_initial_metadata; + calld->on_done_recv = op->recv_initial_metadata_ready; + op->recv_initial_metadata_ready = &calld->hc_on_recv; + } +} + +static void hc_start_transport_op(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + grpc_transport_stream_op *op) { + GPR_TIMER_BEGIN("hc_start_transport_op", 0); + GRPC_CALL_LOG_OP(GPR_INFO, elem, op); + hc_mutate_op(elem, op); + GPR_TIMER_END("hc_start_transport_op", 0); + grpc_call_next_op(exec_ctx, elem, op); +} + +/* Constructor for call_data */ +static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + grpc_call_element_args *args) { + call_data *calld = elem->call_data; + calld->on_done_recv = NULL; + grpc_closure_init(&calld->hc_on_recv, hc_on_recv, elem); +} + +/* Destructor for call_data */ +static void destroy_call_elem(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem) {} + +static grpc_mdelem *scheme_from_args(const grpc_channel_args *args) { + unsigned i; + size_t j; + grpc_mdelem *valid_schemes[] = {GRPC_MDELEM_SCHEME_HTTP, + GRPC_MDELEM_SCHEME_HTTPS}; + if (args != NULL) { + for (i = 0; i < args->num_args; ++i) { + if (args->args[i].type == GRPC_ARG_STRING && + strcmp(args->args[i].key, GRPC_ARG_HTTP2_SCHEME) == 0) { + for (j = 0; j < GPR_ARRAY_SIZE(valid_schemes); j++) { + if (0 == strcmp(grpc_mdstr_as_c_string(valid_schemes[j]->value), + args->args[i].value.string)) { + return valid_schemes[j]; + } + } + } + } + } + return GRPC_MDELEM_SCHEME_HTTP; +} + +static grpc_mdstr *user_agent_from_args(const grpc_channel_args *args) { + gpr_strvec v; + size_t i; + int is_first = 1; + char *tmp; + grpc_mdstr *result; + + gpr_strvec_init(&v); + + for (i = 0; args && i < args->num_args; i++) { + if (0 == strcmp(args->args[i].key, GRPC_ARG_PRIMARY_USER_AGENT_STRING)) { + if (args->args[i].type != GRPC_ARG_STRING) { + gpr_log(GPR_ERROR, "Channel argument '%s' should be a string", + GRPC_ARG_PRIMARY_USER_AGENT_STRING); + } else { + if (!is_first) gpr_strvec_add(&v, gpr_strdup(" ")); + is_first = 0; + gpr_strvec_add(&v, gpr_strdup(args->args[i].value.string)); + } + } + } + + gpr_asprintf(&tmp, "%sgrpc-c/%s (%s)", is_first ? "" : " ", + grpc_version_string(), GPR_PLATFORM_STRING); + is_first = 0; + gpr_strvec_add(&v, tmp); + + for (i = 0; args && i < args->num_args; i++) { + if (0 == strcmp(args->args[i].key, GRPC_ARG_SECONDARY_USER_AGENT_STRING)) { + if (args->args[i].type != GRPC_ARG_STRING) { + gpr_log(GPR_ERROR, "Channel argument '%s' should be a string", + GRPC_ARG_SECONDARY_USER_AGENT_STRING); + } else { + if (!is_first) gpr_strvec_add(&v, gpr_strdup(" ")); + is_first = 0; + gpr_strvec_add(&v, gpr_strdup(args->args[i].value.string)); + } + } + } + + tmp = gpr_strvec_flatten(&v, NULL); + gpr_strvec_destroy(&v); + result = grpc_mdstr_from_string(tmp); + gpr_free(tmp); + + return result; +} + +/* Constructor for channel_data */ +static void init_channel_elem(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem, + grpc_channel_element_args *args) { + channel_data *chand = elem->channel_data; + GPR_ASSERT(!args->is_last); + 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)); +} + +/* Destructor for channel data */ +static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem) { + channel_data *chand = elem->channel_data; + GRPC_MDELEM_UNREF(chand->user_agent); +} + +const grpc_channel_filter grpc_http_client_filter = { + hc_start_transport_op, + grpc_channel_next_op, + sizeof(call_data), + init_call_elem, + grpc_call_stack_ignore_set_pollset, + destroy_call_elem, + sizeof(channel_data), + init_channel_elem, + destroy_channel_elem, + grpc_call_next_get_peer, + "http-client"}; diff --git a/src/core/lib/channel/http_client_filter.h b/src/core/lib/channel/http_client_filter.h new file mode 100644 index 0000000000..6f619bbf00 --- /dev/null +++ b/src/core/lib/channel/http_client_filter.h @@ -0,0 +1,44 @@ +/* + * + * Copyright 2015-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_CHANNEL_HTTP_CLIENT_FILTER_H +#define GRPC_CORE_CHANNEL_HTTP_CLIENT_FILTER_H + +#include "src/core/channel/channel_stack.h" + +/* Processes metadata on the client side for HTTP2 transports */ +extern const grpc_channel_filter grpc_http_client_filter; + +#define GRPC_ARG_HTTP2_SCHEME "grpc.http2_scheme" + +#endif /* GRPC_CORE_CHANNEL_HTTP_CLIENT_FILTER_H */ diff --git a/src/core/lib/channel/http_server_filter.c b/src/core/lib/channel/http_server_filter.c new file mode 100644 index 0000000000..1a2e0c5db3 --- /dev/null +++ b/src/core/lib/channel/http_server_filter.c @@ -0,0 +1,240 @@ +/* + * + * Copyright 2015-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/channel/http_server_filter.h" + +#include +#include +#include +#include "src/core/profiling/timers.h" +#include "src/core/transport/static_metadata.h" + +typedef struct call_data { + uint8_t seen_path; + uint8_t seen_post; + uint8_t sent_status; + uint8_t seen_scheme; + uint8_t seen_te_trailers; + uint8_t seen_authority; + grpc_linked_mdelem status; + grpc_linked_mdelem content_type; + + grpc_metadata_batch *recv_initial_metadata; + /** Closure to call when finished with the hs_on_recv hook */ + grpc_closure *on_done_recv; + /** Receive closures are chained: we inject this closure as the on_done_recv + up-call on transport_op, and remember to call our on_done_recv member + after handling it. */ + grpc_closure hs_on_recv; +} call_data; + +typedef struct channel_data { uint8_t unused; } channel_data; + +typedef struct { + grpc_call_element *elem; + grpc_exec_ctx *exec_ctx; +} server_filter_args; + +static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) { + server_filter_args *a = user_data; + grpc_call_element *elem = a->elem; + call_data *calld = elem->call_data; + + /* Check if it is one of the headers we care about. */ + if (md == GRPC_MDELEM_TE_TRAILERS || md == GRPC_MDELEM_METHOD_POST || + md == GRPC_MDELEM_SCHEME_HTTP || md == GRPC_MDELEM_SCHEME_HTTPS || + md == GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC) { + /* swallow it */ + if (md == GRPC_MDELEM_METHOD_POST) { + calld->seen_post = 1; + } else if (md->key == GRPC_MDSTR_SCHEME) { + calld->seen_scheme = 1; + } else if (md == GRPC_MDELEM_TE_TRAILERS) { + calld->seen_te_trailers = 1; + } + /* TODO(klempner): Track that we've seen all the headers we should + require */ + return NULL; + } else if (md->key == GRPC_MDSTR_CONTENT_TYPE) { + if (strncmp(grpc_mdstr_as_c_string(md->value), "application/grpc+", 17) == + 0) { + /* Although the C implementation doesn't (currently) generate them, + any custom +-suffix is explicitly valid. */ + /* TODO(klempner): We should consider preallocating common values such + as +proto or +json, or at least stashing them if we see them. */ + /* TODO(klempner): Should we be surfacing this to application code? */ + } else { + /* TODO(klempner): We're currently allowing this, but we shouldn't + see it without a proxy so log for now. */ + gpr_log(GPR_INFO, "Unexpected content-type %s", + grpc_mdstr_as_c_string(md->value)); + } + return NULL; + } else if (md->key == GRPC_MDSTR_TE || md->key == GRPC_MDSTR_METHOD || + md->key == GRPC_MDSTR_SCHEME) { + gpr_log(GPR_ERROR, "Invalid %s: header: '%s'", + grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value)); + /* swallow it and error everything out. */ + /* TODO(klempner): We ought to generate more descriptive error messages + on the wire here. */ + grpc_call_element_send_cancel(a->exec_ctx, elem); + return NULL; + } else if (md->key == GRPC_MDSTR_PATH) { + if (calld->seen_path) { + gpr_log(GPR_ERROR, "Received :path twice"); + return NULL; + } + calld->seen_path = 1; + return md; + } else if (md->key == GRPC_MDSTR_AUTHORITY) { + calld->seen_authority = 1; + return md; + } else if (md->key == GRPC_MDSTR_HOST) { + /* translate host to :authority since :authority may be + omitted */ + grpc_mdelem *authority = grpc_mdelem_from_metadata_strings( + GRPC_MDSTR_AUTHORITY, GRPC_MDSTR_REF(md->value)); + calld->seen_authority = 1; + return authority; + } else { + return md; + } +} + +static void hs_on_recv(grpc_exec_ctx *exec_ctx, void *user_data, bool success) { + grpc_call_element *elem = user_data; + call_data *calld = elem->call_data; + if (success) { + server_filter_args a; + a.elem = elem; + a.exec_ctx = exec_ctx; + grpc_metadata_batch_filter(calld->recv_initial_metadata, server_filter, &a); + /* Have we seen the required http2 transport headers? + (:method, :scheme, content-type, with :path and :authority covered + at the channel level right now) */ + if (calld->seen_post && calld->seen_scheme && calld->seen_te_trailers && + calld->seen_path && calld->seen_authority) { + /* do nothing */ + } else { + if (!calld->seen_path) { + gpr_log(GPR_ERROR, "Missing :path header"); + } + if (!calld->seen_authority) { + gpr_log(GPR_ERROR, "Missing :authority header"); + } + if (!calld->seen_post) { + gpr_log(GPR_ERROR, "Missing :method header"); + } + if (!calld->seen_scheme) { + gpr_log(GPR_ERROR, "Missing :scheme header"); + } + if (!calld->seen_te_trailers) { + gpr_log(GPR_ERROR, "Missing te trailers header"); + } + /* Error this call out */ + success = 0; + grpc_call_element_send_cancel(exec_ctx, elem); + } + } + calld->on_done_recv->cb(exec_ctx, calld->on_done_recv->cb_arg, success); +} + +static void hs_mutate_op(grpc_call_element *elem, + grpc_transport_stream_op *op) { + /* grab pointers to our data from the call element */ + call_data *calld = elem->call_data; + + if (op->send_initial_metadata != NULL && !calld->sent_status) { + calld->sent_status = 1; + grpc_metadata_batch_add_head(op->send_initial_metadata, &calld->status, + GRPC_MDELEM_STATUS_200); + grpc_metadata_batch_add_tail( + op->send_initial_metadata, &calld->content_type, + GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC); + } + + if (op->recv_initial_metadata) { + /* substitute our callback for the higher callback */ + calld->recv_initial_metadata = op->recv_initial_metadata; + calld->on_done_recv = op->recv_initial_metadata_ready; + op->recv_initial_metadata_ready = &calld->hs_on_recv; + } +} + +static void hs_start_transport_op(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + grpc_transport_stream_op *op) { + GRPC_CALL_LOG_OP(GPR_INFO, elem, op); + GPR_TIMER_BEGIN("hs_start_transport_op", 0); + hs_mutate_op(elem, op); + grpc_call_next_op(exec_ctx, elem, op); + GPR_TIMER_END("hs_start_transport_op", 0); +} + +/* Constructor for call_data */ +static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + grpc_call_element_args *args) { + /* grab pointers to our data from the call element */ + call_data *calld = elem->call_data; + /* initialize members */ + memset(calld, 0, sizeof(*calld)); + grpc_closure_init(&calld->hs_on_recv, hs_on_recv, elem); +} + +/* Destructor for call_data */ +static void destroy_call_elem(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem) {} + +/* Constructor for channel_data */ +static void init_channel_elem(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem, + grpc_channel_element_args *args) { + GPR_ASSERT(!args->is_last); +} + +/* Destructor for channel data */ +static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem) {} + +const grpc_channel_filter grpc_http_server_filter = { + hs_start_transport_op, + grpc_channel_next_op, + sizeof(call_data), + init_call_elem, + grpc_call_stack_ignore_set_pollset, + destroy_call_elem, + sizeof(channel_data), + init_channel_elem, + destroy_channel_elem, + grpc_call_next_get_peer, + "http-server"}; diff --git a/src/core/lib/channel/http_server_filter.h b/src/core/lib/channel/http_server_filter.h new file mode 100644 index 0000000000..528c8648fd --- /dev/null +++ b/src/core/lib/channel/http_server_filter.h @@ -0,0 +1,42 @@ +/* + * + * Copyright 2015-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_CHANNEL_HTTP_SERVER_FILTER_H +#define GRPC_CORE_CHANNEL_HTTP_SERVER_FILTER_H + +#include "src/core/channel/channel_stack.h" + +/* Processes metadata on the client side for HTTP2 transports */ +extern const grpc_channel_filter grpc_http_server_filter; + +#endif /* GRPC_CORE_CHANNEL_HTTP_SERVER_FILTER_H */ diff --git a/src/core/lib/channel/subchannel_call_holder.c b/src/core/lib/channel/subchannel_call_holder.c new file mode 100644 index 0000000000..9c087dc2a1 --- /dev/null +++ b/src/core/lib/channel/subchannel_call_holder.c @@ -0,0 +1,259 @@ +/* + * + * Copyright 2015-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/channel/subchannel_call_holder.h" + +#include + +#include "src/core/profiling/timers.h" + +#define GET_CALL(holder) \ + ((grpc_subchannel_call *)(gpr_atm_acq_load(&(holder)->subchannel_call))) + +#define CANCELLED_CALL ((grpc_subchannel_call *)1) + +static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *holder, + bool success); +static void retry_ops(grpc_exec_ctx *exec_ctx, void *retry_ops_args, + bool success); + +static void add_waiting_locked(grpc_subchannel_call_holder *holder, + grpc_transport_stream_op *op); +static void fail_locked(grpc_exec_ctx *exec_ctx, + grpc_subchannel_call_holder *holder); +static void retry_waiting_locked(grpc_exec_ctx *exec_ctx, + grpc_subchannel_call_holder *holder); + +void grpc_subchannel_call_holder_init( + grpc_subchannel_call_holder *holder, + grpc_subchannel_call_holder_pick_subchannel pick_subchannel, + void *pick_subchannel_arg, grpc_call_stack *owning_call) { + gpr_atm_rel_store(&holder->subchannel_call, 0); + holder->pick_subchannel = pick_subchannel; + holder->pick_subchannel_arg = pick_subchannel_arg; + gpr_mu_init(&holder->mu); + holder->connected_subchannel = NULL; + holder->waiting_ops = NULL; + holder->waiting_ops_count = 0; + holder->waiting_ops_capacity = 0; + holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING; + holder->owning_call = owning_call; +} + +void grpc_subchannel_call_holder_destroy(grpc_exec_ctx *exec_ctx, + grpc_subchannel_call_holder *holder) { + grpc_subchannel_call *call = GET_CALL(holder); + if (call != NULL && call != CANCELLED_CALL) { + GRPC_SUBCHANNEL_CALL_UNREF(exec_ctx, call, "holder"); + } + GPR_ASSERT(holder->creation_phase == + GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING); + gpr_mu_destroy(&holder->mu); + GPR_ASSERT(holder->waiting_ops_count == 0); + gpr_free(holder->waiting_ops); +} + +void grpc_subchannel_call_holder_perform_op(grpc_exec_ctx *exec_ctx, + grpc_subchannel_call_holder *holder, + grpc_transport_stream_op *op) { + /* try to (atomically) get the call */ + grpc_subchannel_call *call = GET_CALL(holder); + GPR_TIMER_BEGIN("grpc_subchannel_call_holder_perform_op", 0); + if (call == CANCELLED_CALL) { + grpc_transport_stream_op_finish_with_failure(exec_ctx, op); + GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0); + return; + } + if (call != NULL) { + grpc_subchannel_call_process_op(exec_ctx, call, op); + GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0); + return; + } + /* we failed; lock and figure out what to do */ + gpr_mu_lock(&holder->mu); +retry: + /* need to recheck that another thread hasn't set the call */ + call = GET_CALL(holder); + if (call == CANCELLED_CALL) { + gpr_mu_unlock(&holder->mu); + grpc_transport_stream_op_finish_with_failure(exec_ctx, op); + GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0); + return; + } + if (call != NULL) { + gpr_mu_unlock(&holder->mu); + grpc_subchannel_call_process_op(exec_ctx, call, op); + GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0); + return; + } + /* if this is a cancellation, then we can raise our cancelled flag */ + if (op->cancel_with_status != GRPC_STATUS_OK) { + if (!gpr_atm_rel_cas(&holder->subchannel_call, 0, 1)) { + goto retry; + } else { + switch (holder->creation_phase) { + case GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING: + fail_locked(exec_ctx, holder); + break; + case GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL: + holder->pick_subchannel(exec_ctx, holder->pick_subchannel_arg, NULL, + &holder->connected_subchannel, NULL); + break; + } + gpr_mu_unlock(&holder->mu); + grpc_transport_stream_op_finish_with_failure(exec_ctx, op); + GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0); + return; + } + } + /* if we don't have a subchannel, try to get one */ + if (holder->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING && + holder->connected_subchannel == NULL && + op->send_initial_metadata != NULL) { + holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL; + grpc_closure_init(&holder->next_step, subchannel_ready, holder); + GRPC_CALL_STACK_REF(holder->owning_call, "pick_subchannel"); + if (holder->pick_subchannel( + exec_ctx, holder->pick_subchannel_arg, op->send_initial_metadata, + &holder->connected_subchannel, &holder->next_step)) { + holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING; + GRPC_CALL_STACK_UNREF(exec_ctx, holder->owning_call, "pick_subchannel"); + } + } + /* if we've got a subchannel, then let's ask it to create a call */ + if (holder->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING && + holder->connected_subchannel != NULL) { + gpr_atm_rel_store( + &holder->subchannel_call, + (gpr_atm)(uintptr_t)grpc_connected_subchannel_create_call( + exec_ctx, holder->connected_subchannel, holder->pollset)); + retry_waiting_locked(exec_ctx, holder); + goto retry; + } + /* nothing to be done but wait */ + add_waiting_locked(holder, op); + gpr_mu_unlock(&holder->mu); + GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0); +} + +static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *arg, bool success) { + grpc_subchannel_call_holder *holder = arg; + gpr_mu_lock(&holder->mu); + GPR_ASSERT(holder->creation_phase == + GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL); + holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING; + if (holder->connected_subchannel == NULL) { + fail_locked(exec_ctx, holder); + } else if (1 == gpr_atm_acq_load(&holder->subchannel_call)) { + /* already cancelled before subchannel became ready */ + fail_locked(exec_ctx, holder); + } else { + gpr_atm_rel_store( + &holder->subchannel_call, + (gpr_atm)(uintptr_t)grpc_connected_subchannel_create_call( + exec_ctx, holder->connected_subchannel, holder->pollset)); + retry_waiting_locked(exec_ctx, holder); + } + gpr_mu_unlock(&holder->mu); + GRPC_CALL_STACK_UNREF(exec_ctx, holder->owning_call, "pick_subchannel"); +} + +typedef struct { + grpc_transport_stream_op *ops; + size_t nops; + grpc_subchannel_call *call; +} retry_ops_args; + +static void retry_waiting_locked(grpc_exec_ctx *exec_ctx, + grpc_subchannel_call_holder *holder) { + retry_ops_args *a = gpr_malloc(sizeof(*a)); + a->ops = holder->waiting_ops; + a->nops = holder->waiting_ops_count; + a->call = GET_CALL(holder); + if (a->call == CANCELLED_CALL) { + gpr_free(a); + fail_locked(exec_ctx, holder); + return; + } + holder->waiting_ops = NULL; + holder->waiting_ops_count = 0; + holder->waiting_ops_capacity = 0; + GRPC_SUBCHANNEL_CALL_REF(a->call, "retry_ops"); + grpc_exec_ctx_enqueue(exec_ctx, grpc_closure_create(retry_ops, a), true, + NULL); +} + +static void retry_ops(grpc_exec_ctx *exec_ctx, void *args, bool success) { + retry_ops_args *a = args; + size_t i; + for (i = 0; i < a->nops; i++) { + grpc_subchannel_call_process_op(exec_ctx, a->call, &a->ops[i]); + } + GRPC_SUBCHANNEL_CALL_UNREF(exec_ctx, a->call, "retry_ops"); + gpr_free(a->ops); + gpr_free(a); +} + +static void add_waiting_locked(grpc_subchannel_call_holder *holder, + grpc_transport_stream_op *op) { + GPR_TIMER_BEGIN("add_waiting_locked", 0); + if (holder->waiting_ops_count == holder->waiting_ops_capacity) { + holder->waiting_ops_capacity = GPR_MAX(3, 2 * holder->waiting_ops_capacity); + holder->waiting_ops = + gpr_realloc(holder->waiting_ops, holder->waiting_ops_capacity * + sizeof(*holder->waiting_ops)); + } + holder->waiting_ops[holder->waiting_ops_count++] = *op; + GPR_TIMER_END("add_waiting_locked", 0); +} + +static void fail_locked(grpc_exec_ctx *exec_ctx, + grpc_subchannel_call_holder *holder) { + size_t i; + for (i = 0; i < holder->waiting_ops_count; i++) { + grpc_transport_stream_op_finish_with_failure(exec_ctx, + &holder->waiting_ops[i]); + } + holder->waiting_ops_count = 0; +} + +char *grpc_subchannel_call_holder_get_peer( + grpc_exec_ctx *exec_ctx, grpc_subchannel_call_holder *holder) { + grpc_subchannel_call *subchannel_call = GET_CALL(holder); + + if (subchannel_call) { + return grpc_subchannel_call_get_peer(exec_ctx, subchannel_call); + } else { + return NULL; + } +} diff --git a/src/core/lib/channel/subchannel_call_holder.h b/src/core/lib/channel/subchannel_call_holder.h new file mode 100644 index 0000000000..84b4657db4 --- /dev/null +++ b/src/core/lib/channel/subchannel_call_holder.h @@ -0,0 +1,97 @@ +/* + * + * Copyright 2015-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_CHANNEL_SUBCHANNEL_CALL_HOLDER_H +#define GRPC_CORE_CHANNEL_SUBCHANNEL_CALL_HOLDER_H + +#include "src/core/client_config/subchannel.h" + +/** Pick a subchannel for grpc_subchannel_call_holder; + Return 1 if subchannel is available immediately (in which case on_ready + should not be called), or 0 otherwise (in which case on_ready should be + called when the subchannel is available) */ +typedef int (*grpc_subchannel_call_holder_pick_subchannel)( + grpc_exec_ctx *exec_ctx, void *arg, grpc_metadata_batch *initial_metadata, + grpc_connected_subchannel **connected_subchannel, grpc_closure *on_ready); + +typedef enum { + GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING, + GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL +} grpc_subchannel_call_holder_creation_phase; + +/** Wrapper for holding a pointer to grpc_subchannel_call, and the + associated machinery to create such a pointer. + Handles queueing of stream ops until a call object is ready, waiting + for initial metadata before trying to create a call object, + and handling cancellation gracefully. + + The channel filter uses this as their call_data. */ +typedef struct grpc_subchannel_call_holder { + /** either 0 for no call, 1 for cancelled, or a pointer to a + grpc_subchannel_call */ + gpr_atm subchannel_call; + /** Helper function to choose the subchannel on which to create + the call object. Channel filter delegates to the load + balancing policy (once it's ready). */ + grpc_subchannel_call_holder_pick_subchannel pick_subchannel; + void *pick_subchannel_arg; + + gpr_mu mu; + + grpc_subchannel_call_holder_creation_phase creation_phase; + grpc_connected_subchannel *connected_subchannel; + grpc_pollset *pollset; + + grpc_transport_stream_op *waiting_ops; + size_t waiting_ops_count; + size_t waiting_ops_capacity; + + grpc_closure next_step; + + grpc_call_stack *owning_call; +} grpc_subchannel_call_holder; + +void grpc_subchannel_call_holder_init( + grpc_subchannel_call_holder *holder, + grpc_subchannel_call_holder_pick_subchannel pick_subchannel, + void *pick_subchannel_arg, grpc_call_stack *owning_call); +void grpc_subchannel_call_holder_destroy(grpc_exec_ctx *exec_ctx, + grpc_subchannel_call_holder *holder); + +void grpc_subchannel_call_holder_perform_op(grpc_exec_ctx *exec_ctx, + grpc_subchannel_call_holder *holder, + grpc_transport_stream_op *op); +char *grpc_subchannel_call_holder_get_peer(grpc_exec_ctx *exec_ctx, + grpc_subchannel_call_holder *holder); + +#endif /* GRPC_CORE_CHANNEL_SUBCHANNEL_CALL_HOLDER_H */ diff --git a/src/core/lib/client_config/README.md b/src/core/lib/client_config/README.md new file mode 100644 index 0000000000..fff7a5af5b --- /dev/null +++ b/src/core/lib/client_config/README.md @@ -0,0 +1,66 @@ +Client Configuration Support for GRPC +===================================== + +This library provides high level configuration machinery to construct client +channels and load balance between them. + +Each grpc_channel is created with a grpc_resolver. It is the resolver's duty +to resolve a name into configuration data for the channel. Such configuration +data might include: + +- a list of (ip, port) addresses to connect to +- a load balancing policy to decide which server to send a request to +- a set of filters to mutate outgoing requests (say, by adding metadata) + +The resolver provides this data as a stream of grpc_client_config objects to +the channel. We represent configuration as a stream so that it can be changed +by the resolver during execution, by reacting to external events (such as a +new configuration file being pushed to some store). + + +Load Balancing +-------------- + +Load balancing configuration is provided by a grpc_lb_policy object, stored as +part of grpc_client_config. + +The primary job of the load balancing policies is to pick a target server given only the +initial metadata for a request. It does this by providing a grpc_subchannel +object to the owning channel. + + +Sub-Channels +------------ + +A sub-channel provides a connection to a server for a client channel. It has a +connectivity state like a regular channel, and so can be connected or +disconnected. This connectivity state can be used to inform load balancing +decisions (for example, by avoiding disconnected backends). + +Configured sub-channels are fully setup to participate in the grpc data plane. +Their behavior is specified by a set of grpc channel filters defined at their +construction. To customize this behavior, resolvers build +grpc_subchannel_factory objects, which use the decorator pattern to customize +construction arguments for concrete grpc_subchannel instances. + + +Naming for GRPC +=============== + +Names in GRPC are represented by a URI (as defined in +[RFC 3986](https://tools.ietf.org/html/rfc3986)). + +The following schemes are currently supported: + +dns:///host:port - dns schemes are currently supported so long as authority is + empty (authority based dns resolution is expected in a future + release) + +unix:path - the unix scheme is used to create and connect to unix domain + sockets - the authority must be empty, and the path + represents the absolute or relative path to the desired + socket + +ipv4:host:port - a pre-resolved ipv4 dotted decimal address/port combination + +ipv6:[host]:port - a pre-resolved ipv6 address/port combination diff --git a/src/core/lib/client_config/client_config.c b/src/core/lib/client_config/client_config.c new file mode 100644 index 0000000000..c500af25ee --- /dev/null +++ b/src/core/lib/client_config/client_config.c @@ -0,0 +1,74 @@ +/* + * + * Copyright 2015-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/client_config/client_config.h" + +#include + +#include + +struct grpc_client_config { + gpr_refcount refs; + grpc_lb_policy *lb_policy; +}; + +grpc_client_config *grpc_client_config_create() { + grpc_client_config *c = gpr_malloc(sizeof(*c)); + memset(c, 0, sizeof(*c)); + gpr_ref_init(&c->refs, 1); + return c; +} + +void grpc_client_config_ref(grpc_client_config *c) { gpr_ref(&c->refs); } + +void grpc_client_config_unref(grpc_exec_ctx *exec_ctx, grpc_client_config *c) { + if (gpr_unref(&c->refs)) { + if (c->lb_policy != NULL) { + GRPC_LB_POLICY_UNREF(exec_ctx, c->lb_policy, "client_config"); + } + gpr_free(c); + } +} + +void grpc_client_config_set_lb_policy(grpc_client_config *c, + grpc_lb_policy *lb_policy) { + GPR_ASSERT(c->lb_policy == NULL); + if (lb_policy) { + GRPC_LB_POLICY_REF(lb_policy, "client_config"); + } + c->lb_policy = lb_policy; +} + +grpc_lb_policy *grpc_client_config_get_lb_policy(grpc_client_config *c) { + return c->lb_policy; +} diff --git a/src/core/lib/client_config/client_config.h b/src/core/lib/client_config/client_config.h new file mode 100644 index 0000000000..9b37fdc211 --- /dev/null +++ b/src/core/lib/client_config/client_config.h @@ -0,0 +1,53 @@ +/* + * + * Copyright 2015-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_CLIENT_CONFIG_CLIENT_CONFIG_H +#define GRPC_CORE_CLIENT_CONFIG_CLIENT_CONFIG_H + +#include "src/core/client_config/lb_policy.h" + +/** Total configuration for a client. Provided, and updated, by + grpc_resolver */ +typedef struct grpc_client_config grpc_client_config; + +grpc_client_config *grpc_client_config_create(); +void grpc_client_config_ref(grpc_client_config *client_config); +void grpc_client_config_unref(grpc_exec_ctx *exec_ctx, + grpc_client_config *client_config); + +void grpc_client_config_set_lb_policy(grpc_client_config *client_config, + grpc_lb_policy *lb_policy); +grpc_lb_policy *grpc_client_config_get_lb_policy( + grpc_client_config *client_config); + +#endif /* GRPC_CORE_CLIENT_CONFIG_CLIENT_CONFIG_H */ diff --git a/src/core/lib/client_config/connector.c b/src/core/lib/client_config/connector.c new file mode 100644 index 0000000000..aa34aa7fab --- /dev/null +++ b/src/core/lib/client_config/connector.c @@ -0,0 +1,55 @@ +/* + * + * Copyright 2015-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/client_config/connector.h" + +grpc_connector* grpc_connector_ref(grpc_connector* connector) { + connector->vtable->ref(connector); + return connector; +} + +void grpc_connector_unref(grpc_exec_ctx* exec_ctx, grpc_connector* connector) { + connector->vtable->unref(exec_ctx, connector); +} + +void grpc_connector_connect(grpc_exec_ctx* exec_ctx, grpc_connector* connector, + const grpc_connect_in_args* in_args, + grpc_connect_out_args* out_args, + grpc_closure* notify) { + connector->vtable->connect(exec_ctx, connector, in_args, out_args, notify); +} + +void grpc_connector_shutdown(grpc_exec_ctx* exec_ctx, + grpc_connector* connector) { + connector->vtable->shutdown(exec_ctx, connector); +} diff --git a/src/core/lib/client_config/connector.h b/src/core/lib/client_config/connector.h new file mode 100644 index 0000000000..93248fca4b --- /dev/null +++ b/src/core/lib/client_config/connector.h @@ -0,0 +1,92 @@ +/* + * + * Copyright 2015-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_CLIENT_CONFIG_CONNECTOR_H +#define GRPC_CORE_CLIENT_CONFIG_CONNECTOR_H + +#include "src/core/channel/channel_stack.h" +#include "src/core/iomgr/sockaddr.h" +#include "src/core/transport/transport.h" + +typedef struct grpc_connector grpc_connector; +typedef struct grpc_connector_vtable grpc_connector_vtable; + +struct grpc_connector { + const grpc_connector_vtable *vtable; +}; + +typedef struct { + /** set of pollsets interested in this connection */ + grpc_pollset_set *interested_parties; + /** address to connect to */ + const struct sockaddr *addr; + size_t addr_len; + /** initial connect string to send */ + gpr_slice initial_connect_string; + /** deadline for connection */ + gpr_timespec deadline; + /** channel arguments (to be passed to transport) */ + const grpc_channel_args *channel_args; +} grpc_connect_in_args; + +typedef struct { + /** the connected transport */ + grpc_transport *transport; + + /** channel arguments (to be passed to the filters) */ + const grpc_channel_args *channel_args; +} grpc_connect_out_args; + +struct grpc_connector_vtable { + void (*ref)(grpc_connector *connector); + void (*unref)(grpc_exec_ctx *exec_ctx, grpc_connector *connector); + /** Implementation of grpc_connector_shutdown */ + void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_connector *connector); + /** Implementation of grpc_connector_connect */ + void (*connect)(grpc_exec_ctx *exec_ctx, grpc_connector *connector, + const grpc_connect_in_args *in_args, + grpc_connect_out_args *out_args, grpc_closure *notify); +}; + +grpc_connector *grpc_connector_ref(grpc_connector *connector); +void grpc_connector_unref(grpc_exec_ctx *exec_ctx, grpc_connector *connector); +/** Connect using the connector: max one outstanding call at a time */ +void grpc_connector_connect(grpc_exec_ctx *exec_ctx, grpc_connector *connector, + const grpc_connect_in_args *in_args, + grpc_connect_out_args *out_args, + grpc_closure *notify); +/** Cancel any pending connection */ +void grpc_connector_shutdown(grpc_exec_ctx *exec_ctx, + grpc_connector *connector); + +#endif /* GRPC_CORE_CLIENT_CONFIG_CONNECTOR_H */ diff --git a/src/core/lib/client_config/default_initial_connect_string.c b/src/core/lib/client_config/default_initial_connect_string.c new file mode 100644 index 0000000000..6a4e23e6f2 --- /dev/null +++ b/src/core/lib/client_config/default_initial_connect_string.c @@ -0,0 +1,39 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include "src/core/iomgr/sockaddr.h" + +void grpc_set_default_initial_connect_string(struct sockaddr **addr, + size_t *addr_len, + gpr_slice *initial_str) {} diff --git a/src/core/lib/client_config/initial_connect_string.c b/src/core/lib/client_config/initial_connect_string.c new file mode 100644 index 0000000000..19afa1675a --- /dev/null +++ b/src/core/lib/client_config/initial_connect_string.c @@ -0,0 +1,53 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/client_config/initial_connect_string.h" + +#include + +extern void grpc_set_default_initial_connect_string(struct sockaddr **addr, + size_t *addr_len, + gpr_slice *initial_str); + +static grpc_set_initial_connect_string_func g_set_initial_connect_string_func = + grpc_set_default_initial_connect_string; + +void grpc_test_set_initial_connect_string_function( + grpc_set_initial_connect_string_func func) { + g_set_initial_connect_string_func = func; +} + +void grpc_set_initial_connect_string(struct sockaddr **addr, size_t *addr_len, + gpr_slice *initial_str) { + g_set_initial_connect_string_func(addr, addr_len, initial_str); +} diff --git a/src/core/lib/client_config/initial_connect_string.h b/src/core/lib/client_config/initial_connect_string.h new file mode 100644 index 0000000000..e6d2d8f8fe --- /dev/null +++ b/src/core/lib/client_config/initial_connect_string.h @@ -0,0 +1,50 @@ +/* + * + * Copyright 2015-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_CLIENT_CONFIG_INITIAL_CONNECT_STRING_H +#define GRPC_CORE_CLIENT_CONFIG_INITIAL_CONNECT_STRING_H + +#include +#include "src/core/iomgr/sockaddr.h" + +typedef void (*grpc_set_initial_connect_string_func)(struct sockaddr **addr, + size_t *addr_len, + gpr_slice *initial_str); +void grpc_test_set_initial_connect_string_function( + grpc_set_initial_connect_string_func func); + +/** Set a string to be sent once connected. Optionally reset addr. */ +void grpc_set_initial_connect_string(struct sockaddr **addr, size_t *addr_len, + gpr_slice *connect_string); + +#endif /* GRPC_CORE_CLIENT_CONFIG_INITIAL_CONNECT_STRING_H */ diff --git a/src/core/lib/client_config/lb_policies/load_balancer_api.c b/src/core/lib/client_config/lb_policies/load_balancer_api.c new file mode 100644 index 0000000000..a6b5785fe4 --- /dev/null +++ b/src/core/lib/client_config/lb_policies/load_balancer_api.c @@ -0,0 +1,163 @@ +/* + * + * 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/client_config/lb_policies/load_balancer_api.h" +#include "third_party/nanopb/pb_decode.h" +#include "third_party/nanopb/pb_encode.h" + +#include + +typedef struct decode_serverlist_arg { + int first_pass; + int i; + size_t num_servers; + grpc_grpclb_server **servers; +} decode_serverlist_arg; + +/* invoked once for every Server in ServerList */ +static bool decode_serverlist(pb_istream_t *stream, const pb_field_t *field, + void **arg) { + decode_serverlist_arg *dec_arg = *arg; + if (dec_arg->first_pass != 0) { /* first pass */ + grpc_grpclb_server server; + if (!pb_decode(stream, grpc_lb_v0_Server_fields, &server)) { + return false; + } + dec_arg->num_servers++; + } else { /* second pass */ + grpc_grpclb_server *server = gpr_malloc(sizeof(grpc_grpclb_server)); + GPR_ASSERT(dec_arg->num_servers > 0); + if (dec_arg->i == 0) { /* first iteration of second pass */ + dec_arg->servers = + gpr_malloc(sizeof(grpc_grpclb_server *) * dec_arg->num_servers); + } + if (!pb_decode(stream, grpc_lb_v0_Server_fields, server)) { + return false; + } + dec_arg->servers[dec_arg->i++] = server; + } + + return true; +} + +grpc_grpclb_request *grpc_grpclb_request_create(const char *lb_service_name) { + grpc_grpclb_request *req = gpr_malloc(sizeof(grpc_grpclb_request)); + + req->has_client_stats = 0; /* TODO(dgq): add support for stats once defined */ + req->has_initial_request = 1; + req->initial_request.has_name = 1; + strncpy(req->initial_request.name, lb_service_name, + GRPC_GRPCLB_SERVICE_NAME_MAX_LENGTH); + return req; +} + +gpr_slice grpc_grpclb_request_encode(const grpc_grpclb_request *request) { + size_t encoded_length; + pb_ostream_t sizestream; + pb_ostream_t outputstream; + gpr_slice slice; + memset(&sizestream, 0, sizeof(pb_ostream_t)); + pb_encode(&sizestream, grpc_lb_v0_LoadBalanceRequest_fields, request); + encoded_length = sizestream.bytes_written; + + slice = gpr_slice_malloc(encoded_length); + outputstream = + pb_ostream_from_buffer(GPR_SLICE_START_PTR(slice), encoded_length); + GPR_ASSERT(pb_encode(&outputstream, grpc_lb_v0_LoadBalanceRequest_fields, + request) != 0); + return slice; +} + +void grpc_grpclb_request_destroy(grpc_grpclb_request *request) { + gpr_free(request); +} + +grpc_grpclb_response *grpc_grpclb_response_parse(gpr_slice encoded_response) { + bool status; + pb_istream_t stream = + pb_istream_from_buffer(GPR_SLICE_START_PTR(encoded_response), + GPR_SLICE_LENGTH(encoded_response)); + grpc_grpclb_response *res = gpr_malloc(sizeof(grpc_grpclb_response)); + memset(res, 0, sizeof(*res)); + status = pb_decode(&stream, grpc_lb_v0_LoadBalanceResponse_fields, res); + GPR_ASSERT(status == true); + return res; +} + +grpc_grpclb_serverlist *grpc_grpclb_response_parse_serverlist( + gpr_slice encoded_response) { + grpc_grpclb_serverlist *sl = gpr_malloc(sizeof(grpc_grpclb_serverlist)); + bool status; + decode_serverlist_arg arg; + pb_istream_t stream = + pb_istream_from_buffer(GPR_SLICE_START_PTR(encoded_response), + GPR_SLICE_LENGTH(encoded_response)); + pb_istream_t stream_at_start = stream; + grpc_grpclb_response *res = gpr_malloc(sizeof(grpc_grpclb_response)); + memset(res, 0, sizeof(*res)); + memset(&arg, 0, sizeof(decode_serverlist_arg)); + + res->server_list.servers.funcs.decode = decode_serverlist; + res->server_list.servers.arg = &arg; + arg.first_pass = 1; + status = pb_decode(&stream, grpc_lb_v0_LoadBalanceResponse_fields, res); + GPR_ASSERT(status == true); + GPR_ASSERT(arg.num_servers > 0); + + arg.first_pass = 0; + status = + pb_decode(&stream_at_start, grpc_lb_v0_LoadBalanceResponse_fields, res); + GPR_ASSERT(status == true); + GPR_ASSERT(arg.servers != NULL); + + sl->num_servers = arg.num_servers; + sl->servers = arg.servers; + if (res->server_list.has_expiration_interval) { + sl->expiration_interval = res->server_list.expiration_interval; + } + grpc_grpclb_response_destroy(res); + return sl; +} + +void grpc_grpclb_destroy_serverlist(grpc_grpclb_serverlist *serverlist) { + size_t i; + for (i = 0; i < serverlist->num_servers; i++) { + gpr_free(serverlist->servers[i]); + } + gpr_free(serverlist->servers); + gpr_free(serverlist); +} + +void grpc_grpclb_response_destroy(grpc_grpclb_response *response) { + gpr_free(response); +} diff --git a/src/core/lib/client_config/lb_policies/load_balancer_api.h b/src/core/lib/client_config/lb_policies/load_balancer_api.h new file mode 100644 index 0000000000..b7a4c9c8f5 --- /dev/null +++ b/src/core/lib/client_config/lb_policies/load_balancer_api.h @@ -0,0 +1,85 @@ +/* + * + * 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_CLIENT_CONFIG_LB_POLICIES_LOAD_BALANCER_API_H +#define GRPC_CORE_CLIENT_CONFIG_LB_POLICIES_LOAD_BALANCER_API_H + +#include + +#include "src/core/client_config/lb_policy_factory.h" +#include "src/core/proto/grpc/lb/v0/load_balancer.pb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define GRPC_GRPCLB_SERVICE_NAME_MAX_LENGTH 128 + +typedef grpc_lb_v0_LoadBalanceRequest grpc_grpclb_request; +typedef grpc_lb_v0_LoadBalanceResponse grpc_grpclb_response; +typedef grpc_lb_v0_Server grpc_grpclb_server; +typedef grpc_lb_v0_Duration grpc_grpclb_duration; +typedef struct grpc_grpclb_serverlist { + grpc_grpclb_server **servers; + size_t num_servers; + grpc_grpclb_duration expiration_interval; +} grpc_grpclb_serverlist; + +/** Create a request for a gRPC LB service under \a lb_service_name */ +grpc_grpclb_request *grpc_grpclb_request_create(const char *lb_service_name); + +/** Protocol Buffers v3-encode \a request */ +gpr_slice grpc_grpclb_request_encode(const grpc_grpclb_request *request); + +/** Destroy \a request */ +void grpc_grpclb_request_destroy(grpc_grpclb_request *request); + +/** Parse (ie, decode) the bytes in \a encoded_response as a \a + * grpc_grpclb_response */ +grpc_grpclb_response *grpc_grpclb_response_parse(gpr_slice encoded_response); + +/** Destroy \a serverlist */ +void grpc_grpclb_destroy_serverlist(grpc_grpclb_serverlist *serverlist); + +/** Parse the list of servers from an encoded \a grpc_grpclb_response */ +grpc_grpclb_serverlist *grpc_grpclb_response_parse_serverlist( + gpr_slice encoded_response); + +/** Destroy \a response */ +void grpc_grpclb_response_destroy(grpc_grpclb_response *response); + +#ifdef __cplusplus +} +#endif + +#endif /* GRPC_CORE_CLIENT_CONFIG_LB_POLICIES_LOAD_BALANCER_API_H */ diff --git a/src/core/lib/client_config/lb_policies/pick_first.c b/src/core/lib/client_config/lb_policies/pick_first.c new file mode 100644 index 0000000000..2833f112f4 --- /dev/null +++ b/src/core/lib/client_config/lb_policies/pick_first.c @@ -0,0 +1,421 @@ +/* + * + * Copyright 2015-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/client_config/lb_policies/pick_first.h" +#include "src/core/client_config/lb_policy_factory.h" + +#include + +#include +#include "src/core/transport/connectivity_state.h" + +typedef struct pending_pick { + struct pending_pick *next; + grpc_pollset *pollset; + grpc_connected_subchannel **target; + grpc_closure *on_complete; +} pending_pick; + +typedef struct { + /** base policy: must be first */ + grpc_lb_policy base; + /** all our subchannels */ + grpc_subchannel **subchannels; + size_t num_subchannels; + + grpc_closure connectivity_changed; + + /** the selected channel (a grpc_connected_subchannel) */ + gpr_atm selected; + + /** mutex protecting remaining members */ + gpr_mu mu; + /** have we started picking? */ + int started_picking; + /** are we shut down? */ + int shutdown; + /** which subchannel are we watching? */ + size_t checking_subchannel; + /** what is the connectivity of that channel? */ + grpc_connectivity_state checking_connectivity; + /** list of picks that are waiting on connectivity */ + pending_pick *pending_picks; + + /** our connectivity state tracker */ + grpc_connectivity_state_tracker state_tracker; +} pick_first_lb_policy; + +#define GET_SELECTED(p) \ + ((grpc_connected_subchannel *)gpr_atm_acq_load(&(p)->selected)) + +void pf_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { + pick_first_lb_policy *p = (pick_first_lb_policy *)pol; + grpc_connected_subchannel *selected = GET_SELECTED(p); + size_t i; + GPR_ASSERT(p->pending_picks == NULL); + for (i = 0; i < p->num_subchannels; i++) { + GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[i], "pick_first"); + } + if (selected != NULL) { + GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, selected, "picked_first"); + } + grpc_connectivity_state_destroy(exec_ctx, &p->state_tracker); + gpr_free(p->subchannels); + gpr_mu_destroy(&p->mu); + gpr_free(p); +} + +void pf_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { + pick_first_lb_policy *p = (pick_first_lb_policy *)pol; + pending_pick *pp; + grpc_connected_subchannel *selected; + gpr_mu_lock(&p->mu); + selected = GET_SELECTED(p); + p->shutdown = 1; + pp = p->pending_picks; + p->pending_picks = NULL; + grpc_connectivity_state_set(exec_ctx, &p->state_tracker, + GRPC_CHANNEL_FATAL_FAILURE, "shutdown"); + /* cancel subscription */ + if (selected != NULL) { + grpc_connected_subchannel_notify_on_state_change( + exec_ctx, selected, NULL, NULL, &p->connectivity_changed); + } else { + grpc_subchannel_notify_on_state_change( + exec_ctx, p->subchannels[p->checking_subchannel], NULL, NULL, + &p->connectivity_changed); + } + gpr_mu_unlock(&p->mu); + while (pp != NULL) { + pending_pick *next = pp->next; + *pp->target = NULL; + grpc_pollset_set_del_pollset(exec_ctx, p->base.interested_parties, + pp->pollset); + grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL); + gpr_free(pp); + pp = next; + } +} + +static void pf_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, + grpc_connected_subchannel **target) { + pick_first_lb_policy *p = (pick_first_lb_policy *)pol; + pending_pick *pp; + gpr_mu_lock(&p->mu); + pp = p->pending_picks; + p->pending_picks = NULL; + while (pp != NULL) { + pending_pick *next = pp->next; + if (pp->target == target) { + grpc_pollset_set_del_pollset(exec_ctx, p->base.interested_parties, + pp->pollset); + *target = NULL; + grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, false, NULL); + gpr_free(pp); + } else { + pp->next = p->pending_picks; + p->pending_picks = pp; + } + pp = next; + } + gpr_mu_unlock(&p->mu); +} + +static void start_picking(grpc_exec_ctx *exec_ctx, pick_first_lb_policy *p) { + p->started_picking = 1; + p->checking_subchannel = 0; + p->checking_connectivity = GRPC_CHANNEL_IDLE; + GRPC_LB_POLICY_WEAK_REF(&p->base, "pick_first_connectivity"); + grpc_subchannel_notify_on_state_change( + exec_ctx, p->subchannels[p->checking_subchannel], + p->base.interested_parties, &p->checking_connectivity, + &p->connectivity_changed); +} + +void pf_exit_idle(grpc_exec_ctx *exec_ctx, 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(exec_ctx, p); + } + gpr_mu_unlock(&p->mu); +} + +int pf_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, grpc_pollset *pollset, + grpc_metadata_batch *initial_metadata, + grpc_connected_subchannel **target, grpc_closure *on_complete) { + pick_first_lb_policy *p = (pick_first_lb_policy *)pol; + pending_pick *pp; + + /* Check atomically for a selected channel */ + grpc_connected_subchannel *selected = GET_SELECTED(p); + if (selected != NULL) { + *target = selected; + return 1; + } + + /* No subchannel selected yet, so acquire lock and then attempt again */ + gpr_mu_lock(&p->mu); + selected = GET_SELECTED(p); + if (selected) { + gpr_mu_unlock(&p->mu); + *target = selected; + return 1; + } else { + if (!p->started_picking) { + start_picking(exec_ctx, p); + } + grpc_pollset_set_add_pollset(exec_ctx, p->base.interested_parties, pollset); + pp = gpr_malloc(sizeof(*pp)); + pp->next = p->pending_picks; + pp->pollset = pollset; + pp->target = target; + pp->on_complete = on_complete; + p->pending_picks = pp; + gpr_mu_unlock(&p->mu); + return 0; + } +} + +static void destroy_subchannels(grpc_exec_ctx *exec_ctx, void *arg, + bool iomgr_success) { + pick_first_lb_policy *p = arg; + size_t i; + size_t num_subchannels = p->num_subchannels; + grpc_subchannel **subchannels; + + gpr_mu_lock(&p->mu); + subchannels = p->subchannels; + p->num_subchannels = 0; + p->subchannels = NULL; + gpr_mu_unlock(&p->mu); + GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "destroy_subchannels"); + + for (i = 0; i < num_subchannels; i++) { + GRPC_SUBCHANNEL_UNREF(exec_ctx, subchannels[i], "pick_first"); + } + + gpr_free(subchannels); +} + +static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg, + bool iomgr_success) { + pick_first_lb_policy *p = arg; + grpc_subchannel *selected_subchannel; + pending_pick *pp; + grpc_connected_subchannel *selected; + + gpr_mu_lock(&p->mu); + + selected = GET_SELECTED(p); + + if (p->shutdown) { + gpr_mu_unlock(&p->mu); + GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "pick_first_connectivity"); + return; + } else if (selected != NULL) { + if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) { + /* if the selected channel goes bad, we're done */ + p->checking_connectivity = GRPC_CHANNEL_FATAL_FAILURE; + } + grpc_connectivity_state_set(exec_ctx, &p->state_tracker, + p->checking_connectivity, "selected_changed"); + if (p->checking_connectivity != GRPC_CHANNEL_FATAL_FAILURE) { + grpc_connected_subchannel_notify_on_state_change( + exec_ctx, selected, p->base.interested_parties, + &p->checking_connectivity, &p->connectivity_changed); + } else { + GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "pick_first_connectivity"); + } + } else { + loop: + switch (p->checking_connectivity) { + case GRPC_CHANNEL_READY: + grpc_connectivity_state_set(exec_ctx, &p->state_tracker, + GRPC_CHANNEL_READY, "connecting_ready"); + selected_subchannel = p->subchannels[p->checking_subchannel]; + selected = + grpc_subchannel_get_connected_subchannel(selected_subchannel); + GPR_ASSERT(selected != NULL); + GRPC_CONNECTED_SUBCHANNEL_REF(selected, "picked_first"); + /* drop the pick list: we are connected now */ + GRPC_LB_POLICY_WEAK_REF(&p->base, "destroy_subchannels"); + gpr_atm_rel_store(&p->selected, (gpr_atm)selected); + grpc_exec_ctx_enqueue( + exec_ctx, grpc_closure_create(destroy_subchannels, p), true, NULL); + /* update any calls that were waiting for a pick */ + while ((pp = p->pending_picks)) { + p->pending_picks = pp->next; + *pp->target = selected; + grpc_pollset_set_del_pollset(exec_ctx, p->base.interested_parties, + pp->pollset); + grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL); + gpr_free(pp); + } + grpc_connected_subchannel_notify_on_state_change( + exec_ctx, selected, p->base.interested_parties, + &p->checking_connectivity, &p->connectivity_changed); + break; + case GRPC_CHANNEL_TRANSIENT_FAILURE: + grpc_connectivity_state_set(exec_ctx, &p->state_tracker, + GRPC_CHANNEL_TRANSIENT_FAILURE, + "connecting_transient_failure"); + p->checking_subchannel = + (p->checking_subchannel + 1) % p->num_subchannels; + p->checking_connectivity = grpc_subchannel_check_connectivity( + p->subchannels[p->checking_subchannel]); + if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) { + grpc_subchannel_notify_on_state_change( + exec_ctx, p->subchannels[p->checking_subchannel], + p->base.interested_parties, &p->checking_connectivity, + &p->connectivity_changed); + } else { + goto loop; + } + break; + case GRPC_CHANNEL_CONNECTING: + case GRPC_CHANNEL_IDLE: + grpc_connectivity_state_set(exec_ctx, &p->state_tracker, + GRPC_CHANNEL_CONNECTING, + "connecting_changed"); + grpc_subchannel_notify_on_state_change( + exec_ctx, p->subchannels[p->checking_subchannel], + p->base.interested_parties, &p->checking_connectivity, + &p->connectivity_changed); + break; + case GRPC_CHANNEL_FATAL_FAILURE: + p->num_subchannels--; + GPR_SWAP(grpc_subchannel *, p->subchannels[p->checking_subchannel], + p->subchannels[p->num_subchannels]); + GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[p->num_subchannels], + "pick_first"); + if (p->num_subchannels == 0) { + grpc_connectivity_state_set(exec_ctx, &p->state_tracker, + GRPC_CHANNEL_FATAL_FAILURE, + "no_more_channels"); + while ((pp = p->pending_picks)) { + p->pending_picks = pp->next; + *pp->target = NULL; + grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL); + gpr_free(pp); + } + GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, + "pick_first_connectivity"); + } else { + grpc_connectivity_state_set(exec_ctx, &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]); + goto loop; + } + } + } + + gpr_mu_unlock(&p->mu); +} + +static grpc_connectivity_state pf_check_connectivity(grpc_exec_ctx *exec_ctx, + grpc_lb_policy *pol) { + pick_first_lb_policy *p = (pick_first_lb_policy *)pol; + grpc_connectivity_state st; + gpr_mu_lock(&p->mu); + st = grpc_connectivity_state_check(&p->state_tracker); + gpr_mu_unlock(&p->mu); + return st; +} + +void pf_notify_on_state_change(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, + grpc_connectivity_state *current, + grpc_closure *notify) { + pick_first_lb_policy *p = (pick_first_lb_policy *)pol; + gpr_mu_lock(&p->mu); + grpc_connectivity_state_notify_on_state_change(exec_ctx, &p->state_tracker, + current, notify); + gpr_mu_unlock(&p->mu); +} + +void pf_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, + grpc_closure *closure) { + pick_first_lb_policy *p = (pick_first_lb_policy *)pol; + grpc_connected_subchannel *selected = GET_SELECTED(p); + if (selected) { + grpc_connected_subchannel_ping(exec_ctx, selected, closure); + } else { + grpc_exec_ctx_enqueue(exec_ctx, closure, false, NULL); + } +} + +static const grpc_lb_policy_vtable pick_first_lb_policy_vtable = { + pf_destroy, + pf_shutdown, + pf_pick, + pf_cancel_pick, + pf_ping_one, + pf_exit_idle, + pf_check_connectivity, + pf_notify_on_state_change}; + +static void pick_first_factory_ref(grpc_lb_policy_factory *factory) {} + +static void pick_first_factory_unref(grpc_lb_policy_factory *factory) {} + +static grpc_lb_policy *create_pick_first(grpc_lb_policy_factory *factory, + grpc_lb_policy_args *args) { + if (args->num_subchannels == 0) return NULL; + pick_first_lb_policy *p = gpr_malloc(sizeof(*p)); + memset(p, 0, sizeof(*p)); + grpc_lb_policy_init(&p->base, &pick_first_lb_policy_vtable); + p->subchannels = + gpr_malloc(sizeof(grpc_subchannel *) * args->num_subchannels); + p->num_subchannels = args->num_subchannels; + grpc_connectivity_state_init(&p->state_tracker, GRPC_CHANNEL_IDLE, + "pick_first"); + memcpy(p->subchannels, args->subchannels, + sizeof(grpc_subchannel *) * args->num_subchannels); + grpc_closure_init(&p->connectivity_changed, pf_connectivity_changed, p); + gpr_mu_init(&p->mu); + return &p->base; +} + +static const grpc_lb_policy_factory_vtable pick_first_factory_vtable = { + pick_first_factory_ref, pick_first_factory_unref, create_pick_first, + "pick_first"}; + +static grpc_lb_policy_factory pick_first_lb_policy_factory = { + &pick_first_factory_vtable}; + +grpc_lb_policy_factory *grpc_pick_first_lb_factory_create() { + return &pick_first_lb_policy_factory; +} diff --git a/src/core/lib/client_config/lb_policies/pick_first.h b/src/core/lib/client_config/lb_policies/pick_first.h new file mode 100644 index 0000000000..3a3f195df5 --- /dev/null +++ b/src/core/lib/client_config/lb_policies/pick_first.h @@ -0,0 +1,43 @@ +/* + * + * Copyright 2015-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_CLIENT_CONFIG_LB_POLICIES_PICK_FIRST_H +#define GRPC_CORE_CLIENT_CONFIG_LB_POLICIES_PICK_FIRST_H + +#include "src/core/client_config/lb_policy_factory.h" + +/** Returns a load balancing factory for the pick first policy, which picks up + * the first subchannel from \a subchannels to succesfully connect */ +grpc_lb_policy_factory *grpc_pick_first_lb_factory_create(); + +#endif /* GRPC_CORE_CLIENT_CONFIG_LB_POLICIES_PICK_FIRST_H */ diff --git a/src/core/lib/client_config/lb_policies/round_robin.c b/src/core/lib/client_config/lb_policies/round_robin.c new file mode 100644 index 0000000000..114ece6e4d --- /dev/null +++ b/src/core/lib/client_config/lb_policies/round_robin.c @@ -0,0 +1,542 @@ +/* + * + * Copyright 2015-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/client_config/lb_policies/round_robin.h" + +#include + +#include +#include "src/core/transport/connectivity_state.h" + +typedef struct round_robin_lb_policy round_robin_lb_policy; + +int grpc_lb_round_robin_trace = 0; + +/** List of entities waiting for a pick. + * + * Once a pick is available, \a target is updated and \a on_complete called. */ +typedef struct pending_pick { + struct pending_pick *next; + grpc_pollset *pollset; + grpc_connected_subchannel **target; + grpc_closure *on_complete; +} pending_pick; + +/** List of subchannels in a connectivity READY state */ +typedef struct ready_list { + grpc_subchannel *subchannel; + struct ready_list *next; + struct ready_list *prev; +} ready_list; + +typedef struct { + /** index within policy->subchannels */ + size_t index; + /** backpointer to owning policy */ + round_robin_lb_policy *policy; + /** subchannel itself */ + grpc_subchannel *subchannel; + /** notification that connectivity has changed on subchannel */ + grpc_closure connectivity_changed_closure; + /** this subchannels current position in subchannel->ready_list */ + ready_list *ready_list_node; + /** last observed connectivity */ + grpc_connectivity_state connectivity_state; +} subchannel_data; + +struct round_robin_lb_policy { + /** base policy: must be first */ + grpc_lb_policy base; + + /** all our subchannels */ + size_t num_subchannels; + subchannel_data **subchannels; + + /** mutex protecting remaining members */ + gpr_mu mu; + /** have we started picking? */ + int started_picking; + /** are we shutting down? */ + int shutdown; + /** List of picks that are waiting on connectivity */ + pending_pick *pending_picks; + + /** our connectivity state tracker */ + grpc_connectivity_state_tracker state_tracker; + + /** (Dummy) root of the doubly linked list containing READY subchannels */ + ready_list ready_list; + /** Last pick from the ready list. */ + ready_list *ready_list_last_pick; +}; + +/** Returns the next subchannel from the connected list or NULL if the list is + * empty. + * + * Note that this function does *not* advance p->ready_list_last_pick. Use \a + * advance_last_picked_locked() for that. */ +static ready_list *peek_next_connected_locked(const round_robin_lb_policy *p) { + ready_list *selected; + selected = p->ready_list_last_pick->next; + + while (selected != NULL) { + if (selected == &p->ready_list) { + GPR_ASSERT(selected->subchannel == NULL); + /* skip dummy root */ + selected = selected->next; + } else { + GPR_ASSERT(selected->subchannel != NULL); + return selected; + } + } + return NULL; +} + +/** Advance the \a ready_list picking head. */ +static void advance_last_picked_locked(round_robin_lb_policy *p) { + if (p->ready_list_last_pick->next != NULL) { /* non-empty list */ + p->ready_list_last_pick = p->ready_list_last_pick->next; + if (p->ready_list_last_pick == &p->ready_list) { + /* skip dummy root */ + p->ready_list_last_pick = p->ready_list_last_pick->next; + } + } else { /* should be an empty list */ + GPR_ASSERT(p->ready_list_last_pick == &p->ready_list); + } + + if (grpc_lb_round_robin_trace) { + gpr_log(GPR_DEBUG, "[READYLIST] ADVANCED LAST PICK. NOW AT NODE %p (SC %p)", + p->ready_list_last_pick, p->ready_list_last_pick->subchannel); + } +} + +/** Prepends (relative to the root at p->ready_list) the connected subchannel \a + * csc to the list of ready subchannels. */ +static ready_list *add_connected_sc_locked(round_robin_lb_policy *p, + grpc_subchannel *sc) { + ready_list *new_elem = gpr_malloc(sizeof(ready_list)); + new_elem->subchannel = sc; + if (p->ready_list.prev == NULL) { + /* first element */ + new_elem->next = &p->ready_list; + new_elem->prev = &p->ready_list; + p->ready_list.next = new_elem; + p->ready_list.prev = new_elem; + } else { + new_elem->next = &p->ready_list; + new_elem->prev = p->ready_list.prev; + p->ready_list.prev->next = new_elem; + p->ready_list.prev = new_elem; + } + if (grpc_lb_round_robin_trace) { + gpr_log(GPR_DEBUG, "[READYLIST] ADDING NODE %p (SC %p)", new_elem, sc); + } + return new_elem; +} + +/** Removes \a node from the list of connected subchannels */ +static void remove_disconnected_sc_locked(round_robin_lb_policy *p, + ready_list *node) { + if (node == NULL) { + 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; + } + + /* removing last item */ + if (node->next == &p->ready_list && node->prev == &p->ready_list) { + GPR_ASSERT(p->ready_list.next == node); + GPR_ASSERT(p->ready_list.prev == node); + p->ready_list.next = NULL; + p->ready_list.prev = NULL; + } else { + node->prev->next = node->next; + node->next->prev = node->prev; + } + + if (grpc_lb_round_robin_trace) { + gpr_log(GPR_DEBUG, "[READYLIST] REMOVED NODE %p (SC %p)", node, + node->subchannel); + } + + node->next = NULL; + node->prev = NULL; + node->subchannel = NULL; + + gpr_free(node); +} + +void rr_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { + round_robin_lb_policy *p = (round_robin_lb_policy *)pol; + size_t i; + ready_list *elem; + for (i = 0; i < p->num_subchannels; i++) { + subchannel_data *sd = p->subchannels[i]; + GRPC_SUBCHANNEL_UNREF(exec_ctx, sd->subchannel, "round_robin"); + gpr_free(sd); + } + + grpc_connectivity_state_destroy(exec_ctx, &p->state_tracker); + gpr_free(p->subchannels); + gpr_mu_destroy(&p->mu); + + elem = p->ready_list.next; + while (elem != NULL && elem != &p->ready_list) { + ready_list *tmp; + tmp = elem->next; + elem->next = NULL; + elem->prev = NULL; + elem->subchannel = NULL; + gpr_free(elem); + elem = tmp; + } + gpr_free(p); +} + +void rr_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { + round_robin_lb_policy *p = (round_robin_lb_policy *)pol; + pending_pick *pp; + size_t i; + + gpr_mu_lock(&p->mu); + + p->shutdown = 1; + while ((pp = p->pending_picks)) { + p->pending_picks = pp->next; + *pp->target = NULL; + grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, false, NULL); + gpr_free(pp); + } + grpc_connectivity_state_set(exec_ctx, &p->state_tracker, + GRPC_CHANNEL_FATAL_FAILURE, "shutdown"); + for (i = 0; i < p->num_subchannels; i++) { + subchannel_data *sd = p->subchannels[i]; + grpc_subchannel_notify_on_state_change(exec_ctx, sd->subchannel, NULL, NULL, + &sd->connectivity_changed_closure); + } + gpr_mu_unlock(&p->mu); +} + +static void rr_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, + grpc_connected_subchannel **target) { + round_robin_lb_policy *p = (round_robin_lb_policy *)pol; + pending_pick *pp; + gpr_mu_lock(&p->mu); + pp = p->pending_picks; + p->pending_picks = NULL; + while (pp != NULL) { + pending_pick *next = pp->next; + if (pp->target == target) { + grpc_pollset_set_del_pollset(exec_ctx, p->base.interested_parties, + pp->pollset); + *target = NULL; + grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, false, NULL); + gpr_free(pp); + } else { + pp->next = p->pending_picks; + p->pending_picks = pp; + } + pp = next; + } + gpr_mu_unlock(&p->mu); +} + +static void start_picking(grpc_exec_ctx *exec_ctx, round_robin_lb_policy *p) { + size_t i; + p->started_picking = 1; + + gpr_log(GPR_DEBUG, "LB_POLICY: p=%p num_subchannels=%d", p, + p->num_subchannels); + + for (i = 0; i < p->num_subchannels; i++) { + subchannel_data *sd = p->subchannels[i]; + sd->connectivity_state = GRPC_CHANNEL_IDLE; + grpc_subchannel_notify_on_state_change( + exec_ctx, sd->subchannel, p->base.interested_parties, + &sd->connectivity_state, &sd->connectivity_changed_closure); + GRPC_LB_POLICY_WEAK_REF(&p->base, "round_robin_connectivity"); + } +} + +void rr_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { + round_robin_lb_policy *p = (round_robin_lb_policy *)pol; + gpr_mu_lock(&p->mu); + if (!p->started_picking) { + start_picking(exec_ctx, p); + } + gpr_mu_unlock(&p->mu); +} + +int rr_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, grpc_pollset *pollset, + grpc_metadata_batch *initial_metadata, + grpc_connected_subchannel **target, grpc_closure *on_complete) { + round_robin_lb_policy *p = (round_robin_lb_policy *)pol; + pending_pick *pp; + ready_list *selected; + gpr_mu_lock(&p->mu); + if ((selected = peek_next_connected_locked(p))) { + gpr_mu_unlock(&p->mu); + *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); + } + /* only advance the last picked pointer if the selection was used */ + advance_last_picked_locked(p); + return 1; + } else { + if (!p->started_picking) { + start_picking(exec_ctx, p); + } + grpc_pollset_set_add_pollset(exec_ctx, p->base.interested_parties, pollset); + pp = gpr_malloc(sizeof(*pp)); + pp->next = p->pending_picks; + pp->pollset = pollset; + pp->target = target; + pp->on_complete = on_complete; + p->pending_picks = pp; + gpr_mu_unlock(&p->mu); + return 0; + } +} + +static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg, + bool iomgr_success) { + subchannel_data *sd = arg; + round_robin_lb_policy *p = sd->policy; + pending_pick *pp; + ready_list *selected; + + int unref = 0; + + gpr_mu_lock(&p->mu); + + if (p->shutdown) { + unref = 1; + } else { + switch (sd->connectivity_state) { + case GRPC_CHANNEL_READY: + grpc_connectivity_state_set(exec_ctx, &p->state_tracker, + GRPC_CHANNEL_READY, "connecting_ready"); + /* add the newly connected subchannel to the list of connected ones. + * Note that it goes to the "end of the line". */ + sd->ready_list_node = add_connected_sc_locked(p, sd->subchannel); + /* at this point we know there's at least one suitable subchannel. Go + * ahead and pick one and notify the pending suitors in + * p->pending_picks. This preemtively replicates rr_pick()'s actions. */ + selected = peek_next_connected_locked(p); + if (p->pending_picks != NULL) { + /* if the selected subchannel is going to be used for the pending + * picks, update the last picked pointer */ + advance_last_picked_locked(p); + } + while ((pp = p->pending_picks)) { + p->pending_picks = pp->next; + *pp->target = + grpc_subchannel_get_connected_subchannel(selected->subchannel); + if (grpc_lb_round_robin_trace) { + gpr_log(GPR_DEBUG, + "[RR CONN CHANGED] TARGET <-- SUBCHANNEL %p (NODE %p)", + selected->subchannel, selected); + } + grpc_pollset_set_del_pollset(exec_ctx, p->base.interested_parties, + pp->pollset); + grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL); + gpr_free(pp); + } + grpc_subchannel_notify_on_state_change( + exec_ctx, sd->subchannel, p->base.interested_parties, + &sd->connectivity_state, &sd->connectivity_changed_closure); + break; + case GRPC_CHANNEL_CONNECTING: + case GRPC_CHANNEL_IDLE: + grpc_connectivity_state_set(exec_ctx, &p->state_tracker, + sd->connectivity_state, + "connecting_changed"); + grpc_subchannel_notify_on_state_change( + exec_ctx, sd->subchannel, p->base.interested_parties, + &sd->connectivity_state, &sd->connectivity_changed_closure); + break; + case GRPC_CHANNEL_TRANSIENT_FAILURE: + /* renew state notification */ + grpc_subchannel_notify_on_state_change( + exec_ctx, sd->subchannel, p->base.interested_parties, + &sd->connectivity_state, &sd->connectivity_changed_closure); + + /* remove from ready list if still present */ + if (sd->ready_list_node != NULL) { + remove_disconnected_sc_locked(p, sd->ready_list_node); + sd->ready_list_node = NULL; + } + grpc_connectivity_state_set(exec_ctx, &p->state_tracker, + GRPC_CHANNEL_TRANSIENT_FAILURE, + "connecting_transient_failure"); + break; + case GRPC_CHANNEL_FATAL_FAILURE: + if (sd->ready_list_node != NULL) { + remove_disconnected_sc_locked(p, sd->ready_list_node); + sd->ready_list_node = NULL; + } + + p->num_subchannels--; + GPR_SWAP(subchannel_data *, p->subchannels[sd->index], + p->subchannels[p->num_subchannels]); + GRPC_SUBCHANNEL_UNREF(exec_ctx, sd->subchannel, "round_robin"); + p->subchannels[sd->index]->index = sd->index; + gpr_free(sd); + + unref = 1; + if (p->num_subchannels == 0) { + grpc_connectivity_state_set(exec_ctx, &p->state_tracker, + GRPC_CHANNEL_FATAL_FAILURE, + "no_more_channels"); + while ((pp = p->pending_picks)) { + p->pending_picks = pp->next; + *pp->target = NULL; + grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL); + gpr_free(pp); + } + } else { + grpc_connectivity_state_set(exec_ctx, &p->state_tracker, + GRPC_CHANNEL_TRANSIENT_FAILURE, + "subchannel_failed"); + } + } /* switch */ + } /* !unref */ + + gpr_mu_unlock(&p->mu); + + if (unref) { + GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "round_robin_connectivity"); + } +} + +static grpc_connectivity_state rr_check_connectivity(grpc_exec_ctx *exec_ctx, + grpc_lb_policy *pol) { + round_robin_lb_policy *p = (round_robin_lb_policy *)pol; + grpc_connectivity_state st; + gpr_mu_lock(&p->mu); + st = grpc_connectivity_state_check(&p->state_tracker); + gpr_mu_unlock(&p->mu); + return st; +} + +static void rr_notify_on_state_change(grpc_exec_ctx *exec_ctx, + grpc_lb_policy *pol, + grpc_connectivity_state *current, + grpc_closure *notify) { + round_robin_lb_policy *p = (round_robin_lb_policy *)pol; + gpr_mu_lock(&p->mu); + grpc_connectivity_state_notify_on_state_change(exec_ctx, &p->state_tracker, + current, notify); + gpr_mu_unlock(&p->mu); +} + +static void rr_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, + grpc_closure *closure) { + round_robin_lb_policy *p = (round_robin_lb_policy *)pol; + ready_list *selected; + grpc_connected_subchannel *target; + gpr_mu_lock(&p->mu); + if ((selected = peek_next_connected_locked(p))) { + gpr_mu_unlock(&p->mu); + target = grpc_subchannel_get_connected_subchannel(selected->subchannel); + grpc_connected_subchannel_ping(exec_ctx, target, closure); + } else { + gpr_mu_unlock(&p->mu); + grpc_exec_ctx_enqueue(exec_ctx, closure, false, NULL); + } +} + +static const grpc_lb_policy_vtable round_robin_lb_policy_vtable = { + rr_destroy, + rr_shutdown, + rr_pick, + rr_cancel_pick, + rr_ping_one, + rr_exit_idle, + rr_check_connectivity, + rr_notify_on_state_change}; + +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_lb_policy_factory *factory, + grpc_lb_policy_args *args) { + size_t i; + round_robin_lb_policy *p = gpr_malloc(sizeof(*p)); + GPR_ASSERT(args->num_subchannels > 0); + memset(p, 0, sizeof(*p)); + grpc_lb_policy_init(&p->base, &round_robin_lb_policy_vtable); + p->num_subchannels = args->num_subchannels; + p->subchannels = gpr_malloc(sizeof(*p->subchannels) * p->num_subchannels); + memset(p->subchannels, 0, sizeof(*p->subchannels) * p->num_subchannels); + grpc_connectivity_state_init(&p->state_tracker, GRPC_CHANNEL_IDLE, + "round_robin"); + + gpr_mu_init(&p->mu); + for (i = 0; i < args->num_subchannels; i++) { + subchannel_data *sd = gpr_malloc(sizeof(*sd)); + memset(sd, 0, sizeof(*sd)); + p->subchannels[i] = sd; + sd->policy = p; + sd->index = i; + sd->subchannel = args->subchannels[i]; + grpc_closure_init(&sd->connectivity_changed_closure, + rr_connectivity_changed, sd); + } + + /* The (dummy node) root of the ready list */ + p->ready_list.subchannel = NULL; + p->ready_list.prev = NULL; + p->ready_list.next = NULL; + p->ready_list_last_pick = &p->ready_list; + + return &p->base; +} + +static const grpc_lb_policy_factory_vtable round_robin_factory_vtable = { + round_robin_factory_ref, round_robin_factory_unref, create_round_robin, + "round_robin"}; + +static grpc_lb_policy_factory round_robin_lb_policy_factory = { + &round_robin_factory_vtable}; + +grpc_lb_policy_factory *grpc_round_robin_lb_factory_create() { + return &round_robin_lb_policy_factory; +} diff --git a/src/core/lib/client_config/lb_policies/round_robin.h b/src/core/lib/client_config/lb_policies/round_robin.h new file mode 100644 index 0000000000..7e6f1769e4 --- /dev/null +++ b/src/core/lib/client_config/lb_policies/round_robin.h @@ -0,0 +1,46 @@ +/* + * + * Copyright 2015-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_CLIENT_CONFIG_LB_POLICIES_ROUND_ROBIN_H +#define GRPC_CORE_CLIENT_CONFIG_LB_POLICIES_ROUND_ROBIN_H + +#include "src/core/client_config/lb_policy.h" + +extern int grpc_lb_round_robin_trace; + +#include "src/core/client_config/lb_policy_factory.h" + +/** Returns a load balancing factory for the round robin policy */ +grpc_lb_policy_factory *grpc_round_robin_lb_factory_create(); + +#endif /* GRPC_CORE_CLIENT_CONFIG_LB_POLICIES_ROUND_ROBIN_H */ diff --git a/src/core/lib/client_config/lb_policy.c b/src/core/lib/client_config/lb_policy.c new file mode 100644 index 0000000000..0d8b007336 --- /dev/null +++ b/src/core/lib/client_config/lb_policy.c @@ -0,0 +1,134 @@ +/* + * + * Copyright 2015-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/client_config/lb_policy.h" + +#define WEAK_REF_BITS 16 + +void grpc_lb_policy_init(grpc_lb_policy *policy, + const grpc_lb_policy_vtable *vtable) { + policy->vtable = vtable; + gpr_atm_no_barrier_store(&policy->ref_pair, 1 << WEAK_REF_BITS); + policy->interested_parties = grpc_pollset_set_create(); +} + +#ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG +#define REF_FUNC_EXTRA_ARGS , const char *file, int line, const char *reason +#define REF_MUTATE_EXTRA_ARGS REF_FUNC_EXTRA_ARGS, const char *purpose +#define REF_FUNC_PASS_ARGS(new_reason) , file, line, new_reason +#define REF_MUTATE_PASS_ARGS(purpose) , file, line, reason, purpose +#else +#define REF_FUNC_EXTRA_ARGS +#define REF_MUTATE_EXTRA_ARGS +#define REF_FUNC_PASS_ARGS(new_reason) +#define REF_MUTATE_PASS_ARGS(x) +#endif + +static gpr_atm ref_mutate(grpc_lb_policy *c, gpr_atm delta, + int barrier REF_MUTATE_EXTRA_ARGS) { + gpr_atm old_val = barrier ? gpr_atm_full_fetch_add(&c->ref_pair, delta) + : gpr_atm_no_barrier_fetch_add(&c->ref_pair, delta); +#ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, + "LB_POLICY: %p % 12s 0x%08x -> 0x%08x [%s]", c, purpose, old_val, + old_val + delta, reason); +#endif + return old_val; +} + +void grpc_lb_policy_ref(grpc_lb_policy *policy REF_FUNC_EXTRA_ARGS) { + ref_mutate(policy, 1 << WEAK_REF_BITS, 0 REF_MUTATE_PASS_ARGS("STRONG_REF")); +} + +void grpc_lb_policy_unref(grpc_exec_ctx *exec_ctx, + grpc_lb_policy *policy REF_FUNC_EXTRA_ARGS) { + gpr_atm old_val = + ref_mutate(policy, (gpr_atm)1 - (gpr_atm)(1 << WEAK_REF_BITS), + 1 REF_MUTATE_PASS_ARGS("STRONG_UNREF")); + gpr_atm mask = ~(gpr_atm)((1 << WEAK_REF_BITS) - 1); + gpr_atm check = 1 << WEAK_REF_BITS; + if ((old_val & mask) == check) { + policy->vtable->shutdown(exec_ctx, policy); + } + grpc_lb_policy_weak_unref(exec_ctx, + policy REF_FUNC_PASS_ARGS("strong-unref")); +} + +void grpc_lb_policy_weak_ref(grpc_lb_policy *policy REF_FUNC_EXTRA_ARGS) { + ref_mutate(policy, 1, 0 REF_MUTATE_PASS_ARGS("WEAK_REF")); +} + +void grpc_lb_policy_weak_unref(grpc_exec_ctx *exec_ctx, + grpc_lb_policy *policy REF_FUNC_EXTRA_ARGS) { + gpr_atm old_val = + ref_mutate(policy, -(gpr_atm)1, 1 REF_MUTATE_PASS_ARGS("WEAK_UNREF")); + if (old_val == 1) { + grpc_pollset_set_destroy(policy->interested_parties); + policy->vtable->destroy(exec_ctx, policy); + } +} + +int grpc_lb_policy_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, + grpc_pollset *pollset, + grpc_metadata_batch *initial_metadata, + grpc_connected_subchannel **target, + grpc_closure *on_complete) { + return policy->vtable->pick(exec_ctx, policy, pollset, initial_metadata, + target, on_complete); +} + +void grpc_lb_policy_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, + grpc_connected_subchannel **target) { + policy->vtable->cancel_pick(exec_ctx, policy, target); +} + +void grpc_lb_policy_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy) { + policy->vtable->exit_idle(exec_ctx, policy); +} + +void grpc_lb_policy_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, + grpc_closure *closure) { + policy->vtable->ping_one(exec_ctx, policy, closure); +} + +void grpc_lb_policy_notify_on_state_change(grpc_exec_ctx *exec_ctx, + grpc_lb_policy *policy, + grpc_connectivity_state *state, + grpc_closure *closure) { + policy->vtable->notify_on_state_change(exec_ctx, policy, state, closure); +} + +grpc_connectivity_state grpc_lb_policy_check_connectivity( + grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy) { + return policy->vtable->check_connectivity(exec_ctx, policy); +} diff --git a/src/core/lib/client_config/lb_policy.h b/src/core/lib/client_config/lb_policy.h new file mode 100644 index 0000000000..ffebc2a69c --- /dev/null +++ b/src/core/lib/client_config/lb_policy.h @@ -0,0 +1,144 @@ +/* + * + * Copyright 2015-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_CLIENT_CONFIG_LB_POLICY_H +#define GRPC_CORE_CLIENT_CONFIG_LB_POLICY_H + +#include "src/core/client_config/subchannel.h" +#include "src/core/transport/connectivity_state.h" + +/** A load balancing policy: specified by a vtable and a struct (which + is expected to be extended to contain some parameters) */ +typedef struct grpc_lb_policy grpc_lb_policy; +typedef struct grpc_lb_policy_vtable grpc_lb_policy_vtable; + +typedef void (*grpc_lb_completion)(void *cb_arg, grpc_subchannel *subchannel, + grpc_status_code status, const char *errmsg); + +struct grpc_lb_policy { + const grpc_lb_policy_vtable *vtable; + gpr_atm ref_pair; + /* owned pointer to interested parties in load balancing decisions */ + grpc_pollset_set *interested_parties; +}; + +struct grpc_lb_policy_vtable { + void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy); + + void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy); + + /** implement grpc_lb_policy_pick */ + int (*pick)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, + grpc_pollset *pollset, grpc_metadata_batch *initial_metadata, + grpc_connected_subchannel **target, grpc_closure *on_complete); + void (*cancel_pick)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, + grpc_connected_subchannel **target); + + void (*ping_one)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, + grpc_closure *closure); + + /** try to enter a READY connectivity state */ + void (*exit_idle)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy); + + /** check the current connectivity of the lb_policy */ + grpc_connectivity_state (*check_connectivity)(grpc_exec_ctx *exec_ctx, + grpc_lb_policy *policy); + + /** call notify when the connectivity state of a channel changes from *state. + Updates *state with the new state of the policy */ + void (*notify_on_state_change)(grpc_exec_ctx *exec_ctx, + grpc_lb_policy *policy, + grpc_connectivity_state *state, + grpc_closure *closure); +}; + +/*#define GRPC_LB_POLICY_REFCOUNT_DEBUG*/ +#ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG +#define GRPC_LB_POLICY_REF(p, r) \ + grpc_lb_policy_ref((p), __FILE__, __LINE__, (r)) +#define GRPC_LB_POLICY_UNREF(exec_ctx, p, r) \ + grpc_lb_policy_unref((exec_ctx), (p), __FILE__, __LINE__, (r)) +#define GRPC_LB_POLICY_WEAK_REF(p, r) \ + grpc_lb_policy_weak_ref((p), __FILE__, __LINE__, (r)) +#define GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, p, r) \ + grpc_lb_policy_weak_unref((exec_ctx), (p), __FILE__, __LINE__, (r)) +void grpc_lb_policy_ref(grpc_lb_policy *policy, const char *file, int line, + const char *reason); +void grpc_lb_policy_unref(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, + const char *file, int line, const char *reason); +void grpc_lb_policy_weak_ref(grpc_lb_policy *policy, const char *file, int line, + const char *reason); +void grpc_lb_policy_weak_unref(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, + const char *file, int line, const char *reason); +#else +#define GRPC_LB_POLICY_REF(p, r) grpc_lb_policy_ref((p)) +#define GRPC_LB_POLICY_UNREF(cl, p, r) grpc_lb_policy_unref((cl), (p)) +#define GRPC_LB_POLICY_WEAK_REF(p, r) grpc_lb_policy_weak_ref((p)) +#define GRPC_LB_POLICY_WEAK_UNREF(cl, p, r) grpc_lb_policy_weak_unref((cl), (p)) +void grpc_lb_policy_ref(grpc_lb_policy *policy); +void grpc_lb_policy_unref(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy); +void grpc_lb_policy_weak_ref(grpc_lb_policy *policy); +void grpc_lb_policy_weak_unref(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy); +#endif + +/** called by concrete implementations to initialize the base struct */ +void grpc_lb_policy_init(grpc_lb_policy *policy, + const grpc_lb_policy_vtable *vtable); + +/** Given initial metadata in \a initial_metadata, find an appropriate + target for this rpc, and 'return' it by calling \a on_complete after setting + \a target. + Picking can be asynchronous. Any IO should be done under \a pollset. */ +int grpc_lb_policy_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, + grpc_pollset *pollset, + grpc_metadata_batch *initial_metadata, + grpc_connected_subchannel **target, + grpc_closure *on_complete); + +void grpc_lb_policy_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, + grpc_closure *closure); + +void grpc_lb_policy_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, + grpc_connected_subchannel **target); + +void grpc_lb_policy_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy); + +void grpc_lb_policy_notify_on_state_change(grpc_exec_ctx *exec_ctx, + grpc_lb_policy *policy, + grpc_connectivity_state *state, + grpc_closure *closure); + +grpc_connectivity_state grpc_lb_policy_check_connectivity( + grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy); + +#endif /* GRPC_CORE_CLIENT_CONFIG_LB_POLICY_H */ diff --git a/src/core/lib/client_config/lb_policy_factory.c b/src/core/lib/client_config/lb_policy_factory.c new file mode 100644 index 0000000000..e49de544e3 --- /dev/null +++ b/src/core/lib/client_config/lb_policy_factory.c @@ -0,0 +1,48 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/client_config/lb_policy_factory.h" + +void grpc_lb_policy_factory_ref(grpc_lb_policy_factory* factory) { + factory->vtable->ref(factory); +} + +void grpc_lb_policy_factory_unref(grpc_lb_policy_factory* factory) { + factory->vtable->unref(factory); +} + +grpc_lb_policy* grpc_lb_policy_factory_create_lb_policy( + grpc_lb_policy_factory* factory, grpc_lb_policy_args* args) { + if (factory == NULL) return NULL; + return factory->vtable->create_lb_policy(factory, args); +} diff --git a/src/core/lib/client_config/lb_policy_factory.h b/src/core/lib/client_config/lb_policy_factory.h new file mode 100644 index 0000000000..842ba96098 --- /dev/null +++ b/src/core/lib/client_config/lb_policy_factory.h @@ -0,0 +1,73 @@ +/* + * + * Copyright 2015-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_CLIENT_CONFIG_LB_POLICY_FACTORY_H +#define GRPC_CORE_CLIENT_CONFIG_LB_POLICY_FACTORY_H + +#include "src/core/client_config/lb_policy.h" +#include "src/core/client_config/subchannel.h" + +typedef struct grpc_lb_policy_factory grpc_lb_policy_factory; +typedef struct grpc_lb_policy_factory_vtable grpc_lb_policy_factory_vtable; + +/** grpc_lb_policy provides grpc_client_config objects to grpc_channel + objects */ +struct grpc_lb_policy_factory { + const grpc_lb_policy_factory_vtable *vtable; +}; + +typedef struct grpc_lb_policy_args { + grpc_subchannel **subchannels; + size_t num_subchannels; +} grpc_lb_policy_args; + +struct grpc_lb_policy_factory_vtable { + void (*ref)(grpc_lb_policy_factory *factory); + void (*unref)(grpc_lb_policy_factory *factory); + + /** Implementation of grpc_lb_policy_factory_create_lb_policy */ + grpc_lb_policy *(*create_lb_policy)(grpc_lb_policy_factory *factory, + grpc_lb_policy_args *args); + + /** Name for the LB policy this factory implements */ + const char *name; +}; + +void grpc_lb_policy_factory_ref(grpc_lb_policy_factory *factory); +void grpc_lb_policy_factory_unref(grpc_lb_policy_factory *factory); + +/** Create a lb_policy instance. */ +grpc_lb_policy *grpc_lb_policy_factory_create_lb_policy( + grpc_lb_policy_factory *factory, grpc_lb_policy_args *args); + +#endif /* GRPC_CORE_CLIENT_CONFIG_LB_POLICY_FACTORY_H */ diff --git a/src/core/lib/client_config/lb_policy_registry.c b/src/core/lib/client_config/lb_policy_registry.c new file mode 100644 index 0000000000..fc302e82d7 --- /dev/null +++ b/src/core/lib/client_config/lb_policy_registry.c @@ -0,0 +1,88 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/client_config/lb_policy_registry.h" + +#include + +#define MAX_POLICIES 10 + +static grpc_lb_policy_factory *g_all_of_the_lb_policies[MAX_POLICIES]; +static int g_number_of_lb_policies = 0; + +static grpc_lb_policy_factory *g_default_lb_policy_factory; + +void grpc_lb_policy_registry_init(grpc_lb_policy_factory *default_factory) { + g_number_of_lb_policies = 0; + g_default_lb_policy_factory = default_factory; +} + +void grpc_lb_policy_registry_shutdown(void) { + int i; + for (i = 0; i < g_number_of_lb_policies; i++) { + grpc_lb_policy_factory_unref(g_all_of_the_lb_policies[i]); + } +} + +void grpc_register_lb_policy(grpc_lb_policy_factory *factory) { + int i; + for (i = 0; i < g_number_of_lb_policies; i++) { + GPR_ASSERT(0 != strcmp(factory->vtable->name, + g_all_of_the_lb_policies[i]->vtable->name)); + } + GPR_ASSERT(g_number_of_lb_policies != MAX_POLICIES); + grpc_lb_policy_factory_ref(factory); + g_all_of_the_lb_policies[g_number_of_lb_policies++] = factory; +} + +static grpc_lb_policy_factory *lookup_factory(const char *name) { + int i; + + if (name == NULL) return NULL; + + for (i = 0; i < g_number_of_lb_policies; i++) { + if (0 == strcmp(name, g_all_of_the_lb_policies[i]->vtable->name)) { + return g_all_of_the_lb_policies[i]; + } + } + + return NULL; +} + +grpc_lb_policy *grpc_lb_policy_create(const char *name, + grpc_lb_policy_args *args) { + grpc_lb_policy_factory *factory = lookup_factory(name); + grpc_lb_policy *lb_policy = + grpc_lb_policy_factory_create_lb_policy(factory, args); + return lb_policy; +} diff --git a/src/core/lib/client_config/lb_policy_registry.h b/src/core/lib/client_config/lb_policy_registry.h new file mode 100644 index 0000000000..f3a08a3558 --- /dev/null +++ b/src/core/lib/client_config/lb_policy_registry.h @@ -0,0 +1,54 @@ +/* + * + * Copyright 2015-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_CLIENT_CONFIG_LB_POLICY_REGISTRY_H +#define GRPC_CORE_CLIENT_CONFIG_LB_POLICY_REGISTRY_H + +#include "src/core/client_config/lb_policy_factory.h" + +/** Initialize the registry and set \a default_factory as the factory to be + * returned when no name is provided in a lookup */ +void grpc_lb_policy_registry_init(grpc_lb_policy_factory *default_factory); +void grpc_lb_policy_registry_shutdown(void); + +/** Register a LB policy factory. */ +void grpc_register_lb_policy(grpc_lb_policy_factory *factory); + +/** Create a \a grpc_lb_policy instance. + * + * If \a name is NULL, the default factory from \a grpc_lb_policy_registry_init + * will be returned. */ +grpc_lb_policy *grpc_lb_policy_create(const char *name, + grpc_lb_policy_args *args); + +#endif /* GRPC_CORE_CLIENT_CONFIG_LB_POLICY_REGISTRY_H */ diff --git a/src/core/lib/client_config/resolver.c b/src/core/lib/client_config/resolver.c new file mode 100644 index 0000000000..eda01e72ba --- /dev/null +++ b/src/core/lib/client_config/resolver.c @@ -0,0 +1,82 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/client_config/resolver.h" + +void grpc_resolver_init(grpc_resolver *resolver, + const grpc_resolver_vtable *vtable) { + resolver->vtable = vtable; + gpr_ref_init(&resolver->refs, 1); +} + +#ifdef GRPC_RESOLVER_REFCOUNT_DEBUG +void grpc_resolver_ref(grpc_resolver *resolver, grpc_closure_list *closure_list, + const char *file, int line, const char *reason) { + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "RESOLVER:%p ref %d -> %d %s", + resolver, (int)resolver->refs.count, (int)resolver->refs.count + 1, + reason); +#else +void grpc_resolver_ref(grpc_resolver *resolver) { +#endif + gpr_ref(&resolver->refs); +} + +#ifdef GRPC_RESOLVER_REFCOUNT_DEBUG +void grpc_resolver_unref(grpc_resolver *resolver, + grpc_closure_list *closure_list, const char *file, + int line, const char *reason) { + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "RESOLVER:%p unref %d -> %d %s", + resolver, (int)resolver->refs.count, (int)resolver->refs.count - 1, + reason); +#else +void grpc_resolver_unref(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver) { +#endif + if (gpr_unref(&resolver->refs)) { + resolver->vtable->destroy(exec_ctx, resolver); + } +} + +void grpc_resolver_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver) { + resolver->vtable->shutdown(exec_ctx, resolver); +} + +void grpc_resolver_channel_saw_error(grpc_exec_ctx *exec_ctx, + grpc_resolver *resolver) { + resolver->vtable->channel_saw_error(exec_ctx, resolver); +} + +void grpc_resolver_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver, + grpc_client_config **target_config, + grpc_closure *on_complete) { + resolver->vtable->next(exec_ctx, resolver, target_config, on_complete); +} diff --git a/src/core/lib/client_config/resolver.h b/src/core/lib/client_config/resolver.h new file mode 100644 index 0000000000..96f88fef84 --- /dev/null +++ b/src/core/lib/client_config/resolver.h @@ -0,0 +1,94 @@ +/* + * + * Copyright 2015-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_CLIENT_CONFIG_RESOLVER_H +#define GRPC_CORE_CLIENT_CONFIG_RESOLVER_H + +#include "src/core/client_config/client_config.h" +#include "src/core/client_config/subchannel.h" +#include "src/core/iomgr/iomgr.h" + +typedef struct grpc_resolver grpc_resolver; +typedef struct grpc_resolver_vtable grpc_resolver_vtable; + +/** grpc_resolver provides grpc_client_config objects to grpc_channel + objects */ +struct grpc_resolver { + const grpc_resolver_vtable *vtable; + gpr_refcount refs; +}; + +struct grpc_resolver_vtable { + void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver); + void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver); + void (*channel_saw_error)(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver); + void (*next)(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver, + grpc_client_config **target_config, grpc_closure *on_complete); +}; + +#ifdef GRPC_RESOLVER_REFCOUNT_DEBUG +#define GRPC_RESOLVER_REF(p, r) grpc_resolver_ref((p), __FILE__, __LINE__, (r)) +#define GRPC_RESOLVER_UNREF(cl, p, r) \ + grpc_resolver_unref((cl), (p), __FILE__, __LINE__, (r)) +void grpc_resolver_ref(grpc_resolver *policy, const char *file, int line, + const char *reason); +void grpc_resolver_unref(grpc_resolver *policy, grpc_closure_list *closure_list, + const char *file, int line, const char *reason); +#else +#define GRPC_RESOLVER_REF(p, r) grpc_resolver_ref((p)) +#define GRPC_RESOLVER_UNREF(cl, p, r) grpc_resolver_unref((cl), (p)) +void grpc_resolver_ref(grpc_resolver *policy); +void grpc_resolver_unref(grpc_exec_ctx *exec_ctx, grpc_resolver *policy); +#endif + +void grpc_resolver_init(grpc_resolver *resolver, + const grpc_resolver_vtable *vtable); + +void grpc_resolver_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver); + +/** Notification that the channel has seen an error on some address. + Can be used as a hint that re-resolution is desirable soon. */ +void grpc_resolver_channel_saw_error(grpc_exec_ctx *exec_ctx, + grpc_resolver *resolver); + +/** Get the next client config. Called by the channel to fetch a new + configuration. Expected to set *target_config with a new configuration, + and then schedule on_complete for execution. + + If resolution is fatally broken, set *target_config to NULL and + schedule on_complete. */ +void grpc_resolver_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver, + grpc_client_config **target_config, + grpc_closure *on_complete); + +#endif /* GRPC_CORE_CLIENT_CONFIG_RESOLVER_H */ diff --git a/src/core/lib/client_config/resolver_factory.c b/src/core/lib/client_config/resolver_factory.c new file mode 100644 index 0000000000..e7e9196ac4 --- /dev/null +++ b/src/core/lib/client_config/resolver_factory.c @@ -0,0 +1,55 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/client_config/resolver_factory.h" + +void grpc_resolver_factory_ref(grpc_resolver_factory* factory) { + factory->vtable->ref(factory); +} + +void grpc_resolver_factory_unref(grpc_resolver_factory* factory) { + factory->vtable->unref(factory); +} + +/** Create a resolver instance for a name */ +grpc_resolver* grpc_resolver_factory_create_resolver( + grpc_resolver_factory* factory, grpc_resolver_args* args) { + if (factory == NULL) return NULL; + return factory->vtable->create_resolver(factory, args); +} + +char* grpc_resolver_factory_get_default_authority( + grpc_resolver_factory* factory, grpc_uri* uri) { + if (factory == NULL) return NULL; + return factory->vtable->get_default_authority(factory, uri); +} diff --git a/src/core/lib/client_config/resolver_factory.h b/src/core/lib/client_config/resolver_factory.h new file mode 100644 index 0000000000..477f8db7f7 --- /dev/null +++ b/src/core/lib/client_config/resolver_factory.h @@ -0,0 +1,82 @@ +/* + * + * Copyright 2015-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_CLIENT_CONFIG_RESOLVER_FACTORY_H +#define GRPC_CORE_CLIENT_CONFIG_RESOLVER_FACTORY_H + +#include "src/core/client_config/resolver.h" +#include "src/core/client_config/subchannel_factory.h" +#include "src/core/client_config/uri_parser.h" + +typedef struct grpc_resolver_factory grpc_resolver_factory; +typedef struct grpc_resolver_factory_vtable grpc_resolver_factory_vtable; + +/** grpc_resolver provides grpc_client_config objects to grpc_channel + objects */ +struct grpc_resolver_factory { + const grpc_resolver_factory_vtable *vtable; +}; + +typedef struct grpc_resolver_args { + grpc_uri *uri; + grpc_subchannel_factory *subchannel_factory; +} grpc_resolver_args; + +struct grpc_resolver_factory_vtable { + void (*ref)(grpc_resolver_factory *factory); + void (*unref)(grpc_resolver_factory *factory); + + /** Implementation of grpc_resolver_factory_create_resolver */ + grpc_resolver *(*create_resolver)(grpc_resolver_factory *factory, + grpc_resolver_args *args); + + /** Implementation of grpc_resolver_factory_get_default_authority */ + char *(*get_default_authority)(grpc_resolver_factory *factory, grpc_uri *uri); + + /** URI scheme that this factory implements */ + const char *scheme; +}; + +void grpc_resolver_factory_ref(grpc_resolver_factory *resolver); +void grpc_resolver_factory_unref(grpc_resolver_factory *resolver); + +/** Create a resolver instance for a name */ +grpc_resolver *grpc_resolver_factory_create_resolver( + grpc_resolver_factory *factory, grpc_resolver_args *args); + +/** Return a (freshly allocated with gpr_malloc) string representing + the default authority to use for this scheme. */ +char *grpc_resolver_factory_get_default_authority( + grpc_resolver_factory *factory, grpc_uri *uri); + +#endif /* GRPC_CORE_CLIENT_CONFIG_RESOLVER_FACTORY_H */ diff --git a/src/core/lib/client_config/resolver_registry.c b/src/core/lib/client_config/resolver_registry.c new file mode 100644 index 0000000000..89a945c2d3 --- /dev/null +++ b/src/core/lib/client_config/resolver_registry.c @@ -0,0 +1,137 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/client_config/resolver_registry.h" + +#include + +#include +#include +#include + +#define MAX_RESOLVERS 10 + +static grpc_resolver_factory *g_all_of_the_resolvers[MAX_RESOLVERS]; +static int g_number_of_resolvers = 0; + +static char *g_default_resolver_prefix; + +void grpc_resolver_registry_init(const char *default_resolver_prefix) { + g_number_of_resolvers = 0; + g_default_resolver_prefix = gpr_strdup(default_resolver_prefix); +} + +void grpc_resolver_registry_shutdown(void) { + int i; + for (i = 0; i < g_number_of_resolvers; i++) { + grpc_resolver_factory_unref(g_all_of_the_resolvers[i]); + } + gpr_free(g_default_resolver_prefix); +} + +void grpc_register_resolver_type(grpc_resolver_factory *factory) { + int i; + for (i = 0; i < g_number_of_resolvers; i++) { + GPR_ASSERT(0 != strcmp(factory->vtable->scheme, + g_all_of_the_resolvers[i]->vtable->scheme)); + } + GPR_ASSERT(g_number_of_resolvers != MAX_RESOLVERS); + grpc_resolver_factory_ref(factory); + g_all_of_the_resolvers[g_number_of_resolvers++] = factory; +} + +static grpc_resolver_factory *lookup_factory(grpc_uri *uri) { + int i; + + /* handling NULL uri's here simplifies grpc_resolver_create */ + if (!uri) return NULL; + + for (i = 0; i < g_number_of_resolvers; i++) { + if (0 == strcmp(uri->scheme, g_all_of_the_resolvers[i]->vtable->scheme)) { + return g_all_of_the_resolvers[i]; + } + } + + return NULL; +} + +static grpc_resolver_factory *resolve_factory(const char *target, + grpc_uri **uri) { + char *tmp; + grpc_resolver_factory *factory = NULL; + + GPR_ASSERT(uri != NULL); + *uri = grpc_uri_parse(target, 1); + factory = lookup_factory(*uri); + if (factory == NULL) { + if (g_default_resolver_prefix != NULL) { + grpc_uri_destroy(*uri); + gpr_asprintf(&tmp, "%s%s", g_default_resolver_prefix, target); + *uri = grpc_uri_parse(tmp, 1); + factory = lookup_factory(*uri); + if (factory == NULL) { + grpc_uri_destroy(grpc_uri_parse(target, 0)); + grpc_uri_destroy(grpc_uri_parse(tmp, 0)); + gpr_log(GPR_ERROR, "don't know how to resolve '%s' or '%s'", target, + tmp); + } + gpr_free(tmp); + } else { + grpc_uri_destroy(grpc_uri_parse(target, 0)); + gpr_log(GPR_ERROR, "don't know how to resolve '%s'", target); + } + } + return factory; +} + +grpc_resolver *grpc_resolver_create( + const char *target, grpc_subchannel_factory *subchannel_factory) { + grpc_uri *uri = NULL; + grpc_resolver_factory *factory = resolve_factory(target, &uri); + grpc_resolver *resolver; + grpc_resolver_args args; + memset(&args, 0, sizeof(args)); + args.uri = uri; + args.subchannel_factory = subchannel_factory; + resolver = grpc_resolver_factory_create_resolver(factory, &args); + grpc_uri_destroy(uri); + return resolver; +} + +char *grpc_get_default_authority(const char *target) { + grpc_uri *uri = NULL; + grpc_resolver_factory *factory = resolve_factory(target, &uri); + char *authority = grpc_resolver_factory_get_default_authority(factory, uri); + grpc_uri_destroy(uri); + return authority; +} diff --git a/src/core/lib/client_config/resolver_registry.h b/src/core/lib/client_config/resolver_registry.h new file mode 100644 index 0000000000..1e4cebee0b --- /dev/null +++ b/src/core/lib/client_config/resolver_registry.h @@ -0,0 +1,65 @@ +/* + * + * Copyright 2015-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_CLIENT_CONFIG_RESOLVER_REGISTRY_H +#define GRPC_CORE_CLIENT_CONFIG_RESOLVER_REGISTRY_H + +#include "src/core/client_config/resolver_factory.h" + +void grpc_resolver_registry_init(const char *default_prefix); +void grpc_resolver_registry_shutdown(void); + +/** Register a resolver type. + URI's of \a scheme will be resolved with the given resolver. + If \a priority is greater than zero, then the resolver will be eligible + to resolve names that are passed in with no scheme. Higher priority + resolvers will be tried before lower priority schemes. */ +void grpc_register_resolver_type(grpc_resolver_factory *factory); + +/** Create a resolver given \a target. + First tries to parse \a target as a URI. If this succeeds, tries + to locate a registered resolver factory based on the URI scheme. + If parsing or location fails, prefixes default_prefix from + grpc_resolver_registry_init to target, and tries again (if default_prefix + was not NULL). + If a resolver factory was found, use it to instantiate a resolver and + return it. + If a resolver factory was not found, return NULL. */ +grpc_resolver *grpc_resolver_create( + const char *target, grpc_subchannel_factory *subchannel_factory); + +/** Given a target, return a (freshly allocated with gpr_malloc) string + representing the default authority to pass from a client. */ +char *grpc_get_default_authority(const char *target); + +#endif /* GRPC_CORE_CLIENT_CONFIG_RESOLVER_REGISTRY_H */ diff --git a/src/core/lib/client_config/resolvers/dns_resolver.c b/src/core/lib/client_config/resolvers/dns_resolver.c new file mode 100644 index 0000000000..2b2ee97e12 --- /dev/null +++ b/src/core/lib/client_config/resolvers/dns_resolver.c @@ -0,0 +1,309 @@ +/* + * + * Copyright 2015-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/client_config/resolvers/dns_resolver.h" + +#include + +#include +#include +#include + +#include "src/core/client_config/lb_policy_registry.h" +#include "src/core/iomgr/resolve_address.h" +#include "src/core/iomgr/timer.h" +#include "src/core/support/backoff.h" +#include "src/core/support/string.h" + +#define BACKOFF_MULTIPLIER 1.6 +#define BACKOFF_JITTER 0.2 +#define BACKOFF_MIN_SECONDS 1 +#define BACKOFF_MAX_SECONDS 120 + +typedef struct { + /** base class: must be first */ + grpc_resolver base; + /** refcount */ + gpr_refcount refs; + /** name to resolve */ + char *name; + /** default port to use */ + char *default_port; + /** subchannel factory */ + grpc_subchannel_factory *subchannel_factory; + /** load balancing policy name */ + char *lb_policy_name; + + /** mutex guarding the rest of the state */ + gpr_mu mu; + /** are we currently resolving? */ + int resolving; + /** which version of resolved_config have we published? */ + int published_version; + /** which version of resolved_config is current? */ + int resolved_version; + /** pending next completion, or NULL */ + grpc_closure *next_completion; + /** target config address for next completion */ + grpc_client_config **target_config; + /** current (fully resolved) config */ + grpc_client_config *resolved_config; + /** retry timer */ + bool have_retry_timer; + grpc_timer retry_timer; + /** retry backoff state */ + gpr_backoff backoff_state; +} dns_resolver; + +static void dns_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *r); + +static void dns_start_resolving_locked(dns_resolver *r); +static void dns_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx, + dns_resolver *r); + +static void dns_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *r); +static void dns_channel_saw_error(grpc_exec_ctx *exec_ctx, grpc_resolver *r); +static void dns_next(grpc_exec_ctx *exec_ctx, grpc_resolver *r, + grpc_client_config **target_config, + grpc_closure *on_complete); + +static const grpc_resolver_vtable dns_resolver_vtable = { + dns_destroy, dns_shutdown, dns_channel_saw_error, dns_next}; + +static void dns_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver) { + dns_resolver *r = (dns_resolver *)resolver; + gpr_mu_lock(&r->mu); + if (r->have_retry_timer) { + grpc_timer_cancel(exec_ctx, &r->retry_timer); + } + if (r->next_completion != NULL) { + *r->target_config = NULL; + grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, true, NULL); + r->next_completion = NULL; + } + gpr_mu_unlock(&r->mu); +} + +static void dns_channel_saw_error(grpc_exec_ctx *exec_ctx, + grpc_resolver *resolver) { + dns_resolver *r = (dns_resolver *)resolver; + gpr_mu_lock(&r->mu); + if (!r->resolving) { + gpr_backoff_reset(&r->backoff_state); + dns_start_resolving_locked(r); + } + gpr_mu_unlock(&r->mu); +} + +static void dns_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver, + grpc_client_config **target_config, + grpc_closure *on_complete) { + dns_resolver *r = (dns_resolver *)resolver; + gpr_mu_lock(&r->mu); + GPR_ASSERT(!r->next_completion); + r->next_completion = on_complete; + r->target_config = target_config; + if (r->resolved_version == 0 && !r->resolving) { + gpr_backoff_reset(&r->backoff_state); + dns_start_resolving_locked(r); + } else { + dns_maybe_finish_next_locked(exec_ctx, r); + } + gpr_mu_unlock(&r->mu); +} + +static void dns_on_retry_timer(grpc_exec_ctx *exec_ctx, void *arg, + bool success) { + dns_resolver *r = arg; + + gpr_mu_lock(&r->mu); + r->have_retry_timer = false; + if (success) { + if (!r->resolving) { + dns_start_resolving_locked(r); + } + } + gpr_mu_unlock(&r->mu); + + GRPC_RESOLVER_UNREF(exec_ctx, &r->base, "retry-timer"); +} + +static void dns_on_resolved(grpc_exec_ctx *exec_ctx, void *arg, + grpc_resolved_addresses *addresses) { + dns_resolver *r = arg; + grpc_client_config *config = NULL; + grpc_subchannel **subchannels; + grpc_subchannel_args args; + grpc_lb_policy *lb_policy; + size_t i; + gpr_mu_lock(&r->mu); + GPR_ASSERT(r->resolving); + r->resolving = 0; + if (addresses != NULL) { + grpc_lb_policy_args lb_policy_args; + config = grpc_client_config_create(); + subchannels = gpr_malloc(sizeof(grpc_subchannel *) * addresses->naddrs); + size_t naddrs = 0; + for (i = 0; i < addresses->naddrs; i++) { + memset(&args, 0, sizeof(args)); + args.addr = (struct sockaddr *)(addresses->addrs[i].addr); + args.addr_len = (size_t)addresses->addrs[i].len; + grpc_subchannel *subchannel = grpc_subchannel_factory_create_subchannel( + exec_ctx, r->subchannel_factory, &args); + if (subchannel != NULL) { + subchannels[naddrs++] = subchannel; + } + } + memset(&lb_policy_args, 0, sizeof(lb_policy_args)); + lb_policy_args.subchannels = subchannels; + lb_policy_args.num_subchannels = naddrs; + lb_policy = grpc_lb_policy_create(r->lb_policy_name, &lb_policy_args); + if (lb_policy != NULL) { + grpc_client_config_set_lb_policy(config, lb_policy); + GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "construction"); + } + grpc_resolved_addresses_destroy(addresses); + gpr_free(subchannels); + } else { + 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", + timeout.tv_sec, timeout.tv_nsec); + GPR_ASSERT(!r->have_retry_timer); + r->have_retry_timer = true; + GRPC_RESOLVER_REF(&r->base, "retry-timer"); + grpc_timer_init(exec_ctx, &r->retry_timer, next_try, dns_on_retry_timer, r, + now); + } + if (r->resolved_config) { + grpc_client_config_unref(exec_ctx, r->resolved_config); + } + r->resolved_config = config; + r->resolved_version++; + dns_maybe_finish_next_locked(exec_ctx, r); + gpr_mu_unlock(&r->mu); + + GRPC_RESOLVER_UNREF(exec_ctx, &r->base, "dns-resolving"); +} + +static void dns_start_resolving_locked(dns_resolver *r) { + GRPC_RESOLVER_REF(&r->base, "dns-resolving"); + GPR_ASSERT(!r->resolving); + r->resolving = 1; + grpc_resolve_address(r->name, r->default_port, dns_on_resolved, r); +} + +static void dns_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx, + dns_resolver *r) { + if (r->next_completion != NULL && + r->resolved_version != r->published_version) { + *r->target_config = r->resolved_config; + if (r->resolved_config) { + grpc_client_config_ref(r->resolved_config); + } + grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, true, NULL); + r->next_completion = NULL; + r->published_version = r->resolved_version; + } +} + +static void dns_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *gr) { + dns_resolver *r = (dns_resolver *)gr; + gpr_mu_destroy(&r->mu); + if (r->resolved_config) { + grpc_client_config_unref(exec_ctx, r->resolved_config); + } + grpc_subchannel_factory_unref(exec_ctx, r->subchannel_factory); + gpr_free(r->name); + gpr_free(r->default_port); + gpr_free(r->lb_policy_name); + gpr_free(r); +} + +static grpc_resolver *dns_create(grpc_resolver_args *args, + const char *default_port, + const char *lb_policy_name) { + dns_resolver *r; + const char *path = args->uri->path; + + if (0 != strcmp(args->uri->authority, "")) { + gpr_log(GPR_ERROR, "authority based dns uri's not supported"); + return NULL; + } + + if (path[0] == '/') ++path; + + r = gpr_malloc(sizeof(dns_resolver)); + memset(r, 0, sizeof(*r)); + gpr_ref_init(&r->refs, 1); + gpr_mu_init(&r->mu); + grpc_resolver_init(&r->base, &dns_resolver_vtable); + r->name = gpr_strdup(path); + r->default_port = gpr_strdup(default_port); + r->subchannel_factory = args->subchannel_factory; + gpr_backoff_init(&r->backoff_state, BACKOFF_MULTIPLIER, BACKOFF_JITTER, + BACKOFF_MIN_SECONDS * 1000, BACKOFF_MAX_SECONDS * 1000); + grpc_subchannel_factory_ref(r->subchannel_factory); + r->lb_policy_name = gpr_strdup(lb_policy_name); + return &r->base; +} + +/* + * FACTORY + */ + +static void dns_factory_ref(grpc_resolver_factory *factory) {} + +static void dns_factory_unref(grpc_resolver_factory *factory) {} + +static grpc_resolver *dns_factory_create_resolver( + grpc_resolver_factory *factory, grpc_resolver_args *args) { + return dns_create(args, "https", "pick_first"); +} + +char *dns_factory_get_default_host_name(grpc_resolver_factory *factory, + grpc_uri *uri) { + const char *path = uri->path; + if (path[0] == '/') ++path; + return gpr_strdup(path); +} + +static const grpc_resolver_factory_vtable dns_factory_vtable = { + dns_factory_ref, dns_factory_unref, dns_factory_create_resolver, + dns_factory_get_default_host_name, "dns"}; +static grpc_resolver_factory dns_resolver_factory = {&dns_factory_vtable}; + +grpc_resolver_factory *grpc_dns_resolver_factory_create() { + return &dns_resolver_factory; +} diff --git a/src/core/lib/client_config/resolvers/dns_resolver.h b/src/core/lib/client_config/resolvers/dns_resolver.h new file mode 100644 index 0000000000..b24280b507 --- /dev/null +++ b/src/core/lib/client_config/resolvers/dns_resolver.h @@ -0,0 +1,42 @@ +/* + * + * Copyright 2015-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_CLIENT_CONFIG_RESOLVERS_DNS_RESOLVER_H +#define GRPC_CORE_CLIENT_CONFIG_RESOLVERS_DNS_RESOLVER_H + +#include "src/core/client_config/resolver_factory.h" + +/** Create a dns resolver factory */ +grpc_resolver_factory *grpc_dns_resolver_factory_create(void); + +#endif /* GRPC_CORE_CLIENT_CONFIG_RESOLVERS_DNS_RESOLVER_H */ diff --git a/src/core/lib/client_config/resolvers/sockaddr_resolver.c b/src/core/lib/client_config/resolvers/sockaddr_resolver.c new file mode 100644 index 0000000000..3cb7d79b67 --- /dev/null +++ b/src/core/lib/client_config/resolvers/sockaddr_resolver.c @@ -0,0 +1,372 @@ +/* + * + * Copyright 2015-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 + +#include "src/core/client_config/resolvers/sockaddr_resolver.h" + +#include +#include + +#include +#include +#include + +#include "src/core/client_config/lb_policy_registry.h" +#include "src/core/iomgr/resolve_address.h" +#include "src/core/iomgr/unix_sockets_posix.h" +#include "src/core/support/string.h" + +typedef struct { + /** base class: must be first */ + grpc_resolver base; + /** refcount */ + gpr_refcount refs; + /** subchannel factory */ + grpc_subchannel_factory *subchannel_factory; + /** load balancing policy name */ + char *lb_policy_name; + + /** the addresses that we've 'resolved' */ + struct sockaddr_storage *addrs; + /** the corresponding length of the addresses */ + size_t *addrs_len; + /** how many elements in \a addrs */ + size_t num_addrs; + + /** mutex guarding the rest of the state */ + gpr_mu mu; + /** have we published? */ + int published; + /** pending next completion, or NULL */ + grpc_closure *next_completion; + /** target config address for next completion */ + grpc_client_config **target_config; +} sockaddr_resolver; + +static void sockaddr_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *r); + +static void sockaddr_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx, + sockaddr_resolver *r); + +static void sockaddr_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *r); +static void sockaddr_channel_saw_error(grpc_exec_ctx *exec_ctx, + grpc_resolver *r); +static void sockaddr_next(grpc_exec_ctx *exec_ctx, grpc_resolver *r, + grpc_client_config **target_config, + grpc_closure *on_complete); + +static const grpc_resolver_vtable sockaddr_resolver_vtable = { + sockaddr_destroy, sockaddr_shutdown, sockaddr_channel_saw_error, + sockaddr_next}; + +static void sockaddr_shutdown(grpc_exec_ctx *exec_ctx, + grpc_resolver *resolver) { + sockaddr_resolver *r = (sockaddr_resolver *)resolver; + gpr_mu_lock(&r->mu); + if (r->next_completion != NULL) { + *r->target_config = NULL; + grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, true, NULL); + r->next_completion = NULL; + } + gpr_mu_unlock(&r->mu); +} + +static void sockaddr_channel_saw_error(grpc_exec_ctx *exec_ctx, + grpc_resolver *resolver) { + sockaddr_resolver *r = (sockaddr_resolver *)resolver; + gpr_mu_lock(&r->mu); + r->published = 0; + sockaddr_maybe_finish_next_locked(exec_ctx, r); + gpr_mu_unlock(&r->mu); +} + +static void sockaddr_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver, + grpc_client_config **target_config, + grpc_closure *on_complete) { + sockaddr_resolver *r = (sockaddr_resolver *)resolver; + gpr_mu_lock(&r->mu); + GPR_ASSERT(!r->next_completion); + r->next_completion = on_complete; + r->target_config = target_config; + sockaddr_maybe_finish_next_locked(exec_ctx, r); + gpr_mu_unlock(&r->mu); +} + +static void sockaddr_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx, + sockaddr_resolver *r) { + grpc_client_config *cfg; + grpc_lb_policy *lb_policy; + grpc_lb_policy_args lb_policy_args; + grpc_subchannel **subchannels; + grpc_subchannel_args args; + + if (r->next_completion != NULL && !r->published) { + size_t i; + cfg = grpc_client_config_create(); + subchannels = gpr_malloc(sizeof(grpc_subchannel *) * r->num_addrs); + for (i = 0; i < r->num_addrs; i++) { + memset(&args, 0, sizeof(args)); + args.addr = (struct sockaddr *)&r->addrs[i]; + args.addr_len = r->addrs_len[i]; + subchannels[i] = grpc_subchannel_factory_create_subchannel( + exec_ctx, r->subchannel_factory, &args); + } + memset(&lb_policy_args, 0, sizeof(lb_policy_args)); + lb_policy_args.subchannels = subchannels; + lb_policy_args.num_subchannels = r->num_addrs; + lb_policy = grpc_lb_policy_create(r->lb_policy_name, &lb_policy_args); + gpr_free(subchannels); + grpc_client_config_set_lb_policy(cfg, lb_policy); + GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "sockaddr"); + r->published = 1; + *r->target_config = cfg; + grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, true, NULL); + r->next_completion = NULL; + } +} + +static void sockaddr_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *gr) { + sockaddr_resolver *r = (sockaddr_resolver *)gr; + gpr_mu_destroy(&r->mu); + grpc_subchannel_factory_unref(exec_ctx, r->subchannel_factory); + gpr_free(r->addrs); + gpr_free(r->addrs_len); + gpr_free(r->lb_policy_name); + gpr_free(r); +} + +static char *ip_get_default_authority(grpc_uri *uri) { + const char *path = uri->path; + if (path[0] == '/') ++path; + return gpr_strdup(path); +} + +static char *ipv4_get_default_authority(grpc_resolver_factory *factory, + grpc_uri *uri) { + return ip_get_default_authority(uri); +} + +static char *ipv6_get_default_authority(grpc_resolver_factory *factory, + grpc_uri *uri) { + return ip_get_default_authority(uri); +} + +static int parse_ipv4(grpc_uri *uri, struct sockaddr_storage *addr, + size_t *len) { + const char *host_port = uri->path; + char *host; + char *port; + int port_num; + int result = 0; + struct sockaddr_in *in = (struct sockaddr_in *)addr; + + if (*host_port == '/') ++host_port; + if (!gpr_split_host_port(host_port, &host, &port)) { + return 0; + } + + memset(in, 0, sizeof(*in)); + *len = sizeof(*in); + in->sin_family = AF_INET; + if (inet_pton(AF_INET, host, &in->sin_addr) == 0) { + gpr_log(GPR_ERROR, "invalid ipv4 address: '%s'", host); + goto done; + } + + if (port != NULL) { + if (sscanf(port, "%d", &port_num) != 1 || port_num < 0 || + port_num > 65535) { + gpr_log(GPR_ERROR, "invalid ipv4 port: '%s'", port); + goto done; + } + in->sin_port = htons((uint16_t)port_num); + } else { + gpr_log(GPR_ERROR, "no port given for ipv4 scheme"); + goto done; + } + + result = 1; +done: + gpr_free(host); + gpr_free(port); + return result; +} + +static int parse_ipv6(grpc_uri *uri, struct sockaddr_storage *addr, + size_t *len) { + const char *host_port = uri->path; + char *host; + char *port; + int port_num; + int result = 0; + struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)addr; + + if (*host_port == '/') ++host_port; + if (!gpr_split_host_port(host_port, &host, &port)) { + return 0; + } + + memset(in6, 0, sizeof(*in6)); + *len = sizeof(*in6); + in6->sin6_family = AF_INET6; + if (inet_pton(AF_INET6, host, &in6->sin6_addr) == 0) { + gpr_log(GPR_ERROR, "invalid ipv6 address: '%s'", host); + goto done; + } + + if (port != NULL) { + if (sscanf(port, "%d", &port_num) != 1 || port_num < 0 || + port_num > 65535) { + gpr_log(GPR_ERROR, "invalid ipv6 port: '%s'", port); + goto done; + } + in6->sin6_port = htons((uint16_t)port_num); + } else { + gpr_log(GPR_ERROR, "no port given for ipv6 scheme"); + goto done; + } + + result = 1; +done: + gpr_free(host); + gpr_free(port); + return result; +} + +static void do_nothing(void *ignored) {} + +static grpc_resolver *sockaddr_create( + grpc_resolver_args *args, const char *default_lb_policy_name, + int parse(grpc_uri *uri, struct sockaddr_storage *dst, size_t *len)) { + size_t i; + int errors_found = 0; /* GPR_FALSE */ + sockaddr_resolver *r; + gpr_slice path_slice; + gpr_slice_buffer path_parts; + + if (0 != strcmp(args->uri->authority, "")) { + gpr_log(GPR_ERROR, "authority based uri's not supported by the %s scheme", + args->uri->scheme); + return NULL; + } + + r = gpr_malloc(sizeof(sockaddr_resolver)); + memset(r, 0, sizeof(*r)); + + r->lb_policy_name = NULL; + if (0 != strcmp(args->uri->query, "")) { + gpr_slice query_slice; + gpr_slice_buffer query_parts; + + query_slice = + gpr_slice_new(args->uri->query, strlen(args->uri->query), do_nothing); + gpr_slice_buffer_init(&query_parts); + gpr_slice_split(query_slice, "=", &query_parts); + GPR_ASSERT(query_parts.count == 2); + if (0 == gpr_slice_str_cmp(query_parts.slices[0], "lb_policy")) { + r->lb_policy_name = gpr_dump_slice(query_parts.slices[1], GPR_DUMP_ASCII); + } + gpr_slice_buffer_destroy(&query_parts); + gpr_slice_unref(query_slice); + } + if (r->lb_policy_name == NULL) { + r->lb_policy_name = gpr_strdup(default_lb_policy_name); + } + + path_slice = + gpr_slice_new(args->uri->path, strlen(args->uri->path), do_nothing); + gpr_slice_buffer_init(&path_parts); + + gpr_slice_split(path_slice, ",", &path_parts); + r->num_addrs = path_parts.count; + r->addrs = gpr_malloc(sizeof(struct sockaddr_storage) * r->num_addrs); + r->addrs_len = gpr_malloc(sizeof(*r->addrs_len) * r->num_addrs); + + for (i = 0; i < r->num_addrs; i++) { + grpc_uri ith_uri = *args->uri; + char *part_str = gpr_dump_slice(path_parts.slices[i], GPR_DUMP_ASCII); + ith_uri.path = part_str; + if (!parse(&ith_uri, &r->addrs[i], &r->addrs_len[i])) { + errors_found = 1; /* GPR_TRUE */ + } + gpr_free(part_str); + if (errors_found) break; + } + + gpr_slice_buffer_destroy(&path_parts); + gpr_slice_unref(path_slice); + if (errors_found) { + gpr_free(r->lb_policy_name); + gpr_free(r->addrs); + gpr_free(r->addrs_len); + gpr_free(r); + return NULL; + } + + gpr_ref_init(&r->refs, 1); + gpr_mu_init(&r->mu); + grpc_resolver_init(&r->base, &sockaddr_resolver_vtable); + r->subchannel_factory = args->subchannel_factory; + grpc_subchannel_factory_ref(r->subchannel_factory); + + return &r->base; +} + +/* + * FACTORY + */ + +static void sockaddr_factory_ref(grpc_resolver_factory *factory) {} + +static void sockaddr_factory_unref(grpc_resolver_factory *factory) {} + +#define DECL_FACTORY(name, prefix) \ + static grpc_resolver *name##_factory_create_resolver( \ + grpc_resolver_factory *factory, grpc_resolver_args *args) { \ + return sockaddr_create(args, "pick_first", prefix##parse_##name); \ + } \ + static const grpc_resolver_factory_vtable name##_factory_vtable = { \ + sockaddr_factory_ref, sockaddr_factory_unref, \ + name##_factory_create_resolver, prefix##name##_get_default_authority, \ + #name}; \ + static grpc_resolver_factory name##_resolver_factory = { \ + &name##_factory_vtable}; \ + grpc_resolver_factory *grpc_##name##_resolver_factory_create() { \ + return &name##_resolver_factory; \ + } + +#ifdef GPR_HAVE_UNIX_SOCKET +DECL_FACTORY(unix, grpc_) +#endif +DECL_FACTORY(ipv4, ) DECL_FACTORY(ipv6, ) diff --git a/src/core/lib/client_config/resolvers/sockaddr_resolver.h b/src/core/lib/client_config/resolvers/sockaddr_resolver.h new file mode 100644 index 0000000000..f050329431 --- /dev/null +++ b/src/core/lib/client_config/resolvers/sockaddr_resolver.h @@ -0,0 +1,50 @@ +/* + * + * Copyright 2015-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_CLIENT_CONFIG_RESOLVERS_SOCKADDR_RESOLVER_H +#define GRPC_CORE_CLIENT_CONFIG_RESOLVERS_SOCKADDR_RESOLVER_H + +#include + +#include "src/core/client_config/resolver_factory.h" + +grpc_resolver_factory *grpc_ipv4_resolver_factory_create(void); + +grpc_resolver_factory *grpc_ipv6_resolver_factory_create(void); + +#ifdef GPR_POSIX_SOCKET +/** Create a unix resolver factory */ +grpc_resolver_factory *grpc_unix_resolver_factory_create(void); +#endif + +#endif /* GRPC_CORE_CLIENT_CONFIG_RESOLVERS_SOCKADDR_RESOLVER_H */ diff --git a/src/core/lib/client_config/resolvers/zookeeper_resolver.c b/src/core/lib/client_config/resolvers/zookeeper_resolver.c new file mode 100644 index 0000000000..e0e18792a2 --- /dev/null +++ b/src/core/lib/client_config/resolvers/zookeeper_resolver.c @@ -0,0 +1,520 @@ +/* + * + * Copyright 2015-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/client_config/resolvers/zookeeper_resolver.h" + +#include + +#include +#include + +#include +#include + +#include "src/core/client_config/lb_policy_registry.h" +#include "src/core/client_config/resolver_registry.h" +#include "src/core/iomgr/resolve_address.h" +#include "src/core/json/json.h" +#include "src/core/support/string.h" +#include "src/core/surface/api_trace.h" + +/** Zookeeper session expiration time in milliseconds */ +#define GRPC_ZOOKEEPER_SESSION_TIMEOUT 15000 + +typedef struct { + /** base class: must be first */ + grpc_resolver base; + /** refcount */ + gpr_refcount refs; + /** name to resolve */ + char *name; + /** subchannel factory */ + grpc_subchannel_factory *subchannel_factory; + /** load balancing policy name */ + char *lb_policy_name; + + /** mutex guarding the rest of the state */ + gpr_mu mu; + /** are we currently resolving? */ + int resolving; + /** which version of resolved_config have we published? */ + int published_version; + /** which version of resolved_config is current? */ + int resolved_version; + /** pending next completion, or NULL */ + grpc_closure *next_completion; + /** target config address for next completion */ + grpc_client_config **target_config; + /** current (fully resolved) config */ + grpc_client_config *resolved_config; + + /** zookeeper handle */ + zhandle_t *zookeeper_handle; + /** zookeeper resolved addresses */ + grpc_resolved_addresses *resolved_addrs; + /** total number of addresses to be resolved */ + int resolved_total; + /** number of addresses resolved */ + int resolved_num; +} zookeeper_resolver; + +static void zookeeper_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *r); + +static void zookeeper_start_resolving_locked(zookeeper_resolver *r); +static void zookeeper_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx, + zookeeper_resolver *r); + +static void zookeeper_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *r); +static void zookeeper_channel_saw_error(grpc_exec_ctx *exec_ctx, + grpc_resolver *r); +static void zookeeper_next(grpc_exec_ctx *exec_ctx, grpc_resolver *r, + grpc_client_config **target_config, + grpc_closure *on_complete); + +static const grpc_resolver_vtable zookeeper_resolver_vtable = { + zookeeper_destroy, zookeeper_shutdown, zookeeper_channel_saw_error, + zookeeper_next}; + +static void zookeeper_shutdown(grpc_exec_ctx *exec_ctx, + grpc_resolver *resolver) { + zookeeper_resolver *r = (zookeeper_resolver *)resolver; + grpc_closure *call = NULL; + gpr_mu_lock(&r->mu); + if (r->next_completion != NULL) { + *r->target_config = NULL; + call = r->next_completion; + r->next_completion = NULL; + } + zookeeper_close(r->zookeeper_handle); + gpr_mu_unlock(&r->mu); + if (call != NULL) { + call->cb(exec_ctx, call->cb_arg, 1); + } +} + +static void zookeeper_channel_saw_error(grpc_exec_ctx *exec_ctx, + grpc_resolver *resolver) { + zookeeper_resolver *r = (zookeeper_resolver *)resolver; + gpr_mu_lock(&r->mu); + if (r->resolving == 0) { + zookeeper_start_resolving_locked(r); + } + gpr_mu_unlock(&r->mu); +} + +static void zookeeper_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver, + grpc_client_config **target_config, + grpc_closure *on_complete) { + zookeeper_resolver *r = (zookeeper_resolver *)resolver; + gpr_mu_lock(&r->mu); + GPR_ASSERT(r->next_completion == NULL); + r->next_completion = on_complete; + r->target_config = target_config; + if (r->resolved_version == 0 && r->resolving == 0) { + zookeeper_start_resolving_locked(r); + } else { + zookeeper_maybe_finish_next_locked(exec_ctx, r); + } + gpr_mu_unlock(&r->mu); +} + +/** Zookeeper global watcher for connection management + TODO: better connection management besides logs */ +static void zookeeper_global_watcher(zhandle_t *zookeeper_handle, int type, + int state, const char *path, + void *watcher_ctx) { + if (type == ZOO_SESSION_EVENT) { + if (state == ZOO_EXPIRED_SESSION_STATE) { + gpr_log(GPR_ERROR, "Zookeeper session expired"); + } else if (state == ZOO_AUTH_FAILED_STATE) { + gpr_log(GPR_ERROR, "Zookeeper authentication failed"); + } + } +} + +/** Zookeeper watcher triggered by changes to watched nodes + Once triggered, it tries to resolve again to get updated addresses */ +static void zookeeper_watcher(zhandle_t *zookeeper_handle, int type, int state, + const char *path, void *watcher_ctx) { + if (watcher_ctx != NULL) { + zookeeper_resolver *r = (zookeeper_resolver *)watcher_ctx; + if (state == ZOO_CONNECTED_STATE) { + gpr_mu_lock(&r->mu); + if (r->resolving == 0) { + zookeeper_start_resolving_locked(r); + } + gpr_mu_unlock(&r->mu); + } + } +} + +/** Callback function after getting all resolved addresses + Creates a subchannel for each address */ +static void zookeeper_on_resolved(grpc_exec_ctx *exec_ctx, void *arg, + grpc_resolved_addresses *addresses) { + zookeeper_resolver *r = arg; + grpc_client_config *config = NULL; + grpc_subchannel **subchannels; + grpc_subchannel_args args; + grpc_lb_policy *lb_policy; + size_t i; + if (addresses != NULL) { + grpc_lb_policy_args lb_policy_args; + config = grpc_client_config_create(); + subchannels = gpr_malloc(sizeof(grpc_subchannel *) * addresses->naddrs); + for (i = 0; i < addresses->naddrs; i++) { + memset(&args, 0, sizeof(args)); + args.addr = (struct sockaddr *)(addresses->addrs[i].addr); + args.addr_len = addresses->addrs[i].len; + subchannels[i] = grpc_subchannel_factory_create_subchannel( + exec_ctx, r->subchannel_factory, &args); + } + lb_policy_args.subchannels = subchannels; + lb_policy_args.num_subchannels = addresses->naddrs; + lb_policy = grpc_lb_policy_create(r->lb_policy_name, &lb_policy_args); + grpc_client_config_set_lb_policy(config, lb_policy); + GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "construction"); + grpc_resolved_addresses_destroy(addresses); + gpr_free(subchannels); + } + gpr_mu_lock(&r->mu); + GPR_ASSERT(r->resolving == 1); + r->resolving = 0; + if (r->resolved_config != NULL) { + grpc_client_config_unref(exec_ctx, r->resolved_config); + } + r->resolved_config = config; + r->resolved_version++; + zookeeper_maybe_finish_next_locked(exec_ctx, r); + gpr_mu_unlock(&r->mu); + + GRPC_RESOLVER_UNREF(exec_ctx, &r->base, "zookeeper-resolving"); +} + +/** Callback function for each DNS resolved address */ +static void zookeeper_dns_resolved(grpc_exec_ctx *exec_ctx, void *arg, + grpc_resolved_addresses *addresses) { + size_t i; + zookeeper_resolver *r = arg; + int resolve_done = 0; + + gpr_mu_lock(&r->mu); + r->resolved_num++; + r->resolved_addrs->addrs = + gpr_realloc(r->resolved_addrs->addrs, + sizeof(grpc_resolved_address) * + (r->resolved_addrs->naddrs + addresses->naddrs)); + for (i = 0; i < addresses->naddrs; i++) { + memcpy(r->resolved_addrs->addrs[i + r->resolved_addrs->naddrs].addr, + addresses->addrs[i].addr, addresses->addrs[i].len); + r->resolved_addrs->addrs[i + r->resolved_addrs->naddrs].len = + addresses->addrs[i].len; + } + + r->resolved_addrs->naddrs += addresses->naddrs; + grpc_resolved_addresses_destroy(addresses); + + /** Wait for all addresses to be resolved */ + resolve_done = (r->resolved_num == r->resolved_total); + gpr_mu_unlock(&r->mu); + if (resolve_done) { + zookeeper_on_resolved(exec_ctx, r, r->resolved_addrs); + } +} + +/** Parses JSON format address of a zookeeper node */ +static char *zookeeper_parse_address(const char *value, size_t value_len) { + grpc_json *json; + grpc_json *cur; + const char *host; + const char *port; + char *buffer; + char *address = NULL; + + buffer = gpr_malloc(value_len); + memcpy(buffer, value, value_len); + json = grpc_json_parse_string_with_len(buffer, value_len); + if (json != NULL) { + host = NULL; + port = NULL; + for (cur = json->child; cur != NULL; cur = cur->next) { + if (!strcmp(cur->key, "host")) { + host = cur->value; + if (port != NULL) { + break; + } + } else if (!strcmp(cur->key, "port")) { + port = cur->value; + if (host != NULL) { + break; + } + } + } + if (host != NULL && port != NULL) { + gpr_asprintf(&address, "%s:%s", host, port); + } + grpc_json_destroy(json); + } + gpr_free(buffer); + + return address; +} + +static void zookeeper_get_children_node_completion(int rc, const char *value, + int value_len, + const struct Stat *stat, + const void *arg) { + char *address = NULL; + zookeeper_resolver *r = (zookeeper_resolver *)arg; + int resolve_done = 0; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + + if (rc != 0) { + gpr_log(GPR_ERROR, "Error in getting a child node of %s", r->name); + grpc_exec_ctx_finish(&exec_ctx); + return; + } + + address = zookeeper_parse_address(value, (size_t)value_len); + if (address != NULL) { + /** Further resolves address by DNS */ + grpc_resolve_address(address, NULL, zookeeper_dns_resolved, r); + gpr_free(address); + } else { + gpr_log(GPR_ERROR, "Error in resolving a child node of %s", r->name); + gpr_mu_lock(&r->mu); + r->resolved_total--; + resolve_done = (r->resolved_num == r->resolved_total); + gpr_mu_unlock(&r->mu); + if (resolve_done) { + zookeeper_on_resolved(&exec_ctx, r, r->resolved_addrs); + } + } + + grpc_exec_ctx_finish(&exec_ctx); +} + +static void zookeeper_get_children_completion( + int rc, const struct String_vector *children, const void *arg) { + char *path; + int status; + int i; + zookeeper_resolver *r = (zookeeper_resolver *)arg; + + if (rc != 0) { + gpr_log(GPR_ERROR, "Error in getting zookeeper children of %s", r->name); + return; + } + + if (children->count == 0) { + gpr_log(GPR_ERROR, "Error in resolving zookeeper address %s", r->name); + return; + } + + r->resolved_addrs = gpr_malloc(sizeof(grpc_resolved_addresses)); + r->resolved_addrs->addrs = NULL; + r->resolved_addrs->naddrs = 0; + r->resolved_total = children->count; + + /** TODO: Replace expensive heap allocation with stack + if we can get maximum length of zookeeper path */ + for (i = 0; i < children->count; i++) { + gpr_asprintf(&path, "%s/%s", r->name, children->data[i]); + status = zoo_awget(r->zookeeper_handle, path, zookeeper_watcher, r, + zookeeper_get_children_node_completion, r); + gpr_free(path); + if (status != 0) { + gpr_log(GPR_ERROR, "Error in getting zookeeper node %s", path); + } + } +} + +static void zookeeper_get_node_completion(int rc, const char *value, + int value_len, + const struct Stat *stat, + const void *arg) { + int status; + char *address = NULL; + zookeeper_resolver *r = (zookeeper_resolver *)arg; + r->resolved_addrs = NULL; + r->resolved_total = 0; + r->resolved_num = 0; + + if (rc != 0) { + gpr_log(GPR_ERROR, "Error in getting zookeeper node %s", r->name); + return; + } + + /** If zookeeper node of path r->name does not have address + (i.e. service node), get its children */ + address = zookeeper_parse_address(value, (size_t)value_len); + if (address != NULL) { + r->resolved_addrs = gpr_malloc(sizeof(grpc_resolved_addresses)); + r->resolved_addrs->addrs = NULL; + r->resolved_addrs->naddrs = 0; + r->resolved_total = 1; + /** Further resolves address by DNS */ + grpc_resolve_address(address, NULL, zookeeper_dns_resolved, r); + gpr_free(address); + return; + } + + status = zoo_awget_children(r->zookeeper_handle, r->name, zookeeper_watcher, + r, zookeeper_get_children_completion, r); + if (status != 0) { + gpr_log(GPR_ERROR, "Error in getting zookeeper children of %s", r->name); + } +} + +static void zookeeper_resolve_address(zookeeper_resolver *r) { + int status; + status = zoo_awget(r->zookeeper_handle, r->name, zookeeper_watcher, r, + zookeeper_get_node_completion, r); + if (status != 0) { + gpr_log(GPR_ERROR, "Error in getting zookeeper node %s", r->name); + } +} + +static void zookeeper_start_resolving_locked(zookeeper_resolver *r) { + GRPC_RESOLVER_REF(&r->base, "zookeeper-resolving"); + GPR_ASSERT(r->resolving == 0); + r->resolving = 1; + zookeeper_resolve_address(r); +} + +static void zookeeper_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx, + zookeeper_resolver *r) { + if (r->next_completion != NULL && + r->resolved_version != r->published_version) { + *r->target_config = r->resolved_config; + if (r->resolved_config != NULL) { + grpc_client_config_ref(r->resolved_config); + } + grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, true, NULL); + r->next_completion = NULL; + r->published_version = r->resolved_version; + } +} + +static void zookeeper_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *gr) { + zookeeper_resolver *r = (zookeeper_resolver *)gr; + gpr_mu_destroy(&r->mu); + if (r->resolved_config != NULL) { + grpc_client_config_unref(exec_ctx, r->resolved_config); + } + grpc_subchannel_factory_unref(exec_ctx, r->subchannel_factory); + gpr_free(r->name); + gpr_free(r->lb_policy_name); + gpr_free(r); +} + +static grpc_resolver *zookeeper_create(grpc_resolver_args *args, + const char *lb_policy_name) { + zookeeper_resolver *r; + size_t length; + char *path = args->uri->path; + + if (0 == strcmp(args->uri->authority, "")) { + gpr_log(GPR_ERROR, "No authority specified in zookeeper uri"); + return NULL; + } + + /** Removes the trailing slash if exists */ + length = strlen(path); + if (length > 1 && path[length - 1] == '/') { + path[length - 1] = 0; + } + + r = gpr_malloc(sizeof(zookeeper_resolver)); + memset(r, 0, sizeof(*r)); + gpr_ref_init(&r->refs, 1); + gpr_mu_init(&r->mu); + grpc_resolver_init(&r->base, &zookeeper_resolver_vtable); + r->name = gpr_strdup(path); + + r->subchannel_factory = args->subchannel_factory; + grpc_subchannel_factory_ref(r->subchannel_factory); + + r->lb_policy_name = gpr_strdup(lb_policy_name); + + /** Initializes zookeeper client */ + zoo_set_debug_level(ZOO_LOG_LEVEL_WARN); + r->zookeeper_handle = + zookeeper_init(args->uri->authority, zookeeper_global_watcher, + GRPC_ZOOKEEPER_SESSION_TIMEOUT, 0, 0, 0); + if (r->zookeeper_handle == NULL) { + gpr_log(GPR_ERROR, "Unable to connect to zookeeper server"); + return NULL; + } + + return &r->base; +} + +static void zookeeper_plugin_init() { + grpc_register_resolver_type(grpc_zookeeper_resolver_factory_create()); +} + +void grpc_zookeeper_register() { + GRPC_API_TRACE("grpc_zookeeper_register(void)", 0, ()); + grpc_register_plugin(zookeeper_plugin_init, NULL); +} + +/* + * FACTORY + */ + +static void zookeeper_factory_ref(grpc_resolver_factory *factory) {} + +static void zookeeper_factory_unref(grpc_resolver_factory *factory) {} + +static char *zookeeper_factory_get_default_hostname( + grpc_resolver_factory *factory, grpc_uri *uri) { + return NULL; +} + +static grpc_resolver *zookeeper_factory_create_resolver( + grpc_resolver_factory *factory, grpc_resolver_args *args) { + return zookeeper_create(args, "pick_first"); +} + +static const grpc_resolver_factory_vtable zookeeper_factory_vtable = { + zookeeper_factory_ref, zookeeper_factory_unref, + zookeeper_factory_create_resolver, zookeeper_factory_get_default_hostname, + "zookeeper"}; + +static grpc_resolver_factory zookeeper_resolver_factory = { + &zookeeper_factory_vtable}; + +grpc_resolver_factory *grpc_zookeeper_resolver_factory_create() { + return &zookeeper_resolver_factory; +} diff --git a/src/core/lib/client_config/resolvers/zookeeper_resolver.h b/src/core/lib/client_config/resolvers/zookeeper_resolver.h new file mode 100644 index 0000000000..04bd3ca875 --- /dev/null +++ b/src/core/lib/client_config/resolvers/zookeeper_resolver.h @@ -0,0 +1,42 @@ +/* + * + * Copyright 2015-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_CLIENT_CONFIG_RESOLVERS_ZOOKEEPER_RESOLVER_H +#define GRPC_CORE_CLIENT_CONFIG_RESOLVERS_ZOOKEEPER_RESOLVER_H + +#include "src/core/client_config/resolver_factory.h" + +/** Create a zookeeper resolver factory */ +grpc_resolver_factory *grpc_zookeeper_resolver_factory_create(void); + +#endif /* GRPC_CORE_CLIENT_CONFIG_RESOLVERS_ZOOKEEPER_RESOLVER_H */ diff --git a/src/core/lib/client_config/subchannel.c b/src/core/lib/client_config/subchannel.c new file mode 100644 index 0000000000..c5cd504929 --- /dev/null +++ b/src/core/lib/client_config/subchannel.c @@ -0,0 +1,678 @@ +/* + * + * Copyright 2015-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/client_config/subchannel.h" + +#include + +#include +#include + +#include "src/core/channel/channel_args.h" +#include "src/core/channel/client_channel.h" +#include "src/core/channel/connected_channel.h" +#include "src/core/client_config/initial_connect_string.h" +#include "src/core/client_config/subchannel_index.h" +#include "src/core/iomgr/timer.h" +#include "src/core/profiling/timers.h" +#include "src/core/support/backoff.h" +#include "src/core/surface/channel.h" +#include "src/core/surface/channel_init.h" +#include "src/core/transport/connectivity_state.h" + +#define INTERNAL_REF_BITS 16 +#define STRONG_REF_MASK (~(gpr_atm)((1 << INTERNAL_REF_BITS) - 1)) + +#define GRPC_SUBCHANNEL_MIN_CONNECT_TIMEOUT_SECONDS 20 +#define GRPC_SUBCHANNEL_INITIAL_CONNECT_BACKOFF_SECONDS 1 +#define GRPC_SUBCHANNEL_RECONNECT_BACKOFF_MULTIPLIER 1.6 +#define GRPC_SUBCHANNEL_RECONNECT_MAX_BACKOFF_SECONDS 120 +#define GRPC_SUBCHANNEL_RECONNECT_JITTER 0.2 + +#define GET_CONNECTED_SUBCHANNEL(subchannel, barrier) \ + ((grpc_connected_subchannel *)(gpr_atm_##barrier##_load( \ + &(subchannel)->connected_subchannel))) + +typedef struct { + grpc_closure closure; + grpc_subchannel *subchannel; + grpc_connectivity_state connectivity_state; +} state_watcher; + +typedef struct external_state_watcher { + grpc_subchannel *subchannel; + grpc_pollset_set *pollset_set; + grpc_closure *notify; + grpc_closure closure; + struct external_state_watcher *next; + struct external_state_watcher *prev; +} external_state_watcher; + +struct grpc_subchannel { + grpc_connector *connector; + + /** refcount + - lower INTERNAL_REF_BITS bits are for internal references: + these do not keep the subchannel open. + - upper remaining bits are for public references: these do + keep the subchannel open */ + gpr_atm ref_pair; + + /** non-transport related channel filters */ + const grpc_channel_filter **filters; + size_t num_filters; + /** channel arguments */ + grpc_channel_args *args; + /** address to connect to */ + struct sockaddr *addr; + size_t addr_len; + + grpc_subchannel_key *key; + + /** initial string to send to peer */ + gpr_slice initial_connect_string; + + /** set during connection */ + grpc_connect_out_args connecting_result; + + /** callback for connection finishing */ + grpc_closure connected; + + /** pollset_set tracking who's interested in a connection + being setup */ + grpc_pollset_set *pollset_set; + + /** active connection, or null; of type grpc_connected_subchannel */ + gpr_atm connected_subchannel; + + /** mutex protecting remaining elements */ + gpr_mu mu; + + /** have we seen a disconnection? */ + int disconnected; + /** are we connecting */ + int connecting; + /** connectivity state tracking */ + grpc_connectivity_state_tracker state_tracker; + + external_state_watcher root_external_state_watcher; + + /** next connect attempt time */ + gpr_timespec next_attempt; + /** backoff state */ + gpr_backoff backoff_state; + /** do we have an active alarm? */ + int have_alarm; + /** our alarm */ + grpc_timer alarm; + /** current random value */ + uint32_t random; +}; + +struct grpc_subchannel_call { + grpc_connected_subchannel *connection; +}; + +#define SUBCHANNEL_CALL_TO_CALL_STACK(call) ((grpc_call_stack *)((call) + 1)) +#define CHANNEL_STACK_FROM_CONNECTION(con) ((grpc_channel_stack *)(con)) +#define CALLSTACK_TO_SUBCHANNEL_CALL(callstack) \ + (((grpc_subchannel_call *)(callstack)) - 1) + +static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *subchannel, + bool iomgr_success); + +#ifdef GRPC_STREAM_REFCOUNT_DEBUG +#define REF_REASON reason +#define REF_LOG(name, p) \ + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "%s: %p ref %d -> %d %s", \ + (name), (p), (p)->refs.count, (p)->refs.count + 1, reason) +#define UNREF_LOG(name, p) \ + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "%s: %p unref %d -> %d %s", \ + (name), (p), (p)->refs.count, (p)->refs.count - 1, reason) +#define REF_MUTATE_EXTRA_ARGS \ + GRPC_SUBCHANNEL_REF_EXTRA_ARGS, const char *purpose +#define REF_MUTATE_PURPOSE(x) , file, line, reason, x +#else +#define REF_REASON "" +#define REF_LOG(name, p) \ + do { \ + } while (0) +#define UNREF_LOG(name, p) \ + do { \ + } while (0) +#define REF_MUTATE_EXTRA_ARGS +#define REF_MUTATE_PURPOSE(x) +#endif + +/* + * connection implementation + */ + +static void connection_destroy(grpc_exec_ctx *exec_ctx, void *arg, + bool success) { + grpc_connected_subchannel *c = arg; + grpc_channel_stack_destroy(exec_ctx, CHANNEL_STACK_FROM_CONNECTION(c)); + gpr_free(c); +} + +void grpc_connected_subchannel_ref( + grpc_connected_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { + GRPC_CHANNEL_STACK_REF(CHANNEL_STACK_FROM_CONNECTION(c), REF_REASON); +} + +void grpc_connected_subchannel_unref(grpc_exec_ctx *exec_ctx, + grpc_connected_subchannel *c + GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { + GRPC_CHANNEL_STACK_UNREF(exec_ctx, CHANNEL_STACK_FROM_CONNECTION(c), + REF_REASON); +} + +/* + * grpc_subchannel implementation + */ + +static void subchannel_destroy(grpc_exec_ctx *exec_ctx, void *arg, + bool success) { + grpc_subchannel *c = arg; + gpr_free((void *)c->filters); + grpc_channel_args_destroy(c->args); + gpr_free(c->addr); + gpr_slice_unref(c->initial_connect_string); + grpc_connectivity_state_destroy(exec_ctx, &c->state_tracker); + grpc_connector_unref(exec_ctx, c->connector); + grpc_pollset_set_destroy(c->pollset_set); + grpc_subchannel_key_destroy(exec_ctx, c->key); + gpr_free(c); +} + +static gpr_atm ref_mutate(grpc_subchannel *c, gpr_atm delta, + int barrier REF_MUTATE_EXTRA_ARGS) { + gpr_atm old_val = barrier ? gpr_atm_full_fetch_add(&c->ref_pair, delta) + : gpr_atm_no_barrier_fetch_add(&c->ref_pair, delta); +#ifdef GRPC_STREAM_REFCOUNT_DEBUG + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, + "SUBCHANNEL: %p % 12s 0x%08x -> 0x%08x [%s]", c, purpose, old_val, + old_val + delta, reason); +#endif + return old_val; +} + +grpc_subchannel *grpc_subchannel_ref( + grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { + gpr_atm old_refs; + old_refs = ref_mutate(c, (1 << INTERNAL_REF_BITS), + 0 REF_MUTATE_PURPOSE("STRONG_REF")); + GPR_ASSERT((old_refs & STRONG_REF_MASK) != 0); + return c; +} + +grpc_subchannel *grpc_subchannel_weak_ref( + grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { + gpr_atm old_refs; + old_refs = ref_mutate(c, 1, 0 REF_MUTATE_PURPOSE("WEAK_REF")); + GPR_ASSERT(old_refs != 0); + return c; +} + +grpc_subchannel *grpc_subchannel_ref_from_weak_ref( + grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { + if (!c) return NULL; + for (;;) { + gpr_atm old_refs = gpr_atm_acq_load(&c->ref_pair); + if (old_refs >= (1 << INTERNAL_REF_BITS)) { + gpr_atm new_refs = old_refs + (1 << INTERNAL_REF_BITS); + if (gpr_atm_rel_cas(&c->ref_pair, old_refs, new_refs)) { + return c; + } + } else { + return NULL; + } + } +} + +static void disconnect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) { + grpc_connected_subchannel *con; + grpc_subchannel_index_unregister(exec_ctx, c->key, c); + gpr_mu_lock(&c->mu); + GPR_ASSERT(!c->disconnected); + c->disconnected = 1; + grpc_connector_shutdown(exec_ctx, c->connector); + con = GET_CONNECTED_SUBCHANNEL(c, no_barrier); + if (con != NULL) { + GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, con, "connection"); + gpr_atm_no_barrier_store(&c->connected_subchannel, 0xdeadbeef); + } + gpr_mu_unlock(&c->mu); +} + +void grpc_subchannel_unref(grpc_exec_ctx *exec_ctx, + grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { + gpr_atm old_refs; + old_refs = ref_mutate(c, (gpr_atm)1 - (gpr_atm)(1 << INTERNAL_REF_BITS), + 1 REF_MUTATE_PURPOSE("STRONG_UNREF")); + if ((old_refs & STRONG_REF_MASK) == (1 << INTERNAL_REF_BITS)) { + disconnect(exec_ctx, c); + } + GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "strong-unref"); +} + +void grpc_subchannel_weak_unref(grpc_exec_ctx *exec_ctx, + grpc_subchannel *c + GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { + gpr_atm old_refs; + old_refs = ref_mutate(c, -(gpr_atm)1, 1 REF_MUTATE_PURPOSE("WEAK_UNREF")); + if (old_refs == 1) { + grpc_exec_ctx_enqueue(exec_ctx, grpc_closure_create(subchannel_destroy, c), + true, NULL); + } +} + +static uint32_t random_seed() { + return (uint32_t)(gpr_time_to_millis(gpr_now(GPR_CLOCK_MONOTONIC))); +} + +grpc_subchannel *grpc_subchannel_create(grpc_exec_ctx *exec_ctx, + grpc_connector *connector, + grpc_subchannel_args *args) { + grpc_subchannel_key *key = grpc_subchannel_key_create(connector, args); + grpc_subchannel *c = grpc_subchannel_index_find(exec_ctx, key); + if (c) { + grpc_subchannel_key_destroy(exec_ctx, key); + return c; + } + + c = gpr_malloc(sizeof(*c)); + memset(c, 0, sizeof(*c)); + c->key = key; + gpr_atm_no_barrier_store(&c->ref_pair, 1 << INTERNAL_REF_BITS); + c->connector = connector; + grpc_connector_ref(c->connector); + c->num_filters = args->filter_count; + if (c->num_filters > 0) { + c->filters = gpr_malloc(sizeof(grpc_channel_filter *) * c->num_filters); + memcpy((void *)c->filters, args->filters, + sizeof(grpc_channel_filter *) * c->num_filters); + } else { + c->filters = NULL; + } + c->addr = gpr_malloc(args->addr_len); + memcpy(c->addr, args->addr, args->addr_len); + c->pollset_set = grpc_pollset_set_create(); + c->addr_len = args->addr_len; + grpc_set_initial_connect_string(&c->addr, &c->addr_len, + &c->initial_connect_string); + c->args = grpc_channel_args_copy(args->args); + c->random = random_seed(); + c->root_external_state_watcher.next = c->root_external_state_watcher.prev = + &c->root_external_state_watcher; + grpc_closure_init(&c->connected, subchannel_connected, c); + grpc_connectivity_state_init(&c->state_tracker, GRPC_CHANNEL_IDLE, + "subchannel"); + gpr_backoff_init(&c->backoff_state, + GRPC_SUBCHANNEL_RECONNECT_BACKOFF_MULTIPLIER, + GRPC_SUBCHANNEL_RECONNECT_JITTER, + GRPC_SUBCHANNEL_INITIAL_CONNECT_BACKOFF_SECONDS * 1000, + GRPC_SUBCHANNEL_RECONNECT_MAX_BACKOFF_SECONDS * 1000); + if (c->args) { + for (size_t i = 0; i < c->args->num_args; i++) { + if (0 == strcmp(c->args->args[i].key, + "grpc.testing.fixed_reconnect_backoff")) { + GPR_ASSERT(c->args->args[i].type == GRPC_ARG_INTEGER); + gpr_backoff_init(&c->backoff_state, 1.0, 0.0, + c->args->args[i].value.integer, + c->args->args[i].value.integer); + } + } + } + gpr_mu_init(&c->mu); + + return grpc_subchannel_index_register(exec_ctx, key, c); +} + +static void continue_connect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) { + grpc_connect_in_args args; + + args.interested_parties = c->pollset_set; + args.addr = c->addr; + args.addr_len = c->addr_len; + args.deadline = c->next_attempt; + args.channel_args = c->args; + args.initial_connect_string = c->initial_connect_string; + + grpc_connectivity_state_set(exec_ctx, &c->state_tracker, + GRPC_CHANNEL_CONNECTING, "state_change"); + grpc_connector_connect(exec_ctx, c->connector, &args, &c->connecting_result, + &c->connected); +} + +static void start_connect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) { + c->next_attempt = + gpr_backoff_begin(&c->backoff_state, gpr_now(GPR_CLOCK_MONOTONIC)); + continue_connect(exec_ctx, c); +} + +grpc_connectivity_state grpc_subchannel_check_connectivity(grpc_subchannel *c) { + grpc_connectivity_state state; + gpr_mu_lock(&c->mu); + state = grpc_connectivity_state_check(&c->state_tracker); + gpr_mu_unlock(&c->mu); + return state; +} + +static void on_external_state_watcher_done(grpc_exec_ctx *exec_ctx, void *arg, + bool success) { + external_state_watcher *w = arg; + grpc_closure *follow_up = w->notify; + if (w->pollset_set != NULL) { + grpc_pollset_set_del_pollset_set(exec_ctx, w->subchannel->pollset_set, + w->pollset_set); + } + gpr_mu_lock(&w->subchannel->mu); + w->next->prev = w->prev; + w->prev->next = w->next; + gpr_mu_unlock(&w->subchannel->mu); + GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, w->subchannel, "external_state_watcher"); + gpr_free(w); + follow_up->cb(exec_ctx, follow_up->cb_arg, success); +} + +void grpc_subchannel_notify_on_state_change( + grpc_exec_ctx *exec_ctx, grpc_subchannel *c, + grpc_pollset_set *interested_parties, grpc_connectivity_state *state, + grpc_closure *notify) { + external_state_watcher *w; + + if (state == NULL) { + gpr_mu_lock(&c->mu); + for (w = c->root_external_state_watcher.next; + w != &c->root_external_state_watcher; w = w->next) { + if (w->notify == notify) { + grpc_connectivity_state_notify_on_state_change( + exec_ctx, &c->state_tracker, NULL, &w->closure); + } + } + gpr_mu_unlock(&c->mu); + } else { + w = gpr_malloc(sizeof(*w)); + w->subchannel = c; + w->pollset_set = interested_parties; + w->notify = notify; + grpc_closure_init(&w->closure, on_external_state_watcher_done, w); + if (interested_parties != NULL) { + grpc_pollset_set_add_pollset_set(exec_ctx, c->pollset_set, + interested_parties); + } + GRPC_SUBCHANNEL_WEAK_REF(c, "external_state_watcher"); + gpr_mu_lock(&c->mu); + w->next = &c->root_external_state_watcher; + w->prev = w->next->prev; + w->next->prev = w->prev->next = w; + if (grpc_connectivity_state_notify_on_state_change( + exec_ctx, &c->state_tracker, state, &w->closure)) { + c->connecting = 1; + /* released by connection */ + GRPC_SUBCHANNEL_WEAK_REF(c, "connecting"); + start_connect(exec_ctx, c); + } + gpr_mu_unlock(&c->mu); + } +} + +void grpc_connected_subchannel_process_transport_op( + grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *con, + grpc_transport_op *op) { + grpc_channel_stack *channel_stack = CHANNEL_STACK_FROM_CONNECTION(con); + grpc_channel_element *top_elem = grpc_channel_stack_element(channel_stack, 0); + top_elem->filter->start_transport_op(exec_ctx, top_elem, op); +} + +static void subchannel_on_child_state_changed(grpc_exec_ctx *exec_ctx, void *p, + bool iomgr_success) { + state_watcher *sw = p; + grpc_subchannel *c = sw->subchannel; + gpr_mu *mu = &c->mu; + + gpr_mu_lock(mu); + + /* if we failed just leave this closure */ + if (iomgr_success) { + if (sw->connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) { + /* any errors on a subchannel ==> we're done, create a new one */ + sw->connectivity_state = GRPC_CHANNEL_FATAL_FAILURE; + } + grpc_connectivity_state_set(exec_ctx, &c->state_tracker, + sw->connectivity_state, "reflect_child"); + if (sw->connectivity_state != GRPC_CHANNEL_FATAL_FAILURE) { + grpc_connected_subchannel_notify_on_state_change( + exec_ctx, GET_CONNECTED_SUBCHANNEL(c, no_barrier), NULL, + &sw->connectivity_state, &sw->closure); + GRPC_SUBCHANNEL_WEAK_REF(c, "state_watcher"); + sw = NULL; + } + } + + gpr_mu_unlock(mu); + GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "state_watcher"); + gpr_free(sw); +} + +static void connected_subchannel_state_op(grpc_exec_ctx *exec_ctx, + grpc_connected_subchannel *con, + grpc_pollset_set *interested_parties, + grpc_connectivity_state *state, + grpc_closure *closure) { + grpc_transport_op op; + grpc_channel_element *elem; + memset(&op, 0, sizeof(op)); + op.connectivity_state = state; + op.on_connectivity_state_change = closure; + op.bind_pollset_set = interested_parties; + elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CONNECTION(con), 0); + elem->filter->start_transport_op(exec_ctx, elem, &op); +} + +void grpc_connected_subchannel_notify_on_state_change( + grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *con, + grpc_pollset_set *interested_parties, grpc_connectivity_state *state, + grpc_closure *closure) { + connected_subchannel_state_op(exec_ctx, con, interested_parties, state, + closure); +} + +void grpc_connected_subchannel_ping(grpc_exec_ctx *exec_ctx, + grpc_connected_subchannel *con, + grpc_closure *closure) { + grpc_transport_op op; + grpc_channel_element *elem; + memset(&op, 0, sizeof(op)); + op.send_ping = closure; + elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CONNECTION(con), 0); + elem->filter->start_transport_op(exec_ctx, elem, &op); +} + +static void publish_transport_locked(grpc_exec_ctx *exec_ctx, + grpc_subchannel *c) { + grpc_connected_subchannel *con; + grpc_channel_stack *stk; + state_watcher *sw_subchannel; + + /* construct channel stack */ + con = grpc_channel_init_create_stack( + exec_ctx, GRPC_CLIENT_SUBCHANNEL, 0, c->connecting_result.channel_args, 1, + connection_destroy, NULL, c->connecting_result.transport); + stk = CHANNEL_STACK_FROM_CONNECTION(con); + memset(&c->connecting_result, 0, sizeof(c->connecting_result)); + + /* initialize state watcher */ + sw_subchannel = gpr_malloc(sizeof(*sw_subchannel)); + sw_subchannel->subchannel = c; + sw_subchannel->connectivity_state = GRPC_CHANNEL_READY; + grpc_closure_init(&sw_subchannel->closure, subchannel_on_child_state_changed, + sw_subchannel); + + if (c->disconnected) { + gpr_free(sw_subchannel); + grpc_channel_stack_destroy(exec_ctx, stk); + gpr_free(con); + GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting"); + return; + } + + /* publish */ + /* TODO(ctiller): this full barrier seems to clear up a TSAN failure. + I'd have expected the rel_cas below to be enough, but + seemingly it's not. + Re-evaluate if we really need this. */ + gpr_atm_full_barrier(); + GPR_ASSERT(gpr_atm_rel_cas(&c->connected_subchannel, 0, (gpr_atm)con)); + c->connecting = 0; + + /* setup subchannel watching connected subchannel for changes; subchannel ref + for connecting is donated + to the state watcher */ + GRPC_SUBCHANNEL_WEAK_REF(c, "state_watcher"); + GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting"); + grpc_connected_subchannel_notify_on_state_change( + exec_ctx, con, c->pollset_set, &sw_subchannel->connectivity_state, + &sw_subchannel->closure); + + /* signal completion */ + grpc_connectivity_state_set(exec_ctx, &c->state_tracker, GRPC_CHANNEL_READY, + "connected"); +} + +static void on_alarm(grpc_exec_ctx *exec_ctx, void *arg, bool iomgr_success) { + grpc_subchannel *c = arg; + gpr_mu_lock(&c->mu); + c->have_alarm = 0; + if (c->disconnected) { + iomgr_success = 0; + } + if (iomgr_success) { + c->next_attempt = + gpr_backoff_step(&c->backoff_state, gpr_now(GPR_CLOCK_MONOTONIC)); + continue_connect(exec_ctx, c); + gpr_mu_unlock(&c->mu); + } else { + gpr_mu_unlock(&c->mu); + GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting"); + } +} + +static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *arg, + bool iomgr_success) { + grpc_subchannel *c = arg; + + GRPC_SUBCHANNEL_WEAK_REF(c, "connected"); + gpr_mu_lock(&c->mu); + if (c->connecting_result.transport != NULL) { + publish_transport_locked(exec_ctx, c); + } else if (c->disconnected) { + GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting"); + } else { + gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); + GPR_ASSERT(!c->have_alarm); + c->have_alarm = 1; + grpc_connectivity_state_set(exec_ctx, &c->state_tracker, + GRPC_CHANNEL_TRANSIENT_FAILURE, + "connect_failed"); + grpc_timer_init(exec_ctx, &c->alarm, c->next_attempt, on_alarm, c, now); + } + gpr_mu_unlock(&c->mu); + GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting"); +} + +/* + * grpc_subchannel_call implementation + */ + +static void subchannel_call_destroy(grpc_exec_ctx *exec_ctx, void *call, + bool success) { + grpc_subchannel_call *c = call; + GPR_TIMER_BEGIN("grpc_subchannel_call_unref.destroy", 0); + grpc_call_stack_destroy(exec_ctx, SUBCHANNEL_CALL_TO_CALL_STACK(c)); + GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, c->connection, "subchannel_call"); + gpr_free(c); + GPR_TIMER_END("grpc_subchannel_call_unref.destroy", 0); +} + +void grpc_subchannel_call_ref( + grpc_subchannel_call *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { + GRPC_CALL_STACK_REF(SUBCHANNEL_CALL_TO_CALL_STACK(c), REF_REASON); +} + +void grpc_subchannel_call_unref(grpc_exec_ctx *exec_ctx, + grpc_subchannel_call *c + GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { + GRPC_CALL_STACK_UNREF(exec_ctx, SUBCHANNEL_CALL_TO_CALL_STACK(c), REF_REASON); +} + +char *grpc_subchannel_call_get_peer(grpc_exec_ctx *exec_ctx, + grpc_subchannel_call *call) { + grpc_call_stack *call_stack = SUBCHANNEL_CALL_TO_CALL_STACK(call); + grpc_call_element *top_elem = grpc_call_stack_element(call_stack, 0); + return top_elem->filter->get_peer(exec_ctx, top_elem); +} + +void grpc_subchannel_call_process_op(grpc_exec_ctx *exec_ctx, + grpc_subchannel_call *call, + grpc_transport_stream_op *op) { + grpc_call_stack *call_stack = SUBCHANNEL_CALL_TO_CALL_STACK(call); + grpc_call_element *top_elem = grpc_call_stack_element(call_stack, 0); + top_elem->filter->start_transport_stream_op(exec_ctx, top_elem, op); +} + +grpc_connected_subchannel *grpc_subchannel_get_connected_subchannel( + grpc_subchannel *c) { + return GET_CONNECTED_SUBCHANNEL(c, acq); +} + +grpc_subchannel_call *grpc_connected_subchannel_create_call( + grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *con, + grpc_pollset *pollset) { + grpc_channel_stack *chanstk = CHANNEL_STACK_FROM_CONNECTION(con); + grpc_subchannel_call *call = + gpr_malloc(sizeof(grpc_subchannel_call) + chanstk->call_stack_size); + grpc_call_stack *callstk = SUBCHANNEL_CALL_TO_CALL_STACK(call); + call->connection = con; + GRPC_CONNECTED_SUBCHANNEL_REF(con, "subchannel_call"); + grpc_call_stack_init(exec_ctx, chanstk, 1, subchannel_call_destroy, call, + NULL, NULL, callstk); + grpc_call_stack_set_pollset(exec_ctx, callstk, pollset); + return call; +} + +grpc_call_stack *grpc_subchannel_call_get_call_stack( + grpc_subchannel_call *subchannel_call) { + return SUBCHANNEL_CALL_TO_CALL_STACK(subchannel_call); +} diff --git a/src/core/lib/client_config/subchannel.h b/src/core/lib/client_config/subchannel.h new file mode 100644 index 0000000000..83e1c58a4c --- /dev/null +++ b/src/core/lib/client_config/subchannel.h @@ -0,0 +1,174 @@ +/* + * + * Copyright 2015-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_CLIENT_CONFIG_SUBCHANNEL_H +#define GRPC_CORE_CLIENT_CONFIG_SUBCHANNEL_H + +#include "src/core/channel/channel_stack.h" +#include "src/core/client_config/connector.h" +#include "src/core/transport/connectivity_state.h" + +/** A (sub-)channel that knows how to connect to exactly one target + address. Provides a target for load balancing. */ +typedef struct grpc_subchannel grpc_subchannel; +typedef struct grpc_connected_subchannel grpc_connected_subchannel; +typedef struct grpc_subchannel_call grpc_subchannel_call; +typedef struct grpc_subchannel_args grpc_subchannel_args; + +#ifdef GRPC_STREAM_REFCOUNT_DEBUG +#define GRPC_SUBCHANNEL_REF(p, r) \ + grpc_subchannel_ref((p), __FILE__, __LINE__, (r)) +#define GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(p, r) \ + grpc_subchannel_ref_from_weak_ref((p), __FILE__, __LINE__, (r)) +#define GRPC_SUBCHANNEL_UNREF(cl, p, r) \ + grpc_subchannel_unref((cl), (p), __FILE__, __LINE__, (r)) +#define GRPC_SUBCHANNEL_WEAK_REF(p, r) \ + grpc_subchannel_weak_ref((p), __FILE__, __LINE__, (r)) +#define GRPC_SUBCHANNEL_WEAK_UNREF(cl, p, r) \ + grpc_subchannel_weak_unref((cl), (p), __FILE__, __LINE__, (r)) +#define GRPC_CONNECTED_SUBCHANNEL_REF(p, r) \ + grpc_connected_subchannel_ref((p), __FILE__, __LINE__, (r)) +#define GRPC_CONNECTED_SUBCHANNEL_UNREF(cl, p, r) \ + grpc_connected_subchannel_unref((cl), (p), __FILE__, __LINE__, (r)) +#define GRPC_SUBCHANNEL_CALL_REF(p, r) \ + grpc_subchannel_call_ref((p), __FILE__, __LINE__, (r)) +#define GRPC_SUBCHANNEL_CALL_UNREF(cl, p, r) \ + grpc_subchannel_call_unref((cl), (p), __FILE__, __LINE__, (r)) +#define GRPC_SUBCHANNEL_REF_EXTRA_ARGS \ + , const char *file, int line, const char *reason +#else +#define GRPC_SUBCHANNEL_REF(p, r) grpc_subchannel_ref((p)) +#define GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(p, r) \ + grpc_subchannel_ref_from_weak_ref((p)) +#define GRPC_SUBCHANNEL_UNREF(cl, p, r) grpc_subchannel_unref((cl), (p)) +#define GRPC_SUBCHANNEL_WEAK_REF(p, r) grpc_subchannel_weak_ref((p)) +#define GRPC_SUBCHANNEL_WEAK_UNREF(cl, p, r) \ + grpc_subchannel_weak_unref((cl), (p)) +#define GRPC_CONNECTED_SUBCHANNEL_REF(p, r) grpc_connected_subchannel_ref((p)) +#define GRPC_CONNECTED_SUBCHANNEL_UNREF(cl, p, r) \ + grpc_connected_subchannel_unref((cl), (p)) +#define GRPC_SUBCHANNEL_CALL_REF(p, r) grpc_subchannel_call_ref((p)) +#define GRPC_SUBCHANNEL_CALL_UNREF(cl, p, r) \ + grpc_subchannel_call_unref((cl), (p)) +#define GRPC_SUBCHANNEL_REF_EXTRA_ARGS +#endif + +grpc_subchannel *grpc_subchannel_ref( + grpc_subchannel *channel GRPC_SUBCHANNEL_REF_EXTRA_ARGS); +grpc_subchannel *grpc_subchannel_ref_from_weak_ref( + grpc_subchannel *channel GRPC_SUBCHANNEL_REF_EXTRA_ARGS); +void grpc_subchannel_unref(grpc_exec_ctx *exec_ctx, + grpc_subchannel *channel + GRPC_SUBCHANNEL_REF_EXTRA_ARGS); +grpc_subchannel *grpc_subchannel_weak_ref( + grpc_subchannel *channel GRPC_SUBCHANNEL_REF_EXTRA_ARGS); +void grpc_subchannel_weak_unref(grpc_exec_ctx *exec_ctx, + grpc_subchannel *channel + GRPC_SUBCHANNEL_REF_EXTRA_ARGS); +void grpc_connected_subchannel_ref( + grpc_connected_subchannel *channel GRPC_SUBCHANNEL_REF_EXTRA_ARGS); +void grpc_connected_subchannel_unref(grpc_exec_ctx *exec_ctx, + grpc_connected_subchannel *channel + GRPC_SUBCHANNEL_REF_EXTRA_ARGS); +void grpc_subchannel_call_ref( + grpc_subchannel_call *call GRPC_SUBCHANNEL_REF_EXTRA_ARGS); +void grpc_subchannel_call_unref(grpc_exec_ctx *exec_ctx, + grpc_subchannel_call *call + GRPC_SUBCHANNEL_REF_EXTRA_ARGS); + +/** construct a subchannel call */ +grpc_subchannel_call *grpc_connected_subchannel_create_call( + grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *connected_subchannel, + grpc_pollset *pollset); + +/** process a transport level op */ +void grpc_connected_subchannel_process_transport_op( + grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *subchannel, + grpc_transport_op *op); + +/** poll the current connectivity state of a channel */ +grpc_connectivity_state grpc_subchannel_check_connectivity( + grpc_subchannel *channel); + +/** call notify when the connectivity state of a channel changes from *state. + Updates *state with the new state of the channel */ +void grpc_subchannel_notify_on_state_change( + grpc_exec_ctx *exec_ctx, grpc_subchannel *channel, + grpc_pollset_set *interested_parties, grpc_connectivity_state *state, + grpc_closure *notify); +void grpc_connected_subchannel_notify_on_state_change( + grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *channel, + grpc_pollset_set *interested_parties, grpc_connectivity_state *state, + grpc_closure *notify); +void grpc_connected_subchannel_ping(grpc_exec_ctx *exec_ctx, + grpc_connected_subchannel *channel, + grpc_closure *notify); + +/** retrieve the grpc_connected_subchannel - or NULL if called before + the subchannel becomes connected */ +grpc_connected_subchannel *grpc_subchannel_get_connected_subchannel( + grpc_subchannel *subchannel); + +/** continue processing a transport op */ +void grpc_subchannel_call_process_op(grpc_exec_ctx *exec_ctx, + grpc_subchannel_call *subchannel_call, + grpc_transport_stream_op *op); + +/** continue querying for peer */ +char *grpc_subchannel_call_get_peer(grpc_exec_ctx *exec_ctx, + grpc_subchannel_call *subchannel_call); + +grpc_call_stack *grpc_subchannel_call_get_call_stack( + grpc_subchannel_call *subchannel_call); + +struct grpc_subchannel_args { + /* When updating this struct, also update subchannel_index.c */ + + /** Channel filters for this channel - wrapped factories will likely + want to mutate this */ + const grpc_channel_filter **filters; + /** The number of filters in the above array */ + size_t filter_count; + /** Channel arguments to be supplied to the newly created channel */ + const grpc_channel_args *args; + /** Address to connect to */ + struct sockaddr *addr; + size_t addr_len; +}; + +/** create a subchannel given a connector */ +grpc_subchannel *grpc_subchannel_create(grpc_exec_ctx *exec_ctx, + grpc_connector *connector, + grpc_subchannel_args *args); + +#endif /* GRPC_CORE_CLIENT_CONFIG_SUBCHANNEL_H */ diff --git a/src/core/lib/client_config/subchannel_factory.c b/src/core/lib/client_config/subchannel_factory.c new file mode 100644 index 0000000000..2c64219e8b --- /dev/null +++ b/src/core/lib/client_config/subchannel_factory.c @@ -0,0 +1,49 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/client_config/subchannel_factory.h" + +void grpc_subchannel_factory_ref(grpc_subchannel_factory* factory) { + factory->vtable->ref(factory); +} + +void grpc_subchannel_factory_unref(grpc_exec_ctx* exec_ctx, + grpc_subchannel_factory* factory) { + factory->vtable->unref(exec_ctx, factory); +} + +grpc_subchannel* grpc_subchannel_factory_create_subchannel( + grpc_exec_ctx* exec_ctx, grpc_subchannel_factory* factory, + grpc_subchannel_args* args) { + return factory->vtable->create_subchannel(exec_ctx, factory, args); +} diff --git a/src/core/lib/client_config/subchannel_factory.h b/src/core/lib/client_config/subchannel_factory.h new file mode 100644 index 0000000000..c638f377a6 --- /dev/null +++ b/src/core/lib/client_config/subchannel_factory.h @@ -0,0 +1,66 @@ +/* + * + * Copyright 2015-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_CLIENT_CONFIG_SUBCHANNEL_FACTORY_H +#define GRPC_CORE_CLIENT_CONFIG_SUBCHANNEL_FACTORY_H + +#include "src/core/channel/channel_stack.h" +#include "src/core/client_config/subchannel.h" + +typedef struct grpc_subchannel_factory grpc_subchannel_factory; +typedef struct grpc_subchannel_factory_vtable grpc_subchannel_factory_vtable; + +/** Constructor for new configured channels. + Creating decorators around this type is encouraged to adapt behavior. */ +struct grpc_subchannel_factory { + const grpc_subchannel_factory_vtable *vtable; +}; + +struct grpc_subchannel_factory_vtable { + void (*ref)(grpc_subchannel_factory *factory); + void (*unref)(grpc_exec_ctx *exec_ctx, grpc_subchannel_factory *factory); + grpc_subchannel *(*create_subchannel)(grpc_exec_ctx *exec_ctx, + grpc_subchannel_factory *factory, + grpc_subchannel_args *args); +}; + +void grpc_subchannel_factory_ref(grpc_subchannel_factory *factory); +void grpc_subchannel_factory_unref(grpc_exec_ctx *exec_ctx, + grpc_subchannel_factory *factory); + +/** Create a new grpc_subchannel */ +grpc_subchannel *grpc_subchannel_factory_create_subchannel( + grpc_exec_ctx *exec_ctx, grpc_subchannel_factory *factory, + grpc_subchannel_args *args); + +#endif /* GRPC_CORE_CLIENT_CONFIG_SUBCHANNEL_FACTORY_H */ diff --git a/src/core/lib/client_config/subchannel_index.c b/src/core/lib/client_config/subchannel_index.c new file mode 100644 index 0000000000..24cc76cf22 --- /dev/null +++ b/src/core/lib/client_config/subchannel_index.c @@ -0,0 +1,262 @@ +// +// +// 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/client_config/subchannel_index.h" + +#include +#include + +#include +#include +#include + +#include "src/core/channel/channel_args.h" + +// a map of subchannel_key --> subchannel, used for detecting connections +// to the same destination in order to share them +static gpr_avl g_subchannel_index; + +static gpr_mu g_mu; + +struct grpc_subchannel_key { + grpc_connector *connector; + grpc_subchannel_args args; +}; + +GPR_TLS_DECL(subchannel_index_exec_ctx); + +static void enter_ctx(grpc_exec_ctx *exec_ctx) { + GPR_ASSERT(gpr_tls_get(&subchannel_index_exec_ctx) == 0); + gpr_tls_set(&subchannel_index_exec_ctx, (intptr_t)exec_ctx); +} + +static void leave_ctx(grpc_exec_ctx *exec_ctx) { + GPR_ASSERT(gpr_tls_get(&subchannel_index_exec_ctx) == (intptr_t)exec_ctx); + gpr_tls_set(&subchannel_index_exec_ctx, 0); +} + +static grpc_exec_ctx *current_ctx() { + grpc_exec_ctx *c = (grpc_exec_ctx *)gpr_tls_get(&subchannel_index_exec_ctx); + GPR_ASSERT(c != NULL); + return c; +} + +static grpc_subchannel_key *create_key( + grpc_connector *connector, grpc_subchannel_args *args, + grpc_channel_args *(*copy_channel_args)(const grpc_channel_args *args)) { + grpc_subchannel_key *k = gpr_malloc(sizeof(*k)); + k->connector = grpc_connector_ref(connector); + k->args.filter_count = args->filter_count; + k->args.filters = gpr_malloc(sizeof(*k->args.filters) * k->args.filter_count); + memcpy((grpc_channel_filter *)k->args.filters, args->filters, + sizeof(*k->args.filters) * k->args.filter_count); + k->args.addr_len = args->addr_len; + k->args.addr = gpr_malloc(args->addr_len); + memcpy(k->args.addr, args->addr, k->args.addr_len); + k->args.args = copy_channel_args(args->args); + return k; +} + +grpc_subchannel_key *grpc_subchannel_key_create(grpc_connector *connector, + grpc_subchannel_args *args) { + return create_key(connector, args, grpc_channel_args_normalize); +} + +static grpc_subchannel_key *subchannel_key_copy(grpc_subchannel_key *k) { + return create_key(k->connector, &k->args, grpc_channel_args_copy); +} + +static int subchannel_key_compare(grpc_subchannel_key *a, + grpc_subchannel_key *b) { + int c = GPR_ICMP(a->connector, b->connector); + if (c != 0) return c; + c = GPR_ICMP(a->args.addr_len, b->args.addr_len); + if (c != 0) return c; + c = GPR_ICMP(a->args.filter_count, b->args.filter_count); + if (c != 0) return c; + c = memcmp(a->args.addr, b->args.addr, a->args.addr_len); + if (c != 0) return c; + c = memcmp(a->args.filters, b->args.filters, + a->args.filter_count * sizeof(*a->args.filters)); + if (c != 0) return c; + return grpc_channel_args_compare(a->args.args, b->args.args); +} + +void grpc_subchannel_key_destroy(grpc_exec_ctx *exec_ctx, + grpc_subchannel_key *k) { + grpc_connector_unref(exec_ctx, k->connector); + gpr_free(k->args.addr); + gpr_free((grpc_channel_args *)k->args.filters); + grpc_channel_args_destroy((grpc_channel_args *)k->args.args); + gpr_free(k); +} + +static void sck_avl_destroy(void *p) { + grpc_subchannel_key_destroy(current_ctx(), p); +} + +static void *sck_avl_copy(void *p) { return subchannel_key_copy(p); } + +static long sck_avl_compare(void *a, void *b) { + return subchannel_key_compare(a, b); +} + +static void scv_avl_destroy(void *p) { + GRPC_SUBCHANNEL_WEAK_UNREF(current_ctx(), p, "subchannel_index"); +} + +static void *scv_avl_copy(void *p) { + GRPC_SUBCHANNEL_WEAK_REF(p, "subchannel_index"); + return p; +} + +static const gpr_avl_vtable subchannel_avl_vtable = { + .destroy_key = sck_avl_destroy, + .copy_key = sck_avl_copy, + .compare_keys = sck_avl_compare, + .destroy_value = scv_avl_destroy, + .copy_value = scv_avl_copy}; + +void grpc_subchannel_index_init(void) { + g_subchannel_index = gpr_avl_create(&subchannel_avl_vtable); + gpr_mu_init(&g_mu); + gpr_tls_init(&subchannel_index_exec_ctx); +} + +void grpc_subchannel_index_shutdown(void) { + gpr_mu_destroy(&g_mu); + gpr_avl_unref(g_subchannel_index); + gpr_tls_destroy(&subchannel_index_exec_ctx); +} + +grpc_subchannel *grpc_subchannel_index_find(grpc_exec_ctx *exec_ctx, + grpc_subchannel_key *key) { + enter_ctx(exec_ctx); + + // Lock, and take a reference to the subchannel index. + // We don't need to do the search under a lock as avl's are immutable. + gpr_mu_lock(&g_mu); + gpr_avl index = gpr_avl_ref(g_subchannel_index); + gpr_mu_unlock(&g_mu); + + grpc_subchannel *c = + GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(gpr_avl_get(index, key), "index_find"); + gpr_avl_unref(index); + + leave_ctx(exec_ctx); + return c; +} + +grpc_subchannel *grpc_subchannel_index_register(grpc_exec_ctx *exec_ctx, + grpc_subchannel_key *key, + grpc_subchannel *constructed) { + enter_ctx(exec_ctx); + + grpc_subchannel *c = NULL; + + while (c == NULL) { + // Compare and swap loop: + // - take a reference to the current index + gpr_mu_lock(&g_mu); + gpr_avl index = gpr_avl_ref(g_subchannel_index); + gpr_mu_unlock(&g_mu); + + // - Check to see if a subchannel already exists + c = gpr_avl_get(index, key); + if (c != NULL) { + // yes -> we're done + GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, constructed, "index_register"); + } else { + // no -> update the avl and compare/swap + gpr_avl updated = + gpr_avl_add(gpr_avl_ref(index), subchannel_key_copy(key), + GRPC_SUBCHANNEL_WEAK_REF(constructed, "index_register")); + + // it may happen (but it's expected to be unlikely) + // that some other thread has changed the index: + // compare/swap here to check that, and retry as necessary + gpr_mu_lock(&g_mu); + if (index.root == g_subchannel_index.root) { + GPR_SWAP(gpr_avl, updated, g_subchannel_index); + c = constructed; + } + gpr_mu_unlock(&g_mu); + + gpr_avl_unref(updated); + } + gpr_avl_unref(index); + } + + leave_ctx(exec_ctx); + + return c; +} + +void grpc_subchannel_index_unregister(grpc_exec_ctx *exec_ctx, + grpc_subchannel_key *key, + grpc_subchannel *constructed) { + enter_ctx(exec_ctx); + + bool done = false; + while (!done) { + // Compare and swap loop: + // - take a reference to the current index + gpr_mu_lock(&g_mu); + gpr_avl index = gpr_avl_ref(g_subchannel_index); + gpr_mu_unlock(&g_mu); + + // Check to see if this key still refers to the previously + // registered subchannel + grpc_subchannel *c = gpr_avl_get(index, key); + if (c != constructed) { + gpr_avl_unref(index); + break; + } + + // compare and swap the update (some other thread may have + // mutated the index behind us) + gpr_avl updated = gpr_avl_remove(gpr_avl_ref(index), key); + + gpr_mu_lock(&g_mu); + if (index.root == g_subchannel_index.root) { + GPR_SWAP(gpr_avl, updated, g_subchannel_index); + done = true; + } + gpr_mu_unlock(&g_mu); + + gpr_avl_unref(updated); + gpr_avl_unref(index); + } + + leave_ctx(exec_ctx); +} diff --git a/src/core/lib/client_config/subchannel_index.h b/src/core/lib/client_config/subchannel_index.h new file mode 100644 index 0000000000..3cd5d12349 --- /dev/null +++ b/src/core/lib/client_config/subchannel_index.h @@ -0,0 +1,77 @@ +/* + * + * 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_CLIENT_CONFIG_SUBCHANNEL_INDEX_H +#define GRPC_CORE_CLIENT_CONFIG_SUBCHANNEL_INDEX_H + +#include "src/core/client_config/connector.h" +#include "src/core/client_config/subchannel.h" + +/** \file Provides an index of active subchannels so that they can be + shared amongst channels */ + +typedef struct grpc_subchannel_key grpc_subchannel_key; + +/** Create a key that can be used to uniquely identify a subchannel */ +grpc_subchannel_key *grpc_subchannel_key_create(grpc_connector *con, + grpc_subchannel_args *args); + +/** Destroy a subchannel key */ +void grpc_subchannel_key_destroy(grpc_exec_ctx *exec_ctx, + grpc_subchannel_key *key); + +/** Given a subchannel key, find the subchannel registered for it. + Returns NULL if no such channel exists. + Thread-safe. */ +grpc_subchannel *grpc_subchannel_index_find(grpc_exec_ctx *exec_ctx, + grpc_subchannel_key *key); + +/** Register a subchannel against a key. + Takes ownership of \a constructed. + Returns the registered subchannel. This may be different from + \a constructed in the case of a registration race. */ +grpc_subchannel *grpc_subchannel_index_register(grpc_exec_ctx *exec_ctx, + grpc_subchannel_key *key, + grpc_subchannel *constructed); + +/** Remove \a constructed as the registered subchannel for \a key. */ +void grpc_subchannel_index_unregister(grpc_exec_ctx *exec_ctx, + grpc_subchannel_key *key, + grpc_subchannel *constructed); + +/** Initialize the subchannel index (global) */ +void grpc_subchannel_index_init(void); +/** Shutdown the subchannel index (global) */ +void grpc_subchannel_index_shutdown(void); + +#endif /* GRPC_CORE_CLIENT_CONFIG_SUBCHANNEL_INDEX_H */ diff --git a/src/core/lib/client_config/uri_parser.c b/src/core/lib/client_config/uri_parser.c new file mode 100644 index 0000000000..cbdfffcf8e --- /dev/null +++ b/src/core/lib/client_config/uri_parser.c @@ -0,0 +1,242 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/client_config/uri_parser.h" + +#include + +#include +#include +#include +#include + +/** a size_t default value... maps to all 1's */ +#define NOT_SET (~(size_t)0) + +static grpc_uri *bad_uri(const char *uri_text, size_t pos, const char *section, + int suppress_errors) { + char *line_prefix; + size_t pfx_len; + + if (!suppress_errors) { + gpr_asprintf(&line_prefix, "bad uri.%s: '", section); + pfx_len = strlen(line_prefix) + pos; + gpr_log(GPR_ERROR, "%s%s'", line_prefix, uri_text); + gpr_free(line_prefix); + + line_prefix = gpr_malloc(pfx_len + 1); + memset(line_prefix, ' ', pfx_len); + line_prefix[pfx_len] = 0; + gpr_log(GPR_ERROR, "%s^ here", line_prefix); + gpr_free(line_prefix); + } + + return NULL; +} + +/** Returns a copy of \a src[begin, end) */ +static char *copy_component(const char *src, size_t begin, size_t end) { + char *out = gpr_malloc(end - begin + 1); + memcpy(out, src + begin, end - begin); + out[end - begin] = 0; + return out; +} + +/** Returns how many chars to advance if \a uri_text[i] begins a valid \a pchar + * production. If \a uri_text[i] introduces an invalid \a pchar (such as percent + * sign not followed by two hex digits), NOT_SET is returned. */ +static size_t parse_pchar(const char *uri_text, size_t i) { + /* pchar = unreserved / pct-encoded / sub-delims / ":" / "@" + * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + * pct-encoded = "%" HEXDIG HEXDIG + * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" + / "*" / "+" / "," / ";" / "=" */ + char c = uri_text[i]; + if (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) || + ((c >= '0') && (c <= '9')) || + (c == '-' || c == '.' || c == '_' || c == '~') || /* unreserved */ + (c == '!' || c == '$' || c == '&' || c == '\'' || c == '$' || c == '&' || + c == '(' || c == ')' || c == '*' || c == '+' || c == ',' || c == ';' || + c == '=') /* sub-delims */) { + return 1; + } + if (c == '%') { /* pct-encoded */ + size_t j; + if (uri_text[i + 1] == 0 || uri_text[i + 2] == 0) { + return NOT_SET; + } + for (j = i + 1; j < 2; j++) { + c = uri_text[j]; + if (!(((c >= '0') && (c <= '9')) || ((c >= 'a') && (c <= 'f')) || + ((c >= 'A') && (c <= 'F')))) { + return NOT_SET; + } + } + return 2; + } + return 0; +} + +/* *( pchar / "?" / "/" ) */ +static int parse_fragment_or_query(const char *uri_text, size_t *i) { + char c; + while ((c = uri_text[*i]) != 0) { + const size_t advance = parse_pchar(uri_text, *i); /* pchar */ + switch (advance) { + case 0: /* uri_text[i] isn't in pchar */ + /* maybe it's ? or / */ + if (uri_text[*i] == '?' || uri_text[*i] == '/') { + (*i)++; + break; + } else { + return 1; + } + GPR_UNREACHABLE_CODE(return 0); + default: + (*i) += advance; + break; + case NOT_SET: /* uri_text[i] introduces an invalid URI */ + return 0; + } + } + /* *i is the first uri_text position past the \a query production, maybe \0 */ + return 1; +} + +grpc_uri *grpc_uri_parse(const char *uri_text, int suppress_errors) { + grpc_uri *uri; + size_t scheme_begin = 0; + size_t scheme_end = NOT_SET; + size_t authority_begin = NOT_SET; + size_t authority_end = NOT_SET; + size_t path_begin = NOT_SET; + size_t path_end = NOT_SET; + size_t query_begin = NOT_SET; + size_t query_end = NOT_SET; + size_t fragment_begin = NOT_SET; + size_t fragment_end = NOT_SET; + size_t i; + + for (i = scheme_begin; uri_text[i] != 0; i++) { + if (uri_text[i] == ':') { + scheme_end = i; + break; + } + if (uri_text[i] >= 'a' && uri_text[i] <= 'z') continue; + if (uri_text[i] >= 'A' && uri_text[i] <= 'Z') continue; + if (i != scheme_begin) { + if (uri_text[i] >= '0' && uri_text[i] <= '9') continue; + if (uri_text[i] == '+') continue; + if (uri_text[i] == '-') continue; + if (uri_text[i] == '.') continue; + } + break; + } + if (scheme_end == NOT_SET) { + return bad_uri(uri_text, i, "scheme", suppress_errors); + } + + if (uri_text[scheme_end + 1] == '/' && uri_text[scheme_end + 2] == '/') { + authority_begin = scheme_end + 3; + for (i = authority_begin; uri_text[i] != 0 && authority_end == NOT_SET; + i++) { + if (uri_text[i] == '/' || uri_text[i] == '?' || uri_text[i] == '#') { + authority_end = i; + } + } + if (authority_end == NOT_SET && uri_text[i] == 0) { + authority_end = i; + } + if (authority_end == NOT_SET) { + return bad_uri(uri_text, i, "authority", suppress_errors); + } + /* TODO(ctiller): parse the authority correctly */ + path_begin = authority_end; + } else { + path_begin = scheme_end + 1; + } + + for (i = path_begin; uri_text[i] != 0; i++) { + if (uri_text[i] == '?' || uri_text[i] == '#') { + path_end = i; + break; + } + } + if (path_end == NOT_SET && uri_text[i] == 0) { + path_end = i; + } + if (path_end == NOT_SET) { + return bad_uri(uri_text, i, "path", suppress_errors); + } + + if (uri_text[i] == '?') { + query_begin = ++i; + if (!parse_fragment_or_query(uri_text, &i)) { + return bad_uri(uri_text, i, "query", suppress_errors); + } else if (uri_text[i] != 0 && uri_text[i] != '#') { + /* We must be at the end or at the beginning of a fragment */ + return bad_uri(uri_text, i, "query", suppress_errors); + } + query_end = i; + } + if (uri_text[i] == '#') { + fragment_begin = ++i; + if (!parse_fragment_or_query(uri_text, &i)) { + return bad_uri(uri_text, i - fragment_end, "fragment", suppress_errors); + } else if (uri_text[i] != 0) { + /* We must be at the end */ + return bad_uri(uri_text, i, "fragment", suppress_errors); + } + fragment_end = i; + } + + uri = gpr_malloc(sizeof(*uri)); + memset(uri, 0, sizeof(*uri)); + uri->scheme = copy_component(uri_text, scheme_begin, scheme_end); + uri->authority = copy_component(uri_text, authority_begin, authority_end); + uri->path = copy_component(uri_text, path_begin, path_end); + uri->query = copy_component(uri_text, query_begin, query_end); + uri->fragment = copy_component(uri_text, fragment_begin, fragment_end); + + return uri; +} + +void grpc_uri_destroy(grpc_uri *uri) { + if (!uri) return; + gpr_free(uri->scheme); + gpr_free(uri->authority); + gpr_free(uri->path); + gpr_free(uri->query); + gpr_free(uri->fragment); + gpr_free(uri); +} diff --git a/src/core/lib/client_config/uri_parser.h b/src/core/lib/client_config/uri_parser.h new file mode 100644 index 0000000000..af013d8cac --- /dev/null +++ b/src/core/lib/client_config/uri_parser.h @@ -0,0 +1,51 @@ +/* + * + * Copyright 2015-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_CLIENT_CONFIG_URI_PARSER_H +#define GRPC_CORE_CLIENT_CONFIG_URI_PARSER_H + +typedef struct { + char *scheme; + char *authority; + char *path; + char *query; + char *fragment; +} grpc_uri; + +/** parse a uri, return NULL on failure */ +grpc_uri *grpc_uri_parse(const char *uri_text, int suppress_errors); + +/** destroy a uri */ +void grpc_uri_destroy(grpc_uri *uri); + +#endif /* GRPC_CORE_CLIENT_CONFIG_URI_PARSER_H */ diff --git a/src/core/lib/compression/algorithm_metadata.h b/src/core/lib/compression/algorithm_metadata.h new file mode 100644 index 0000000000..34abf1dba2 --- /dev/null +++ b/src/core/lib/compression/algorithm_metadata.h @@ -0,0 +1,53 @@ +/* + * + * Copyright 2015-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_COMPRESSION_ALGORITHM_METADATA_H +#define GRPC_CORE_COMPRESSION_ALGORITHM_METADATA_H + +#include +#include "src/core/transport/metadata.h" + +/** Return compression algorithm based metadata value */ +grpc_mdstr *grpc_compression_algorithm_mdstr( + grpc_compression_algorithm algorithm); + +/** Return compression algorithm based metadata element (grpc-encoding: xxx) */ +grpc_mdelem *grpc_compression_encoding_mdelem( + grpc_compression_algorithm algorithm); + +/** Find compression algorithm based on passed in mdstr - returns + * GRPC_COMPRESS_ALGORITHM_COUNT on failure */ +grpc_compression_algorithm grpc_compression_algorithm_from_mdstr( + grpc_mdstr *str); + +#endif /* GRPC_CORE_COMPRESSION_ALGORITHM_METADATA_H */ diff --git a/src/core/lib/compression/compression_algorithm.c b/src/core/lib/compression/compression_algorithm.c new file mode 100644 index 0000000000..2810a38b68 --- /dev/null +++ b/src/core/lib/compression/compression_algorithm.c @@ -0,0 +1,203 @@ +/* + * + * Copyright 2015-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 +#include + +#include +#include + +#include "src/core/compression/algorithm_metadata.h" +#include "src/core/surface/api_trace.h" +#include "src/core/transport/static_metadata.h" + +int grpc_compression_algorithm_parse(const char *name, size_t name_length, + grpc_compression_algorithm *algorithm) { + /* we use strncmp not only because it's safer (even though in this case it + * doesn't matter, given that we are comparing against string literals, but + * because this way we needn't have "name" nil-terminated (useful for slice + * data, for example) */ + GRPC_API_TRACE( + "grpc_compression_algorithm_parse(" + "name=%*.*s, name_length=%lu, algorithm=%p)", + 5, ((int)name_length, (int)name_length, name, (unsigned long)name_length, + algorithm)); + if (name_length == 0) { + return 0; + } + if (strncmp(name, "identity", name_length) == 0) { + *algorithm = GRPC_COMPRESS_NONE; + } else if (strncmp(name, "gzip", name_length) == 0) { + *algorithm = GRPC_COMPRESS_GZIP; + } else if (strncmp(name, "deflate", name_length) == 0) { + *algorithm = GRPC_COMPRESS_DEFLATE; + } else { + return 0; + } + return 1; +} + +int grpc_compression_algorithm_name(grpc_compression_algorithm algorithm, + char **name) { + GRPC_API_TRACE("grpc_compression_algorithm_parse(algorithm=%d, name=%p)", 2, + ((int)algorithm, name)); + switch (algorithm) { + case GRPC_COMPRESS_NONE: + *name = "identity"; + return 1; + case GRPC_COMPRESS_DEFLATE: + *name = "deflate"; + return 1; + case GRPC_COMPRESS_GZIP: + *name = "gzip"; + return 1; + case GRPC_COMPRESS_ALGORITHMS_COUNT: + return 0; + } + return 0; +} + +grpc_compression_algorithm grpc_compression_algorithm_from_mdstr( + grpc_mdstr *str) { + if (str == GRPC_MDSTR_IDENTITY) return GRPC_COMPRESS_NONE; + if (str == GRPC_MDSTR_DEFLATE) return GRPC_COMPRESS_DEFLATE; + if (str == GRPC_MDSTR_GZIP) return GRPC_COMPRESS_GZIP; + return GRPC_COMPRESS_ALGORITHMS_COUNT; +} + +grpc_mdstr *grpc_compression_algorithm_mdstr( + grpc_compression_algorithm algorithm) { + switch (algorithm) { + case GRPC_COMPRESS_NONE: + return GRPC_MDSTR_IDENTITY; + case GRPC_COMPRESS_DEFLATE: + return GRPC_MDSTR_DEFLATE; + case GRPC_COMPRESS_GZIP: + return GRPC_MDSTR_GZIP; + case GRPC_COMPRESS_ALGORITHMS_COUNT: + return NULL; + } + return NULL; +} + +grpc_mdelem *grpc_compression_encoding_mdelem( + grpc_compression_algorithm algorithm) { + switch (algorithm) { + case GRPC_COMPRESS_NONE: + return GRPC_MDELEM_GRPC_ENCODING_IDENTITY; + case GRPC_COMPRESS_DEFLATE: + return GRPC_MDELEM_GRPC_ENCODING_DEFLATE; + case GRPC_COMPRESS_GZIP: + return GRPC_MDELEM_GRPC_ENCODING_GZIP; + default: + break; + } + return NULL; +} + +/* TODO(dgq): Add the ability to specify parameters to the individual + * compression algorithms */ +grpc_compression_algorithm grpc_compression_algorithm_for_level( + grpc_compression_level level, uint32_t accepted_encodings) { + GRPC_API_TRACE("grpc_compression_algorithm_for_level(level=%d)", 1, + ((int)level)); + if (level > GRPC_COMPRESS_LEVEL_HIGH) { + gpr_log(GPR_ERROR, "Unknown compression level %d.", (int)level); + abort(); + } + + const size_t num_supported = + GPR_BITCOUNT(accepted_encodings) - 1; /* discard NONE */ + if (level == GRPC_COMPRESS_LEVEL_NONE || num_supported == 0) { + return GRPC_COMPRESS_NONE; + } + + GPR_ASSERT(level > 0); + + /* Establish a "ranking" or compression algorithms in increasing order of + * compression. + * This is simplistic and we will probably want to introduce other dimensions + * in the future (cpu/memory cost, etc). */ + const grpc_compression_algorithm algos_ranking[] = {GRPC_COMPRESS_GZIP, + GRPC_COMPRESS_DEFLATE}; + + /* intersect algos_ranking with the supported ones keeping the ranked order */ + grpc_compression_algorithm + sorted_supported_algos[GRPC_COMPRESS_ALGORITHMS_COUNT]; + size_t algos_supported_idx = 0; + for (size_t i = 0; i < GPR_ARRAY_SIZE(algos_ranking); i++) { + const grpc_compression_algorithm alg = algos_ranking[i]; + for (size_t j = 0; j < num_supported; j++) { + if (GPR_BITGET(accepted_encodings, alg) == 1) { + /* if \a alg in supported */ + sorted_supported_algos[algos_supported_idx++] = alg; + break; + } + } + if (algos_supported_idx == num_supported) break; + } + + switch (level) { + case GRPC_COMPRESS_LEVEL_NONE: + abort(); /* should have been handled already */ + case GRPC_COMPRESS_LEVEL_LOW: + return sorted_supported_algos[0]; + case GRPC_COMPRESS_LEVEL_MED: + return sorted_supported_algos[num_supported / 2]; + case GRPC_COMPRESS_LEVEL_HIGH: + return sorted_supported_algos[num_supported - 1]; + default: + 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) { + return GPR_BITGET(opts->enabled_algorithms_bitset, algorithm); +} diff --git a/src/core/lib/compression/message_compress.c b/src/core/lib/compression/message_compress.c new file mode 100644 index 0000000000..edc21a9eb7 --- /dev/null +++ b/src/core/lib/compression/message_compress.c @@ -0,0 +1,198 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/compression/message_compress.h" + +#include + +#include +#include + +#include + +#define OUTPUT_BLOCK_SIZE 1024 + +static int zlib_body(z_stream* zs, gpr_slice_buffer* input, + gpr_slice_buffer* output, + int (*flate)(z_stream* zs, int flush)) { + int r; + int flush; + size_t i; + gpr_slice outbuf = gpr_slice_malloc(OUTPUT_BLOCK_SIZE); + const uInt uint_max = ~(uInt)0; + + GPR_ASSERT(GPR_SLICE_LENGTH(outbuf) <= uint_max); + zs->avail_out = (uInt)GPR_SLICE_LENGTH(outbuf); + zs->next_out = GPR_SLICE_START_PTR(outbuf); + flush = Z_NO_FLUSH; + for (i = 0; i < input->count; i++) { + if (i == input->count - 1) flush = Z_FINISH; + GPR_ASSERT(GPR_SLICE_LENGTH(input->slices[i]) <= uint_max); + zs->avail_in = (uInt)GPR_SLICE_LENGTH(input->slices[i]); + zs->next_in = GPR_SLICE_START_PTR(input->slices[i]); + do { + if (zs->avail_out == 0) { + gpr_slice_buffer_add_indexed(output, outbuf); + outbuf = gpr_slice_malloc(OUTPUT_BLOCK_SIZE); + GPR_ASSERT(GPR_SLICE_LENGTH(outbuf) <= uint_max); + zs->avail_out = (uInt)GPR_SLICE_LENGTH(outbuf); + zs->next_out = GPR_SLICE_START_PTR(outbuf); + } + r = flate(zs, flush); + if (r < 0 && r != Z_BUF_ERROR /* not fatal */) { + gpr_log(GPR_INFO, "zlib error (%d)", r); + goto error; + } + } while (zs->avail_out == 0); + if (zs->avail_in) { + gpr_log(GPR_INFO, "zlib: not all input consumed"); + goto error; + } + } + + GPR_ASSERT(outbuf.refcount); + outbuf.data.refcounted.length -= zs->avail_out; + gpr_slice_buffer_add_indexed(output, outbuf); + + return 1; + +error: + gpr_slice_unref(outbuf); + return 0; +} + +static void* zalloc_gpr(void* opaque, unsigned int items, unsigned int size) { + return gpr_malloc(items * size); +} + +static void zfree_gpr(void* opaque, void* address) { gpr_free(address); } + +static int zlib_compress(gpr_slice_buffer* input, gpr_slice_buffer* output, + int gzip) { + z_stream zs; + int r; + size_t i; + size_t count_before = output->count; + size_t length_before = output->length; + memset(&zs, 0, sizeof(zs)); + zs.zalloc = zalloc_gpr; + zs.zfree = zfree_gpr; + r = deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 | (gzip ? 16 : 0), + 8, Z_DEFAULT_STRATEGY); + GPR_ASSERT(r == Z_OK); + r = zlib_body(&zs, input, output, deflate) && output->length < input->length; + if (!r) { + for (i = count_before; i < output->count; i++) { + gpr_slice_unref(output->slices[i]); + } + output->count = count_before; + output->length = length_before; + } + deflateEnd(&zs); + return r; +} + +static int zlib_decompress(gpr_slice_buffer* input, gpr_slice_buffer* output, + int gzip) { + z_stream zs; + int r; + size_t i; + size_t count_before = output->count; + size_t length_before = output->length; + memset(&zs, 0, sizeof(zs)); + zs.zalloc = zalloc_gpr; + zs.zfree = zfree_gpr; + r = inflateInit2(&zs, 15 | (gzip ? 16 : 0)); + GPR_ASSERT(r == Z_OK); + r = zlib_body(&zs, input, output, inflate); + if (!r) { + for (i = count_before; i < output->count; i++) { + gpr_slice_unref(output->slices[i]); + } + output->count = count_before; + output->length = length_before; + } + inflateEnd(&zs); + return r; +} + +static int copy(gpr_slice_buffer* input, gpr_slice_buffer* output) { + size_t i; + for (i = 0; i < input->count; i++) { + gpr_slice_buffer_add(output, gpr_slice_ref(input->slices[i])); + } + return 1; +} + +static int compress_inner(grpc_compression_algorithm algorithm, + gpr_slice_buffer* input, gpr_slice_buffer* output) { + switch (algorithm) { + case GRPC_COMPRESS_NONE: + /* the fallback path always needs to be send uncompressed: we simply + rely on that here */ + return 0; + case GRPC_COMPRESS_DEFLATE: + return zlib_compress(input, output, 0); + case GRPC_COMPRESS_GZIP: + return zlib_compress(input, output, 1); + case GRPC_COMPRESS_ALGORITHMS_COUNT: + break; + } + gpr_log(GPR_ERROR, "invalid compression algorithm %d", algorithm); + return 0; +} + +int grpc_msg_compress(grpc_compression_algorithm algorithm, + gpr_slice_buffer* input, gpr_slice_buffer* output) { + if (!compress_inner(algorithm, input, output)) { + copy(input, output); + return 0; + } + return 1; +} + +int grpc_msg_decompress(grpc_compression_algorithm algorithm, + gpr_slice_buffer* input, gpr_slice_buffer* output) { + switch (algorithm) { + case GRPC_COMPRESS_NONE: + return copy(input, output); + case GRPC_COMPRESS_DEFLATE: + return zlib_decompress(input, output, 0); + case GRPC_COMPRESS_GZIP: + return zlib_decompress(input, output, 1); + case GRPC_COMPRESS_ALGORITHMS_COUNT: + break; + } + gpr_log(GPR_ERROR, "invalid compression algorithm %d", algorithm); + return 0; +} diff --git a/src/core/lib/compression/message_compress.h b/src/core/lib/compression/message_compress.h new file mode 100644 index 0000000000..20b78c063b --- /dev/null +++ b/src/core/lib/compression/message_compress.h @@ -0,0 +1,52 @@ +/* + * + * Copyright 2015-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_COMPRESSION_MESSAGE_COMPRESS_H +#define GRPC_CORE_COMPRESSION_MESSAGE_COMPRESS_H + +#include +#include + +/* compress 'input' to 'output' using 'algorithm'. + On success, appends compressed slices to output and returns 1. + On failure, appends uncompressed slices to output and returns 0. */ +int grpc_msg_compress(grpc_compression_algorithm algorithm, + gpr_slice_buffer* input, gpr_slice_buffer* output); + +/* decompress 'input' to 'output' using 'algorithm'. + On success, appends slices to output and returns 1. + On failure, output is unchanged, and returns 0. */ +int grpc_msg_decompress(grpc_compression_algorithm algorithm, + gpr_slice_buffer* input, gpr_slice_buffer* output); + +#endif /* GRPC_CORE_COMPRESSION_MESSAGE_COMPRESS_H */ diff --git a/src/core/lib/debug/trace.c b/src/core/lib/debug/trace.c new file mode 100644 index 0000000000..3b35d81cd8 --- /dev/null +++ b/src/core/lib/debug/trace.c @@ -0,0 +1,136 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/debug/trace.h" + +#include + +#include +#include +#include +#include "src/core/support/env.h" + +typedef struct tracer { + const char *name; + int *flag; + struct tracer *next; +} tracer; +static tracer *tracers; + +void grpc_register_tracer(const char *name, int *flag) { + tracer *t = gpr_malloc(sizeof(*t)); + t->name = name; + t->flag = flag; + t->next = tracers; + *flag = 0; + tracers = t; +} + +static void add(const char *beg, const char *end, char ***ss, size_t *ns) { + size_t n = *ns; + size_t np = n + 1; + char *s; + size_t len; + GPR_ASSERT(end >= beg); + len = (size_t)(end - beg); + s = gpr_malloc(len + 1); + memcpy(s, beg, len); + s[len] = 0; + *ss = gpr_realloc(*ss, sizeof(char **) * np); + (*ss)[n] = s; + *ns = np; +} + +static void split(const char *s, char ***ss, size_t *ns) { + const char *c = strchr(s, ','); + if (c == NULL) { + add(s, s + strlen(s), ss, ns); + } else { + add(s, c, ss, ns); + split(c + 1, ss, ns); + } +} + +static void parse(const char *s) { + char **strings = NULL; + size_t nstrings = 0; + size_t i; + split(s, &strings, &nstrings); + + for (i = 0; i < nstrings; i++) { + grpc_tracer_set_enabled(strings[i], 1); + } + + for (i = 0; i < nstrings; i++) { + gpr_free(strings[i]); + } + gpr_free(strings); +} + +void grpc_tracer_init(const char *env_var) { + char *e = gpr_getenv(env_var); + if (e != NULL) { + parse(e); + gpr_free(e); + } +} + +void grpc_tracer_shutdown(void) { + while (tracers) { + tracer *t = tracers; + tracers = t->next; + gpr_free(t); + } +} + +int grpc_tracer_set_enabled(const char *name, int enabled) { + tracer *t; + if (0 == strcmp(name, "all")) { + for (t = tracers; t; t = t->next) { + *t->flag = 1; + } + } else { + int found = 0; + for (t = tracers; t; t = t->next) { + if (0 == strcmp(name, t->name)) { + *t->flag = enabled; + found = 1; + } + } + if (!found) { + gpr_log(GPR_ERROR, "Unknown trace var: '%s'", name); + return 0; /* early return */ + } + } + return 1; +} diff --git a/src/core/lib/debug/trace.h b/src/core/lib/debug/trace.h new file mode 100644 index 0000000000..91ec14052e --- /dev/null +++ b/src/core/lib/debug/trace.h @@ -0,0 +1,43 @@ +/* + * + * Copyright 2015-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_DEBUG_TRACE_H +#define GRPC_CORE_DEBUG_TRACE_H + +#include + +void grpc_register_tracer(const char *name, int *flag); +void grpc_tracer_init(const char *env_var_name); +void grpc_tracer_shutdown(void); + +#endif /* GRPC_CORE_DEBUG_TRACE_H */ diff --git a/src/core/lib/http/format_request.c b/src/core/lib/http/format_request.c new file mode 100644 index 0000000000..ac9bb8aeb8 --- /dev/null +++ b/src/core/lib/http/format_request.c @@ -0,0 +1,120 @@ +/* + * + * Copyright 2015-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/http/format_request.h" + +#include +#include +#include + +#include +#include +#include +#include +#include "src/core/support/string.h" + +static void fill_common_header(const grpc_httpcli_request *request, + gpr_strvec *buf) { + size_t i; + gpr_strvec_add(buf, gpr_strdup(request->http.path)); + gpr_strvec_add(buf, gpr_strdup(" HTTP/1.0\r\n")); + /* just in case some crazy server really expects HTTP/1.1 */ + gpr_strvec_add(buf, gpr_strdup("Host: ")); + gpr_strvec_add(buf, gpr_strdup(request->host)); + gpr_strvec_add(buf, gpr_strdup("\r\n")); + gpr_strvec_add(buf, gpr_strdup("Connection: close\r\n")); + gpr_strvec_add(buf, + gpr_strdup("User-Agent: " GRPC_HTTPCLI_USER_AGENT "\r\n")); + /* user supplied headers */ + for (i = 0; i < request->http.hdr_count; i++) { + gpr_strvec_add(buf, gpr_strdup(request->http.hdrs[i].key)); + gpr_strvec_add(buf, gpr_strdup(": ")); + gpr_strvec_add(buf, gpr_strdup(request->http.hdrs[i].value)); + gpr_strvec_add(buf, gpr_strdup("\r\n")); + } +} + +gpr_slice grpc_httpcli_format_get_request(const grpc_httpcli_request *request) { + gpr_strvec out; + char *flat; + size_t flat_len; + + gpr_strvec_init(&out); + gpr_strvec_add(&out, gpr_strdup("GET ")); + fill_common_header(request, &out); + gpr_strvec_add(&out, gpr_strdup("\r\n")); + + flat = gpr_strvec_flatten(&out, &flat_len); + gpr_strvec_destroy(&out); + + return gpr_slice_new(flat, flat_len, gpr_free); +} + +gpr_slice grpc_httpcli_format_post_request(const grpc_httpcli_request *request, + const char *body_bytes, + size_t body_size) { + gpr_strvec out; + char *tmp; + size_t out_len; + size_t i; + + gpr_strvec_init(&out); + + gpr_strvec_add(&out, gpr_strdup("POST ")); + fill_common_header(request, &out); + if (body_bytes) { + uint8_t has_content_type = 0; + for (i = 0; i < request->http.hdr_count; i++) { + if (strcmp(request->http.hdrs[i].key, "Content-Type") == 0) { + has_content_type = 1; + break; + } + } + if (!has_content_type) { + gpr_strvec_add(&out, gpr_strdup("Content-Type: text/plain\r\n")); + } + gpr_asprintf(&tmp, "Content-Length: %lu\r\n", (unsigned long)body_size); + gpr_strvec_add(&out, tmp); + } + gpr_strvec_add(&out, gpr_strdup("\r\n")); + tmp = gpr_strvec_flatten(&out, &out_len); + gpr_strvec_destroy(&out); + + if (body_bytes) { + tmp = gpr_realloc(tmp, out_len + body_size); + memcpy(tmp + out_len, body_bytes, body_size); + out_len += body_size; + } + + return gpr_slice_new(tmp, out_len, gpr_free); +} diff --git a/src/core/lib/http/format_request.h b/src/core/lib/http/format_request.h new file mode 100644 index 0000000000..dfd6fadbde --- /dev/null +++ b/src/core/lib/http/format_request.h @@ -0,0 +1,45 @@ +/* + * + * Copyright 2015-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_HTTP_FORMAT_REQUEST_H +#define GRPC_CORE_HTTP_FORMAT_REQUEST_H + +#include +#include "src/core/http/httpcli.h" + +gpr_slice grpc_httpcli_format_get_request(const grpc_httpcli_request *request); +gpr_slice grpc_httpcli_format_post_request(const grpc_httpcli_request *request, + const char *body_bytes, + size_t body_size); + +#endif /* GRPC_CORE_HTTP_FORMAT_REQUEST_H */ diff --git a/src/core/lib/http/httpcli.c b/src/core/lib/http/httpcli.c new file mode 100644 index 0000000000..1c0d3336ea --- /dev/null +++ b/src/core/lib/http/httpcli.c @@ -0,0 +1,293 @@ +/* + * + * Copyright 2015-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/http/httpcli.h" +#include "src/core/iomgr/sockaddr.h" + +#include + +#include +#include +#include + +#include "src/core/http/format_request.h" +#include "src/core/http/parser.h" +#include "src/core/iomgr/endpoint.h" +#include "src/core/iomgr/iomgr_internal.h" +#include "src/core/iomgr/resolve_address.h" +#include "src/core/iomgr/tcp_client.h" +#include "src/core/support/string.h" + +typedef struct { + gpr_slice request_text; + grpc_http_parser parser; + grpc_resolved_addresses *addresses; + size_t next_address; + grpc_endpoint *ep; + char *host; + char *ssl_host_override; + gpr_timespec deadline; + int have_read_byte; + const grpc_httpcli_handshaker *handshaker; + grpc_httpcli_response_cb on_response; + void *user_data; + grpc_httpcli_context *context; + grpc_pollset *pollset; + grpc_iomgr_object iomgr_obj; + gpr_slice_buffer incoming; + gpr_slice_buffer outgoing; + grpc_closure on_read; + grpc_closure done_write; + grpc_closure connected; +} internal_request; + +static grpc_httpcli_get_override g_get_override = NULL; +static grpc_httpcli_post_override g_post_override = NULL; + +static void plaintext_handshake(grpc_exec_ctx *exec_ctx, void *arg, + grpc_endpoint *endpoint, const char *host, + void (*on_done)(grpc_exec_ctx *exec_ctx, + void *arg, + grpc_endpoint *endpoint)) { + on_done(exec_ctx, arg, endpoint); +} + +const grpc_httpcli_handshaker grpc_httpcli_plaintext = {"http", + plaintext_handshake}; + +void grpc_httpcli_context_init(grpc_httpcli_context *context) { + context->pollset_set = grpc_pollset_set_create(); +} + +void grpc_httpcli_context_destroy(grpc_httpcli_context *context) { + grpc_pollset_set_destroy(context->pollset_set); +} + +static void next_address(grpc_exec_ctx *exec_ctx, internal_request *req); + +static void finish(grpc_exec_ctx *exec_ctx, internal_request *req, + int success) { + grpc_pollset_set_del_pollset(exec_ctx, req->context->pollset_set, + req->pollset); + req->on_response(exec_ctx, req->user_data, + success ? &req->parser.http.response : NULL); + grpc_http_parser_destroy(&req->parser); + if (req->addresses != NULL) { + grpc_resolved_addresses_destroy(req->addresses); + } + if (req->ep != NULL) { + grpc_endpoint_destroy(exec_ctx, req->ep); + } + gpr_slice_unref(req->request_text); + gpr_free(req->host); + gpr_free(req->ssl_host_override); + grpc_iomgr_unregister_object(&req->iomgr_obj); + gpr_slice_buffer_destroy(&req->incoming); + gpr_slice_buffer_destroy(&req->outgoing); + gpr_free(req); +} + +static void on_read(grpc_exec_ctx *exec_ctx, void *user_data, bool success); + +static void do_read(grpc_exec_ctx *exec_ctx, internal_request *req) { + grpc_endpoint_read(exec_ctx, req->ep, &req->incoming, &req->on_read); +} + +static void on_read(grpc_exec_ctx *exec_ctx, void *user_data, bool success) { + internal_request *req = user_data; + size_t i; + + for (i = 0; i < req->incoming.count; i++) { + if (GPR_SLICE_LENGTH(req->incoming.slices[i])) { + req->have_read_byte = 1; + if (!grpc_http_parser_parse(&req->parser, req->incoming.slices[i])) { + finish(exec_ctx, req, 0); + return; + } + } + } + + if (success) { + do_read(exec_ctx, req); + } else if (!req->have_read_byte) { + next_address(exec_ctx, req); + } else { + int parse_success = grpc_http_parser_eof(&req->parser); + if (parse_success && (req->parser.type != GRPC_HTTP_RESPONSE)) { + parse_success = 0; + } + finish(exec_ctx, req, parse_success); + } +} + +static void on_written(grpc_exec_ctx *exec_ctx, internal_request *req) { + do_read(exec_ctx, req); +} + +static void done_write(grpc_exec_ctx *exec_ctx, void *arg, bool success) { + internal_request *req = arg; + if (success) { + on_written(exec_ctx, req); + } else { + next_address(exec_ctx, req); + } +} + +static void start_write(grpc_exec_ctx *exec_ctx, internal_request *req) { + gpr_slice_ref(req->request_text); + gpr_slice_buffer_add(&req->outgoing, req->request_text); + grpc_endpoint_write(exec_ctx, req->ep, &req->outgoing, &req->done_write); +} + +static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg, + grpc_endpoint *ep) { + internal_request *req = arg; + + if (!ep) { + next_address(exec_ctx, req); + return; + } + + req->ep = ep; + start_write(exec_ctx, req); +} + +static void on_connected(grpc_exec_ctx *exec_ctx, void *arg, bool success) { + internal_request *req = arg; + + if (!req->ep) { + next_address(exec_ctx, req); + return; + } + req->handshaker->handshake( + exec_ctx, req, req->ep, + req->ssl_host_override ? req->ssl_host_override : req->host, + on_handshake_done); +} + +static void next_address(grpc_exec_ctx *exec_ctx, internal_request *req) { + grpc_resolved_address *addr; + if (req->next_address == req->addresses->naddrs) { + finish(exec_ctx, req, 0); + return; + } + addr = &req->addresses->addrs[req->next_address++]; + grpc_closure_init(&req->connected, on_connected, req); + grpc_tcp_client_connect( + exec_ctx, &req->connected, &req->ep, req->context->pollset_set, + (struct sockaddr *)&addr->addr, addr->len, req->deadline); +} + +static void on_resolved(grpc_exec_ctx *exec_ctx, void *arg, + grpc_resolved_addresses *addresses) { + internal_request *req = arg; + if (!addresses) { + finish(exec_ctx, req, 0); + return; + } + req->addresses = addresses; + req->next_address = 0; + next_address(exec_ctx, req); +} + +static void internal_request_begin( + grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context, + grpc_pollset *pollset, const grpc_httpcli_request *request, + gpr_timespec deadline, grpc_httpcli_response_cb on_response, + void *user_data, const char *name, gpr_slice request_text) { + internal_request *req = gpr_malloc(sizeof(internal_request)); + memset(req, 0, sizeof(*req)); + req->request_text = request_text; + grpc_http_parser_init(&req->parser); + req->on_response = on_response; + req->user_data = user_data; + req->deadline = deadline; + req->handshaker = + request->handshaker ? request->handshaker : &grpc_httpcli_plaintext; + req->context = context; + req->pollset = pollset; + grpc_closure_init(&req->on_read, on_read, req); + grpc_closure_init(&req->done_write, done_write, req); + gpr_slice_buffer_init(&req->incoming); + gpr_slice_buffer_init(&req->outgoing); + grpc_iomgr_register_object(&req->iomgr_obj, name); + req->host = gpr_strdup(request->host); + req->ssl_host_override = gpr_strdup(request->ssl_host_override); + + grpc_pollset_set_add_pollset(exec_ctx, req->context->pollset_set, + req->pollset); + grpc_resolve_address(request->host, req->handshaker->default_port, + on_resolved, req); +} + +void grpc_httpcli_get(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context, + grpc_pollset *pollset, + const grpc_httpcli_request *request, + gpr_timespec deadline, + grpc_httpcli_response_cb on_response, void *user_data) { + char *name; + if (g_get_override && + g_get_override(exec_ctx, request, deadline, on_response, user_data)) { + return; + } + gpr_asprintf(&name, "HTTP:GET:%s:%s", request->host, request->http.path); + internal_request_begin(exec_ctx, context, pollset, request, deadline, + on_response, user_data, name, + grpc_httpcli_format_get_request(request)); + gpr_free(name); +} + +void grpc_httpcli_post(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context, + grpc_pollset *pollset, + const grpc_httpcli_request *request, + const char *body_bytes, size_t body_size, + gpr_timespec deadline, + grpc_httpcli_response_cb on_response, void *user_data) { + char *name; + if (g_post_override && + g_post_override(exec_ctx, request, body_bytes, body_size, deadline, + on_response, user_data)) { + return; + } + gpr_asprintf(&name, "HTTP:POST:%s:%s", request->host, request->http.path); + internal_request_begin( + exec_ctx, context, pollset, request, deadline, on_response, user_data, + name, grpc_httpcli_format_post_request(request, body_bytes, body_size)); + gpr_free(name); +} + +void grpc_httpcli_set_override(grpc_httpcli_get_override get, + grpc_httpcli_post_override post) { + g_get_override = get; + g_post_override = post; +} diff --git a/src/core/lib/http/httpcli.h b/src/core/lib/http/httpcli.h new file mode 100644 index 0000000000..0bf4f2f445 --- /dev/null +++ b/src/core/lib/http/httpcli.h @@ -0,0 +1,144 @@ +/* + * + * Copyright 2015-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_HTTP_HTTPCLI_H +#define GRPC_CORE_HTTP_HTTPCLI_H + +#include + +#include + +#include "src/core/http/parser.h" +#include "src/core/iomgr/endpoint.h" +#include "src/core/iomgr/iomgr_internal.h" +#include "src/core/iomgr/pollset_set.h" + +/* User agent this library reports */ +#define GRPC_HTTPCLI_USER_AGENT "grpc-httpcli/0.0" + +/* Tracks in-progress http requests + TODO(ctiller): allow caching and capturing multiple requests for the + same content and combining them */ +typedef struct grpc_httpcli_context { + grpc_pollset_set *pollset_set; +} grpc_httpcli_context; + +typedef struct { + const char *default_port; + void (*handshake)(grpc_exec_ctx *exec_ctx, void *arg, grpc_endpoint *endpoint, + const char *host, + void (*on_done)(grpc_exec_ctx *exec_ctx, void *arg, + grpc_endpoint *endpoint)); +} grpc_httpcli_handshaker; + +extern const grpc_httpcli_handshaker grpc_httpcli_plaintext; +extern const grpc_httpcli_handshaker grpc_httpcli_ssl; + +/* A request */ +typedef struct grpc_httpcli_request { + /* The host name to connect to */ + char *host; + /* The host to verify in the SSL handshake (or NULL) */ + char *ssl_host_override; + /* The main part of the request + The following headers are supplied automatically and MUST NOT be set here: + Host, Connection, User-Agent */ + grpc_http_request http; + /* handshaker to use ssl for the request */ + const grpc_httpcli_handshaker *handshaker; +} grpc_httpcli_request; + +/* Expose the parser response type as a httpcli response too */ +typedef struct grpc_http_response grpc_httpcli_response; + +/* Callback for grpc_httpcli_get and grpc_httpcli_post. */ +typedef void (*grpc_httpcli_response_cb)(grpc_exec_ctx *exec_ctx, + void *user_data, + const grpc_http_response *response); + +void grpc_httpcli_context_init(grpc_httpcli_context *context); +void grpc_httpcli_context_destroy(grpc_httpcli_context *context); + +/* Asynchronously perform a HTTP GET. + 'context' specifies the http context under which to do the get + 'pollset' indicates a grpc_pollset that is interested in the result + of the get - work on this pollset may be used to progress the get + operation + 'request' contains request parameters - these are caller owned and can be + destroyed once the call returns + 'deadline' contains a deadline for the request (or gpr_inf_future) + 'on_response' is a callback to report results to (and 'user_data' is a user + supplied pointer to pass to said call) */ +void grpc_httpcli_get(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context, + grpc_pollset *pollset, + const grpc_httpcli_request *request, + gpr_timespec deadline, + grpc_httpcli_response_cb on_response, void *user_data); + +/* Asynchronously perform a HTTP POST. + 'context' specifies the http context under which to do the post + 'pollset' indicates a grpc_pollset that is interested in the result + of the post - work on this pollset may be used to progress the post + operation + 'request' contains request parameters - these are caller owned and can be + destroyed once the call returns + 'body_bytes' and 'body_size' specify the payload for the post. + When there is no body, pass in NULL as body_bytes. + 'deadline' contains a deadline for the request (or gpr_inf_future) + 'em' points to a caller owned event manager that must be alive for the + lifetime of the request + 'on_response' is a callback to report results to (and 'user_data' is a user + supplied pointer to pass to said call) + Does not support ?var1=val1&var2=val2 in the path. */ +void grpc_httpcli_post(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context, + grpc_pollset *pollset, + const grpc_httpcli_request *request, + const char *body_bytes, size_t body_size, + gpr_timespec deadline, + grpc_httpcli_response_cb on_response, void *user_data); + +/* override functions return 1 if they handled the request, 0 otherwise */ +typedef int (*grpc_httpcli_get_override)(grpc_exec_ctx *exec_ctx, + const grpc_httpcli_request *request, + gpr_timespec deadline, + grpc_httpcli_response_cb on_response, + void *user_data); +typedef int (*grpc_httpcli_post_override)( + grpc_exec_ctx *exec_ctx, const grpc_httpcli_request *request, + const char *body_bytes, size_t body_size, gpr_timespec deadline, + grpc_httpcli_response_cb on_response, void *user_data); + +void grpc_httpcli_set_override(grpc_httpcli_get_override get, + grpc_httpcli_post_override post); + +#endif /* GRPC_CORE_HTTP_HTTPCLI_H */ diff --git a/src/core/lib/http/httpcli_security_connector.c b/src/core/lib/http/httpcli_security_connector.c new file mode 100644 index 0000000000..a1a32f7558 --- /dev/null +++ b/src/core/lib/http/httpcli_security_connector.c @@ -0,0 +1,188 @@ +/* + * + * Copyright 2015-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/http/httpcli.h" + +#include + +#include +#include +#include +#include "src/core/security/handshake.h" +#include "src/core/support/string.h" +#include "src/core/tsi/ssl_transport_security.h" + +typedef struct { + grpc_channel_security_connector base; + tsi_ssl_handshaker_factory *handshaker_factory; + char *secure_peer_name; +} grpc_httpcli_ssl_channel_security_connector; + +static void httpcli_ssl_destroy(grpc_security_connector *sc) { + grpc_httpcli_ssl_channel_security_connector *c = + (grpc_httpcli_ssl_channel_security_connector *)sc; + if (c->handshaker_factory != NULL) { + tsi_ssl_handshaker_factory_destroy(c->handshaker_factory); + } + if (c->secure_peer_name != NULL) gpr_free(c->secure_peer_name); + gpr_free(sc); +} + +static void httpcli_ssl_do_handshake(grpc_exec_ctx *exec_ctx, + grpc_channel_security_connector *sc, + grpc_endpoint *nonsecure_endpoint, + grpc_security_handshake_done_cb cb, + void *user_data) { + grpc_httpcli_ssl_channel_security_connector *c = + (grpc_httpcli_ssl_channel_security_connector *)sc; + tsi_result result = TSI_OK; + tsi_handshaker *handshaker; + if (c->handshaker_factory == NULL) { + cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL); + return; + } + result = tsi_ssl_handshaker_factory_create_handshaker( + c->handshaker_factory, c->secure_peer_name, &handshaker); + if (result != TSI_OK) { + gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.", + tsi_result_to_string(result)); + cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL); + } else { + grpc_do_security_handshake(exec_ctx, handshaker, &sc->base, true, + nonsecure_endpoint, cb, user_data); + } +} + +static void httpcli_ssl_check_peer(grpc_exec_ctx *exec_ctx, + grpc_security_connector *sc, tsi_peer peer, + grpc_security_peer_check_cb cb, + void *user_data) { + grpc_httpcli_ssl_channel_security_connector *c = + (grpc_httpcli_ssl_channel_security_connector *)sc; + grpc_security_status status = GRPC_SECURITY_OK; + + /* Check the peer name. */ + if (c->secure_peer_name != NULL && + !tsi_ssl_peer_matches_name(&peer, c->secure_peer_name)) { + gpr_log(GPR_ERROR, "Peer name %s is not in peer certificate", + c->secure_peer_name); + status = GRPC_SECURITY_ERROR; + } + cb(exec_ctx, user_data, status, NULL); + tsi_peer_destruct(&peer); +} + +static grpc_security_connector_vtable httpcli_ssl_vtable = { + httpcli_ssl_destroy, httpcli_ssl_check_peer}; + +static grpc_security_status httpcli_ssl_channel_security_connector_create( + const unsigned char *pem_root_certs, size_t pem_root_certs_size, + const char *secure_peer_name, grpc_channel_security_connector **sc) { + tsi_result result = TSI_OK; + grpc_httpcli_ssl_channel_security_connector *c; + + if (secure_peer_name != NULL && pem_root_certs == NULL) { + gpr_log(GPR_ERROR, + "Cannot assert a secure peer name without a trust root."); + return GRPC_SECURITY_ERROR; + } + + c = gpr_malloc(sizeof(grpc_httpcli_ssl_channel_security_connector)); + memset(c, 0, sizeof(grpc_httpcli_ssl_channel_security_connector)); + + gpr_ref_init(&c->base.base.refcount, 1); + c->base.base.vtable = &httpcli_ssl_vtable; + if (secure_peer_name != NULL) { + c->secure_peer_name = gpr_strdup(secure_peer_name); + } + result = tsi_create_ssl_client_handshaker_factory( + NULL, 0, NULL, 0, pem_root_certs, pem_root_certs_size, NULL, NULL, NULL, + 0, &c->handshaker_factory); + if (result != TSI_OK) { + gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.", + tsi_result_to_string(result)); + httpcli_ssl_destroy(&c->base.base); + *sc = NULL; + return GRPC_SECURITY_ERROR; + } + c->base.do_handshake = httpcli_ssl_do_handshake; + *sc = &c->base; + return GRPC_SECURITY_OK; +} + +/* handshaker */ + +typedef struct { + void (*func)(grpc_exec_ctx *exec_ctx, void *arg, grpc_endpoint *endpoint); + void *arg; +} on_done_closure; + +static void on_secure_transport_setup_done(grpc_exec_ctx *exec_ctx, void *rp, + grpc_security_status status, + grpc_endpoint *secure_endpoint, + grpc_auth_context *auth_context) { + on_done_closure *c = rp; + if (status != GRPC_SECURITY_OK) { + gpr_log(GPR_ERROR, "Secure transport setup failed with error %d.", status); + c->func(exec_ctx, c->arg, NULL); + } else { + c->func(exec_ctx, c->arg, secure_endpoint); + } + gpr_free(c); +} + +static void ssl_handshake(grpc_exec_ctx *exec_ctx, void *arg, + grpc_endpoint *tcp, const char *host, + void (*on_done)(grpc_exec_ctx *exec_ctx, void *arg, + grpc_endpoint *endpoint)) { + grpc_channel_security_connector *sc = NULL; + const unsigned char *pem_root_certs = NULL; + on_done_closure *c = gpr_malloc(sizeof(*c)); + size_t pem_root_certs_size = grpc_get_default_ssl_roots(&pem_root_certs); + if (pem_root_certs == NULL || pem_root_certs_size == 0) { + gpr_log(GPR_ERROR, "Could not get default pem root certs."); + on_done(exec_ctx, arg, NULL); + gpr_free(c); + return; + } + c->func = on_done; + c->arg = arg; + GPR_ASSERT(httpcli_ssl_channel_security_connector_create( + pem_root_certs, pem_root_certs_size, host, &sc) == + GRPC_SECURITY_OK); + grpc_channel_security_connector_do_handshake( + exec_ctx, sc, tcp, on_secure_transport_setup_done, c); + GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "httpcli"); +} + +const grpc_httpcli_handshaker grpc_httpcli_ssl = {"https", ssl_handshake}; diff --git a/src/core/lib/http/parser.c b/src/core/lib/http/parser.c new file mode 100644 index 0000000000..ebec8a5157 --- /dev/null +++ b/src/core/lib/http/parser.c @@ -0,0 +1,313 @@ +/* + * + * Copyright 2015-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/http/parser.h" + +#include + +#include +#include +#include + +static char *buf2str(void *buffer, size_t length) { + char *out = gpr_malloc(length + 1); + memcpy(out, buffer, length); + out[length] = 0; + return out; +} + +static int handle_response_line(grpc_http_parser *parser) { + uint8_t *beg = parser->cur_line; + uint8_t *cur = beg; + uint8_t *end = beg + parser->cur_line_length; + + if (cur == end || *cur++ != 'H') goto error; + if (cur == end || *cur++ != 'T') goto error; + if (cur == end || *cur++ != 'T') goto error; + if (cur == end || *cur++ != 'P') goto error; + if (cur == end || *cur++ != '/') goto error; + if (cur == end || *cur++ != '1') goto error; + if (cur == end || *cur++ != '.') goto error; + if (cur == end || *cur < '0' || *cur++ > '1') goto error; + if (cur == end || *cur++ != ' ') goto error; + if (cur == end || *cur < '1' || *cur++ > '9') goto error; + if (cur == end || *cur < '0' || *cur++ > '9') goto error; + if (cur == end || *cur < '0' || *cur++ > '9') goto error; + parser->http.response.status = + (cur[-3] - '0') * 100 + (cur[-2] - '0') * 10 + (cur[-1] - '0'); + if (cur == end || *cur++ != ' ') goto error; + + /* we don't really care about the status code message */ + + return 1; + +error: + gpr_log(GPR_ERROR, "Failed parsing response line"); + return 0; +} + +static int handle_request_line(grpc_http_parser *parser) { + uint8_t *beg = parser->cur_line; + uint8_t *cur = beg; + uint8_t *end = beg + parser->cur_line_length; + uint8_t vers_major = 0; + uint8_t vers_minor = 0; + + while (cur != end && *cur++ != ' ') + ; + if (cur == end) goto error; + parser->http.request.method = buf2str(beg, (size_t)(cur - beg - 1)); + + beg = cur; + while (cur != end && *cur++ != ' ') + ; + if (cur == end) goto error; + parser->http.request.path = buf2str(beg, (size_t)(cur - beg - 1)); + + if (cur == end || *cur++ != 'H') goto error; + if (cur == end || *cur++ != 'T') goto error; + if (cur == end || *cur++ != 'T') goto error; + if (cur == end || *cur++ != 'P') goto error; + if (cur == end || *cur++ != '/') goto error; + vers_major = (uint8_t)(*cur++ - '1' + 1); + ++cur; + if (cur == end) goto error; + vers_minor = (uint8_t)(*cur++ - '1' + 1); + + if (vers_major == 1) { + if (vers_minor == 0) { + parser->http.request.version = GRPC_HTTP_HTTP10; + } else if (vers_minor == 1) { + parser->http.request.version = GRPC_HTTP_HTTP11; + } else { + goto error; + } + } else if (vers_major == 2) { + if (vers_minor == 0) { + parser->http.request.version = GRPC_HTTP_HTTP20; + } else { + goto error; + } + } else { + goto error; + } + + return 1; + +error: + gpr_log(GPR_ERROR, "Failed parsing request line"); + return 0; +} + +static int handle_first_line(grpc_http_parser *parser) { + if (parser->cur_line[0] == 'H') { + parser->type = GRPC_HTTP_RESPONSE; + return handle_response_line(parser); + } else { + parser->type = GRPC_HTTP_REQUEST; + return handle_request_line(parser); + } +} + +static int add_header(grpc_http_parser *parser) { + uint8_t *beg = parser->cur_line; + uint8_t *cur = beg; + uint8_t *end = beg + parser->cur_line_length; + size_t *hdr_count = NULL; + grpc_http_header **hdrs = NULL; + grpc_http_header hdr = {NULL, NULL}; + + GPR_ASSERT(cur != end); + + if (*cur == ' ' || *cur == '\t') { + gpr_log(GPR_ERROR, "Continued header lines not supported yet"); + goto error; + } + + while (cur != end && *cur != ':') { + cur++; + } + if (cur == end) { + gpr_log(GPR_ERROR, "Didn't find ':' in header string"); + goto error; + } + GPR_ASSERT(cur >= beg); + hdr.key = buf2str(beg, (size_t)(cur - beg)); + cur++; /* skip : */ + + while (cur != end && (*cur == ' ' || *cur == '\t')) { + cur++; + } + GPR_ASSERT(end - cur >= 2); + hdr.value = buf2str(cur, (size_t)(end - cur) - 2); + + if (parser->type == GRPC_HTTP_RESPONSE) { + hdr_count = &parser->http.response.hdr_count; + hdrs = &parser->http.response.hdrs; + } else if (parser->type == GRPC_HTTP_REQUEST) { + hdr_count = &parser->http.request.hdr_count; + hdrs = &parser->http.request.hdrs; + } else { + return 0; + } + + if (*hdr_count == parser->hdr_capacity) { + parser->hdr_capacity = + GPR_MAX(parser->hdr_capacity + 1, parser->hdr_capacity * 3 / 2); + *hdrs = gpr_realloc(*hdrs, parser->hdr_capacity * sizeof(**hdrs)); + } + (*hdrs)[(*hdr_count)++] = hdr; + return 1; + +error: + gpr_free(hdr.key); + gpr_free(hdr.value); + return 0; +} + +static int finish_line(grpc_http_parser *parser) { + switch (parser->state) { + case GRPC_HTTP_FIRST_LINE: + if (!handle_first_line(parser)) { + return 0; + } + parser->state = GRPC_HTTP_HEADERS; + break; + case GRPC_HTTP_HEADERS: + if (parser->cur_line_length == 2) { + parser->state = GRPC_HTTP_BODY; + break; + } + if (!add_header(parser)) { + return 0; + } + break; + case GRPC_HTTP_BODY: + GPR_UNREACHABLE_CODE(return 0); + } + + parser->cur_line_length = 0; + return 1; +} + +static int addbyte_body(grpc_http_parser *parser, uint8_t byte) { + size_t *body_length = NULL; + char **body = NULL; + + if (parser->type == GRPC_HTTP_RESPONSE) { + body_length = &parser->http.response.body_length; + body = &parser->http.response.body; + } else if (parser->type == GRPC_HTTP_REQUEST) { + body_length = &parser->http.request.body_length; + body = &parser->http.request.body; + } else { + return 0; + } + + if (*body_length == parser->body_capacity) { + parser->body_capacity = GPR_MAX(8, parser->body_capacity * 3 / 2); + *body = gpr_realloc((void *)*body, parser->body_capacity); + } + (*body)[*body_length] = (char)byte; + (*body_length)++; + + return 1; +} + +static int addbyte(grpc_http_parser *parser, uint8_t byte) { + switch (parser->state) { + case GRPC_HTTP_FIRST_LINE: + case GRPC_HTTP_HEADERS: + if (parser->cur_line_length >= GRPC_HTTP_PARSER_MAX_HEADER_LENGTH) { + gpr_log(GPR_ERROR, "HTTP client max line length (%d) exceeded", + GRPC_HTTP_PARSER_MAX_HEADER_LENGTH); + return 0; + } + parser->cur_line[parser->cur_line_length] = byte; + parser->cur_line_length++; + if (parser->cur_line_length >= 2 && + parser->cur_line[parser->cur_line_length - 2] == '\r' && + parser->cur_line[parser->cur_line_length - 1] == '\n') { + return finish_line(parser); + } else { + return 1; + } + GPR_UNREACHABLE_CODE(return 0); + case GRPC_HTTP_BODY: + return addbyte_body(parser, byte); + } + GPR_UNREACHABLE_CODE(return 0); +} + +void grpc_http_parser_init(grpc_http_parser *parser) { + memset(parser, 0, sizeof(*parser)); + parser->state = GRPC_HTTP_FIRST_LINE; + parser->type = GRPC_HTTP_UNKNOWN; +} + +void grpc_http_parser_destroy(grpc_http_parser *parser) { + size_t i; + if (parser->type == GRPC_HTTP_RESPONSE) { + gpr_free(parser->http.response.body); + for (i = 0; i < parser->http.response.hdr_count; i++) { + gpr_free(parser->http.response.hdrs[i].key); + gpr_free(parser->http.response.hdrs[i].value); + } + gpr_free(parser->http.response.hdrs); + } else if (parser->type == GRPC_HTTP_REQUEST) { + gpr_free(parser->http.request.body); + for (i = 0; i < parser->http.request.hdr_count; i++) { + gpr_free(parser->http.request.hdrs[i].key); + gpr_free(parser->http.request.hdrs[i].value); + } + gpr_free(parser->http.request.hdrs); + gpr_free(parser->http.request.method); + gpr_free(parser->http.request.path); + } +} + +int grpc_http_parser_parse(grpc_http_parser *parser, gpr_slice slice) { + size_t i; + + for (i = 0; i < GPR_SLICE_LENGTH(slice); i++) { + if (!addbyte(parser, GPR_SLICE_START_PTR(slice)[i])) { + return 0; + } + } + + return 1; +} + +int grpc_http_parser_eof(grpc_http_parser *parser) { + return parser->state == GRPC_HTTP_BODY; +} diff --git a/src/core/lib/http/parser.h b/src/core/lib/http/parser.h new file mode 100644 index 0000000000..39517e485a --- /dev/null +++ b/src/core/lib/http/parser.h @@ -0,0 +1,116 @@ +/* + * + * Copyright 2015-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_HTTP_PARSER_H +#define GRPC_CORE_HTTP_PARSER_H + +#include +#include + +/* Maximum length of a header string of the form 'Key: Value\r\n' */ +#define GRPC_HTTP_PARSER_MAX_HEADER_LENGTH 4096 + +/* A single header to be passed in a request */ +typedef struct grpc_http_header { + char *key; + char *value; +} grpc_http_header; + +typedef enum { + GRPC_HTTP_FIRST_LINE, + GRPC_HTTP_HEADERS, + GRPC_HTTP_BODY +} grpc_http_parser_state; + +typedef enum { + GRPC_HTTP_HTTP10, + GRPC_HTTP_HTTP11, + GRPC_HTTP_HTTP20, +} grpc_http_version; + +typedef enum { + GRPC_HTTP_RESPONSE, + GRPC_HTTP_REQUEST, + GRPC_HTTP_UNKNOWN +} grpc_http_type; + +/* A request */ +typedef struct grpc_http_request { + /* Method of the request (e.g. GET, POST) */ + char *method; + /* The path of the resource to fetch */ + char *path; + /* HTTP version to use */ + grpc_http_version version; + /* Headers attached to the request */ + size_t hdr_count; + grpc_http_header *hdrs; + /* Body: length and contents; contents are NOT null-terminated */ + size_t body_length; + char *body; +} grpc_http_request; + +/* A response */ +typedef struct grpc_http_response { + /* HTTP status code */ + int status; + /* Headers: count and key/values */ + size_t hdr_count; + grpc_http_header *hdrs; + /* Body: length and contents; contents are NOT null-terminated */ + size_t body_length; + char *body; +} grpc_http_response; + +typedef struct { + grpc_http_parser_state state; + grpc_http_type type; + + union { + grpc_http_response response; + grpc_http_request request; + } http; + size_t body_capacity; + size_t hdr_capacity; + + uint8_t cur_line[GRPC_HTTP_PARSER_MAX_HEADER_LENGTH]; + size_t cur_line_length; +} grpc_http_parser; + +void grpc_http_parser_init(grpc_http_parser *parser); +void grpc_http_parser_destroy(grpc_http_parser *parser); + +int grpc_http_parser_parse(grpc_http_parser *parser, gpr_slice slice); +int grpc_http_parser_eof(grpc_http_parser *parser); + +#endif /* GRPC_CORE_HTTP_PARSER_H */ diff --git a/src/core/lib/iomgr/closure.c b/src/core/lib/iomgr/closure.c new file mode 100644 index 0000000000..3a96f7385f --- /dev/null +++ b/src/core/lib/iomgr/closure.c @@ -0,0 +1,98 @@ +/* + * + * Copyright 2015-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/iomgr/closure.h" + +#include + +void grpc_closure_init(grpc_closure *closure, grpc_iomgr_cb_func cb, + void *cb_arg) { + closure->cb = cb; + closure->cb_arg = cb_arg; + closure->final_data = 0; +} + +void grpc_closure_list_add(grpc_closure_list *closure_list, + grpc_closure *closure, bool success) { + if (closure == NULL) return; + closure->final_data = (success != 0); + if (closure_list->head == NULL) { + closure_list->head = closure; + } else { + closure_list->tail->final_data |= (uintptr_t)closure; + } + closure_list->tail = closure; +} + +bool grpc_closure_list_empty(grpc_closure_list closure_list) { + return closure_list.head == NULL; +} + +void grpc_closure_list_move(grpc_closure_list *src, grpc_closure_list *dst) { + if (src->head == NULL) { + return; + } + if (dst->head == NULL) { + *dst = *src; + } else { + dst->tail->final_data |= (uintptr_t)src->head; + dst->tail = src->tail; + } + src->head = src->tail = NULL; +} + +typedef struct { + grpc_iomgr_cb_func cb; + void *cb_arg; + grpc_closure wrapper; +} wrapped_closure; + +static void closure_wrapper(grpc_exec_ctx *exec_ctx, void *arg, bool success) { + wrapped_closure *wc = arg; + grpc_iomgr_cb_func cb = wc->cb; + void *cb_arg = wc->cb_arg; + gpr_free(wc); + cb(exec_ctx, cb_arg, success); +} + +grpc_closure *grpc_closure_create(grpc_iomgr_cb_func cb, void *cb_arg) { + wrapped_closure *wc = gpr_malloc(sizeof(*wc)); + wc->cb = cb; + wc->cb_arg = cb_arg; + grpc_closure_init(&wc->wrapper, closure_wrapper, wc); + return &wc->wrapper; +} + +grpc_closure *grpc_closure_next(grpc_closure *closure) { + return (grpc_closure *)(closure->final_data & ~(uintptr_t)1); +} diff --git a/src/core/lib/iomgr/closure.h b/src/core/lib/iomgr/closure.h new file mode 100644 index 0000000000..d5e1f455b9 --- /dev/null +++ b/src/core/lib/iomgr/closure.h @@ -0,0 +1,98 @@ +/* + * + * Copyright 2015-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_IOMGR_CLOSURE_H +#define GRPC_CORE_IOMGR_CLOSURE_H + +#include +#include + +struct grpc_closure; +typedef struct grpc_closure grpc_closure; + +/* forward declaration for exec_ctx.h */ +struct grpc_exec_ctx; +typedef struct grpc_exec_ctx grpc_exec_ctx; + +typedef struct grpc_closure_list { + grpc_closure *head; + grpc_closure *tail; +} grpc_closure_list; + +/** gRPC Callback definition. + * + * \param arg Arbitrary input. + * \param success An indication on the state of the iomgr. On false, cleanup + * actions should be taken (eg, shutdown). */ +typedef void (*grpc_iomgr_cb_func)(grpc_exec_ctx *exec_ctx, void *arg, + bool success); + +/** A closure over a grpc_iomgr_cb_func. */ +struct grpc_closure { + /** Bound callback. */ + grpc_iomgr_cb_func cb; + + /** Arguments to be passed to "cb". */ + void *cb_arg; + + /** Once enqueued, contains in the lower bit the success of the closure, + and in the upper bits the pointer to the next closure in the list. + Before enqueing for execution, this is usable for scratch data. */ + uintptr_t final_data; +}; + +/** Initializes \a closure with \a cb and \a cb_arg. */ +void grpc_closure_init(grpc_closure *closure, grpc_iomgr_cb_func cb, + void *cb_arg); + +/* Create a heap allocated closure: try to avoid except for very rare events */ +grpc_closure *grpc_closure_create(grpc_iomgr_cb_func cb, void *cb_arg); + +#define GRPC_CLOSURE_LIST_INIT \ + { NULL, NULL } + +/** add \a closure to the end of \a list and set \a closure's success to \a + * success */ +void grpc_closure_list_add(grpc_closure_list *list, grpc_closure *closure, + bool success); + +/** append all closures from \a src to \a dst and empty \a src. */ +void grpc_closure_list_move(grpc_closure_list *src, grpc_closure_list *dst); + +/** return whether \a list is empty. */ +bool grpc_closure_list_empty(grpc_closure_list list); + +/** return the next pointer for a queued closure list */ +grpc_closure *grpc_closure_next(grpc_closure *closure); + +#endif /* GRPC_CORE_IOMGR_CLOSURE_H */ diff --git a/src/core/lib/iomgr/endpoint.c b/src/core/lib/iomgr/endpoint.c new file mode 100644 index 0000000000..bd64707669 --- /dev/null +++ b/src/core/lib/iomgr/endpoint.c @@ -0,0 +1,67 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/iomgr/endpoint.h" + +void grpc_endpoint_read(grpc_exec_ctx* exec_ctx, grpc_endpoint* ep, + gpr_slice_buffer* slices, grpc_closure* cb) { + ep->vtable->read(exec_ctx, ep, slices, cb); +} + +void grpc_endpoint_write(grpc_exec_ctx* exec_ctx, grpc_endpoint* ep, + gpr_slice_buffer* slices, grpc_closure* cb) { + ep->vtable->write(exec_ctx, ep, slices, cb); +} + +void grpc_endpoint_add_to_pollset(grpc_exec_ctx* exec_ctx, grpc_endpoint* ep, + grpc_pollset* pollset) { + ep->vtable->add_to_pollset(exec_ctx, ep, pollset); +} + +void grpc_endpoint_add_to_pollset_set(grpc_exec_ctx* exec_ctx, + grpc_endpoint* ep, + grpc_pollset_set* pollset_set) { + ep->vtable->add_to_pollset_set(exec_ctx, ep, pollset_set); +} + +void grpc_endpoint_shutdown(grpc_exec_ctx* exec_ctx, grpc_endpoint* ep) { + ep->vtable->shutdown(exec_ctx, ep); +} + +void grpc_endpoint_destroy(grpc_exec_ctx* exec_ctx, grpc_endpoint* ep) { + ep->vtable->destroy(exec_ctx, ep); +} + +char* grpc_endpoint_get_peer(grpc_endpoint* ep) { + return ep->vtable->get_peer(ep); +} diff --git a/src/core/lib/iomgr/endpoint.h b/src/core/lib/iomgr/endpoint.h new file mode 100644 index 0000000000..b4be852e33 --- /dev/null +++ b/src/core/lib/iomgr/endpoint.h @@ -0,0 +1,102 @@ +/* + * + * Copyright 2015-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_IOMGR_ENDPOINT_H +#define GRPC_CORE_IOMGR_ENDPOINT_H + +#include +#include +#include +#include "src/core/iomgr/pollset.h" +#include "src/core/iomgr/pollset_set.h" + +/* An endpoint caps a streaming channel between two communicating processes. + Examples may be: a tcp socket, , or some shared memory. */ + +typedef struct grpc_endpoint grpc_endpoint; +typedef struct grpc_endpoint_vtable grpc_endpoint_vtable; + +struct grpc_endpoint_vtable { + void (*read)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, + gpr_slice_buffer *slices, grpc_closure *cb); + void (*write)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, + gpr_slice_buffer *slices, grpc_closure *cb); + void (*add_to_pollset)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, + grpc_pollset *pollset); + void (*add_to_pollset_set)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, + grpc_pollset_set *pollset); + void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep); + void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep); + char *(*get_peer)(grpc_endpoint *ep); +}; + +/* When data is available on the connection, calls the callback with slices. + Callback success indicates that the endpoint can accept more reads, failure + indicates the endpoint is closed. + Valid slices may be placed into \a slices even on callback success == 0. */ +void grpc_endpoint_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, + gpr_slice_buffer *slices, grpc_closure *cb); + +char *grpc_endpoint_get_peer(grpc_endpoint *ep); + +/* Write slices out to the socket. + + If the connection is ready for more data after the end of the call, it + returns GRPC_ENDPOINT_DONE. + Otherwise it returns GRPC_ENDPOINT_PENDING and calls cb when the + connection is ready for more data. + \a slices may be mutated at will by the endpoint until cb is called. + No guarantee is made to the content of slices after a write EXCEPT that + it is a valid slice buffer. + */ +void grpc_endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, + gpr_slice_buffer *slices, grpc_closure *cb); + +/* Causes any pending read/write callbacks to run immediately with + success==0 */ +void grpc_endpoint_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep); +void grpc_endpoint_destroy(grpc_exec_ctx *exec_ctx, 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_exec_ctx *exec_ctx, grpc_endpoint *ep, + grpc_pollset *pollset); +void grpc_endpoint_add_to_pollset_set(grpc_exec_ctx *exec_ctx, + grpc_endpoint *ep, + grpc_pollset_set *pollset_set); + +struct grpc_endpoint { + const grpc_endpoint_vtable *vtable; +}; + +#endif /* GRPC_CORE_IOMGR_ENDPOINT_H */ diff --git a/src/core/lib/iomgr/endpoint_pair.h b/src/core/lib/iomgr/endpoint_pair.h new file mode 100644 index 0000000000..59015d8ffb --- /dev/null +++ b/src/core/lib/iomgr/endpoint_pair.h @@ -0,0 +1,47 @@ +/* + * + * Copyright 2015-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_IOMGR_ENDPOINT_PAIR_H +#define GRPC_CORE_IOMGR_ENDPOINT_PAIR_H + +#include "src/core/iomgr/endpoint.h" + +typedef struct { + grpc_endpoint *client; + grpc_endpoint *server; +} grpc_endpoint_pair; + +grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name, + size_t read_slice_size); + +#endif /* GRPC_CORE_IOMGR_ENDPOINT_PAIR_H */ diff --git a/src/core/lib/iomgr/endpoint_pair_posix.c b/src/core/lib/iomgr/endpoint_pair_posix.c new file mode 100644 index 0000000000..66d19a486c --- /dev/null +++ b/src/core/lib/iomgr/endpoint_pair_posix.c @@ -0,0 +1,83 @@ +/* + * + * 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 + +#ifdef GPR_POSIX_SOCKET + +#include "src/core/iomgr/endpoint_pair.h" +#include "src/core/iomgr/socket_utils_posix.h" +#include "src/core/iomgr/unix_sockets_posix.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include "src/core/iomgr/tcp_posix.h" +#include "src/core/support/string.h" + +static void create_sockets(int sv[2]) { + int flags; + grpc_create_socketpair_if_unix(sv); + flags = fcntl(sv[0], F_GETFL, 0); + GPR_ASSERT(fcntl(sv[0], F_SETFL, flags | O_NONBLOCK) == 0); + flags = fcntl(sv[1], F_GETFL, 0); + GPR_ASSERT(fcntl(sv[1], F_SETFL, flags | O_NONBLOCK) == 0); + GPR_ASSERT(grpc_set_socket_no_sigpipe_if_possible(sv[0])); + GPR_ASSERT(grpc_set_socket_no_sigpipe_if_possible(sv[1])); +} + +grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name, + size_t read_slice_size) { + int sv[2]; + grpc_endpoint_pair p; + char *final_name; + create_sockets(sv); + + gpr_asprintf(&final_name, "%s:client", name); + p.client = grpc_tcp_create(grpc_fd_create(sv[1], final_name), read_slice_size, + "socketpair-server"); + gpr_free(final_name); + gpr_asprintf(&final_name, "%s:server", name); + p.server = grpc_tcp_create(grpc_fd_create(sv[0], final_name), read_slice_size, + "socketpair-client"); + gpr_free(final_name); + return p; +} + +#endif diff --git a/src/core/lib/iomgr/endpoint_pair_windows.c b/src/core/lib/iomgr/endpoint_pair_windows.c new file mode 100644 index 0000000000..2024f58143 --- /dev/null +++ b/src/core/lib/iomgr/endpoint_pair_windows.c @@ -0,0 +1,97 @@ +/* + * + * Copyright 2015-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 + +#ifdef GPR_WINSOCK_SOCKET +#include "src/core/iomgr/endpoint_pair.h" +#include "src/core/iomgr/sockaddr_utils.h" + +#include +#include +#include + +#include +#include "src/core/iomgr/socket_windows.h" +#include "src/core/iomgr/tcp_windows.h" + +static void create_sockets(SOCKET sv[2]) { + SOCKET svr_sock = INVALID_SOCKET; + SOCKET lst_sock = INVALID_SOCKET; + SOCKET cli_sock = INVALID_SOCKET; + SOCKADDR_IN addr; + int addr_len = sizeof(addr); + + lst_sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, + WSA_FLAG_OVERLAPPED); + GPR_ASSERT(lst_sock != INVALID_SOCKET); + + memset(&addr, 0, sizeof(addr)); + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + addr.sin_family = AF_INET; + GPR_ASSERT(bind(lst_sock, (struct sockaddr *)&addr, sizeof(addr)) != + SOCKET_ERROR); + GPR_ASSERT(listen(lst_sock, SOMAXCONN) != SOCKET_ERROR); + GPR_ASSERT(getsockname(lst_sock, (struct sockaddr *)&addr, &addr_len) != + SOCKET_ERROR); + + cli_sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, + WSA_FLAG_OVERLAPPED); + GPR_ASSERT(cli_sock != INVALID_SOCKET); + + GPR_ASSERT(WSAConnect(cli_sock, (struct sockaddr *)&addr, addr_len, NULL, + NULL, NULL, NULL) == 0); + svr_sock = accept(lst_sock, (struct sockaddr *)&addr, &addr_len); + GPR_ASSERT(svr_sock != INVALID_SOCKET); + + closesocket(lst_sock); + grpc_tcp_prepare_socket(cli_sock); + grpc_tcp_prepare_socket(svr_sock); + + sv[1] = cli_sock; + sv[0] = svr_sock; +} + +grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name, + size_t read_slice_size) { + SOCKET sv[2]; + grpc_endpoint_pair p; + create_sockets(sv); + p.client = grpc_tcp_create(grpc_winsocket_create(sv[1], "endpoint:client"), + "endpoint:server"); + p.server = grpc_tcp_create(grpc_winsocket_create(sv[0], "endpoint:server"), + "endpoint:client"); + return p; +} + +#endif diff --git a/src/core/lib/iomgr/exec_ctx.c b/src/core/lib/iomgr/exec_ctx.c new file mode 100644 index 0000000000..893fe4515c --- /dev/null +++ b/src/core/lib/iomgr/exec_ctx.c @@ -0,0 +1,151 @@ +/* + * + * Copyright 2015-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/iomgr/exec_ctx.h" + +#include +#include +#include + +#include "src/core/profiling/timers.h" + +#ifndef GRPC_EXECUTION_CONTEXT_SANITIZER +bool grpc_exec_ctx_flush(grpc_exec_ctx *exec_ctx) { + bool did_something = 0; + GPR_TIMER_BEGIN("grpc_exec_ctx_flush", 0); + while (!grpc_closure_list_empty(exec_ctx->closure_list)) { + grpc_closure *c = exec_ctx->closure_list.head; + exec_ctx->closure_list.head = exec_ctx->closure_list.tail = NULL; + while (c != NULL) { + bool success = (bool)(c->final_data & 1); + grpc_closure *next = (grpc_closure *)(c->final_data & ~(uintptr_t)1); + did_something = true; + GPR_TIMER_BEGIN("grpc_exec_ctx_flush.cb", 0); + c->cb(exec_ctx, c->cb_arg, success); + GPR_TIMER_END("grpc_exec_ctx_flush.cb", 0); + c = next; + } + } + GPR_TIMER_END("grpc_exec_ctx_flush", 0); + return did_something; +} + +void grpc_exec_ctx_finish(grpc_exec_ctx *exec_ctx) { + grpc_exec_ctx_flush(exec_ctx); +} + +void grpc_exec_ctx_enqueue(grpc_exec_ctx *exec_ctx, grpc_closure *closure, + bool success, + grpc_workqueue *offload_target_or_null) { + GPR_ASSERT(offload_target_or_null == NULL); + grpc_closure_list_add(&exec_ctx->closure_list, closure, success); +} + +void grpc_exec_ctx_enqueue_list(grpc_exec_ctx *exec_ctx, + grpc_closure_list *list, + grpc_workqueue *offload_target_or_null) { + GPR_ASSERT(offload_target_or_null == NULL); + grpc_closure_list_move(list, &exec_ctx->closure_list); +} + +void grpc_exec_ctx_global_init(void) {} +void grpc_exec_ctx_global_shutdown(void) {} +#else +static gpr_mu g_mu; +static gpr_cv g_cv; +static int g_threads = 0; + +static void run_closure(void *arg) { + grpc_closure *closure = arg; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + closure->cb(&exec_ctx, closure->cb_arg, (closure->final_data & 1) != 0); + grpc_exec_ctx_finish(&exec_ctx); + gpr_mu_lock(&g_mu); + if (--g_threads == 0) { + gpr_cv_signal(&g_cv); + } + gpr_mu_unlock(&g_mu); +} + +static void start_closure(grpc_closure *closure) { + gpr_thd_id id; + gpr_mu_lock(&g_mu); + g_threads++; + gpr_mu_unlock(&g_mu); + gpr_thd_new(&id, run_closure, closure, NULL); +} + +bool grpc_exec_ctx_flush(grpc_exec_ctx *exec_ctx) { return false; } + +void grpc_exec_ctx_finish(grpc_exec_ctx *exec_ctx) {} + +void grpc_exec_ctx_enqueue(grpc_exec_ctx *exec_ctx, grpc_closure *closure, + bool success, + grpc_workqueue *offload_target_or_null) { + GPR_ASSERT(offload_target_or_null == NULL); + if (closure == NULL) return; + closure->final_data = success; + start_closure(closure); +} + +void grpc_exec_ctx_enqueue_list(grpc_exec_ctx *exec_ctx, + grpc_closure_list *list, + grpc_workqueue *offload_target_or_null) { + GPR_ASSERT(offload_target_or_null == NULL); + if (list == NULL) return; + grpc_closure *p = list->head; + while (p) { + grpc_closure *start = p; + p = grpc_closure_next(start); + start_closure(start); + } + grpc_closure_list r = GRPC_CLOSURE_LIST_INIT; + *list = r; +} + +void grpc_exec_ctx_global_init(void) { + gpr_mu_init(&g_mu); + gpr_cv_init(&g_cv); +} + +void grpc_exec_ctx_global_shutdown(void) { + gpr_mu_lock(&g_mu); + while (g_threads != 0) { + gpr_cv_wait(&g_cv, &g_mu, gpr_inf_future(GPR_CLOCK_REALTIME)); + } + gpr_mu_unlock(&g_mu); + + gpr_mu_destroy(&g_mu); + gpr_cv_destroy(&g_cv); +} +#endif diff --git a/src/core/lib/iomgr/exec_ctx.h b/src/core/lib/iomgr/exec_ctx.h new file mode 100644 index 0000000000..07b54a0ab8 --- /dev/null +++ b/src/core/lib/iomgr/exec_ctx.h @@ -0,0 +1,98 @@ +/* + * + * Copyright 2015-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_IOMGR_EXEC_CTX_H +#define GRPC_CORE_IOMGR_EXEC_CTX_H + +#include "src/core/iomgr/closure.h" + +/* #define GRPC_EXECUTION_CONTEXT_SANITIZER 1 */ + +/** A workqueue represents a list of work to be executed asynchronously. + Forward declared here to avoid a circular dependency with workqueue.h. */ +struct grpc_workqueue; +typedef struct grpc_workqueue grpc_workqueue; + +#ifndef GRPC_EXECUTION_CONTEXT_SANITIZER +/** Execution context. + * A bag of data that collects information along a callstack. + * Generally created at public API entry points, and passed down as + * pointer to child functions that manipulate it. + * + * Specific responsibilities (this may grow in the future): + * - track a list of work that needs to be delayed until the top of the + * call stack (this provides a convenient mechanism to run callbacks + * without worrying about locking issues) + * + * CONVENTIONS: + * Instance of this must ALWAYS be constructed on the stack, never + * heap allocated. Instances and pointers to them must always be called + * exec_ctx. Instances are always passed as the first argument + * to a function that takes it, and always as a pointer (grpc_exec_ctx + * is never copied). + */ +struct grpc_exec_ctx { + grpc_closure_list closure_list; +}; + +#define GRPC_EXEC_CTX_INIT \ + { GRPC_CLOSURE_LIST_INIT } +#else +struct grpc_exec_ctx { + int unused; +}; +#define GRPC_EXEC_CTX_INIT \ + { 0 } +#endif + +/** Flush any work that has been enqueued onto this grpc_exec_ctx. + * Caller must guarantee that no interfering locks are held. + * Returns true if work was performed, false otherwise. */ +bool grpc_exec_ctx_flush(grpc_exec_ctx *exec_ctx); +/** Finish any pending work for a grpc_exec_ctx. Must be called before + * the instance is destroyed, or work may be lost. */ +void grpc_exec_ctx_finish(grpc_exec_ctx *exec_ctx); +/** Add a closure to be executed at the next flush/finish point */ +void grpc_exec_ctx_enqueue(grpc_exec_ctx *exec_ctx, grpc_closure *closure, + bool success, + grpc_workqueue *offload_target_or_null); +/** Add a list of closures to be executed at the next flush/finish point. + * Leaves \a list empty. */ +void grpc_exec_ctx_enqueue_list(grpc_exec_ctx *exec_ctx, + grpc_closure_list *list, + grpc_workqueue *offload_target_or_null); + +void grpc_exec_ctx_global_init(void); +void grpc_exec_ctx_global_shutdown(void); + +#endif /* GRPC_CORE_IOMGR_EXEC_CTX_H */ diff --git a/src/core/lib/iomgr/executor.c b/src/core/lib/iomgr/executor.c new file mode 100644 index 0000000000..f22d8f30ac --- /dev/null +++ b/src/core/lib/iomgr/executor.c @@ -0,0 +1,143 @@ +/* + * + * Copyright 2015-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/iomgr/executor.h" + +#include + +#include +#include +#include +#include +#include "src/core/iomgr/exec_ctx.h" + +typedef struct grpc_executor_data { + int busy; /**< is the thread currently running? */ + int shutting_down; /**< has \a grpc_shutdown() been invoked? */ + int pending_join; /**< has the thread finished but not been joined? */ + grpc_closure_list closures; /**< collection of pending work */ + gpr_thd_id tid; /**< thread id of the thread, only valid if \a busy or \a + pending_join are true */ + gpr_thd_options options; + gpr_mu mu; +} grpc_executor; + +static grpc_executor g_executor; + +void grpc_executor_init() { + memset(&g_executor, 0, sizeof(grpc_executor)); + gpr_mu_init(&g_executor.mu); + g_executor.options = gpr_thd_options_default(); + gpr_thd_options_set_joinable(&g_executor.options); +} + +/* thread body */ +static void closure_exec_thread_func(void *ignored) { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + while (1) { + gpr_mu_lock(&g_executor.mu); + if (g_executor.shutting_down != 0) { + gpr_mu_unlock(&g_executor.mu); + break; + } + if (grpc_closure_list_empty(g_executor.closures)) { + /* no more work, time to die */ + GPR_ASSERT(g_executor.busy == 1); + g_executor.busy = 0; + gpr_mu_unlock(&g_executor.mu); + break; + } else { + grpc_exec_ctx_enqueue_list(&exec_ctx, &g_executor.closures, NULL); + } + gpr_mu_unlock(&g_executor.mu); + grpc_exec_ctx_flush(&exec_ctx); + } + grpc_exec_ctx_finish(&exec_ctx); +} + +/* Spawn the thread if new work has arrived a no thread is up */ +static void maybe_spawn_locked() { + if (grpc_closure_list_empty(g_executor.closures) == 1) { + return; + } + if (g_executor.shutting_down == 1) { + return; + } + + if (g_executor.busy != 0) { + /* Thread still working. New work will be picked up by already running + * thread. Not spawning anything. */ + return; + } else if (g_executor.pending_join != 0) { + /* Pickup the remains of the previous incarnations of the thread. */ + gpr_thd_join(g_executor.tid); + g_executor.pending_join = 0; + } + + /* All previous instances of the thread should have been joined at this point. + * Spawn time! */ + g_executor.busy = 1; + gpr_thd_new(&g_executor.tid, closure_exec_thread_func, NULL, + &g_executor.options); + g_executor.pending_join = 1; +} + +void grpc_executor_enqueue(grpc_closure *closure, bool success) { + gpr_mu_lock(&g_executor.mu); + if (g_executor.shutting_down == 0) { + grpc_closure_list_add(&g_executor.closures, closure, success); + maybe_spawn_locked(); + } + gpr_mu_unlock(&g_executor.mu); +} + +void grpc_executor_shutdown() { + int pending_join; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + + gpr_mu_lock(&g_executor.mu); + pending_join = g_executor.pending_join; + g_executor.shutting_down = 1; + gpr_mu_unlock(&g_executor.mu); + /* we can release the lock at this point despite the access to the closure + * list below because we aren't accepting new work */ + + /* Execute pending callbacks, some may be performing cleanups */ + grpc_exec_ctx_enqueue_list(&exec_ctx, &g_executor.closures, NULL); + grpc_exec_ctx_finish(&exec_ctx); + GPR_ASSERT(grpc_closure_list_empty(g_executor.closures)); + if (pending_join) { + gpr_thd_join(g_executor.tid); + } + gpr_mu_destroy(&g_executor.mu); +} diff --git a/src/core/lib/iomgr/executor.h b/src/core/lib/iomgr/executor.h new file mode 100644 index 0000000000..f66b3560e3 --- /dev/null +++ b/src/core/lib/iomgr/executor.h @@ -0,0 +1,53 @@ +/* + * + * Copyright 2015-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_IOMGR_EXECUTOR_H +#define GRPC_CORE_IOMGR_EXECUTOR_H + +#include "src/core/iomgr/closure.h" + +/** Initialize the global executor. + * + * This mechanism is meant to outsource work (grpc_closure instances) to a + * thread, for those cases where blocking isn't an option but there isn't a + * non-blocking solution available. */ +void grpc_executor_init(); + +/** Enqueue \a closure for its eventual execution of \a f(arg) on a separate + * thread */ +void grpc_executor_enqueue(grpc_closure *closure, bool success); + +/** Shutdown the executor, running all pending work as part of the call */ +void grpc_executor_shutdown(); + +#endif /* GRPC_CORE_IOMGR_EXECUTOR_H */ diff --git a/src/core/lib/iomgr/fd_posix.c b/src/core/lib/iomgr/fd_posix.c new file mode 100644 index 0000000000..b4d038a3a1 --- /dev/null +++ b/src/core/lib/iomgr/fd_posix.c @@ -0,0 +1,454 @@ +/* + * + * Copyright 2015-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 + +#ifdef GPR_POSIX_SOCKET + +#include "src/core/iomgr/fd_posix.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include "src/core/iomgr/pollset_posix.h" + +#define CLOSURE_NOT_READY ((grpc_closure *)0) +#define CLOSURE_READY ((grpc_closure *)1) + +/* We need to keep a freelist not because of any concerns of malloc performance + * but instead so that implementations with multiple threads in (for example) + * epoll_wait deal with the race between pollset removal and incoming poll + * notifications. + * + * The problem is that the poller ultimately holds a reference to this + * object, so it is very difficult to know when is safe to free it, at least + * without some expensive synchronization. + * + * If we keep the object freelisted, in the worst case losing this race just + * becomes a spurious read notification on a reused fd. + */ +/* TODO(klempner): We could use some form of polling generation count to know + * when these are safe to free. */ +/* TODO(klempner): Consider disabling freelisting if we don't have multiple + * threads in poll on the same fd */ +/* TODO(klempner): Batch these allocations to reduce fragmentation */ +static grpc_fd *fd_freelist = NULL; +static gpr_mu fd_freelist_mu; + +static void freelist_fd(grpc_fd *fd) { + gpr_mu_lock(&fd_freelist_mu); + fd->freelist_next = fd_freelist; + fd_freelist = fd; + grpc_iomgr_unregister_object(&fd->iomgr_object); + gpr_mu_unlock(&fd_freelist_mu); +} + +static grpc_fd *alloc_fd(int fd) { + grpc_fd *r = NULL; + gpr_mu_lock(&fd_freelist_mu); + if (fd_freelist != NULL) { + r = fd_freelist; + fd_freelist = fd_freelist->freelist_next; + } + gpr_mu_unlock(&fd_freelist_mu); + if (r == NULL) { + r = gpr_malloc(sizeof(grpc_fd)); + gpr_mu_init(&r->mu); + } + + gpr_mu_lock(&r->mu); + r->shutdown = 0; + r->read_closure = CLOSURE_NOT_READY; + r->write_closure = CLOSURE_NOT_READY; + r->fd = fd; + r->inactive_watcher_root.next = r->inactive_watcher_root.prev = + &r->inactive_watcher_root; + r->freelist_next = NULL; + r->read_watcher = r->write_watcher = NULL; + r->on_done_closure = NULL; + r->closed = 0; + r->released = 0; + gpr_atm_rel_store(&r->refst, 1); + gpr_mu_unlock(&r->mu); + + return r; +} + +static void destroy(grpc_fd *fd) { + gpr_mu_destroy(&fd->mu); + gpr_free(fd); +} + +#ifdef GRPC_FD_REF_COUNT_DEBUG +#define REF_BY(fd, n, reason) ref_by(fd, n, reason, __FILE__, __LINE__) +#define UNREF_BY(fd, n, reason) unref_by(fd, n, reason, __FILE__, __LINE__) +static void ref_by(grpc_fd *fd, int n, const char *reason, const char *file, + int line) { + gpr_log(GPR_DEBUG, "FD %d %p ref %d %d -> %d [%s; %s:%d]", fd->fd, fd, n, + gpr_atm_no_barrier_load(&fd->refst), + gpr_atm_no_barrier_load(&fd->refst) + n, reason, file, line); +#else +#define REF_BY(fd, n, reason) ref_by(fd, n) +#define UNREF_BY(fd, n, reason) unref_by(fd, n) +static void ref_by(grpc_fd *fd, int n) { +#endif + GPR_ASSERT(gpr_atm_no_barrier_fetch_add(&fd->refst, n) > 0); +} + +#ifdef GRPC_FD_REF_COUNT_DEBUG +static void unref_by(grpc_fd *fd, int n, const char *reason, const char *file, + int line) { + gpr_atm old; + gpr_log(GPR_DEBUG, "FD %d %p unref %d %d -> %d [%s; %s:%d]", fd->fd, fd, n, + gpr_atm_no_barrier_load(&fd->refst), + gpr_atm_no_barrier_load(&fd->refst) - n, reason, file, line); +#else +static void unref_by(grpc_fd *fd, int n) { + gpr_atm old; +#endif + old = gpr_atm_full_fetch_add(&fd->refst, -n); + if (old == n) { + freelist_fd(fd); + } else { + GPR_ASSERT(old > n); + } +} + +void grpc_fd_global_init(void) { gpr_mu_init(&fd_freelist_mu); } + +void grpc_fd_global_shutdown(void) { + gpr_mu_lock(&fd_freelist_mu); + gpr_mu_unlock(&fd_freelist_mu); + while (fd_freelist != NULL) { + grpc_fd *fd = fd_freelist; + fd_freelist = fd_freelist->freelist_next; + destroy(fd); + } + gpr_mu_destroy(&fd_freelist_mu); +} + +grpc_fd *grpc_fd_create(int fd, const char *name) { + grpc_fd *r = alloc_fd(fd); + char *name2; + gpr_asprintf(&name2, "%s fd=%d", name, fd); + grpc_iomgr_register_object(&r->iomgr_object, name2); + gpr_free(name2); +#ifdef GRPC_FD_REF_COUNT_DEBUG + gpr_log(GPR_DEBUG, "FD %d %p create %s", fd, r, name); +#endif + return r; +} + +int grpc_fd_is_orphaned(grpc_fd *fd) { + return (gpr_atm_acq_load(&fd->refst) & 1) == 0; +} + +static void pollset_kick_locked(grpc_fd_watcher *watcher) { + gpr_mu_lock(&watcher->pollset->mu); + GPR_ASSERT(watcher->worker); + grpc_pollset_kick_ext(watcher->pollset, watcher->worker, + GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP); + gpr_mu_unlock(&watcher->pollset->mu); +} + +static void maybe_wake_one_watcher_locked(grpc_fd *fd) { + if (fd->inactive_watcher_root.next != &fd->inactive_watcher_root) { + pollset_kick_locked(fd->inactive_watcher_root.next); + } else if (fd->read_watcher) { + pollset_kick_locked(fd->read_watcher); + } else if (fd->write_watcher) { + pollset_kick_locked(fd->write_watcher); + } +} + +static void wake_all_watchers_locked(grpc_fd *fd) { + grpc_fd_watcher *watcher; + for (watcher = fd->inactive_watcher_root.next; + watcher != &fd->inactive_watcher_root; watcher = watcher->next) { + pollset_kick_locked(watcher); + } + if (fd->read_watcher) { + pollset_kick_locked(fd->read_watcher); + } + if (fd->write_watcher && fd->write_watcher != fd->read_watcher) { + pollset_kick_locked(fd->write_watcher); + } +} + +static int has_watchers(grpc_fd *fd) { + return fd->read_watcher != NULL || fd->write_watcher != NULL || + fd->inactive_watcher_root.next != &fd->inactive_watcher_root; +} + +static void close_fd_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd) { + fd->closed = 1; + if (!fd->released) { + close(fd->fd); + } else { + grpc_remove_fd_from_all_epoll_sets(fd->fd); + } + grpc_exec_ctx_enqueue(exec_ctx, fd->on_done_closure, true, NULL); +} + +int grpc_fd_wrapped_fd(grpc_fd *fd) { + if (fd->released || fd->closed) { + return -1; + } else { + return fd->fd; + } +} + +void grpc_fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *on_done, + int *release_fd, const char *reason) { + fd->on_done_closure = on_done; + fd->released = release_fd != NULL; + if (!fd->released) { + shutdown(fd->fd, SHUT_RDWR); + } else { + *release_fd = fd->fd; + } + gpr_mu_lock(&fd->mu); + REF_BY(fd, 1, reason); /* remove active status, but keep referenced */ + if (!has_watchers(fd)) { + close_fd_locked(exec_ctx, fd); + } else { + wake_all_watchers_locked(fd); + } + gpr_mu_unlock(&fd->mu); + UNREF_BY(fd, 2, reason); /* drop the reference */ +} + +/* increment refcount by two to avoid changing the orphan bit */ +#ifdef GRPC_FD_REF_COUNT_DEBUG +void grpc_fd_ref(grpc_fd *fd, const char *reason, const char *file, int line) { + ref_by(fd, 2, reason, file, line); +} + +void grpc_fd_unref(grpc_fd *fd, const char *reason, const char *file, + int line) { + unref_by(fd, 2, reason, file, line); +} +#else +void grpc_fd_ref(grpc_fd *fd) { ref_by(fd, 2); } + +void grpc_fd_unref(grpc_fd *fd) { unref_by(fd, 2); } +#endif + +static void notify_on_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd, + grpc_closure **st, grpc_closure *closure) { + if (*st == CLOSURE_NOT_READY) { + /* not ready ==> switch to a waiting state by setting the closure */ + *st = closure; + } else if (*st == CLOSURE_READY) { + /* already ready ==> queue the closure to run immediately */ + *st = CLOSURE_NOT_READY; + grpc_exec_ctx_enqueue(exec_ctx, closure, !fd->shutdown, NULL); + maybe_wake_one_watcher_locked(fd); + } else { + /* upcallptr was set to a different closure. This is an error! */ + gpr_log(GPR_ERROR, + "User called a notify_on function with a previous callback still " + "pending"); + abort(); + } +} + +/* returns 1 if state becomes not ready */ +static int set_ready_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd, + grpc_closure **st) { + if (*st == CLOSURE_READY) { + /* duplicate ready ==> ignore */ + return 0; + } else if (*st == CLOSURE_NOT_READY) { + /* not ready, and not waiting ==> flag ready */ + *st = CLOSURE_READY; + return 0; + } else { + /* waiting ==> queue closure */ + grpc_exec_ctx_enqueue(exec_ctx, *st, !fd->shutdown, NULL); + *st = CLOSURE_NOT_READY; + return 1; + } +} + +static void set_ready(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure **st) { + /* only one set_ready can be active at once (but there may be a racing + notify_on) */ + gpr_mu_lock(&fd->mu); + set_ready_locked(exec_ctx, fd, st); + gpr_mu_unlock(&fd->mu); +} + +void grpc_fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd) { + gpr_mu_lock(&fd->mu); + GPR_ASSERT(!fd->shutdown); + fd->shutdown = 1; + set_ready_locked(exec_ctx, fd, &fd->read_closure); + set_ready_locked(exec_ctx, fd, &fd->write_closure); + gpr_mu_unlock(&fd->mu); +} + +void grpc_fd_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_fd *fd, + grpc_closure *closure) { + gpr_mu_lock(&fd->mu); + notify_on_locked(exec_ctx, fd, &fd->read_closure, closure); + gpr_mu_unlock(&fd->mu); +} + +void grpc_fd_notify_on_write(grpc_exec_ctx *exec_ctx, grpc_fd *fd, + grpc_closure *closure) { + gpr_mu_lock(&fd->mu); + notify_on_locked(exec_ctx, fd, &fd->write_closure, closure); + gpr_mu_unlock(&fd->mu); +} + +uint32_t grpc_fd_begin_poll(grpc_fd *fd, grpc_pollset *pollset, + grpc_pollset_worker *worker, uint32_t read_mask, + uint32_t write_mask, grpc_fd_watcher *watcher) { + uint32_t mask = 0; + grpc_closure *cur; + int requested; + /* keep track of pollers that have requested our events, in case they change + */ + GRPC_FD_REF(fd, "poll"); + + gpr_mu_lock(&fd->mu); + + /* if we are shutdown, then don't add to the watcher set */ + if (fd->shutdown) { + watcher->fd = NULL; + watcher->pollset = NULL; + watcher->worker = NULL; + gpr_mu_unlock(&fd->mu); + GRPC_FD_UNREF(fd, "poll"); + return 0; + } + + /* if there is nobody polling for read, but we need to, then start doing so */ + cur = fd->read_closure; + requested = cur != CLOSURE_READY; + if (read_mask && fd->read_watcher == NULL && requested) { + fd->read_watcher = watcher; + mask |= read_mask; + } + /* if there is nobody polling for write, but we need to, then start doing so + */ + cur = fd->write_closure; + requested = cur != CLOSURE_READY; + if (write_mask && fd->write_watcher == NULL && requested) { + fd->write_watcher = watcher; + mask |= write_mask; + } + /* if not polling, remember this watcher in case we need someone to later */ + if (mask == 0 && worker != NULL) { + watcher->next = &fd->inactive_watcher_root; + watcher->prev = watcher->next->prev; + watcher->next->prev = watcher->prev->next = watcher; + } + watcher->pollset = pollset; + watcher->worker = worker; + watcher->fd = fd; + gpr_mu_unlock(&fd->mu); + + return mask; +} + +void grpc_fd_end_poll(grpc_exec_ctx *exec_ctx, grpc_fd_watcher *watcher, + int got_read, int got_write) { + int was_polling = 0; + int kick = 0; + grpc_fd *fd = watcher->fd; + + if (fd == NULL) { + return; + } + + gpr_mu_lock(&fd->mu); + + if (watcher == fd->read_watcher) { + /* remove read watcher, kick if we still need a read */ + was_polling = 1; + if (!got_read) { + kick = 1; + } + fd->read_watcher = NULL; + } + if (watcher == fd->write_watcher) { + /* remove write watcher, kick if we still need a write */ + was_polling = 1; + if (!got_write) { + kick = 1; + } + fd->write_watcher = NULL; + } + if (!was_polling && watcher->worker != NULL) { + /* remove from inactive list */ + watcher->next->prev = watcher->prev; + watcher->prev->next = watcher->next; + } + if (got_read) { + if (set_ready_locked(exec_ctx, fd, &fd->read_closure)) { + kick = 1; + } + } + if (got_write) { + if (set_ready_locked(exec_ctx, fd, &fd->write_closure)) { + kick = 1; + } + } + if (kick) { + maybe_wake_one_watcher_locked(fd); + } + if (grpc_fd_is_orphaned(fd) && !has_watchers(fd) && !fd->closed) { + close_fd_locked(exec_ctx, fd); + } + gpr_mu_unlock(&fd->mu); + + GRPC_FD_UNREF(fd, "poll"); +} + +void grpc_fd_become_readable(grpc_exec_ctx *exec_ctx, grpc_fd *fd) { + set_ready(exec_ctx, fd, &fd->read_closure); +} + +void grpc_fd_become_writable(grpc_exec_ctx *exec_ctx, grpc_fd *fd) { + set_ready(exec_ctx, fd, &fd->write_closure); +} + +#endif diff --git a/src/core/lib/iomgr/fd_posix.h b/src/core/lib/iomgr/fd_posix.h new file mode 100644 index 0000000000..1993ada79f --- /dev/null +++ b/src/core/lib/iomgr/fd_posix.h @@ -0,0 +1,192 @@ +/* + * + * Copyright 2015-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_IOMGR_FD_POSIX_H +#define GRPC_CORE_IOMGR_FD_POSIX_H + +#include +#include +#include +#include "src/core/iomgr/iomgr_internal.h" +#include "src/core/iomgr/pollset.h" + +typedef struct grpc_fd grpc_fd; + +typedef struct grpc_fd_watcher { + struct grpc_fd_watcher *next; + struct grpc_fd_watcher *prev; + grpc_pollset *pollset; + grpc_pollset_worker *worker; + grpc_fd *fd; +} grpc_fd_watcher; + +struct grpc_fd { + int fd; + /* refst format: + bit0: 1=active/0=orphaned + bit1-n: refcount + meaning that mostly we ref by two to avoid altering the orphaned bit, + and just unref by 1 when we're ready to flag the object as orphaned */ + gpr_atm refst; + + gpr_mu mu; + int shutdown; + int closed; + int released; + + /* The watcher list. + + The following watcher related fields are protected by watcher_mu. + + An fd_watcher is an ephemeral object created when an fd wants to + begin polling, and destroyed after the poll. + + It denotes the fd's interest in whether to read poll or write poll + or both or neither on this fd. + + If a watcher is asked to poll for reads or writes, the read_watcher + or write_watcher fields are set respectively. A watcher may be asked + to poll for both, in which case both fields will be set. + + read_watcher and write_watcher may be NULL if no watcher has been + asked to poll for reads or writes. + + If an fd_watcher is not asked to poll for reads or writes, it's added + to a linked list of inactive watchers, rooted at inactive_watcher_root. + If at a later time there becomes need of a poller to poll, one of + the inactive pollers may be kicked out of their poll loops to take + that responsibility. */ + grpc_fd_watcher inactive_watcher_root; + grpc_fd_watcher *read_watcher; + grpc_fd_watcher *write_watcher; + + grpc_closure *read_closure; + grpc_closure *write_closure; + + struct grpc_fd *freelist_next; + + grpc_closure *on_done_closure; + + grpc_iomgr_object iomgr_object; +}; + +/* Create a wrapped file descriptor. + Requires fd is a non-blocking file descriptor. + This takes ownership of closing fd. */ +grpc_fd *grpc_fd_create(int fd, const char *name); + +/* Return the wrapped fd, or -1 if it has been released or closed. */ +int grpc_fd_wrapped_fd(grpc_fd *fd); + +/* Releases fd to be asynchronously destroyed. + on_done is called when the underlying file descriptor is definitely close()d. + If on_done is NULL, no callback will be made. + If release_fd is not NULL, it's set to fd and fd will not be closed. + Requires: *fd initialized; no outstanding notify_on_read or + notify_on_write. + MUST NOT be called with a pollset lock taken */ +void grpc_fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *on_done, + int *release_fd, const char *reason); + +/* Begin polling on an fd. + Registers that the given pollset is interested in this fd - so that if read + or writability interest changes, the pollset can be kicked to pick up that + new interest. + Return value is: + (fd_needs_read? read_mask : 0) | (fd_needs_write? write_mask : 0) + i.e. a combination of read_mask and write_mask determined by the fd's current + interest in said events. + Polling strategies that do not need to alter their behavior depending on the + fd's current interest (such as epoll) do not need to call this function. + MUST NOT be called with a pollset lock taken */ +uint32_t grpc_fd_begin_poll(grpc_fd *fd, grpc_pollset *pollset, + grpc_pollset_worker *worker, uint32_t read_mask, + uint32_t write_mask, grpc_fd_watcher *rec); +/* Complete polling previously started with grpc_fd_begin_poll + MUST NOT be called with a pollset lock taken + if got_read or got_write are 1, also does the become_{readable,writable} as + appropriate. */ +void grpc_fd_end_poll(grpc_exec_ctx *exec_ctx, grpc_fd_watcher *rec, + int got_read, int got_write); + +/* Return 1 if this fd is orphaned, 0 otherwise */ +int grpc_fd_is_orphaned(grpc_fd *fd); + +/* Cause any current callbacks to error out with GRPC_CALLBACK_CANCELLED. */ +void grpc_fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd); + +/* Register read interest, causing read_cb to be called once when fd becomes + readable, on deadline specified by deadline, or on shutdown triggered by + grpc_fd_shutdown. + read_cb will be called with read_cb_arg when *fd becomes readable. + read_cb is Called with status of GRPC_CALLBACK_SUCCESS if readable, + GRPC_CALLBACK_TIMED_OUT if the call timed out, + and CANCELLED if the call was cancelled. + + Requires:This method must not be called before the read_cb for any previous + call runs. Edge triggered events are used whenever they are supported by the + underlying platform. This means that users must drain fd in read_cb before + calling notify_on_read again. Users are also expected to handle spurious + events, i.e read_cb is called while nothing can be readable from fd */ +void grpc_fd_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_fd *fd, + grpc_closure *closure); + +/* Exactly the same semantics as above, except based on writable events. */ +void grpc_fd_notify_on_write(grpc_exec_ctx *exec_ctx, grpc_fd *fd, + grpc_closure *closure); + +/* Notification from the poller to an fd that it has become readable or + writable. + If allow_synchronous_callback is 1, allow running the fd callback inline + in this callstack, otherwise register an asynchronous callback and return */ +void grpc_fd_become_readable(grpc_exec_ctx *exec_ctx, grpc_fd *fd); +void grpc_fd_become_writable(grpc_exec_ctx *exec_ctx, grpc_fd *fd); + +/* Reference counting for fds */ +/*#define GRPC_FD_REF_COUNT_DEBUG*/ +#ifdef GRPC_FD_REF_COUNT_DEBUG +void grpc_fd_ref(grpc_fd *fd, const char *reason, const char *file, int line); +void grpc_fd_unref(grpc_fd *fd, const char *reason, const char *file, int line); +#define GRPC_FD_REF(fd, reason) grpc_fd_ref(fd, reason, __FILE__, __LINE__) +#define GRPC_FD_UNREF(fd, reason) grpc_fd_unref(fd, reason, __FILE__, __LINE__) +#else +void grpc_fd_ref(grpc_fd *fd); +void grpc_fd_unref(grpc_fd *fd); +#define GRPC_FD_REF(fd, reason) grpc_fd_ref(fd) +#define GRPC_FD_UNREF(fd, reason) grpc_fd_unref(fd) +#endif + +void grpc_fd_global_init(void); +void grpc_fd_global_shutdown(void); + +#endif /* GRPC_CORE_IOMGR_FD_POSIX_H */ diff --git a/src/core/lib/iomgr/iocp_windows.c b/src/core/lib/iomgr/iocp_windows.c new file mode 100644 index 0000000000..37e277dcc1 --- /dev/null +++ b/src/core/lib/iomgr/iocp_windows.c @@ -0,0 +1,208 @@ +/* + * + * Copyright 2015-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 + +#ifdef GPR_WINSOCK_SOCKET + +#include + +#include +#include +#include +#include + +#include "src/core/iomgr/iocp_windows.h" +#include "src/core/iomgr/iomgr_internal.h" +#include "src/core/iomgr/socket_windows.h" +#include "src/core/iomgr/timer.h" + +static ULONG g_iocp_kick_token; +static OVERLAPPED g_iocp_custom_overlap; + +static gpr_atm g_custom_events = 0; + +static HANDLE g_iocp; + +static DWORD deadline_to_millis_timeout(gpr_timespec deadline, + gpr_timespec now) { + gpr_timespec timeout; + static const int64_t max_spin_polling_us = 10; + if (gpr_time_cmp(deadline, gpr_inf_future(deadline.clock_type)) == 0) { + return INFINITE; + } + if (gpr_time_cmp(deadline, gpr_time_add(now, gpr_time_from_micros( + max_spin_polling_us, + GPR_TIMESPAN))) <= 0) { + return 0; + } + timeout = gpr_time_sub(deadline, now); + return (DWORD)gpr_time_to_millis(gpr_time_add( + timeout, gpr_time_from_nanos(GPR_NS_PER_MS - 1, GPR_TIMESPAN))); +} + +grpc_iocp_work_status grpc_iocp_work(grpc_exec_ctx *exec_ctx, + gpr_timespec deadline) { + BOOL success; + DWORD bytes = 0; + DWORD flags = 0; + ULONG_PTR completion_key; + LPOVERLAPPED overlapped; + grpc_winsocket *socket; + grpc_winsocket_callback_info *info; + grpc_closure *closure = NULL; + success = GetQueuedCompletionStatus( + g_iocp, &bytes, &completion_key, &overlapped, + deadline_to_millis_timeout(deadline, gpr_now(deadline.clock_type))); + if (success == 0 && overlapped == NULL) { + return GRPC_IOCP_WORK_TIMEOUT; + } + GPR_ASSERT(completion_key && overlapped); + if (overlapped == &g_iocp_custom_overlap) { + gpr_atm_full_fetch_add(&g_custom_events, -1); + if (completion_key == (ULONG_PTR)&g_iocp_kick_token) { + /* We were awoken from a kick. */ + return GRPC_IOCP_WORK_KICK; + } + gpr_log(GPR_ERROR, "Unknown custom completion key."); + abort(); + } + + socket = (grpc_winsocket *)completion_key; + if (overlapped == &socket->write_info.overlapped) { + info = &socket->write_info; + } else if (overlapped == &socket->read_info.overlapped) { + info = &socket->read_info; + } else { + gpr_log(GPR_ERROR, "Unknown IOCP operation"); + abort(); + } + success = WSAGetOverlappedResult(socket->socket, &info->overlapped, &bytes, + FALSE, &flags); + info->bytes_transfered = bytes; + info->wsa_error = success ? 0 : WSAGetLastError(); + GPR_ASSERT(overlapped == &info->overlapped); + GPR_ASSERT(!info->has_pending_iocp); + gpr_mu_lock(&socket->state_mu); + if (info->closure) { + closure = info->closure; + info->closure = NULL; + } else { + info->has_pending_iocp = 1; + } + gpr_mu_unlock(&socket->state_mu); + grpc_exec_ctx_enqueue(exec_ctx, closure, true, NULL); + return GRPC_IOCP_WORK_WORK; +} + +void grpc_iocp_init(void) { + g_iocp = + CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, (ULONG_PTR)NULL, 0); + GPR_ASSERT(g_iocp); +} + +void grpc_iocp_kick(void) { + BOOL success; + + gpr_atm_full_fetch_add(&g_custom_events, 1); + success = PostQueuedCompletionStatus(g_iocp, 0, (ULONG_PTR)&g_iocp_kick_token, + &g_iocp_custom_overlap); + GPR_ASSERT(success); +} + +void grpc_iocp_flush(void) { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_iocp_work_status work_status; + + do { + work_status = grpc_iocp_work(&exec_ctx, gpr_inf_past(GPR_CLOCK_MONOTONIC)); + } while (work_status == GRPC_IOCP_WORK_KICK || + grpc_exec_ctx_flush(&exec_ctx)); +} + +void grpc_iocp_shutdown(void) { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + while (gpr_atm_acq_load(&g_custom_events)) { + grpc_iocp_work(&exec_ctx, gpr_inf_future(GPR_CLOCK_MONOTONIC)); + grpc_exec_ctx_flush(&exec_ctx); + } + grpc_exec_ctx_finish(&exec_ctx); + GPR_ASSERT(CloseHandle(g_iocp)); +} + +void grpc_iocp_add_socket(grpc_winsocket *socket) { + HANDLE ret; + if (socket->added_to_iocp) return; + ret = CreateIoCompletionPort((HANDLE)socket->socket, g_iocp, + (uintptr_t)socket, 0); + if (!ret) { + char *utf8_message = gpr_format_message(WSAGetLastError()); + gpr_log(GPR_ERROR, "Unable to add socket to iocp: %s", utf8_message); + gpr_free(utf8_message); + __debugbreak(); + abort(); + } + socket->added_to_iocp = 1; + GPR_ASSERT(ret == g_iocp); +} + +/* Calling notify_on_read or write means either of two things: + -) The IOCP already completed in the background, and we need to call + the callback now. + -) The IOCP hasn't completed yet, and we're queuing it for later. */ +static void socket_notify_on_iocp(grpc_exec_ctx *exec_ctx, + grpc_winsocket *socket, grpc_closure *closure, + grpc_winsocket_callback_info *info) { + GPR_ASSERT(info->closure == NULL); + gpr_mu_lock(&socket->state_mu); + if (info->has_pending_iocp) { + info->has_pending_iocp = 0; + grpc_exec_ctx_enqueue(exec_ctx, closure, true, NULL); + } else { + info->closure = closure; + } + gpr_mu_unlock(&socket->state_mu); +} + +void grpc_socket_notify_on_write(grpc_exec_ctx *exec_ctx, + grpc_winsocket *socket, + grpc_closure *closure) { + socket_notify_on_iocp(exec_ctx, socket, closure, &socket->write_info); +} + +void grpc_socket_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_winsocket *socket, + grpc_closure *closure) { + socket_notify_on_iocp(exec_ctx, socket, closure, &socket->read_info); +} + +#endif /* GPR_WINSOCK_SOCKET */ diff --git a/src/core/lib/iomgr/iocp_windows.h b/src/core/lib/iomgr/iocp_windows.h new file mode 100644 index 0000000000..570b8925aa --- /dev/null +++ b/src/core/lib/iomgr/iocp_windows.h @@ -0,0 +1,63 @@ +/* + * + * Copyright 2015-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_IOMGR_IOCP_WINDOWS_H +#define GRPC_CORE_IOMGR_IOCP_WINDOWS_H + +#include + +#include "src/core/iomgr/socket_windows.h" + +typedef enum { + GRPC_IOCP_WORK_WORK, + GRPC_IOCP_WORK_TIMEOUT, + GRPC_IOCP_WORK_KICK +} grpc_iocp_work_status; + +grpc_iocp_work_status grpc_iocp_work(grpc_exec_ctx *exec_ctx, + gpr_timespec deadline); +void grpc_iocp_init(void); +void grpc_iocp_kick(void); +void grpc_iocp_flush(void); +void grpc_iocp_shutdown(void); +void grpc_iocp_add_socket(grpc_winsocket *); + +void grpc_socket_notify_on_write(grpc_exec_ctx *exec_ctx, + grpc_winsocket *winsocket, + grpc_closure *closure); + +void grpc_socket_notify_on_read(grpc_exec_ctx *exec_ctx, + grpc_winsocket *winsocket, + grpc_closure *closure); + +#endif /* GRPC_CORE_IOMGR_IOCP_WINDOWS_H */ diff --git a/src/core/lib/iomgr/iomgr.c b/src/core/lib/iomgr/iomgr.c new file mode 100644 index 0000000000..3ab4430668 --- /dev/null +++ b/src/core/lib/iomgr/iomgr.c @@ -0,0 +1,175 @@ +/* + * + * Copyright 2015-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/iomgr/iomgr.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "src/core/iomgr/exec_ctx.h" +#include "src/core/iomgr/iomgr_internal.h" +#include "src/core/iomgr/timer.h" +#include "src/core/support/env.h" +#include "src/core/support/string.h" + +static gpr_mu g_mu; +static gpr_cv g_rcv; +static int g_shutdown; +static grpc_iomgr_object g_root_object; + +void grpc_iomgr_init(void) { + g_shutdown = 0; + gpr_mu_init(&g_mu); + gpr_cv_init(&g_rcv); + grpc_exec_ctx_global_init(); + grpc_timer_list_init(gpr_now(GPR_CLOCK_MONOTONIC)); + g_root_object.next = g_root_object.prev = &g_root_object; + g_root_object.name = "root"; + grpc_iomgr_platform_init(); + grpc_pollset_global_init(); +} + +static size_t count_objects(void) { + grpc_iomgr_object *obj; + size_t n = 0; + for (obj = g_root_object.next; obj != &g_root_object; obj = obj->next) { + n++; + } + return n; +} + +static void dump_objects(const char *kind) { + grpc_iomgr_object *obj; + for (obj = g_root_object.next; obj != &g_root_object; obj = obj->next) { + gpr_log(GPR_DEBUG, "%s OBJECT: %s %p", kind, obj->name, obj); + } +} + +void grpc_iomgr_shutdown(void) { + gpr_timespec shutdown_deadline = gpr_time_add( + gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_seconds(10, GPR_TIMESPAN)); + gpr_timespec last_warning_time = gpr_now(GPR_CLOCK_REALTIME); + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + + grpc_iomgr_platform_flush(); + + gpr_mu_lock(&g_mu); + g_shutdown = 1; + while (g_root_object.next != &g_root_object) { + if (gpr_time_cmp( + gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), last_warning_time), + gpr_time_from_seconds(1, GPR_TIMESPAN)) >= 0) { + if (g_root_object.next != &g_root_object) { + gpr_log(GPR_DEBUG, "Waiting for %d iomgr objects to be destroyed", + count_objects()); + } + last_warning_time = gpr_now(GPR_CLOCK_REALTIME); + } + if (grpc_timer_check(&exec_ctx, gpr_inf_future(GPR_CLOCK_MONOTONIC), + NULL)) { + gpr_mu_unlock(&g_mu); + grpc_exec_ctx_flush(&exec_ctx); + gpr_mu_lock(&g_mu); + continue; + } + if (g_root_object.next != &g_root_object) { + gpr_timespec short_deadline = gpr_time_add( + gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_millis(100, GPR_TIMESPAN)); + if (gpr_cv_wait(&g_rcv, &g_mu, short_deadline)) { + 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", + count_objects()); + dump_objects("LEAKED"); + if (grpc_iomgr_abort_on_leaks()) { + abort(); + } + } + break; + } + } + } + } + gpr_mu_unlock(&g_mu); + + grpc_timer_list_shutdown(&exec_ctx); + grpc_exec_ctx_finish(&exec_ctx); + + /* ensure all threads have left g_mu */ + gpr_mu_lock(&g_mu); + gpr_mu_unlock(&g_mu); + + grpc_pollset_global_shutdown(); + grpc_iomgr_platform_shutdown(); + grpc_exec_ctx_global_shutdown(); + gpr_mu_destroy(&g_mu); + gpr_cv_destroy(&g_rcv); +} + +void grpc_iomgr_register_object(grpc_iomgr_object *obj, const char *name) { + obj->name = gpr_strdup(name); + gpr_mu_lock(&g_mu); + obj->next = &g_root_object; + obj->prev = g_root_object.prev; + obj->next->prev = obj->prev->next = obj; + gpr_mu_unlock(&g_mu); +} + +void grpc_iomgr_unregister_object(grpc_iomgr_object *obj) { + gpr_mu_lock(&g_mu); + obj->next->prev = obj->prev; + obj->prev->next = obj->next; + gpr_cv_signal(&g_rcv); + gpr_mu_unlock(&g_mu); + gpr_free(obj->name); +} + +bool grpc_iomgr_abort_on_leaks(void) { + char *env = gpr_getenv("GRPC_ABORT_ON_LEAKS"); + if (env == NULL) return false; + static const char *truthy[] = {"yes", "Yes", "YES", "true", + "True", "TRUE", "1"}; + for (size_t i = 0; i < GPR_ARRAY_SIZE(truthy); i++) { + if (0 == strcmp(env, truthy[i])) return true; + } + return false; +} diff --git a/src/core/lib/iomgr/iomgr.h b/src/core/lib/iomgr/iomgr.h new file mode 100644 index 0000000000..e1237a4533 --- /dev/null +++ b/src/core/lib/iomgr/iomgr.h @@ -0,0 +1,43 @@ +/* + * + * Copyright 2015-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_IOMGR_IOMGR_H +#define GRPC_CORE_IOMGR_IOMGR_H + +/** Initializes the iomgr. */ +void grpc_iomgr_init(void); + +/** Signals the intention to shutdown the iomgr. */ +void grpc_iomgr_shutdown(void); + +#endif /* GRPC_CORE_IOMGR_IOMGR_H */ diff --git a/src/core/lib/iomgr/iomgr_internal.h b/src/core/lib/iomgr/iomgr_internal.h new file mode 100644 index 0000000000..1cad3182ec --- /dev/null +++ b/src/core/lib/iomgr/iomgr_internal.h @@ -0,0 +1,62 @@ +/* + * + * Copyright 2015-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_IOMGR_IOMGR_INTERNAL_H +#define GRPC_CORE_IOMGR_IOMGR_INTERNAL_H + +#include + +#include +#include "src/core/iomgr/iomgr.h" + +typedef struct grpc_iomgr_object { + char *name; + struct grpc_iomgr_object *next; + struct grpc_iomgr_object *prev; +} grpc_iomgr_object; + +void grpc_pollset_global_init(void); +void grpc_pollset_global_shutdown(void); + +void grpc_iomgr_register_object(grpc_iomgr_object *obj, const char *name); +void grpc_iomgr_unregister_object(grpc_iomgr_object *obj); + +void grpc_iomgr_platform_init(void); +/** flush any globally queued work from iomgr */ +void grpc_iomgr_platform_flush(void); +/** tear down all platform specific global iomgr structures */ +void grpc_iomgr_platform_shutdown(void); + +bool grpc_iomgr_abort_on_leaks(void); + +#endif /* GRPC_CORE_IOMGR_IOMGR_INTERNAL_H */ diff --git a/src/core/lib/iomgr/iomgr_posix.c b/src/core/lib/iomgr/iomgr_posix.c new file mode 100644 index 0000000000..2f7f34746b --- /dev/null +++ b/src/core/lib/iomgr/iomgr_posix.c @@ -0,0 +1,52 @@ +/* + * + * Copyright 2015-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 + +#ifdef GPR_POSIX_SOCKET + +#include "src/core/debug/trace.h" +#include "src/core/iomgr/fd_posix.h" +#include "src/core/iomgr/iomgr_posix.h" +#include "src/core/iomgr/tcp_posix.h" + +void grpc_iomgr_platform_init(void) { + grpc_fd_global_init(); + grpc_register_tracer("tcp", &grpc_tcp_trace); +} + +void grpc_iomgr_platform_flush(void) {} + +void grpc_iomgr_platform_shutdown(void) { grpc_fd_global_shutdown(); } + +#endif /* GRPC_POSIX_SOCKET */ diff --git a/src/core/lib/iomgr/iomgr_posix.h b/src/core/lib/iomgr/iomgr_posix.h new file mode 100644 index 0000000000..698fb6aee7 --- /dev/null +++ b/src/core/lib/iomgr/iomgr_posix.h @@ -0,0 +1,39 @@ +/* + * + * Copyright 2015-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_IOMGR_IOMGR_POSIX_H +#define GRPC_CORE_IOMGR_IOMGR_POSIX_H + +#include "src/core/iomgr/iomgr_internal.h" + +#endif /* GRPC_CORE_IOMGR_IOMGR_POSIX_H */ diff --git a/src/core/lib/iomgr/iomgr_windows.c b/src/core/lib/iomgr/iomgr_windows.c new file mode 100644 index 0000000000..2d104130f7 --- /dev/null +++ b/src/core/lib/iomgr/iomgr_windows.c @@ -0,0 +1,73 @@ +/* + * + * Copyright 2015-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 + +#ifdef GPR_WINSOCK_SOCKET + +#include "src/core/iomgr/sockaddr_win32.h" + +#include + +#include "src/core/iomgr/iocp_windows.h" +#include "src/core/iomgr/iomgr.h" +#include "src/core/iomgr/socket_windows.h" + +/* Windows' io manager is going to be fully designed using IO completion + ports. All of what we're doing here is basically make sure that + Windows sockets are initialized in and out. */ + +static void winsock_init(void) { + WSADATA wsaData; + int status = WSAStartup(MAKEWORD(2, 0), &wsaData); + GPR_ASSERT(status == 0); +} + +static void winsock_shutdown(void) { + int status = WSACleanup(); + GPR_ASSERT(status == 0); +} + +void grpc_iomgr_platform_init(void) { + winsock_init(); + grpc_iocp_init(); +} + +void grpc_iomgr_platform_flush(void) { grpc_iocp_flush(); } + +void grpc_iomgr_platform_shutdown(void) { + grpc_iocp_shutdown(); + winsock_shutdown(); +} + +#endif /* GRPC_WINSOCK_SOCKET */ diff --git a/src/core/lib/iomgr/pollset.h b/src/core/lib/iomgr/pollset.h new file mode 100644 index 0000000000..9500b1a73a --- /dev/null +++ b/src/core/lib/iomgr/pollset.h @@ -0,0 +1,94 @@ +/* + * + * Copyright 2015-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_IOMGR_POLLSET_H +#define GRPC_CORE_IOMGR_POLLSET_H + +#include +#include +#include + +#include "src/core/iomgr/exec_ctx.h" + +#define GRPC_POLLSET_KICK_BROADCAST ((grpc_pollset_worker *)1) + +/* A grpc_pollset is a set of file descriptors that a higher level item is + interested in. For example: + - a server will typically keep a pollset containing all connected channels, + so that it can find new calls to service + - a completion queue might keep a pollset with an entry for each transport + that is servicing a call that it's tracking */ + +typedef struct grpc_pollset grpc_pollset; +typedef struct grpc_pollset_worker grpc_pollset_worker; + +size_t grpc_pollset_size(void); +void grpc_pollset_init(grpc_pollset *pollset, gpr_mu **mu); +/* Begin shutting down the pollset, and call closure when done. + * pollset's mutex must be held */ +void grpc_pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, + grpc_closure *closure); +/** Reset the pollset to its initial state (perhaps with some cached objects); + * must have been previously shutdown */ +void grpc_pollset_reset(grpc_pollset *pollset); +void grpc_pollset_destroy(grpc_pollset *pollset); + +/* Do some work on a pollset. + May involve invoking asynchronous callbacks, or actually polling file + descriptors. + Requires pollset's mutex locked. + May unlock its mutex during its execution. + + worker is a (platform-specific) handle that can be used to wake up + from grpc_pollset_work before any events are received and before the timeout + has expired. It is both initialized and destroyed by grpc_pollset_work. + Initialization of worker is guaranteed to occur BEFORE the + pollset's mutex is released for the first time by grpc_pollset_work + and it is guaranteed that it will not be released by grpc_pollset_work + AFTER worker has been destroyed. + + Tries not to block past deadline. + May call grpc_closure_list_run on grpc_closure_list, without holding the + pollset + lock */ +void grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, + grpc_pollset_worker **worker, gpr_timespec now, + gpr_timespec deadline); + +/* Break one polling thread out of polling work for this pollset. + If specific_worker is GRPC_POLLSET_KICK_BROADCAST, kick ALL the workers. + Otherwise, if specific_worker is non-NULL, then kick that worker. */ +void grpc_pollset_kick(grpc_pollset *pollset, + grpc_pollset_worker *specific_worker); + +#endif /* GRPC_CORE_IOMGR_POLLSET_H */ diff --git a/src/core/lib/iomgr/pollset_multipoller_with_epoll.c b/src/core/lib/iomgr/pollset_multipoller_with_epoll.c new file mode 100644 index 0000000000..2e0f27fab8 --- /dev/null +++ b/src/core/lib/iomgr/pollset_multipoller_with_epoll.c @@ -0,0 +1,324 @@ +/* + * + * Copyright 2015-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 + +#ifdef GPR_LINUX_MULTIPOLL_WITH_EPOLL + +#include +#include +#include +#include +#include + +#include +#include +#include +#include "src/core/iomgr/fd_posix.h" +#include "src/core/iomgr/pollset_posix.h" +#include "src/core/profiling/timers.h" +#include "src/core/support/block_annotate.h" + +struct epoll_fd_list { + int *epoll_fds; + size_t count; + size_t capacity; +}; + +static struct epoll_fd_list epoll_fd_global_list; +static gpr_once init_epoll_fd_list_mu = GPR_ONCE_INIT; +static gpr_mu epoll_fd_list_mu; + +static void init_mu(void) { gpr_mu_init(&epoll_fd_list_mu); } + +static void add_epoll_fd_to_global_list(int epoll_fd) { + gpr_once_init(&init_epoll_fd_list_mu, init_mu); + + gpr_mu_lock(&epoll_fd_list_mu); + if (epoll_fd_global_list.count == epoll_fd_global_list.capacity) { + epoll_fd_global_list.capacity = + GPR_MAX((size_t)8, epoll_fd_global_list.capacity * 2); + epoll_fd_global_list.epoll_fds = + gpr_realloc(epoll_fd_global_list.epoll_fds, + epoll_fd_global_list.capacity * sizeof(int)); + } + epoll_fd_global_list.epoll_fds[epoll_fd_global_list.count++] = epoll_fd; + gpr_mu_unlock(&epoll_fd_list_mu); +} + +static void remove_epoll_fd_from_global_list(int epoll_fd) { + gpr_mu_lock(&epoll_fd_list_mu); + GPR_ASSERT(epoll_fd_global_list.count > 0); + for (size_t i = 0; i < epoll_fd_global_list.count; i++) { + if (epoll_fd == epoll_fd_global_list.epoll_fds[i]) { + epoll_fd_global_list.epoll_fds[i] = + epoll_fd_global_list.epoll_fds[--(epoll_fd_global_list.count)]; + break; + } + } + gpr_mu_unlock(&epoll_fd_list_mu); +} + +void grpc_remove_fd_from_all_epoll_sets(int fd) { + int err; + gpr_once_init(&init_epoll_fd_list_mu, init_mu); + gpr_mu_lock(&epoll_fd_list_mu); + if (epoll_fd_global_list.count == 0) { + gpr_mu_unlock(&epoll_fd_list_mu); + return; + } + for (size_t i = 0; i < epoll_fd_global_list.count; i++) { + err = epoll_ctl(epoll_fd_global_list.epoll_fds[i], EPOLL_CTL_DEL, fd, NULL); + if (err < 0 && errno != ENOENT) { + gpr_log(GPR_ERROR, "epoll_ctl del for %d failed: %s", fd, + strerror(errno)); + } + } + gpr_mu_unlock(&epoll_fd_list_mu); +} + +typedef struct { + grpc_pollset *pollset; + grpc_fd *fd; + grpc_closure closure; +} delayed_add; + +typedef struct { int epoll_fd; } pollset_hdr; + +static void finally_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, + grpc_fd *fd) { + pollset_hdr *h = pollset->data.ptr; + struct epoll_event ev; + int err; + grpc_fd_watcher watcher; + + /* We pretend to be polling whilst adding an fd to keep the fd from being + closed during the add. This may result in a spurious wakeup being assigned + to this pollset whilst adding, but that should be benign. */ + GPR_ASSERT(grpc_fd_begin_poll(fd, pollset, NULL, 0, 0, &watcher) == 0); + if (watcher.fd != NULL) { + ev.events = (uint32_t)(EPOLLIN | EPOLLOUT | EPOLLET); + ev.data.ptr = fd; + err = epoll_ctl(h->epoll_fd, EPOLL_CTL_ADD, fd->fd, &ev); + if (err < 0) { + /* FDs may be added to a pollset multiple times, so EEXIST is normal. */ + if (errno != EEXIST) { + gpr_log(GPR_ERROR, "epoll_ctl add for %d failed: %s", fd->fd, + strerror(errno)); + } + } + } + grpc_fd_end_poll(exec_ctx, &watcher, 0, 0); +} + +static void perform_delayed_add(grpc_exec_ctx *exec_ctx, void *arg, + bool iomgr_status) { + delayed_add *da = arg; + + if (!grpc_fd_is_orphaned(da->fd)) { + finally_add_fd(exec_ctx, da->pollset, da->fd); + } + + gpr_mu_lock(&da->pollset->mu); + da->pollset->in_flight_cbs--; + if (da->pollset->shutting_down) { + /* We don't care about this pollset anymore. */ + if (da->pollset->in_flight_cbs == 0 && !da->pollset->called_shutdown) { + da->pollset->called_shutdown = 1; + grpc_exec_ctx_enqueue(exec_ctx, da->pollset->shutdown_done, true, NULL); + } + } + gpr_mu_unlock(&da->pollset->mu); + + GRPC_FD_UNREF(da->fd, "delayed_add"); + + gpr_free(da); +} + +static void multipoll_with_epoll_pollset_add_fd(grpc_exec_ctx *exec_ctx, + grpc_pollset *pollset, + grpc_fd *fd, + int and_unlock_pollset) { + if (and_unlock_pollset) { + gpr_mu_unlock(&pollset->mu); + finally_add_fd(exec_ctx, pollset, fd); + } else { + delayed_add *da = gpr_malloc(sizeof(*da)); + da->pollset = pollset; + da->fd = fd; + GRPC_FD_REF(fd, "delayed_add"); + grpc_closure_init(&da->closure, perform_delayed_add, da); + pollset->in_flight_cbs++; + grpc_exec_ctx_enqueue(exec_ctx, &da->closure, true, NULL); + } +} + +/* TODO(klempner): We probably want to turn this down a bit */ +#define GRPC_EPOLL_MAX_EVENTS 1000 + +static void multipoll_with_epoll_pollset_maybe_work_and_unlock( + grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker *worker, + gpr_timespec deadline, gpr_timespec now) { + struct epoll_event ep_ev[GRPC_EPOLL_MAX_EVENTS]; + int ep_rv; + int poll_rv; + pollset_hdr *h = pollset->data.ptr; + int timeout_ms; + struct pollfd pfds[2]; + + /* If you want to ignore epoll's ability to sanely handle parallel pollers, + * for a more apples-to-apples performance comparison with poll, add a + * if (pollset->counter != 0) { return 0; } + * here. + */ + + gpr_mu_unlock(&pollset->mu); + + timeout_ms = grpc_poll_deadline_to_millis_timeout(deadline, now); + + pfds[0].fd = GRPC_WAKEUP_FD_GET_READ_FD(&worker->wakeup_fd->fd); + pfds[0].events = POLLIN; + pfds[0].revents = 0; + pfds[1].fd = h->epoll_fd; + pfds[1].events = POLLIN; + pfds[1].revents = 0; + + /* TODO(vpai): Consider first doing a 0 timeout poll here to avoid + even going into the blocking annotation if possible */ + GPR_TIMER_BEGIN("poll", 0); + GRPC_SCHEDULING_START_BLOCKING_REGION; + poll_rv = grpc_poll_function(pfds, 2, timeout_ms); + GRPC_SCHEDULING_END_BLOCKING_REGION; + GPR_TIMER_END("poll", 0); + + if (poll_rv < 0) { + if (errno != EINTR) { + gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno)); + } + } else if (poll_rv == 0) { + /* do nothing */ + } else { + if (pfds[0].revents) { + grpc_wakeup_fd_consume_wakeup(&worker->wakeup_fd->fd); + } + if (pfds[1].revents) { + do { + /* The following epoll_wait never blocks; it has a timeout of 0 */ + ep_rv = epoll_wait(h->epoll_fd, ep_ev, GRPC_EPOLL_MAX_EVENTS, 0); + if (ep_rv < 0) { + if (errno != EINTR) { + gpr_log(GPR_ERROR, "epoll_wait() failed: %s", strerror(errno)); + } + } else { + int i; + for (i = 0; i < ep_rv; ++i) { + grpc_fd *fd = ep_ev[i].data.ptr; + /* TODO(klempner): We might want to consider making err and pri + * separate events */ + int cancel = ep_ev[i].events & (EPOLLERR | EPOLLHUP); + int read_ev = ep_ev[i].events & (EPOLLIN | EPOLLPRI); + int write_ev = ep_ev[i].events & EPOLLOUT; + if (fd == NULL) { + grpc_wakeup_fd_consume_wakeup(&grpc_global_wakeup_fd); + } else { + if (read_ev || cancel) { + grpc_fd_become_readable(exec_ctx, fd); + } + if (write_ev || cancel) { + grpc_fd_become_writable(exec_ctx, fd); + } + } + } + } + } while (ep_rv == GRPC_EPOLL_MAX_EVENTS); + } + } +} + +static void multipoll_with_epoll_pollset_finish_shutdown( + grpc_pollset *pollset) {} + +static void multipoll_with_epoll_pollset_destroy(grpc_pollset *pollset) { + pollset_hdr *h = pollset->data.ptr; + close(h->epoll_fd); + remove_epoll_fd_from_global_list(h->epoll_fd); + gpr_free(h); +} + +static const grpc_pollset_vtable multipoll_with_epoll_pollset = { + multipoll_with_epoll_pollset_add_fd, + multipoll_with_epoll_pollset_maybe_work_and_unlock, + multipoll_with_epoll_pollset_finish_shutdown, + multipoll_with_epoll_pollset_destroy}; + +static void epoll_become_multipoller(grpc_exec_ctx *exec_ctx, + grpc_pollset *pollset, grpc_fd **fds, + size_t nfds) { + size_t i; + pollset_hdr *h = gpr_malloc(sizeof(pollset_hdr)); + struct epoll_event ev; + int err; + + pollset->vtable = &multipoll_with_epoll_pollset; + pollset->data.ptr = h; + h->epoll_fd = epoll_create1(EPOLL_CLOEXEC); + if (h->epoll_fd < 0) { + /* TODO(klempner): Fall back to poll here, especially on ENOSYS */ + gpr_log(GPR_ERROR, "epoll_create1 failed: %s", strerror(errno)); + abort(); + } + add_epoll_fd_to_global_list(h->epoll_fd); + + ev.events = (uint32_t)(EPOLLIN | EPOLLET); + ev.data.ptr = NULL; + err = epoll_ctl(h->epoll_fd, EPOLL_CTL_ADD, + GRPC_WAKEUP_FD_GET_READ_FD(&grpc_global_wakeup_fd), &ev); + if (err < 0) { + gpr_log(GPR_ERROR, "epoll_ctl add for %d failed: %s", + GRPC_WAKEUP_FD_GET_READ_FD(&grpc_global_wakeup_fd), + strerror(errno)); + } + + for (i = 0; i < nfds; i++) { + multipoll_with_epoll_pollset_add_fd(exec_ctx, pollset, fds[i], 0); + } +} + +grpc_platform_become_multipoller_type grpc_platform_become_multipoller = + epoll_become_multipoller; + +#else /* GPR_LINUX_MULTIPOLL_WITH_EPOLL */ + +void grpc_remove_fd_from_all_epoll_sets(int fd) {} + +#endif /* GPR_LINUX_MULTIPOLL_WITH_EPOLL */ diff --git a/src/core/lib/iomgr/pollset_multipoller_with_poll_posix.c b/src/core/lib/iomgr/pollset_multipoller_with_poll_posix.c new file mode 100644 index 0000000000..92d6fb7241 --- /dev/null +++ b/src/core/lib/iomgr/pollset_multipoller_with_poll_posix.c @@ -0,0 +1,234 @@ +/* + * + * Copyright 2015-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 + +#ifdef GPR_POSIX_SOCKET + +#include "src/core/iomgr/pollset_posix.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include "src/core/iomgr/fd_posix.h" +#include "src/core/iomgr/iomgr_internal.h" +#include "src/core/iomgr/pollset_posix.h" +#include "src/core/support/block_annotate.h" + +typedef struct { + /* all polled fds */ + size_t fd_count; + size_t fd_capacity; + grpc_fd **fds; + /* fds that have been removed from the pollset explicitly */ + size_t del_count; + size_t del_capacity; + grpc_fd **dels; +} pollset_hdr; + +static void multipoll_with_poll_pollset_add_fd(grpc_exec_ctx *exec_ctx, + grpc_pollset *pollset, + grpc_fd *fd, + int and_unlock_pollset) { + size_t i; + pollset_hdr *h = pollset->data.ptr; + /* TODO(ctiller): this is O(num_fds^2); maybe switch to a hash set here */ + for (i = 0; i < h->fd_count; i++) { + if (h->fds[i] == fd) goto exit; + } + if (h->fd_count == h->fd_capacity) { + h->fd_capacity = GPR_MAX(h->fd_capacity + 8, h->fd_count * 3 / 2); + h->fds = gpr_realloc(h->fds, sizeof(grpc_fd *) * h->fd_capacity); + } + h->fds[h->fd_count++] = fd; + GRPC_FD_REF(fd, "multipoller"); +exit: + if (and_unlock_pollset) { + gpr_mu_unlock(&pollset->mu); + } +} + +static void multipoll_with_poll_pollset_maybe_work_and_unlock( + grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker *worker, + gpr_timespec deadline, gpr_timespec now) { +#define POLLOUT_CHECK (POLLOUT | POLLHUP | POLLERR) +#define POLLIN_CHECK (POLLIN | POLLHUP | POLLERR) + + int timeout; + int r; + size_t i, j, fd_count; + nfds_t pfd_count; + pollset_hdr *h; + /* TODO(ctiller): inline some elements to avoid an allocation */ + grpc_fd_watcher *watchers; + struct pollfd *pfds; + + h = pollset->data.ptr; + timeout = grpc_poll_deadline_to_millis_timeout(deadline, now); + /* TODO(ctiller): perform just one malloc here if we exceed the inline case */ + pfds = gpr_malloc(sizeof(*pfds) * (h->fd_count + 2)); + watchers = gpr_malloc(sizeof(*watchers) * (h->fd_count + 2)); + fd_count = 0; + pfd_count = 2; + pfds[0].fd = GRPC_WAKEUP_FD_GET_READ_FD(&grpc_global_wakeup_fd); + pfds[0].events = POLLIN; + pfds[0].revents = 0; + pfds[1].fd = GRPC_WAKEUP_FD_GET_READ_FD(&worker->wakeup_fd->fd); + pfds[1].events = POLLIN; + pfds[1].revents = 0; + for (i = 0; i < h->fd_count; i++) { + int remove = grpc_fd_is_orphaned(h->fds[i]); + for (j = 0; !remove && j < h->del_count; j++) { + if (h->fds[i] == h->dels[j]) remove = 1; + } + if (remove) { + GRPC_FD_UNREF(h->fds[i], "multipoller"); + } else { + h->fds[fd_count++] = h->fds[i]; + watchers[pfd_count].fd = h->fds[i]; + GRPC_FD_REF(watchers[pfd_count].fd, "multipoller_start"); + pfds[pfd_count].fd = h->fds[i]->fd; + pfds[pfd_count].revents = 0; + pfd_count++; + } + } + for (j = 0; j < h->del_count; j++) { + GRPC_FD_UNREF(h->dels[j], "multipoller_del"); + } + h->del_count = 0; + h->fd_count = fd_count; + gpr_mu_unlock(&pollset->mu); + + for (i = 2; i < pfd_count; i++) { + grpc_fd *fd = watchers[i].fd; + pfds[i].events = (short)grpc_fd_begin_poll(fd, pollset, worker, POLLIN, + POLLOUT, &watchers[i]); + GRPC_FD_UNREF(fd, "multipoller_start"); + } + + /* TODO(vpai): Consider first doing a 0 timeout poll here to avoid + even going into the blocking annotation if possible */ + GRPC_SCHEDULING_START_BLOCKING_REGION; + r = grpc_poll_function(pfds, pfd_count, timeout); + GRPC_SCHEDULING_END_BLOCKING_REGION; + + if (r < 0) { + if (errno != EINTR) { + gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno)); + } + for (i = 2; i < pfd_count; i++) { + grpc_fd_end_poll(exec_ctx, &watchers[i], 0, 0); + } + } else if (r == 0) { + for (i = 2; i < pfd_count; i++) { + grpc_fd_end_poll(exec_ctx, &watchers[i], 0, 0); + } + } else { + if (pfds[0].revents & POLLIN_CHECK) { + grpc_wakeup_fd_consume_wakeup(&grpc_global_wakeup_fd); + } + if (pfds[1].revents & POLLIN_CHECK) { + grpc_wakeup_fd_consume_wakeup(&worker->wakeup_fd->fd); + } + for (i = 2; i < pfd_count; i++) { + if (watchers[i].fd == NULL) { + grpc_fd_end_poll(exec_ctx, &watchers[i], 0, 0); + continue; + } + grpc_fd_end_poll(exec_ctx, &watchers[i], pfds[i].revents & POLLIN_CHECK, + pfds[i].revents & POLLOUT_CHECK); + } + } + + gpr_free(pfds); + gpr_free(watchers); +} + +static void multipoll_with_poll_pollset_finish_shutdown(grpc_pollset *pollset) { + size_t i; + pollset_hdr *h = pollset->data.ptr; + for (i = 0; i < h->fd_count; i++) { + GRPC_FD_UNREF(h->fds[i], "multipoller"); + } + for (i = 0; i < h->del_count; i++) { + GRPC_FD_UNREF(h->dels[i], "multipoller_del"); + } + h->fd_count = 0; + h->del_count = 0; +} + +static void multipoll_with_poll_pollset_destroy(grpc_pollset *pollset) { + pollset_hdr *h = pollset->data.ptr; + multipoll_with_poll_pollset_finish_shutdown(pollset); + gpr_free(h->fds); + gpr_free(h->dels); + gpr_free(h); +} + +static const grpc_pollset_vtable multipoll_with_poll_pollset = { + multipoll_with_poll_pollset_add_fd, + multipoll_with_poll_pollset_maybe_work_and_unlock, + multipoll_with_poll_pollset_finish_shutdown, + multipoll_with_poll_pollset_destroy}; + +void grpc_poll_become_multipoller(grpc_exec_ctx *exec_ctx, + grpc_pollset *pollset, grpc_fd **fds, + size_t nfds) { + size_t i; + pollset_hdr *h = gpr_malloc(sizeof(pollset_hdr)); + pollset->vtable = &multipoll_with_poll_pollset; + pollset->data.ptr = h; + h->fd_count = nfds; + h->fd_capacity = nfds; + h->fds = gpr_malloc(nfds * sizeof(grpc_fd *)); + h->del_count = 0; + h->del_capacity = 0; + h->dels = NULL; + for (i = 0; i < nfds; i++) { + h->fds[i] = fds[i]; + GRPC_FD_REF(fds[i], "multipoller"); + } +} + +#endif /* GPR_POSIX_SOCKET */ + +#ifdef GPR_POSIX_MULTIPOLL_WITH_POLL +grpc_platform_become_multipoller_type grpc_platform_become_multipoller = + grpc_poll_become_multipoller; +#endif diff --git a/src/core/lib/iomgr/pollset_posix.c b/src/core/lib/iomgr/pollset_posix.c new file mode 100644 index 0000000000..e895a77884 --- /dev/null +++ b/src/core/lib/iomgr/pollset_posix.c @@ -0,0 +1,633 @@ +/* + * + * Copyright 2015-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 + +#ifdef GPR_POSIX_SOCKET + +#include "src/core/iomgr/pollset_posix.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "src/core/iomgr/fd_posix.h" +#include "src/core/iomgr/iomgr_internal.h" +#include "src/core/iomgr/socket_utils_posix.h" +#include "src/core/profiling/timers.h" +#include "src/core/support/block_annotate.h" + +GPR_TLS_DECL(g_current_thread_poller); +GPR_TLS_DECL(g_current_thread_worker); + +/** Default poll() function - a pointer so that it can be overridden by some + * tests */ +grpc_poll_function_type grpc_poll_function = poll; + +/** The alarm system needs to be able to wakeup 'some poller' sometimes + * (specifically when a new alarm needs to be triggered earlier than the next + * alarm 'epoch'). + * This wakeup_fd gives us something to alert on when such a case occurs. */ +grpc_wakeup_fd grpc_global_wakeup_fd; + +static void remove_worker(grpc_pollset *p, grpc_pollset_worker *worker) { + worker->prev->next = worker->next; + worker->next->prev = worker->prev; +} + +int grpc_pollset_has_workers(grpc_pollset *p) { + return p->root_worker.next != &p->root_worker; +} + +static grpc_pollset_worker *pop_front_worker(grpc_pollset *p) { + if (grpc_pollset_has_workers(p)) { + grpc_pollset_worker *w = p->root_worker.next; + remove_worker(p, w); + return w; + } else { + return NULL; + } +} + +static void push_back_worker(grpc_pollset *p, grpc_pollset_worker *worker) { + worker->next = &p->root_worker; + worker->prev = worker->next->prev; + worker->prev->next = worker->next->prev = worker; +} + +static void push_front_worker(grpc_pollset *p, grpc_pollset_worker *worker) { + worker->prev = &p->root_worker; + worker->next = worker->prev->next; + worker->prev->next = worker->next->prev = worker; +} + +size_t grpc_pollset_size(void) { return sizeof(grpc_pollset); } + +void grpc_pollset_kick_ext(grpc_pollset *p, + grpc_pollset_worker *specific_worker, + uint32_t flags) { + GPR_TIMER_BEGIN("grpc_pollset_kick_ext", 0); + + /* pollset->mu already held */ + if (specific_worker != NULL) { + if (specific_worker == GRPC_POLLSET_KICK_BROADCAST) { + GPR_TIMER_BEGIN("grpc_pollset_kick_ext.broadcast", 0); + GPR_ASSERT((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) == 0); + for (specific_worker = p->root_worker.next; + specific_worker != &p->root_worker; + specific_worker = specific_worker->next) { + grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd); + } + p->kicked_without_pollers = 1; + GPR_TIMER_END("grpc_pollset_kick_ext.broadcast", 0); + } else if (gpr_tls_get(&g_current_thread_worker) != + (intptr_t)specific_worker) { + GPR_TIMER_MARK("different_thread_worker", 0); + if ((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) != 0) { + specific_worker->reevaluate_polling_on_wakeup = 1; + } + specific_worker->kicked_specifically = 1; + grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd); + } else if ((flags & GRPC_POLLSET_CAN_KICK_SELF) != 0) { + GPR_TIMER_MARK("kick_yoself", 0); + if ((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) != 0) { + specific_worker->reevaluate_polling_on_wakeup = 1; + } + specific_worker->kicked_specifically = 1; + grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd); + } + } else if (gpr_tls_get(&g_current_thread_poller) != (intptr_t)p) { + GPR_ASSERT((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) == 0); + GPR_TIMER_MARK("kick_anonymous", 0); + specific_worker = pop_front_worker(p); + if (specific_worker != NULL) { + if (gpr_tls_get(&g_current_thread_worker) == (intptr_t)specific_worker) { + GPR_TIMER_MARK("kick_anonymous_not_self", 0); + push_back_worker(p, specific_worker); + specific_worker = pop_front_worker(p); + if ((flags & GRPC_POLLSET_CAN_KICK_SELF) == 0 && + gpr_tls_get(&g_current_thread_worker) == + (intptr_t)specific_worker) { + push_back_worker(p, specific_worker); + specific_worker = NULL; + } + } + if (specific_worker != NULL) { + GPR_TIMER_MARK("finally_kick", 0); + push_back_worker(p, specific_worker); + grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd); + } + } else { + GPR_TIMER_MARK("kicked_no_pollers", 0); + p->kicked_without_pollers = 1; + } + } + + GPR_TIMER_END("grpc_pollset_kick_ext", 0); +} + +void grpc_pollset_kick(grpc_pollset *p, grpc_pollset_worker *specific_worker) { + grpc_pollset_kick_ext(p, specific_worker, 0); +} + +/* global state management */ + +void grpc_pollset_global_init(void) { + gpr_tls_init(&g_current_thread_poller); + gpr_tls_init(&g_current_thread_worker); + grpc_wakeup_fd_global_init(); + grpc_wakeup_fd_init(&grpc_global_wakeup_fd); +} + +void grpc_pollset_global_shutdown(void) { + grpc_wakeup_fd_destroy(&grpc_global_wakeup_fd); + gpr_tls_destroy(&g_current_thread_poller); + gpr_tls_destroy(&g_current_thread_worker); + grpc_wakeup_fd_global_destroy(); +} + +void grpc_kick_poller(void) { grpc_wakeup_fd_wakeup(&grpc_global_wakeup_fd); } + +/* main interface */ + +static void become_basic_pollset(grpc_pollset *pollset, grpc_fd *fd_or_null); + +void grpc_pollset_init(grpc_pollset *pollset, gpr_mu **mu) { + gpr_mu_init(&pollset->mu); + *mu = &pollset->mu; + pollset->root_worker.next = pollset->root_worker.prev = &pollset->root_worker; + pollset->in_flight_cbs = 0; + pollset->shutting_down = 0; + pollset->called_shutdown = 0; + pollset->kicked_without_pollers = 0; + pollset->idle_jobs.head = pollset->idle_jobs.tail = NULL; + pollset->local_wakeup_cache = NULL; + pollset->kicked_without_pollers = 0; + become_basic_pollset(pollset, NULL); +} + +void grpc_pollset_destroy(grpc_pollset *pollset) { + GPR_ASSERT(pollset->in_flight_cbs == 0); + GPR_ASSERT(!grpc_pollset_has_workers(pollset)); + GPR_ASSERT(pollset->idle_jobs.head == pollset->idle_jobs.tail); + pollset->vtable->destroy(pollset); + while (pollset->local_wakeup_cache) { + grpc_cached_wakeup_fd *next = pollset->local_wakeup_cache->next; + grpc_wakeup_fd_destroy(&pollset->local_wakeup_cache->fd); + gpr_free(pollset->local_wakeup_cache); + pollset->local_wakeup_cache = next; + } +} + +void grpc_pollset_reset(grpc_pollset *pollset) { + GPR_ASSERT(pollset->shutting_down); + GPR_ASSERT(pollset->in_flight_cbs == 0); + GPR_ASSERT(!grpc_pollset_has_workers(pollset)); + GPR_ASSERT(pollset->idle_jobs.head == pollset->idle_jobs.tail); + pollset->vtable->destroy(pollset); + pollset->shutting_down = 0; + pollset->called_shutdown = 0; + pollset->kicked_without_pollers = 0; + become_basic_pollset(pollset, NULL); +} + +void grpc_pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, + grpc_fd *fd) { + gpr_mu_lock(&pollset->mu); + pollset->vtable->add_fd(exec_ctx, pollset, fd, 1); +/* the following (enabled only in debug) will reacquire and then release + our lock - meaning that if the unlocking flag passed to add_fd above is + not respected, the code will deadlock (in a way that we have a chance of + debugging) */ +#ifndef NDEBUG + gpr_mu_lock(&pollset->mu); + gpr_mu_unlock(&pollset->mu); +#endif +} + +static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) { + GPR_ASSERT(grpc_closure_list_empty(pollset->idle_jobs)); + pollset->vtable->finish_shutdown(pollset); + grpc_exec_ctx_enqueue(exec_ctx, pollset->shutdown_done, true, NULL); +} + +void grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, + grpc_pollset_worker **worker_hdl, gpr_timespec now, + gpr_timespec deadline) { + grpc_pollset_worker worker; + *worker_hdl = &worker; + + /* pollset->mu already held */ + int added_worker = 0; + int locked = 1; + int queued_work = 0; + int keep_polling = 0; + GPR_TIMER_BEGIN("grpc_pollset_work", 0); + /* this must happen before we (potentially) drop pollset->mu */ + worker.next = worker.prev = NULL; + worker.reevaluate_polling_on_wakeup = 0; + if (pollset->local_wakeup_cache != NULL) { + worker.wakeup_fd = pollset->local_wakeup_cache; + pollset->local_wakeup_cache = worker.wakeup_fd->next; + } else { + worker.wakeup_fd = gpr_malloc(sizeof(*worker.wakeup_fd)); + grpc_wakeup_fd_init(&worker.wakeup_fd->fd); + } + worker.kicked_specifically = 0; + /* If there's work waiting for the pollset to be idle, and the + pollset is idle, then do that work */ + if (!grpc_pollset_has_workers(pollset) && + !grpc_closure_list_empty(pollset->idle_jobs)) { + GPR_TIMER_MARK("grpc_pollset_work.idle_jobs", 0); + grpc_exec_ctx_enqueue_list(exec_ctx, &pollset->idle_jobs, NULL); + goto done; + } + /* If we're shutting down then we don't execute any extended work */ + if (pollset->shutting_down) { + GPR_TIMER_MARK("grpc_pollset_work.shutting_down", 0); + goto done; + } + /* Give do_promote priority so we don't starve it out */ + if (pollset->in_flight_cbs) { + GPR_TIMER_MARK("grpc_pollset_work.in_flight_cbs", 0); + gpr_mu_unlock(&pollset->mu); + locked = 0; + goto done; + } + /* Start polling, and keep doing so while we're being asked to + re-evaluate our pollers (this allows poll() based pollers to + ensure they don't miss wakeups) */ + keep_polling = 1; + while (keep_polling) { + keep_polling = 0; + if (!pollset->kicked_without_pollers) { + if (!added_worker) { + push_front_worker(pollset, &worker); + added_worker = 1; + gpr_tls_set(&g_current_thread_worker, (intptr_t)&worker); + } + gpr_tls_set(&g_current_thread_poller, (intptr_t)pollset); + GPR_TIMER_BEGIN("maybe_work_and_unlock", 0); + pollset->vtable->maybe_work_and_unlock(exec_ctx, pollset, &worker, + deadline, now); + GPR_TIMER_END("maybe_work_and_unlock", 0); + locked = 0; + gpr_tls_set(&g_current_thread_poller, 0); + } else { + GPR_TIMER_MARK("grpc_pollset_work.kicked_without_pollers", 0); + pollset->kicked_without_pollers = 0; + } + /* Finished execution - start cleaning up. + Note that we may arrive here from outside the enclosing while() loop. + In that case we won't loop though as we haven't added worker to the + worker list, which means nobody could ask us to re-evaluate polling). */ + done: + if (!locked) { + queued_work |= grpc_exec_ctx_flush(exec_ctx); + gpr_mu_lock(&pollset->mu); + locked = 1; + } + /* If we're forced to re-evaluate polling (via grpc_pollset_kick with + GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) then we land here and force + a loop */ + if (worker.reevaluate_polling_on_wakeup) { + worker.reevaluate_polling_on_wakeup = 0; + pollset->kicked_without_pollers = 0; + if (queued_work || worker.kicked_specifically) { + /* If there's queued work on the list, then set the deadline to be + immediate so we get back out of the polling loop quickly */ + deadline = gpr_inf_past(GPR_CLOCK_MONOTONIC); + } + keep_polling = 1; + } + } + if (added_worker) { + remove_worker(pollset, &worker); + gpr_tls_set(&g_current_thread_worker, 0); + } + /* release wakeup fd to the local pool */ + worker.wakeup_fd->next = pollset->local_wakeup_cache; + pollset->local_wakeup_cache = worker.wakeup_fd; + /* check shutdown conditions */ + if (pollset->shutting_down) { + if (grpc_pollset_has_workers(pollset)) { + grpc_pollset_kick(pollset, NULL); + } else if (!pollset->called_shutdown && pollset->in_flight_cbs == 0) { + pollset->called_shutdown = 1; + gpr_mu_unlock(&pollset->mu); + finish_shutdown(exec_ctx, pollset); + grpc_exec_ctx_flush(exec_ctx); + /* Continuing to access pollset here is safe -- it is the caller's + * responsibility to not destroy when it has outstanding calls to + * grpc_pollset_work. + * TODO(dklempner): Can we refactor the shutdown logic to avoid this? */ + gpr_mu_lock(&pollset->mu); + } else if (!grpc_closure_list_empty(pollset->idle_jobs)) { + grpc_exec_ctx_enqueue_list(exec_ctx, &pollset->idle_jobs, NULL); + gpr_mu_unlock(&pollset->mu); + grpc_exec_ctx_flush(exec_ctx); + gpr_mu_lock(&pollset->mu); + } + } + *worker_hdl = NULL; + GPR_TIMER_END("grpc_pollset_work", 0); +} + +void grpc_pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, + grpc_closure *closure) { + GPR_ASSERT(!pollset->shutting_down); + pollset->shutting_down = 1; + pollset->shutdown_done = closure; + grpc_pollset_kick(pollset, GRPC_POLLSET_KICK_BROADCAST); + if (!grpc_pollset_has_workers(pollset)) { + grpc_exec_ctx_enqueue_list(exec_ctx, &pollset->idle_jobs, NULL); + } + if (!pollset->called_shutdown && pollset->in_flight_cbs == 0 && + !grpc_pollset_has_workers(pollset)) { + pollset->called_shutdown = 1; + finish_shutdown(exec_ctx, pollset); + } +} + +int grpc_poll_deadline_to_millis_timeout(gpr_timespec deadline, + gpr_timespec now) { + gpr_timespec timeout; + static const int64_t max_spin_polling_us = 10; + if (gpr_time_cmp(deadline, gpr_inf_future(deadline.clock_type)) == 0) { + return -1; + } + if (gpr_time_cmp(deadline, gpr_time_add(now, gpr_time_from_micros( + max_spin_polling_us, + GPR_TIMESPAN))) <= 0) { + return 0; + } + timeout = gpr_time_sub(deadline, now); + return gpr_time_to_millis(gpr_time_add( + timeout, gpr_time_from_nanos(GPR_NS_PER_MS - 1, GPR_TIMESPAN))); +} + +/* + * basic_pollset - a vtable that provides polling for zero or one file + * descriptor via poll() + */ + +typedef struct grpc_unary_promote_args { + const grpc_pollset_vtable *original_vtable; + grpc_pollset *pollset; + grpc_fd *fd; + grpc_closure promotion_closure; +} grpc_unary_promote_args; + +static void basic_do_promote(grpc_exec_ctx *exec_ctx, void *args, + bool success) { + grpc_unary_promote_args *up_args = args; + const grpc_pollset_vtable *original_vtable = up_args->original_vtable; + grpc_pollset *pollset = up_args->pollset; + grpc_fd *fd = up_args->fd; + + /* + * This is quite tricky. There are a number of cases to keep in mind here: + * 1. fd may have been orphaned + * 2. The pollset may no longer be a unary poller (and we can't let case #1 + * leak to other pollset types!) + * 3. pollset's fd (which may have changed) may have been orphaned + * 4. The pollset may be shutting down. + */ + + gpr_mu_lock(&pollset->mu); + /* First we need to ensure that nobody is polling concurrently */ + GPR_ASSERT(!grpc_pollset_has_workers(pollset)); + + gpr_free(up_args); + /* At this point the pollset may no longer be a unary poller. In that case + * we should just call the right add function and be done. */ + /* TODO(klempner): If we're not careful this could cause infinite recursion. + * That's not a problem for now because empty_pollset has a trivial poller + * and we don't have any mechanism to unbecome multipoller. */ + pollset->in_flight_cbs--; + if (pollset->shutting_down) { + /* We don't care about this pollset anymore. */ + if (pollset->in_flight_cbs == 0 && !pollset->called_shutdown) { + pollset->called_shutdown = 1; + finish_shutdown(exec_ctx, pollset); + } + } else if (grpc_fd_is_orphaned(fd)) { + /* Don't try to add it to anything, we'll drop our ref on it below */ + } else if (pollset->vtable != original_vtable) { + pollset->vtable->add_fd(exec_ctx, pollset, fd, 0); + } else if (fd != pollset->data.ptr) { + grpc_fd *fds[2]; + fds[0] = pollset->data.ptr; + fds[1] = fd; + + if (fds[0] && !grpc_fd_is_orphaned(fds[0])) { + grpc_platform_become_multipoller(exec_ctx, pollset, fds, + GPR_ARRAY_SIZE(fds)); + GRPC_FD_UNREF(fds[0], "basicpoll"); + } else { + /* old fd is orphaned and we haven't cleaned it up until now, so remain a + * unary poller */ + /* Note that it is possible that fds[1] is also orphaned at this point. + * That's okay, we'll correct it at the next add or poll. */ + if (fds[0]) GRPC_FD_UNREF(fds[0], "basicpoll"); + pollset->data.ptr = fd; + GRPC_FD_REF(fd, "basicpoll"); + } + } + + gpr_mu_unlock(&pollset->mu); + + /* Matching ref in basic_pollset_add_fd */ + GRPC_FD_UNREF(fd, "basicpoll_add"); +} + +static void basic_pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, + grpc_fd *fd, int and_unlock_pollset) { + grpc_unary_promote_args *up_args; + GPR_ASSERT(fd); + if (fd == pollset->data.ptr) goto exit; + + if (!grpc_pollset_has_workers(pollset)) { + /* Fast path -- no in flight cbs */ + /* TODO(klempner): Comment this out and fix any test failures or establish + * they are due to timing issues */ + grpc_fd *fds[2]; + fds[0] = pollset->data.ptr; + fds[1] = fd; + + if (fds[0] == NULL) { + pollset->data.ptr = fd; + GRPC_FD_REF(fd, "basicpoll"); + } else if (!grpc_fd_is_orphaned(fds[0])) { + grpc_platform_become_multipoller(exec_ctx, pollset, fds, + GPR_ARRAY_SIZE(fds)); + GRPC_FD_UNREF(fds[0], "basicpoll"); + } else { + /* old fd is orphaned and we haven't cleaned it up until now, so remain a + * unary poller */ + GRPC_FD_UNREF(fds[0], "basicpoll"); + pollset->data.ptr = fd; + GRPC_FD_REF(fd, "basicpoll"); + } + goto exit; + } + + /* Now we need to promote. This needs to happen when we're not polling. Since + * this may be called from poll, the wait needs to happen asynchronously. */ + GRPC_FD_REF(fd, "basicpoll_add"); + pollset->in_flight_cbs++; + up_args = gpr_malloc(sizeof(*up_args)); + up_args->fd = fd; + up_args->original_vtable = pollset->vtable; + up_args->pollset = pollset; + up_args->promotion_closure.cb = basic_do_promote; + up_args->promotion_closure.cb_arg = up_args; + + grpc_closure_list_add(&pollset->idle_jobs, &up_args->promotion_closure, 1); + grpc_pollset_kick(pollset, GRPC_POLLSET_KICK_BROADCAST); + +exit: + if (and_unlock_pollset) { + gpr_mu_unlock(&pollset->mu); + } +} + +static void basic_pollset_maybe_work_and_unlock(grpc_exec_ctx *exec_ctx, + grpc_pollset *pollset, + grpc_pollset_worker *worker, + gpr_timespec deadline, + gpr_timespec now) { +#define POLLOUT_CHECK (POLLOUT | POLLHUP | POLLERR) +#define POLLIN_CHECK (POLLIN | POLLHUP | POLLERR) + + struct pollfd pfd[3]; + grpc_fd *fd; + grpc_fd_watcher fd_watcher; + int timeout; + int r; + nfds_t nfds; + + fd = pollset->data.ptr; + if (fd && grpc_fd_is_orphaned(fd)) { + GRPC_FD_UNREF(fd, "basicpoll"); + fd = pollset->data.ptr = NULL; + } + timeout = grpc_poll_deadline_to_millis_timeout(deadline, now); + pfd[0].fd = GRPC_WAKEUP_FD_GET_READ_FD(&grpc_global_wakeup_fd); + pfd[0].events = POLLIN; + pfd[0].revents = 0; + pfd[1].fd = GRPC_WAKEUP_FD_GET_READ_FD(&worker->wakeup_fd->fd); + pfd[1].events = POLLIN; + pfd[1].revents = 0; + nfds = 2; + if (fd) { + pfd[2].fd = fd->fd; + pfd[2].revents = 0; + GRPC_FD_REF(fd, "basicpoll_begin"); + gpr_mu_unlock(&pollset->mu); + pfd[2].events = (short)grpc_fd_begin_poll(fd, pollset, worker, POLLIN, + POLLOUT, &fd_watcher); + if (pfd[2].events != 0) { + nfds++; + } + } else { + gpr_mu_unlock(&pollset->mu); + } + + /* TODO(vpai): Consider first doing a 0 timeout poll here to avoid + even going into the blocking annotation if possible */ + /* poll fd count (argument 2) is shortened by one if we have no events + to poll on - such that it only includes the kicker */ + GPR_TIMER_BEGIN("poll", 0); + GRPC_SCHEDULING_START_BLOCKING_REGION; + r = grpc_poll_function(pfd, nfds, timeout); + GRPC_SCHEDULING_END_BLOCKING_REGION; + GPR_TIMER_END("poll", 0); + + if (r < 0) { + if (errno != EINTR) { + gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno)); + } + if (fd) { + grpc_fd_end_poll(exec_ctx, &fd_watcher, 0, 0); + } + } else if (r == 0) { + if (fd) { + grpc_fd_end_poll(exec_ctx, &fd_watcher, 0, 0); + } + } else { + if (pfd[0].revents & POLLIN_CHECK) { + grpc_wakeup_fd_consume_wakeup(&grpc_global_wakeup_fd); + } + if (pfd[1].revents & POLLIN_CHECK) { + grpc_wakeup_fd_consume_wakeup(&worker->wakeup_fd->fd); + } + if (nfds > 2) { + grpc_fd_end_poll(exec_ctx, &fd_watcher, pfd[2].revents & POLLIN_CHECK, + pfd[2].revents & POLLOUT_CHECK); + } else if (fd) { + grpc_fd_end_poll(exec_ctx, &fd_watcher, 0, 0); + } + } + + if (fd) { + GRPC_FD_UNREF(fd, "basicpoll_begin"); + } +} + +static void basic_pollset_destroy(grpc_pollset *pollset) { + if (pollset->data.ptr != NULL) { + GRPC_FD_UNREF(pollset->data.ptr, "basicpoll"); + pollset->data.ptr = NULL; + } +} + +static const grpc_pollset_vtable basic_pollset = { + basic_pollset_add_fd, basic_pollset_maybe_work_and_unlock, + basic_pollset_destroy, basic_pollset_destroy}; + +static void become_basic_pollset(grpc_pollset *pollset, grpc_fd *fd_or_null) { + pollset->vtable = &basic_pollset; + pollset->data.ptr = fd_or_null; + if (fd_or_null != NULL) { + GRPC_FD_REF(fd_or_null, "basicpoll"); + } +} + +#endif /* GPR_POSIX_POLLSET */ diff --git a/src/core/lib/iomgr/pollset_posix.h b/src/core/lib/iomgr/pollset_posix.h new file mode 100644 index 0000000000..e0cfc44395 --- /dev/null +++ b/src/core/lib/iomgr/pollset_posix.h @@ -0,0 +1,153 @@ +/* + * + * Copyright 2015-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_IOMGR_POLLSET_POSIX_H +#define GRPC_CORE_IOMGR_POLLSET_POSIX_H + +#include + +#include + +#include "src/core/iomgr/exec_ctx.h" +#include "src/core/iomgr/iomgr.h" +#include "src/core/iomgr/pollset.h" +#include "src/core/iomgr/wakeup_fd_posix.h" + +typedef struct grpc_pollset_vtable grpc_pollset_vtable; + +/* forward declare only in this file to avoid leaking impl details via + pollset.h; real users of grpc_fd should always include 'fd_posix.h' and not + use the struct tag */ +struct grpc_fd; + +typedef struct grpc_cached_wakeup_fd { + grpc_wakeup_fd fd; + struct grpc_cached_wakeup_fd *next; +} grpc_cached_wakeup_fd; + +struct grpc_pollset_worker { + grpc_cached_wakeup_fd *wakeup_fd; + int reevaluate_polling_on_wakeup; + int kicked_specifically; + struct grpc_pollset_worker *next; + struct grpc_pollset_worker *prev; +}; + +struct grpc_pollset { + /* pollsets under posix can mutate representation as fds are added and + removed. + For example, we may choose a poll() based implementation on linux for + few fds, and an epoll() based implementation for many fds */ + const grpc_pollset_vtable *vtable; + gpr_mu mu; + grpc_pollset_worker root_worker; + int in_flight_cbs; + int shutting_down; + int called_shutdown; + int kicked_without_pollers; + grpc_closure *shutdown_done; + grpc_closure_list idle_jobs; + union { + int fd; + void *ptr; + } data; + /* Local cache of eventfds for workers */ + grpc_cached_wakeup_fd *local_wakeup_cache; +}; + +struct grpc_pollset_vtable { + void (*add_fd)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, + struct grpc_fd *fd, int and_unlock_pollset); + void (*maybe_work_and_unlock)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, + grpc_pollset_worker *worker, + gpr_timespec deadline, gpr_timespec now); + void (*finish_shutdown)(grpc_pollset *pollset); + void (*destroy)(grpc_pollset *pollset); +}; + +/* Add an fd to a pollset */ +void grpc_pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, + struct grpc_fd *fd); + +/* Returns the fd to listen on for kicks */ +int grpc_kick_read_fd(grpc_pollset *p); +/* Call after polling has been kicked to leave the kicked state */ +void grpc_kick_drain(grpc_pollset *p); + +/* Convert a timespec to milliseconds: + - very small or negative poll times are clamped to zero to do a + non-blocking poll (which becomes spin polling) + - other small values are rounded up to one millisecond + - longer than a millisecond polls are rounded up to the next nearest + millisecond to avoid spinning + - infinite timeouts are converted to -1 */ +int grpc_poll_deadline_to_millis_timeout(gpr_timespec deadline, + gpr_timespec now); + +/* Allow kick to wakeup the currently polling worker */ +#define GRPC_POLLSET_CAN_KICK_SELF 1 +/* Force the wakee to repoll when awoken */ +#define GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP 2 +/* As per grpc_pollset_kick, with an extended set of flags (defined above) + -- mostly for fd_posix's use. */ +void grpc_pollset_kick_ext(grpc_pollset *p, + grpc_pollset_worker *specific_worker, + uint32_t flags); + +/* turn a pollset into a multipoller: platform specific */ +typedef void (*grpc_platform_become_multipoller_type)(grpc_exec_ctx *exec_ctx, + grpc_pollset *pollset, + struct grpc_fd **fds, + size_t fd_count); +extern grpc_platform_become_multipoller_type grpc_platform_become_multipoller; + +void grpc_poll_become_multipoller(grpc_exec_ctx *exec_ctx, + grpc_pollset *pollset, struct grpc_fd **fds, + size_t fd_count); + +/* Return 1 if the pollset has active threads in grpc_pollset_work (pollset must + * be locked) */ +int grpc_pollset_has_workers(grpc_pollset *pollset); + +void grpc_remove_fd_from_all_epoll_sets(int fd); + +/* override to allow tests to hook poll() usage */ +/* NOTE: Any changes to grpc_poll_function must take place when the gRPC + is certainly not doing any polling anywhere. + Otherwise, there might be a race between changing the variable and actually + doing a polling operation */ +typedef int (*grpc_poll_function_type)(struct pollfd *, nfds_t, int); +extern grpc_poll_function_type grpc_poll_function; +extern grpc_wakeup_fd grpc_global_wakeup_fd; + +#endif /* GRPC_CORE_IOMGR_POLLSET_POSIX_H */ diff --git a/src/core/lib/iomgr/pollset_set.h b/src/core/lib/iomgr/pollset_set.h new file mode 100644 index 0000000000..204c625933 --- /dev/null +++ b/src/core/lib/iomgr/pollset_set.h @@ -0,0 +1,61 @@ +/* + * + * Copyright 2015-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_IOMGR_POLLSET_SET_H +#define GRPC_CORE_IOMGR_POLLSET_SET_H + +#include "src/core/iomgr/pollset.h" + +/* A grpc_pollset_set is a set of pollsets that are interested in an + action. Adding a pollset to a pollset_set automatically adds any + fd's (etc) that have been registered with the set_set to that pollset. + Registering fd's automatically adds them to all current pollsets. */ + +typedef struct grpc_pollset_set grpc_pollset_set; + +grpc_pollset_set *grpc_pollset_set_create(void); +void grpc_pollset_set_destroy(grpc_pollset_set *pollset_set); +void grpc_pollset_set_add_pollset(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *pollset_set, + grpc_pollset *pollset); +void grpc_pollset_set_del_pollset(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *pollset_set, + grpc_pollset *pollset); +void grpc_pollset_set_add_pollset_set(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *bag, + grpc_pollset_set *item); +void grpc_pollset_set_del_pollset_set(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *bag, + grpc_pollset_set *item); + +#endif /* GRPC_CORE_IOMGR_POLLSET_SET_H */ diff --git a/src/core/lib/iomgr/pollset_set_posix.c b/src/core/lib/iomgr/pollset_set_posix.c new file mode 100644 index 0000000000..9dc9aff4a8 --- /dev/null +++ b/src/core/lib/iomgr/pollset_set_posix.c @@ -0,0 +1,202 @@ +/* + * + * Copyright 2015-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 + +#ifdef GPR_POSIX_SOCKET + +#include +#include + +#include +#include + +#include "src/core/iomgr/pollset_posix.h" +#include "src/core/iomgr/pollset_set_posix.h" + +struct grpc_pollset_set { + gpr_mu mu; + + size_t pollset_count; + size_t pollset_capacity; + grpc_pollset **pollsets; + + size_t pollset_set_count; + size_t pollset_set_capacity; + struct grpc_pollset_set **pollset_sets; + + size_t fd_count; + size_t fd_capacity; + grpc_fd **fds; +}; + +grpc_pollset_set *grpc_pollset_set_create(void) { + grpc_pollset_set *pollset_set = gpr_malloc(sizeof(*pollset_set)); + memset(pollset_set, 0, sizeof(*pollset_set)); + gpr_mu_init(&pollset_set->mu); + return pollset_set; +} + +void grpc_pollset_set_destroy(grpc_pollset_set *pollset_set) { + size_t i; + gpr_mu_destroy(&pollset_set->mu); + for (i = 0; i < pollset_set->fd_count; i++) { + GRPC_FD_UNREF(pollset_set->fds[i], "pollset_set"); + } + gpr_free(pollset_set->pollsets); + gpr_free(pollset_set->pollset_sets); + gpr_free(pollset_set->fds); + gpr_free(pollset_set); +} + +void grpc_pollset_set_add_pollset(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *pollset_set, + grpc_pollset *pollset) { + size_t i, j; + gpr_mu_lock(&pollset_set->mu); + if (pollset_set->pollset_count == pollset_set->pollset_capacity) { + pollset_set->pollset_capacity = + GPR_MAX(8, 2 * pollset_set->pollset_capacity); + pollset_set->pollsets = + gpr_realloc(pollset_set->pollsets, pollset_set->pollset_capacity * + sizeof(*pollset_set->pollsets)); + } + pollset_set->pollsets[pollset_set->pollset_count++] = pollset; + for (i = 0, j = 0; i < pollset_set->fd_count; i++) { + if (grpc_fd_is_orphaned(pollset_set->fds[i])) { + GRPC_FD_UNREF(pollset_set->fds[i], "pollset_set"); + } else { + grpc_pollset_add_fd(exec_ctx, pollset, pollset_set->fds[i]); + pollset_set->fds[j++] = pollset_set->fds[i]; + } + } + pollset_set->fd_count = j; + gpr_mu_unlock(&pollset_set->mu); +} + +void grpc_pollset_set_del_pollset(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *pollset_set, + grpc_pollset *pollset) { + size_t i; + gpr_mu_lock(&pollset_set->mu); + for (i = 0; i < pollset_set->pollset_count; i++) { + if (pollset_set->pollsets[i] == pollset) { + pollset_set->pollset_count--; + GPR_SWAP(grpc_pollset *, pollset_set->pollsets[i], + pollset_set->pollsets[pollset_set->pollset_count]); + break; + } + } + gpr_mu_unlock(&pollset_set->mu); +} + +void grpc_pollset_set_add_pollset_set(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *bag, + grpc_pollset_set *item) { + size_t i, j; + gpr_mu_lock(&bag->mu); + if (bag->pollset_set_count == bag->pollset_set_capacity) { + bag->pollset_set_capacity = GPR_MAX(8, 2 * bag->pollset_set_capacity); + bag->pollset_sets = + gpr_realloc(bag->pollset_sets, + bag->pollset_set_capacity * sizeof(*bag->pollset_sets)); + } + bag->pollset_sets[bag->pollset_set_count++] = item; + for (i = 0, j = 0; i < bag->fd_count; i++) { + if (grpc_fd_is_orphaned(bag->fds[i])) { + GRPC_FD_UNREF(bag->fds[i], "pollset_set"); + } else { + grpc_pollset_set_add_fd(exec_ctx, item, bag->fds[i]); + bag->fds[j++] = bag->fds[i]; + } + } + bag->fd_count = j; + gpr_mu_unlock(&bag->mu); +} + +void grpc_pollset_set_del_pollset_set(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *bag, + grpc_pollset_set *item) { + size_t i; + gpr_mu_lock(&bag->mu); + for (i = 0; i < bag->pollset_set_count; i++) { + if (bag->pollset_sets[i] == item) { + bag->pollset_set_count--; + GPR_SWAP(grpc_pollset_set *, bag->pollset_sets[i], + bag->pollset_sets[bag->pollset_set_count]); + break; + } + } + gpr_mu_unlock(&bag->mu); +} + +void grpc_pollset_set_add_fd(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *pollset_set, grpc_fd *fd) { + size_t i; + gpr_mu_lock(&pollset_set->mu); + if (pollset_set->fd_count == pollset_set->fd_capacity) { + pollset_set->fd_capacity = GPR_MAX(8, 2 * pollset_set->fd_capacity); + pollset_set->fds = gpr_realloc( + pollset_set->fds, pollset_set->fd_capacity * sizeof(*pollset_set->fds)); + } + GRPC_FD_REF(fd, "pollset_set"); + pollset_set->fds[pollset_set->fd_count++] = fd; + for (i = 0; i < pollset_set->pollset_count; i++) { + grpc_pollset_add_fd(exec_ctx, pollset_set->pollsets[i], fd); + } + for (i = 0; i < pollset_set->pollset_set_count; i++) { + grpc_pollset_set_add_fd(exec_ctx, pollset_set->pollset_sets[i], fd); + } + gpr_mu_unlock(&pollset_set->mu); +} + +void grpc_pollset_set_del_fd(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *pollset_set, grpc_fd *fd) { + size_t i; + gpr_mu_lock(&pollset_set->mu); + for (i = 0; i < pollset_set->fd_count; i++) { + if (pollset_set->fds[i] == fd) { + pollset_set->fd_count--; + GPR_SWAP(grpc_fd *, pollset_set->fds[i], + pollset_set->fds[pollset_set->fd_count]); + GRPC_FD_UNREF(fd, "pollset_set"); + break; + } + } + for (i = 0; i < pollset_set->pollset_set_count; i++) { + grpc_pollset_set_del_fd(exec_ctx, pollset_set->pollset_sets[i], fd); + } + gpr_mu_unlock(&pollset_set->mu); +} + +#endif /* GPR_POSIX_SOCKET */ diff --git a/src/core/lib/iomgr/pollset_set_posix.h b/src/core/lib/iomgr/pollset_set_posix.h new file mode 100644 index 0000000000..80f487718e --- /dev/null +++ b/src/core/lib/iomgr/pollset_set_posix.h @@ -0,0 +1,45 @@ +/* + * + * Copyright 2015-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_IOMGR_POLLSET_SET_POSIX_H +#define GRPC_CORE_IOMGR_POLLSET_SET_POSIX_H + +#include "src/core/iomgr/fd_posix.h" +#include "src/core/iomgr/pollset_set.h" + +void grpc_pollset_set_add_fd(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *pollset_set, grpc_fd *fd); +void grpc_pollset_set_del_fd(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *pollset_set, grpc_fd *fd); + +#endif /* GRPC_CORE_IOMGR_POLLSET_SET_POSIX_H */ diff --git a/src/core/lib/iomgr/pollset_set_windows.c b/src/core/lib/iomgr/pollset_set_windows.c new file mode 100644 index 0000000000..3b8eca28e6 --- /dev/null +++ b/src/core/lib/iomgr/pollset_set_windows.c @@ -0,0 +1,60 @@ +/* + * + * Copyright 2015-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 + +#ifdef GPR_WINSOCK_SOCKET + +#include "src/core/iomgr/pollset_set_windows.h" + +grpc_pollset_set* grpc_pollset_set_create(pollset_set) { return NULL; } + +void grpc_pollset_set_destroy(grpc_pollset_set* pollset_set) {} + +void grpc_pollset_set_add_pollset(grpc_exec_ctx* exec_ctx, + grpc_pollset_set* pollset_set, + grpc_pollset* pollset) {} + +void grpc_pollset_set_del_pollset(grpc_exec_ctx* exec_ctx, + grpc_pollset_set* pollset_set, + grpc_pollset* pollset) {} + +void grpc_pollset_set_add_pollset_set(grpc_exec_ctx* exec_ctx, + grpc_pollset_set* bag, + grpc_pollset_set* item) {} + +void grpc_pollset_set_del_pollset_set(grpc_exec_ctx* exec_ctx, + grpc_pollset_set* bag, + grpc_pollset_set* item) {} + +#endif /* GPR_WINSOCK_SOCKET */ diff --git a/src/core/lib/iomgr/pollset_set_windows.h b/src/core/lib/iomgr/pollset_set_windows.h new file mode 100644 index 0000000000..0f040fef82 --- /dev/null +++ b/src/core/lib/iomgr/pollset_set_windows.h @@ -0,0 +1,39 @@ +/* + * + * Copyright 2015-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_IOMGR_POLLSET_SET_WINDOWS_H +#define GRPC_CORE_IOMGR_POLLSET_SET_WINDOWS_H + +#include "src/core/iomgr/pollset_set.h" + +#endif /* GRPC_CORE_IOMGR_POLLSET_SET_WINDOWS_H */ diff --git a/src/core/lib/iomgr/pollset_windows.c b/src/core/lib/iomgr/pollset_windows.c new file mode 100644 index 0000000000..1a99224c80 --- /dev/null +++ b/src/core/lib/iomgr/pollset_windows.c @@ -0,0 +1,240 @@ +/* + * + * Copyright 2015-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 + +#ifdef GPR_WINSOCK_SOCKET + +#include +#include + +#include "src/core/iomgr/iocp_windows.h" +#include "src/core/iomgr/iomgr_internal.h" +#include "src/core/iomgr/pollset.h" +#include "src/core/iomgr/pollset_windows.h" + +gpr_mu grpc_polling_mu; +static grpc_pollset_worker *g_active_poller; +static grpc_pollset_worker g_global_root_worker; + +void grpc_pollset_global_init() { + gpr_mu_init(&grpc_polling_mu); + g_active_poller = NULL; + g_global_root_worker.links[GRPC_POLLSET_WORKER_LINK_GLOBAL].next = + g_global_root_worker.links[GRPC_POLLSET_WORKER_LINK_GLOBAL].prev = + &g_global_root_worker; +} + +void grpc_pollset_global_shutdown() { gpr_mu_destroy(&grpc_polling_mu); } + +static void remove_worker(grpc_pollset_worker *worker, + grpc_pollset_worker_link_type type) { + worker->links[type].prev->links[type].next = worker->links[type].next; + worker->links[type].next->links[type].prev = worker->links[type].prev; + worker->links[type].next = worker->links[type].prev = worker; +} + +static int has_workers(grpc_pollset_worker *root, + grpc_pollset_worker_link_type type) { + return root->links[type].next != root; +} + +static grpc_pollset_worker *pop_front_worker( + grpc_pollset_worker *root, grpc_pollset_worker_link_type type) { + if (has_workers(root, type)) { + grpc_pollset_worker *w = root->links[type].next; + remove_worker(w, type); + return w; + } else { + return NULL; + } +} + +static void push_front_worker(grpc_pollset_worker *root, + grpc_pollset_worker_link_type type, + grpc_pollset_worker *worker) { + worker->links[type].prev = root; + worker->links[type].next = worker->links[type].prev->links[type].next; + worker->links[type].prev->links[type].next = + worker->links[type].next->links[type].prev = worker; +} + +size_t grpc_pollset_size(void) { return sizeof(grpc_pollset); } + +/* There isn't really any such thing as a pollset under Windows, due to the + nature of the IO completion ports. We're still going to provide a minimal + set of features for the sake of the rest of grpc. But grpc_pollset_work + won't actually do any polling, and return as quickly as possible. */ + +void grpc_pollset_init(grpc_pollset *pollset, gpr_mu **mu) { + *mu = &grpc_polling_mu; + memset(pollset, 0, sizeof(*pollset)); + pollset->root_worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].next = + pollset->root_worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].prev = + &pollset->root_worker; +} + +void grpc_pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, + grpc_closure *closure) { + pollset->shutting_down = 1; + grpc_pollset_kick(pollset, GRPC_POLLSET_KICK_BROADCAST); + if (!pollset->is_iocp_worker) { + grpc_exec_ctx_enqueue(exec_ctx, closure, true, NULL); + } else { + pollset->on_shutdown = closure; + } +} + +void grpc_pollset_destroy(grpc_pollset *pollset) {} + +void grpc_pollset_reset(grpc_pollset *pollset) { + GPR_ASSERT(pollset->shutting_down); + GPR_ASSERT( + !has_workers(&pollset->root_worker, GRPC_POLLSET_WORKER_LINK_POLLSET)); + pollset->shutting_down = 0; + pollset->is_iocp_worker = 0; + pollset->kicked_without_pollers = 0; + pollset->on_shutdown = NULL; +} + +void grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, + grpc_pollset_worker **worker_hdl, gpr_timespec now, + gpr_timespec deadline) { + grpc_pollset_worker worker; + *worker_hdl = &worker; + + int added_worker = 0; + worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].next = + worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].prev = + worker.links[GRPC_POLLSET_WORKER_LINK_GLOBAL].next = + worker.links[GRPC_POLLSET_WORKER_LINK_GLOBAL].prev = NULL; + worker.kicked = 0; + worker.pollset = pollset; + gpr_cv_init(&worker.cv); + if (!pollset->kicked_without_pollers && !pollset->shutting_down) { + if (g_active_poller == NULL) { + grpc_pollset_worker *next_worker; + /* become poller */ + pollset->is_iocp_worker = 1; + g_active_poller = &worker; + gpr_mu_unlock(&grpc_polling_mu); + grpc_iocp_work(exec_ctx, deadline); + grpc_exec_ctx_flush(exec_ctx); + gpr_mu_lock(&grpc_polling_mu); + pollset->is_iocp_worker = 0; + g_active_poller = NULL; + /* try to get a worker from this pollsets worker list */ + next_worker = pop_front_worker(&pollset->root_worker, + GRPC_POLLSET_WORKER_LINK_POLLSET); + if (next_worker == NULL) { + /* try to get a worker from the global list */ + next_worker = pop_front_worker(&g_global_root_worker, + GRPC_POLLSET_WORKER_LINK_GLOBAL); + } + if (next_worker != NULL) { + next_worker->kicked = 1; + gpr_cv_signal(&next_worker->cv); + } + + if (pollset->shutting_down && pollset->on_shutdown != NULL) { + grpc_exec_ctx_enqueue(exec_ctx, pollset->on_shutdown, true, NULL); + pollset->on_shutdown = NULL; + } + goto done; + } + push_front_worker(&g_global_root_worker, GRPC_POLLSET_WORKER_LINK_GLOBAL, + &worker); + push_front_worker(&pollset->root_worker, GRPC_POLLSET_WORKER_LINK_POLLSET, + &worker); + added_worker = 1; + while (!worker.kicked) { + if (gpr_cv_wait(&worker.cv, &grpc_polling_mu, deadline)) { + break; + } + } + } else { + pollset->kicked_without_pollers = 0; + } +done: + if (!grpc_closure_list_empty(exec_ctx->closure_list)) { + gpr_mu_unlock(&grpc_polling_mu); + grpc_exec_ctx_flush(exec_ctx); + gpr_mu_lock(&grpc_polling_mu); + } + if (added_worker) { + remove_worker(&worker, GRPC_POLLSET_WORKER_LINK_GLOBAL); + remove_worker(&worker, GRPC_POLLSET_WORKER_LINK_POLLSET); + } + gpr_cv_destroy(&worker.cv); + *worker_hdl = NULL; +} + +void grpc_pollset_kick(grpc_pollset *p, grpc_pollset_worker *specific_worker) { + if (specific_worker != NULL) { + if (specific_worker == GRPC_POLLSET_KICK_BROADCAST) { + for (specific_worker = + p->root_worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].next; + specific_worker != &p->root_worker; + specific_worker = + specific_worker->links[GRPC_POLLSET_WORKER_LINK_POLLSET].next) { + specific_worker->kicked = 1; + gpr_cv_signal(&specific_worker->cv); + } + p->kicked_without_pollers = 1; + if (p->is_iocp_worker) { + grpc_iocp_kick(); + } + } else { + if (p->is_iocp_worker && g_active_poller == specific_worker) { + grpc_iocp_kick(); + } else { + specific_worker->kicked = 1; + gpr_cv_signal(&specific_worker->cv); + } + } + } else { + specific_worker = + pop_front_worker(&p->root_worker, GRPC_POLLSET_WORKER_LINK_POLLSET); + if (specific_worker != NULL) { + grpc_pollset_kick(p, specific_worker); + } else if (p->is_iocp_worker) { + grpc_iocp_kick(); + } else { + p->kicked_without_pollers = 1; + } + } +} + +void grpc_kick_poller(void) { grpc_iocp_kick(); } + +#endif /* GPR_WINSOCK_SOCKET */ diff --git a/src/core/lib/iomgr/pollset_windows.h b/src/core/lib/iomgr/pollset_windows.h new file mode 100644 index 0000000000..f1d1585922 --- /dev/null +++ b/src/core/lib/iomgr/pollset_windows.h @@ -0,0 +1,75 @@ +/* + * + * Copyright 2015-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_IOMGR_POLLSET_WINDOWS_H +#define GRPC_CORE_IOMGR_POLLSET_WINDOWS_H + +#include + +#include "src/core/iomgr/socket_windows.h" + +/* There isn't really any such thing as a pollset under Windows, due to the + nature of the IO completion ports. A Windows "pollset" is merely a mutex + used to synchronize with the IOCP, and workers are condition variables + used to block threads until work is ready. */ + +typedef enum { + GRPC_POLLSET_WORKER_LINK_POLLSET = 0, + GRPC_POLLSET_WORKER_LINK_GLOBAL, + GRPC_POLLSET_WORKER_LINK_TYPES +} grpc_pollset_worker_link_type; + +typedef struct grpc_pollset_worker_link { + struct grpc_pollset_worker *next; + struct grpc_pollset_worker *prev; +} grpc_pollset_worker_link; + +struct grpc_pollset; +typedef struct grpc_pollset grpc_pollset; + +typedef struct grpc_pollset_worker { + gpr_cv cv; + int kicked; + struct grpc_pollset *pollset; + grpc_pollset_worker_link links[GRPC_POLLSET_WORKER_LINK_TYPES]; +} grpc_pollset_worker; + +struct grpc_pollset { + int shutting_down; + int kicked_without_pollers; + int is_iocp_worker; + grpc_pollset_worker root_worker; + grpc_closure *on_shutdown; +}; + +#endif /* GRPC_CORE_IOMGR_POLLSET_WINDOWS_H */ diff --git a/src/core/lib/iomgr/resolve_address.h b/src/core/lib/iomgr/resolve_address.h new file mode 100644 index 0000000000..aa0d7d194b --- /dev/null +++ b/src/core/lib/iomgr/resolve_address.h @@ -0,0 +1,72 @@ +/* + * + * Copyright 2015-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_IOMGR_RESOLVE_ADDRESS_H +#define GRPC_CORE_IOMGR_RESOLVE_ADDRESS_H + +#include +#include "src/core/iomgr/exec_ctx.h" +#include "src/core/iomgr/iomgr.h" + +#define GRPC_MAX_SOCKADDR_SIZE 128 + +typedef struct { + char addr[GRPC_MAX_SOCKADDR_SIZE]; + size_t len; +} grpc_resolved_address; + +typedef struct { + size_t naddrs; + grpc_resolved_address *addrs; +} grpc_resolved_addresses; + +/* Async result callback: + On success: addresses is the result, and the callee must call + grpc_resolved_addresses_destroy when it's done with them + On failure: addresses is NULL */ +typedef void (*grpc_resolve_cb)(grpc_exec_ctx *exec_ctx, void *arg, + grpc_resolved_addresses *addresses); +/* Asynchronously resolve addr. Use default_port if a port isn't designated + in addr, otherwise use the port in addr. */ +/* TODO(ctiller): add a timeout here */ +void grpc_resolve_address(const char *addr, const char *default_port, + grpc_resolve_cb cb, void *arg); +/* Destroy resolved addresses */ +void grpc_resolved_addresses_destroy(grpc_resolved_addresses *addresses); + +/* Resolve addr in a blocking fashion. Returns NULL on failure. On success, + result must be freed with grpc_resolved_addresses_destroy. */ +extern grpc_resolved_addresses *(*grpc_blocking_resolve_address)( + const char *name, const char *default_port); + +#endif /* GRPC_CORE_IOMGR_RESOLVE_ADDRESS_H */ diff --git a/src/core/lib/iomgr/resolve_address_posix.c b/src/core/lib/iomgr/resolve_address_posix.c new file mode 100644 index 0000000000..26b3aa8189 --- /dev/null +++ b/src/core/lib/iomgr/resolve_address_posix.c @@ -0,0 +1,178 @@ +/* + * + * Copyright 2015-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 +#ifdef GPR_POSIX_SOCKET + +#include "src/core/iomgr/resolve_address.h" +#include "src/core/iomgr/sockaddr.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "src/core/iomgr/executor.h" +#include "src/core/iomgr/iomgr_internal.h" +#include "src/core/iomgr/sockaddr_utils.h" +#include "src/core/iomgr/unix_sockets_posix.h" +#include "src/core/support/block_annotate.h" +#include "src/core/support/string.h" + +typedef struct { + char *name; + char *default_port; + grpc_resolve_cb cb; + grpc_closure request_closure; + void *arg; +} request; + +static grpc_resolved_addresses *blocking_resolve_address_impl( + const char *name, const char *default_port) { + struct addrinfo hints; + struct addrinfo *result = NULL, *resp; + char *host; + char *port; + int s; + size_t i; + grpc_resolved_addresses *addrs = NULL; + + if (name[0] == 'u' && name[1] == 'n' && name[2] == 'i' && name[3] == 'x' && + name[4] == ':' && name[5] != 0) { + return grpc_resolve_unix_domain_address(name + 5); + } + + /* parse name, splitting it into host and port parts */ + gpr_split_host_port(name, &host, &port); + if (host == NULL) { + gpr_log(GPR_ERROR, "unparseable host:port: '%s'", name); + goto done; + } + if (port == NULL) { + if (default_port == NULL) { + gpr_log(GPR_ERROR, "no port in name '%s'", name); + goto done; + } + port = gpr_strdup(default_port); + } + + /* Call getaddrinfo */ + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; /* ipv4 or ipv6 */ + hints.ai_socktype = SOCK_STREAM; /* stream socket */ + hints.ai_flags = AI_PASSIVE; /* for wildcard IP address */ + + GRPC_SCHEDULING_START_BLOCKING_REGION; + s = getaddrinfo(host, port, &hints, &result); + GRPC_SCHEDULING_END_BLOCKING_REGION; + + if (s != 0) { + /* Retry if well-known service name is recognized */ + char *svc[][2] = {{"http", "80"}, {"https", "443"}}; + for (i = 0; i < GPR_ARRAY_SIZE(svc); i++) { + if (strcmp(port, svc[i][0]) == 0) { + GRPC_SCHEDULING_START_BLOCKING_REGION; + s = getaddrinfo(host, svc[i][1], &hints, &result); + GRPC_SCHEDULING_END_BLOCKING_REGION; + break; + } + } + } + + if (s != 0) { + gpr_log(GPR_ERROR, "getaddrinfo: %s", gai_strerror(s)); + goto done; + } + + /* Success path: set addrs non-NULL, fill it in */ + addrs = gpr_malloc(sizeof(grpc_resolved_addresses)); + addrs->naddrs = 0; + for (resp = result; resp != NULL; resp = resp->ai_next) { + addrs->naddrs++; + } + addrs->addrs = gpr_malloc(sizeof(grpc_resolved_address) * addrs->naddrs); + i = 0; + for (resp = result; resp != NULL; resp = resp->ai_next) { + memcpy(&addrs->addrs[i].addr, resp->ai_addr, resp->ai_addrlen); + addrs->addrs[i].len = resp->ai_addrlen; + i++; + } + +done: + gpr_free(host); + gpr_free(port); + if (result) { + freeaddrinfo(result); + } + return addrs; +} + +grpc_resolved_addresses *(*grpc_blocking_resolve_address)( + const char *name, const char *default_port) = blocking_resolve_address_impl; + +/* Callback to be passed to grpc_executor to asynch-ify + * grpc_blocking_resolve_address */ +static void do_request_thread(grpc_exec_ctx *exec_ctx, void *rp, bool success) { + request *r = rp; + grpc_resolved_addresses *resolved = + grpc_blocking_resolve_address(r->name, r->default_port); + void *arg = r->arg; + grpc_resolve_cb cb = r->cb; + gpr_free(r->name); + gpr_free(r->default_port); + cb(exec_ctx, arg, resolved); + gpr_free(r); +} + +void grpc_resolved_addresses_destroy(grpc_resolved_addresses *addrs) { + gpr_free(addrs->addrs); + gpr_free(addrs); +} + +void grpc_resolve_address(const char *name, const char *default_port, + grpc_resolve_cb cb, void *arg) { + request *r = gpr_malloc(sizeof(request)); + grpc_closure_init(&r->request_closure, do_request_thread, r); + r->name = gpr_strdup(name); + r->default_port = gpr_strdup(default_port); + r->cb = cb; + r->arg = arg; + grpc_executor_enqueue(&r->request_closure, 1); +} + +#endif diff --git a/src/core/lib/iomgr/resolve_address_windows.c b/src/core/lib/iomgr/resolve_address_windows.c new file mode 100644 index 0000000000..472e797163 --- /dev/null +++ b/src/core/lib/iomgr/resolve_address_windows.c @@ -0,0 +1,169 @@ +/* + * + * Copyright 2015-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 +#ifdef GPR_WINSOCK_SOCKET + +#include "src/core/iomgr/resolve_address.h" +#include "src/core/iomgr/sockaddr.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "src/core/iomgr/executor.h" +#include "src/core/iomgr/iomgr_internal.h" +#include "src/core/iomgr/sockaddr_utils.h" +#include "src/core/support/block_annotate.h" +#include "src/core/support/string.h" + +typedef struct { + char *name; + char *default_port; + grpc_resolve_cb cb; + grpc_closure request_closure; + void *arg; +} request; + +static grpc_resolved_addresses *blocking_resolve_address_impl( + const char *name, const char *default_port) { + struct addrinfo hints; + struct addrinfo *result = NULL, *resp; + char *host; + char *port; + int s; + size_t i; + grpc_resolved_addresses *addrs = NULL; + + /* parse name, splitting it into host and port parts */ + gpr_split_host_port(name, &host, &port); + if (host == NULL) { + gpr_log(GPR_ERROR, "unparseable host:port: '%s'", name); + goto done; + } + if (port == NULL) { + if (default_port == NULL) { + gpr_log(GPR_ERROR, "no port in name '%s'", name); + goto done; + } + port = gpr_strdup(default_port); + } + + /* Call getaddrinfo */ + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; /* ipv4 or ipv6 */ + hints.ai_socktype = SOCK_STREAM; /* stream socket */ + hints.ai_flags = AI_PASSIVE; /* for wildcard IP address */ + + GRPC_SCHEDULING_START_BLOCKING_REGION; + s = getaddrinfo(host, port, &hints, &result); + GRPC_SCHEDULING_END_BLOCKING_REGION; + if (s != 0) { + char *error_message = gpr_format_message(s); + gpr_log(GPR_ERROR, "getaddrinfo: %s", error_message); + gpr_free(error_message); + goto done; + } + + /* Success path: set addrs non-NULL, fill it in */ + addrs = gpr_malloc(sizeof(grpc_resolved_addresses)); + addrs->naddrs = 0; + for (resp = result; resp != NULL; resp = resp->ai_next) { + addrs->naddrs++; + } + addrs->addrs = gpr_malloc(sizeof(grpc_resolved_address) * addrs->naddrs); + i = 0; + for (resp = result; resp != NULL; resp = resp->ai_next) { + memcpy(&addrs->addrs[i].addr, resp->ai_addr, resp->ai_addrlen); + addrs->addrs[i].len = resp->ai_addrlen; + i++; + } + + { + for (i = 0; i < addrs->naddrs; i++) { + char *buf; + grpc_sockaddr_to_string(&buf, (struct sockaddr *)&addrs->addrs[i].addr, + 0); + gpr_free(buf); + } + } + +done: + gpr_free(host); + gpr_free(port); + if (result) { + freeaddrinfo(result); + } + return addrs; +} + +grpc_resolved_addresses *(*grpc_blocking_resolve_address)( + const char *name, const char *default_port) = blocking_resolve_address_impl; + +/* Callback to be passed to grpc_executor to asynch-ify + * grpc_blocking_resolve_address */ +static void do_request_thread(grpc_exec_ctx *exec_ctx, void *rp, bool success) { + request *r = rp; + grpc_resolved_addresses *resolved = + grpc_blocking_resolve_address(r->name, r->default_port); + void *arg = r->arg; + grpc_resolve_cb cb = r->cb; + gpr_free(r->name); + gpr_free(r->default_port); + cb(exec_ctx, arg, resolved); + gpr_free(r); +} + +void grpc_resolved_addresses_destroy(grpc_resolved_addresses *addrs) { + gpr_free(addrs->addrs); + gpr_free(addrs); +} + +void grpc_resolve_address(const char *name, const char *default_port, + grpc_resolve_cb cb, void *arg) { + request *r = gpr_malloc(sizeof(request)); + grpc_closure_init(&r->request_closure, do_request_thread, r); + r->name = gpr_strdup(name); + r->default_port = gpr_strdup(default_port); + r->cb = cb; + r->arg = arg; + grpc_executor_enqueue(&r->request_closure, 1); +} + +#endif diff --git a/src/core/lib/iomgr/sockaddr.h b/src/core/lib/iomgr/sockaddr.h new file mode 100644 index 0000000000..68241bdd55 --- /dev/null +++ b/src/core/lib/iomgr/sockaddr.h @@ -0,0 +1,47 @@ +/* + * + * Copyright 2015-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_IOMGR_SOCKADDR_H +#define GRPC_CORE_IOMGR_SOCKADDR_H + +#include + +#ifdef GPR_WIN32 +#include "src/core/iomgr/sockaddr_win32.h" +#endif + +#ifdef GPR_POSIX_SOCKETADDR +#include "src/core/iomgr/sockaddr_posix.h" +#endif + +#endif /* GRPC_CORE_IOMGR_SOCKADDR_H */ diff --git a/src/core/lib/iomgr/sockaddr_posix.h b/src/core/lib/iomgr/sockaddr_posix.h new file mode 100644 index 0000000000..a398096837 --- /dev/null +++ b/src/core/lib/iomgr/sockaddr_posix.h @@ -0,0 +1,44 @@ +/* + * + * Copyright 2015-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_IOMGR_SOCKADDR_POSIX_H +#define GRPC_CORE_IOMGR_SOCKADDR_POSIX_H + +#include +#include +#include +#include +#include +#include + +#endif /* GRPC_CORE_IOMGR_SOCKADDR_POSIX_H */ diff --git a/src/core/lib/iomgr/sockaddr_utils.c b/src/core/lib/iomgr/sockaddr_utils.c new file mode 100644 index 0000000000..a3c3a874c1 --- /dev/null +++ b/src/core/lib/iomgr/sockaddr_utils.c @@ -0,0 +1,227 @@ +/* + * + * 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/iomgr/sockaddr_utils.h" + +#include +#include + +#include +#include +#include +#include +#include + +#include "src/core/iomgr/unix_sockets_posix.h" +#include "src/core/support/string.h" + +static const uint8_t kV4MappedPrefix[] = {0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0xff, 0xff}; + +int grpc_sockaddr_is_v4mapped(const struct sockaddr *addr, + struct sockaddr_in *addr4_out) { + GPR_ASSERT(addr != (struct sockaddr *)addr4_out); + if (addr->sa_family == AF_INET6) { + const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr; + if (memcmp(addr6->sin6_addr.s6_addr, kV4MappedPrefix, + sizeof(kV4MappedPrefix)) == 0) { + if (addr4_out != NULL) { + /* Normalize ::ffff:0.0.0.0/96 to IPv4. */ + memset(addr4_out, 0, sizeof(*addr4_out)); + addr4_out->sin_family = AF_INET; + /* s6_addr32 would be nice, but it's non-standard. */ + memcpy(&addr4_out->sin_addr, &addr6->sin6_addr.s6_addr[12], 4); + addr4_out->sin_port = addr6->sin6_port; + } + return 1; + } + } + return 0; +} + +int grpc_sockaddr_to_v4mapped(const struct sockaddr *addr, + struct sockaddr_in6 *addr6_out) { + GPR_ASSERT(addr != (struct sockaddr *)addr6_out); + if (addr->sa_family == AF_INET) { + const struct sockaddr_in *addr4 = (const struct sockaddr_in *)addr; + memset(addr6_out, 0, sizeof(*addr6_out)); + addr6_out->sin6_family = AF_INET6; + memcpy(&addr6_out->sin6_addr.s6_addr[0], kV4MappedPrefix, 12); + memcpy(&addr6_out->sin6_addr.s6_addr[12], &addr4->sin_addr, 4); + addr6_out->sin6_port = addr4->sin_port; + return 1; + } + return 0; +} + +int grpc_sockaddr_is_wildcard(const struct sockaddr *addr, int *port_out) { + struct sockaddr_in addr4_normalized; + if (grpc_sockaddr_is_v4mapped(addr, &addr4_normalized)) { + addr = (struct sockaddr *)&addr4_normalized; + } + if (addr->sa_family == AF_INET) { + /* Check for 0.0.0.0 */ + const struct sockaddr_in *addr4 = (const struct sockaddr_in *)addr; + if (addr4->sin_addr.s_addr != 0) { + return 0; + } + *port_out = ntohs(addr4->sin_port); + return 1; + } else if (addr->sa_family == AF_INET6) { + /* Check for :: */ + const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr; + int i; + for (i = 0; i < 16; i++) { + if (addr6->sin6_addr.s6_addr[i] != 0) { + return 0; + } + } + *port_out = ntohs(addr6->sin6_port); + return 1; + } else { + return 0; + } +} + +void grpc_sockaddr_make_wildcards(int port, struct sockaddr_in *wild4_out, + struct sockaddr_in6 *wild6_out) { + grpc_sockaddr_make_wildcard4(port, wild4_out); + grpc_sockaddr_make_wildcard6(port, wild6_out); +} + +void grpc_sockaddr_make_wildcard4(int port, struct sockaddr_in *wild_out) { + GPR_ASSERT(port >= 0 && port < 65536); + memset(wild_out, 0, sizeof(*wild_out)); + wild_out->sin_family = AF_INET; + wild_out->sin_port = htons((uint16_t)port); +} + +void grpc_sockaddr_make_wildcard6(int port, struct sockaddr_in6 *wild_out) { + GPR_ASSERT(port >= 0 && port < 65536); + memset(wild_out, 0, sizeof(*wild_out)); + wild_out->sin6_family = AF_INET6; + wild_out->sin6_port = htons((uint16_t)port); +} + +int grpc_sockaddr_to_string(char **out, const struct sockaddr *addr, + int normalize) { + const int save_errno = errno; + struct sockaddr_in addr_normalized; + char ntop_buf[INET6_ADDRSTRLEN]; + const void *ip = NULL; + int port; + int ret; + + *out = NULL; + if (normalize && grpc_sockaddr_is_v4mapped(addr, &addr_normalized)) { + addr = (const struct sockaddr *)&addr_normalized; + } + if (addr->sa_family == AF_INET) { + const struct sockaddr_in *addr4 = (const struct sockaddr_in *)addr; + ip = &addr4->sin_addr; + port = ntohs(addr4->sin_port); + } else if (addr->sa_family == AF_INET6) { + const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr; + ip = &addr6->sin6_addr; + port = ntohs(addr6->sin6_port); + } + /* Windows inet_ntop wants a mutable ip pointer */ + if (ip != NULL && + inet_ntop(addr->sa_family, (void *)ip, ntop_buf, sizeof(ntop_buf)) != + NULL) { + ret = gpr_join_host_port(out, ntop_buf, port); + } else { + ret = gpr_asprintf(out, "(sockaddr family=%d)", addr->sa_family); + } + /* This is probably redundant, but we wouldn't want to log the wrong error. */ + errno = save_errno; + return ret; +} + +char *grpc_sockaddr_to_uri(const struct sockaddr *addr) { + char *temp; + char *result; + struct sockaddr_in addr_normalized; + + if (grpc_sockaddr_is_v4mapped(addr, &addr_normalized)) { + addr = (const struct sockaddr *)&addr_normalized; + } + + switch (addr->sa_family) { + case AF_INET: + grpc_sockaddr_to_string(&temp, addr, 0); + gpr_asprintf(&result, "ipv4:%s", temp); + gpr_free(temp); + return result; + case AF_INET6: + grpc_sockaddr_to_string(&temp, addr, 0); + gpr_asprintf(&result, "ipv6:%s", temp); + gpr_free(temp); + return result; + default: + return grpc_sockaddr_to_uri_unix_if_possible(addr); + } +} + +int grpc_sockaddr_get_port(const struct sockaddr *addr) { + switch (addr->sa_family) { + case AF_INET: + return ntohs(((struct sockaddr_in *)addr)->sin_port); + case AF_INET6: + return ntohs(((struct sockaddr_in6 *)addr)->sin6_port); + default: + if (grpc_is_unix_socket(addr)) { + return 1; + } + gpr_log(GPR_ERROR, "Unknown socket family %d in grpc_sockaddr_get_port", + addr->sa_family); + return 0; + } +} + +int grpc_sockaddr_set_port(const struct sockaddr *addr, int port) { + switch (addr->sa_family) { + case AF_INET: + GPR_ASSERT(port >= 0 && port < 65536); + ((struct sockaddr_in *)addr)->sin_port = htons((uint16_t)port); + return 1; + case AF_INET6: + GPR_ASSERT(port >= 0 && port < 65536); + ((struct sockaddr_in6 *)addr)->sin6_port = htons((uint16_t)port); + return 1; + default: + gpr_log(GPR_ERROR, "Unknown socket family %d in grpc_sockaddr_set_port", + addr->sa_family); + return 0; + } +} diff --git a/src/core/lib/iomgr/sockaddr_utils.h b/src/core/lib/iomgr/sockaddr_utils.h new file mode 100644 index 0000000000..43dc7a45ec --- /dev/null +++ b/src/core/lib/iomgr/sockaddr_utils.h @@ -0,0 +1,89 @@ +/* + * + * Copyright 2015-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_IOMGR_SOCKADDR_UTILS_H +#define GRPC_CORE_IOMGR_SOCKADDR_UTILS_H + +#include "src/core/iomgr/sockaddr.h" + +/* Returns true if addr is an IPv4-mapped IPv6 address within the + ::ffff:0.0.0.0/96 range, or false otherwise. + + If addr4_out is non-NULL, the inner IPv4 address will be copied here when + returning true. */ +int grpc_sockaddr_is_v4mapped(const struct sockaddr *addr, + struct sockaddr_in *addr4_out); + +/* If addr is an AF_INET address, writes the corresponding ::ffff:0.0.0.0/96 + address to addr6_out and returns true. Otherwise returns false. */ +int grpc_sockaddr_to_v4mapped(const struct sockaddr *addr, + struct sockaddr_in6 *addr6_out); + +/* If addr is ::, 0.0.0.0, or ::ffff:0.0.0.0, writes the port number to + *port_out (if not NULL) and returns true, otherwise returns false. */ +int grpc_sockaddr_is_wildcard(const struct sockaddr *addr, int *port_out); + +/* Writes 0.0.0.0:port and [::]:port to separate sockaddrs. */ +void grpc_sockaddr_make_wildcards(int port, struct sockaddr_in *wild4_out, + struct sockaddr_in6 *wild6_out); + +/* Writes 0.0.0.0:port. */ +void grpc_sockaddr_make_wildcard4(int port, struct sockaddr_in *wild_out); + +/* Writes [::]:port. */ +void grpc_sockaddr_make_wildcard6(int port, struct sockaddr_in6 *wild_out); + +/* Return the IP port number of a sockaddr */ +int grpc_sockaddr_get_port(const struct sockaddr *addr); + +/* Set IP port number of a sockaddr */ +int grpc_sockaddr_set_port(const struct sockaddr *addr, int port); + +/* Converts a sockaddr into a newly-allocated human-readable string. + + Currently, only the AF_INET and AF_INET6 families are recognized. + If the normalize flag is enabled, ::ffff:0.0.0.0/96 IPv6 addresses are + displayed as plain IPv4. + + Usage is similar to gpr_asprintf: returns the number of bytes written + (excluding the final '\0'), and *out points to a string which must later be + destroyed using gpr_free(). + + In the unlikely event of an error, returns -1 and sets *out to NULL. + The existing value of errno is always preserved. */ +int grpc_sockaddr_to_string(char **out, const struct sockaddr *addr, + int normalize); + +char *grpc_sockaddr_to_uri(const struct sockaddr *addr); + +#endif /* GRPC_CORE_IOMGR_SOCKADDR_UTILS_H */ diff --git a/src/core/lib/iomgr/sockaddr_win32.h b/src/core/lib/iomgr/sockaddr_win32.h new file mode 100644 index 0000000000..ef306e3cc3 --- /dev/null +++ b/src/core/lib/iomgr/sockaddr_win32.h @@ -0,0 +1,43 @@ +/* + * + * Copyright 2015-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_IOMGR_SOCKADDR_WIN32_H +#define GRPC_CORE_IOMGR_SOCKADDR_WIN32_H + +#include +#include + +// must be included after the above +#include + +#endif /* GRPC_CORE_IOMGR_SOCKADDR_WIN32_H */ diff --git a/src/core/lib/iomgr/socket_utils_common_posix.c b/src/core/lib/iomgr/socket_utils_common_posix.c new file mode 100644 index 0000000000..570daccc9e --- /dev/null +++ b/src/core/lib/iomgr/socket_utils_common_posix.c @@ -0,0 +1,208 @@ +/* + * + * Copyright 2015-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 + +#ifdef GPR_POSIX_SOCKET + +#include "src/core/iomgr/socket_utils_posix.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "src/core/iomgr/sockaddr_utils.h" +#include "src/core/support/string.h" + +/* set a socket to non blocking mode */ +int grpc_set_socket_nonblocking(int fd, int non_blocking) { + int oldflags = fcntl(fd, F_GETFL, 0); + if (oldflags < 0) { + return 0; + } + + if (non_blocking) { + oldflags |= O_NONBLOCK; + } else { + oldflags &= ~O_NONBLOCK; + } + + if (fcntl(fd, F_SETFL, oldflags) != 0) { + return 0; + } + + return 1; +} + +int grpc_set_socket_no_sigpipe_if_possible(int fd) { +#ifdef GPR_HAVE_SO_NOSIGPIPE + int val = 1; + int newval; + socklen_t intlen = sizeof(newval); + return 0 == setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(val)) && + 0 == getsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &newval, &intlen) && + (newval != 0) == val; +#else + return 1; +#endif +} + +/* set a socket to close on exec */ +int grpc_set_socket_cloexec(int fd, int close_on_exec) { + int oldflags = fcntl(fd, F_GETFD, 0); + if (oldflags < 0) { + return 0; + } + + if (close_on_exec) { + oldflags |= FD_CLOEXEC; + } else { + oldflags &= ~FD_CLOEXEC; + } + + if (fcntl(fd, F_SETFD, oldflags) != 0) { + return 0; + } + + return 1; +} + +/* set a socket to reuse old addresses */ +int grpc_set_socket_reuse_addr(int fd, int reuse) { + int val = (reuse != 0); + int newval; + socklen_t intlen = sizeof(newval); + return 0 == setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) && + 0 == getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &newval, &intlen) && + (newval != 0) == val; +} + +/* disable nagle */ +int grpc_set_socket_low_latency(int fd, int low_latency) { + int val = (low_latency != 0); + int newval; + socklen_t intlen = sizeof(newval); + return 0 == setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) && + 0 == getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &newval, &intlen) && + (newval != 0) == val; +} + +static gpr_once g_probe_ipv6_once = GPR_ONCE_INIT; +static int g_ipv6_loopback_available; + +static void probe_ipv6_once(void) { + int fd = socket(AF_INET6, SOCK_STREAM, 0); + g_ipv6_loopback_available = 0; + if (fd < 0) { + gpr_log(GPR_INFO, "Disabling AF_INET6 sockets because socket() failed."); + } else { + struct sockaddr_in6 addr; + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + addr.sin6_addr.s6_addr[15] = 1; /* [::1]:0 */ + if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == 0) { + g_ipv6_loopback_available = 1; + } else { + gpr_log(GPR_INFO, + "Disabling AF_INET6 sockets because ::1 is not available."); + } + close(fd); + } +} + +int grpc_ipv6_loopback_available(void) { + gpr_once_init(&g_probe_ipv6_once, probe_ipv6_once); + return g_ipv6_loopback_available; +} + +/* This should be 0 in production, but it may be enabled for testing or + debugging purposes, to simulate an environment where IPv6 sockets can't + also speak IPv4. */ +int grpc_forbid_dualstack_sockets_for_testing = 0; + +static int set_socket_dualstack(int fd) { + if (!grpc_forbid_dualstack_sockets_for_testing) { + const int off = 0; + return 0 == setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &off, sizeof(off)); + } else { + /* Force an IPv6-only socket, for testing purposes. */ + const int on = 1; + setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)); + return 0; + } +} + +int grpc_create_dualstack_socket(const struct sockaddr *addr, int type, + int protocol, grpc_dualstack_mode *dsmode) { + int family = addr->sa_family; + if (family == AF_INET6) { + int fd; + if (grpc_ipv6_loopback_available()) { + fd = socket(family, type, protocol); + } else { + fd = -1; + errno = EAFNOSUPPORT; + } + /* Check if we've got a valid dualstack socket. */ + if (fd >= 0 && set_socket_dualstack(fd)) { + *dsmode = GRPC_DSMODE_DUALSTACK; + return fd; + } + /* If this isn't an IPv4 address, then return whatever we've got. */ + if (!grpc_sockaddr_is_v4mapped(addr, NULL)) { + *dsmode = GRPC_DSMODE_IPV6; + return fd; + } + /* Fall back to AF_INET. */ + if (fd >= 0) { + close(fd); + } + family = AF_INET; + } + *dsmode = family == AF_INET ? GRPC_DSMODE_IPV4 : GRPC_DSMODE_NONE; + return socket(family, type, protocol); +} + +#endif diff --git a/src/core/lib/iomgr/socket_utils_linux.c b/src/core/lib/iomgr/socket_utils_linux.c new file mode 100644 index 0000000000..e16885f231 --- /dev/null +++ b/src/core/lib/iomgr/socket_utils_linux.c @@ -0,0 +1,51 @@ +/* + * + * Copyright 2015-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 + +#ifdef GPR_LINUX_SOCKETUTILS + +#include "src/core/iomgr/socket_utils_posix.h" + +#include +#include + +int grpc_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, + int nonblock, int cloexec) { + int flags = 0; + flags |= nonblock ? SOCK_NONBLOCK : 0; + flags |= cloexec ? SOCK_CLOEXEC : 0; + return accept4(sockfd, addr, addrlen, flags); +} + +#endif diff --git a/src/core/lib/iomgr/socket_utils_posix.c b/src/core/lib/iomgr/socket_utils_posix.c new file mode 100644 index 0000000000..3c56b46744 --- /dev/null +++ b/src/core/lib/iomgr/socket_utils_posix.c @@ -0,0 +1,70 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +#ifdef GPR_POSIX_SOCKETUTILS + +#include "src/core/iomgr/socket_utils_posix.h" + +#include +#include +#include + +#include + +int grpc_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, + int nonblock, int cloexec) { + int fd, flags; + + fd = accept(sockfd, addr, addrlen); + if (fd >= 0) { + if (nonblock) { + flags = fcntl(fd, F_GETFL, 0); + if (flags < 0) goto close_and_error; + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) goto close_and_error; + } + if (cloexec) { + flags = fcntl(fd, F_GETFD, 0); + if (flags < 0) goto close_and_error; + if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) != 0) goto close_and_error; + } + } + return fd; + +close_and_error: + close(fd); + return -1; +} + +#endif /* GPR_POSIX_SOCKETUTILS */ diff --git a/src/core/lib/iomgr/socket_utils_posix.h b/src/core/lib/iomgr/socket_utils_posix.h new file mode 100644 index 0000000000..3908550380 --- /dev/null +++ b/src/core/lib/iomgr/socket_utils_posix.h @@ -0,0 +1,113 @@ +/* + * + * Copyright 2015-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_IOMGR_SOCKET_UTILS_POSIX_H +#define GRPC_CORE_IOMGR_SOCKET_UTILS_POSIX_H + +#include +#include + +/* a wrapper for accept or accept4 */ +int grpc_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, + int nonblock, int cloexec); + +/* set a socket to non blocking mode */ +int grpc_set_socket_nonblocking(int fd, int non_blocking); + +/* set a socket to close on exec */ +int grpc_set_socket_cloexec(int fd, int close_on_exec); + +/* set a socket to reuse old addresses */ +int grpc_set_socket_reuse_addr(int fd, int reuse); + +/* disable nagle */ +int grpc_set_socket_low_latency(int fd, int low_latency); + +/* Returns true if this system can create AF_INET6 sockets bound to ::1. + The value is probed once, and cached for the life of the process. + + This is more restrictive than checking for socket(AF_INET6) to succeed, + because Linux with "net.ipv6.conf.all.disable_ipv6 = 1" is able to create + and bind IPv6 sockets, but cannot connect to a getsockname() of [::]:port + without a valid loopback interface. Rather than expose this half-broken + state to library users, we turn off IPv6 sockets. */ +int grpc_ipv6_loopback_available(void); + +/* Tries to set SO_NOSIGPIPE if available on this platform. + Returns 1 on success, 0 on failure. + If SO_NO_SIGPIPE is not available, returns 1. */ +int grpc_set_socket_no_sigpipe_if_possible(int fd); + +/* An enum to keep track of IPv4/IPv6 socket modes. + + Currently, this information is only used when a socket is first created, but + in the future we may wish to store it alongside the fd. This would let calls + like sendto() know which family to use without asking the kernel first. */ +typedef enum grpc_dualstack_mode { + /* Uninitialized, or a non-IP socket. */ + GRPC_DSMODE_NONE, + /* AF_INET only. */ + GRPC_DSMODE_IPV4, + /* AF_INET6 only, because IPV6_V6ONLY could not be cleared. */ + GRPC_DSMODE_IPV6, + /* AF_INET6, which also supports ::ffff-mapped IPv4 addresses. */ + GRPC_DSMODE_DUALSTACK +} grpc_dualstack_mode; + +/* Only tests should use this flag. */ +extern int grpc_forbid_dualstack_sockets_for_testing; + +/* Creates a new socket for connecting to (or listening on) an address. + + If addr is AF_INET6, this creates an IPv6 socket first. If that fails, + and addr is within ::ffff:0.0.0.0/96, then it automatically falls back to + an IPv4 socket. + + If addr is AF_INET, AF_UNIX, or anything else, then this is similar to + calling socket() directly. + + Returns an fd on success, otherwise returns -1 with errno set to the result + of a failed socket() call. + + The *dsmode output indicates which address family was actually created. + The recommended way to use this is: + - First convert to IPv6 using grpc_sockaddr_to_v4mapped(). + - Create the socket. + - If *dsmode is IPV4, use grpc_sockaddr_is_v4mapped() to convert back to + IPv4, so that bind() or connect() see the correct family. + Also, it's important to distinguish between DUALSTACK and IPV6 when + listening on the [::] wildcard address. */ +int grpc_create_dualstack_socket(const struct sockaddr *addr, int type, + int protocol, grpc_dualstack_mode *dsmode); + +#endif /* GRPC_CORE_IOMGR_SOCKET_UTILS_POSIX_H */ diff --git a/src/core/lib/iomgr/socket_windows.c b/src/core/lib/iomgr/socket_windows.c new file mode 100644 index 0000000000..c1f419e273 --- /dev/null +++ b/src/core/lib/iomgr/socket_windows.c @@ -0,0 +1,100 @@ +/* + * + * Copyright 2015-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 + +#ifdef GPR_WINSOCK_SOCKET + +#include + +// must be included after winsock2.h +#include + +#include +#include +#include +#include + +#include "src/core/iomgr/iocp_windows.h" +#include "src/core/iomgr/iomgr_internal.h" +#include "src/core/iomgr/pollset.h" +#include "src/core/iomgr/pollset_windows.h" +#include "src/core/iomgr/socket_windows.h" + +grpc_winsocket *grpc_winsocket_create(SOCKET socket, const char *name) { + char *final_name; + grpc_winsocket *r = gpr_malloc(sizeof(grpc_winsocket)); + memset(r, 0, sizeof(grpc_winsocket)); + r->socket = socket; + gpr_mu_init(&r->state_mu); + gpr_asprintf(&final_name, "%s:socket=0x%p", name, r); + grpc_iomgr_register_object(&r->iomgr_object, final_name); + gpr_free(final_name); + grpc_iocp_add_socket(r); + return r; +} + +/* Schedule a shutdown of the socket operations. Will call the pending + operations to abort them. We need to do that this way because of the + various callsites of that function, which happens to be in various + mutex hold states, and that'd be unsafe to call them directly. */ +void grpc_winsocket_shutdown(grpc_winsocket *winsocket) { + /* Grab the function pointer for DisconnectEx for that specific socket. + It may change depending on the interface. */ + int status; + GUID guid = WSAID_DISCONNECTEX; + LPFN_DISCONNECTEX DisconnectEx; + DWORD ioctl_num_bytes; + + status = WSAIoctl(winsocket->socket, SIO_GET_EXTENSION_FUNCTION_POINTER, + &guid, sizeof(guid), &DisconnectEx, sizeof(DisconnectEx), + &ioctl_num_bytes, NULL, NULL); + + if (status == 0) { + DisconnectEx(winsocket->socket, NULL, 0, 0); + } else { + char *utf8_message = gpr_format_message(WSAGetLastError()); + gpr_log(GPR_ERROR, "Unable to retrieve DisconnectEx pointer : %s", + utf8_message); + gpr_free(utf8_message); + } + closesocket(winsocket->socket); +} + +void grpc_winsocket_destroy(grpc_winsocket *winsocket) { + grpc_iomgr_unregister_object(&winsocket->iomgr_object); + gpr_mu_destroy(&winsocket->state_mu); + gpr_free(winsocket); +} + +#endif /* GPR_WINSOCK_SOCKET */ diff --git a/src/core/lib/iomgr/socket_windows.h b/src/core/lib/iomgr/socket_windows.h new file mode 100644 index 0000000000..6fe3c6e080 --- /dev/null +++ b/src/core/lib/iomgr/socket_windows.h @@ -0,0 +1,111 @@ +/* + * + * Copyright 2015-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_IOMGR_SOCKET_WINDOWS_H +#define GRPC_CORE_IOMGR_SOCKET_WINDOWS_H + +#include +#include + +#include +#include + +#include "src/core/iomgr/exec_ctx.h" +#include "src/core/iomgr/iomgr_internal.h" + +/* This holds the data for an outstanding read or write on a socket. + The mutex to protect the concurrent access to that data is the one + inside the winsocket wrapper. */ +typedef struct grpc_winsocket_callback_info { + /* This is supposed to be a WSAOVERLAPPED, but in order to get that + definition, we need to include ws2tcpip.h, which needs to be included + from the top, otherwise it'll clash with a previous inclusion of + windows.h that in turns includes winsock.h. If anyone knows a way + to do it properly, feel free to send a patch. */ + OVERLAPPED overlapped; + /* The callback information for the pending operation. May be empty if the + caller hasn't registered a callback yet. */ + grpc_closure *closure; + /* A boolean to describe if the IO Completion Port got a notification for + that operation. This will happen if the operation completed before the + called had time to register a callback. We could avoid that behavior + altogether by forcing the caller to always register its callback before + proceeding queue an operation, but it is frequent for an IO Completion + Port to trigger quickly. This way we avoid a context switch for calling + the callback. We also simplify the read / write operations to avoid having + to hold a mutex for a long amount of time. */ + int has_pending_iocp; + /* The results of the overlapped operation. */ + DWORD bytes_transfered; + int wsa_error; +} grpc_winsocket_callback_info; + +/* This is a wrapper to a Windows socket. A socket can have one outstanding + read, and one outstanding write. Doing an asynchronous accept means waiting + for a read operation. Doing an asynchronous connect means waiting for a + write operation. These are completely arbitrary ties between the operation + and the kind of event, because we can have one overlapped per pending + operation, whichever its nature is. So we could have more dedicated pending + operation callbacks for connect and listen. But given the scope of listen + and accept, we don't need to go to that extent and waste memory. Also, this + is closer to what happens in posix world. */ +typedef struct grpc_winsocket { + SOCKET socket; + + grpc_winsocket_callback_info write_info; + grpc_winsocket_callback_info read_info; + + gpr_mu state_mu; + + /* You can't add the same socket twice to the same IO Completion Port. + This prevents that. */ + int added_to_iocp; + + grpc_closure shutdown_closure; + + /* A label for iomgr to track outstanding objects */ + grpc_iomgr_object iomgr_object; +} grpc_winsocket; + +/* Create a wrapped windows handle. This takes ownership of it, meaning that + it will be responsible for closing it. */ +grpc_winsocket *grpc_winsocket_create(SOCKET socket, const char *name); + +/* Initiate an asynchronous shutdown of the socket. Will call off any pending + operation to cancel them. */ +void grpc_winsocket_shutdown(grpc_winsocket *socket); + +/* Destroy a socket. Should only be called if there's no pending operation. */ +void grpc_winsocket_destroy(grpc_winsocket *socket); + +#endif /* GRPC_CORE_IOMGR_SOCKET_WINDOWS_H */ diff --git a/src/core/lib/iomgr/tcp_client.h b/src/core/lib/iomgr/tcp_client.h new file mode 100644 index 0000000000..c36f8de713 --- /dev/null +++ b/src/core/lib/iomgr/tcp_client.h @@ -0,0 +1,53 @@ +/* + * + * Copyright 2015-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_IOMGR_TCP_CLIENT_H +#define GRPC_CORE_IOMGR_TCP_CLIENT_H + +#include +#include "src/core/iomgr/endpoint.h" +#include "src/core/iomgr/pollset_set.h" +#include "src/core/iomgr/sockaddr.h" + +/* Asynchronously connect to an address (specified as (addr, len)), and call + cb with arg and the completed connection when done (or call cb with arg and + NULL on failure). + interested_parties points to a set of pollsets that would be interested + in this connection being established (in order to continue their work) */ +void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *on_connect, + grpc_endpoint **endpoint, + grpc_pollset_set *interested_parties, + const struct sockaddr *addr, size_t addr_len, + gpr_timespec deadline); + +#endif /* GRPC_CORE_IOMGR_TCP_CLIENT_H */ diff --git a/src/core/lib/iomgr/tcp_client_posix.c b/src/core/lib/iomgr/tcp_client_posix.c new file mode 100644 index 0000000000..1d3f9b6555 --- /dev/null +++ b/src/core/lib/iomgr/tcp_client_posix.c @@ -0,0 +1,306 @@ +/* + * + * Copyright 2015-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 + +#ifdef GPR_POSIX_SOCKET + +#include "src/core/iomgr/tcp_client.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "src/core/iomgr/iomgr_posix.h" +#include "src/core/iomgr/pollset_posix.h" +#include "src/core/iomgr/pollset_set_posix.h" +#include "src/core/iomgr/sockaddr_utils.h" +#include "src/core/iomgr/socket_utils_posix.h" +#include "src/core/iomgr/tcp_posix.h" +#include "src/core/iomgr/timer.h" +#include "src/core/iomgr/unix_sockets_posix.h" +#include "src/core/support/string.h" + +extern int grpc_tcp_trace; + +typedef struct { + gpr_mu mu; + grpc_fd *fd; + gpr_timespec deadline; + grpc_timer alarm; + int refs; + grpc_closure write_closure; + grpc_pollset_set *interested_parties; + char *addr_str; + grpc_endpoint **ep; + grpc_closure *closure; +} async_connect; + +static int prepare_socket(const struct sockaddr *addr, int fd) { + if (fd < 0) { + goto error; + } + + if (!grpc_set_socket_nonblocking(fd, 1) || !grpc_set_socket_cloexec(fd, 1) || + (!grpc_is_unix_socket(addr) && !grpc_set_socket_low_latency(fd, 1)) || + !grpc_set_socket_no_sigpipe_if_possible(fd)) { + gpr_log(GPR_ERROR, "Unable to configure socket %d: %s", fd, + strerror(errno)); + goto error; + } + return 1; + +error: + if (fd >= 0) { + close(fd); + } + return 0; +} + +static void tc_on_alarm(grpc_exec_ctx *exec_ctx, void *acp, bool success) { + int done; + async_connect *ac = acp; + if (grpc_tcp_trace) { + gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: on_alarm: success=%d", ac->addr_str, + success); + } + gpr_mu_lock(&ac->mu); + if (ac->fd != NULL) { + grpc_fd_shutdown(exec_ctx, ac->fd); + } + done = (--ac->refs == 0); + gpr_mu_unlock(&ac->mu); + if (done) { + gpr_mu_destroy(&ac->mu); + gpr_free(ac->addr_str); + gpr_free(ac); + } +} + +static void on_writable(grpc_exec_ctx *exec_ctx, void *acp, bool success) { + async_connect *ac = acp; + int so_error = 0; + socklen_t so_error_size; + int err; + int done; + grpc_endpoint **ep = ac->ep; + grpc_closure *closure = ac->closure; + grpc_fd *fd; + + if (grpc_tcp_trace) { + gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: on_writable: success=%d", + ac->addr_str, success); + } + + gpr_mu_lock(&ac->mu); + GPR_ASSERT(ac->fd); + fd = ac->fd; + ac->fd = NULL; + gpr_mu_unlock(&ac->mu); + + grpc_timer_cancel(exec_ctx, &ac->alarm); + + gpr_mu_lock(&ac->mu); + if (success) { + do { + so_error_size = sizeof(so_error); + err = getsockopt(fd->fd, SOL_SOCKET, SO_ERROR, &so_error, &so_error_size); + } while (err < 0 && errno == EINTR); + if (err < 0) { + gpr_log(GPR_ERROR, "failed to connect to '%s': getsockopt(ERROR): %s", + ac->addr_str, strerror(errno)); + goto finish; + } else if (so_error != 0) { + if (so_error == ENOBUFS) { + /* We will get one of these errors if we have run out of + memory in the kernel for the data structures allocated + when you connect a socket. If this happens it is very + likely that if we wait a little bit then try again the + connection will work (since other programs or this + program will close their network connections and free up + memory). This does _not_ indicate that there is anything + wrong with the server we are connecting to, this is a + local problem. + + If you are looking at this code, then chances are that + your program or another program on the same computer + opened too many network connections. The "easy" fix: + don't do that! */ + gpr_log(GPR_ERROR, "kernel out of buffers"); + gpr_mu_unlock(&ac->mu); + grpc_fd_notify_on_write(exec_ctx, fd, &ac->write_closure); + return; + } else { + switch (so_error) { + case ECONNREFUSED: + gpr_log( + GPR_ERROR, + "failed to connect to '%s': socket error: connection refused", + ac->addr_str); + break; + default: + gpr_log(GPR_ERROR, "failed to connect to '%s': socket error: %d", + ac->addr_str, so_error); + break; + } + goto finish; + } + } else { + grpc_pollset_set_del_fd(exec_ctx, ac->interested_parties, fd); + *ep = grpc_tcp_create(fd, GRPC_TCP_DEFAULT_READ_SLICE_SIZE, ac->addr_str); + fd = NULL; + goto finish; + } + } else { + gpr_log(GPR_ERROR, "failed to connect to '%s': timeout occurred", + ac->addr_str); + goto finish; + } + + GPR_UNREACHABLE_CODE(return ); + +finish: + if (fd != NULL) { + grpc_pollset_set_del_fd(exec_ctx, ac->interested_parties, fd); + grpc_fd_orphan(exec_ctx, fd, NULL, NULL, "tcp_client_orphan"); + fd = NULL; + } + done = (--ac->refs == 0); + gpr_mu_unlock(&ac->mu); + if (done) { + gpr_mu_destroy(&ac->mu); + gpr_free(ac->addr_str); + gpr_free(ac); + } + grpc_exec_ctx_enqueue(exec_ctx, closure, *ep != NULL, NULL); +} + +void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *closure, + grpc_endpoint **ep, + grpc_pollset_set *interested_parties, + const struct sockaddr *addr, size_t addr_len, + gpr_timespec deadline) { + int fd; + grpc_dualstack_mode dsmode; + int err; + async_connect *ac; + struct sockaddr_in6 addr6_v4mapped; + struct sockaddr_in addr4_copy; + grpc_fd *fdobj; + char *name; + char *addr_str; + + *ep = NULL; + + /* Use dualstack sockets where available. */ + if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) { + addr = (const struct sockaddr *)&addr6_v4mapped; + addr_len = sizeof(addr6_v4mapped); + } + + fd = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode); + if (fd < 0) { + gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno)); + } + if (dsmode == GRPC_DSMODE_IPV4) { + /* If we got an AF_INET socket, map the address back to IPv4. */ + GPR_ASSERT(grpc_sockaddr_is_v4mapped(addr, &addr4_copy)); + addr = (struct sockaddr *)&addr4_copy; + addr_len = sizeof(addr4_copy); + } + if (!prepare_socket(addr, fd)) { + grpc_exec_ctx_enqueue(exec_ctx, closure, false, NULL); + return; + } + + do { + GPR_ASSERT(addr_len < ~(socklen_t)0); + err = connect(fd, addr, (socklen_t)addr_len); + } while (err < 0 && errno == EINTR); + + addr_str = grpc_sockaddr_to_uri(addr); + gpr_asprintf(&name, "tcp-client:%s", addr_str); + + fdobj = grpc_fd_create(fd, name); + + if (err >= 0) { + *ep = grpc_tcp_create(fdobj, GRPC_TCP_DEFAULT_READ_SLICE_SIZE, addr_str); + grpc_exec_ctx_enqueue(exec_ctx, closure, true, NULL); + goto done; + } + + if (errno != EWOULDBLOCK && errno != EINPROGRESS) { + gpr_log(GPR_ERROR, "connect error to '%s': %s", addr_str, strerror(errno)); + grpc_fd_orphan(exec_ctx, fdobj, NULL, NULL, "tcp_client_connect_error"); + grpc_exec_ctx_enqueue(exec_ctx, closure, false, NULL); + goto done; + } + + grpc_pollset_set_add_fd(exec_ctx, interested_parties, fdobj); + + ac = gpr_malloc(sizeof(async_connect)); + ac->closure = closure; + ac->ep = ep; + ac->fd = fdobj; + ac->interested_parties = interested_parties; + ac->addr_str = addr_str; + addr_str = NULL; + gpr_mu_init(&ac->mu); + ac->refs = 2; + ac->write_closure.cb = on_writable; + ac->write_closure.cb_arg = ac; + + if (grpc_tcp_trace) { + gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: asynchronously connecting", + ac->addr_str); + } + + gpr_mu_lock(&ac->mu); + grpc_timer_init(exec_ctx, &ac->alarm, + gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC), + tc_on_alarm, ac, gpr_now(GPR_CLOCK_MONOTONIC)); + grpc_fd_notify_on_write(exec_ctx, ac->fd, &ac->write_closure); + gpr_mu_unlock(&ac->mu); + +done: + gpr_free(name); + gpr_free(addr_str); +} + +#endif diff --git a/src/core/lib/iomgr/tcp_client_windows.c b/src/core/lib/iomgr/tcp_client_windows.c new file mode 100644 index 0000000000..da83f7b79c --- /dev/null +++ b/src/core/lib/iomgr/tcp_client_windows.c @@ -0,0 +1,221 @@ +/* + * + * Copyright 2015-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 + +#ifdef GPR_WINSOCK_SOCKET + +#include "src/core/iomgr/sockaddr_win32.h" + +#include +#include +#include +#include +#include + +#include "src/core/iomgr/iocp_windows.h" +#include "src/core/iomgr/sockaddr.h" +#include "src/core/iomgr/sockaddr_utils.h" +#include "src/core/iomgr/socket_windows.h" +#include "src/core/iomgr/tcp_client.h" +#include "src/core/iomgr/tcp_windows.h" +#include "src/core/iomgr/timer.h" + +typedef struct { + grpc_closure *on_done; + gpr_mu mu; + grpc_winsocket *socket; + gpr_timespec deadline; + grpc_timer alarm; + char *addr_name; + int refs; + grpc_closure on_connect; + grpc_endpoint **endpoint; +} async_connect; + +static void async_connect_unlock_and_cleanup(async_connect *ac) { + int done = (--ac->refs == 0); + gpr_mu_unlock(&ac->mu); + if (done) { + if (ac->socket != NULL) grpc_winsocket_destroy(ac->socket); + gpr_mu_destroy(&ac->mu); + gpr_free(ac->addr_name); + gpr_free(ac); + } +} + +static void on_alarm(grpc_exec_ctx *exec_ctx, void *acp, bool occured) { + async_connect *ac = acp; + gpr_mu_lock(&ac->mu); + /* If the alarm didn't occur, it got cancelled. */ + if (ac->socket != NULL && occured) { + grpc_winsocket_shutdown(ac->socket); + } + async_connect_unlock_and_cleanup(ac); +} + +static void on_connect(grpc_exec_ctx *exec_ctx, void *acp, bool from_iocp) { + async_connect *ac = acp; + SOCKET sock = ac->socket->socket; + grpc_endpoint **ep = ac->endpoint; + grpc_winsocket_callback_info *info = &ac->socket->write_info; + grpc_closure *on_done = ac->on_done; + + grpc_timer_cancel(exec_ctx, &ac->alarm); + + gpr_mu_lock(&ac->mu); + + if (from_iocp) { + DWORD transfered_bytes = 0; + DWORD flags; + BOOL wsa_success = WSAGetOverlappedResult(sock, &info->overlapped, + &transfered_bytes, FALSE, &flags); + GPR_ASSERT(transfered_bytes == 0); + if (!wsa_success) { + char *utf8_message = gpr_format_message(WSAGetLastError()); + gpr_log(GPR_ERROR, "on_connect error: %s", utf8_message); + gpr_free(utf8_message); + } else { + *ep = grpc_tcp_create(ac->socket, ac->addr_name); + ac->socket = NULL; + } + } + + async_connect_unlock_and_cleanup(ac); + /* If the connection was aborted, the callback was already called when + the deadline was met. */ + on_done->cb(exec_ctx, on_done->cb_arg, *ep != NULL); +} + +/* Tries to issue one async connection, then schedules both an IOCP + notification request for the connection, and one timeout alert. */ +void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *on_done, + grpc_endpoint **endpoint, + grpc_pollset_set *interested_parties, + const struct sockaddr *addr, size_t addr_len, + gpr_timespec deadline) { + SOCKET sock = INVALID_SOCKET; + BOOL success; + int status; + struct sockaddr_in6 addr6_v4mapped; + struct sockaddr_in6 local_address; + async_connect *ac; + grpc_winsocket *socket = NULL; + LPFN_CONNECTEX ConnectEx; + GUID guid = WSAID_CONNECTEX; + DWORD ioctl_num_bytes; + const char *message = NULL; + char *utf8_message; + grpc_winsocket_callback_info *info; + + *endpoint = NULL; + + /* Use dualstack sockets where available. */ + if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) { + addr = (const struct sockaddr *)&addr6_v4mapped; + addr_len = sizeof(addr6_v4mapped); + } + + sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0, + WSA_FLAG_OVERLAPPED); + if (sock == INVALID_SOCKET) { + message = "Unable to create socket: %s"; + goto failure; + } + + if (!grpc_tcp_prepare_socket(sock)) { + message = "Unable to set socket options: %s"; + goto failure; + } + + /* Grab the function pointer for ConnectEx for that specific socket. + It may change depending on the interface. */ + status = + WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid), + &ConnectEx, sizeof(ConnectEx), &ioctl_num_bytes, NULL, NULL); + + if (status != 0) { + message = "Unable to retrieve ConnectEx pointer: %s"; + goto failure; + } + + grpc_sockaddr_make_wildcard6(0, &local_address); + + status = bind(sock, (struct sockaddr *)&local_address, sizeof(local_address)); + if (status != 0) { + message = "Unable to bind socket: %s"; + goto failure; + } + + socket = grpc_winsocket_create(sock, "client"); + info = &socket->write_info; + success = + ConnectEx(sock, addr, (int)addr_len, NULL, 0, NULL, &info->overlapped); + + /* It wouldn't be unusual to get a success immediately. But we'll still get + an IOCP notification, so let's ignore it. */ + if (!success) { + int error = WSAGetLastError(); + if (error != ERROR_IO_PENDING) { + message = "ConnectEx failed: %s"; + goto failure; + } + } + + ac = gpr_malloc(sizeof(async_connect)); + ac->on_done = on_done; + ac->socket = socket; + gpr_mu_init(&ac->mu); + ac->refs = 2; + ac->addr_name = grpc_sockaddr_to_uri(addr); + ac->endpoint = endpoint; + grpc_closure_init(&ac->on_connect, on_connect, ac); + + grpc_timer_init(exec_ctx, &ac->alarm, deadline, on_alarm, ac, + gpr_now(GPR_CLOCK_MONOTONIC)); + grpc_socket_notify_on_write(exec_ctx, socket, &ac->on_connect); + return; + +failure: + utf8_message = gpr_format_message(WSAGetLastError()); + gpr_log(GPR_ERROR, message, utf8_message); + gpr_free(utf8_message); + if (socket != NULL) { + grpc_winsocket_destroy(socket); + } else if (sock != INVALID_SOCKET) { + closesocket(sock); + } + grpc_exec_ctx_enqueue(exec_ctx, on_done, false, NULL); +} + +#endif /* GPR_WINSOCK_SOCKET */ diff --git a/src/core/lib/iomgr/tcp_posix.c b/src/core/lib/iomgr/tcp_posix.c new file mode 100644 index 0000000000..e8f73811ce --- /dev/null +++ b/src/core/lib/iomgr/tcp_posix.c @@ -0,0 +1,493 @@ +/* + * + * Copyright 2015-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 + +#ifdef GPR_POSIX_SOCKET + +#include "src/core/iomgr/tcp_posix.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "src/core/debug/trace.h" +#include "src/core/iomgr/pollset_posix.h" +#include "src/core/iomgr/pollset_set_posix.h" +#include "src/core/profiling/timers.h" +#include "src/core/support/string.h" + +#ifdef GPR_HAVE_MSG_NOSIGNAL +#define SENDMSG_FLAGS MSG_NOSIGNAL +#else +#define SENDMSG_FLAGS 0 +#endif + +#ifdef GPR_MSG_IOVLEN_TYPE +typedef GPR_MSG_IOVLEN_TYPE msg_iovlen_type; +#else +typedef size_t msg_iovlen_type; +#endif + +int grpc_tcp_trace = 0; + +typedef struct { + grpc_endpoint base; + grpc_fd *em_fd; + int fd; + int finished_edge; + msg_iovlen_type iov_size; /* Number of slices to allocate per read attempt */ + size_t slice_size; + gpr_refcount refcount; + + /* garbage after the last read */ + gpr_slice_buffer last_read_buffer; + + gpr_slice_buffer *incoming_buffer; + gpr_slice_buffer *outgoing_buffer; + /** slice within outgoing_buffer to write next */ + size_t outgoing_slice_idx; + /** byte within outgoing_buffer->slices[outgoing_slice_idx] to write next */ + size_t outgoing_byte_idx; + + grpc_closure *read_cb; + grpc_closure *write_cb; + grpc_closure *release_fd_cb; + int *release_fd; + + grpc_closure read_closure; + grpc_closure write_closure; + + char *peer_string; +} grpc_tcp; + +static void tcp_handle_read(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */, + bool success); +static void tcp_handle_write(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */, + bool success); + +static void tcp_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) { + grpc_tcp *tcp = (grpc_tcp *)ep; + grpc_fd_shutdown(exec_ctx, tcp->em_fd); +} + +static void tcp_free(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) { + grpc_fd_orphan(exec_ctx, tcp->em_fd, tcp->release_fd_cb, tcp->release_fd, + "tcp_unref_orphan"); + gpr_slice_buffer_destroy(&tcp->last_read_buffer); + gpr_free(tcp->peer_string); + gpr_free(tcp); +} + +/*#define GRPC_TCP_REFCOUNT_DEBUG*/ +#ifdef GRPC_TCP_REFCOUNT_DEBUG +#define TCP_UNREF(cl, tcp, reason) \ + tcp_unref((cl), (tcp), (reason), __FILE__, __LINE__) +#define TCP_REF(tcp, reason) tcp_ref((tcp), (reason), __FILE__, __LINE__) +static void tcp_unref(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp, + const char *reason, const char *file, int line) { + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP unref %p : %s %d -> %d", tcp, + reason, tcp->refcount.count, tcp->refcount.count - 1); + if (gpr_unref(&tcp->refcount)) { + tcp_free(exec_ctx, tcp); + } +} + +static void tcp_ref(grpc_tcp *tcp, const char *reason, const char *file, + int line) { + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP ref %p : %s %d -> %d", tcp, + reason, tcp->refcount.count, tcp->refcount.count + 1); + gpr_ref(&tcp->refcount); +} +#else +#define TCP_UNREF(cl, tcp, reason) tcp_unref((cl), (tcp)) +#define TCP_REF(tcp, reason) tcp_ref((tcp)) +static void tcp_unref(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) { + if (gpr_unref(&tcp->refcount)) { + tcp_free(exec_ctx, tcp); + } +} + +static void tcp_ref(grpc_tcp *tcp) { gpr_ref(&tcp->refcount); } +#endif + +static void tcp_destroy(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) { + grpc_tcp *tcp = (grpc_tcp *)ep; + TCP_UNREF(exec_ctx, tcp, "destroy"); +} + +static void call_read_cb(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp, int success) { + grpc_closure *cb = tcp->read_cb; + + if (grpc_tcp_trace) { + size_t i; + gpr_log(GPR_DEBUG, "read: success=%d", success); + for (i = 0; i < tcp->incoming_buffer->count; i++) { + char *dump = gpr_dump_slice(tcp->incoming_buffer->slices[i], + GPR_DUMP_HEX | GPR_DUMP_ASCII); + gpr_log(GPR_DEBUG, "READ %p: %s", tcp, dump); + gpr_free(dump); + } + } + + tcp->read_cb = NULL; + tcp->incoming_buffer = NULL; + cb->cb(exec_ctx, cb->cb_arg, success); +} + +#define MAX_READ_IOVEC 4 +static void tcp_continue_read(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) { + struct msghdr msg; + struct iovec iov[MAX_READ_IOVEC]; + ssize_t read_bytes; + size_t i; + + GPR_ASSERT(!tcp->finished_edge); + GPR_ASSERT(tcp->iov_size <= MAX_READ_IOVEC); + GPR_ASSERT(tcp->incoming_buffer->count <= MAX_READ_IOVEC); + GPR_TIMER_BEGIN("tcp_continue_read", 0); + + while (tcp->incoming_buffer->count < (size_t)tcp->iov_size) { + gpr_slice_buffer_add_indexed(tcp->incoming_buffer, + gpr_slice_malloc(tcp->slice_size)); + } + for (i = 0; i < tcp->incoming_buffer->count; i++) { + iov[i].iov_base = GPR_SLICE_START_PTR(tcp->incoming_buffer->slices[i]); + iov[i].iov_len = GPR_SLICE_LENGTH(tcp->incoming_buffer->slices[i]); + } + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = iov; + msg.msg_iovlen = tcp->iov_size; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = 0; + + GPR_TIMER_BEGIN("recvmsg", 1); + do { + read_bytes = recvmsg(tcp->fd, &msg, 0); + } while (read_bytes < 0 && errno == EINTR); + GPR_TIMER_END("recvmsg", 0); + + if (read_bytes < 0) { + /* NB: After calling call_read_cb a parallel call of the read handler may + * be running. */ + if (errno == EAGAIN) { + if (tcp->iov_size > 1) { + tcp->iov_size /= 2; + } + /* We've consumed the edge, request a new one */ + grpc_fd_notify_on_read(exec_ctx, tcp->em_fd, &tcp->read_closure); + } else { + /* TODO(klempner): Log interesting errors */ + gpr_slice_buffer_reset_and_unref(tcp->incoming_buffer); + call_read_cb(exec_ctx, tcp, 0); + TCP_UNREF(exec_ctx, tcp, "read"); + } + } else if (read_bytes == 0) { + /* 0 read size ==> end of stream */ + gpr_slice_buffer_reset_and_unref(tcp->incoming_buffer); + call_read_cb(exec_ctx, tcp, 0); + TCP_UNREF(exec_ctx, tcp, "read"); + } else { + GPR_ASSERT((size_t)read_bytes <= tcp->incoming_buffer->length); + if ((size_t)read_bytes < tcp->incoming_buffer->length) { + gpr_slice_buffer_trim_end( + tcp->incoming_buffer, + tcp->incoming_buffer->length - (size_t)read_bytes, + &tcp->last_read_buffer); + } else if (tcp->iov_size < MAX_READ_IOVEC) { + ++tcp->iov_size; + } + GPR_ASSERT((size_t)read_bytes == tcp->incoming_buffer->length); + call_read_cb(exec_ctx, tcp, 1); + TCP_UNREF(exec_ctx, tcp, "read"); + } + + GPR_TIMER_END("tcp_continue_read", 0); +} + +static void tcp_handle_read(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */, + bool success) { + grpc_tcp *tcp = (grpc_tcp *)arg; + GPR_ASSERT(!tcp->finished_edge); + + if (!success) { + gpr_slice_buffer_reset_and_unref(tcp->incoming_buffer); + call_read_cb(exec_ctx, tcp, 0); + TCP_UNREF(exec_ctx, tcp, "read"); + } else { + tcp_continue_read(exec_ctx, tcp); + } +} + +static void tcp_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, + gpr_slice_buffer *incoming_buffer, grpc_closure *cb) { + grpc_tcp *tcp = (grpc_tcp *)ep; + GPR_ASSERT(tcp->read_cb == NULL); + tcp->read_cb = cb; + tcp->incoming_buffer = incoming_buffer; + gpr_slice_buffer_reset_and_unref(incoming_buffer); + gpr_slice_buffer_swap(incoming_buffer, &tcp->last_read_buffer); + TCP_REF(tcp, "read"); + if (tcp->finished_edge) { + tcp->finished_edge = 0; + grpc_fd_notify_on_read(exec_ctx, tcp->em_fd, &tcp->read_closure); + } else { + grpc_exec_ctx_enqueue(exec_ctx, &tcp->read_closure, true, NULL); + } +} + +typedef enum { FLUSH_DONE, FLUSH_PENDING, FLUSH_ERROR } flush_result; + +#define MAX_WRITE_IOVEC 16 +static flush_result tcp_flush(grpc_tcp *tcp) { + struct msghdr msg; + struct iovec iov[MAX_WRITE_IOVEC]; + msg_iovlen_type iov_size; + ssize_t sent_length; + size_t sending_length; + size_t trailing; + size_t unwind_slice_idx; + size_t unwind_byte_idx; + + for (;;) { + sending_length = 0; + unwind_slice_idx = tcp->outgoing_slice_idx; + unwind_byte_idx = tcp->outgoing_byte_idx; + for (iov_size = 0; tcp->outgoing_slice_idx != tcp->outgoing_buffer->count && + iov_size != MAX_WRITE_IOVEC; + iov_size++) { + iov[iov_size].iov_base = + GPR_SLICE_START_PTR( + tcp->outgoing_buffer->slices[tcp->outgoing_slice_idx]) + + tcp->outgoing_byte_idx; + iov[iov_size].iov_len = + GPR_SLICE_LENGTH( + tcp->outgoing_buffer->slices[tcp->outgoing_slice_idx]) - + tcp->outgoing_byte_idx; + sending_length += iov[iov_size].iov_len; + tcp->outgoing_slice_idx++; + tcp->outgoing_byte_idx = 0; + } + GPR_ASSERT(iov_size > 0); + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = iov; + msg.msg_iovlen = iov_size; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = 0; + + GPR_TIMER_BEGIN("sendmsg", 1); + do { + /* TODO(klempner): Cork if this is a partial write */ + sent_length = sendmsg(tcp->fd, &msg, SENDMSG_FLAGS); + } while (sent_length < 0 && errno == EINTR); + GPR_TIMER_END("sendmsg", 0); + + if (sent_length < 0) { + if (errno == EAGAIN) { + tcp->outgoing_slice_idx = unwind_slice_idx; + tcp->outgoing_byte_idx = unwind_byte_idx; + return FLUSH_PENDING; + } else { + /* TODO(klempner): Log some of these */ + return FLUSH_ERROR; + } + } + + GPR_ASSERT(tcp->outgoing_byte_idx == 0); + trailing = sending_length - (size_t)sent_length; + while (trailing > 0) { + size_t slice_length; + + tcp->outgoing_slice_idx--; + slice_length = GPR_SLICE_LENGTH( + tcp->outgoing_buffer->slices[tcp->outgoing_slice_idx]); + if (slice_length > trailing) { + tcp->outgoing_byte_idx = slice_length - trailing; + break; + } else { + trailing -= slice_length; + } + } + + if (tcp->outgoing_slice_idx == tcp->outgoing_buffer->count) { + return FLUSH_DONE; + } + }; +} + +static void tcp_handle_write(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */, + bool success) { + grpc_tcp *tcp = (grpc_tcp *)arg; + flush_result status; + grpc_closure *cb; + + if (!success) { + cb = tcp->write_cb; + tcp->write_cb = NULL; + cb->cb(exec_ctx, cb->cb_arg, 0); + TCP_UNREF(exec_ctx, tcp, "write"); + return; + } + + status = tcp_flush(tcp); + if (status == FLUSH_PENDING) { + grpc_fd_notify_on_write(exec_ctx, tcp->em_fd, &tcp->write_closure); + } else { + cb = tcp->write_cb; + tcp->write_cb = NULL; + GPR_TIMER_BEGIN("tcp_handle_write.cb", 0); + cb->cb(exec_ctx, cb->cb_arg, status == FLUSH_DONE); + GPR_TIMER_END("tcp_handle_write.cb", 0); + TCP_UNREF(exec_ctx, tcp, "write"); + } +} + +static void tcp_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, + gpr_slice_buffer *buf, grpc_closure *cb) { + grpc_tcp *tcp = (grpc_tcp *)ep; + flush_result status; + + if (grpc_tcp_trace) { + size_t i; + + for (i = 0; i < buf->count; i++) { + char *data = + gpr_dump_slice(buf->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII); + gpr_log(GPR_DEBUG, "WRITE %p: %s", tcp, data); + gpr_free(data); + } + } + + GPR_TIMER_BEGIN("tcp_write", 0); + GPR_ASSERT(tcp->write_cb == NULL); + + if (buf->length == 0) { + GPR_TIMER_END("tcp_write", 0); + grpc_exec_ctx_enqueue(exec_ctx, cb, true, NULL); + return; + } + tcp->outgoing_buffer = buf; + tcp->outgoing_slice_idx = 0; + tcp->outgoing_byte_idx = 0; + + status = tcp_flush(tcp); + if (status == FLUSH_PENDING) { + TCP_REF(tcp, "write"); + tcp->write_cb = cb; + grpc_fd_notify_on_write(exec_ctx, tcp->em_fd, &tcp->write_closure); + } else { + grpc_exec_ctx_enqueue(exec_ctx, cb, status == FLUSH_DONE, NULL); + } + + GPR_TIMER_END("tcp_write", 0); +} + +static void tcp_add_to_pollset(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, + grpc_pollset *pollset) { + grpc_tcp *tcp = (grpc_tcp *)ep; + grpc_pollset_add_fd(exec_ctx, pollset, tcp->em_fd); +} + +static void tcp_add_to_pollset_set(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, + grpc_pollset_set *pollset_set) { + grpc_tcp *tcp = (grpc_tcp *)ep; + grpc_pollset_set_add_fd(exec_ctx, pollset_set, tcp->em_fd); +} + +static char *tcp_get_peer(grpc_endpoint *ep) { + grpc_tcp *tcp = (grpc_tcp *)ep; + return gpr_strdup(tcp->peer_string); +} + +static const grpc_endpoint_vtable vtable = { + tcp_read, tcp_write, tcp_add_to_pollset, tcp_add_to_pollset_set, + tcp_shutdown, tcp_destroy, tcp_get_peer}; + +grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd, size_t slice_size, + const char *peer_string) { + grpc_tcp *tcp = (grpc_tcp *)gpr_malloc(sizeof(grpc_tcp)); + tcp->base.vtable = &vtable; + tcp->peer_string = gpr_strdup(peer_string); + tcp->fd = em_fd->fd; + tcp->read_cb = NULL; + tcp->write_cb = NULL; + tcp->release_fd_cb = NULL; + tcp->release_fd = NULL; + tcp->incoming_buffer = NULL; + tcp->slice_size = slice_size; + tcp->iov_size = 1; + tcp->finished_edge = 1; + /* paired with unref in grpc_tcp_destroy */ + gpr_ref_init(&tcp->refcount, 1); + tcp->em_fd = em_fd; + tcp->read_closure.cb = tcp_handle_read; + tcp->read_closure.cb_arg = tcp; + tcp->write_closure.cb = tcp_handle_write; + tcp->write_closure.cb_arg = tcp; + gpr_slice_buffer_init(&tcp->last_read_buffer); + + return &tcp->base; +} + +int grpc_tcp_fd(grpc_endpoint *ep) { + grpc_tcp *tcp = (grpc_tcp *)ep; + GPR_ASSERT(ep->vtable == &vtable); + return grpc_fd_wrapped_fd(tcp->em_fd); +} + +void grpc_tcp_destroy_and_release_fd(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, + int *fd, grpc_closure *done) { + grpc_tcp *tcp = (grpc_tcp *)ep; + GPR_ASSERT(ep->vtable == &vtable); + tcp->release_fd = fd; + tcp->release_fd_cb = done; + TCP_UNREF(exec_ctx, tcp, "destroy"); +} + +#endif diff --git a/src/core/lib/iomgr/tcp_posix.h b/src/core/lib/iomgr/tcp_posix.h new file mode 100644 index 0000000000..d846ec570f --- /dev/null +++ b/src/core/lib/iomgr/tcp_posix.h @@ -0,0 +1,71 @@ +/* + * + * Copyright 2015-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_IOMGR_TCP_POSIX_H +#define GRPC_CORE_IOMGR_TCP_POSIX_H +/* + Low level TCP "bottom half" implementation, for use by transports built on + top of a TCP connection. + + Note that this file does not (yet) include APIs for creating the socket in + the first place. + + All calls passing slice transfer ownership of a slice refcount unless + otherwise specified. +*/ + +#include "src/core/iomgr/endpoint.h" +#include "src/core/iomgr/fd_posix.h" + +#define GRPC_TCP_DEFAULT_READ_SLICE_SIZE 8192 + +extern int grpc_tcp_trace; + +/* Create a tcp endpoint given a file desciptor and a read slice size. + Takes ownership of fd. */ +grpc_endpoint *grpc_tcp_create(grpc_fd *fd, size_t read_slice_size, + const char *peer_string); + +/* Return the tcp endpoint's fd, or -1 if this is not available. Does not + release the fd. + Requires: ep must be a tcp endpoint. + */ +int grpc_tcp_fd(grpc_endpoint *ep); + +/* Destroy the tcp endpoint without closing its fd. *fd will be set and done + * will be called when the endpoint is destroyed. + * Requires: ep must be a tcp endpoint and fd must not be NULL. */ +void grpc_tcp_destroy_and_release_fd(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, + int *fd, grpc_closure *done); + +#endif /* GRPC_CORE_IOMGR_TCP_POSIX_H */ diff --git a/src/core/lib/iomgr/tcp_server.h b/src/core/lib/iomgr/tcp_server.h new file mode 100644 index 0000000000..93247e9e4e --- /dev/null +++ b/src/core/lib/iomgr/tcp_server.h @@ -0,0 +1,103 @@ +/* + * + * Copyright 2015-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_IOMGR_TCP_SERVER_H +#define GRPC_CORE_IOMGR_TCP_SERVER_H + +#include "src/core/iomgr/closure.h" +#include "src/core/iomgr/endpoint.h" + +/* Forward decl of grpc_tcp_server */ +typedef struct grpc_tcp_server grpc_tcp_server; + +typedef struct grpc_tcp_server_acceptor { + /* grpc_tcp_server_cb functions share a ref on from_server that is valid + until the function returns. */ + grpc_tcp_server *from_server; + /* Indices that may be passed to grpc_tcp_server_port_fd(). */ + unsigned port_index; + unsigned fd_index; +} grpc_tcp_server_acceptor; + +/* Called for newly connected TCP connections. */ +typedef void (*grpc_tcp_server_cb)(grpc_exec_ctx *exec_ctx, void *arg, + grpc_endpoint *ep, + grpc_tcp_server_acceptor *acceptor); + +/* Create a server, initially not bound to any ports. The caller owns one ref. + If shutdown_complete is not NULL, it will be used by + grpc_tcp_server_unref() when the ref count reaches zero. */ +grpc_tcp_server *grpc_tcp_server_create(grpc_closure *shutdown_complete); + +/* Start listening to bound ports */ +void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *server, + grpc_pollset **pollsets, size_t pollset_count, + grpc_tcp_server_cb on_accept_cb, void *cb_arg); + +/* Add a port to the server, returning the newly allocated port on success, or + -1 on failure. + + The :: and 0.0.0.0 wildcard addresses are treated identically, accepting + both IPv4 and IPv6 connections, but :: is the preferred style. This usually + creates one socket, but possibly two on systems which support IPv6, + but not dualstack sockets. */ +/* TODO(ctiller): deprecate this, and make grpc_tcp_server_add_ports to handle + all of the multiple socket port matching logic in one place */ +int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr, + size_t addr_len); + +/* Number of fds at the given port_index, or 0 if port_index is out of + bounds. */ +unsigned grpc_tcp_server_port_fd_count(grpc_tcp_server *s, unsigned port_index); + +/* Returns the file descriptor of the Mth (fd_index) listening socket of the Nth + (port_index) call to add_port() on this server, or -1 if the indices are out + of bounds. The file descriptor remains owned by the server, and will be + cleaned up when the ref count reaches zero. */ +int grpc_tcp_server_port_fd(grpc_tcp_server *s, unsigned port_index, + unsigned fd_index); + +/* Ref s and return s. */ +grpc_tcp_server *grpc_tcp_server_ref(grpc_tcp_server *s); + +/* shutdown_starting is called when ref count has reached zero and the server is + about to be destroyed. The server will be deleted after it returns. Calling + grpc_tcp_server_ref() from it has no effect. */ +void grpc_tcp_server_shutdown_starting_add(grpc_tcp_server *s, + grpc_closure *shutdown_starting); + +/* If the refcount drops to zero, delete s, and call (exec_ctx==NULL) or enqueue + a call (exec_ctx!=NULL) to shutdown_complete. */ +void grpc_tcp_server_unref(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s); + +#endif /* GRPC_CORE_IOMGR_TCP_SERVER_H */ diff --git a/src/core/lib/iomgr/tcp_server_posix.c b/src/core/lib/iomgr/tcp_server_posix.c new file mode 100644 index 0000000000..74ee68a6f1 --- /dev/null +++ b/src/core/lib/iomgr/tcp_server_posix.c @@ -0,0 +1,607 @@ +/* + * + * Copyright 2015-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. + * + */ + +/* FIXME: "posix" files shouldn't be depending on _GNU_SOURCE */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include + +#ifdef GPR_POSIX_SOCKET + +#include "src/core/iomgr/tcp_server.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "src/core/iomgr/pollset_posix.h" +#include "src/core/iomgr/resolve_address.h" +#include "src/core/iomgr/sockaddr_utils.h" +#include "src/core/iomgr/socket_utils_posix.h" +#include "src/core/iomgr/tcp_posix.h" +#include "src/core/iomgr/unix_sockets_posix.h" +#include "src/core/support/string.h" + +#define MIN_SAFE_ACCEPT_QUEUE_SIZE 100 + +static gpr_once s_init_max_accept_queue_size; +static int s_max_accept_queue_size; + +/* one listening port */ +typedef struct grpc_tcp_listener grpc_tcp_listener; +struct grpc_tcp_listener { + int fd; + grpc_fd *emfd; + grpc_tcp_server *server; + union { + uint8_t untyped[GRPC_MAX_SOCKADDR_SIZE]; + struct sockaddr sockaddr; + } addr; + size_t addr_len; + int port; + unsigned port_index; + unsigned fd_index; + grpc_closure read_closure; + grpc_closure destroyed_closure; + struct grpc_tcp_listener *next; + /* When we add a listener, more than one can be created, mainly because of + IPv6. A sibling will still be in the normal list, but will be flagged + as such. Any action, such as ref or unref, will affect all of the + siblings in the list. */ + struct grpc_tcp_listener *sibling; + int is_sibling; +}; + +/* the overall server */ +struct grpc_tcp_server { + gpr_refcount refs; + /* Called whenever accept() succeeds on a server port. */ + grpc_tcp_server_cb on_accept_cb; + void *on_accept_cb_arg; + + gpr_mu mu; + + /* active port count: how many ports are actually still listening */ + size_t active_ports; + /* destroyed port count: how many ports are completely destroyed */ + size_t destroyed_ports; + + /* is this server shutting down? (boolean) */ + int shutdown; + + /* linked list of server ports */ + grpc_tcp_listener *head; + grpc_tcp_listener *tail; + unsigned nports; + + /* List of closures passed to shutdown_starting_add(). */ + grpc_closure_list shutdown_starting; + + /* shutdown callback */ + grpc_closure *shutdown_complete; + + /* all pollsets interested in new connections */ + grpc_pollset **pollsets; + /* number of pollsets in the pollsets array */ + size_t pollset_count; +}; + +grpc_tcp_server *grpc_tcp_server_create(grpc_closure *shutdown_complete) { + grpc_tcp_server *s = gpr_malloc(sizeof(grpc_tcp_server)); + gpr_ref_init(&s->refs, 1); + gpr_mu_init(&s->mu); + s->active_ports = 0; + s->destroyed_ports = 0; + s->shutdown = 0; + s->shutdown_starting.head = NULL; + s->shutdown_starting.tail = NULL; + s->shutdown_complete = shutdown_complete; + s->on_accept_cb = NULL; + s->on_accept_cb_arg = NULL; + s->head = NULL; + s->tail = NULL; + s->nports = 0; + return s; +} + +static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { + if (s->shutdown_complete != NULL) { + grpc_exec_ctx_enqueue(exec_ctx, s->shutdown_complete, true, NULL); + } + + gpr_mu_destroy(&s->mu); + + while (s->head) { + grpc_tcp_listener *sp = s->head; + s->head = sp->next; + gpr_free(sp); + } + + gpr_free(s); +} + +static void destroyed_port(grpc_exec_ctx *exec_ctx, void *server, + bool success) { + grpc_tcp_server *s = server; + gpr_mu_lock(&s->mu); + s->destroyed_ports++; + if (s->destroyed_ports == s->nports) { + gpr_mu_unlock(&s->mu); + finish_shutdown(exec_ctx, s); + } else { + GPR_ASSERT(s->destroyed_ports < s->nports); + gpr_mu_unlock(&s->mu); + } +} + +/* called when all listening endpoints have been shutdown, so no further + events will be received on them - at this point it's safe to destroy + things */ +static void deactivated_all_ports(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { + /* delete ALL the things */ + gpr_mu_lock(&s->mu); + + if (!s->shutdown) { + gpr_mu_unlock(&s->mu); + return; + } + + if (s->head) { + grpc_tcp_listener *sp; + for (sp = s->head; sp; sp = sp->next) { + grpc_unlink_if_unix_domain_socket(&sp->addr.sockaddr); + sp->destroyed_closure.cb = destroyed_port; + sp->destroyed_closure.cb_arg = s; + grpc_fd_orphan(exec_ctx, sp->emfd, &sp->destroyed_closure, NULL, + "tcp_listener_shutdown"); + } + gpr_mu_unlock(&s->mu); + } else { + gpr_mu_unlock(&s->mu); + finish_shutdown(exec_ctx, s); + } +} + +static void tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { + gpr_mu_lock(&s->mu); + + GPR_ASSERT(!s->shutdown); + s->shutdown = 1; + + /* shutdown all fd's */ + if (s->active_ports) { + grpc_tcp_listener *sp; + for (sp = s->head; sp; sp = sp->next) { + grpc_fd_shutdown(exec_ctx, sp->emfd); + } + gpr_mu_unlock(&s->mu); + } else { + gpr_mu_unlock(&s->mu); + deactivated_all_ports(exec_ctx, s); + } +} + +/* get max listen queue size on linux */ +static void init_max_accept_queue_size(void) { + int n = SOMAXCONN; + char buf[64]; + FILE *fp = fopen("/proc/sys/net/core/somaxconn", "r"); + if (fp == NULL) { + /* 2.4 kernel. */ + s_max_accept_queue_size = SOMAXCONN; + return; + } + if (fgets(buf, sizeof buf, fp)) { + char *end; + long i = strtol(buf, &end, 10); + if (i > 0 && i <= INT_MAX && end && *end == 0) { + n = (int)i; + } + } + fclose(fp); + s_max_accept_queue_size = n; + + if (s_max_accept_queue_size < MIN_SAFE_ACCEPT_QUEUE_SIZE) { + gpr_log(GPR_INFO, + "Suspiciously small accept queue (%d) will probably lead to " + "connection drops", + s_max_accept_queue_size); + } +} + +static int get_max_accept_queue_size(void) { + gpr_once_init(&s_init_max_accept_queue_size, init_max_accept_queue_size); + return s_max_accept_queue_size; +} + +/* Prepare a recently-created socket for listening. */ +static int prepare_socket(int fd, const struct sockaddr *addr, + size_t addr_len) { + struct sockaddr_storage sockname_temp; + socklen_t sockname_len; + + if (fd < 0) { + goto error; + } + + if (!grpc_set_socket_nonblocking(fd, 1) || !grpc_set_socket_cloexec(fd, 1) || + (!grpc_is_unix_socket(addr) && (!grpc_set_socket_low_latency(fd, 1) || + !grpc_set_socket_reuse_addr(fd, 1))) || + !grpc_set_socket_no_sigpipe_if_possible(fd)) { + gpr_log(GPR_ERROR, "Unable to configure socket %d: %s", fd, + strerror(errno)); + goto error; + } + + GPR_ASSERT(addr_len < ~(socklen_t)0); + if (bind(fd, addr, (socklen_t)addr_len) < 0) { + char *addr_str; + grpc_sockaddr_to_string(&addr_str, addr, 0); + gpr_log(GPR_ERROR, "bind addr=%s: %s", addr_str, strerror(errno)); + gpr_free(addr_str); + goto error; + } + + if (listen(fd, get_max_accept_queue_size()) < 0) { + gpr_log(GPR_ERROR, "listen: %s", strerror(errno)); + goto error; + } + + sockname_len = sizeof(sockname_temp); + if (getsockname(fd, (struct sockaddr *)&sockname_temp, &sockname_len) < 0) { + goto error; + } + + return grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp); + +error: + if (fd >= 0) { + close(fd); + } + return -1; +} + +/* event manager callback when reads are ready */ +static void on_read(grpc_exec_ctx *exec_ctx, void *arg, bool success) { + grpc_tcp_listener *sp = arg; + grpc_tcp_server_acceptor acceptor = {sp->server, sp->port_index, + sp->fd_index}; + grpc_fd *fdobj; + size_t i; + + if (!success) { + goto error; + } + + /* loop until accept4 returns EAGAIN, and then re-arm notification */ + for (;;) { + struct sockaddr_storage addr; + socklen_t addrlen = sizeof(addr); + char *addr_str; + char *name; + /* Note: If we ever decide to return this address to the user, remember to + strip off the ::ffff:0.0.0.0/96 prefix first. */ + int fd = grpc_accept4(sp->fd, (struct sockaddr *)&addr, &addrlen, 1, 1); + if (fd < 0) { + switch (errno) { + case EINTR: + continue; + case EAGAIN: + grpc_fd_notify_on_read(exec_ctx, sp->emfd, &sp->read_closure); + return; + default: + gpr_log(GPR_ERROR, "Failed accept4: %s", strerror(errno)); + goto error; + } + } + + grpc_set_socket_no_sigpipe_if_possible(fd); + + addr_str = grpc_sockaddr_to_uri((struct sockaddr *)&addr); + gpr_asprintf(&name, "tcp-server-connection:%s", addr_str); + + if (grpc_tcp_trace) { + gpr_log(GPR_DEBUG, "SERVER_CONNECT: incoming connection: %s", addr_str); + } + + fdobj = grpc_fd_create(fd, name); + /* TODO(ctiller): revise this when we have server-side sharding + of channels -- we certainly should not be automatically adding every + incoming channel to every pollset owned by the server */ + for (i = 0; i < sp->server->pollset_count; i++) { + grpc_pollset_add_fd(exec_ctx, sp->server->pollsets[i], fdobj); + } + sp->server->on_accept_cb( + exec_ctx, sp->server->on_accept_cb_arg, + grpc_tcp_create(fdobj, GRPC_TCP_DEFAULT_READ_SLICE_SIZE, addr_str), + &acceptor); + + gpr_free(name); + gpr_free(addr_str); + } + + GPR_UNREACHABLE_CODE(return ); + +error: + gpr_mu_lock(&sp->server->mu); + if (0 == --sp->server->active_ports) { + gpr_mu_unlock(&sp->server->mu); + deactivated_all_ports(exec_ctx, sp->server); + } else { + gpr_mu_unlock(&sp->server->mu); + } +} + +static grpc_tcp_listener *add_socket_to_server(grpc_tcp_server *s, int fd, + const struct sockaddr *addr, + size_t addr_len, + unsigned port_index, + unsigned fd_index) { + grpc_tcp_listener *sp = NULL; + int port; + char *addr_str; + char *name; + + port = prepare_socket(fd, addr, addr_len); + if (port >= 0) { + grpc_sockaddr_to_string(&addr_str, (struct sockaddr *)&addr, 1); + gpr_asprintf(&name, "tcp-server-listener:%s", addr_str); + gpr_mu_lock(&s->mu); + s->nports++; + GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server"); + sp = gpr_malloc(sizeof(grpc_tcp_listener)); + sp->next = NULL; + if (s->head == NULL) { + s->head = sp; + } else { + s->tail->next = sp; + } + s->tail = sp; + sp->server = s; + sp->fd = fd; + sp->emfd = grpc_fd_create(fd, name); + memcpy(sp->addr.untyped, addr, addr_len); + sp->addr_len = addr_len; + sp->port = port; + sp->port_index = port_index; + sp->fd_index = fd_index; + sp->is_sibling = 0; + sp->sibling = NULL; + GPR_ASSERT(sp->emfd); + gpr_mu_unlock(&s->mu); + gpr_free(addr_str); + gpr_free(name); + } + + return sp; +} + +int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr, + size_t addr_len) { + grpc_tcp_listener *sp; + grpc_tcp_listener *sp2 = NULL; + int fd; + grpc_dualstack_mode dsmode; + struct sockaddr_in6 addr6_v4mapped; + struct sockaddr_in wild4; + struct sockaddr_in6 wild6; + struct sockaddr_in addr4_copy; + struct sockaddr *allocated_addr = NULL; + struct sockaddr_storage sockname_temp; + socklen_t sockname_len; + int port; + unsigned port_index = 0; + unsigned fd_index = 0; + if (s->tail != NULL) { + port_index = s->tail->port_index + 1; + } + grpc_unlink_if_unix_domain_socket((struct sockaddr *)addr); + + /* Check if this is a wildcard port, and if so, try to keep the port the same + as some previously created listener. */ + if (grpc_sockaddr_get_port(addr) == 0) { + for (sp = s->head; sp; sp = sp->next) { + sockname_len = sizeof(sockname_temp); + if (0 == getsockname(sp->fd, (struct sockaddr *)&sockname_temp, + &sockname_len)) { + port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp); + if (port > 0) { + allocated_addr = malloc(addr_len); + memcpy(allocated_addr, addr, addr_len); + grpc_sockaddr_set_port(allocated_addr, port); + addr = allocated_addr; + break; + } + } + } + } + + sp = NULL; + + if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) { + addr = (const struct sockaddr *)&addr6_v4mapped; + addr_len = sizeof(addr6_v4mapped); + } + + /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */ + if (grpc_sockaddr_is_wildcard(addr, &port)) { + grpc_sockaddr_make_wildcards(port, &wild4, &wild6); + + /* Try listening on IPv6 first. */ + addr = (struct sockaddr *)&wild6; + addr_len = sizeof(wild6); + fd = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode); + sp = add_socket_to_server(s, fd, addr, addr_len, port_index, fd_index); + if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) { + goto done; + } + if (sp != NULL) { + ++fd_index; + } + /* If we didn't get a dualstack socket, also listen on 0.0.0.0. */ + if (port == 0 && sp != NULL) { + grpc_sockaddr_set_port((struct sockaddr *)&wild4, sp->port); + } + addr = (struct sockaddr *)&wild4; + addr_len = sizeof(wild4); + } + + fd = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode); + if (fd < 0) { + gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno)); + } else { + if (dsmode == GRPC_DSMODE_IPV4 && + grpc_sockaddr_is_v4mapped(addr, &addr4_copy)) { + addr = (struct sockaddr *)&addr4_copy; + addr_len = sizeof(addr4_copy); + } + sp2 = sp; + sp = add_socket_to_server(s, fd, addr, addr_len, port_index, fd_index); + if (sp2 != NULL && sp != NULL) { + sp2->sibling = sp; + sp->is_sibling = 1; + } + } + +done: + gpr_free(allocated_addr); + if (sp != NULL) { + return sp->port; + } else { + return -1; + } +} + +unsigned grpc_tcp_server_port_fd_count(grpc_tcp_server *s, + unsigned port_index) { + unsigned num_fds = 0; + grpc_tcp_listener *sp; + for (sp = s->head; sp && port_index != 0; sp = sp->next) { + if (!sp->is_sibling) { + --port_index; + } + } + for (; sp; sp = sp->sibling, ++num_fds) + ; + return num_fds; +} + +int grpc_tcp_server_port_fd(grpc_tcp_server *s, unsigned port_index, + unsigned fd_index) { + grpc_tcp_listener *sp; + for (sp = s->head; sp && port_index != 0; sp = sp->next) { + if (!sp->is_sibling) { + --port_index; + } + } + for (; sp && fd_index != 0; sp = sp->sibling, --fd_index) + ; + if (sp) { + return sp->fd; + } else { + return -1; + } +} + +void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s, + grpc_pollset **pollsets, size_t pollset_count, + grpc_tcp_server_cb on_accept_cb, + void *on_accept_cb_arg) { + size_t i; + grpc_tcp_listener *sp; + GPR_ASSERT(on_accept_cb); + gpr_mu_lock(&s->mu); + GPR_ASSERT(!s->on_accept_cb); + GPR_ASSERT(s->active_ports == 0); + s->on_accept_cb = on_accept_cb; + s->on_accept_cb_arg = on_accept_cb_arg; + s->pollsets = pollsets; + s->pollset_count = pollset_count; + for (sp = s->head; sp; sp = sp->next) { + for (i = 0; i < pollset_count; i++) { + grpc_pollset_add_fd(exec_ctx, pollsets[i], sp->emfd); + } + sp->read_closure.cb = on_read; + sp->read_closure.cb_arg = sp; + grpc_fd_notify_on_read(exec_ctx, sp->emfd, &sp->read_closure); + s->active_ports++; + } + gpr_mu_unlock(&s->mu); +} + +grpc_tcp_server *grpc_tcp_server_ref(grpc_tcp_server *s) { + gpr_ref(&s->refs); + return s; +} + +void grpc_tcp_server_shutdown_starting_add(grpc_tcp_server *s, + grpc_closure *shutdown_starting) { + gpr_mu_lock(&s->mu); + grpc_closure_list_add(&s->shutdown_starting, shutdown_starting, 1); + gpr_mu_unlock(&s->mu); +} + +void grpc_tcp_server_unref(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { + if (gpr_unref(&s->refs)) { + /* Complete shutdown_starting work before destroying. */ + grpc_exec_ctx local_exec_ctx = GRPC_EXEC_CTX_INIT; + gpr_mu_lock(&s->mu); + grpc_exec_ctx_enqueue_list(&local_exec_ctx, &s->shutdown_starting, NULL); + gpr_mu_unlock(&s->mu); + if (exec_ctx == NULL) { + grpc_exec_ctx_flush(&local_exec_ctx); + tcp_server_destroy(&local_exec_ctx, s); + grpc_exec_ctx_finish(&local_exec_ctx); + } else { + grpc_exec_ctx_finish(&local_exec_ctx); + tcp_server_destroy(exec_ctx, s); + } + } +} + +#endif diff --git a/src/core/lib/iomgr/tcp_server_windows.c b/src/core/lib/iomgr/tcp_server_windows.c new file mode 100644 index 0000000000..a4abc5b974 --- /dev/null +++ b/src/core/lib/iomgr/tcp_server_windows.c @@ -0,0 +1,557 @@ +/* + * + * Copyright 2015-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 + +#ifdef GPR_WINSOCK_SOCKET + +#include + +#include "src/core/iomgr/sockaddr_utils.h" + +#include +#include +#include +#include +#include +#include + +#include "src/core/iomgr/iocp_windows.h" +#include "src/core/iomgr/pollset_windows.h" +#include "src/core/iomgr/socket_windows.h" +#include "src/core/iomgr/tcp_server.h" +#include "src/core/iomgr/tcp_windows.h" + +#define MIN_SAFE_ACCEPT_QUEUE_SIZE 100 + +/* one listening port */ +typedef struct grpc_tcp_listener grpc_tcp_listener; +struct grpc_tcp_listener { + /* This seemingly magic number comes from AcceptEx's documentation. each + address buffer needs to have at least 16 more bytes at their end. */ + uint8_t addresses[(sizeof(struct sockaddr_in6) + 16) * 2]; + /* This will hold the socket for the next accept. */ + SOCKET new_socket; + /* The listener winsocket. */ + grpc_winsocket *socket; + /* The actual TCP port number. */ + int port; + unsigned port_index; + grpc_tcp_server *server; + /* The cached AcceptEx for that port. */ + LPFN_ACCEPTEX AcceptEx; + int shutting_down; + /* closure for socket notification of accept being ready */ + grpc_closure on_accept; + /* linked list */ + struct grpc_tcp_listener *next; +}; + +/* the overall server */ +struct grpc_tcp_server { + gpr_refcount refs; + /* Called whenever accept() succeeds on a server port. */ + grpc_tcp_server_cb on_accept_cb; + void *on_accept_cb_arg; + + gpr_mu mu; + + /* active port count: how many ports are actually still listening */ + int active_ports; + + /* linked list of server ports */ + grpc_tcp_listener *head; + grpc_tcp_listener *tail; + + /* List of closures passed to shutdown_starting_add(). */ + grpc_closure_list shutdown_starting; + + /* shutdown callback */ + grpc_closure *shutdown_complete; +}; + +/* Public function. Allocates the proper data structures to hold a + grpc_tcp_server. */ +grpc_tcp_server *grpc_tcp_server_create(grpc_closure *shutdown_complete) { + grpc_tcp_server *s = gpr_malloc(sizeof(grpc_tcp_server)); + gpr_ref_init(&s->refs, 1); + gpr_mu_init(&s->mu); + s->active_ports = 0; + s->on_accept_cb = NULL; + s->on_accept_cb_arg = NULL; + s->head = NULL; + s->tail = NULL; + s->shutdown_starting.head = NULL; + s->shutdown_starting.tail = NULL; + s->shutdown_complete = shutdown_complete; + return s; +} + +static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { + if (s->shutdown_complete != NULL) { + grpc_exec_ctx_enqueue(exec_ctx, s->shutdown_complete, true, NULL); + } + + /* Now that the accepts have been aborted, we can destroy the sockets. + The IOCP won't get notified on these, so we can flag them as already + closed by the system. */ + while (s->head) { + grpc_tcp_listener *sp = s->head; + s->head = sp->next; + sp->next = NULL; + grpc_winsocket_destroy(sp->socket); + gpr_free(sp); + } + gpr_free(s); +} + +grpc_tcp_server *grpc_tcp_server_ref(grpc_tcp_server *s) { + gpr_ref(&s->refs); + return s; +} + +void grpc_tcp_server_shutdown_starting_add(grpc_tcp_server *s, + grpc_closure *shutdown_starting) { + gpr_mu_lock(&s->mu); + grpc_closure_list_add(&s->shutdown_starting, shutdown_starting, 1); + gpr_mu_unlock(&s->mu); +} + +static void tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { + int immediately_done = 0; + grpc_tcp_listener *sp; + gpr_mu_lock(&s->mu); + + /* First, shutdown all fd's. This will queue abortion calls for all + of the pending accepts due to the normal operation mechanism. */ + if (s->active_ports == 0) { + immediately_done = 1; + } + for (sp = s->head; sp; sp = sp->next) { + sp->shutting_down = 1; + grpc_winsocket_shutdown(sp->socket); + } + gpr_mu_unlock(&s->mu); + + if (immediately_done) { + finish_shutdown(exec_ctx, s); + } +} + +void grpc_tcp_server_unref(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { + if (gpr_unref(&s->refs)) { + /* Complete shutdown_starting work before destroying. */ + grpc_exec_ctx local_exec_ctx = GRPC_EXEC_CTX_INIT; + gpr_mu_lock(&s->mu); + grpc_exec_ctx_enqueue_list(&local_exec_ctx, &s->shutdown_starting, NULL); + gpr_mu_unlock(&s->mu); + if (exec_ctx == NULL) { + grpc_exec_ctx_flush(&local_exec_ctx); + tcp_server_destroy(&local_exec_ctx, s); + grpc_exec_ctx_finish(&local_exec_ctx); + } else { + grpc_exec_ctx_finish(&local_exec_ctx); + tcp_server_destroy(exec_ctx, s); + } + } +} + +/* Prepare (bind) a recently-created socket for listening. */ +static int prepare_socket(SOCKET sock, const struct sockaddr *addr, + size_t addr_len) { + struct sockaddr_storage sockname_temp; + socklen_t sockname_len; + + if (sock == INVALID_SOCKET) goto error; + + if (!grpc_tcp_prepare_socket(sock)) { + char *utf8_message = gpr_format_message(WSAGetLastError()); + gpr_log(GPR_ERROR, "Unable to prepare socket: %s", utf8_message); + gpr_free(utf8_message); + goto error; + } + + if (bind(sock, addr, (int)addr_len) == SOCKET_ERROR) { + char *addr_str; + char *utf8_message = gpr_format_message(WSAGetLastError()); + grpc_sockaddr_to_string(&addr_str, addr, 0); + gpr_log(GPR_ERROR, "bind addr=%s: %s", addr_str, utf8_message); + gpr_free(utf8_message); + gpr_free(addr_str); + goto error; + } + + if (listen(sock, SOMAXCONN) == SOCKET_ERROR) { + char *utf8_message = gpr_format_message(WSAGetLastError()); + gpr_log(GPR_ERROR, "listen: %s", utf8_message); + gpr_free(utf8_message); + goto error; + } + + sockname_len = sizeof(sockname_temp); + if (getsockname(sock, (struct sockaddr *)&sockname_temp, &sockname_len) == + SOCKET_ERROR) { + char *utf8_message = gpr_format_message(WSAGetLastError()); + gpr_log(GPR_ERROR, "getsockname: %s", utf8_message); + gpr_free(utf8_message); + goto error; + } + + return grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp); + +error: + if (sock != INVALID_SOCKET) closesocket(sock); + return -1; +} + +static void decrement_active_ports_and_notify(grpc_exec_ctx *exec_ctx, + grpc_tcp_listener *sp) { + int notify = 0; + sp->shutting_down = 0; + gpr_mu_lock(&sp->server->mu); + GPR_ASSERT(sp->server->active_ports > 0); + if (0 == --sp->server->active_ports) { + notify = 1; + } + gpr_mu_unlock(&sp->server->mu); + if (notify) { + finish_shutdown(exec_ctx, sp->server); + } +} + +/* In order to do an async accept, we need to create a socket first which + will be the one assigned to the new incoming connection. */ +static void start_accept(grpc_exec_ctx *exec_ctx, grpc_tcp_listener *port) { + SOCKET sock = INVALID_SOCKET; + char *message; + char *utf8_message; + BOOL success; + DWORD addrlen = sizeof(struct sockaddr_in6) + 16; + DWORD bytes_received = 0; + + sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0, + WSA_FLAG_OVERLAPPED); + + if (sock == INVALID_SOCKET) { + message = "Unable to create socket: %s"; + goto failure; + } + + if (!grpc_tcp_prepare_socket(sock)) { + message = "Unable to prepare socket: %s"; + goto failure; + } + + /* Start the "accept" asynchronously. */ + success = port->AcceptEx(port->socket->socket, sock, port->addresses, 0, + addrlen, addrlen, &bytes_received, + &port->socket->read_info.overlapped); + + /* It is possible to get an accept immediately without delay. However, we + will still get an IOCP notification for it. So let's just ignore it. */ + if (!success) { + int error = WSAGetLastError(); + if (error != ERROR_IO_PENDING) { + message = "AcceptEx failed: %s"; + goto failure; + } + } + + /* We're ready to do the accept. Calling grpc_socket_notify_on_read may + immediately process an accept that happened in the meantime. */ + port->new_socket = sock; + grpc_socket_notify_on_read(exec_ctx, port->socket, &port->on_accept); + return; + +failure: + if (port->shutting_down) { + /* We are abandoning the listener port, take that into account to prevent + occasional hangs on shutdown. The hang happens when sp->shutting_down + change is not seen by on_accept and we proceed to trying new accept, + but we fail there because the listening port has been closed in the + meantime. */ + decrement_active_ports_and_notify(exec_ctx, port); + return; + } + utf8_message = gpr_format_message(WSAGetLastError()); + gpr_log(GPR_ERROR, message, utf8_message); + gpr_free(utf8_message); + if (sock != INVALID_SOCKET) closesocket(sock); +} + +/* Event manager callback when reads are ready. */ +static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, bool from_iocp) { + grpc_tcp_listener *sp = arg; + grpc_tcp_server_acceptor acceptor = {sp->server, sp->port_index, 0}; + SOCKET sock = sp->new_socket; + grpc_winsocket_callback_info *info = &sp->socket->read_info; + grpc_endpoint *ep = NULL; + struct sockaddr_storage peer_name; + char *peer_name_string; + char *fd_name; + int peer_name_len = sizeof(peer_name); + DWORD transfered_bytes; + DWORD flags; + BOOL wsa_success; + int err; + + /* The general mechanism for shutting down is to queue abortion calls. While + this is necessary in the read/write case, it's useless for the accept + case. We only need to adjust the pending callback count */ + if (!from_iocp) { + return; + } + + /* The IOCP notified us of a completed operation. Let's grab the results, + and act accordingly. */ + transfered_bytes = 0; + wsa_success = WSAGetOverlappedResult(sock, &info->overlapped, + &transfered_bytes, FALSE, &flags); + if (!wsa_success) { + if (sp->shutting_down) { + /* During the shutdown case, we ARE expecting an error. So that's well, + and we can wake up the shutdown thread. */ + decrement_active_ports_and_notify(exec_ctx, sp); + return; + } else { + char *utf8_message = gpr_format_message(WSAGetLastError()); + gpr_log(GPR_ERROR, "on_accept error: %s", utf8_message); + gpr_free(utf8_message); + closesocket(sock); + } + } else { + if (!sp->shutting_down) { + peer_name_string = NULL; + err = setsockopt(sock, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, + (char *)&sp->socket->socket, sizeof(sp->socket->socket)); + if (err) { + char *utf8_message = gpr_format_message(WSAGetLastError()); + gpr_log(GPR_ERROR, "setsockopt error: %s", utf8_message); + gpr_free(utf8_message); + } + err = getpeername(sock, (struct sockaddr *)&peer_name, &peer_name_len); + if (!err) { + peer_name_string = grpc_sockaddr_to_uri((struct sockaddr *)&peer_name); + } else { + char *utf8_message = gpr_format_message(WSAGetLastError()); + gpr_log(GPR_ERROR, "getpeername error: %s", utf8_message); + gpr_free(utf8_message); + } + gpr_asprintf(&fd_name, "tcp_server:%s", peer_name_string); + ep = grpc_tcp_create(grpc_winsocket_create(sock, fd_name), + peer_name_string); + gpr_free(fd_name); + gpr_free(peer_name_string); + } else { + closesocket(sock); + } + } + + /* The only time we should call our callback, is where we successfully + managed to accept a connection, and created an endpoint. */ + if (ep) + sp->server->on_accept_cb(exec_ctx, sp->server->on_accept_cb_arg, ep, + &acceptor); + /* As we were notified from the IOCP of one and exactly one accept, + the former socked we created has now either been destroy or assigned + to the new connection. We need to create a new one for the next + connection. */ + start_accept(exec_ctx, sp); +} + +static grpc_tcp_listener *add_socket_to_server(grpc_tcp_server *s, SOCKET sock, + const struct sockaddr *addr, + size_t addr_len, + unsigned port_index) { + grpc_tcp_listener *sp = NULL; + int port; + int status; + GUID guid = WSAID_ACCEPTEX; + DWORD ioctl_num_bytes; + LPFN_ACCEPTEX AcceptEx; + + if (sock == INVALID_SOCKET) return NULL; + + /* We need to grab the AcceptEx pointer for that port, as it may be + interface-dependent. We'll cache it to avoid doing that again. */ + status = + WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid), + &AcceptEx, sizeof(AcceptEx), &ioctl_num_bytes, NULL, NULL); + + if (status != 0) { + char *utf8_message = gpr_format_message(WSAGetLastError()); + gpr_log(GPR_ERROR, "on_connect error: %s", utf8_message); + gpr_free(utf8_message); + closesocket(sock); + return NULL; + } + + port = prepare_socket(sock, addr, addr_len); + if (port >= 0) { + gpr_mu_lock(&s->mu); + GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server"); + sp = gpr_malloc(sizeof(grpc_tcp_listener)); + sp->next = NULL; + if (s->head == NULL) { + s->head = sp; + } else { + s->tail->next = sp; + } + s->tail = sp; + sp->server = s; + sp->socket = grpc_winsocket_create(sock, "listener"); + sp->shutting_down = 0; + sp->AcceptEx = AcceptEx; + sp->new_socket = INVALID_SOCKET; + sp->port = port; + sp->port_index = port_index; + grpc_closure_init(&sp->on_accept, on_accept, sp); + GPR_ASSERT(sp->socket); + gpr_mu_unlock(&s->mu); + } + + return sp; +} + +int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr, + size_t addr_len) { + grpc_tcp_listener *sp; + SOCKET sock; + struct sockaddr_in6 addr6_v4mapped; + struct sockaddr_in6 wildcard; + struct sockaddr *allocated_addr = NULL; + struct sockaddr_storage sockname_temp; + socklen_t sockname_len; + int port; + unsigned port_index = 0; + if (s->tail != NULL) { + port_index = s->tail->port_index + 1; + } + + /* Check if this is a wildcard port, and if so, try to keep the port the same + as some previously created listener. */ + if (grpc_sockaddr_get_port(addr) == 0) { + for (sp = s->head; sp; sp = sp->next) { + sockname_len = sizeof(sockname_temp); + if (0 == getsockname(sp->socket->socket, + (struct sockaddr *)&sockname_temp, &sockname_len)) { + port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp); + if (port > 0) { + allocated_addr = malloc(addr_len); + memcpy(allocated_addr, addr, addr_len); + grpc_sockaddr_set_port(allocated_addr, port); + addr = allocated_addr; + break; + } + } + } + } + + if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) { + addr = (const struct sockaddr *)&addr6_v4mapped; + addr_len = sizeof(addr6_v4mapped); + } + + /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */ + if (grpc_sockaddr_is_wildcard(addr, &port)) { + grpc_sockaddr_make_wildcard6(port, &wildcard); + + addr = (struct sockaddr *)&wildcard; + addr_len = sizeof(wildcard); + } + + sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0, + WSA_FLAG_OVERLAPPED); + if (sock == INVALID_SOCKET) { + char *utf8_message = gpr_format_message(WSAGetLastError()); + gpr_log(GPR_ERROR, "unable to create socket: %s", utf8_message); + gpr_free(utf8_message); + } + + sp = add_socket_to_server(s, sock, addr, addr_len, port_index); + gpr_free(allocated_addr); + + if (sp) { + return sp->port; + } else { + return -1; + } +} + +unsigned grpc_tcp_server_port_fd_count(grpc_tcp_server *s, + unsigned port_index) { + grpc_tcp_listener *sp; + for (sp = s->head; sp && port_index != 0; sp = sp->next, --port_index) + ; + if (sp) { + return 1; + } else { + return 0; + } +} + +int grpc_tcp_server_port_fd(grpc_tcp_server *s, unsigned port_index, + unsigned fd_index) { + grpc_tcp_listener *sp; + if (fd_index != 0) { + /* Windows implementation has only one fd per port_index. */ + return -1; + } + for (sp = s->head; sp && port_index != 0; sp = sp->next, --port_index) + ; + if (sp) { + return _open_osfhandle((intptr_t)sp->socket->socket, 0); + } else { + return -1; + } +} + +void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s, + grpc_pollset **pollset, size_t pollset_count, + grpc_tcp_server_cb on_accept_cb, + void *on_accept_cb_arg) { + grpc_tcp_listener *sp; + GPR_ASSERT(on_accept_cb); + gpr_mu_lock(&s->mu); + GPR_ASSERT(!s->on_accept_cb); + GPR_ASSERT(s->active_ports == 0); + s->on_accept_cb = on_accept_cb; + s->on_accept_cb_arg = on_accept_cb_arg; + for (sp = s->head; sp; sp = sp->next) { + start_accept(exec_ctx, sp); + s->active_ports++; + } + gpr_mu_unlock(&s->mu); +} + +#endif /* GPR_WINSOCK_SOCKET */ diff --git a/src/core/lib/iomgr/tcp_windows.c b/src/core/lib/iomgr/tcp_windows.c new file mode 100644 index 0000000000..9b1db5fa7e --- /dev/null +++ b/src/core/lib/iomgr/tcp_windows.c @@ -0,0 +1,402 @@ +/* + * + * Copyright 2015-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 + +#ifdef GPR_WINSOCK_SOCKET + +#include "src/core/iomgr/sockaddr_win32.h" + +#include +#include +#include +#include +#include +#include + +#include "src/core/iomgr/iocp_windows.h" +#include "src/core/iomgr/sockaddr.h" +#include "src/core/iomgr/sockaddr_utils.h" +#include "src/core/iomgr/socket_windows.h" +#include "src/core/iomgr/tcp_client.h" +#include "src/core/iomgr/timer.h" + +static int set_non_block(SOCKET sock) { + int status; + unsigned long param = 1; + DWORD ret; + status = + WSAIoctl(sock, FIONBIO, ¶m, sizeof(param), NULL, 0, &ret, NULL, NULL); + return status == 0; +} + +static int set_dualstack(SOCKET sock) { + int status; + unsigned long param = 0; + status = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)¶m, + sizeof(param)); + return status == 0; +} + +int grpc_tcp_prepare_socket(SOCKET sock) { + if (!set_non_block(sock)) return 0; + if (!set_dualstack(sock)) return 0; + return 1; +} + +typedef struct grpc_tcp { + /* This is our C++ class derivation emulation. */ + grpc_endpoint base; + /* The one socket this endpoint is using. */ + grpc_winsocket *socket; + /* Refcounting how many operations are in progress. */ + gpr_refcount refcount; + + grpc_closure on_read; + grpc_closure on_write; + + grpc_closure *read_cb; + grpc_closure *write_cb; + gpr_slice read_slice; + gpr_slice_buffer *write_slices; + gpr_slice_buffer *read_slices; + + /* The IO Completion Port runs from another thread. We need some mechanism + to protect ourselves when requesting a shutdown. */ + gpr_mu mu; + int shutting_down; + + char *peer_string; +} grpc_tcp; + +static void tcp_free(grpc_tcp *tcp) { + grpc_winsocket_destroy(tcp->socket); + gpr_mu_destroy(&tcp->mu); + gpr_free(tcp->peer_string); + gpr_free(tcp); +} + +/*#define GRPC_TCP_REFCOUNT_DEBUG*/ +#ifdef GRPC_TCP_REFCOUNT_DEBUG +#define TCP_UNREF(tcp, reason) tcp_unref((tcp), (reason), __FILE__, __LINE__) +#define TCP_REF(tcp, reason) tcp_ref((tcp), (reason), __FILE__, __LINE__) +static void tcp_unref(grpc_tcp *tcp, const char *reason, const char *file, + int line) { + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP unref %p : %s %d -> %d", tcp, + reason, tcp->refcount.count, tcp->refcount.count - 1); + if (gpr_unref(&tcp->refcount)) { + tcp_free(tcp); + } +} + +static void tcp_ref(grpc_tcp *tcp, const char *reason, const char *file, + int line) { + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP ref %p : %s %d -> %d", tcp, + reason, tcp->refcount.count, tcp->refcount.count + 1); + gpr_ref(&tcp->refcount); +} +#else +#define TCP_UNREF(tcp, reason) tcp_unref((tcp)) +#define TCP_REF(tcp, reason) tcp_ref((tcp)) +static void tcp_unref(grpc_tcp *tcp) { + if (gpr_unref(&tcp->refcount)) { + tcp_free(tcp); + } +} + +static void tcp_ref(grpc_tcp *tcp) { gpr_ref(&tcp->refcount); } +#endif + +/* Asynchronous callback from the IOCP, or the background thread. */ +static void on_read(grpc_exec_ctx *exec_ctx, void *tcpp, bool success) { + grpc_tcp *tcp = tcpp; + grpc_closure *cb = tcp->read_cb; + grpc_winsocket *socket = tcp->socket; + gpr_slice sub; + grpc_winsocket_callback_info *info = &socket->read_info; + + if (success) { + if (info->wsa_error != 0 && !tcp->shutting_down) { + if (info->wsa_error != WSAECONNRESET) { + char *utf8_message = gpr_format_message(info->wsa_error); + gpr_log(GPR_ERROR, "ReadFile overlapped error: %s", utf8_message); + gpr_free(utf8_message); + } + success = 0; + gpr_slice_unref(tcp->read_slice); + } else { + if (info->bytes_transfered != 0 && !tcp->shutting_down) { + sub = gpr_slice_sub_no_ref(tcp->read_slice, 0, info->bytes_transfered); + gpr_slice_buffer_add(tcp->read_slices, sub); + success = 1; + } else { + gpr_slice_unref(tcp->read_slice); + success = 0; + } + } + } + + tcp->read_cb = NULL; + TCP_UNREF(tcp, "read"); + if (cb) { + cb->cb(exec_ctx, cb->cb_arg, success); + } +} + +static void win_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, + gpr_slice_buffer *read_slices, grpc_closure *cb) { + grpc_tcp *tcp = (grpc_tcp *)ep; + grpc_winsocket *handle = tcp->socket; + grpc_winsocket_callback_info *info = &handle->read_info; + int status; + DWORD bytes_read = 0; + DWORD flags = 0; + WSABUF buffer; + + if (tcp->shutting_down) { + grpc_exec_ctx_enqueue(exec_ctx, cb, false, NULL); + return; + } + + tcp->read_cb = cb; + tcp->read_slices = read_slices; + gpr_slice_buffer_reset_and_unref(read_slices); + + tcp->read_slice = gpr_slice_malloc(8192); + + buffer.len = (ULONG)GPR_SLICE_LENGTH( + tcp->read_slice); // we know slice size fits in 32bit. + buffer.buf = (char *)GPR_SLICE_START_PTR(tcp->read_slice); + + TCP_REF(tcp, "read"); + + /* First let's try a synchronous, non-blocking read. */ + status = + WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags, NULL, NULL); + info->wsa_error = status == 0 ? 0 : WSAGetLastError(); + + /* Did we get data immediately ? Yay. */ + if (info->wsa_error != WSAEWOULDBLOCK) { + info->bytes_transfered = bytes_read; + grpc_exec_ctx_enqueue(exec_ctx, &tcp->on_read, true, NULL); + return; + } + + /* Otherwise, let's retry, by queuing a read. */ + memset(&tcp->socket->read_info.overlapped, 0, sizeof(OVERLAPPED)); + status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags, + &info->overlapped, NULL); + + if (status != 0) { + int wsa_error = WSAGetLastError(); + if (wsa_error != WSA_IO_PENDING) { + info->wsa_error = wsa_error; + grpc_exec_ctx_enqueue(exec_ctx, &tcp->on_read, false, NULL); + return; + } + } + + grpc_socket_notify_on_read(exec_ctx, tcp->socket, &tcp->on_read); +} + +/* Asynchronous callback from the IOCP, or the background thread. */ +static void on_write(grpc_exec_ctx *exec_ctx, void *tcpp, bool success) { + grpc_tcp *tcp = (grpc_tcp *)tcpp; + grpc_winsocket *handle = tcp->socket; + grpc_winsocket_callback_info *info = &handle->write_info; + grpc_closure *cb; + + gpr_mu_lock(&tcp->mu); + cb = tcp->write_cb; + tcp->write_cb = NULL; + gpr_mu_unlock(&tcp->mu); + + if (success) { + if (info->wsa_error != 0) { + if (info->wsa_error != WSAECONNRESET) { + char *utf8_message = gpr_format_message(info->wsa_error); + gpr_log(GPR_ERROR, "WSASend overlapped error: %s", utf8_message); + gpr_free(utf8_message); + } + success = 0; + } else { + GPR_ASSERT(info->bytes_transfered == tcp->write_slices->length); + } + } + + TCP_UNREF(tcp, "write"); + cb->cb(exec_ctx, cb->cb_arg, success); +} + +/* Initiates a write. */ +static void win_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, + gpr_slice_buffer *slices, grpc_closure *cb) { + grpc_tcp *tcp = (grpc_tcp *)ep; + grpc_winsocket *socket = tcp->socket; + grpc_winsocket_callback_info *info = &socket->write_info; + unsigned i; + DWORD bytes_sent; + int status; + WSABUF local_buffers[16]; + WSABUF *allocated = NULL; + WSABUF *buffers = local_buffers; + size_t len; + + if (tcp->shutting_down) { + grpc_exec_ctx_enqueue(exec_ctx, cb, false, NULL); + return; + } + + tcp->write_cb = cb; + tcp->write_slices = slices; + GPR_ASSERT(tcp->write_slices->count <= UINT_MAX); + if (tcp->write_slices->count > GPR_ARRAY_SIZE(local_buffers)) { + buffers = (WSABUF *)gpr_malloc(sizeof(WSABUF) * tcp->write_slices->count); + allocated = buffers; + } + + for (i = 0; i < tcp->write_slices->count; i++) { + len = GPR_SLICE_LENGTH(tcp->write_slices->slices[i]); + GPR_ASSERT(len <= ULONG_MAX); + buffers[i].len = (ULONG)len; + buffers[i].buf = (char *)GPR_SLICE_START_PTR(tcp->write_slices->slices[i]); + } + + /* First, let's try a synchronous, non-blocking write. */ + status = WSASend(socket->socket, buffers, (DWORD)tcp->write_slices->count, + &bytes_sent, 0, NULL, NULL); + info->wsa_error = status == 0 ? 0 : WSAGetLastError(); + + /* We would kind of expect to get a WSAEWOULDBLOCK here, especially on a busy + connection that has its send queue filled up. But if we don't, then we can + avoid doing an async write operation at all. */ + if (info->wsa_error != WSAEWOULDBLOCK) { + bool ok = false; + if (status == 0) { + ok = true; + GPR_ASSERT(bytes_sent == tcp->write_slices->length); + } else { + if (info->wsa_error != WSAECONNRESET) { + char *utf8_message = gpr_format_message(info->wsa_error); + gpr_log(GPR_ERROR, "WSASend error: %s", utf8_message); + gpr_free(utf8_message); + } + } + if (allocated) gpr_free(allocated); + grpc_exec_ctx_enqueue(exec_ctx, cb, ok, NULL); + return; + } + + TCP_REF(tcp, "write"); + + /* If we got a WSAEWOULDBLOCK earlier, then we need to re-do the same + operation, this time asynchronously. */ + memset(&socket->write_info.overlapped, 0, sizeof(OVERLAPPED)); + status = WSASend(socket->socket, buffers, (DWORD)tcp->write_slices->count, + &bytes_sent, 0, &socket->write_info.overlapped, NULL); + if (allocated) gpr_free(allocated); + + if (status != 0) { + int wsa_error = WSAGetLastError(); + if (wsa_error != WSA_IO_PENDING) { + TCP_UNREF(tcp, "write"); + grpc_exec_ctx_enqueue(exec_ctx, cb, false, NULL); + return; + } + } + + /* As all is now setup, we can now ask for the IOCP notification. It may + trigger the callback immediately however, but no matter. */ + grpc_socket_notify_on_write(exec_ctx, socket, &tcp->on_write); +} + +static void win_add_to_pollset(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, + grpc_pollset *ps) { + grpc_tcp *tcp; + (void)ps; + tcp = (grpc_tcp *)ep; + grpc_iocp_add_socket(tcp->socket); +} + +static void win_add_to_pollset_set(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, + grpc_pollset_set *pss) { + grpc_tcp *tcp; + (void)pss; + tcp = (grpc_tcp *)ep; + grpc_iocp_add_socket(tcp->socket); +} + +/* Initiates a shutdown of the TCP endpoint. This will queue abort callbacks + for the potential read and write operations. It is up to the caller to + guarantee this isn't called in parallel to a read or write request, so + we're not going to protect against these. However the IO Completion Port + callback will happen from another thread, so we need to protect against + concurrent access of the data structure in that regard. */ +static void win_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) { + grpc_tcp *tcp = (grpc_tcp *)ep; + gpr_mu_lock(&tcp->mu); + /* At that point, what may happen is that we're already inside the IOCP + callback. See the comments in on_read and on_write. */ + tcp->shutting_down = 1; + grpc_winsocket_shutdown(tcp->socket); + gpr_mu_unlock(&tcp->mu); +} + +static void win_destroy(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) { + grpc_tcp *tcp = (grpc_tcp *)ep; + TCP_UNREF(tcp, "destroy"); +} + +static char *win_get_peer(grpc_endpoint *ep) { + grpc_tcp *tcp = (grpc_tcp *)ep; + return gpr_strdup(tcp->peer_string); +} + +static grpc_endpoint_vtable vtable = { + win_read, win_write, win_add_to_pollset, win_add_to_pollset_set, + win_shutdown, win_destroy, win_get_peer}; + +grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket, char *peer_string) { + grpc_tcp *tcp = (grpc_tcp *)gpr_malloc(sizeof(grpc_tcp)); + memset(tcp, 0, sizeof(grpc_tcp)); + tcp->base.vtable = &vtable; + tcp->socket = socket; + gpr_mu_init(&tcp->mu); + gpr_ref_init(&tcp->refcount, 1); + grpc_closure_init(&tcp->on_read, on_read, tcp); + grpc_closure_init(&tcp->on_write, on_write, tcp); + tcp->peer_string = gpr_strdup(peer_string); + return &tcp->base; +} + +#endif /* GPR_WINSOCK_SOCKET */ diff --git a/src/core/lib/iomgr/tcp_windows.h b/src/core/lib/iomgr/tcp_windows.h new file mode 100644 index 0000000000..78bc13389a --- /dev/null +++ b/src/core/lib/iomgr/tcp_windows.h @@ -0,0 +1,57 @@ +/* + * + * Copyright 2015-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_IOMGR_TCP_WINDOWS_H +#define GRPC_CORE_IOMGR_TCP_WINDOWS_H +/* + Low level TCP "bottom half" implementation, for use by transports built on + top of a TCP connection. + + Note that this file does not (yet) include APIs for creating the socket in + the first place. + + All calls passing slice transfer ownership of a slice refcount unless + otherwise specified. +*/ + +#include "src/core/iomgr/endpoint.h" +#include "src/core/iomgr/socket_windows.h" + +/* Create a tcp endpoint given a winsock handle. + * Takes ownership of the handle. + */ +grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket, char *peer_string); + +int grpc_tcp_prepare_socket(SOCKET sock); + +#endif /* GRPC_CORE_IOMGR_TCP_WINDOWS_H */ diff --git a/src/core/lib/iomgr/time_averaged_stats.c b/src/core/lib/iomgr/time_averaged_stats.c new file mode 100644 index 0000000000..e075db4373 --- /dev/null +++ b/src/core/lib/iomgr/time_averaged_stats.c @@ -0,0 +1,77 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/iomgr/time_averaged_stats.h" + +void grpc_time_averaged_stats_init(grpc_time_averaged_stats* stats, + double init_avg, double regress_weight, + double persistence_factor) { + stats->init_avg = init_avg; + stats->regress_weight = regress_weight; + stats->persistence_factor = persistence_factor; + stats->batch_total_value = 0; + stats->batch_num_samples = 0; + stats->aggregate_total_weight = 0; + stats->aggregate_weighted_avg = init_avg; +} + +void grpc_time_averaged_stats_add_sample(grpc_time_averaged_stats* stats, + double value) { + stats->batch_total_value += value; + ++stats->batch_num_samples; +} + +double grpc_time_averaged_stats_update_average( + grpc_time_averaged_stats* stats) { + /* Start with the current batch: */ + double weighted_sum = stats->batch_total_value; + double total_weight = stats->batch_num_samples; + if (stats->regress_weight > 0) { + /* Add in the regression towards init_avg_: */ + weighted_sum += stats->regress_weight * stats->init_avg; + total_weight += stats->regress_weight; + } + if (stats->persistence_factor > 0) { + /* Add in the persistence: */ + const double prev_sample_weight = + stats->persistence_factor * stats->aggregate_total_weight; + weighted_sum += prev_sample_weight * stats->aggregate_weighted_avg; + total_weight += prev_sample_weight; + } + stats->aggregate_weighted_avg = + (total_weight > 0) ? (weighted_sum / total_weight) : stats->init_avg; + stats->aggregate_total_weight = total_weight; + stats->batch_num_samples = 0; + stats->batch_total_value = 0; + return stats->aggregate_weighted_avg; +} diff --git a/src/core/lib/iomgr/time_averaged_stats.h b/src/core/lib/iomgr/time_averaged_stats.h new file mode 100644 index 0000000000..048e244bcc --- /dev/null +++ b/src/core/lib/iomgr/time_averaged_stats.h @@ -0,0 +1,88 @@ +/* + * + * Copyright 2015-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_IOMGR_TIME_AVERAGED_STATS_H +#define GRPC_CORE_IOMGR_TIME_AVERAGED_STATS_H + +/* This tracks a time-decaying weighted average. It works by collecting + batches of samples and then mixing their average into a time-decaying + weighted mean. It is designed for batch operations where we do many adds + before updating the average. */ + +typedef struct { + /* The initial average value. This is the reported average until the first + grpc_time_averaged_stats_update_average call. If a positive regress_weight + is used, we also regress towards this value on each update. */ + double init_avg; + /* The sample weight of "init_avg" that is mixed in with each call to + grpc_time_averaged_stats_update_average. If the calls to + grpc_time_averaged_stats_add_sample stop, this will cause the average to + regress back to the mean. This should be non-negative. Set it to 0 to + disable the bias. A value of 1 has the effect of adding in 1 bonus sample + with value init_avg to each sample period. */ + double regress_weight; + /* This determines the rate of decay of the time-averaging from one period + to the next by scaling the aggregate_total_weight of samples from prior + periods when combining with the latest period. It should be in the range + [0,1]. A higher value adapts more slowly. With a value of 0.5, if the + batches each have k samples, the samples_in_avg_ will grow to 2 k, so the + weighting of the time average will eventually be 1/3 new batch and 2/3 + old average. */ + double persistence_factor; + + /* The total value of samples since the last UpdateAverage(). */ + double batch_total_value; + /* The number of samples since the last UpdateAverage(). */ + double batch_num_samples; + /* The time-decayed sum of batch_num_samples_ over previous batches. This is + the "weight" of the old aggregate_weighted_avg_ when updating the + average. */ + double aggregate_total_weight; + /* A time-decayed average of the (batch_total_value_ / batch_num_samples_), + computed by decaying the samples_in_avg_ weight in the weighted average. */ + double aggregate_weighted_avg; +} grpc_time_averaged_stats; + +/* See the comments on the members above for an explanation of init_avg, + regress_weight, and persistence_factor. */ +void grpc_time_averaged_stats_init(grpc_time_averaged_stats* stats, + double init_avg, double regress_weight, + double persistence_factor); +/* Add a sample to the current batch. */ +void grpc_time_averaged_stats_add_sample(grpc_time_averaged_stats* stats, + double value); +/* Complete a batch and compute the new estimate of the average sample + value. */ +double grpc_time_averaged_stats_update_average(grpc_time_averaged_stats* stats); + +#endif /* GRPC_CORE_IOMGR_TIME_AVERAGED_STATS_H */ diff --git a/src/core/lib/iomgr/timer.c b/src/core/lib/iomgr/timer.c new file mode 100644 index 0000000000..f444643428 --- /dev/null +++ b/src/core/lib/iomgr/timer.c @@ -0,0 +1,356 @@ +/* + * + * Copyright 2015-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/iomgr/timer.h" + +#include +#include +#include +#include "src/core/iomgr/time_averaged_stats.h" +#include "src/core/iomgr/timer_heap.h" + +#define INVALID_HEAP_INDEX 0xffffffffu + +#define LOG2_NUM_SHARDS 5 +#define NUM_SHARDS (1 << LOG2_NUM_SHARDS) +#define ADD_DEADLINE_SCALE 0.33 +#define MIN_QUEUE_WINDOW_DURATION 0.01 +#define MAX_QUEUE_WINDOW_DURATION 1 + +typedef struct { + gpr_mu mu; + grpc_time_averaged_stats stats; + /* All and only timers with deadlines <= this will be in the heap. */ + gpr_timespec queue_deadline_cap; + gpr_timespec min_deadline; + /* Index in the g_shard_queue */ + uint32_t shard_queue_index; + /* This holds all timers with deadlines < queue_deadline_cap. Timers in this + list have the top bit of their deadline set to 0. */ + grpc_timer_heap heap; + /* This holds timers whose deadline is >= queue_deadline_cap. */ + grpc_timer list; +} shard_type; + +/* Protects g_shard_queue */ +static gpr_mu g_mu; +/* Allow only one run_some_expired_timers at once */ +static gpr_mu g_checker_mu; +static gpr_clock_type g_clock_type; +static shard_type g_shards[NUM_SHARDS]; +/* Protected by g_mu */ +static shard_type *g_shard_queue[NUM_SHARDS]; + +static int run_some_expired_timers(grpc_exec_ctx *exec_ctx, gpr_timespec now, + gpr_timespec *next, int success); + +static gpr_timespec compute_min_deadline(shard_type *shard) { + return grpc_timer_heap_is_empty(&shard->heap) + ? shard->queue_deadline_cap + : grpc_timer_heap_top(&shard->heap)->deadline; +} + +void grpc_timer_list_init(gpr_timespec now) { + uint32_t i; + + gpr_mu_init(&g_mu); + gpr_mu_init(&g_checker_mu); + g_clock_type = now.clock_type; + + for (i = 0; i < NUM_SHARDS; i++) { + shard_type *shard = &g_shards[i]; + gpr_mu_init(&shard->mu); + grpc_time_averaged_stats_init(&shard->stats, 1.0 / ADD_DEADLINE_SCALE, 0.1, + 0.5); + shard->queue_deadline_cap = now; + shard->shard_queue_index = i; + grpc_timer_heap_init(&shard->heap); + shard->list.next = shard->list.prev = &shard->list; + shard->min_deadline = compute_min_deadline(shard); + g_shard_queue[i] = shard; + } +} + +void grpc_timer_list_shutdown(grpc_exec_ctx *exec_ctx) { + int i; + run_some_expired_timers(exec_ctx, gpr_inf_future(g_clock_type), NULL, 0); + for (i = 0; i < NUM_SHARDS; i++) { + shard_type *shard = &g_shards[i]; + gpr_mu_destroy(&shard->mu); + grpc_timer_heap_destroy(&shard->heap); + } + gpr_mu_destroy(&g_mu); + gpr_mu_destroy(&g_checker_mu); +} + +/* This is a cheap, but good enough, pointer hash for sharding the tasks: */ +static size_t shard_idx(const grpc_timer *info) { + size_t x = (size_t)info; + return ((x >> 4) ^ (x >> 9) ^ (x >> 14)) & (NUM_SHARDS - 1); +} + +static double ts_to_dbl(gpr_timespec ts) { + return (double)ts.tv_sec + 1e-9 * ts.tv_nsec; +} + +static gpr_timespec dbl_to_ts(double d) { + gpr_timespec ts; + ts.tv_sec = (int64_t)d; + ts.tv_nsec = (int32_t)(1e9 * (d - (double)ts.tv_sec)); + ts.clock_type = GPR_TIMESPAN; + return ts; +} + +static void list_join(grpc_timer *head, grpc_timer *timer) { + timer->next = head; + timer->prev = head->prev; + timer->next->prev = timer->prev->next = timer; +} + +static void list_remove(grpc_timer *timer) { + timer->next->prev = timer->prev; + timer->prev->next = timer->next; +} + +static void swap_adjacent_shards_in_queue(uint32_t first_shard_queue_index) { + shard_type *temp; + temp = g_shard_queue[first_shard_queue_index]; + g_shard_queue[first_shard_queue_index] = + g_shard_queue[first_shard_queue_index + 1]; + g_shard_queue[first_shard_queue_index + 1] = temp; + g_shard_queue[first_shard_queue_index]->shard_queue_index = + first_shard_queue_index; + g_shard_queue[first_shard_queue_index + 1]->shard_queue_index = + first_shard_queue_index + 1; +} + +static void note_deadline_change(shard_type *shard) { + while (shard->shard_queue_index > 0 && + gpr_time_cmp( + shard->min_deadline, + g_shard_queue[shard->shard_queue_index - 1]->min_deadline) < 0) { + swap_adjacent_shards_in_queue(shard->shard_queue_index - 1); + } + while (shard->shard_queue_index < NUM_SHARDS - 1 && + gpr_time_cmp( + shard->min_deadline, + g_shard_queue[shard->shard_queue_index + 1]->min_deadline) > 0) { + swap_adjacent_shards_in_queue(shard->shard_queue_index); + } +} + +void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer, + gpr_timespec deadline, grpc_iomgr_cb_func timer_cb, + void *timer_cb_arg, gpr_timespec now) { + int is_first_timer = 0; + shard_type *shard = &g_shards[shard_idx(timer)]; + GPR_ASSERT(deadline.clock_type == g_clock_type); + GPR_ASSERT(now.clock_type == g_clock_type); + grpc_closure_init(&timer->closure, timer_cb, timer_cb_arg); + timer->deadline = deadline; + timer->triggered = 0; + + /* TODO(ctiller): check deadline expired */ + + gpr_mu_lock(&shard->mu); + grpc_time_averaged_stats_add_sample(&shard->stats, + ts_to_dbl(gpr_time_sub(deadline, now))); + if (gpr_time_cmp(deadline, shard->queue_deadline_cap) < 0) { + is_first_timer = grpc_timer_heap_add(&shard->heap, timer); + } else { + timer->heap_index = INVALID_HEAP_INDEX; + list_join(&shard->list, timer); + } + gpr_mu_unlock(&shard->mu); + + /* Deadline may have decreased, we need to adjust the master queue. Note + that there is a potential racy unlocked region here. There could be a + reordering of multiple grpc_timer_init calls, at this point, but the < test + below should ensure that we err on the side of caution. There could + also be a race with grpc_timer_check, which might beat us to the lock. In + that case, it is possible that the timer that we added will have already + run by the time we hold the lock, but that too is a safe error. + Finally, it's possible that the grpc_timer_check that intervened failed to + trigger the new timer because the min_deadline hadn't yet been reduced. + In that case, the timer will simply have to wait for the next + grpc_timer_check. */ + if (is_first_timer) { + gpr_mu_lock(&g_mu); + if (gpr_time_cmp(deadline, shard->min_deadline) < 0) { + gpr_timespec old_min_deadline = g_shard_queue[0]->min_deadline; + shard->min_deadline = deadline; + note_deadline_change(shard); + if (shard->shard_queue_index == 0 && + gpr_time_cmp(deadline, old_min_deadline) < 0) { + grpc_kick_poller(); + } + } + gpr_mu_unlock(&g_mu); + } +} + +void grpc_timer_cancel(grpc_exec_ctx *exec_ctx, grpc_timer *timer) { + shard_type *shard = &g_shards[shard_idx(timer)]; + gpr_mu_lock(&shard->mu); + if (!timer->triggered) { + grpc_exec_ctx_enqueue(exec_ctx, &timer->closure, false, NULL); + timer->triggered = 1; + if (timer->heap_index == INVALID_HEAP_INDEX) { + list_remove(timer); + } else { + grpc_timer_heap_remove(&shard->heap, timer); + } + } + gpr_mu_unlock(&shard->mu); +} + +/* This is called when the queue is empty and "now" has reached the + queue_deadline_cap. We compute a new queue deadline and then scan the map + for timers that fall at or under it. Returns true if the queue is no + longer empty. + REQUIRES: shard->mu locked */ +static int refill_queue(shard_type *shard, gpr_timespec now) { + /* Compute the new queue window width and bound by the limits: */ + double computed_deadline_delta = + grpc_time_averaged_stats_update_average(&shard->stats) * + ADD_DEADLINE_SCALE; + double deadline_delta = + GPR_CLAMP(computed_deadline_delta, MIN_QUEUE_WINDOW_DURATION, + MAX_QUEUE_WINDOW_DURATION); + grpc_timer *timer, *next; + + /* Compute the new cap and put all timers under it into the queue: */ + shard->queue_deadline_cap = gpr_time_add( + gpr_time_max(now, shard->queue_deadline_cap), dbl_to_ts(deadline_delta)); + for (timer = shard->list.next; timer != &shard->list; timer = next) { + next = timer->next; + + if (gpr_time_cmp(timer->deadline, shard->queue_deadline_cap) < 0) { + list_remove(timer); + grpc_timer_heap_add(&shard->heap, timer); + } + } + return !grpc_timer_heap_is_empty(&shard->heap); +} + +/* This pops the next non-cancelled timer with deadline <= now from the queue, + or returns NULL if there isn't one. + REQUIRES: shard->mu locked */ +static grpc_timer *pop_one(shard_type *shard, gpr_timespec now) { + grpc_timer *timer; + for (;;) { + if (grpc_timer_heap_is_empty(&shard->heap)) { + if (gpr_time_cmp(now, shard->queue_deadline_cap) < 0) return NULL; + if (!refill_queue(shard, now)) return NULL; + } + timer = grpc_timer_heap_top(&shard->heap); + if (gpr_time_cmp(timer->deadline, now) > 0) return NULL; + timer->triggered = 1; + grpc_timer_heap_pop(&shard->heap); + return timer; + } +} + +/* REQUIRES: shard->mu unlocked */ +static size_t pop_timers(grpc_exec_ctx *exec_ctx, shard_type *shard, + gpr_timespec now, gpr_timespec *new_min_deadline, + int success) { + size_t n = 0; + grpc_timer *timer; + gpr_mu_lock(&shard->mu); + while ((timer = pop_one(shard, now))) { + grpc_exec_ctx_enqueue(exec_ctx, &timer->closure, success, NULL); + n++; + } + *new_min_deadline = compute_min_deadline(shard); + gpr_mu_unlock(&shard->mu); + return n; +} + +static int run_some_expired_timers(grpc_exec_ctx *exec_ctx, gpr_timespec now, + gpr_timespec *next, int success) { + size_t n = 0; + + /* TODO(ctiller): verify that there are any timers (atomically) here */ + + if (gpr_mu_trylock(&g_checker_mu)) { + gpr_mu_lock(&g_mu); + + while (gpr_time_cmp(g_shard_queue[0]->min_deadline, now) < 0) { + gpr_timespec new_min_deadline; + + /* For efficiency, we pop as many available timers as we can from the + shard. This may violate perfect timer deadline ordering, but that + shouldn't be a big deal because we don't make ordering guarantees. */ + n += pop_timers(exec_ctx, g_shard_queue[0], now, &new_min_deadline, + success); + + /* An grpc_timer_init() on the shard could intervene here, adding a new + timer that is earlier than new_min_deadline. However, + grpc_timer_init() will block on the master_lock before it can call + set_min_deadline, so this one will complete first and then the Addtimer + will reduce the min_deadline (perhaps unnecessarily). */ + g_shard_queue[0]->min_deadline = new_min_deadline; + note_deadline_change(g_shard_queue[0]); + } + + if (next) { + *next = gpr_time_min(*next, g_shard_queue[0]->min_deadline); + } + + gpr_mu_unlock(&g_mu); + gpr_mu_unlock(&g_checker_mu); + } else if (next != NULL) { + /* TODO(ctiller): this forces calling code to do an short poll, and + then retry the timer check (because this time through the timer list was + contended). + + We could reduce the cost here dramatically by keeping a count of how many + currently active pollers got through the uncontended case above + successfully, and waking up other pollers IFF that count drops to zero. + + Once that count is in place, this entire else branch could disappear. */ + *next = gpr_time_min( + *next, gpr_time_add(now, gpr_time_from_millis(1, GPR_TIMESPAN))); + } + + return (int)n; +} + +bool grpc_timer_check(grpc_exec_ctx *exec_ctx, gpr_timespec now, + gpr_timespec *next) { + GPR_ASSERT(now.clock_type == g_clock_type); + return run_some_expired_timers( + exec_ctx, now, next, + gpr_time_cmp(now, gpr_inf_future(now.clock_type)) != 0); +} diff --git a/src/core/lib/iomgr/timer.h b/src/core/lib/iomgr/timer.h new file mode 100644 index 0000000000..1e2d1cbfbd --- /dev/null +++ b/src/core/lib/iomgr/timer.h @@ -0,0 +1,108 @@ +/* + * + * Copyright 2015-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_IOMGR_TIMER_H +#define GRPC_CORE_IOMGR_TIMER_H + +#include +#include +#include "src/core/iomgr/exec_ctx.h" +#include "src/core/iomgr/iomgr.h" + +typedef struct grpc_timer { + gpr_timespec deadline; + uint32_t heap_index; /* INVALID_HEAP_INDEX if not in heap */ + int triggered; + struct grpc_timer *next; + struct grpc_timer *prev; + grpc_closure closure; +} grpc_timer; + +/* Initialize *timer. When expired or canceled, timer_cb will be called with + *timer_cb_arg and status to indicate if it expired (SUCCESS) or was + canceled (CANCELLED). timer_cb is guaranteed to be called exactly once, + and application code should check the status to determine how it was + invoked. The application callback is also responsible for maintaining + information about when to free up any user-level state. */ +void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer, + gpr_timespec deadline, grpc_iomgr_cb_func timer_cb, + void *timer_cb_arg, gpr_timespec now); + +/* Note that there is no timer destroy function. This is because the + timer is a one-time occurrence with a guarantee that the callback will + be called exactly once, either at expiration or cancellation. Thus, all + the internal timer event management state is destroyed just before + that callback is invoked. If the user has additional state associated with + the timer, the user is responsible for determining when it is safe to + destroy that state. */ + +/* Cancel an *timer. + There are three cases: + 1. We normally cancel the timer + 2. The timer has already run + 3. We can't cancel the timer because it is "in flight". + + In all of these cases, the cancellation is still considered successful. + They are essentially distinguished in that the timer_cb will be run + exactly once from either the cancellation (with status CANCELLED) + or from the activation (with status SUCCESS) + + Note carefully that the callback function MAY occur in the same callstack + as grpc_timer_cancel. It's expected that most timers will be cancelled (their + primary use is to implement deadlines), and so this code is optimized such + that cancellation costs as little as possible. Making callbacks run inline + matches this aim. + + Requires: cancel() must happen after add() on a given timer */ +void grpc_timer_cancel(grpc_exec_ctx *exec_ctx, grpc_timer *timer); + +/* iomgr internal api for dealing with timers */ + +/* Check for timers to be run, and run them. + Return true if timer callbacks were executed. + Drops drop_mu if it is non-null before executing callbacks. + If next is non-null, TRY to update *next with the next running timer + IF that timer occurs before *next current value. + *next is never guaranteed to be updated on any given execution; however, + with high probability at least one thread in the system will see an update + at any time slice. */ +bool grpc_timer_check(grpc_exec_ctx *exec_ctx, gpr_timespec now, + gpr_timespec *next); +void grpc_timer_list_init(gpr_timespec now); +void grpc_timer_list_shutdown(grpc_exec_ctx *exec_ctx); + +/* the following must be implemented by each iomgr implementation */ + +void grpc_kick_poller(void); + +#endif /* GRPC_CORE_IOMGR_TIMER_H */ diff --git a/src/core/lib/iomgr/timer_heap.c b/src/core/lib/iomgr/timer_heap.c new file mode 100644 index 0000000000..b5df566c45 --- /dev/null +++ b/src/core/lib/iomgr/timer_heap.c @@ -0,0 +1,146 @@ +/* + * + * Copyright 2015-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/iomgr/timer_heap.h" + +#include + +#include +#include + +/* Adjusts a heap so as to move a hole at position i closer to the root, + until a suitable position is found for element t. Then, copies t into that + position. This functor is called each time immediately after modifying a + value in the underlying container, with the offset of the modified element as + its argument. */ +static void adjust_upwards(grpc_timer **first, uint32_t i, grpc_timer *t) { + while (i > 0) { + uint32_t parent = (uint32_t)(((int)i - 1) / 2); + if (gpr_time_cmp(first[parent]->deadline, t->deadline) <= 0) break; + first[i] = first[parent]; + first[i]->heap_index = i; + i = parent; + } + first[i] = t; + t->heap_index = i; +} + +/* Adjusts a heap so as to move a hole at position i farther away from the root, + until a suitable position is found for element t. Then, copies t into that + position. */ +static void adjust_downwards(grpc_timer **first, uint32_t i, uint32_t length, + grpc_timer *t) { + for (;;) { + uint32_t left_child = 1u + 2u * i; + if (left_child >= length) break; + uint32_t right_child = left_child + 1; + uint32_t next_i = right_child < length && + gpr_time_cmp(first[left_child]->deadline, + first[right_child]->deadline) > 0 + ? right_child + : left_child; + if (gpr_time_cmp(t->deadline, first[next_i]->deadline) <= 0) break; + first[i] = first[next_i]; + first[i]->heap_index = i; + i = next_i; + } + first[i] = t; + t->heap_index = i; +} + +#define SHRINK_MIN_ELEMS 8 +#define SHRINK_FULLNESS_FACTOR 2 + +static void maybe_shrink(grpc_timer_heap *heap) { + if (heap->timer_count >= 8 && + heap->timer_count <= heap->timer_capacity / SHRINK_FULLNESS_FACTOR / 2) { + heap->timer_capacity = heap->timer_count * SHRINK_FULLNESS_FACTOR; + heap->timers = + gpr_realloc(heap->timers, heap->timer_capacity * sizeof(grpc_timer *)); + } +} + +static void note_changed_priority(grpc_timer_heap *heap, grpc_timer *timer) { + uint32_t i = timer->heap_index; + uint32_t parent = (uint32_t)(((int)i - 1) / 2); + if (gpr_time_cmp(heap->timers[parent]->deadline, timer->deadline) > 0) { + adjust_upwards(heap->timers, i, timer); + } else { + adjust_downwards(heap->timers, i, heap->timer_count, timer); + } +} + +void grpc_timer_heap_init(grpc_timer_heap *heap) { + memset(heap, 0, sizeof(*heap)); +} + +void grpc_timer_heap_destroy(grpc_timer_heap *heap) { gpr_free(heap->timers); } + +int grpc_timer_heap_add(grpc_timer_heap *heap, grpc_timer *timer) { + if (heap->timer_count == heap->timer_capacity) { + heap->timer_capacity = + GPR_MAX(heap->timer_capacity + 1, heap->timer_capacity * 3 / 2); + heap->timers = + gpr_realloc(heap->timers, heap->timer_capacity * sizeof(grpc_timer *)); + } + timer->heap_index = heap->timer_count; + adjust_upwards(heap->timers, heap->timer_count, timer); + heap->timer_count++; + return timer->heap_index == 0; +} + +void grpc_timer_heap_remove(grpc_timer_heap *heap, grpc_timer *timer) { + uint32_t i = timer->heap_index; + if (i == heap->timer_count - 1) { + heap->timer_count--; + maybe_shrink(heap); + return; + } + heap->timers[i] = heap->timers[heap->timer_count - 1]; + heap->timers[i]->heap_index = i; + heap->timer_count--; + maybe_shrink(heap); + note_changed_priority(heap, heap->timers[i]); +} + +int grpc_timer_heap_is_empty(grpc_timer_heap *heap) { + return heap->timer_count == 0; +} + +grpc_timer *grpc_timer_heap_top(grpc_timer_heap *heap) { + return heap->timers[0]; +} + +void grpc_timer_heap_pop(grpc_timer_heap *heap) { + grpc_timer_heap_remove(heap, grpc_timer_heap_top(heap)); +} diff --git a/src/core/lib/iomgr/timer_heap.h b/src/core/lib/iomgr/timer_heap.h new file mode 100644 index 0000000000..c2912ef45d --- /dev/null +++ b/src/core/lib/iomgr/timer_heap.h @@ -0,0 +1,57 @@ +/* + * + * Copyright 2015-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_IOMGR_TIMER_HEAP_H +#define GRPC_CORE_IOMGR_TIMER_HEAP_H + +#include "src/core/iomgr/timer.h" + +typedef struct { + grpc_timer **timers; + uint32_t timer_count; + uint32_t timer_capacity; +} grpc_timer_heap; + +/* return 1 if the new timer is the first timer in the heap */ +int grpc_timer_heap_add(grpc_timer_heap *heap, grpc_timer *timer); + +void grpc_timer_heap_init(grpc_timer_heap *heap); +void grpc_timer_heap_destroy(grpc_timer_heap *heap); + +void grpc_timer_heap_remove(grpc_timer_heap *heap, grpc_timer *timer); +grpc_timer *grpc_timer_heap_top(grpc_timer_heap *heap); +void grpc_timer_heap_pop(grpc_timer_heap *heap); + +int grpc_timer_heap_is_empty(grpc_timer_heap *heap); + +#endif /* GRPC_CORE_IOMGR_TIMER_HEAP_H */ diff --git a/src/core/lib/iomgr/udp_server.c b/src/core/lib/iomgr/udp_server.c new file mode 100644 index 0000000000..174159170f --- /dev/null +++ b/src/core/lib/iomgr/udp_server.c @@ -0,0 +1,418 @@ +/* + * + * Copyright 2015-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. + * + */ + +/* FIXME: "posix" files shouldn't be depending on _GNU_SOURCE */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include + +#ifdef GRPC_NEED_UDP +#ifdef GPR_POSIX_SOCKET + +#include "src/core/iomgr/udp_server.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include "src/core/iomgr/fd_posix.h" +#include "src/core/iomgr/pollset_posix.h" +#include "src/core/iomgr/resolve_address.h" +#include "src/core/iomgr/sockaddr_utils.h" +#include "src/core/iomgr/socket_utils_posix.h" +#include "src/core/iomgr/unix_sockets_posix.h" +#include "src/core/support/string.h" + +#define INIT_PORT_CAP 2 + +/* one listening port */ +typedef struct { + int fd; + grpc_fd *emfd; + grpc_udp_server *server; + union { + uint8_t untyped[GRPC_MAX_SOCKADDR_SIZE]; + struct sockaddr sockaddr; + } addr; + size_t addr_len; + grpc_closure read_closure; + grpc_closure destroyed_closure; + grpc_udp_server_read_cb read_cb; +} server_port; + +/* the overall server */ +struct grpc_udp_server { + gpr_mu mu; + gpr_cv cv; + + /* active port count: how many ports are actually still listening */ + size_t active_ports; + /* destroyed port count: how many ports are completely destroyed */ + size_t destroyed_ports; + + /* is this server shutting down? (boolean) */ + int shutdown; + + /* all listening ports */ + server_port *ports; + size_t nports; + size_t port_capacity; + + /* shutdown callback */ + grpc_closure *shutdown_complete; + + /* all pollsets interested in new connections */ + grpc_pollset **pollsets; + /* number of pollsets in the pollsets array */ + size_t pollset_count; + /* The parent grpc server */ + grpc_server *grpc_server; +}; + +grpc_udp_server *grpc_udp_server_create(void) { + grpc_udp_server *s = gpr_malloc(sizeof(grpc_udp_server)); + gpr_mu_init(&s->mu); + gpr_cv_init(&s->cv); + s->active_ports = 0; + s->destroyed_ports = 0; + s->shutdown = 0; + s->ports = gpr_malloc(sizeof(server_port) * INIT_PORT_CAP); + s->nports = 0; + s->port_capacity = INIT_PORT_CAP; + + return s; +} + +static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_udp_server *s) { + grpc_exec_ctx_enqueue(exec_ctx, s->shutdown_complete, 1, NULL); + + gpr_mu_destroy(&s->mu); + gpr_cv_destroy(&s->cv); + + gpr_free(s->ports); + gpr_free(s); +} + +static void destroyed_port(grpc_exec_ctx *exec_ctx, void *server, + bool success) { + grpc_udp_server *s = server; + gpr_mu_lock(&s->mu); + s->destroyed_ports++; + if (s->destroyed_ports == s->nports) { + gpr_mu_unlock(&s->mu); + finish_shutdown(exec_ctx, s); + } else { + gpr_mu_unlock(&s->mu); + } +} + +/* called when all listening endpoints have been shutdown, so no further + events will be received on them - at this point it's safe to destroy + things */ +static void deactivated_all_ports(grpc_exec_ctx *exec_ctx, grpc_udp_server *s) { + size_t i; + + /* delete ALL the things */ + gpr_mu_lock(&s->mu); + + if (!s->shutdown) { + gpr_mu_unlock(&s->mu); + return; + } + + if (s->nports) { + for (i = 0; i < s->nports; i++) { + server_port *sp = &s->ports[i]; + grpc_unlink_if_unix_domain_socket(&sp->addr.sockaddr); + sp->destroyed_closure.cb = destroyed_port; + sp->destroyed_closure.cb_arg = s; + grpc_fd_orphan(exec_ctx, sp->emfd, &sp->destroyed_closure, NULL, + "udp_listener_shutdown"); + } + gpr_mu_unlock(&s->mu); + } else { + gpr_mu_unlock(&s->mu); + finish_shutdown(exec_ctx, s); + } +} + +void grpc_udp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_udp_server *s, + grpc_closure *on_done) { + size_t i; + gpr_mu_lock(&s->mu); + + GPR_ASSERT(!s->shutdown); + s->shutdown = 1; + + s->shutdown_complete = on_done; + + /* shutdown all fd's */ + if (s->active_ports) { + for (i = 0; i < s->nports; i++) { + grpc_fd_shutdown(exec_ctx, s->ports[i].emfd); + } + gpr_mu_unlock(&s->mu); + } else { + gpr_mu_unlock(&s->mu); + deactivated_all_ports(exec_ctx, s); + } +} + +/* Prepare a recently-created socket for listening. */ +static int prepare_socket(int fd, const struct sockaddr *addr, + size_t addr_len) { + struct sockaddr_storage sockname_temp; + socklen_t sockname_len; + int get_local_ip; + int rc; + + if (fd < 0) { + goto error; + } + + if (!grpc_set_socket_nonblocking(fd, 1) || !grpc_set_socket_cloexec(fd, 1)) { + gpr_log(GPR_ERROR, "Unable to configure socket %d: %s", fd, + strerror(errno)); + } + + get_local_ip = 1; + rc = setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &get_local_ip, + sizeof(get_local_ip)); + if (rc == 0 && addr->sa_family == AF_INET6) { +#if !defined(__APPLE__) + rc = setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &get_local_ip, + sizeof(get_local_ip)); +#endif + } + + GPR_ASSERT(addr_len < ~(socklen_t)0); + if (bind(fd, addr, (socklen_t)addr_len) < 0) { + char *addr_str; + grpc_sockaddr_to_string(&addr_str, addr, 0); + gpr_log(GPR_ERROR, "bind addr=%s: %s", addr_str, strerror(errno)); + gpr_free(addr_str); + goto error; + } + + sockname_len = sizeof(sockname_temp); + if (getsockname(fd, (struct sockaddr *)&sockname_temp, &sockname_len) < 0) { + goto error; + } + + return grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp); + +error: + if (fd >= 0) { + close(fd); + } + return -1; +} + +/* event manager callback when reads are ready */ +static void on_read(grpc_exec_ctx *exec_ctx, void *arg, bool success) { + server_port *sp = arg; + + if (!success) { + gpr_mu_lock(&sp->server->mu); + if (0 == --sp->server->active_ports) { + gpr_mu_unlock(&sp->server->mu); + deactivated_all_ports(exec_ctx, sp->server); + } else { + gpr_mu_unlock(&sp->server->mu); + } + return; + } + + /* Tell the registered callback that data is available to read. */ + GPR_ASSERT(sp->read_cb); + sp->read_cb(exec_ctx, sp->emfd, sp->server->grpc_server); + + /* Re-arm the notification event so we get another chance to read. */ + grpc_fd_notify_on_read(exec_ctx, sp->emfd, &sp->read_closure); +} + +static int add_socket_to_server(grpc_udp_server *s, int fd, + const struct sockaddr *addr, size_t addr_len, + grpc_udp_server_read_cb read_cb) { + server_port *sp; + int port; + char *addr_str; + char *name; + + port = prepare_socket(fd, addr, addr_len); + if (port >= 0) { + grpc_sockaddr_to_string(&addr_str, (struct sockaddr *)&addr, 1); + gpr_asprintf(&name, "udp-server-listener:%s", addr_str); + gpr_free(addr_str); + gpr_mu_lock(&s->mu); + /* append it to the list under a lock */ + if (s->nports == s->port_capacity) { + s->port_capacity *= 2; + s->ports = gpr_realloc(s->ports, sizeof(server_port) * s->port_capacity); + } + sp = &s->ports[s->nports++]; + sp->server = s; + sp->fd = fd; + sp->emfd = grpc_fd_create(fd, name); + memcpy(sp->addr.untyped, addr, addr_len); + sp->addr_len = addr_len; + sp->read_cb = read_cb; + GPR_ASSERT(sp->emfd); + gpr_mu_unlock(&s->mu); + gpr_free(name); + } + + return port; +} + +int grpc_udp_server_add_port(grpc_udp_server *s, const void *addr, + size_t addr_len, grpc_udp_server_read_cb read_cb) { + int allocated_port1 = -1; + int allocated_port2 = -1; + unsigned i; + int fd; + grpc_dualstack_mode dsmode; + struct sockaddr_in6 addr6_v4mapped; + struct sockaddr_in wild4; + struct sockaddr_in6 wild6; + struct sockaddr_in addr4_copy; + struct sockaddr *allocated_addr = NULL; + struct sockaddr_storage sockname_temp; + socklen_t sockname_len; + int port; + + grpc_unlink_if_unix_domain_socket((struct sockaddr *)addr); + + /* Check if this is a wildcard port, and if so, try to keep the port the same + as some previously created listener. */ + if (grpc_sockaddr_get_port(addr) == 0) { + for (i = 0; i < s->nports; i++) { + sockname_len = sizeof(sockname_temp); + if (0 == getsockname(s->ports[i].fd, (struct sockaddr *)&sockname_temp, + &sockname_len)) { + port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp); + if (port > 0) { + allocated_addr = malloc(addr_len); + memcpy(allocated_addr, addr, addr_len); + grpc_sockaddr_set_port(allocated_addr, port); + addr = allocated_addr; + break; + } + } + } + } + + if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) { + addr = (const struct sockaddr *)&addr6_v4mapped; + addr_len = sizeof(addr6_v4mapped); + } + + /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */ + if (grpc_sockaddr_is_wildcard(addr, &port)) { + grpc_sockaddr_make_wildcards(port, &wild4, &wild6); + + /* Try listening on IPv6 first. */ + addr = (struct sockaddr *)&wild6; + addr_len = sizeof(wild6); + fd = grpc_create_dualstack_socket(addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode); + allocated_port1 = add_socket_to_server(s, fd, addr, addr_len, read_cb); + if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) { + goto done; + } + + /* If we didn't get a dualstack socket, also listen on 0.0.0.0. */ + if (port == 0 && allocated_port1 > 0) { + grpc_sockaddr_set_port((struct sockaddr *)&wild4, allocated_port1); + } + addr = (struct sockaddr *)&wild4; + addr_len = sizeof(wild4); + } + + fd = grpc_create_dualstack_socket(addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode); + if (fd < 0) { + gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno)); + } + if (dsmode == GRPC_DSMODE_IPV4 && + grpc_sockaddr_is_v4mapped(addr, &addr4_copy)) { + addr = (struct sockaddr *)&addr4_copy; + addr_len = sizeof(addr4_copy); + } + allocated_port2 = add_socket_to_server(s, fd, addr, addr_len, read_cb); + +done: + gpr_free(allocated_addr); + return allocated_port1 >= 0 ? allocated_port1 : allocated_port2; +} + +int grpc_udp_server_get_fd(grpc_udp_server *s, unsigned port_index) { + return (port_index < s->nports) ? s->ports[port_index].fd : -1; +} + +void grpc_udp_server_start(grpc_exec_ctx *exec_ctx, grpc_udp_server *s, + grpc_pollset **pollsets, size_t pollset_count, + grpc_server *server) { + size_t i, j; + gpr_mu_lock(&s->mu); + GPR_ASSERT(s->active_ports == 0); + s->pollsets = pollsets; + s->grpc_server = server; + for (i = 0; i < s->nports; i++) { + for (j = 0; j < pollset_count; j++) { + grpc_pollset_add_fd(exec_ctx, pollsets[j], s->ports[i].emfd); + } + s->ports[i].read_closure.cb = on_read; + s->ports[i].read_closure.cb_arg = &s->ports[i]; + grpc_fd_notify_on_read(exec_ctx, s->ports[i].emfd, + &s->ports[i].read_closure); + s->active_ports++; + } + gpr_mu_unlock(&s->mu); +} + +#endif +#endif diff --git a/src/core/lib/iomgr/udp_server.h b/src/core/lib/iomgr/udp_server.h new file mode 100644 index 0000000000..148c04fa9b --- /dev/null +++ b/src/core/lib/iomgr/udp_server.h @@ -0,0 +1,77 @@ +/* + * + * Copyright 2015-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_IOMGR_UDP_SERVER_H +#define GRPC_CORE_IOMGR_UDP_SERVER_H + +#include "src/core/iomgr/endpoint.h" +#include "src/core/iomgr/fd_posix.h" + +/* Forward decl of struct grpc_server */ +/* This is not typedef'ed to avoid a typedef-redefinition error */ +struct grpc_server; + +/* Forward decl of grpc_udp_server */ +typedef struct grpc_udp_server grpc_udp_server; + +/* Called when data is available to read from the socket. */ +typedef void (*grpc_udp_server_read_cb)(grpc_exec_ctx *exec_ctx, grpc_fd *emfd, + struct grpc_server *server); + +/* Create a server, initially not bound to any ports */ +grpc_udp_server *grpc_udp_server_create(void); + +/* Start listening to bound ports */ +void grpc_udp_server_start(grpc_exec_ctx *exec_ctx, grpc_udp_server *udp_server, + grpc_pollset **pollsets, size_t pollset_count, + struct grpc_server *server); + +int grpc_udp_server_get_fd(grpc_udp_server *s, unsigned index); + +/* Add a port to the server, returning port number on success, or negative + on failure. + + The :: and 0.0.0.0 wildcard addresses are treated identically, accepting + both IPv4 and IPv6 connections, but :: is the preferred style. This usually + creates one socket, but possibly two on systems which support IPv6, + but not dualstack sockets. */ + +/* TODO(ctiller): deprecate this, and make grpc_udp_server_add_ports to handle + all of the multiple socket port matching logic in one place */ +int grpc_udp_server_add_port(grpc_udp_server *s, const void *addr, + size_t addr_len, grpc_udp_server_read_cb read_cb); + +void grpc_udp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_udp_server *server, + grpc_closure *on_done); + +#endif /* GRPC_CORE_IOMGR_UDP_SERVER_H */ diff --git a/src/core/lib/iomgr/unix_sockets_posix.c b/src/core/lib/iomgr/unix_sockets_posix.c new file mode 100644 index 0000000000..174a7e7abf --- /dev/null +++ b/src/core/lib/iomgr/unix_sockets_posix.c @@ -0,0 +1,103 @@ +/* + * + * 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/iomgr/unix_sockets_posix.h" + +#ifdef GPR_HAVE_UNIX_SOCKET + +#include +#include +#include +#include + +#include + +void grpc_create_socketpair_if_unix(int sv[2]) { + GPR_ASSERT(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0); +} + +grpc_resolved_addresses *grpc_resolve_unix_domain_address(const char *name) { + struct sockaddr_un *un; + + grpc_resolved_addresses *addrs = gpr_malloc(sizeof(grpc_resolved_addresses)); + addrs->naddrs = 1; + addrs->addrs = gpr_malloc(sizeof(grpc_resolved_address)); + un = (struct sockaddr_un *)addrs->addrs->addr; + un->sun_family = AF_UNIX; + strcpy(un->sun_path, name); + addrs->addrs->len = strlen(un->sun_path) + sizeof(un->sun_family) + 1; + return addrs; +} + +int grpc_is_unix_socket(const struct sockaddr *addr) { + return addr->sa_family == AF_UNIX; +} + +void grpc_unlink_if_unix_domain_socket(const struct sockaddr *addr) { + if (addr->sa_family != AF_UNIX) { + return; + } + struct sockaddr_un *un = (struct sockaddr_un *)addr; + struct stat st; + + if (stat(un->sun_path, &st) == 0 && (st.st_mode & S_IFMT) == S_IFSOCK) { + unlink(un->sun_path); + } +} + +int grpc_parse_unix(grpc_uri *uri, struct sockaddr_storage *addr, size_t *len) { + struct sockaddr_un *un = (struct sockaddr_un *)addr; + + un->sun_family = AF_UNIX; + strcpy(un->sun_path, uri->path); + *len = strlen(un->sun_path) + sizeof(un->sun_family) + 1; + + return 1; +} + +char *grpc_unix_get_default_authority(grpc_resolver_factory *factory, + grpc_uri *uri) { + return gpr_strdup("localhost"); +} + +char *grpc_sockaddr_to_uri_unix_if_possible(const struct sockaddr *addr) { + if (addr->sa_family != AF_UNIX) { + return NULL; + } + + char *result; + gpr_asprintf(&result, "unix:%s", ((struct sockaddr_un *)addr)->sun_path); + return result; +} + +#endif diff --git a/src/core/lib/iomgr/unix_sockets_posix.h b/src/core/lib/iomgr/unix_sockets_posix.h new file mode 100644 index 0000000000..e842ba3770 --- /dev/null +++ b/src/core/lib/iomgr/unix_sockets_posix.h @@ -0,0 +1,61 @@ +/* + * + * 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_IOMGR_UNIX_SOCKETS_POSIX_H +#define GRPC_CORE_IOMGR_UNIX_SOCKETS_POSIX_H + +#include + +#include + +#include "src/core/client_config/resolver_factory.h" +#include "src/core/client_config/uri_parser.h" +#include "src/core/iomgr/resolve_address.h" +#include "src/core/iomgr/sockaddr.h" + +void grpc_create_socketpair_if_unix(int sv[2]); + +grpc_resolved_addresses *grpc_resolve_unix_domain_address(const char *name); + +int grpc_is_unix_socket(const struct sockaddr *addr); + +void grpc_unlink_if_unix_domain_socket(const struct sockaddr *addr); + +int grpc_parse_unix(grpc_uri *uri, struct sockaddr_storage *addr, size_t *len); + +char *grpc_unix_get_default_authority(grpc_resolver_factory *factory, + grpc_uri *uri); + +char *grpc_sockaddr_to_uri_unix_if_possible(const struct sockaddr *addr); + +#endif /* GRPC_CORE_IOMGR_UNIX_SOCKETS_POSIX_H */ diff --git a/src/core/lib/iomgr/unix_sockets_posix_noop.c b/src/core/lib/iomgr/unix_sockets_posix_noop.c new file mode 100644 index 0000000000..045467bea4 --- /dev/null +++ b/src/core/lib/iomgr/unix_sockets_posix_noop.c @@ -0,0 +1,61 @@ +/* + * + * 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/iomgr/unix_sockets_posix.h" + +#ifndef GPR_HAVE_UNIX_SOCKET + +void grpc_create_socketpair_if_unix(int sv[2]) {} + +grpc_resolved_addresses *grpc_resolve_unix_domain_address(const char *name) { + return NULL; +} + +int grpc_is_unix_socket(const struct sockaddr *addr) { return false; } + +void grpc_unlink_if_unix_domain_socket(const struct sockaddr *addr) {} + +int grpc_parse_unix(grpc_uri *uri, struct sockaddr_storage *addr, size_t *len) { + return 0; +} + +char *grpc_unix_get_default_authority(grpc_resolver_factory *factory, + grpc_uri *uri) { + return NULL; +} + +char *grpc_sockaddr_to_uri_unix_if_possible(const struct sockaddr *addr) { + return NULL; +} + +#endif diff --git a/src/core/lib/iomgr/wakeup_fd_eventfd.c b/src/core/lib/iomgr/wakeup_fd_eventfd.c new file mode 100644 index 0000000000..f67379e4fc --- /dev/null +++ b/src/core/lib/iomgr/wakeup_fd_eventfd.c @@ -0,0 +1,85 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +#ifdef GPR_LINUX_EVENTFD + +#include +#include +#include + +#include + +#include "src/core/iomgr/wakeup_fd_posix.h" +#include "src/core/profiling/timers.h" + +static void eventfd_create(grpc_wakeup_fd* fd_info) { + int efd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); + /* TODO(klempner): Handle failure more gracefully */ + GPR_ASSERT(efd >= 0); + fd_info->read_fd = efd; + fd_info->write_fd = -1; +} + +static void eventfd_consume(grpc_wakeup_fd* fd_info) { + eventfd_t value; + int err; + do { + err = eventfd_read(fd_info->read_fd, &value); + } while (err < 0 && errno == EINTR); +} + +static void eventfd_wakeup(grpc_wakeup_fd* fd_info) { + int err; + GPR_TIMER_BEGIN("eventfd_wakeup", 0); + do { + err = eventfd_write(fd_info->read_fd, 1); + } while (err < 0 && errno == EINTR); + GPR_TIMER_END("eventfd_wakeup", 0); +} + +static void eventfd_destroy(grpc_wakeup_fd* fd_info) { + if (fd_info->read_fd != 0) close(fd_info->read_fd); +} + +static int eventfd_check_availability(void) { + /* TODO(klempner): Actually check if eventfd is available */ + return 1; +} + +const grpc_wakeup_fd_vtable grpc_specialized_wakeup_fd_vtable = { + eventfd_create, eventfd_consume, eventfd_wakeup, eventfd_destroy, + eventfd_check_availability}; + +#endif /* GPR_LINUX_EVENTFD */ diff --git a/src/core/lib/iomgr/wakeup_fd_nospecial.c b/src/core/lib/iomgr/wakeup_fd_nospecial.c new file mode 100644 index 0000000000..7b2be9ed52 --- /dev/null +++ b/src/core/lib/iomgr/wakeup_fd_nospecial.c @@ -0,0 +1,51 @@ +/* + * + * Copyright 2015-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. + * + */ + +/* + * This is a dummy file to provide an invalid specialized_wakeup_fd_vtable on + * systems without anything better than pipe. + */ + +#include + +#ifdef GPR_POSIX_NO_SPECIAL_WAKEUP_FD + +#include +#include "src/core/iomgr/wakeup_fd_posix.h" + +static int check_availability_invalid(void) { return 0; } + +const grpc_wakeup_fd_vtable grpc_specialized_wakeup_fd_vtable = { + NULL, NULL, NULL, NULL, check_availability_invalid}; + +#endif /* GPR_POSIX_NO_SPECIAL_WAKEUP_FD */ diff --git a/src/core/lib/iomgr/wakeup_fd_pipe.c b/src/core/lib/iomgr/wakeup_fd_pipe.c new file mode 100644 index 0000000000..dd2fd1f057 --- /dev/null +++ b/src/core/lib/iomgr/wakeup_fd_pipe.c @@ -0,0 +1,102 @@ +/* + * + * Copyright 2015-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 + +#ifdef GPR_POSIX_WAKEUP_FD + +#include "src/core/iomgr/wakeup_fd_posix.h" + +#include +#include +#include + +#include + +#include "src/core/iomgr/socket_utils_posix.h" + +static void pipe_init(grpc_wakeup_fd* fd_info) { + int pipefd[2]; + /* TODO(klempner): Make this nonfatal */ + int r = pipe(pipefd); + if (0 != r) { + gpr_log(GPR_ERROR, "pipe creation failed (%d): %s", errno, strerror(errno)); + abort(); + } + GPR_ASSERT(grpc_set_socket_nonblocking(pipefd[0], 1)); + GPR_ASSERT(grpc_set_socket_nonblocking(pipefd[1], 1)); + fd_info->read_fd = pipefd[0]; + fd_info->write_fd = pipefd[1]; +} + +static void pipe_consume(grpc_wakeup_fd* fd_info) { + char buf[128]; + ssize_t r; + + for (;;) { + r = read(fd_info->read_fd, buf, sizeof(buf)); + if (r > 0) continue; + if (r == 0) return; + switch (errno) { + case EAGAIN: + return; + case EINTR: + continue; + default: + gpr_log(GPR_ERROR, "error reading pipe: %s", strerror(errno)); + return; + } + } +} + +static void pipe_wakeup(grpc_wakeup_fd* fd_info) { + char c = 0; + while (write(fd_info->write_fd, &c, 1) != 1 && errno == EINTR) + ; +} + +static void pipe_destroy(grpc_wakeup_fd* fd_info) { + if (fd_info->read_fd != 0) close(fd_info->read_fd); + if (fd_info->write_fd != 0) close(fd_info->write_fd); +} + +static int pipe_check_availability(void) { + /* Assume that pipes are always available. */ + return 1; +} + +const grpc_wakeup_fd_vtable grpc_pipe_wakeup_fd_vtable = { + pipe_init, pipe_consume, pipe_wakeup, pipe_destroy, + pipe_check_availability}; + +#endif /* GPR_POSIX_WAKUP_FD */ diff --git a/src/core/lib/iomgr/wakeup_fd_pipe.h b/src/core/lib/iomgr/wakeup_fd_pipe.h new file mode 100644 index 0000000000..eb3e02b482 --- /dev/null +++ b/src/core/lib/iomgr/wakeup_fd_pipe.h @@ -0,0 +1,41 @@ +/* + * + * Copyright 2015-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_IOMGR_WAKEUP_FD_PIPE_H +#define GRPC_CORE_IOMGR_WAKEUP_FD_PIPE_H + +#include "src/core/iomgr/wakeup_fd_posix.h" + +extern grpc_wakeup_fd_vtable grpc_pipe_wakeup_fd_vtable; + +#endif /* GRPC_CORE_IOMGR_WAKEUP_FD_PIPE_H */ diff --git a/src/core/lib/iomgr/wakeup_fd_posix.c b/src/core/lib/iomgr/wakeup_fd_posix.c new file mode 100644 index 0000000000..07778c408e --- /dev/null +++ b/src/core/lib/iomgr/wakeup_fd_posix.c @@ -0,0 +1,72 @@ +/* + * + * Copyright 2015-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 + +#ifdef GPR_POSIX_WAKEUP_FD + +#include +#include "src/core/iomgr/wakeup_fd_pipe.h" +#include "src/core/iomgr/wakeup_fd_posix.h" + +static const grpc_wakeup_fd_vtable *wakeup_fd_vtable = NULL; +int grpc_allow_specialized_wakeup_fd = 1; + +void grpc_wakeup_fd_global_init(void) { + if (grpc_allow_specialized_wakeup_fd && + grpc_specialized_wakeup_fd_vtable.check_availability()) { + wakeup_fd_vtable = &grpc_specialized_wakeup_fd_vtable; + } else { + wakeup_fd_vtable = &grpc_pipe_wakeup_fd_vtable; + } +} + +void grpc_wakeup_fd_global_destroy(void) { wakeup_fd_vtable = NULL; } + +void grpc_wakeup_fd_init(grpc_wakeup_fd *fd_info) { + wakeup_fd_vtable->init(fd_info); +} + +void grpc_wakeup_fd_consume_wakeup(grpc_wakeup_fd *fd_info) { + wakeup_fd_vtable->consume(fd_info); +} + +void grpc_wakeup_fd_wakeup(grpc_wakeup_fd *fd_info) { + wakeup_fd_vtable->wakeup(fd_info); +} + +void grpc_wakeup_fd_destroy(grpc_wakeup_fd *fd_info) { + wakeup_fd_vtable->destroy(fd_info); +} + +#endif /* GPR_POSIX_WAKEUP_FD */ diff --git a/src/core/lib/iomgr/wakeup_fd_posix.h b/src/core/lib/iomgr/wakeup_fd_posix.h new file mode 100644 index 0000000000..d7e3cf4673 --- /dev/null +++ b/src/core/lib/iomgr/wakeup_fd_posix.h @@ -0,0 +1,101 @@ +/* + * + * Copyright 2015-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. + * + */ + +/* + * wakeup_fd abstracts the concept of a file descriptor for the purpose of + * waking up a thread in select()/poll()/epoll_wait()/etc. + + * The poll() family of system calls provide a way for a thread to block until + * there is activity on one (or more) of a set of file descriptors. An + * application may wish to wake up this thread to do non file related work. The + * typical way to do this is to add a pipe to the set of file descriptors, then + * write to the pipe to wake up the thread in poll(). + * + * Linux has a lighter weight eventfd specifically designed for this purpose. + * wakeup_fd abstracts the difference between the two. + * + * Setup: + * 1. Before calling anything, call global_init() at least once. + * 1. Call grpc_wakeup_fd_create() to get a wakeup_fd. + * 2. Add the result of GRPC_WAKEUP_FD_FD to the set of monitored file + * descriptors for the poll() style API you are using. Monitor the file + * descriptor for readability. + * 3. To tear down, call grpc_wakeup_fd_destroy(). This closes the underlying + * file descriptor. + * + * Usage: + * 1. To wake up a polling thread, call grpc_wakeup_fd_wakeup() on a wakeup_fd + * it is monitoring. + * 2. If the polling thread was awakened by a wakeup_fd event, call + * grpc_wakeup_fd_consume_wakeup() on it. + */ +#ifndef GRPC_CORE_IOMGR_WAKEUP_FD_POSIX_H +#define GRPC_CORE_IOMGR_WAKEUP_FD_POSIX_H + +void grpc_wakeup_fd_global_init(void); +void grpc_wakeup_fd_global_destroy(void); + +/* Force using the fallback implementation. This is intended for testing + * purposes only.*/ +void grpc_wakeup_fd_global_init_force_fallback(void); + +typedef struct grpc_wakeup_fd grpc_wakeup_fd; + +typedef struct grpc_wakeup_fd_vtable { + void (*init)(grpc_wakeup_fd* fd_info); + void (*consume)(grpc_wakeup_fd* fd_info); + void (*wakeup)(grpc_wakeup_fd* fd_info); + void (*destroy)(grpc_wakeup_fd* fd_info); + /* Must be called before calling any other functions */ + int (*check_availability)(void); +} grpc_wakeup_fd_vtable; + +struct grpc_wakeup_fd { + int read_fd; + int write_fd; +}; + +extern int grpc_allow_specialized_wakeup_fd; + +#define GRPC_WAKEUP_FD_GET_READ_FD(fd_info) ((fd_info)->read_fd) + +void grpc_wakeup_fd_init(grpc_wakeup_fd* fd_info); +void grpc_wakeup_fd_consume_wakeup(grpc_wakeup_fd* fd_info); +void grpc_wakeup_fd_wakeup(grpc_wakeup_fd* fd_info); +void grpc_wakeup_fd_destroy(grpc_wakeup_fd* fd_info); + +/* Defined in some specialized implementation's .c file, or by + * wakeup_fd_nospecial.c if no such implementation exists. */ +extern const grpc_wakeup_fd_vtable grpc_specialized_wakeup_fd_vtable; + +#endif /* GRPC_CORE_IOMGR_WAKEUP_FD_POSIX_H */ diff --git a/src/core/lib/iomgr/workqueue.h b/src/core/lib/iomgr/workqueue.h new file mode 100644 index 0000000000..2b923ba152 --- /dev/null +++ b/src/core/lib/iomgr/workqueue.h @@ -0,0 +1,83 @@ +/* + * + * Copyright 2015-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_IOMGR_WORKQUEUE_H +#define GRPC_CORE_IOMGR_WORKQUEUE_H + +#include "src/core/iomgr/closure.h" +#include "src/core/iomgr/exec_ctx.h" +#include "src/core/iomgr/iomgr.h" +#include "src/core/iomgr/pollset.h" + +#ifdef GPR_POSIX_SOCKET +#include "src/core/iomgr/workqueue_posix.h" +#endif + +#ifdef GPR_WIN32 +#include "src/core/iomgr/workqueue_windows.h" +#endif + +/* grpc_workqueue is forward declared in exec_ctx.h */ + +/** Create a work queue */ +grpc_workqueue *grpc_workqueue_create(grpc_exec_ctx *exec_ctx); + +void grpc_workqueue_flush(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue); + +#define GRPC_WORKQUEUE_REFCOUNT_DEBUG +#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG +#define GRPC_WORKQUEUE_REF(p, r) \ + grpc_workqueue_ref((p), __FILE__, __LINE__, (r)) +#define GRPC_WORKQUEUE_UNREF(cl, p, r) \ + grpc_workqueue_unref((cl), (p), __FILE__, __LINE__, (r)) +void grpc_workqueue_ref(grpc_workqueue *workqueue, const char *file, int line, + const char *reason); +void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue, + const char *file, int line, const char *reason); +#else +#define GRPC_WORKQUEUE_REF(p, r) grpc_workqueue_ref((p)) +#define GRPC_WORKQUEUE_UNREF(cl, p, r) grpc_workqueue_unref((cl), (p)) +void grpc_workqueue_ref(grpc_workqueue *workqueue); +void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue); +#endif + +/** Bind this workqueue to a pollset */ +void grpc_workqueue_add_to_pollset(grpc_exec_ctx *exec_ctx, + grpc_workqueue *workqueue, + grpc_pollset *pollset); + +/** Add a work item to a workqueue */ +void grpc_workqueue_push(grpc_workqueue *workqueue, grpc_closure *closure, + int success); + +#endif /* GRPC_CORE_IOMGR_WORKQUEUE_H */ diff --git a/src/core/lib/iomgr/workqueue_posix.c b/src/core/lib/iomgr/workqueue_posix.c new file mode 100644 index 0000000000..2b42e6d4fb --- /dev/null +++ b/src/core/lib/iomgr/workqueue_posix.c @@ -0,0 +1,144 @@ +/* + * + * Copyright 2015-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 + +#ifdef GPR_POSIX_SOCKET + +#include "src/core/iomgr/workqueue.h" + +#include + +#include +#include +#include + +#include "src/core/iomgr/fd_posix.h" +#include "src/core/iomgr/pollset_posix.h" + +static void on_readable(grpc_exec_ctx *exec_ctx, void *arg, bool success); + +grpc_workqueue *grpc_workqueue_create(grpc_exec_ctx *exec_ctx) { + char name[32]; + grpc_workqueue *workqueue = gpr_malloc(sizeof(grpc_workqueue)); + gpr_ref_init(&workqueue->refs, 1); + gpr_mu_init(&workqueue->mu); + workqueue->closure_list.head = workqueue->closure_list.tail = NULL; + grpc_wakeup_fd_init(&workqueue->wakeup_fd); + sprintf(name, "workqueue:%p", (void *)workqueue); + workqueue->wakeup_read_fd = + grpc_fd_create(GRPC_WAKEUP_FD_GET_READ_FD(&workqueue->wakeup_fd), name); + grpc_closure_init(&workqueue->read_closure, on_readable, workqueue); + grpc_fd_notify_on_read(exec_ctx, workqueue->wakeup_read_fd, + &workqueue->read_closure); + return workqueue; +} + +static void workqueue_destroy(grpc_exec_ctx *exec_ctx, + grpc_workqueue *workqueue) { + GPR_ASSERT(grpc_closure_list_empty(workqueue->closure_list)); + grpc_fd_shutdown(exec_ctx, workqueue->wakeup_read_fd); +} + +#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG +void grpc_workqueue_ref(grpc_workqueue *workqueue, const char *file, int line, + const char *reason) { + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "WORKQUEUE:%p ref %d -> %d %s", + workqueue, (int)workqueue->refs.count, (int)workqueue->refs.count + 1, + reason); +#else +void grpc_workqueue_ref(grpc_workqueue *workqueue) { +#endif + gpr_ref(&workqueue->refs); +} + +#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG +void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue, + const char *file, int line, const char *reason) { + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "WORKQUEUE:%p unref %d -> %d %s", + workqueue, (int)workqueue->refs.count, (int)workqueue->refs.count - 1, + reason); +#else +void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) { +#endif + if (gpr_unref(&workqueue->refs)) { + workqueue_destroy(exec_ctx, workqueue); + } +} + +void grpc_workqueue_add_to_pollset(grpc_exec_ctx *exec_ctx, + grpc_workqueue *workqueue, + grpc_pollset *pollset) { + grpc_pollset_add_fd(exec_ctx, pollset, workqueue->wakeup_read_fd); +} + +void grpc_workqueue_flush(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) { + gpr_mu_lock(&workqueue->mu); + if (grpc_closure_list_empty(workqueue->closure_list)) { + grpc_wakeup_fd_wakeup(&workqueue->wakeup_fd); + } + grpc_exec_ctx_enqueue_list(exec_ctx, &workqueue->closure_list, NULL); + gpr_mu_unlock(&workqueue->mu); +} + +static void on_readable(grpc_exec_ctx *exec_ctx, void *arg, bool success) { + grpc_workqueue *workqueue = arg; + + if (!success) { + gpr_mu_destroy(&workqueue->mu); + /* HACK: let wakeup_fd code know that we stole the fd */ + workqueue->wakeup_fd.read_fd = 0; + grpc_wakeup_fd_destroy(&workqueue->wakeup_fd); + grpc_fd_orphan(exec_ctx, workqueue->wakeup_read_fd, NULL, NULL, "destroy"); + gpr_free(workqueue); + } else { + gpr_mu_lock(&workqueue->mu); + grpc_exec_ctx_enqueue_list(exec_ctx, &workqueue->closure_list, NULL); + grpc_wakeup_fd_consume_wakeup(&workqueue->wakeup_fd); + gpr_mu_unlock(&workqueue->mu); + grpc_fd_notify_on_read(exec_ctx, workqueue->wakeup_read_fd, + &workqueue->read_closure); + } +} + +void grpc_workqueue_push(grpc_workqueue *workqueue, grpc_closure *closure, + int success) { + gpr_mu_lock(&workqueue->mu); + if (grpc_closure_list_empty(workqueue->closure_list)) { + grpc_wakeup_fd_wakeup(&workqueue->wakeup_fd); + } + grpc_closure_list_add(&workqueue->closure_list, closure, success); + gpr_mu_unlock(&workqueue->mu); +} + +#endif /* GPR_POSIX_SOCKET */ diff --git a/src/core/lib/iomgr/workqueue_posix.h b/src/core/lib/iomgr/workqueue_posix.h new file mode 100644 index 0000000000..89937b1ea8 --- /dev/null +++ b/src/core/lib/iomgr/workqueue_posix.h @@ -0,0 +1,53 @@ +/* + * + * Copyright 2015-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_IOMGR_WORKQUEUE_POSIX_H +#define GRPC_CORE_IOMGR_WORKQUEUE_POSIX_H + +#include "src/core/iomgr/wakeup_fd_posix.h" + +struct grpc_fd; + +struct grpc_workqueue { + gpr_refcount refs; + + gpr_mu mu; + grpc_closure_list closure_list; + + grpc_wakeup_fd wakeup_fd; + struct grpc_fd *wakeup_read_fd; + + grpc_closure read_closure; +}; + +#endif /* GRPC_CORE_IOMGR_WORKQUEUE_POSIX_H */ diff --git a/src/core/lib/iomgr/workqueue_windows.c b/src/core/lib/iomgr/workqueue_windows.c new file mode 100644 index 0000000000..f9ca57557b --- /dev/null +++ b/src/core/lib/iomgr/workqueue_windows.c @@ -0,0 +1,40 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +#ifdef GPR_WIN32 + +#include "src/core/iomgr/workqueue.h" + +#endif /* GPR_WIN32 */ diff --git a/src/core/lib/iomgr/workqueue_windows.h b/src/core/lib/iomgr/workqueue_windows.h new file mode 100644 index 0000000000..7e8186921e --- /dev/null +++ b/src/core/lib/iomgr/workqueue_windows.h @@ -0,0 +1,37 @@ +/* + * + * Copyright 2015-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_IOMGR_WORKQUEUE_WINDOWS_H +#define GRPC_CORE_IOMGR_WORKQUEUE_WINDOWS_H + +#endif /* GRPC_CORE_IOMGR_WORKQUEUE_WINDOWS_H */ diff --git a/src/core/lib/json/json.c b/src/core/lib/json/json.c new file mode 100644 index 0000000000..96e11eebb1 --- /dev/null +++ b/src/core/lib/json/json.c @@ -0,0 +1,64 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +#include + +#include "src/core/json/json.h" + +grpc_json *grpc_json_create(grpc_json_type type) { + grpc_json *json = gpr_malloc(sizeof(*json)); + memset(json, 0, sizeof(*json)); + json->type = type; + + return json; +} + +void grpc_json_destroy(grpc_json *json) { + while (json->child) { + grpc_json_destroy(json->child); + } + + if (json->next) { + json->next->prev = json->prev; + } + + if (json->prev) { + json->prev->next = json->next; + } else if (json->parent) { + json->parent->child = json->next; + } + + gpr_free(json); +} diff --git a/src/core/lib/json/json.h b/src/core/lib/json/json.h new file mode 100644 index 0000000000..aea9d5dadb --- /dev/null +++ b/src/core/lib/json/json.h @@ -0,0 +1,88 @@ +/* + * + * Copyright 2015-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_JSON_JSON_H +#define GRPC_CORE_JSON_JSON_H + +#include + +#include "src/core/json/json_common.h" + +/* A tree-like structure to hold json values. The key and value pointers + * are not owned by it. + */ +typedef struct grpc_json { + struct grpc_json *next; + struct grpc_json *prev; + struct grpc_json *child; + struct grpc_json *parent; + + grpc_json_type type; + const char *key; + const char *value; +} grpc_json; + +/* The next two functions are going to parse the input string, and + * modify it in the process, in order to use its space to store + * all of the keys and values for the returned object tree. + * + * They assume UTF-8 input stream, and will output UTF-8 encoded + * strings in the tree. The input stream's UTF-8 isn't validated, + * as in, what you input is what you get as an output. + * + * All the keys and values in the grpc_json objects will be strings + * pointing at your input buffer. + * + * Delete the allocated tree afterward using grpc_json_destroy(). + */ +grpc_json *grpc_json_parse_string_with_len(char *input, size_t size); +grpc_json *grpc_json_parse_string(char *input); + +/* This function will create a new string using gpr_realloc, and will + * deserialize the grpc_json tree into it. It'll be zero-terminated, + * but will be allocated in chunks of 256 bytes. + * + * The indent parameter controls the way the output is formatted. + * If indent is 0, then newlines will be suppressed as well, and the + * output will be condensed at its maximum. + */ +char *grpc_json_dump_to_string(grpc_json *json, int indent); + +/* Use these to create or delete a grpc_json object. + * Deletion is recursive. We will not attempt to free any of the strings + * in any of the objects of that tree. + */ +grpc_json *grpc_json_create(grpc_json_type type); +void grpc_json_destroy(grpc_json *json); + +#endif /* GRPC_CORE_JSON_JSON_H */ diff --git a/src/core/lib/json/json_common.h b/src/core/lib/json/json_common.h new file mode 100644 index 0000000000..7205a94685 --- /dev/null +++ b/src/core/lib/json/json_common.h @@ -0,0 +1,49 @@ +/* + * + * Copyright 2015-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_JSON_JSON_COMMON_H +#define GRPC_CORE_JSON_JSON_COMMON_H + +/* The various json types. */ +typedef enum { + GRPC_JSON_OBJECT, + GRPC_JSON_ARRAY, + GRPC_JSON_STRING, + GRPC_JSON_NUMBER, + GRPC_JSON_TRUE, + GRPC_JSON_FALSE, + GRPC_JSON_NULL, + GRPC_JSON_TOP_LEVEL +} grpc_json_type; + +#endif /* GRPC_CORE_JSON_JSON_COMMON_H */ diff --git a/src/core/lib/json/json_reader.c b/src/core/lib/json/json_reader.c new file mode 100644 index 0000000000..30da6f28f3 --- /dev/null +++ b/src/core/lib/json/json_reader.c @@ -0,0 +1,659 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +#include + +#include + +#include "src/core/json/json_reader.h" + +static void json_reader_string_clear(grpc_json_reader *reader) { + reader->vtable->string_clear(reader->userdata); +} + +static void json_reader_string_add_char(grpc_json_reader *reader, uint32_t c) { + reader->vtable->string_add_char(reader->userdata, c); +} + +static void json_reader_string_add_utf32(grpc_json_reader *reader, + uint32_t utf32) { + reader->vtable->string_add_utf32(reader->userdata, utf32); +} + +static uint32_t grpc_json_reader_read_char(grpc_json_reader *reader) { + return reader->vtable->read_char(reader->userdata); +} + +static void json_reader_container_begins(grpc_json_reader *reader, + grpc_json_type type) { + reader->vtable->container_begins(reader->userdata, type); +} + +static grpc_json_type grpc_json_reader_container_ends( + grpc_json_reader *reader) { + return reader->vtable->container_ends(reader->userdata); +} + +static void json_reader_set_key(grpc_json_reader *reader) { + reader->vtable->set_key(reader->userdata); +} + +static void json_reader_set_string(grpc_json_reader *reader) { + reader->vtable->set_string(reader->userdata); +} + +static int json_reader_set_number(grpc_json_reader *reader) { + return reader->vtable->set_number(reader->userdata); +} + +static void json_reader_set_true(grpc_json_reader *reader) { + reader->vtable->set_true(reader->userdata); +} + +static void json_reader_set_false(grpc_json_reader *reader) { + reader->vtable->set_false(reader->userdata); +} + +static void json_reader_set_null(grpc_json_reader *reader) { + reader->vtable->set_null(reader->userdata); +} + +/* Call this function to initialize the reader structure. */ +void grpc_json_reader_init(grpc_json_reader *reader, + grpc_json_reader_vtable *vtable, void *userdata) { + memset(reader, 0, sizeof(*reader)); + reader->vtable = vtable; + reader->userdata = userdata; + json_reader_string_clear(reader); + reader->state = GRPC_JSON_STATE_VALUE_BEGIN; +} + +int grpc_json_reader_is_complete(grpc_json_reader *reader) { + return ((reader->depth == 0) && + ((reader->state == GRPC_JSON_STATE_END) || + (reader->state == GRPC_JSON_STATE_VALUE_END))); +} + +grpc_json_reader_status grpc_json_reader_run(grpc_json_reader *reader) { + uint32_t c, success; + + /* This state-machine is a strict implementation of ECMA-404 */ + for (;;) { + c = grpc_json_reader_read_char(reader); + switch (c) { + /* Let's process the error cases first. */ + case GRPC_JSON_READ_CHAR_ERROR: + return GRPC_JSON_READ_ERROR; + + case GRPC_JSON_READ_CHAR_EAGAIN: + return GRPC_JSON_EAGAIN; + + case GRPC_JSON_READ_CHAR_EOF: + if (grpc_json_reader_is_complete(reader)) { + return GRPC_JSON_DONE; + } else { + return GRPC_JSON_PARSE_ERROR; + } + break; + + /* Processing whitespaces. */ + case ' ': + case '\t': + case '\n': + case '\r': + switch (reader->state) { + case GRPC_JSON_STATE_OBJECT_KEY_BEGIN: + case GRPC_JSON_STATE_OBJECT_KEY_END: + case GRPC_JSON_STATE_VALUE_BEGIN: + case GRPC_JSON_STATE_VALUE_END: + case GRPC_JSON_STATE_END: + break; + + case GRPC_JSON_STATE_OBJECT_KEY_STRING: + case GRPC_JSON_STATE_VALUE_STRING: + if (c != ' ') return GRPC_JSON_PARSE_ERROR; + if (reader->unicode_high_surrogate != 0) + return GRPC_JSON_PARSE_ERROR; + json_reader_string_add_char(reader, c); + break; + + case GRPC_JSON_STATE_VALUE_NUMBER: + case GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL: + case GRPC_JSON_STATE_VALUE_NUMBER_ZERO: + case GRPC_JSON_STATE_VALUE_NUMBER_EPM: + success = (uint32_t)json_reader_set_number(reader); + if (!success) return GRPC_JSON_PARSE_ERROR; + json_reader_string_clear(reader); + reader->state = GRPC_JSON_STATE_VALUE_END; + break; + + default: + return GRPC_JSON_PARSE_ERROR; + } + break; + + /* Value, object or array terminations. */ + case ',': + case '}': + case ']': + switch (reader->state) { + case GRPC_JSON_STATE_OBJECT_KEY_STRING: + case GRPC_JSON_STATE_VALUE_STRING: + if (reader->unicode_high_surrogate != 0) + return GRPC_JSON_PARSE_ERROR; + json_reader_string_add_char(reader, c); + break; + + case GRPC_JSON_STATE_VALUE_NUMBER: + case GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL: + case GRPC_JSON_STATE_VALUE_NUMBER_ZERO: + case GRPC_JSON_STATE_VALUE_NUMBER_EPM: + success = (uint32_t)json_reader_set_number(reader); + if (!success) return GRPC_JSON_PARSE_ERROR; + json_reader_string_clear(reader); + reader->state = GRPC_JSON_STATE_VALUE_END; + /* The missing break here is intentional. */ + + case GRPC_JSON_STATE_VALUE_END: + case GRPC_JSON_STATE_OBJECT_KEY_BEGIN: + case GRPC_JSON_STATE_VALUE_BEGIN: + if (c == ',') { + if (reader->state != GRPC_JSON_STATE_VALUE_END) { + return GRPC_JSON_PARSE_ERROR; + } + if (reader->in_object) { + reader->state = GRPC_JSON_STATE_OBJECT_KEY_BEGIN; + } else { + reader->state = GRPC_JSON_STATE_VALUE_BEGIN; + } + } else { + if (reader->depth-- == 0) return GRPC_JSON_PARSE_ERROR; + if ((c == '}') && !reader->in_object) { + return GRPC_JSON_PARSE_ERROR; + } + if ((c == '}') && + (reader->state == GRPC_JSON_STATE_OBJECT_KEY_BEGIN) && + !reader->container_just_begun) { + return GRPC_JSON_PARSE_ERROR; + } + if ((c == ']') && !reader->in_array) return GRPC_JSON_PARSE_ERROR; + if ((c == ']') && + (reader->state == GRPC_JSON_STATE_VALUE_BEGIN) && + !reader->container_just_begun) { + return GRPC_JSON_PARSE_ERROR; + } + reader->state = GRPC_JSON_STATE_VALUE_END; + switch (grpc_json_reader_container_ends(reader)) { + case GRPC_JSON_OBJECT: + reader->in_object = 1; + reader->in_array = 0; + break; + case GRPC_JSON_ARRAY: + reader->in_object = 0; + reader->in_array = 1; + break; + case GRPC_JSON_TOP_LEVEL: + GPR_ASSERT(reader->depth == 0); + reader->in_object = 0; + reader->in_array = 0; + reader->state = GRPC_JSON_STATE_END; + break; + default: + GPR_UNREACHABLE_CODE(return GRPC_JSON_INTERNAL_ERROR); + } + } + break; + + default: + return GRPC_JSON_PARSE_ERROR; + } + break; + + /* In-string escaping. */ + case '\\': + switch (reader->state) { + case GRPC_JSON_STATE_OBJECT_KEY_STRING: + reader->escaped_string_was_key = 1; + reader->state = GRPC_JSON_STATE_STRING_ESCAPE; + break; + + case GRPC_JSON_STATE_VALUE_STRING: + reader->escaped_string_was_key = 0; + reader->state = GRPC_JSON_STATE_STRING_ESCAPE; + break; + + /* This is the \\ case. */ + case GRPC_JSON_STATE_STRING_ESCAPE: + if (reader->unicode_high_surrogate != 0) + return GRPC_JSON_PARSE_ERROR; + json_reader_string_add_char(reader, '\\'); + if (reader->escaped_string_was_key) { + reader->state = GRPC_JSON_STATE_OBJECT_KEY_STRING; + } else { + reader->state = GRPC_JSON_STATE_VALUE_STRING; + } + break; + + default: + return GRPC_JSON_PARSE_ERROR; + } + break; + + default: + reader->container_just_begun = 0; + switch (reader->state) { + case GRPC_JSON_STATE_OBJECT_KEY_BEGIN: + if (c != '"') return GRPC_JSON_PARSE_ERROR; + reader->state = GRPC_JSON_STATE_OBJECT_KEY_STRING; + break; + + case GRPC_JSON_STATE_OBJECT_KEY_STRING: + GPR_ASSERT(reader->unicode_high_surrogate == 0); + if (c == '"') { + reader->state = GRPC_JSON_STATE_OBJECT_KEY_END; + json_reader_set_key(reader); + json_reader_string_clear(reader); + } else { + if (c <= 0x001f) return GRPC_JSON_PARSE_ERROR; + json_reader_string_add_char(reader, c); + } + break; + + case GRPC_JSON_STATE_VALUE_STRING: + if (reader->unicode_high_surrogate != 0) + return GRPC_JSON_PARSE_ERROR; + if (c == '"') { + reader->state = GRPC_JSON_STATE_VALUE_END; + json_reader_set_string(reader); + json_reader_string_clear(reader); + } else { + if (c < 32) return GRPC_JSON_PARSE_ERROR; + json_reader_string_add_char(reader, c); + } + break; + + case GRPC_JSON_STATE_OBJECT_KEY_END: + if (c != ':') return GRPC_JSON_PARSE_ERROR; + reader->state = GRPC_JSON_STATE_VALUE_BEGIN; + break; + + case GRPC_JSON_STATE_VALUE_BEGIN: + switch (c) { + case 't': + reader->state = GRPC_JSON_STATE_VALUE_TRUE_R; + break; + + case 'f': + reader->state = GRPC_JSON_STATE_VALUE_FALSE_A; + break; + + case 'n': + reader->state = GRPC_JSON_STATE_VALUE_NULL_U; + break; + + case '"': + reader->state = GRPC_JSON_STATE_VALUE_STRING; + break; + + case '0': + json_reader_string_add_char(reader, c); + reader->state = GRPC_JSON_STATE_VALUE_NUMBER_ZERO; + break; + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '-': + json_reader_string_add_char(reader, c); + reader->state = GRPC_JSON_STATE_VALUE_NUMBER; + break; + + case '{': + reader->container_just_begun = 1; + json_reader_container_begins(reader, GRPC_JSON_OBJECT); + reader->depth++; + reader->state = GRPC_JSON_STATE_OBJECT_KEY_BEGIN; + reader->in_object = 1; + reader->in_array = 0; + break; + + case '[': + reader->container_just_begun = 1; + json_reader_container_begins(reader, GRPC_JSON_ARRAY); + reader->depth++; + reader->in_object = 0; + reader->in_array = 1; + break; + } + break; + + case GRPC_JSON_STATE_STRING_ESCAPE: + if (reader->escaped_string_was_key) { + reader->state = GRPC_JSON_STATE_OBJECT_KEY_STRING; + } else { + reader->state = GRPC_JSON_STATE_VALUE_STRING; + } + if (reader->unicode_high_surrogate && c != 'u') + return GRPC_JSON_PARSE_ERROR; + switch (c) { + case '"': + case '/': + json_reader_string_add_char(reader, c); + break; + case 'b': + json_reader_string_add_char(reader, '\b'); + break; + case 'f': + json_reader_string_add_char(reader, '\f'); + break; + case 'n': + json_reader_string_add_char(reader, '\n'); + break; + case 'r': + json_reader_string_add_char(reader, '\r'); + break; + case 't': + json_reader_string_add_char(reader, '\t'); + break; + case 'u': + reader->state = GRPC_JSON_STATE_STRING_ESCAPE_U1; + reader->unicode_char = 0; + break; + default: + return GRPC_JSON_PARSE_ERROR; + } + break; + + case GRPC_JSON_STATE_STRING_ESCAPE_U1: + case GRPC_JSON_STATE_STRING_ESCAPE_U2: + case GRPC_JSON_STATE_STRING_ESCAPE_U3: + case GRPC_JSON_STATE_STRING_ESCAPE_U4: + if ((c >= '0') && (c <= '9')) { + c -= '0'; + } else if ((c >= 'A') && (c <= 'F')) { + c -= 'A' - 10; + } else if ((c >= 'a') && (c <= 'f')) { + c -= 'a' - 10; + } else { + return GRPC_JSON_PARSE_ERROR; + } + reader->unicode_char = (uint16_t)(reader->unicode_char << 4); + reader->unicode_char = (uint16_t)(reader->unicode_char | c); + + switch (reader->state) { + case GRPC_JSON_STATE_STRING_ESCAPE_U1: + reader->state = GRPC_JSON_STATE_STRING_ESCAPE_U2; + break; + case GRPC_JSON_STATE_STRING_ESCAPE_U2: + reader->state = GRPC_JSON_STATE_STRING_ESCAPE_U3; + break; + case GRPC_JSON_STATE_STRING_ESCAPE_U3: + reader->state = GRPC_JSON_STATE_STRING_ESCAPE_U4; + break; + case GRPC_JSON_STATE_STRING_ESCAPE_U4: + /* See grpc_json_writer_escape_string to have a description + * of what's going on here. + */ + if ((reader->unicode_char & 0xfc00) == 0xd800) { + /* high surrogate utf-16 */ + if (reader->unicode_high_surrogate != 0) + return GRPC_JSON_PARSE_ERROR; + reader->unicode_high_surrogate = reader->unicode_char; + } else if ((reader->unicode_char & 0xfc00) == 0xdc00) { + /* low surrogate utf-16 */ + uint32_t utf32; + if (reader->unicode_high_surrogate == 0) + return GRPC_JSON_PARSE_ERROR; + utf32 = 0x10000; + utf32 += (uint32_t)( + (reader->unicode_high_surrogate - 0xd800) * 0x400); + utf32 += (uint32_t)(reader->unicode_char - 0xdc00); + json_reader_string_add_utf32(reader, utf32); + reader->unicode_high_surrogate = 0; + } else { + /* anything else */ + if (reader->unicode_high_surrogate != 0) + return GRPC_JSON_PARSE_ERROR; + json_reader_string_add_utf32(reader, reader->unicode_char); + } + if (reader->escaped_string_was_key) { + reader->state = GRPC_JSON_STATE_OBJECT_KEY_STRING; + } else { + reader->state = GRPC_JSON_STATE_VALUE_STRING; + } + break; + default: + GPR_UNREACHABLE_CODE(return GRPC_JSON_INTERNAL_ERROR); + } + break; + + case GRPC_JSON_STATE_VALUE_NUMBER: + json_reader_string_add_char(reader, c); + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + break; + case 'e': + case 'E': + reader->state = GRPC_JSON_STATE_VALUE_NUMBER_E; + break; + case '.': + reader->state = GRPC_JSON_STATE_VALUE_NUMBER_DOT; + break; + default: + return GRPC_JSON_PARSE_ERROR; + } + break; + + case GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL: + json_reader_string_add_char(reader, c); + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + break; + case 'e': + case 'E': + reader->state = GRPC_JSON_STATE_VALUE_NUMBER_E; + break; + default: + return GRPC_JSON_PARSE_ERROR; + } + break; + + case GRPC_JSON_STATE_VALUE_NUMBER_ZERO: + if (c != '.') return GRPC_JSON_PARSE_ERROR; + json_reader_string_add_char(reader, c); + reader->state = GRPC_JSON_STATE_VALUE_NUMBER_DOT; + break; + + case GRPC_JSON_STATE_VALUE_NUMBER_DOT: + json_reader_string_add_char(reader, c); + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + reader->state = GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL; + break; + default: + return GRPC_JSON_PARSE_ERROR; + } + break; + + case GRPC_JSON_STATE_VALUE_NUMBER_E: + json_reader_string_add_char(reader, c); + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '+': + case '-': + reader->state = GRPC_JSON_STATE_VALUE_NUMBER_EPM; + break; + default: + return GRPC_JSON_PARSE_ERROR; + } + break; + + case GRPC_JSON_STATE_VALUE_NUMBER_EPM: + json_reader_string_add_char(reader, c); + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + break; + default: + return GRPC_JSON_PARSE_ERROR; + } + break; + + case GRPC_JSON_STATE_VALUE_TRUE_R: + if (c != 'r') return GRPC_JSON_PARSE_ERROR; + reader->state = GRPC_JSON_STATE_VALUE_TRUE_U; + break; + + case GRPC_JSON_STATE_VALUE_TRUE_U: + if (c != 'u') return GRPC_JSON_PARSE_ERROR; + reader->state = GRPC_JSON_STATE_VALUE_TRUE_E; + break; + + case GRPC_JSON_STATE_VALUE_TRUE_E: + if (c != 'e') return GRPC_JSON_PARSE_ERROR; + json_reader_set_true(reader); + reader->state = GRPC_JSON_STATE_VALUE_END; + break; + + case GRPC_JSON_STATE_VALUE_FALSE_A: + if (c != 'a') return GRPC_JSON_PARSE_ERROR; + reader->state = GRPC_JSON_STATE_VALUE_FALSE_L; + break; + + case GRPC_JSON_STATE_VALUE_FALSE_L: + if (c != 'l') return GRPC_JSON_PARSE_ERROR; + reader->state = GRPC_JSON_STATE_VALUE_FALSE_S; + break; + + case GRPC_JSON_STATE_VALUE_FALSE_S: + if (c != 's') return GRPC_JSON_PARSE_ERROR; + reader->state = GRPC_JSON_STATE_VALUE_FALSE_E; + break; + + case GRPC_JSON_STATE_VALUE_FALSE_E: + if (c != 'e') return GRPC_JSON_PARSE_ERROR; + json_reader_set_false(reader); + reader->state = GRPC_JSON_STATE_VALUE_END; + break; + + case GRPC_JSON_STATE_VALUE_NULL_U: + if (c != 'u') return GRPC_JSON_PARSE_ERROR; + reader->state = GRPC_JSON_STATE_VALUE_NULL_L1; + break; + + case GRPC_JSON_STATE_VALUE_NULL_L1: + if (c != 'l') return GRPC_JSON_PARSE_ERROR; + reader->state = GRPC_JSON_STATE_VALUE_NULL_L2; + break; + + case GRPC_JSON_STATE_VALUE_NULL_L2: + if (c != 'l') return GRPC_JSON_PARSE_ERROR; + json_reader_set_null(reader); + reader->state = GRPC_JSON_STATE_VALUE_END; + break; + + /* All of the VALUE_END cases are handled in the specialized case + * above. */ + case GRPC_JSON_STATE_VALUE_END: + switch (c) { + case ',': + case '}': + case ']': + GPR_UNREACHABLE_CODE(return GRPC_JSON_INTERNAL_ERROR); + break; + + default: + return GRPC_JSON_PARSE_ERROR; + } + break; + + case GRPC_JSON_STATE_END: + return GRPC_JSON_PARSE_ERROR; + } + } + } + + GPR_UNREACHABLE_CODE(return GRPC_JSON_INTERNAL_ERROR); +} diff --git a/src/core/lib/json/json_reader.h b/src/core/lib/json/json_reader.h new file mode 100644 index 0000000000..f25f44b2ef --- /dev/null +++ b/src/core/lib/json/json_reader.h @@ -0,0 +1,160 @@ +/* + * + * Copyright 2015-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_JSON_JSON_READER_H +#define GRPC_CORE_JSON_JSON_READER_H + +#include +#include "src/core/json/json_common.h" + +typedef enum { + GRPC_JSON_STATE_OBJECT_KEY_BEGIN, + GRPC_JSON_STATE_OBJECT_KEY_STRING, + GRPC_JSON_STATE_OBJECT_KEY_END, + GRPC_JSON_STATE_VALUE_BEGIN, + GRPC_JSON_STATE_VALUE_STRING, + GRPC_JSON_STATE_STRING_ESCAPE, + GRPC_JSON_STATE_STRING_ESCAPE_U1, + GRPC_JSON_STATE_STRING_ESCAPE_U2, + GRPC_JSON_STATE_STRING_ESCAPE_U3, + GRPC_JSON_STATE_STRING_ESCAPE_U4, + GRPC_JSON_STATE_VALUE_NUMBER, + GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL, + GRPC_JSON_STATE_VALUE_NUMBER_ZERO, + GRPC_JSON_STATE_VALUE_NUMBER_DOT, + GRPC_JSON_STATE_VALUE_NUMBER_E, + GRPC_JSON_STATE_VALUE_NUMBER_EPM, + GRPC_JSON_STATE_VALUE_TRUE_R, + GRPC_JSON_STATE_VALUE_TRUE_U, + GRPC_JSON_STATE_VALUE_TRUE_E, + GRPC_JSON_STATE_VALUE_FALSE_A, + GRPC_JSON_STATE_VALUE_FALSE_L, + GRPC_JSON_STATE_VALUE_FALSE_S, + GRPC_JSON_STATE_VALUE_FALSE_E, + GRPC_JSON_STATE_VALUE_NULL_U, + GRPC_JSON_STATE_VALUE_NULL_L1, + GRPC_JSON_STATE_VALUE_NULL_L2, + GRPC_JSON_STATE_VALUE_END, + GRPC_JSON_STATE_END +} grpc_json_reader_state; + +enum { + /* The first non-unicode value is 0x110000. But let's pick + * a value high enough to start our error codes from. These + * values are safe to return from the read_char function. + */ + GRPC_JSON_READ_CHAR_EOF = 0x7ffffff0, + GRPC_JSON_READ_CHAR_EAGAIN, + GRPC_JSON_READ_CHAR_ERROR +}; + +struct grpc_json_reader; + +typedef struct grpc_json_reader_vtable { + /* Clears your internal string scratchpad. */ + void (*string_clear)(void *userdata); + /* Adds a char to the string scratchpad. */ + void (*string_add_char)(void *userdata, uint32_t c); + /* Adds a utf32 char to the string scratchpad. */ + void (*string_add_utf32)(void *userdata, uint32_t c); + /* Reads a character from your input. May be utf-8, 16 or 32. */ + uint32_t (*read_char)(void *userdata); + /* Starts a container of type GRPC_JSON_ARRAY or GRPC_JSON_OBJECT. */ + void (*container_begins)(void *userdata, grpc_json_type type); + /* Ends the current container. Must return the type of its parent. */ + grpc_json_type (*container_ends)(void *userdata); + /* Your internal string scratchpad is an object's key. */ + void (*set_key)(void *userdata); + /* Your internal string scratchpad is a string value. */ + void (*set_string)(void *userdata); + /* Your internal string scratchpad is a numerical value. Return 1 if valid. */ + int (*set_number)(void *userdata); + /* Sets the values true, false or null. */ + void (*set_true)(void *userdata); + void (*set_false)(void *userdata); + void (*set_null)(void *userdata); +} grpc_json_reader_vtable; + +typedef struct grpc_json_reader { + /* That structure is fully private, and initialized by grpc_json_reader_init. + * The definition is public so you can put it on your stack. + */ + + void *userdata; + grpc_json_reader_vtable *vtable; + int depth; + int in_object; + int in_array; + int escaped_string_was_key; + int container_just_begun; + uint16_t unicode_char, unicode_high_surrogate; + grpc_json_reader_state state; +} grpc_json_reader; + +/* The return type of the parser. */ +typedef enum { + GRPC_JSON_DONE, /* The parser finished successfully. */ + GRPC_JSON_EAGAIN, /* The parser yields to get more data. */ + GRPC_JSON_READ_ERROR, /* The parser passes through a read error. */ + GRPC_JSON_PARSE_ERROR, /* The parser found an error in the json stream. */ + GRPC_JSON_INTERNAL_ERROR /* The parser got an internal error. */ +} grpc_json_reader_status; + +/* Call this function to start parsing the input. It will return the following: + * . GRPC_JSON_DONE if the input got eof, and the parsing finished + * successfully. + * . GRPC_JSON_EAGAIN if the read_char function returned again. Call the + * parser again as needed. It is okay to call the parser in polling mode, + * although a bit dull. + * . GRPC_JSON_READ_ERROR if the read_char function returned an error. The + * state isn't broken however, and the function can be called again if the + * error has been corrected. But please use the EAGAIN feature instead for + * consistency. + * . GRPC_JSON_PARSE_ERROR if the input was somehow invalid. + * . GRPC_JSON_INTERNAL_ERROR if the parser somehow ended into an invalid + * internal state. + */ +grpc_json_reader_status grpc_json_reader_run(grpc_json_reader *reader); + +/* Call this function to initialize the reader structure. */ +void grpc_json_reader_init(grpc_json_reader *reader, + grpc_json_reader_vtable *vtable, void *userdata); + +/* You may call this from the read_char callback if you don't know where is the + * end of your input stream, and you'd like the json reader to hint you that it + * has completed reading its input, so you can return an EOF to it. Note that + * there might still be trailing whitespaces after that point. + */ +int grpc_json_reader_is_complete(grpc_json_reader *reader); + +#endif /* GRPC_CORE_JSON_JSON_READER_H */ diff --git a/src/core/lib/json/json_string.c b/src/core/lib/json/json_string.c new file mode 100644 index 0000000000..d4ebce18e1 --- /dev/null +++ b/src/core/lib/json/json_string.c @@ -0,0 +1,379 @@ +/* + * + * Copyright 2015-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 +#include + +#include +#include + +#include "src/core/json/json.h" +#include "src/core/json/json_reader.h" +#include "src/core/json/json_writer.h" + +/* The json reader will construct a bunch of grpc_json objects and + * link them all up together in a tree-like structure that will represent + * the json data in memory. + * + * It also uses its own input as a scratchpad to store all of the decoded, + * unescaped strings. So we need to keep track of all these pointers in + * that opaque structure the reader will carry for us. + * + * Note that this works because the act of parsing json always reduces its + * input size, and never expands it. + */ +typedef struct { + grpc_json *top; + grpc_json *current_container; + grpc_json *current_value; + uint8_t *input; + uint8_t *key; + uint8_t *string; + uint8_t *string_ptr; + size_t remaining_input; +} json_reader_userdata; + +/* This json writer will put everything in a big string. + * The point is that we allocate that string in chunks of 256 bytes. + */ +typedef struct { + char *output; + size_t free_space; + size_t string_len; + size_t allocated; +} json_writer_userdata; + +/* This function checks if there's enough space left in the output buffer, + * and will enlarge it if necessary. We're only allocating chunks of 256 + * bytes at a time (or multiples thereof). + */ +static void json_writer_output_check(void *userdata, size_t needed) { + json_writer_userdata *state = userdata; + if (state->free_space >= needed) return; + needed -= state->free_space; + /* Round up by 256 bytes. */ + needed = (needed + 0xff) & ~0xffU; + state->output = gpr_realloc(state->output, state->allocated + needed); + state->free_space += needed; + state->allocated += needed; +} + +/* These are needed by the writer's implementation. */ +static void json_writer_output_char(void *userdata, char c) { + json_writer_userdata *state = userdata; + json_writer_output_check(userdata, 1); + state->output[state->string_len++] = c; + state->free_space--; +} + +static void json_writer_output_string_with_len(void *userdata, const char *str, + size_t len) { + json_writer_userdata *state = userdata; + json_writer_output_check(userdata, len); + memcpy(state->output + state->string_len, str, len); + state->string_len += len; + state->free_space -= len; +} + +static void json_writer_output_string(void *userdata, const char *str) { + size_t len = strlen(str); + json_writer_output_string_with_len(userdata, str, len); +} + +/* The reader asks us to clear our scratchpad. In our case, we'll simply mark + * the end of the current string, and advance our output pointer. + */ +static void json_reader_string_clear(void *userdata) { + json_reader_userdata *state = userdata; + if (state->string) { + GPR_ASSERT(state->string_ptr < state->input); + *state->string_ptr++ = 0; + } + state->string = state->string_ptr; +} + +static void json_reader_string_add_char(void *userdata, uint32_t c) { + json_reader_userdata *state = userdata; + GPR_ASSERT(state->string_ptr < state->input); + GPR_ASSERT(c <= 0xff); + *state->string_ptr++ = (uint8_t)c; +} + +/* We are converting a UTF-32 character into UTF-8 here, + * as described by RFC3629. + */ +static void json_reader_string_add_utf32(void *userdata, uint32_t c) { + if (c <= 0x7f) { + json_reader_string_add_char(userdata, c); + } else if (c <= 0x7ff) { + uint32_t b1 = 0xc0 | ((c >> 6) & 0x1f); + uint32_t b2 = 0x80 | (c & 0x3f); + json_reader_string_add_char(userdata, b1); + json_reader_string_add_char(userdata, b2); + } else if (c <= 0xffff) { + uint32_t b1 = 0xe0 | ((c >> 12) & 0x0f); + uint32_t b2 = 0x80 | ((c >> 6) & 0x3f); + uint32_t b3 = 0x80 | (c & 0x3f); + json_reader_string_add_char(userdata, b1); + json_reader_string_add_char(userdata, b2); + json_reader_string_add_char(userdata, b3); + } else if (c <= 0x1fffff) { + uint32_t b1 = 0xf0 | ((c >> 18) & 0x07); + uint32_t b2 = 0x80 | ((c >> 12) & 0x3f); + uint32_t b3 = 0x80 | ((c >> 6) & 0x3f); + uint32_t b4 = 0x80 | (c & 0x3f); + json_reader_string_add_char(userdata, b1); + json_reader_string_add_char(userdata, b2); + json_reader_string_add_char(userdata, b3); + json_reader_string_add_char(userdata, b4); + } +} + +/* We consider that the input may be a zero-terminated string. So we + * can end up hitting eof before the end of the alleged string length. + */ +static uint32_t json_reader_read_char(void *userdata) { + uint32_t r; + json_reader_userdata *state = userdata; + + if (state->remaining_input == 0) return GRPC_JSON_READ_CHAR_EOF; + + r = *state->input++; + state->remaining_input--; + + if (r == 0) { + state->remaining_input = 0; + return GRPC_JSON_READ_CHAR_EOF; + } + + return r; +} + +/* Helper function to create a new grpc_json object and link it into + * our tree-in-progress inside our opaque structure. + */ +static grpc_json *json_create_and_link(void *userdata, grpc_json_type type) { + json_reader_userdata *state = userdata; + grpc_json *json = grpc_json_create(type); + + json->parent = state->current_container; + json->prev = state->current_value; + state->current_value = json; + + if (json->prev) { + json->prev->next = json; + } + if (json->parent) { + if (!json->parent->child) { + json->parent->child = json; + } + if (json->parent->type == GRPC_JSON_OBJECT) { + json->key = (char *)state->key; + } + } + if (!state->top) { + state->top = json; + } + + return json; +} + +static void json_reader_container_begins(void *userdata, grpc_json_type type) { + json_reader_userdata *state = userdata; + grpc_json *container; + + GPR_ASSERT(type == GRPC_JSON_ARRAY || type == GRPC_JSON_OBJECT); + + container = json_create_and_link(userdata, type); + state->current_container = container; + state->current_value = NULL; +} + +/* It's important to remember that the reader is mostly stateless, so it + * isn't trying to remember what the container was prior the one that just + * ends. Since we're keeping track of these for our own purpose, we are + * able to return that information back, which is useful for it to validate + * the input json stream. + * + * Also note that if we're at the top of the tree, and the last container + * ends, we have to return GRPC_JSON_TOP_LEVEL. + */ +static grpc_json_type json_reader_container_ends(void *userdata) { + grpc_json_type container_type = GRPC_JSON_TOP_LEVEL; + json_reader_userdata *state = userdata; + + GPR_ASSERT(state->current_container); + + state->current_value = state->current_container; + state->current_container = state->current_container->parent; + + if (state->current_container) { + container_type = state->current_container->type; + } + + return container_type; +} + +/* The next 3 functions basically are the reader asking us to use our string + * scratchpad for one of these 3 purposes. + * + * Note that in the set_number case, we're not going to try interpreting it. + * We'll keep it as a string, and leave it to the caller to evaluate it. + */ +static void json_reader_set_key(void *userdata) { + json_reader_userdata *state = userdata; + state->key = state->string; +} + +static void json_reader_set_string(void *userdata) { + json_reader_userdata *state = userdata; + grpc_json *json = json_create_and_link(userdata, GRPC_JSON_STRING); + json->value = (char *)state->string; +} + +static int json_reader_set_number(void *userdata) { + json_reader_userdata *state = userdata; + grpc_json *json = json_create_and_link(userdata, GRPC_JSON_NUMBER); + json->value = (char *)state->string; + return 1; +} + +/* The object types true, false and null are self-sufficient, and don't need + * any more information beside their type. + */ +static void json_reader_set_true(void *userdata) { + json_create_and_link(userdata, GRPC_JSON_TRUE); +} + +static void json_reader_set_false(void *userdata) { + json_create_and_link(userdata, GRPC_JSON_FALSE); +} + +static void json_reader_set_null(void *userdata) { + json_create_and_link(userdata, GRPC_JSON_NULL); +} + +static grpc_json_reader_vtable reader_vtable = { + json_reader_string_clear, json_reader_string_add_char, + json_reader_string_add_utf32, json_reader_read_char, + json_reader_container_begins, json_reader_container_ends, + json_reader_set_key, json_reader_set_string, + json_reader_set_number, json_reader_set_true, + json_reader_set_false, json_reader_set_null}; + +/* And finally, let's define our public API. */ +grpc_json *grpc_json_parse_string_with_len(char *input, size_t size) { + grpc_json_reader reader; + json_reader_userdata state; + grpc_json *json = NULL; + grpc_json_reader_status status; + + if (!input) return NULL; + + state.top = state.current_container = state.current_value = NULL; + state.string = state.key = NULL; + state.string_ptr = state.input = (uint8_t *)input; + state.remaining_input = size; + grpc_json_reader_init(&reader, &reader_vtable, &state); + + status = grpc_json_reader_run(&reader); + json = state.top; + + if ((status != GRPC_JSON_DONE) && json) { + grpc_json_destroy(json); + json = NULL; + } + + return json; +} + +#define UNBOUND_JSON_STRING_LENGTH 0x7fffffff + +grpc_json *grpc_json_parse_string(char *input) { + return grpc_json_parse_string_with_len(input, UNBOUND_JSON_STRING_LENGTH); +} + +static void json_dump_recursive(grpc_json_writer *writer, grpc_json *json, + int in_object) { + while (json) { + if (in_object) grpc_json_writer_object_key(writer, json->key); + + switch (json->type) { + case GRPC_JSON_OBJECT: + case GRPC_JSON_ARRAY: + grpc_json_writer_container_begins(writer, json->type); + if (json->child) + json_dump_recursive(writer, json->child, + json->type == GRPC_JSON_OBJECT); + grpc_json_writer_container_ends(writer, json->type); + break; + case GRPC_JSON_STRING: + grpc_json_writer_value_string(writer, json->value); + break; + case GRPC_JSON_NUMBER: + grpc_json_writer_value_raw(writer, json->value); + break; + case GRPC_JSON_TRUE: + grpc_json_writer_value_raw_with_len(writer, "true", 4); + break; + case GRPC_JSON_FALSE: + grpc_json_writer_value_raw_with_len(writer, "false", 5); + break; + case GRPC_JSON_NULL: + grpc_json_writer_value_raw_with_len(writer, "null", 4); + break; + default: + GPR_UNREACHABLE_CODE(abort()); + } + json = json->next; + } +} + +static grpc_json_writer_vtable writer_vtable = { + json_writer_output_char, json_writer_output_string, + json_writer_output_string_with_len}; + +char *grpc_json_dump_to_string(grpc_json *json, int indent) { + grpc_json_writer writer; + json_writer_userdata state; + + state.output = NULL; + state.free_space = state.string_len = state.allocated = 0; + grpc_json_writer_init(&writer, indent, &writer_vtable, &state); + + json_dump_recursive(&writer, json, 0); + + json_writer_output_char(&state, 0); + + return state.output; +} diff --git a/src/core/lib/json/json_writer.c b/src/core/lib/json/json_writer.c new file mode 100644 index 0000000000..326ec2d431 --- /dev/null +++ b/src/core/lib/json/json_writer.c @@ -0,0 +1,258 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +#include + +#include "src/core/json/json_writer.h" + +static void json_writer_output_char(grpc_json_writer *writer, char c) { + writer->vtable->output_char(writer->userdata, c); +} + +static void json_writer_output_string(grpc_json_writer *writer, + const char *str) { + writer->vtable->output_string(writer->userdata, str); +} + +static void json_writer_output_string_with_len(grpc_json_writer *writer, + const char *str, size_t len) { + writer->vtable->output_string_with_len(writer->userdata, str, len); +} + +void grpc_json_writer_init(grpc_json_writer *writer, int indent, + grpc_json_writer_vtable *vtable, void *userdata) { + memset(writer, 0, sizeof(*writer)); + writer->container_empty = 1; + writer->indent = indent; + writer->vtable = vtable; + writer->userdata = userdata; +} + +static void json_writer_output_indent(grpc_json_writer *writer) { + static const char spacesstr[] = + " " + " " + " " + " "; + + unsigned spaces = (unsigned)(writer->depth * writer->indent); + + if (writer->indent == 0) return; + + if (writer->got_key) { + json_writer_output_char(writer, ' '); + return; + } + + while (spaces >= (sizeof(spacesstr) - 1)) { + json_writer_output_string_with_len(writer, spacesstr, + sizeof(spacesstr) - 1); + spaces -= (unsigned)(sizeof(spacesstr) - 1); + } + + if (spaces == 0) return; + + json_writer_output_string_with_len( + writer, spacesstr + sizeof(spacesstr) - 1 - spaces, spaces); +} + +static void json_writer_value_end(grpc_json_writer *writer) { + if (writer->container_empty) { + writer->container_empty = 0; + if ((writer->indent == 0) || (writer->depth == 0)) return; + json_writer_output_char(writer, '\n'); + } else { + json_writer_output_char(writer, ','); + if (writer->indent == 0) return; + json_writer_output_char(writer, '\n'); + } +} + +static void json_writer_escape_utf16(grpc_json_writer *writer, uint16_t utf16) { + static const char hex[] = "0123456789abcdef"; + + json_writer_output_string_with_len(writer, "\\u", 2); + json_writer_output_char(writer, hex[(utf16 >> 12) & 0x0f]); + json_writer_output_char(writer, hex[(utf16 >> 8) & 0x0f]); + json_writer_output_char(writer, hex[(utf16 >> 4) & 0x0f]); + json_writer_output_char(writer, hex[(utf16)&0x0f]); +} + +static void json_writer_escape_string(grpc_json_writer *writer, + const char *string) { + json_writer_output_char(writer, '"'); + + for (;;) { + uint8_t c = (uint8_t)*string++; + if (c == 0) { + break; + } else if ((c >= 32) && (c <= 126)) { + if ((c == '\\') || (c == '"')) json_writer_output_char(writer, '\\'); + json_writer_output_char(writer, (char)c); + } else if ((c < 32) || (c == 127)) { + switch (c) { + case '\b': + json_writer_output_string_with_len(writer, "\\b", 2); + break; + case '\f': + json_writer_output_string_with_len(writer, "\\f", 2); + break; + case '\n': + json_writer_output_string_with_len(writer, "\\n", 2); + break; + case '\r': + json_writer_output_string_with_len(writer, "\\r", 2); + break; + case '\t': + json_writer_output_string_with_len(writer, "\\t", 2); + break; + default: + json_writer_escape_utf16(writer, c); + break; + } + } else { + uint32_t utf32 = 0; + int extra = 0; + int i; + int valid = 1; + if ((c & 0xe0) == 0xc0) { + utf32 = c & 0x1f; + extra = 1; + } else if ((c & 0xf0) == 0xe0) { + utf32 = c & 0x0f; + extra = 2; + } else if ((c & 0xf8) == 0xf0) { + utf32 = c & 0x07; + extra = 3; + } else { + break; + } + for (i = 0; i < extra; i++) { + utf32 <<= 6; + c = (uint8_t)(*string++); + /* Breaks out and bail on any invalid UTF-8 sequence, including \0. */ + if ((c & 0xc0) != 0x80) { + valid = 0; + break; + } + utf32 |= c & 0x3f; + } + if (!valid) break; + /* The range 0xd800 - 0xdfff is reserved by the surrogates ad vitam. + * Any other range is technically reserved for future usage, so if we + * don't want the software to break in the future, we have to allow + * anything else. The first non-unicode character is 0x110000. */ + if (((utf32 >= 0xd800) && (utf32 <= 0xdfff)) || (utf32 >= 0x110000)) + break; + if (utf32 >= 0x10000) { + /* If utf32 contains a character that is above 0xffff, it needs to be + * broken down into a utf-16 surrogate pair. A surrogate pair is first + * a high surrogate, followed by a low surrogate. Each surrogate holds + * 10 bits of usable data, thus allowing a total of 20 bits of data. + * The high surrogate marker is 0xd800, while the low surrogate marker + * is 0xdc00. The low 10 bits of each will be the usable data. + * + * After re-combining the 20 bits of data, one has to add 0x10000 to + * the resulting value, in order to obtain the original character. + * This is obviously because the range 0x0000 - 0xffff can be written + * without any special trick. + * + * Since 0x10ffff is the highest allowed character, we're working in + * the range 0x00000 - 0xfffff after we decrement it by 0x10000. + * That range is exactly 20 bits. + */ + utf32 -= 0x10000; + json_writer_escape_utf16(writer, (uint16_t)(0xd800 | (utf32 >> 10))); + json_writer_escape_utf16(writer, (uint16_t)(0xdc00 | (utf32 & 0x3ff))); + } else { + json_writer_escape_utf16(writer, (uint16_t)utf32); + } + } + } + + json_writer_output_char(writer, '"'); +} + +void grpc_json_writer_container_begins(grpc_json_writer *writer, + grpc_json_type type) { + if (!writer->got_key) json_writer_value_end(writer); + json_writer_output_indent(writer); + json_writer_output_char(writer, type == GRPC_JSON_OBJECT ? '{' : '['); + writer->container_empty = 1; + writer->got_key = 0; + writer->depth++; +} + +void grpc_json_writer_container_ends(grpc_json_writer *writer, + grpc_json_type type) { + if (writer->indent && !writer->container_empty) + json_writer_output_char(writer, '\n'); + writer->depth--; + if (!writer->container_empty) json_writer_output_indent(writer); + json_writer_output_char(writer, type == GRPC_JSON_OBJECT ? '}' : ']'); + writer->container_empty = 0; + writer->got_key = 0; +} + +void grpc_json_writer_object_key(grpc_json_writer *writer, const char *string) { + json_writer_value_end(writer); + json_writer_output_indent(writer); + json_writer_escape_string(writer, string); + json_writer_output_char(writer, ':'); + writer->got_key = 1; +} + +void grpc_json_writer_value_raw(grpc_json_writer *writer, const char *string) { + if (!writer->got_key) json_writer_value_end(writer); + json_writer_output_indent(writer); + json_writer_output_string(writer, string); + writer->got_key = 0; +} + +void grpc_json_writer_value_raw_with_len(grpc_json_writer *writer, + const char *string, size_t len) { + if (!writer->got_key) json_writer_value_end(writer); + json_writer_output_indent(writer); + json_writer_output_string_with_len(writer, string, len); + writer->got_key = 0; +} + +void grpc_json_writer_value_string(grpc_json_writer *writer, + const char *string) { + if (!writer->got_key) json_writer_value_end(writer); + json_writer_output_indent(writer); + json_writer_escape_string(writer, string); + writer->got_key = 0; +} diff --git a/src/core/lib/json/json_writer.h b/src/core/lib/json/json_writer.h new file mode 100644 index 0000000000..c392126950 --- /dev/null +++ b/src/core/lib/json/json_writer.h @@ -0,0 +1,97 @@ +/* + * + * Copyright 2015-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. + * + */ + +/* The idea of the writer is basically symmetrical of the reader. While the + * reader emits various calls to your code, the writer takes basically the + * same calls and emit json out of it. It doesn't try to make any check on + * the order of the calls you do on it. Meaning you can theorically force + * it to generate invalid json. + * + * Also, unlike the reader, the writer expects UTF-8 encoded input strings. + * These strings will be UTF-8 validated, and any invalid character will + * cut the conversion short, before any invalid UTF-8 sequence, thus forming + * a valid UTF-8 string overall. + */ + +#ifndef GRPC_CORE_JSON_JSON_WRITER_H +#define GRPC_CORE_JSON_JSON_WRITER_H + +#include + +#include "src/core/json/json_common.h" + +typedef struct grpc_json_writer_vtable { + /* Adds a character to the output stream. */ + void (*output_char)(void *userdata, char); + /* Adds a zero-terminated string to the output stream. */ + void (*output_string)(void *userdata, const char *str); + /* Adds a fixed-length string to the output stream. */ + void (*output_string_with_len)(void *userdata, const char *str, size_t len); + +} grpc_json_writer_vtable; + +typedef struct grpc_json_writer { + void *userdata; + grpc_json_writer_vtable *vtable; + int indent; + int depth; + int container_empty; + int got_key; +} grpc_json_writer; + +/* Call this to initialize your writer structure. The indent parameter is + * specifying the number of spaces to use for indenting the output. If you + * use indent=0, then the output will not have any newlines either, thus + * emitting a condensed json output. + */ +void grpc_json_writer_init(grpc_json_writer *writer, int indent, + grpc_json_writer_vtable *vtable, void *userdata); + +/* Signals the beginning of a container. */ +void grpc_json_writer_container_begins(grpc_json_writer *writer, + grpc_json_type type); +/* Signals the end of a container. */ +void grpc_json_writer_container_ends(grpc_json_writer *writer, + grpc_json_type type); +/* Writes down an object key for the next value. */ +void grpc_json_writer_object_key(grpc_json_writer *writer, const char *string); +/* Sets a raw value. Useful for numbers. */ +void grpc_json_writer_value_raw(grpc_json_writer *writer, const char *string); +/* Sets a raw value with its length. Useful for values like true or false. */ +void grpc_json_writer_value_raw_with_len(grpc_json_writer *writer, + const char *string, size_t len); +/* Sets a string value. It'll be escaped, and utf-8 validated. */ +void grpc_json_writer_value_string(grpc_json_writer *writer, + const char *string); + +#endif /* GRPC_CORE_JSON_JSON_WRITER_H */ diff --git a/src/core/lib/profiling/basic_timers.c b/src/core/lib/profiling/basic_timers.c new file mode 100644 index 0000000000..3067f52c21 --- /dev/null +++ b/src/core/lib/profiling/basic_timers.c @@ -0,0 +1,274 @@ +/* + * + * Copyright 2015-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 + +#ifdef GRPC_BASIC_PROFILER + +#include "src/core/profiling/timers.h" + +#include +#include +#include +#include +#include +#include + +typedef enum { BEGIN = '{', END = '}', MARK = '.' } marker_type; + +typedef struct gpr_timer_entry { + gpr_timespec tm; + const char *tagstr; + const char *file; + short line; + char type; + uint8_t important; + int thd; +} gpr_timer_entry; + +#define MAX_COUNT 1000000 + +typedef struct gpr_timer_log { + size_t num_entries; + struct gpr_timer_log *next; + struct gpr_timer_log *prev; + gpr_timer_entry log[MAX_COUNT]; +} gpr_timer_log; + +typedef struct gpr_timer_log_list { + gpr_timer_log *head; + /* valid iff head!=NULL */ + gpr_timer_log *tail; +} gpr_timer_log_list; + +static __thread gpr_timer_log *g_thread_log; +static gpr_once g_once_init = GPR_ONCE_INIT; +static FILE *output_file; +static const char *output_filename = "latency_trace.txt"; +static pthread_mutex_t g_mu; +static pthread_cond_t g_cv; +static gpr_timer_log_list g_in_progress_logs; +static gpr_timer_log_list g_done_logs; +static int g_shutdown; +static gpr_thd_id g_writing_thread; +static __thread int g_thread_id; +static int g_next_thread_id; + +static int timer_log_push_back(gpr_timer_log_list *list, gpr_timer_log *log) { + if (list->head == NULL) { + list->head = list->tail = log; + log->next = log->prev = NULL; + return 1; + } else { + log->prev = list->tail; + log->next = NULL; + list->tail->next = log; + list->tail = log; + return 0; + } +} + +static gpr_timer_log *timer_log_pop_front(gpr_timer_log_list *list) { + gpr_timer_log *out = list->head; + if (out != NULL) { + list->head = out->next; + if (list->head != NULL) { + list->head->prev = NULL; + } else { + list->tail = NULL; + } + } + return out; +} + +static void timer_log_remove(gpr_timer_log_list *list, gpr_timer_log *log) { + if (log->prev == NULL) { + list->head = log->next; + if (list->head != NULL) { + list->head->prev = NULL; + } + } else { + log->prev->next = log->next; + } + if (log->next == NULL) { + list->tail = log->prev; + if (list->tail != NULL) { + list->tail->next = NULL; + } + } else { + log->next->prev = log->prev; + } +} + +static void write_log(gpr_timer_log *log) { + size_t i; + if (output_file == NULL) { + output_file = fopen(output_filename, "w"); + } + for (i = 0; i < log->num_entries; i++) { + gpr_timer_entry *entry = &(log->log[i]); + if (gpr_time_cmp(entry->tm, gpr_time_0(entry->tm.clock_type)) < 0) { + entry->tm = gpr_time_0(entry->tm.clock_type); + } + fprintf(output_file, + "{\"t\": %lld.%09d, \"thd\": \"%d\", \"type\": \"%c\", \"tag\": " + "\"%s\", \"file\": \"%s\", \"line\": %d, \"imp\": %d}\n", + (long long)entry->tm.tv_sec, (int)entry->tm.tv_nsec, entry->thd, + entry->type, entry->tagstr, entry->file, entry->line, + entry->important); + } +} + +static void writing_thread(void *unused) { + gpr_timer_log *log; + pthread_mutex_lock(&g_mu); + for (;;) { + while ((log = timer_log_pop_front(&g_done_logs)) == NULL && !g_shutdown) { + pthread_cond_wait(&g_cv, &g_mu); + } + if (log != NULL) { + pthread_mutex_unlock(&g_mu); + write_log(log); + free(log); + pthread_mutex_lock(&g_mu); + } + if (g_shutdown) { + pthread_mutex_unlock(&g_mu); + return; + } + } +} + +static void flush_logs(gpr_timer_log_list *list) { + gpr_timer_log *log; + while ((log = timer_log_pop_front(list)) != NULL) { + write_log(log); + free(log); + } +} + +static void finish_writing() { + pthread_mutex_lock(&g_mu); + g_shutdown = 1; + pthread_cond_signal(&g_cv); + pthread_mutex_unlock(&g_mu); + gpr_thd_join(g_writing_thread); + + gpr_log(GPR_INFO, "flushing logs"); + + pthread_mutex_lock(&g_mu); + flush_logs(&g_done_logs); + flush_logs(&g_in_progress_logs); + pthread_mutex_unlock(&g_mu); + + if (output_file) { + fclose(output_file); + } +} + +void gpr_timers_set_log_filename(const char *filename) { + output_filename = filename; +} + +static void init_output() { + gpr_thd_options options = gpr_thd_options_default(); + gpr_thd_options_set_joinable(&options); + gpr_thd_new(&g_writing_thread, writing_thread, NULL, &options); + atexit(finish_writing); +} + +static void rotate_log() { + gpr_timer_log *new = malloc(sizeof(*new)); + gpr_once_init(&g_once_init, init_output); + new->num_entries = 0; + pthread_mutex_lock(&g_mu); + if (g_thread_log != NULL) { + timer_log_remove(&g_in_progress_logs, g_thread_log); + if (timer_log_push_back(&g_done_logs, g_thread_log)) { + pthread_cond_signal(&g_cv); + } + } else { + g_thread_id = g_next_thread_id++; + } + timer_log_push_back(&g_in_progress_logs, new); + pthread_mutex_unlock(&g_mu); + g_thread_log = new; +} + +static void gpr_timers_log_add(const char *tagstr, marker_type type, + int important, const char *file, int line) { + gpr_timer_entry *entry; + + if (g_thread_log == NULL || g_thread_log->num_entries == MAX_COUNT) { + rotate_log(); + } + + entry = &g_thread_log->log[g_thread_log->num_entries++]; + + entry->tm = gpr_now(GPR_CLOCK_PRECISE); + entry->tagstr = tagstr; + entry->type = type; + entry->file = file; + entry->line = (short)line; + entry->important = important != 0; + entry->thd = g_thread_id; +} + +/* Latency profiler API implementation. */ +void gpr_timer_add_mark(const char *tagstr, int important, const char *file, + int line) { + gpr_timers_log_add(tagstr, MARK, important, file, line); +} + +void gpr_timer_begin(const char *tagstr, int important, const char *file, + int line) { + gpr_timers_log_add(tagstr, BEGIN, important, file, line); +} + +void gpr_timer_end(const char *tagstr, int important, const char *file, + int line) { + gpr_timers_log_add(tagstr, END, important, file, line); +} + +/* Basic profiler specific API functions. */ +void gpr_timers_global_init(void) {} + +void gpr_timers_global_destroy(void) {} + +#else /* !GRPC_BASIC_PROFILER */ +void gpr_timers_global_init(void) {} + +void gpr_timers_global_destroy(void) {} + +void gpr_timers_set_log_filename(const char *filename) {} +#endif /* GRPC_BASIC_PROFILER */ diff --git a/src/core/lib/profiling/stap_probes.d b/src/core/lib/profiling/stap_probes.d new file mode 100644 index 0000000000..153de91752 --- /dev/null +++ b/src/core/lib/profiling/stap_probes.d @@ -0,0 +1,7 @@ +provider _stap { + probe add_mark(int tag); + probe add_important_mark(int tag); + probe timing_ns_begin(int tag); + probe timing_ns_end(int tag); +}; + diff --git a/src/core/lib/profiling/stap_timers.c b/src/core/lib/profiling/stap_timers.c new file mode 100644 index 0000000000..efcd1af4a1 --- /dev/null +++ b/src/core/lib/profiling/stap_timers.c @@ -0,0 +1,65 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +#ifdef GRPC_STAP_PROFILER + +#include "src/core/profiling/timers.h" + +#include +/* Generated from src/core/profiling/stap_probes.d */ +#include "src/core/profiling/stap_probes.h" + +/* Latency profiler API implementation. */ +void gpr_timer_add_mark(int tag, const char *tagstr, void *id, const char *file, + int line) { + _STAP_ADD_MARK(tag); +} + +void gpr_timer_add_important_mark(int tag, const char *tagstr, void *id, + const char *file, int line) { + _STAP_ADD_IMPORTANT_MARK(tag); +} + +void gpr_timer_begin(int tag, const char *tagstr, void *id, const char *file, + int line) { + _STAP_TIMING_NS_BEGIN(tag); +} + +void gpr_timer_end(int tag, const char *tagstr, void *id, const char *file, + int line) { + _STAP_TIMING_NS_END(tag); +} + +#endif /* GRPC_STAP_PROFILER */ diff --git a/src/core/lib/profiling/timers.h b/src/core/lib/profiling/timers.h new file mode 100644 index 0000000000..6a188dc566 --- /dev/null +++ b/src/core/lib/profiling/timers.h @@ -0,0 +1,119 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef GRPC_CORE_PROFILING_TIMERS_H +#define GRPC_CORE_PROFILING_TIMERS_H + +#ifdef __cplusplus +extern "C" { +#endif + +void gpr_timers_global_init(void); +void gpr_timers_global_destroy(void); + +void gpr_timer_add_mark(const char *tagstr, int important, const char *file, + int line); +void gpr_timer_begin(const char *tagstr, int important, const char *file, + int line); +void gpr_timer_end(const char *tagstr, int important, const char *file, + int line); + +void gpr_timers_set_log_filename(const char *filename); + +#if !(defined(GRPC_STAP_PROFILER) + defined(GRPC_BASIC_PROFILER)) +/* No profiling. No-op all the things. */ +#define GPR_TIMER_MARK(tag, important) \ + do { \ + } while (0) + +#define GPR_TIMER_BEGIN(tag, important) \ + do { \ + } while (0) + +#define GPR_TIMER_END(tag, important) \ + do { \ + } while (0) + +#else /* at least one profiler requested... */ +/* ... hopefully only one. */ +#if defined(GRPC_STAP_PROFILER) && defined(GRPC_BASIC_PROFILER) +#error "GRPC_STAP_PROFILER and GRPC_BASIC_PROFILER are mutually exclusive." +#endif + +/* Generic profiling interface. */ +#define GPR_TIMER_MARK(tag, important) \ + gpr_timer_add_mark(tag, important, __FILE__, __LINE__); + +#define GPR_TIMER_BEGIN(tag, important) \ + gpr_timer_begin(tag, important, __FILE__, __LINE__); + +#define GPR_TIMER_END(tag, important) \ + gpr_timer_end(tag, important, __FILE__, __LINE__); + +#ifdef GRPC_STAP_PROFILER +/* Empty placeholder for now. */ +#endif /* GRPC_STAP_PROFILER */ + +#ifdef GRPC_BASIC_PROFILER +/* Empty placeholder for now. */ +#endif /* GRPC_BASIC_PROFILER */ + +#endif /* at least one profiler requested. */ + +#ifdef __cplusplus +} + +#if (defined(GRPC_STAP_PROFILER) + defined(GRPC_BASIC_PROFILER)) +namespace grpc { +class ProfileScope { + public: + ProfileScope(const char *desc, bool important) : desc_(desc) { + GPR_TIMER_BEGIN(desc_, important ? 1 : 0); + } + ~ProfileScope() { GPR_TIMER_END(desc_, 0); } + + private: + const char *const desc_; +}; +} + +#define GPR_TIMER_SCOPE(tag, important) \ + ::grpc::ProfileScope _profile_scope_##__LINE__((tag), (important)) +#else +#define GPR_TIMER_SCOPE(tag, important) \ + do { \ + } while (false) +#endif +#endif + +#endif /* GRPC_CORE_PROFILING_TIMERS_H */ diff --git a/src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c b/src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c new file mode 100644 index 0000000000..59aae30cff --- /dev/null +++ b/src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c @@ -0,0 +1,119 @@ +/* + * + * 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. + * + */ +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.3.5-dev */ + +#include "src/core/proto/grpc/lb/v0/load_balancer.pb.h" + +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + + + +const pb_field_t grpc_lb_v0_Duration_fields[3] = { + PB_FIELD( 1, INT64 , OPTIONAL, STATIC , FIRST, grpc_lb_v0_Duration, seconds, seconds, 0), + PB_FIELD( 2, INT32 , OPTIONAL, STATIC , OTHER, grpc_lb_v0_Duration, nanos, seconds, 0), + PB_LAST_FIELD +}; + +const pb_field_t grpc_lb_v0_LoadBalanceRequest_fields[3] = { + PB_FIELD( 1, MESSAGE , OPTIONAL, STATIC , FIRST, grpc_lb_v0_LoadBalanceRequest, initial_request, initial_request, &grpc_lb_v0_InitialLoadBalanceRequest_fields), + PB_FIELD( 2, MESSAGE , OPTIONAL, STATIC , OTHER, grpc_lb_v0_LoadBalanceRequest, client_stats, initial_request, &grpc_lb_v0_ClientStats_fields), + PB_LAST_FIELD +}; + +const pb_field_t grpc_lb_v0_InitialLoadBalanceRequest_fields[2] = { + PB_FIELD( 1, STRING , OPTIONAL, STATIC , FIRST, grpc_lb_v0_InitialLoadBalanceRequest, name, name, 0), + PB_LAST_FIELD +}; + +const pb_field_t grpc_lb_v0_ClientStats_fields[4] = { + PB_FIELD( 1, INT64 , OPTIONAL, STATIC , FIRST, grpc_lb_v0_ClientStats, total_requests, total_requests, 0), + PB_FIELD( 2, INT64 , OPTIONAL, STATIC , OTHER, grpc_lb_v0_ClientStats, client_rpc_errors, total_requests, 0), + PB_FIELD( 3, INT64 , OPTIONAL, STATIC , OTHER, grpc_lb_v0_ClientStats, dropped_requests, client_rpc_errors, 0), + PB_LAST_FIELD +}; + +const pb_field_t grpc_lb_v0_LoadBalanceResponse_fields[3] = { + PB_FIELD( 1, MESSAGE , OPTIONAL, STATIC , FIRST, grpc_lb_v0_LoadBalanceResponse, initial_response, initial_response, &grpc_lb_v0_InitialLoadBalanceResponse_fields), + PB_FIELD( 2, MESSAGE , OPTIONAL, STATIC , OTHER, grpc_lb_v0_LoadBalanceResponse, server_list, initial_response, &grpc_lb_v0_ServerList_fields), + PB_LAST_FIELD +}; + +const pb_field_t grpc_lb_v0_InitialLoadBalanceResponse_fields[4] = { + PB_FIELD( 1, STRING , OPTIONAL, STATIC , FIRST, grpc_lb_v0_InitialLoadBalanceResponse, client_config, client_config, 0), + PB_FIELD( 2, STRING , OPTIONAL, STATIC , OTHER, grpc_lb_v0_InitialLoadBalanceResponse, load_balancer_delegate, client_config, 0), + PB_FIELD( 3, MESSAGE , OPTIONAL, STATIC , OTHER, grpc_lb_v0_InitialLoadBalanceResponse, client_stats_report_interval, load_balancer_delegate, &grpc_lb_v0_Duration_fields), + PB_LAST_FIELD +}; + +const pb_field_t grpc_lb_v0_ServerList_fields[3] = { + PB_FIELD( 1, MESSAGE , REPEATED, CALLBACK, FIRST, grpc_lb_v0_ServerList, servers, servers, &grpc_lb_v0_Server_fields), + PB_FIELD( 3, MESSAGE , OPTIONAL, STATIC , OTHER, grpc_lb_v0_ServerList, expiration_interval, servers, &grpc_lb_v0_Duration_fields), + PB_LAST_FIELD +}; + +const pb_field_t grpc_lb_v0_Server_fields[5] = { + PB_FIELD( 1, STRING , OPTIONAL, STATIC , FIRST, grpc_lb_v0_Server, ip_address, ip_address, 0), + PB_FIELD( 2, INT32 , OPTIONAL, STATIC , OTHER, grpc_lb_v0_Server, port, ip_address, 0), + PB_FIELD( 3, BYTES , OPTIONAL, STATIC , OTHER, grpc_lb_v0_Server, load_balance_token, port, 0), + PB_FIELD( 4, BOOL , OPTIONAL, STATIC , OTHER, grpc_lb_v0_Server, drop_request, load_balance_token, 0), + PB_LAST_FIELD +}; + + +/* Check that field information fits in pb_field_t */ +#if !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_32BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in 8 or 16 bit + * field descriptors. + */ +PB_STATIC_ASSERT((pb_membersize(grpc_lb_v0_LoadBalanceRequest, initial_request) < 65536 && pb_membersize(grpc_lb_v0_LoadBalanceRequest, client_stats) < 65536 && pb_membersize(grpc_lb_v0_LoadBalanceResponse, initial_response) < 65536 && pb_membersize(grpc_lb_v0_LoadBalanceResponse, server_list) < 65536 && pb_membersize(grpc_lb_v0_InitialLoadBalanceResponse, client_stats_report_interval) < 65536 && pb_membersize(grpc_lb_v0_ServerList, servers) < 65536 && pb_membersize(grpc_lb_v0_ServerList, expiration_interval) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_grpc_lb_v0_Duration_grpc_lb_v0_LoadBalanceRequest_grpc_lb_v0_InitialLoadBalanceRequest_grpc_lb_v0_ClientStats_grpc_lb_v0_LoadBalanceResponse_grpc_lb_v0_InitialLoadBalanceResponse_grpc_lb_v0_ServerList_grpc_lb_v0_Server) +#endif + +#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_16BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in the default + * 8 bit descriptors. + */ +PB_STATIC_ASSERT((pb_membersize(grpc_lb_v0_LoadBalanceRequest, initial_request) < 256 && pb_membersize(grpc_lb_v0_LoadBalanceRequest, client_stats) < 256 && pb_membersize(grpc_lb_v0_LoadBalanceResponse, initial_response) < 256 && pb_membersize(grpc_lb_v0_LoadBalanceResponse, server_list) < 256 && pb_membersize(grpc_lb_v0_InitialLoadBalanceResponse, client_stats_report_interval) < 256 && pb_membersize(grpc_lb_v0_ServerList, servers) < 256 && pb_membersize(grpc_lb_v0_ServerList, expiration_interval) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_grpc_lb_v0_Duration_grpc_lb_v0_LoadBalanceRequest_grpc_lb_v0_InitialLoadBalanceRequest_grpc_lb_v0_ClientStats_grpc_lb_v0_LoadBalanceResponse_grpc_lb_v0_InitialLoadBalanceResponse_grpc_lb_v0_ServerList_grpc_lb_v0_Server) +#endif + + diff --git a/src/core/lib/proto/grpc/lb/v0/load_balancer.pb.h b/src/core/lib/proto/grpc/lb/v0/load_balancer.pb.h new file mode 100644 index 0000000000..3599f881bb --- /dev/null +++ b/src/core/lib/proto/grpc/lb/v0/load_balancer.pb.h @@ -0,0 +1,182 @@ +/* + * + * 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. + * + */ +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.3.5-dev */ + +#ifndef PB_LOAD_BALANCER_PB_H_INCLUDED +#define PB_LOAD_BALANCER_PB_H_INCLUDED +#include "third_party/nanopb/pb.h" +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Struct definitions */ +typedef struct _grpc_lb_v0_ClientStats { + bool has_total_requests; + int64_t total_requests; + bool has_client_rpc_errors; + int64_t client_rpc_errors; + bool has_dropped_requests; + int64_t dropped_requests; +} grpc_lb_v0_ClientStats; + +typedef struct _grpc_lb_v0_Duration { + bool has_seconds; + int64_t seconds; + bool has_nanos; + int32_t nanos; +} grpc_lb_v0_Duration; + +typedef struct _grpc_lb_v0_InitialLoadBalanceRequest { + bool has_name; + char name[128]; +} grpc_lb_v0_InitialLoadBalanceRequest; + +typedef PB_BYTES_ARRAY_T(64) grpc_lb_v0_Server_load_balance_token_t; +typedef struct _grpc_lb_v0_Server { + bool has_ip_address; + char ip_address[46]; + bool has_port; + int32_t port; + bool has_load_balance_token; + grpc_lb_v0_Server_load_balance_token_t load_balance_token; + bool has_drop_request; + bool drop_request; +} grpc_lb_v0_Server; + +typedef struct _grpc_lb_v0_InitialLoadBalanceResponse { + bool has_client_config; + char client_config[64]; + bool has_load_balancer_delegate; + char load_balancer_delegate[64]; + bool has_client_stats_report_interval; + grpc_lb_v0_Duration client_stats_report_interval; +} grpc_lb_v0_InitialLoadBalanceResponse; + +typedef struct _grpc_lb_v0_LoadBalanceRequest { + bool has_initial_request; + grpc_lb_v0_InitialLoadBalanceRequest initial_request; + bool has_client_stats; + grpc_lb_v0_ClientStats client_stats; +} grpc_lb_v0_LoadBalanceRequest; + +typedef struct _grpc_lb_v0_ServerList { + pb_callback_t servers; + bool has_expiration_interval; + grpc_lb_v0_Duration expiration_interval; +} grpc_lb_v0_ServerList; + +typedef struct _grpc_lb_v0_LoadBalanceResponse { + bool has_initial_response; + grpc_lb_v0_InitialLoadBalanceResponse initial_response; + bool has_server_list; + grpc_lb_v0_ServerList server_list; +} grpc_lb_v0_LoadBalanceResponse; + +/* Default values for struct fields */ + +/* Initializer values for message structs */ +#define grpc_lb_v0_Duration_init_default {false, 0, false, 0} +#define grpc_lb_v0_LoadBalanceRequest_init_default {false, grpc_lb_v0_InitialLoadBalanceRequest_init_default, false, grpc_lb_v0_ClientStats_init_default} +#define grpc_lb_v0_InitialLoadBalanceRequest_init_default {false, ""} +#define grpc_lb_v0_ClientStats_init_default {false, 0, false, 0, false, 0} +#define grpc_lb_v0_LoadBalanceResponse_init_default {false, grpc_lb_v0_InitialLoadBalanceResponse_init_default, false, grpc_lb_v0_ServerList_init_default} +#define grpc_lb_v0_InitialLoadBalanceResponse_init_default {false, "", false, "", false, grpc_lb_v0_Duration_init_default} +#define grpc_lb_v0_ServerList_init_default {{{NULL}, NULL}, false, grpc_lb_v0_Duration_init_default} +#define grpc_lb_v0_Server_init_default {false, "", false, 0, false, {0, {0}}, false, 0} +#define grpc_lb_v0_Duration_init_zero {false, 0, false, 0} +#define grpc_lb_v0_LoadBalanceRequest_init_zero {false, grpc_lb_v0_InitialLoadBalanceRequest_init_zero, false, grpc_lb_v0_ClientStats_init_zero} +#define grpc_lb_v0_InitialLoadBalanceRequest_init_zero {false, ""} +#define grpc_lb_v0_ClientStats_init_zero {false, 0, false, 0, false, 0} +#define grpc_lb_v0_LoadBalanceResponse_init_zero {false, grpc_lb_v0_InitialLoadBalanceResponse_init_zero, false, grpc_lb_v0_ServerList_init_zero} +#define grpc_lb_v0_InitialLoadBalanceResponse_init_zero {false, "", false, "", false, grpc_lb_v0_Duration_init_zero} +#define grpc_lb_v0_ServerList_init_zero {{{NULL}, NULL}, false, grpc_lb_v0_Duration_init_zero} +#define grpc_lb_v0_Server_init_zero {false, "", false, 0, false, {0, {0}}, false, 0} + +/* Field tags (for use in manual encoding/decoding) */ +#define grpc_lb_v0_ClientStats_total_requests_tag 1 +#define grpc_lb_v0_ClientStats_client_rpc_errors_tag 2 +#define grpc_lb_v0_ClientStats_dropped_requests_tag 3 +#define grpc_lb_v0_Duration_seconds_tag 1 +#define grpc_lb_v0_Duration_nanos_tag 2 +#define grpc_lb_v0_InitialLoadBalanceRequest_name_tag 1 +#define grpc_lb_v0_Server_ip_address_tag 1 +#define grpc_lb_v0_Server_port_tag 2 +#define grpc_lb_v0_Server_load_balance_token_tag 3 +#define grpc_lb_v0_Server_drop_request_tag 4 +#define grpc_lb_v0_InitialLoadBalanceResponse_client_config_tag 1 +#define grpc_lb_v0_InitialLoadBalanceResponse_load_balancer_delegate_tag 2 +#define grpc_lb_v0_InitialLoadBalanceResponse_client_stats_report_interval_tag 3 +#define grpc_lb_v0_LoadBalanceRequest_initial_request_tag 1 +#define grpc_lb_v0_LoadBalanceRequest_client_stats_tag 2 +#define grpc_lb_v0_ServerList_servers_tag 1 +#define grpc_lb_v0_ServerList_expiration_interval_tag 3 +#define grpc_lb_v0_LoadBalanceResponse_initial_response_tag 1 +#define grpc_lb_v0_LoadBalanceResponse_server_list_tag 2 + +/* Struct field encoding specification for nanopb */ +extern const pb_field_t grpc_lb_v0_Duration_fields[3]; +extern const pb_field_t grpc_lb_v0_LoadBalanceRequest_fields[3]; +extern const pb_field_t grpc_lb_v0_InitialLoadBalanceRequest_fields[2]; +extern const pb_field_t grpc_lb_v0_ClientStats_fields[4]; +extern const pb_field_t grpc_lb_v0_LoadBalanceResponse_fields[3]; +extern const pb_field_t grpc_lb_v0_InitialLoadBalanceResponse_fields[4]; +extern const pb_field_t grpc_lb_v0_ServerList_fields[3]; +extern const pb_field_t grpc_lb_v0_Server_fields[5]; + +/* Maximum encoded size of messages (where known) */ +#define grpc_lb_v0_Duration_size 22 +#define grpc_lb_v0_LoadBalanceRequest_size 169 +#define grpc_lb_v0_InitialLoadBalanceRequest_size 131 +#define grpc_lb_v0_ClientStats_size 33 +#define grpc_lb_v0_LoadBalanceResponse_size (165 + grpc_lb_v0_ServerList_size) +#define grpc_lb_v0_InitialLoadBalanceResponse_size 156 +#define grpc_lb_v0_Server_size 127 + +/* Message IDs (where set with "msgid" option) */ +#ifdef PB_MSGID + +#define LOAD_BALANCER_MESSAGES \ + + +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/src/core/lib/security/auth_filters.h b/src/core/lib/security/auth_filters.h new file mode 100644 index 0000000000..1154a1d914 --- /dev/null +++ b/src/core/lib/security/auth_filters.h @@ -0,0 +1,42 @@ +/* + * + * Copyright 2015-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_SECURITY_AUTH_FILTERS_H +#define GRPC_CORE_SECURITY_AUTH_FILTERS_H + +#include "src/core/channel/channel_stack.h" + +extern const grpc_channel_filter grpc_client_auth_filter; +extern const grpc_channel_filter grpc_server_auth_filter; + +#endif /* GRPC_CORE_SECURITY_AUTH_FILTERS_H */ diff --git a/src/core/lib/security/b64.c b/src/core/lib/security/b64.c new file mode 100644 index 0000000000..c40b528e2f --- /dev/null +++ b/src/core/lib/security/b64.c @@ -0,0 +1,233 @@ +/* + * + * Copyright 2015-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/security/b64.h" + +#include +#include + +#include +#include +#include + +/* --- Constants. --- */ + +static const int8_t base64_bytes[] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 0x3E, -1, -1, -1, 0x3F, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, -1, -1, + -1, 0x7F, -1, -1, -1, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, + 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, -1, -1, -1, -1, -1, + -1, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, + 0x31, 0x32, 0x33, -1, -1, -1, -1, -1}; + +static const char base64_url_unsafe_chars[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char base64_url_safe_chars[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; + +#define GRPC_BASE64_PAD_CHAR '=' +#define GRPC_BASE64_PAD_BYTE 0x7F +#define GRPC_BASE64_MULTILINE_LINE_LEN 76 +#define GRPC_BASE64_MULTILINE_NUM_BLOCKS (GRPC_BASE64_MULTILINE_LINE_LEN / 4) + +/* --- base64 functions. --- */ + +char *grpc_base64_encode(const void *vdata, size_t data_size, int url_safe, + int multiline) { + const unsigned char *data = vdata; + const char *base64_chars = + url_safe ? base64_url_safe_chars : base64_url_unsafe_chars; + size_t result_projected_size = + 4 * ((data_size + 3) / 3) + + 2 * (multiline ? (data_size / (3 * GRPC_BASE64_MULTILINE_NUM_BLOCKS)) + : 0) + + 1; + char *result = gpr_malloc(result_projected_size); + char *current = result; + size_t num_blocks = 0; + size_t i = 0; + + /* Encode each block. */ + while (data_size >= 3) { + *current++ = base64_chars[(data[i] >> 2) & 0x3F]; + *current++ = + base64_chars[((data[i] & 0x03) << 4) | ((data[i + 1] >> 4) & 0x0F)]; + *current++ = + base64_chars[((data[i + 1] & 0x0F) << 2) | ((data[i + 2] >> 6) & 0x03)]; + *current++ = base64_chars[data[i + 2] & 0x3F]; + + data_size -= 3; + i += 3; + if (multiline && (++num_blocks == GRPC_BASE64_MULTILINE_NUM_BLOCKS)) { + *current++ = '\r'; + *current++ = '\n'; + num_blocks = 0; + } + } + + /* Take care of the tail. */ + if (data_size == 2) { + *current++ = base64_chars[(data[i] >> 2) & 0x3F]; + *current++ = + base64_chars[((data[i] & 0x03) << 4) | ((data[i + 1] >> 4) & 0x0F)]; + *current++ = base64_chars[(data[i + 1] & 0x0F) << 2]; + *current++ = GRPC_BASE64_PAD_CHAR; + } else if (data_size == 1) { + *current++ = base64_chars[(data[i] >> 2) & 0x3F]; + *current++ = base64_chars[(data[i] & 0x03) << 4]; + *current++ = GRPC_BASE64_PAD_CHAR; + *current++ = GRPC_BASE64_PAD_CHAR; + } + + GPR_ASSERT(current >= result); + GPR_ASSERT((uintptr_t)(current - result) < result_projected_size); + result[current - result] = '\0'; + return result; +} + +gpr_slice grpc_base64_decode(const char *b64, int url_safe) { + return grpc_base64_decode_with_len(b64, strlen(b64), url_safe); +} + +static void decode_one_char(const unsigned char *codes, unsigned char *result, + size_t *result_offset) { + uint32_t packed = ((uint32_t)codes[0] << 2) | ((uint32_t)codes[1] >> 4); + result[(*result_offset)++] = (unsigned char)packed; +} + +static void decode_two_chars(const unsigned char *codes, unsigned char *result, + size_t *result_offset) { + uint32_t packed = ((uint32_t)codes[0] << 10) | ((uint32_t)codes[1] << 4) | + ((uint32_t)codes[2] >> 2); + result[(*result_offset)++] = (unsigned char)(packed >> 8); + result[(*result_offset)++] = (unsigned char)(packed); +} + +static int decode_group(const unsigned char *codes, size_t num_codes, + unsigned char *result, size_t *result_offset) { + GPR_ASSERT(num_codes <= 4); + + /* Short end groups that may not have padding. */ + if (num_codes == 1) { + gpr_log(GPR_ERROR, "Invalid group. Must be at least 2 bytes."); + return 0; + } + if (num_codes == 2) { + decode_one_char(codes, result, result_offset); + return 1; + } + if (num_codes == 3) { + decode_two_chars(codes, result, result_offset); + return 1; + } + + /* Regular 4 byte groups with padding or not. */ + GPR_ASSERT(num_codes == 4); + if (codes[0] == GRPC_BASE64_PAD_BYTE || codes[1] == GRPC_BASE64_PAD_BYTE) { + gpr_log(GPR_ERROR, "Invalid padding detected."); + return 0; + } + if (codes[2] == GRPC_BASE64_PAD_BYTE) { + if (codes[3] == GRPC_BASE64_PAD_BYTE) { + decode_one_char(codes, result, result_offset); + } else { + gpr_log(GPR_ERROR, "Invalid padding detected."); + return 0; + } + } else if (codes[3] == GRPC_BASE64_PAD_BYTE) { + decode_two_chars(codes, result, result_offset); + } else { + /* No padding. */ + uint32_t packed = ((uint32_t)codes[0] << 18) | ((uint32_t)codes[1] << 12) | + ((uint32_t)codes[2] << 6) | codes[3]; + result[(*result_offset)++] = (unsigned char)(packed >> 16); + result[(*result_offset)++] = (unsigned char)(packed >> 8); + result[(*result_offset)++] = (unsigned char)(packed); + } + return 1; +} + +gpr_slice grpc_base64_decode_with_len(const char *b64, size_t b64_len, + int url_safe) { + gpr_slice result = gpr_slice_malloc(b64_len); + unsigned char *current = GPR_SLICE_START_PTR(result); + size_t result_size = 0; + unsigned char codes[4]; + size_t num_codes = 0; + + while (b64_len--) { + unsigned char c = (unsigned char)(*b64++); + signed char code; + if (c >= GPR_ARRAY_SIZE(base64_bytes)) continue; + if (url_safe) { + if (c == '+' || c == '/') { + gpr_log(GPR_ERROR, "Invalid character for url safe base64 %c", c); + goto fail; + } + if (c == '-') { + c = '+'; + } else if (c == '_') { + c = '/'; + } + } + code = base64_bytes[c]; + if (code == -1) { + if (c != '\r' && c != '\n') { + gpr_log(GPR_ERROR, "Invalid character %c", c); + goto fail; + } + } else { + codes[num_codes++] = (unsigned char)code; + if (num_codes == 4) { + if (!decode_group(codes, num_codes, current, &result_size)) goto fail; + num_codes = 0; + } + } + } + + if (num_codes != 0 && + !decode_group(codes, num_codes, current, &result_size)) { + goto fail; + } + GPR_SLICE_SET_LENGTH(result, result_size); + return result; + +fail: + gpr_slice_unref(result); + return gpr_empty_slice(); +} diff --git a/src/core/lib/security/b64.h b/src/core/lib/security/b64.h new file mode 100644 index 0000000000..d18f69563d --- /dev/null +++ b/src/core/lib/security/b64.h @@ -0,0 +1,52 @@ +/* + * + * Copyright 2015-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_SECURITY_B64_H +#define GRPC_CORE_SECURITY_B64_H + +#include + +/* Encodes data using base64. It is the caller's responsability to free + the returned char * using gpr_free. Returns NULL on NULL input. */ +char *grpc_base64_encode(const void *data, size_t data_size, int url_safe, + int multiline); + +/* Decodes data according to the base64 specification. Returns an empty + slice in case of failure. */ +gpr_slice grpc_base64_decode(const char *b64, int url_safe); + +/* Same as above except that the length is provided by the caller. */ +gpr_slice grpc_base64_decode_with_len(const char *b64, size_t b64_len, + int url_safe); + +#endif /* GRPC_CORE_SECURITY_B64_H */ diff --git a/src/core/lib/security/client_auth_filter.c b/src/core/lib/security/client_auth_filter.c new file mode 100644 index 0000000000..e2c23ef98d --- /dev/null +++ b/src/core/lib/security/client_auth_filter.c @@ -0,0 +1,336 @@ +/* + * + * Copyright 2015-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/security/auth_filters.h" + +#include + +#include +#include +#include + +#include "src/core/channel/channel_stack.h" +#include "src/core/security/credentials.h" +#include "src/core/security/security_connector.h" +#include "src/core/security/security_context.h" +#include "src/core/support/string.h" +#include "src/core/surface/call.h" +#include "src/core/transport/static_metadata.h" + +#define MAX_CREDENTIALS_METADATA_COUNT 4 + +/* We can have a per-call credentials. */ +typedef struct { + grpc_call_credentials *creds; + grpc_mdstr *host; + grpc_mdstr *method; + /* pollset bound to this call; if we need to make external + network requests, they should be done under this pollset + so that work can progress when this call wants work to + progress */ + grpc_pollset *pollset; + grpc_transport_stream_op op; + uint8_t security_context_set; + grpc_linked_mdelem md_links[MAX_CREDENTIALS_METADATA_COUNT]; + grpc_auth_metadata_context auth_md_context; +} call_data; + +/* We can have a per-channel credentials. */ +typedef struct { + grpc_channel_security_connector *security_connector; + grpc_auth_context *auth_context; +} channel_data; + +static void reset_auth_metadata_context( + grpc_auth_metadata_context *auth_md_context) { + if (auth_md_context->service_url != NULL) { + gpr_free((char *)auth_md_context->service_url); + auth_md_context->service_url = NULL; + } + if (auth_md_context->method_name != NULL) { + gpr_free((char *)auth_md_context->method_name); + auth_md_context->method_name = NULL; + } + GRPC_AUTH_CONTEXT_UNREF( + (grpc_auth_context *)auth_md_context->channel_auth_context, + "grpc_auth_metadata_context"); + auth_md_context->channel_auth_context = NULL; +} + +static void bubble_up_error(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + grpc_status_code status, const char *error_msg) { + call_data *calld = elem->call_data; + gpr_log(GPR_ERROR, "Client side authentication failure: %s", error_msg); + grpc_transport_stream_op_add_cancellation(&calld->op, status); + grpc_call_next_op(exec_ctx, elem, &calld->op); +} + +static void on_credentials_metadata(grpc_exec_ctx *exec_ctx, void *user_data, + grpc_credentials_md *md_elems, + size_t num_md, + grpc_credentials_status status) { + grpc_call_element *elem = (grpc_call_element *)user_data; + call_data *calld = elem->call_data; + grpc_transport_stream_op *op = &calld->op; + grpc_metadata_batch *mdb; + size_t i; + reset_auth_metadata_context(&calld->auth_md_context); + if (status != GRPC_CREDENTIALS_OK) { + bubble_up_error(exec_ctx, elem, GRPC_STATUS_UNAUTHENTICATED, + "Credentials failed to get metadata."); + return; + } + GPR_ASSERT(num_md <= MAX_CREDENTIALS_METADATA_COUNT); + GPR_ASSERT(op->send_initial_metadata != NULL); + mdb = op->send_initial_metadata; + for (i = 0; i < num_md; i++) { + grpc_metadata_batch_add_tail( + mdb, &calld->md_links[i], + grpc_mdelem_from_slices(gpr_slice_ref(md_elems[i].key), + gpr_slice_ref(md_elems[i].value))); + } + grpc_call_next_op(exec_ctx, elem, op); +} + +void build_auth_metadata_context(grpc_security_connector *sc, + grpc_auth_context *auth_context, + call_data *calld) { + char *service = gpr_strdup(grpc_mdstr_as_c_string(calld->method)); + char *last_slash = strrchr(service, '/'); + char *method_name = NULL; + char *service_url = NULL; + reset_auth_metadata_context(&calld->auth_md_context); + if (last_slash == NULL) { + gpr_log(GPR_ERROR, "No '/' found in fully qualified method name"); + service[0] = '\0'; + } else if (last_slash == service) { + /* No service part in fully qualified method name: will just be "/". */ + service[1] = '\0'; + } else { + *last_slash = '\0'; + method_name = gpr_strdup(last_slash + 1); + } + if (method_name == NULL) method_name = gpr_strdup(""); + gpr_asprintf(&service_url, "%s://%s%s", + sc->url_scheme == NULL ? "" : sc->url_scheme, + grpc_mdstr_as_c_string(calld->host), service); + calld->auth_md_context.service_url = service_url; + calld->auth_md_context.method_name = method_name; + calld->auth_md_context.channel_auth_context = + GRPC_AUTH_CONTEXT_REF(auth_context, "grpc_auth_metadata_context"); + gpr_free(service); +} + +static void send_security_metadata(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + grpc_transport_stream_op *op) { + call_data *calld = elem->call_data; + channel_data *chand = elem->channel_data; + grpc_client_security_context *ctx = + (grpc_client_security_context *)op->context[GRPC_CONTEXT_SECURITY].value; + grpc_call_credentials *channel_call_creds = + chand->security_connector->request_metadata_creds; + int call_creds_has_md = (ctx != NULL) && (ctx->creds != NULL); + + if (channel_call_creds == NULL && !call_creds_has_md) { + /* Skip sending metadata altogether. */ + grpc_call_next_op(exec_ctx, elem, op); + return; + } + + if (channel_call_creds != NULL && call_creds_has_md) { + calld->creds = grpc_composite_call_credentials_create(channel_call_creds, + ctx->creds, NULL); + if (calld->creds == NULL) { + bubble_up_error(exec_ctx, elem, GRPC_STATUS_INVALID_ARGUMENT, + "Incompatible credentials set on channel and call."); + return; + } + } else { + calld->creds = grpc_call_credentials_ref( + call_creds_has_md ? ctx->creds : channel_call_creds); + } + + build_auth_metadata_context(&chand->security_connector->base, + chand->auth_context, calld); + calld->op = *op; /* Copy op (originates from the caller's stack). */ + GPR_ASSERT(calld->pollset); + grpc_call_credentials_get_request_metadata( + exec_ctx, calld->creds, calld->pollset, calld->auth_md_context, + on_credentials_metadata, elem); +} + +static void on_host_checked(grpc_exec_ctx *exec_ctx, void *user_data, + grpc_security_status status) { + grpc_call_element *elem = (grpc_call_element *)user_data; + call_data *calld = elem->call_data; + + if (status == GRPC_SECURITY_OK) { + send_security_metadata(exec_ctx, elem, &calld->op); + } else { + char *error_msg; + gpr_asprintf(&error_msg, "Invalid host %s set in :authority metadata.", + grpc_mdstr_as_c_string(calld->host)); + bubble_up_error(exec_ctx, elem, GRPC_STATUS_INVALID_ARGUMENT, error_msg); + gpr_free(error_msg); + } +} + +/* Called either: + - in response to an API call (or similar) from above, to send something + - a network event (or similar) from below, to receive something + op contains type and call direction information, in addition to the data + that is being sent or received. */ +static void auth_start_transport_op(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + grpc_transport_stream_op *op) { + /* grab pointers to our data from the call element */ + call_data *calld = elem->call_data; + channel_data *chand = elem->channel_data; + grpc_linked_mdelem *l; + grpc_client_security_context *sec_ctx = NULL; + + if (calld->security_context_set == 0 && + op->cancel_with_status == GRPC_STATUS_OK) { + calld->security_context_set = 1; + GPR_ASSERT(op->context); + if (op->context[GRPC_CONTEXT_SECURITY].value == NULL) { + op->context[GRPC_CONTEXT_SECURITY].value = + grpc_client_security_context_create(); + op->context[GRPC_CONTEXT_SECURITY].destroy = + grpc_client_security_context_destroy; + } + sec_ctx = op->context[GRPC_CONTEXT_SECURITY].value; + GRPC_AUTH_CONTEXT_UNREF(sec_ctx->auth_context, "client auth filter"); + sec_ctx->auth_context = + GRPC_AUTH_CONTEXT_REF(chand->auth_context, "client_auth_filter"); + } + + if (op->send_initial_metadata != NULL) { + for (l = op->send_initial_metadata->list.head; l != NULL; l = l->next) { + grpc_mdelem *md = l->md; + /* Pointer comparison is OK for md_elems created from the same context. + */ + if (md->key == GRPC_MDSTR_AUTHORITY) { + if (calld->host != NULL) GRPC_MDSTR_UNREF(calld->host); + calld->host = GRPC_MDSTR_REF(md->value); + } else if (md->key == GRPC_MDSTR_PATH) { + if (calld->method != NULL) GRPC_MDSTR_UNREF(calld->method); + calld->method = GRPC_MDSTR_REF(md->value); + } + } + if (calld->host != NULL) { + const char *call_host = grpc_mdstr_as_c_string(calld->host); + calld->op = *op; /* Copy op (originates from the caller's stack). */ + grpc_channel_security_connector_check_call_host( + exec_ctx, chand->security_connector, call_host, chand->auth_context, + on_host_checked, elem); + return; /* early exit */ + } + } + + /* pass control down the stack */ + grpc_call_next_op(exec_ctx, elem, op); +} + +/* Constructor for call_data */ +static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + grpc_call_element_args *args) { + call_data *calld = elem->call_data; + memset(calld, 0, sizeof(*calld)); +} + +static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + grpc_pollset *pollset) { + call_data *calld = elem->call_data; + calld->pollset = pollset; +} + +/* Destructor for call_data */ +static void destroy_call_elem(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem) { + call_data *calld = elem->call_data; + grpc_call_credentials_unref(calld->creds); + if (calld->host != NULL) { + GRPC_MDSTR_UNREF(calld->host); + } + if (calld->method != NULL) { + GRPC_MDSTR_UNREF(calld->method); + } + reset_auth_metadata_context(&calld->auth_md_context); +} + +/* Constructor for channel_data */ +static void init_channel_elem(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem, + grpc_channel_element_args *args) { + grpc_security_connector *sc = + grpc_find_security_connector_in_args(args->channel_args); + grpc_auth_context *auth_context = + grpc_find_auth_context_in_args(args->channel_args); + + /* grab pointers to our data from the channel element */ + channel_data *chand = elem->channel_data; + + /* The first and the last filters tend to be implemented differently to + handle the case that there's no 'next' filter to call on the up or down + path */ + GPR_ASSERT(!args->is_last); + GPR_ASSERT(sc != NULL); + GPR_ASSERT(auth_context != NULL); + + /* initialize members */ + chand->security_connector = + (grpc_channel_security_connector *)GRPC_SECURITY_CONNECTOR_REF( + sc, "client_auth_filter"); + chand->auth_context = + GRPC_AUTH_CONTEXT_REF(auth_context, "client_auth_filter"); +} + +/* Destructor for channel data */ +static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem) { + /* grab pointers to our data from the channel element */ + channel_data *chand = elem->channel_data; + grpc_channel_security_connector *sc = chand->security_connector; + if (sc != NULL) { + GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "client_auth_filter"); + } + GRPC_AUTH_CONTEXT_UNREF(chand->auth_context, "client_auth_filter"); +} + +const grpc_channel_filter grpc_client_auth_filter = { + auth_start_transport_op, grpc_channel_next_op, sizeof(call_data), + init_call_elem, set_pollset, destroy_call_elem, + sizeof(channel_data), init_channel_elem, destroy_channel_elem, + grpc_call_next_get_peer, "client-auth"}; diff --git a/src/core/lib/security/credentials.c b/src/core/lib/security/credentials.c new file mode 100644 index 0000000000..c8348bc12c --- /dev/null +++ b/src/core/lib/security/credentials.c @@ -0,0 +1,1281 @@ +/* + * + * Copyright 2015-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/security/credentials.h" + +#include +#include + +#include "src/core/channel/channel_args.h" +#include "src/core/channel/http_client_filter.h" +#include "src/core/http/httpcli.h" +#include "src/core/http/parser.h" +#include "src/core/iomgr/executor.h" +#include "src/core/json/json.h" +#include "src/core/support/string.h" +#include "src/core/surface/api_trace.h" + +#include +#include +#include +#include +#include + +/* -- Common. -- */ + +struct grpc_credentials_metadata_request { + grpc_call_credentials *creds; + grpc_credentials_metadata_cb cb; + void *user_data; +}; + +static grpc_credentials_metadata_request * +grpc_credentials_metadata_request_create(grpc_call_credentials *creds, + grpc_credentials_metadata_cb cb, + void *user_data) { + grpc_credentials_metadata_request *r = + gpr_malloc(sizeof(grpc_credentials_metadata_request)); + r->creds = grpc_call_credentials_ref(creds); + r->cb = cb; + r->user_data = user_data; + return r; +} + +static void grpc_credentials_metadata_request_destroy( + grpc_credentials_metadata_request *r) { + grpc_call_credentials_unref(r->creds); + gpr_free(r); +} + +grpc_channel_credentials *grpc_channel_credentials_ref( + grpc_channel_credentials *creds) { + if (creds == NULL) return NULL; + gpr_ref(&creds->refcount); + return creds; +} + +void grpc_channel_credentials_unref(grpc_channel_credentials *creds) { + if (creds == NULL) return; + if (gpr_unref(&creds->refcount)) { + if (creds->vtable->destruct != NULL) creds->vtable->destruct(creds); + gpr_free(creds); + } +} + +void grpc_channel_credentials_release(grpc_channel_credentials *creds) { + GRPC_API_TRACE("grpc_channel_credentials_release(creds=%p)", 1, (creds)); + grpc_channel_credentials_unref(creds); +} + +grpc_call_credentials *grpc_call_credentials_ref(grpc_call_credentials *creds) { + if (creds == NULL) return NULL; + gpr_ref(&creds->refcount); + return creds; +} + +void grpc_call_credentials_unref(grpc_call_credentials *creds) { + if (creds == NULL) return; + if (gpr_unref(&creds->refcount)) { + if (creds->vtable->destruct != NULL) creds->vtable->destruct(creds); + gpr_free(creds); + } +} + +void grpc_call_credentials_release(grpc_call_credentials *creds) { + GRPC_API_TRACE("grpc_call_credentials_release(creds=%p)", 1, (creds)); + grpc_call_credentials_unref(creds); +} + +void grpc_call_credentials_get_request_metadata( + grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, + grpc_pollset *pollset, grpc_auth_metadata_context context, + grpc_credentials_metadata_cb cb, void *user_data) { + if (creds == NULL || creds->vtable->get_request_metadata == NULL) { + if (cb != NULL) { + cb(exec_ctx, user_data, NULL, 0, GRPC_CREDENTIALS_OK); + } + return; + } + creds->vtable->get_request_metadata(exec_ctx, creds, pollset, context, cb, + user_data); +} + +grpc_security_status grpc_channel_credentials_create_security_connector( + grpc_channel_credentials *channel_creds, const char *target, + const grpc_channel_args *args, grpc_channel_security_connector **sc, + grpc_channel_args **new_args) { + *new_args = NULL; + if (channel_creds == NULL) { + return GRPC_SECURITY_ERROR; + } + GPR_ASSERT(channel_creds->vtable->create_security_connector != NULL); + return channel_creds->vtable->create_security_connector( + channel_creds, NULL, target, args, sc, new_args); +} + +grpc_server_credentials *grpc_server_credentials_ref( + grpc_server_credentials *creds) { + if (creds == NULL) return NULL; + gpr_ref(&creds->refcount); + return creds; +} + +void grpc_server_credentials_unref(grpc_server_credentials *creds) { + if (creds == NULL) return; + if (gpr_unref(&creds->refcount)) { + if (creds->vtable->destruct != NULL) creds->vtable->destruct(creds); + if (creds->processor.destroy != NULL && creds->processor.state != NULL) { + creds->processor.destroy(creds->processor.state); + } + gpr_free(creds); + } +} + +void grpc_server_credentials_release(grpc_server_credentials *creds) { + GRPC_API_TRACE("grpc_server_credentials_release(creds=%p)", 1, (creds)); + grpc_server_credentials_unref(creds); +} + +grpc_security_status grpc_server_credentials_create_security_connector( + grpc_server_credentials *creds, grpc_server_security_connector **sc) { + if (creds == NULL || creds->vtable->create_security_connector == NULL) { + gpr_log(GPR_ERROR, "Server credentials cannot create security context."); + return GRPC_SECURITY_ERROR; + } + return creds->vtable->create_security_connector(creds, sc); +} + +void grpc_server_credentials_set_auth_metadata_processor( + grpc_server_credentials *creds, grpc_auth_metadata_processor processor) { + GRPC_API_TRACE( + "grpc_server_credentials_set_auth_metadata_processor(" + "creds=%p, " + "processor=grpc_auth_metadata_processor { process: %p, state: %p })", + 3, (creds, (void *)(intptr_t)processor.process, processor.state)); + if (creds == NULL) return; + if (creds->processor.destroy != NULL && creds->processor.state != NULL) { + creds->processor.destroy(creds->processor.state); + } + creds->processor = processor; +} + +static void server_credentials_pointer_arg_destroy(void *p) { + grpc_server_credentials_unref(p); +} + +static void *server_credentials_pointer_arg_copy(void *p) { + return grpc_server_credentials_ref(p); +} + +static int server_credentials_pointer_cmp(void *a, void *b) { + return GPR_ICMP(a, b); +} + +static const grpc_arg_pointer_vtable cred_ptr_vtable = { + server_credentials_pointer_arg_copy, server_credentials_pointer_arg_destroy, + server_credentials_pointer_cmp}; + +grpc_arg grpc_server_credentials_to_arg(grpc_server_credentials *p) { + grpc_arg arg; + memset(&arg, 0, sizeof(grpc_arg)); + arg.type = GRPC_ARG_POINTER; + arg.key = GRPC_SERVER_CREDENTIALS_ARG; + arg.value.pointer.p = p; + arg.value.pointer.vtable = &cred_ptr_vtable; + return arg; +} + +grpc_server_credentials *grpc_server_credentials_from_arg(const grpc_arg *arg) { + if (strcmp(arg->key, GRPC_SERVER_CREDENTIALS_ARG) != 0) return NULL; + if (arg->type != GRPC_ARG_POINTER) { + gpr_log(GPR_ERROR, "Invalid type %d for arg %s", arg->type, + GRPC_SERVER_CREDENTIALS_ARG); + return NULL; + } + return arg->value.pointer.p; +} + +grpc_server_credentials *grpc_find_server_credentials_in_args( + const grpc_channel_args *args) { + size_t i; + if (args == NULL) return NULL; + for (i = 0; i < args->num_args; i++) { + grpc_server_credentials *p = + grpc_server_credentials_from_arg(&args->args[i]); + if (p != NULL) return p; + } + return NULL; +} + +/* -- Ssl credentials. -- */ + +static void ssl_destruct(grpc_channel_credentials *creds) { + grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds; + if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs); + if (c->config.pem_private_key != NULL) gpr_free(c->config.pem_private_key); + if (c->config.pem_cert_chain != NULL) gpr_free(c->config.pem_cert_chain); +} + +static void ssl_server_destruct(grpc_server_credentials *creds) { + grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds; + size_t i; + for (i = 0; i < c->config.num_key_cert_pairs; i++) { + if (c->config.pem_private_keys[i] != NULL) { + gpr_free(c->config.pem_private_keys[i]); + } + if (c->config.pem_cert_chains[i] != NULL) { + gpr_free(c->config.pem_cert_chains[i]); + } + } + if (c->config.pem_private_keys != NULL) gpr_free(c->config.pem_private_keys); + if (c->config.pem_private_keys_sizes != NULL) { + gpr_free(c->config.pem_private_keys_sizes); + } + if (c->config.pem_cert_chains != NULL) gpr_free(c->config.pem_cert_chains); + if (c->config.pem_cert_chains_sizes != NULL) { + gpr_free(c->config.pem_cert_chains_sizes); + } + if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs); +} + +static grpc_security_status ssl_create_security_connector( + grpc_channel_credentials *creds, grpc_call_credentials *call_creds, + const char *target, const grpc_channel_args *args, + grpc_channel_security_connector **sc, grpc_channel_args **new_args) { + grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds; + grpc_security_status status = GRPC_SECURITY_OK; + size_t i = 0; + const char *overridden_target_name = NULL; + grpc_arg new_arg; + + for (i = 0; args && i < args->num_args; i++) { + grpc_arg *arg = &args->args[i]; + if (strcmp(arg->key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG) == 0 && + arg->type == GRPC_ARG_STRING) { + overridden_target_name = arg->value.string; + break; + } + } + status = grpc_ssl_channel_security_connector_create( + call_creds, &c->config, target, overridden_target_name, sc); + if (status != GRPC_SECURITY_OK) { + return status; + } + new_arg.type = GRPC_ARG_STRING; + new_arg.key = GRPC_ARG_HTTP2_SCHEME; + new_arg.value.string = "https"; + *new_args = grpc_channel_args_copy_and_add(args, &new_arg, 1); + return status; +} + +static grpc_security_status ssl_server_create_security_connector( + grpc_server_credentials *creds, grpc_server_security_connector **sc) { + grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds; + return grpc_ssl_server_security_connector_create(&c->config, sc); +} + +static grpc_channel_credentials_vtable ssl_vtable = { + ssl_destruct, ssl_create_security_connector}; + +static grpc_server_credentials_vtable ssl_server_vtable = { + ssl_server_destruct, ssl_server_create_security_connector}; + +static void ssl_copy_key_material(const char *input, unsigned char **output, + size_t *output_size) { + *output_size = strlen(input); + *output = gpr_malloc(*output_size); + memcpy(*output, input, *output_size); +} + +static void ssl_build_config(const char *pem_root_certs, + grpc_ssl_pem_key_cert_pair *pem_key_cert_pair, + grpc_ssl_config *config) { + if (pem_root_certs != NULL) { + ssl_copy_key_material(pem_root_certs, &config->pem_root_certs, + &config->pem_root_certs_size); + } + if (pem_key_cert_pair != NULL) { + GPR_ASSERT(pem_key_cert_pair->private_key != NULL); + GPR_ASSERT(pem_key_cert_pair->cert_chain != NULL); + ssl_copy_key_material(pem_key_cert_pair->private_key, + &config->pem_private_key, + &config->pem_private_key_size); + ssl_copy_key_material(pem_key_cert_pair->cert_chain, + &config->pem_cert_chain, + &config->pem_cert_chain_size); + } +} + +static void ssl_build_server_config( + const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs, + size_t num_key_cert_pairs, int force_client_auth, + grpc_ssl_server_config *config) { + size_t i; + config->force_client_auth = force_client_auth; + if (pem_root_certs != NULL) { + ssl_copy_key_material(pem_root_certs, &config->pem_root_certs, + &config->pem_root_certs_size); + } + if (num_key_cert_pairs > 0) { + GPR_ASSERT(pem_key_cert_pairs != NULL); + config->pem_private_keys = + gpr_malloc(num_key_cert_pairs * sizeof(unsigned char *)); + config->pem_cert_chains = + gpr_malloc(num_key_cert_pairs * sizeof(unsigned char *)); + config->pem_private_keys_sizes = + gpr_malloc(num_key_cert_pairs * sizeof(size_t)); + config->pem_cert_chains_sizes = + gpr_malloc(num_key_cert_pairs * sizeof(size_t)); + } + config->num_key_cert_pairs = num_key_cert_pairs; + for (i = 0; i < num_key_cert_pairs; i++) { + GPR_ASSERT(pem_key_cert_pairs[i].private_key != NULL); + GPR_ASSERT(pem_key_cert_pairs[i].cert_chain != NULL); + ssl_copy_key_material(pem_key_cert_pairs[i].private_key, + &config->pem_private_keys[i], + &config->pem_private_keys_sizes[i]); + ssl_copy_key_material(pem_key_cert_pairs[i].cert_chain, + &config->pem_cert_chains[i], + &config->pem_cert_chains_sizes[i]); + } +} + +grpc_channel_credentials *grpc_ssl_credentials_create( + const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair, + void *reserved) { + grpc_ssl_credentials *c = gpr_malloc(sizeof(grpc_ssl_credentials)); + GRPC_API_TRACE( + "grpc_ssl_credentials_create(pem_root_certs=%s, " + "pem_key_cert_pair=%p, " + "reserved=%p)", + 3, (pem_root_certs, pem_key_cert_pair, reserved)); + GPR_ASSERT(reserved == NULL); + memset(c, 0, sizeof(grpc_ssl_credentials)); + c->base.type = GRPC_CHANNEL_CREDENTIALS_TYPE_SSL; + c->base.vtable = &ssl_vtable; + gpr_ref_init(&c->base.refcount, 1); + ssl_build_config(pem_root_certs, pem_key_cert_pair, &c->config); + return &c->base; +} + +grpc_server_credentials *grpc_ssl_server_credentials_create( + const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs, + size_t num_key_cert_pairs, int force_client_auth, void *reserved) { + grpc_ssl_server_credentials *c = + gpr_malloc(sizeof(grpc_ssl_server_credentials)); + GRPC_API_TRACE( + "grpc_ssl_server_credentials_create(" + "pem_root_certs=%s, pem_key_cert_pairs=%p, num_key_cert_pairs=%lu, " + "force_client_auth=%d, reserved=%p)", + 5, (pem_root_certs, pem_key_cert_pairs, (unsigned long)num_key_cert_pairs, + force_client_auth, reserved)); + GPR_ASSERT(reserved == NULL); + memset(c, 0, sizeof(grpc_ssl_server_credentials)); + c->base.type = GRPC_CHANNEL_CREDENTIALS_TYPE_SSL; + gpr_ref_init(&c->base.refcount, 1); + c->base.vtable = &ssl_server_vtable; + ssl_build_server_config(pem_root_certs, pem_key_cert_pairs, + num_key_cert_pairs, force_client_auth, &c->config); + return &c->base; +} + +/* -- Jwt credentials -- */ + +static void jwt_reset_cache(grpc_service_account_jwt_access_credentials *c) { + if (c->cached.jwt_md != NULL) { + grpc_credentials_md_store_unref(c->cached.jwt_md); + c->cached.jwt_md = NULL; + } + if (c->cached.service_url != NULL) { + gpr_free(c->cached.service_url); + c->cached.service_url = NULL; + } + c->cached.jwt_expiration = gpr_inf_past(GPR_CLOCK_REALTIME); +} + +static void jwt_destruct(grpc_call_credentials *creds) { + grpc_service_account_jwt_access_credentials *c = + (grpc_service_account_jwt_access_credentials *)creds; + grpc_auth_json_key_destruct(&c->key); + jwt_reset_cache(c); + gpr_mu_destroy(&c->cache_mu); +} + +static void jwt_get_request_metadata(grpc_exec_ctx *exec_ctx, + grpc_call_credentials *creds, + grpc_pollset *pollset, + grpc_auth_metadata_context context, + grpc_credentials_metadata_cb cb, + void *user_data) { + grpc_service_account_jwt_access_credentials *c = + (grpc_service_account_jwt_access_credentials *)creds; + gpr_timespec refresh_threshold = gpr_time_from_seconds( + GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS, GPR_TIMESPAN); + + /* See if we can return a cached jwt. */ + grpc_credentials_md_store *jwt_md = NULL; + { + gpr_mu_lock(&c->cache_mu); + if (c->cached.service_url != NULL && + strcmp(c->cached.service_url, context.service_url) == 0 && + c->cached.jwt_md != NULL && + (gpr_time_cmp(gpr_time_sub(c->cached.jwt_expiration, + gpr_now(GPR_CLOCK_REALTIME)), + refresh_threshold) > 0)) { + jwt_md = grpc_credentials_md_store_ref(c->cached.jwt_md); + } + gpr_mu_unlock(&c->cache_mu); + } + + if (jwt_md == NULL) { + char *jwt = NULL; + /* Generate a new jwt. */ + gpr_mu_lock(&c->cache_mu); + jwt_reset_cache(c); + jwt = grpc_jwt_encode_and_sign(&c->key, context.service_url, + c->jwt_lifetime, NULL); + if (jwt != NULL) { + char *md_value; + gpr_asprintf(&md_value, "Bearer %s", jwt); + gpr_free(jwt); + c->cached.jwt_expiration = + gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), c->jwt_lifetime); + c->cached.service_url = gpr_strdup(context.service_url); + c->cached.jwt_md = grpc_credentials_md_store_create(1); + grpc_credentials_md_store_add_cstrings( + c->cached.jwt_md, GRPC_AUTHORIZATION_METADATA_KEY, md_value); + gpr_free(md_value); + jwt_md = grpc_credentials_md_store_ref(c->cached.jwt_md); + } + gpr_mu_unlock(&c->cache_mu); + } + + if (jwt_md != NULL) { + cb(exec_ctx, user_data, jwt_md->entries, jwt_md->num_entries, + GRPC_CREDENTIALS_OK); + grpc_credentials_md_store_unref(jwt_md); + } else { + cb(exec_ctx, user_data, NULL, 0, GRPC_CREDENTIALS_ERROR); + } +} + +static grpc_call_credentials_vtable jwt_vtable = {jwt_destruct, + jwt_get_request_metadata}; + +grpc_call_credentials * +grpc_service_account_jwt_access_credentials_create_from_auth_json_key( + grpc_auth_json_key key, gpr_timespec token_lifetime) { + grpc_service_account_jwt_access_credentials *c; + if (!grpc_auth_json_key_is_valid(&key)) { + gpr_log(GPR_ERROR, "Invalid input for jwt credentials creation"); + return NULL; + } + c = gpr_malloc(sizeof(grpc_service_account_jwt_access_credentials)); + memset(c, 0, sizeof(grpc_service_account_jwt_access_credentials)); + c->base.type = GRPC_CALL_CREDENTIALS_TYPE_JWT; + gpr_ref_init(&c->base.refcount, 1); + c->base.vtable = &jwt_vtable; + c->key = key; + c->jwt_lifetime = token_lifetime; + gpr_mu_init(&c->cache_mu); + jwt_reset_cache(c); + return &c->base; +} + +grpc_call_credentials *grpc_service_account_jwt_access_credentials_create( + const char *json_key, gpr_timespec token_lifetime, void *reserved) { + GRPC_API_TRACE( + "grpc_service_account_jwt_access_credentials_create(" + "json_key=%s, " + "token_lifetime=" + "gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, " + "reserved=%p)", + 5, + (json_key, (long long)token_lifetime.tv_sec, (int)token_lifetime.tv_nsec, + (int)token_lifetime.clock_type, reserved)); + GPR_ASSERT(reserved == NULL); + return grpc_service_account_jwt_access_credentials_create_from_auth_json_key( + grpc_auth_json_key_create_from_string(json_key), token_lifetime); +} + +/* -- Oauth2TokenFetcher credentials -- */ + +static void oauth2_token_fetcher_destruct(grpc_call_credentials *creds) { + grpc_oauth2_token_fetcher_credentials *c = + (grpc_oauth2_token_fetcher_credentials *)creds; + grpc_credentials_md_store_unref(c->access_token_md); + gpr_mu_destroy(&c->mu); + grpc_httpcli_context_destroy(&c->httpcli_context); +} + +grpc_credentials_status +grpc_oauth2_token_fetcher_credentials_parse_server_response( + const grpc_http_response *response, grpc_credentials_md_store **token_md, + gpr_timespec *token_lifetime) { + char *null_terminated_body = NULL; + char *new_access_token = NULL; + grpc_credentials_status status = GRPC_CREDENTIALS_OK; + grpc_json *json = NULL; + + if (response == NULL) { + gpr_log(GPR_ERROR, "Received NULL response."); + status = GRPC_CREDENTIALS_ERROR; + goto end; + } + + if (response->body_length > 0) { + null_terminated_body = gpr_malloc(response->body_length + 1); + null_terminated_body[response->body_length] = '\0'; + memcpy(null_terminated_body, response->body, response->body_length); + } + + if (response->status != 200) { + gpr_log(GPR_ERROR, "Call to http server ended with error %d [%s].", + response->status, + null_terminated_body != NULL ? null_terminated_body : ""); + status = GRPC_CREDENTIALS_ERROR; + goto end; + } else { + grpc_json *access_token = NULL; + grpc_json *token_type = NULL; + grpc_json *expires_in = NULL; + grpc_json *ptr; + json = grpc_json_parse_string(null_terminated_body); + if (json == NULL) { + gpr_log(GPR_ERROR, "Could not parse JSON from %s", null_terminated_body); + status = GRPC_CREDENTIALS_ERROR; + goto end; + } + if (json->type != GRPC_JSON_OBJECT) { + gpr_log(GPR_ERROR, "Response should be a JSON object"); + status = GRPC_CREDENTIALS_ERROR; + goto end; + } + for (ptr = json->child; ptr; ptr = ptr->next) { + if (strcmp(ptr->key, "access_token") == 0) { + access_token = ptr; + } else if (strcmp(ptr->key, "token_type") == 0) { + token_type = ptr; + } else if (strcmp(ptr->key, "expires_in") == 0) { + expires_in = ptr; + } + } + if (access_token == NULL || access_token->type != GRPC_JSON_STRING) { + gpr_log(GPR_ERROR, "Missing or invalid access_token in JSON."); + status = GRPC_CREDENTIALS_ERROR; + goto end; + } + if (token_type == NULL || token_type->type != GRPC_JSON_STRING) { + gpr_log(GPR_ERROR, "Missing or invalid token_type in JSON."); + status = GRPC_CREDENTIALS_ERROR; + goto end; + } + if (expires_in == NULL || expires_in->type != GRPC_JSON_NUMBER) { + gpr_log(GPR_ERROR, "Missing or invalid expires_in in JSON."); + status = GRPC_CREDENTIALS_ERROR; + goto end; + } + gpr_asprintf(&new_access_token, "%s %s", token_type->value, + access_token->value); + token_lifetime->tv_sec = strtol(expires_in->value, NULL, 10); + token_lifetime->tv_nsec = 0; + token_lifetime->clock_type = GPR_TIMESPAN; + if (*token_md != NULL) grpc_credentials_md_store_unref(*token_md); + *token_md = grpc_credentials_md_store_create(1); + grpc_credentials_md_store_add_cstrings( + *token_md, GRPC_AUTHORIZATION_METADATA_KEY, new_access_token); + status = GRPC_CREDENTIALS_OK; + } + +end: + if (status != GRPC_CREDENTIALS_OK && (*token_md != NULL)) { + grpc_credentials_md_store_unref(*token_md); + *token_md = NULL; + } + if (null_terminated_body != NULL) gpr_free(null_terminated_body); + if (new_access_token != NULL) gpr_free(new_access_token); + if (json != NULL) grpc_json_destroy(json); + return status; +} + +static void on_oauth2_token_fetcher_http_response( + grpc_exec_ctx *exec_ctx, void *user_data, + const grpc_http_response *response) { + grpc_credentials_metadata_request *r = + (grpc_credentials_metadata_request *)user_data; + grpc_oauth2_token_fetcher_credentials *c = + (grpc_oauth2_token_fetcher_credentials *)r->creds; + gpr_timespec token_lifetime; + grpc_credentials_status status; + + gpr_mu_lock(&c->mu); + status = grpc_oauth2_token_fetcher_credentials_parse_server_response( + response, &c->access_token_md, &token_lifetime); + if (status == GRPC_CREDENTIALS_OK) { + c->token_expiration = + gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), token_lifetime); + r->cb(exec_ctx, r->user_data, c->access_token_md->entries, + c->access_token_md->num_entries, status); + } else { + c->token_expiration = gpr_inf_past(GPR_CLOCK_REALTIME); + r->cb(exec_ctx, r->user_data, NULL, 0, status); + } + gpr_mu_unlock(&c->mu); + grpc_credentials_metadata_request_destroy(r); +} + +static void oauth2_token_fetcher_get_request_metadata( + grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, + grpc_pollset *pollset, grpc_auth_metadata_context context, + grpc_credentials_metadata_cb cb, void *user_data) { + grpc_oauth2_token_fetcher_credentials *c = + (grpc_oauth2_token_fetcher_credentials *)creds; + gpr_timespec refresh_threshold = gpr_time_from_seconds( + GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS, GPR_TIMESPAN); + grpc_credentials_md_store *cached_access_token_md = NULL; + { + gpr_mu_lock(&c->mu); + if (c->access_token_md != NULL && + (gpr_time_cmp( + gpr_time_sub(c->token_expiration, gpr_now(GPR_CLOCK_REALTIME)), + refresh_threshold) > 0)) { + cached_access_token_md = + grpc_credentials_md_store_ref(c->access_token_md); + } + gpr_mu_unlock(&c->mu); + } + if (cached_access_token_md != NULL) { + cb(exec_ctx, user_data, cached_access_token_md->entries, + cached_access_token_md->num_entries, GRPC_CREDENTIALS_OK); + grpc_credentials_md_store_unref(cached_access_token_md); + } else { + c->fetch_func( + exec_ctx, + grpc_credentials_metadata_request_create(creds, cb, user_data), + &c->httpcli_context, pollset, on_oauth2_token_fetcher_http_response, + gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), refresh_threshold)); + } +} + +static void init_oauth2_token_fetcher(grpc_oauth2_token_fetcher_credentials *c, + grpc_fetch_oauth2_func fetch_func) { + memset(c, 0, sizeof(grpc_oauth2_token_fetcher_credentials)); + c->base.type = GRPC_CALL_CREDENTIALS_TYPE_OAUTH2; + gpr_ref_init(&c->base.refcount, 1); + gpr_mu_init(&c->mu); + c->token_expiration = gpr_inf_past(GPR_CLOCK_REALTIME); + c->fetch_func = fetch_func; + grpc_httpcli_context_init(&c->httpcli_context); +} + +/* -- GoogleComputeEngine credentials. -- */ + +static grpc_call_credentials_vtable compute_engine_vtable = { + oauth2_token_fetcher_destruct, oauth2_token_fetcher_get_request_metadata}; + +static void compute_engine_fetch_oauth2( + grpc_exec_ctx *exec_ctx, grpc_credentials_metadata_request *metadata_req, + grpc_httpcli_context *httpcli_context, grpc_pollset *pollset, + grpc_httpcli_response_cb response_cb, gpr_timespec deadline) { + grpc_http_header header = {"Metadata-Flavor", "Google"}; + grpc_httpcli_request request; + memset(&request, 0, sizeof(grpc_httpcli_request)); + request.host = GRPC_COMPUTE_ENGINE_METADATA_HOST; + request.http.path = GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH; + request.http.hdr_count = 1; + request.http.hdrs = &header; + grpc_httpcli_get(exec_ctx, httpcli_context, pollset, &request, deadline, + response_cb, metadata_req); +} + +grpc_call_credentials *grpc_google_compute_engine_credentials_create( + void *reserved) { + grpc_oauth2_token_fetcher_credentials *c = + gpr_malloc(sizeof(grpc_oauth2_token_fetcher_credentials)); + GRPC_API_TRACE("grpc_compute_engine_credentials_create(reserved=%p)", 1, + (reserved)); + GPR_ASSERT(reserved == NULL); + init_oauth2_token_fetcher(c, compute_engine_fetch_oauth2); + c->base.vtable = &compute_engine_vtable; + return &c->base; +} + +/* -- GoogleRefreshToken credentials. -- */ + +static void refresh_token_destruct(grpc_call_credentials *creds) { + grpc_google_refresh_token_credentials *c = + (grpc_google_refresh_token_credentials *)creds; + grpc_auth_refresh_token_destruct(&c->refresh_token); + oauth2_token_fetcher_destruct(&c->base.base); +} + +static grpc_call_credentials_vtable refresh_token_vtable = { + refresh_token_destruct, oauth2_token_fetcher_get_request_metadata}; + +static void refresh_token_fetch_oauth2( + grpc_exec_ctx *exec_ctx, grpc_credentials_metadata_request *metadata_req, + grpc_httpcli_context *httpcli_context, grpc_pollset *pollset, + grpc_httpcli_response_cb response_cb, gpr_timespec deadline) { + grpc_google_refresh_token_credentials *c = + (grpc_google_refresh_token_credentials *)metadata_req->creds; + grpc_http_header header = {"Content-Type", + "application/x-www-form-urlencoded"}; + grpc_httpcli_request request; + char *body = NULL; + gpr_asprintf(&body, GRPC_REFRESH_TOKEN_POST_BODY_FORMAT_STRING, + c->refresh_token.client_id, c->refresh_token.client_secret, + c->refresh_token.refresh_token); + memset(&request, 0, sizeof(grpc_httpcli_request)); + request.host = GRPC_GOOGLE_OAUTH2_SERVICE_HOST; + request.http.path = GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH; + request.http.hdr_count = 1; + request.http.hdrs = &header; + request.handshaker = &grpc_httpcli_ssl; + grpc_httpcli_post(exec_ctx, httpcli_context, pollset, &request, body, + strlen(body), deadline, response_cb, metadata_req); + gpr_free(body); +} + +grpc_call_credentials * +grpc_refresh_token_credentials_create_from_auth_refresh_token( + grpc_auth_refresh_token refresh_token) { + grpc_google_refresh_token_credentials *c; + if (!grpc_auth_refresh_token_is_valid(&refresh_token)) { + gpr_log(GPR_ERROR, "Invalid input for refresh token credentials creation"); + return NULL; + } + c = gpr_malloc(sizeof(grpc_google_refresh_token_credentials)); + memset(c, 0, sizeof(grpc_google_refresh_token_credentials)); + init_oauth2_token_fetcher(&c->base, refresh_token_fetch_oauth2); + c->base.base.vtable = &refresh_token_vtable; + c->refresh_token = refresh_token; + return &c->base.base; +} + +grpc_call_credentials *grpc_google_refresh_token_credentials_create( + const char *json_refresh_token, void *reserved) { + GRPC_API_TRACE( + "grpc_refresh_token_credentials_create(json_refresh_token=%s, " + "reserved=%p)", + 2, (json_refresh_token, reserved)); + GPR_ASSERT(reserved == NULL); + return grpc_refresh_token_credentials_create_from_auth_refresh_token( + grpc_auth_refresh_token_create_from_string(json_refresh_token)); +} + +/* -- Metadata-only credentials. -- */ + +static void md_only_test_destruct(grpc_call_credentials *creds) { + grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)creds; + grpc_credentials_md_store_unref(c->md_store); +} + +static void on_simulated_token_fetch_done(grpc_exec_ctx *exec_ctx, + void *user_data, bool success) { + grpc_credentials_metadata_request *r = + (grpc_credentials_metadata_request *)user_data; + grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)r->creds; + r->cb(exec_ctx, r->user_data, c->md_store->entries, c->md_store->num_entries, + GRPC_CREDENTIALS_OK); + grpc_credentials_metadata_request_destroy(r); +} + +static void md_only_test_get_request_metadata( + grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, + grpc_pollset *pollset, grpc_auth_metadata_context context, + grpc_credentials_metadata_cb cb, void *user_data) { + grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)creds; + + if (c->is_async) { + grpc_credentials_metadata_request *cb_arg = + grpc_credentials_metadata_request_create(creds, cb, user_data); + grpc_executor_enqueue( + grpc_closure_create(on_simulated_token_fetch_done, cb_arg), true); + } else { + cb(exec_ctx, user_data, c->md_store->entries, 1, GRPC_CREDENTIALS_OK); + } +} + +static grpc_call_credentials_vtable md_only_test_vtable = { + md_only_test_destruct, md_only_test_get_request_metadata}; + +grpc_call_credentials *grpc_md_only_test_credentials_create( + const char *md_key, const char *md_value, int is_async) { + grpc_md_only_test_credentials *c = + gpr_malloc(sizeof(grpc_md_only_test_credentials)); + memset(c, 0, sizeof(grpc_md_only_test_credentials)); + c->base.type = GRPC_CALL_CREDENTIALS_TYPE_OAUTH2; + c->base.vtable = &md_only_test_vtable; + gpr_ref_init(&c->base.refcount, 1); + c->md_store = grpc_credentials_md_store_create(1); + grpc_credentials_md_store_add_cstrings(c->md_store, md_key, md_value); + c->is_async = is_async; + return &c->base; +} + +/* -- Oauth2 Access Token credentials. -- */ + +static void access_token_destruct(grpc_call_credentials *creds) { + grpc_access_token_credentials *c = (grpc_access_token_credentials *)creds; + grpc_credentials_md_store_unref(c->access_token_md); +} + +static void access_token_get_request_metadata( + grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, + grpc_pollset *pollset, grpc_auth_metadata_context context, + grpc_credentials_metadata_cb cb, void *user_data) { + grpc_access_token_credentials *c = (grpc_access_token_credentials *)creds; + cb(exec_ctx, user_data, c->access_token_md->entries, 1, GRPC_CREDENTIALS_OK); +} + +static grpc_call_credentials_vtable access_token_vtable = { + access_token_destruct, access_token_get_request_metadata}; + +grpc_call_credentials *grpc_access_token_credentials_create( + const char *access_token, void *reserved) { + grpc_access_token_credentials *c = + gpr_malloc(sizeof(grpc_access_token_credentials)); + char *token_md_value; + GRPC_API_TRACE( + "grpc_access_token_credentials_create(access_token=%s, " + "reserved=%p)", + 2, (access_token, reserved)); + GPR_ASSERT(reserved == NULL); + memset(c, 0, sizeof(grpc_access_token_credentials)); + c->base.type = GRPC_CALL_CREDENTIALS_TYPE_OAUTH2; + c->base.vtable = &access_token_vtable; + gpr_ref_init(&c->base.refcount, 1); + c->access_token_md = grpc_credentials_md_store_create(1); + gpr_asprintf(&token_md_value, "Bearer %s", access_token); + grpc_credentials_md_store_add_cstrings( + c->access_token_md, GRPC_AUTHORIZATION_METADATA_KEY, token_md_value); + gpr_free(token_md_value); + return &c->base; +} + +/* -- Fake transport security credentials. -- */ + +static grpc_security_status fake_transport_security_create_security_connector( + grpc_channel_credentials *c, grpc_call_credentials *call_creds, + const char *target, const grpc_channel_args *args, + grpc_channel_security_connector **sc, grpc_channel_args **new_args) { + *sc = grpc_fake_channel_security_connector_create(call_creds); + return GRPC_SECURITY_OK; +} + +static grpc_security_status +fake_transport_security_server_create_security_connector( + grpc_server_credentials *c, grpc_server_security_connector **sc) { + *sc = grpc_fake_server_security_connector_create(); + return GRPC_SECURITY_OK; +} + +static grpc_channel_credentials_vtable + fake_transport_security_credentials_vtable = { + NULL, fake_transport_security_create_security_connector}; + +static grpc_server_credentials_vtable + fake_transport_security_server_credentials_vtable = { + NULL, fake_transport_security_server_create_security_connector}; + +grpc_channel_credentials *grpc_fake_transport_security_credentials_create( + void) { + grpc_channel_credentials *c = gpr_malloc(sizeof(grpc_channel_credentials)); + memset(c, 0, sizeof(grpc_channel_credentials)); + c->type = GRPC_CHANNEL_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY; + c->vtable = &fake_transport_security_credentials_vtable; + gpr_ref_init(&c->refcount, 1); + return c; +} + +grpc_server_credentials *grpc_fake_transport_security_server_credentials_create( + void) { + grpc_server_credentials *c = gpr_malloc(sizeof(grpc_server_credentials)); + memset(c, 0, sizeof(grpc_server_credentials)); + c->type = GRPC_CHANNEL_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY; + gpr_ref_init(&c->refcount, 1); + c->vtable = &fake_transport_security_server_credentials_vtable; + return c; +} + +/* -- Composite call credentials. -- */ + +typedef struct { + grpc_composite_call_credentials *composite_creds; + size_t creds_index; + grpc_credentials_md_store *md_elems; + grpc_auth_metadata_context auth_md_context; + void *user_data; + grpc_pollset *pollset; + grpc_credentials_metadata_cb cb; +} grpc_composite_call_credentials_metadata_context; + +static void composite_call_destruct(grpc_call_credentials *creds) { + grpc_composite_call_credentials *c = (grpc_composite_call_credentials *)creds; + size_t i; + for (i = 0; i < c->inner.num_creds; i++) { + grpc_call_credentials_unref(c->inner.creds_array[i]); + } + gpr_free(c->inner.creds_array); +} + +static void composite_call_md_context_destroy( + grpc_composite_call_credentials_metadata_context *ctx) { + grpc_credentials_md_store_unref(ctx->md_elems); + gpr_free(ctx); +} + +static void composite_call_metadata_cb(grpc_exec_ctx *exec_ctx, void *user_data, + grpc_credentials_md *md_elems, + size_t num_md, + grpc_credentials_status status) { + grpc_composite_call_credentials_metadata_context *ctx = + (grpc_composite_call_credentials_metadata_context *)user_data; + if (status != GRPC_CREDENTIALS_OK) { + ctx->cb(exec_ctx, ctx->user_data, NULL, 0, status); + return; + } + + /* Copy the metadata in the context. */ + if (num_md > 0) { + size_t i; + for (i = 0; i < num_md; i++) { + grpc_credentials_md_store_add(ctx->md_elems, md_elems[i].key, + md_elems[i].value); + } + } + + /* See if we need to get some more metadata. */ + if (ctx->creds_index < ctx->composite_creds->inner.num_creds) { + grpc_call_credentials *inner_creds = + ctx->composite_creds->inner.creds_array[ctx->creds_index++]; + grpc_call_credentials_get_request_metadata( + exec_ctx, inner_creds, ctx->pollset, ctx->auth_md_context, + composite_call_metadata_cb, ctx); + return; + } + + /* We're done!. */ + ctx->cb(exec_ctx, ctx->user_data, ctx->md_elems->entries, + ctx->md_elems->num_entries, GRPC_CREDENTIALS_OK); + composite_call_md_context_destroy(ctx); +} + +static void composite_call_get_request_metadata( + grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, + grpc_pollset *pollset, grpc_auth_metadata_context auth_md_context, + grpc_credentials_metadata_cb cb, void *user_data) { + grpc_composite_call_credentials *c = (grpc_composite_call_credentials *)creds; + grpc_composite_call_credentials_metadata_context *ctx; + + ctx = gpr_malloc(sizeof(grpc_composite_call_credentials_metadata_context)); + memset(ctx, 0, sizeof(grpc_composite_call_credentials_metadata_context)); + ctx->auth_md_context = auth_md_context; + ctx->user_data = user_data; + ctx->cb = cb; + ctx->composite_creds = c; + ctx->pollset = pollset; + ctx->md_elems = grpc_credentials_md_store_create(c->inner.num_creds); + grpc_call_credentials_get_request_metadata( + exec_ctx, c->inner.creds_array[ctx->creds_index++], pollset, + auth_md_context, composite_call_metadata_cb, ctx); +} + +static grpc_call_credentials_vtable composite_call_credentials_vtable = { + composite_call_destruct, composite_call_get_request_metadata}; + +static grpc_call_credentials_array get_creds_array( + grpc_call_credentials **creds_addr) { + grpc_call_credentials_array result; + grpc_call_credentials *creds = *creds_addr; + result.creds_array = creds_addr; + result.num_creds = 1; + if (strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0) { + result = *grpc_composite_call_credentials_get_credentials(creds); + } + return result; +} + +grpc_call_credentials *grpc_composite_call_credentials_create( + grpc_call_credentials *creds1, grpc_call_credentials *creds2, + void *reserved) { + size_t i; + size_t creds_array_byte_size; + grpc_call_credentials_array creds1_array; + grpc_call_credentials_array creds2_array; + grpc_composite_call_credentials *c; + GRPC_API_TRACE( + "grpc_composite_call_credentials_create(creds1=%p, creds2=%p, " + "reserved=%p)", + 3, (creds1, creds2, reserved)); + GPR_ASSERT(reserved == NULL); + GPR_ASSERT(creds1 != NULL); + GPR_ASSERT(creds2 != NULL); + c = gpr_malloc(sizeof(grpc_composite_call_credentials)); + memset(c, 0, sizeof(grpc_composite_call_credentials)); + c->base.type = GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE; + c->base.vtable = &composite_call_credentials_vtable; + gpr_ref_init(&c->base.refcount, 1); + creds1_array = get_creds_array(&creds1); + creds2_array = get_creds_array(&creds2); + c->inner.num_creds = creds1_array.num_creds + creds2_array.num_creds; + creds_array_byte_size = c->inner.num_creds * sizeof(grpc_call_credentials *); + c->inner.creds_array = gpr_malloc(creds_array_byte_size); + memset(c->inner.creds_array, 0, creds_array_byte_size); + for (i = 0; i < creds1_array.num_creds; i++) { + grpc_call_credentials *cur_creds = creds1_array.creds_array[i]; + c->inner.creds_array[i] = grpc_call_credentials_ref(cur_creds); + } + for (i = 0; i < creds2_array.num_creds; i++) { + grpc_call_credentials *cur_creds = creds2_array.creds_array[i]; + c->inner.creds_array[i + creds1_array.num_creds] = + grpc_call_credentials_ref(cur_creds); + } + return &c->base; +} + +const grpc_call_credentials_array * +grpc_composite_call_credentials_get_credentials(grpc_call_credentials *creds) { + const grpc_composite_call_credentials *c = + (const grpc_composite_call_credentials *)creds; + GPR_ASSERT(strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0); + return &c->inner; +} + +grpc_call_credentials *grpc_credentials_contains_type( + grpc_call_credentials *creds, const char *type, + grpc_call_credentials **composite_creds) { + size_t i; + if (strcmp(creds->type, type) == 0) { + if (composite_creds != NULL) *composite_creds = NULL; + return creds; + } else if (strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0) { + const grpc_call_credentials_array *inner_creds_array = + grpc_composite_call_credentials_get_credentials(creds); + for (i = 0; i < inner_creds_array->num_creds; i++) { + if (strcmp(type, inner_creds_array->creds_array[i]->type) == 0) { + if (composite_creds != NULL) *composite_creds = creds; + return inner_creds_array->creds_array[i]; + } + } + } + return NULL; +} + +/* -- IAM credentials. -- */ + +static void iam_destruct(grpc_call_credentials *creds) { + grpc_google_iam_credentials *c = (grpc_google_iam_credentials *)creds; + grpc_credentials_md_store_unref(c->iam_md); +} + +static void iam_get_request_metadata(grpc_exec_ctx *exec_ctx, + grpc_call_credentials *creds, + grpc_pollset *pollset, + grpc_auth_metadata_context context, + grpc_credentials_metadata_cb cb, + void *user_data) { + grpc_google_iam_credentials *c = (grpc_google_iam_credentials *)creds; + cb(exec_ctx, user_data, c->iam_md->entries, c->iam_md->num_entries, + GRPC_CREDENTIALS_OK); +} + +static grpc_call_credentials_vtable iam_vtable = {iam_destruct, + iam_get_request_metadata}; + +grpc_call_credentials *grpc_google_iam_credentials_create( + const char *token, const char *authority_selector, void *reserved) { + grpc_google_iam_credentials *c; + GRPC_API_TRACE( + "grpc_iam_credentials_create(token=%s, authority_selector=%s, " + "reserved=%p)", + 3, (token, authority_selector, reserved)); + GPR_ASSERT(reserved == NULL); + GPR_ASSERT(token != NULL); + GPR_ASSERT(authority_selector != NULL); + c = gpr_malloc(sizeof(grpc_google_iam_credentials)); + memset(c, 0, sizeof(grpc_google_iam_credentials)); + c->base.type = GRPC_CALL_CREDENTIALS_TYPE_IAM; + c->base.vtable = &iam_vtable; + gpr_ref_init(&c->base.refcount, 1); + c->iam_md = grpc_credentials_md_store_create(2); + grpc_credentials_md_store_add_cstrings( + c->iam_md, GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY, token); + grpc_credentials_md_store_add_cstrings( + c->iam_md, GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY, authority_selector); + return &c->base; +} + +/* -- Plugin credentials. -- */ + +typedef struct { + void *user_data; + grpc_credentials_metadata_cb cb; +} grpc_metadata_plugin_request; + +static void plugin_destruct(grpc_call_credentials *creds) { + grpc_plugin_credentials *c = (grpc_plugin_credentials *)creds; + if (c->plugin.state != NULL && c->plugin.destroy != NULL) { + c->plugin.destroy(c->plugin.state); + } +} + +static void plugin_md_request_metadata_ready(void *request, + const grpc_metadata *md, + size_t num_md, + grpc_status_code status, + const char *error_details) { + /* called from application code */ + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_metadata_plugin_request *r = (grpc_metadata_plugin_request *)request; + if (status != GRPC_STATUS_OK) { + if (error_details != NULL) { + gpr_log(GPR_ERROR, "Getting metadata from plugin failed with error: %s", + error_details); + } + r->cb(&exec_ctx, r->user_data, NULL, 0, GRPC_CREDENTIALS_ERROR); + } else { + size_t i; + grpc_credentials_md *md_array = NULL; + if (num_md > 0) { + md_array = gpr_malloc(num_md * sizeof(grpc_credentials_md)); + for (i = 0; i < num_md; i++) { + md_array[i].key = gpr_slice_from_copied_string(md[i].key); + md_array[i].value = + gpr_slice_from_copied_buffer(md[i].value, md[i].value_length); + } + } + r->cb(&exec_ctx, r->user_data, md_array, num_md, GRPC_CREDENTIALS_OK); + if (md_array != NULL) { + for (i = 0; i < num_md; i++) { + gpr_slice_unref(md_array[i].key); + gpr_slice_unref(md_array[i].value); + } + gpr_free(md_array); + } + } + gpr_free(r); + grpc_exec_ctx_finish(&exec_ctx); +} + +static void plugin_get_request_metadata(grpc_exec_ctx *exec_ctx, + grpc_call_credentials *creds, + grpc_pollset *pollset, + grpc_auth_metadata_context context, + grpc_credentials_metadata_cb cb, + void *user_data) { + grpc_plugin_credentials *c = (grpc_plugin_credentials *)creds; + if (c->plugin.get_metadata != NULL) { + grpc_metadata_plugin_request *request = gpr_malloc(sizeof(*request)); + memset(request, 0, sizeof(*request)); + request->user_data = user_data; + request->cb = cb; + c->plugin.get_metadata(c->plugin.state, context, + plugin_md_request_metadata_ready, request); + } else { + cb(exec_ctx, user_data, NULL, 0, GRPC_CREDENTIALS_OK); + } +} + +static grpc_call_credentials_vtable plugin_vtable = { + plugin_destruct, plugin_get_request_metadata}; + +grpc_call_credentials *grpc_metadata_credentials_create_from_plugin( + grpc_metadata_credentials_plugin plugin, void *reserved) { + grpc_plugin_credentials *c = gpr_malloc(sizeof(*c)); + GRPC_API_TRACE("grpc_metadata_credentials_create_from_plugin(reserved=%p)", 1, + (reserved)); + GPR_ASSERT(reserved == NULL); + memset(c, 0, sizeof(*c)); + c->base.type = plugin.type; + c->base.vtable = &plugin_vtable; + gpr_ref_init(&c->base.refcount, 1); + c->plugin = plugin; + return &c->base; +} + +/* -- Composite channel credentials. -- */ + +static void composite_channel_destruct(grpc_channel_credentials *creds) { + grpc_composite_channel_credentials *c = + (grpc_composite_channel_credentials *)creds; + grpc_channel_credentials_unref(c->inner_creds); + grpc_call_credentials_unref(c->call_creds); +} + +static grpc_security_status composite_channel_create_security_connector( + grpc_channel_credentials *creds, grpc_call_credentials *call_creds, + const char *target, const grpc_channel_args *args, + grpc_channel_security_connector **sc, grpc_channel_args **new_args) { + grpc_composite_channel_credentials *c = + (grpc_composite_channel_credentials *)creds; + grpc_security_status status = GRPC_SECURITY_ERROR; + + GPR_ASSERT(c->inner_creds != NULL && c->call_creds != NULL && + c->inner_creds->vtable != NULL && + c->inner_creds->vtable->create_security_connector != NULL); + /* If we are passed a call_creds, create a call composite to pass it + downstream. */ + if (call_creds != NULL) { + grpc_call_credentials *composite_call_creds = + grpc_composite_call_credentials_create(c->call_creds, call_creds, NULL); + status = c->inner_creds->vtable->create_security_connector( + c->inner_creds, composite_call_creds, target, args, sc, new_args); + grpc_call_credentials_unref(composite_call_creds); + } else { + status = c->inner_creds->vtable->create_security_connector( + c->inner_creds, c->call_creds, target, args, sc, new_args); + } + return status; +} + +static grpc_channel_credentials_vtable composite_channel_credentials_vtable = { + composite_channel_destruct, composite_channel_create_security_connector}; + +grpc_channel_credentials *grpc_composite_channel_credentials_create( + grpc_channel_credentials *channel_creds, grpc_call_credentials *call_creds, + void *reserved) { + grpc_composite_channel_credentials *c = gpr_malloc(sizeof(*c)); + memset(c, 0, sizeof(*c)); + GPR_ASSERT(channel_creds != NULL && call_creds != NULL && reserved == NULL); + GRPC_API_TRACE( + "grpc_composite_channel_credentials_create(channel_creds=%p, " + "call_creds=%p, reserved=%p)", + 3, (channel_creds, call_creds, reserved)); + c->base.type = channel_creds->type; + c->base.vtable = &composite_channel_credentials_vtable; + gpr_ref_init(&c->base.refcount, 1); + c->inner_creds = grpc_channel_credentials_ref(channel_creds); + c->call_creds = grpc_call_credentials_ref(call_creds); + return &c->base; +} diff --git a/src/core/lib/security/credentials.h b/src/core/lib/security/credentials.h new file mode 100644 index 0000000000..bfa7cc71bd --- /dev/null +++ b/src/core/lib/security/credentials.h @@ -0,0 +1,377 @@ +/* + * + * Copyright 2015-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_SECURITY_CREDENTIALS_H +#define GRPC_CORE_SECURITY_CREDENTIALS_H + +#include +#include +#include +#include "src/core/transport/metadata_batch.h" + +#include "src/core/http/httpcli.h" +#include "src/core/http/parser.h" +#include "src/core/security/json_token.h" +#include "src/core/security/security_connector.h" + +struct grpc_http_response; + +/* --- Constants. --- */ + +typedef enum { + GRPC_CREDENTIALS_OK = 0, + GRPC_CREDENTIALS_ERROR +} grpc_credentials_status; + +#define GRPC_FAKE_TRANSPORT_SECURITY_TYPE "fake" + +#define GRPC_CHANNEL_CREDENTIALS_TYPE_SSL "Ssl" +#define GRPC_CHANNEL_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY \ + "FakeTransportSecurity" + +#define GRPC_CALL_CREDENTIALS_TYPE_OAUTH2 "Oauth2" +#define GRPC_CALL_CREDENTIALS_TYPE_JWT "Jwt" +#define GRPC_CALL_CREDENTIALS_TYPE_IAM "Iam" +#define GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE "Composite" + +#define GRPC_AUTHORIZATION_METADATA_KEY "authorization" +#define GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY \ + "x-goog-iam-authorization-token" +#define GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY "x-goog-iam-authority-selector" + +#define GRPC_GOOGLE_CLOUD_SDK_CONFIG_DIRECTORY "gcloud" +#define GRPC_GOOGLE_WELL_KNOWN_CREDENTIALS_FILE \ + "application_default_credentials.json" + +#define GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS 60 + +#define GRPC_COMPUTE_ENGINE_METADATA_HOST "metadata" +#define GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH \ + "/computeMetadata/v1/instance/service-accounts/default/token" + +#define GRPC_GOOGLE_OAUTH2_SERVICE_HOST "www.googleapis.com" +#define GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH "/oauth2/v3/token" + +#define GRPC_SERVICE_ACCOUNT_POST_BODY_PREFIX \ + "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&" \ + "assertion=" + +#define GRPC_REFRESH_TOKEN_POST_BODY_FORMAT_STRING \ + "client_id=%s&client_secret=%s&refresh_token=%s&grant_type=refresh_token" + +/* --- Google utils --- */ + +/* It is the caller's responsibility to gpr_free the result if not NULL. */ +char *grpc_get_well_known_google_credentials_file_path(void); + +/* Implementation function for the different platforms. */ +char *grpc_get_well_known_google_credentials_file_path_impl(void); + +/* Override for testing only. Not thread-safe */ +typedef char *(*grpc_well_known_credentials_path_getter)(void); +void grpc_override_well_known_credentials_path_getter( + grpc_well_known_credentials_path_getter getter); + +/* --- grpc_channel_credentials. --- */ + +typedef struct { + void (*destruct)(grpc_channel_credentials *c); + + grpc_security_status (*create_security_connector)( + grpc_channel_credentials *c, grpc_call_credentials *call_creds, + const char *target, const grpc_channel_args *args, + grpc_channel_security_connector **sc, grpc_channel_args **new_args); +} grpc_channel_credentials_vtable; + +struct grpc_channel_credentials { + const grpc_channel_credentials_vtable *vtable; + const char *type; + gpr_refcount refcount; +}; + +grpc_channel_credentials *grpc_channel_credentials_ref( + grpc_channel_credentials *creds); +void grpc_channel_credentials_unref(grpc_channel_credentials *creds); + +/* Creates a security connector for the channel. May also create new channel + args for the channel to be used in place of the passed in const args if + returned non NULL. In that case the caller is responsible for destroying + new_args after channel creation. */ +grpc_security_status grpc_channel_credentials_create_security_connector( + grpc_channel_credentials *creds, const char *target, + const grpc_channel_args *args, grpc_channel_security_connector **sc, + grpc_channel_args **new_args); + +/* --- grpc_credentials_md. --- */ + +typedef struct { + gpr_slice key; + gpr_slice value; +} grpc_credentials_md; + +typedef struct { + grpc_credentials_md *entries; + size_t num_entries; + size_t allocated; + gpr_refcount refcount; +} grpc_credentials_md_store; + +grpc_credentials_md_store *grpc_credentials_md_store_create( + size_t initial_capacity); + +/* Will ref key and value. */ +void grpc_credentials_md_store_add(grpc_credentials_md_store *store, + gpr_slice key, gpr_slice value); +void grpc_credentials_md_store_add_cstrings(grpc_credentials_md_store *store, + const char *key, const char *value); +grpc_credentials_md_store *grpc_credentials_md_store_ref( + grpc_credentials_md_store *store); +void grpc_credentials_md_store_unref(grpc_credentials_md_store *store); + +/* --- grpc_call_credentials. --- */ + +typedef void (*grpc_credentials_metadata_cb)(grpc_exec_ctx *exec_ctx, + void *user_data, + grpc_credentials_md *md_elems, + size_t num_md, + grpc_credentials_status status); + +typedef struct { + void (*destruct)(grpc_call_credentials *c); + void (*get_request_metadata)(grpc_exec_ctx *exec_ctx, + grpc_call_credentials *c, grpc_pollset *pollset, + grpc_auth_metadata_context context, + grpc_credentials_metadata_cb cb, + void *user_data); +} grpc_call_credentials_vtable; + +struct grpc_call_credentials { + const grpc_call_credentials_vtable *vtable; + const char *type; + gpr_refcount refcount; +}; + +grpc_call_credentials *grpc_call_credentials_ref(grpc_call_credentials *creds); +void grpc_call_credentials_unref(grpc_call_credentials *creds); +void grpc_call_credentials_get_request_metadata( + grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, + grpc_pollset *pollset, grpc_auth_metadata_context context, + grpc_credentials_metadata_cb cb, void *user_data); + +typedef struct { + grpc_call_credentials **creds_array; + size_t num_creds; +} grpc_call_credentials_array; + +const grpc_call_credentials_array * +grpc_composite_call_credentials_get_credentials( + grpc_call_credentials *composite_creds); + +/* Returns creds if creds is of the specified type or the inner creds of the + specified type (if found), if the creds is of type COMPOSITE. + If composite_creds is not NULL, *composite_creds will point to creds if of + type COMPOSITE in case of success. */ +grpc_call_credentials *grpc_credentials_contains_type( + grpc_call_credentials *creds, const char *type, + grpc_call_credentials **composite_creds); + +/* Exposed for testing only. */ +grpc_credentials_status +grpc_oauth2_token_fetcher_credentials_parse_server_response( + const struct grpc_http_response *response, + grpc_credentials_md_store **token_md, gpr_timespec *token_lifetime); + +void grpc_flush_cached_google_default_credentials(void); + +/* Metadata-only credentials with the specified key and value where + asynchronicity can be simulated for testing. */ +grpc_call_credentials *grpc_md_only_test_credentials_create( + const char *md_key, const char *md_value, int is_async); + +/* Private constructor for jwt credentials from an already parsed json key. + Takes ownership of the key. */ +grpc_call_credentials * +grpc_service_account_jwt_access_credentials_create_from_auth_json_key( + grpc_auth_json_key key, gpr_timespec token_lifetime); + +/* Private constructor for refresh token credentials from an already parsed + refresh token. Takes ownership of the refresh token. */ +grpc_call_credentials * +grpc_refresh_token_credentials_create_from_auth_refresh_token( + grpc_auth_refresh_token token); + +/* --- grpc_server_credentials. --- */ + +typedef struct { + void (*destruct)(grpc_server_credentials *c); + grpc_security_status (*create_security_connector)( + grpc_server_credentials *c, grpc_server_security_connector **sc); +} grpc_server_credentials_vtable; + +struct grpc_server_credentials { + const grpc_server_credentials_vtable *vtable; + const char *type; + gpr_refcount refcount; + grpc_auth_metadata_processor processor; +}; + +grpc_security_status grpc_server_credentials_create_security_connector( + grpc_server_credentials *creds, grpc_server_security_connector **sc); + +grpc_server_credentials *grpc_server_credentials_ref( + grpc_server_credentials *creds); + +void grpc_server_credentials_unref(grpc_server_credentials *creds); + +#define GRPC_SERVER_CREDENTIALS_ARG "grpc.server_credentials" + +grpc_arg grpc_server_credentials_to_arg(grpc_server_credentials *c); +grpc_server_credentials *grpc_server_credentials_from_arg(const grpc_arg *arg); +grpc_server_credentials *grpc_find_server_credentials_in_args( + const grpc_channel_args *args); + +/* -- Fake transport security credentials. -- */ + +/* Creates a fake transport security credentials object for testing. */ +grpc_channel_credentials *grpc_fake_transport_security_credentials_create(void); +/* Creates a fake server transport security credentials object for testing. */ +grpc_server_credentials *grpc_fake_transport_security_server_credentials_create( + void); + +/* -- Ssl credentials. -- */ + +typedef struct { + grpc_channel_credentials base; + grpc_ssl_config config; +} grpc_ssl_credentials; + +typedef struct { + grpc_server_credentials base; + grpc_ssl_server_config config; +} grpc_ssl_server_credentials; + +/* -- Channel composite credentials. -- */ + +typedef struct { + grpc_channel_credentials base; + grpc_channel_credentials *inner_creds; + grpc_call_credentials *call_creds; +} grpc_composite_channel_credentials; + +/* -- Jwt credentials -- */ + +typedef struct { + grpc_call_credentials base; + + /* Have a simple cache for now with just 1 entry. We could have a map based on + the service_url for a more sophisticated one. */ + gpr_mu cache_mu; + struct { + grpc_credentials_md_store *jwt_md; + char *service_url; + gpr_timespec jwt_expiration; + } cached; + + grpc_auth_json_key key; + gpr_timespec jwt_lifetime; +} grpc_service_account_jwt_access_credentials; + +/* -- Oauth2TokenFetcher credentials -- + + This object is a base for credentials that need to acquire an oauth2 token + from an http service. */ + +typedef struct grpc_credentials_metadata_request + grpc_credentials_metadata_request; + +typedef void (*grpc_fetch_oauth2_func)(grpc_exec_ctx *exec_ctx, + grpc_credentials_metadata_request *req, + grpc_httpcli_context *http_context, + grpc_pollset *pollset, + grpc_httpcli_response_cb response_cb, + gpr_timespec deadline); + +typedef struct { + grpc_call_credentials base; + gpr_mu mu; + grpc_credentials_md_store *access_token_md; + gpr_timespec token_expiration; + grpc_httpcli_context httpcli_context; + grpc_fetch_oauth2_func fetch_func; +} grpc_oauth2_token_fetcher_credentials; + +/* -- GoogleRefreshToken credentials. -- */ + +typedef struct { + grpc_oauth2_token_fetcher_credentials base; + grpc_auth_refresh_token refresh_token; +} grpc_google_refresh_token_credentials; + +/* -- Oauth2 Access Token credentials. -- */ + +typedef struct { + grpc_call_credentials base; + grpc_credentials_md_store *access_token_md; +} grpc_access_token_credentials; + +/* -- Metadata-only Test credentials. -- */ + +typedef struct { + grpc_call_credentials base; + grpc_credentials_md_store *md_store; + int is_async; +} grpc_md_only_test_credentials; + +/* -- GoogleIAM credentials. -- */ + +typedef struct { + grpc_call_credentials base; + grpc_credentials_md_store *iam_md; +} grpc_google_iam_credentials; + +/* -- Composite credentials. -- */ + +typedef struct { + grpc_call_credentials base; + grpc_call_credentials_array inner; +} grpc_composite_call_credentials; + +/* -- Plugin credentials. -- */ + +typedef struct { + grpc_call_credentials base; + grpc_metadata_credentials_plugin plugin; + grpc_credentials_md_store *plugin_md; +} grpc_plugin_credentials; + +#endif /* GRPC_CORE_SECURITY_CREDENTIALS_H */ diff --git a/src/core/lib/security/credentials_metadata.c b/src/core/lib/security/credentials_metadata.c new file mode 100644 index 0000000000..b8a132f1ea --- /dev/null +++ b/src/core/lib/security/credentials_metadata.c @@ -0,0 +1,101 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/security/credentials.h" + +#include + +#include + +static void store_ensure_capacity(grpc_credentials_md_store *store) { + if (store->num_entries == store->allocated) { + store->allocated = (store->allocated == 0) ? 1 : store->allocated * 2; + store->entries = gpr_realloc( + store->entries, store->allocated * sizeof(grpc_credentials_md)); + } +} + +grpc_credentials_md_store *grpc_credentials_md_store_create( + size_t initial_capacity) { + grpc_credentials_md_store *store = + gpr_malloc(sizeof(grpc_credentials_md_store)); + memset(store, 0, sizeof(grpc_credentials_md_store)); + if (initial_capacity > 0) { + store->entries = gpr_malloc(initial_capacity * sizeof(grpc_credentials_md)); + store->allocated = initial_capacity; + } + gpr_ref_init(&store->refcount, 1); + return store; +} + +void grpc_credentials_md_store_add(grpc_credentials_md_store *store, + gpr_slice key, gpr_slice value) { + if (store == NULL) return; + store_ensure_capacity(store); + store->entries[store->num_entries].key = gpr_slice_ref(key); + store->entries[store->num_entries].value = gpr_slice_ref(value); + store->num_entries++; +} + +void grpc_credentials_md_store_add_cstrings(grpc_credentials_md_store *store, + const char *key, + const char *value) { + if (store == NULL) return; + store_ensure_capacity(store); + store->entries[store->num_entries].key = gpr_slice_from_copied_string(key); + store->entries[store->num_entries].value = + gpr_slice_from_copied_string(value); + store->num_entries++; +} + +grpc_credentials_md_store *grpc_credentials_md_store_ref( + grpc_credentials_md_store *store) { + if (store == NULL) return NULL; + gpr_ref(&store->refcount); + return store; +} + +void grpc_credentials_md_store_unref(grpc_credentials_md_store *store) { + if (store == NULL) return; + if (gpr_unref(&store->refcount)) { + if (store->entries != NULL) { + size_t i; + for (i = 0; i < store->num_entries; i++) { + gpr_slice_unref(store->entries[i].key); + gpr_slice_unref(store->entries[i].value); + } + gpr_free(store->entries); + } + gpr_free(store); + } +} diff --git a/src/core/lib/security/credentials_posix.c b/src/core/lib/security/credentials_posix.c new file mode 100644 index 0000000000..0c92bd4a96 --- /dev/null +++ b/src/core/lib/security/credentials_posix.c @@ -0,0 +1,61 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +#ifdef GPR_POSIX_FILE + +#include "src/core/security/credentials.h" + +#include +#include +#include + +#include "src/core/support/env.h" +#include "src/core/support/string.h" + +char *grpc_get_well_known_google_credentials_file_path_impl(void) { + char *result = NULL; + char *home = gpr_getenv("HOME"); + if (home == NULL) { + gpr_log(GPR_ERROR, "Could not get HOME environment variable."); + return NULL; + } + gpr_asprintf(&result, "%s/.config/%s/%s", home, + GRPC_GOOGLE_CLOUD_SDK_CONFIG_DIRECTORY, + GRPC_GOOGLE_WELL_KNOWN_CREDENTIALS_FILE); + gpr_free(home); + return result; +} + +#endif /* GPR_POSIX_FILE */ diff --git a/src/core/lib/security/credentials_win32.c b/src/core/lib/security/credentials_win32.c new file mode 100644 index 0000000000..8ee9f706a1 --- /dev/null +++ b/src/core/lib/security/credentials_win32.c @@ -0,0 +1,61 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +#ifdef GPR_WIN32 + +#include "src/core/security/credentials.h" + +#include +#include +#include + +#include "src/core/support/env.h" +#include "src/core/support/string.h" + +char *grpc_get_well_known_google_credentials_file_path_impl(void) { + char *result = NULL; + char *appdata_path = gpr_getenv("APPDATA"); + if (appdata_path == NULL) { + gpr_log(GPR_ERROR, "Could not get APPDATA environment variable."); + return NULL; + } + gpr_asprintf(&result, "%s/%s/%s", appdata_path, + GRPC_GOOGLE_CLOUD_SDK_CONFIG_DIRECTORY, + GRPC_GOOGLE_WELL_KNOWN_CREDENTIALS_FILE); + gpr_free(appdata_path); + return result; +} + +#endif /* GPR_WIN32 */ diff --git a/src/core/lib/security/google_default_credentials.c b/src/core/lib/security/google_default_credentials.c new file mode 100644 index 0000000000..3872e86993 --- /dev/null +++ b/src/core/lib/security/google_default_credentials.c @@ -0,0 +1,266 @@ +/* + * + * Copyright 2015-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/security/credentials.h" + +#include + +#include +#include +#include + +#include "src/core/http/httpcli.h" +#include "src/core/http/parser.h" +#include "src/core/support/env.h" +#include "src/core/support/load_file.h" +#include "src/core/surface/api_trace.h" + +/* -- Constants. -- */ + +#define GRPC_COMPUTE_ENGINE_DETECTION_HOST "metadata.google.internal" + +/* -- Default credentials. -- */ + +static grpc_channel_credentials *default_credentials = NULL; +static int compute_engine_detection_done = 0; +static gpr_mu g_state_mu; +static gpr_mu *g_polling_mu; +static gpr_once g_once = GPR_ONCE_INIT; + +static void init_default_credentials(void) { gpr_mu_init(&g_state_mu); } + +typedef struct { + grpc_pollset *pollset; + int is_done; + int success; +} compute_engine_detector; + +static void on_compute_engine_detection_http_response( + grpc_exec_ctx *exec_ctx, void *user_data, + const grpc_http_response *response) { + compute_engine_detector *detector = (compute_engine_detector *)user_data; + if (response != NULL && response->status == 200 && response->hdr_count > 0) { + /* Internet providers can return a generic response to all requests, so + it is necessary to check that metadata header is present also. */ + size_t i; + for (i = 0; i < response->hdr_count; i++) { + grpc_http_header *header = &response->hdrs[i]; + if (strcmp(header->key, "Metadata-Flavor") == 0 && + strcmp(header->value, "Google") == 0) { + detector->success = 1; + break; + } + } + } + gpr_mu_lock(g_polling_mu); + detector->is_done = 1; + grpc_pollset_kick(detector->pollset, NULL); + gpr_mu_unlock(g_polling_mu); +} + +static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p, bool s) { + grpc_pollset_destroy(p); +} + +static int is_stack_running_on_compute_engine(void) { + compute_engine_detector detector; + grpc_httpcli_request request; + grpc_httpcli_context context; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_closure destroy_closure; + + /* The http call is local. If it takes more than one sec, it is for sure not + on compute engine. */ + gpr_timespec max_detection_delay = gpr_time_from_seconds(1, GPR_TIMESPAN); + + detector.pollset = gpr_malloc(grpc_pollset_size()); + grpc_pollset_init(detector.pollset, &g_polling_mu); + detector.is_done = 0; + detector.success = 0; + + memset(&request, 0, sizeof(grpc_httpcli_request)); + request.host = GRPC_COMPUTE_ENGINE_DETECTION_HOST; + request.http.path = "/"; + + grpc_httpcli_context_init(&context); + + grpc_httpcli_get( + &exec_ctx, &context, detector.pollset, &request, + gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), max_detection_delay), + on_compute_engine_detection_http_response, &detector); + + grpc_exec_ctx_finish(&exec_ctx); + + /* Block until we get the response. This is not ideal but this should only be + called once for the lifetime of the process by the default credentials. */ + gpr_mu_lock(g_polling_mu); + while (!detector.is_done) { + grpc_pollset_worker *worker = NULL; + grpc_pollset_work(&exec_ctx, detector.pollset, &worker, + gpr_now(GPR_CLOCK_MONOTONIC), + gpr_inf_future(GPR_CLOCK_MONOTONIC)); + } + gpr_mu_unlock(g_polling_mu); + + grpc_httpcli_context_destroy(&context); + grpc_closure_init(&destroy_closure, destroy_pollset, detector.pollset); + grpc_pollset_shutdown(&exec_ctx, detector.pollset, &destroy_closure); + grpc_exec_ctx_finish(&exec_ctx); + g_polling_mu = NULL; + + gpr_free(detector.pollset); + + return detector.success; +} + +/* Takes ownership of creds_path if not NULL. */ +static grpc_call_credentials *create_default_creds_from_path(char *creds_path) { + grpc_json *json = NULL; + grpc_auth_json_key key; + grpc_auth_refresh_token token; + grpc_call_credentials *result = NULL; + gpr_slice creds_data = gpr_empty_slice(); + int file_ok = 0; + if (creds_path == NULL) goto end; + creds_data = gpr_load_file(creds_path, 0, &file_ok); + if (!file_ok) goto end; + json = grpc_json_parse_string_with_len( + (char *)GPR_SLICE_START_PTR(creds_data), GPR_SLICE_LENGTH(creds_data)); + if (json == NULL) goto end; + + /* First, try an auth json key. */ + key = grpc_auth_json_key_create_from_json(json); + if (grpc_auth_json_key_is_valid(&key)) { + result = + grpc_service_account_jwt_access_credentials_create_from_auth_json_key( + key, grpc_max_auth_token_lifetime()); + goto end; + } + + /* Then try a refresh token if the auth json key was invalid. */ + token = grpc_auth_refresh_token_create_from_json(json); + if (grpc_auth_refresh_token_is_valid(&token)) { + result = + grpc_refresh_token_credentials_create_from_auth_refresh_token(token); + goto end; + } + +end: + if (creds_path != NULL) gpr_free(creds_path); + gpr_slice_unref(creds_data); + if (json != NULL) grpc_json_destroy(json); + return result; +} + +grpc_channel_credentials *grpc_google_default_credentials_create(void) { + grpc_channel_credentials *result = NULL; + grpc_call_credentials *call_creds = NULL; + + GRPC_API_TRACE("grpc_google_default_credentials_create(void)", 0, ()); + + gpr_once_init(&g_once, init_default_credentials); + + gpr_mu_lock(&g_state_mu); + + if (default_credentials != NULL) { + result = grpc_channel_credentials_ref(default_credentials); + goto end; + } + + /* First, try the environment variable. */ + call_creds = create_default_creds_from_path( + gpr_getenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR)); + if (call_creds != NULL) goto end; + + /* Then the well-known file. */ + call_creds = create_default_creds_from_path( + grpc_get_well_known_google_credentials_file_path()); + if (call_creds != NULL) goto end; + + /* At last try to see if we're on compute engine (do the detection only once + since it requires a network test). */ + if (!compute_engine_detection_done) { + int need_compute_engine_creds = is_stack_running_on_compute_engine(); + compute_engine_detection_done = 1; + if (need_compute_engine_creds) { + call_creds = grpc_google_compute_engine_credentials_create(NULL); + } + } + +end: + if (result == NULL) { + if (call_creds != NULL) { + /* Blend with default ssl credentials and add a global reference so that + it + can be cached and re-served. */ + grpc_channel_credentials *ssl_creds = + grpc_ssl_credentials_create(NULL, NULL, NULL); + default_credentials = grpc_channel_credentials_ref( + grpc_composite_channel_credentials_create(ssl_creds, call_creds, + NULL)); + GPR_ASSERT(default_credentials != NULL); + grpc_channel_credentials_unref(ssl_creds); + grpc_call_credentials_unref(call_creds); + result = default_credentials; + } else { + gpr_log(GPR_ERROR, "Could not create google default credentials."); + } + } + gpr_mu_unlock(&g_state_mu); + return result; +} + +void grpc_flush_cached_google_default_credentials(void) { + gpr_once_init(&g_once, init_default_credentials); + gpr_mu_lock(&g_state_mu); + if (default_credentials != NULL) { + grpc_channel_credentials_unref(default_credentials); + default_credentials = NULL; + } + compute_engine_detection_done = 0; + gpr_mu_unlock(&g_state_mu); +} + +/* -- Well known credentials path. -- */ + +static grpc_well_known_credentials_path_getter creds_path_getter = NULL; + +char *grpc_get_well_known_google_credentials_file_path(void) { + if (creds_path_getter != NULL) return creds_path_getter(); + return grpc_get_well_known_google_credentials_file_path_impl(); +} + +void grpc_override_well_known_credentials_path_getter( + grpc_well_known_credentials_path_getter getter) { + creds_path_getter = getter; +} diff --git a/src/core/lib/security/handshake.c b/src/core/lib/security/handshake.c new file mode 100644 index 0000000000..9fb10a0ecb --- /dev/null +++ b/src/core/lib/security/handshake.c @@ -0,0 +1,336 @@ +/* + * + * Copyright 2015-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/security/handshake.h" + +#include +#include + +#include +#include +#include +#include "src/core/security/secure_endpoint.h" +#include "src/core/security/security_context.h" + +#define GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE 256 + +typedef struct { + grpc_security_connector *connector; + tsi_handshaker *handshaker; + bool is_client_side; + unsigned char *handshake_buffer; + size_t handshake_buffer_size; + grpc_endpoint *wrapped_endpoint; + grpc_endpoint *secure_endpoint; + gpr_slice_buffer left_overs; + gpr_slice_buffer incoming; + gpr_slice_buffer outgoing; + grpc_security_handshake_done_cb cb; + void *user_data; + grpc_closure on_handshake_data_sent_to_peer; + grpc_closure on_handshake_data_received_from_peer; + grpc_auth_context *auth_context; +} grpc_security_handshake; + +static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx, + void *setup, bool success); + +static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx, void *setup, + bool success); + +static void security_connector_remove_handshake(grpc_security_handshake *h) { + GPR_ASSERT(!h->is_client_side); + grpc_security_connector_handshake_list *node; + grpc_security_connector_handshake_list *tmp; + grpc_server_security_connector *sc = + (grpc_server_security_connector *)h->connector; + gpr_mu_lock(&sc->mu); + node = sc->handshaking_handshakes; + if (node && node->handshake == h) { + sc->handshaking_handshakes = node->next; + gpr_free(node); + gpr_mu_unlock(&sc->mu); + return; + } + while (node) { + if (node->next->handshake == h) { + tmp = node->next; + node->next = node->next->next; + gpr_free(tmp); + gpr_mu_unlock(&sc->mu); + return; + } + node = node->next; + } + gpr_mu_unlock(&sc->mu); +} + +static void security_handshake_done(grpc_exec_ctx *exec_ctx, + grpc_security_handshake *h, + int is_success) { + if (!h->is_client_side) { + security_connector_remove_handshake(h); + } + if (is_success) { + h->cb(exec_ctx, h->user_data, GRPC_SECURITY_OK, h->secure_endpoint, + h->auth_context); + } else { + if (h->secure_endpoint != NULL) { + grpc_endpoint_shutdown(exec_ctx, h->secure_endpoint); + grpc_endpoint_destroy(exec_ctx, h->secure_endpoint); + } else { + grpc_endpoint_destroy(exec_ctx, h->wrapped_endpoint); + } + h->cb(exec_ctx, h->user_data, GRPC_SECURITY_ERROR, NULL, NULL); + } + if (h->handshaker != NULL) tsi_handshaker_destroy(h->handshaker); + if (h->handshake_buffer != NULL) gpr_free(h->handshake_buffer); + gpr_slice_buffer_destroy(&h->left_overs); + gpr_slice_buffer_destroy(&h->outgoing); + gpr_slice_buffer_destroy(&h->incoming); + GRPC_AUTH_CONTEXT_UNREF(h->auth_context, "handshake"); + GRPC_SECURITY_CONNECTOR_UNREF(h->connector, "handshake"); + gpr_free(h); +} + +static void on_peer_checked(grpc_exec_ctx *exec_ctx, void *user_data, + grpc_security_status status, + grpc_auth_context *auth_context) { + grpc_security_handshake *h = user_data; + tsi_frame_protector *protector; + tsi_result result; + if (status != GRPC_SECURITY_OK) { + gpr_log(GPR_ERROR, "Error checking peer."); + security_handshake_done(exec_ctx, h, 0); + return; + } + h->auth_context = GRPC_AUTH_CONTEXT_REF(auth_context, "handshake"); + result = + tsi_handshaker_create_frame_protector(h->handshaker, NULL, &protector); + if (result != TSI_OK) { + gpr_log(GPR_ERROR, "Frame protector creation failed with error %s.", + tsi_result_to_string(result)); + security_handshake_done(exec_ctx, h, 0); + return; + } + h->secure_endpoint = + grpc_secure_endpoint_create(protector, h->wrapped_endpoint, + h->left_overs.slices, h->left_overs.count); + h->left_overs.count = 0; + h->left_overs.length = 0; + security_handshake_done(exec_ctx, h, 1); + return; +} + +static void check_peer(grpc_exec_ctx *exec_ctx, grpc_security_handshake *h) { + tsi_peer peer; + tsi_result result = tsi_handshaker_extract_peer(h->handshaker, &peer); + + if (result != TSI_OK) { + gpr_log(GPR_ERROR, "Peer extraction failed with error %s", + tsi_result_to_string(result)); + security_handshake_done(exec_ctx, h, 0); + return; + } + grpc_security_connector_check_peer(exec_ctx, h->connector, peer, + on_peer_checked, h); +} + +static void send_handshake_bytes_to_peer(grpc_exec_ctx *exec_ctx, + grpc_security_handshake *h) { + size_t offset = 0; + tsi_result result = TSI_OK; + gpr_slice to_send; + + do { + size_t to_send_size = h->handshake_buffer_size - offset; + result = tsi_handshaker_get_bytes_to_send_to_peer( + h->handshaker, h->handshake_buffer + offset, &to_send_size); + offset += to_send_size; + if (result == TSI_INCOMPLETE_DATA) { + h->handshake_buffer_size *= 2; + h->handshake_buffer = + gpr_realloc(h->handshake_buffer, h->handshake_buffer_size); + } + } while (result == TSI_INCOMPLETE_DATA); + + if (result != TSI_OK) { + gpr_log(GPR_ERROR, "Handshake failed with error %s", + tsi_result_to_string(result)); + security_handshake_done(exec_ctx, h, 0); + return; + } + + to_send = + gpr_slice_from_copied_buffer((const char *)h->handshake_buffer, offset); + gpr_slice_buffer_reset_and_unref(&h->outgoing); + gpr_slice_buffer_add(&h->outgoing, to_send); + /* TODO(klempner,jboeuf): This should probably use the client setup + deadline */ + grpc_endpoint_write(exec_ctx, h->wrapped_endpoint, &h->outgoing, + &h->on_handshake_data_sent_to_peer); +} + +static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx, + void *handshake, + bool success) { + grpc_security_handshake *h = handshake; + size_t consumed_slice_size = 0; + tsi_result result = TSI_OK; + size_t i; + size_t num_left_overs; + int has_left_overs_in_current_slice = 0; + + if (!success) { + gpr_log(GPR_ERROR, "Read failed."); + security_handshake_done(exec_ctx, h, 0); + return; + } + + for (i = 0; i < h->incoming.count; i++) { + consumed_slice_size = GPR_SLICE_LENGTH(h->incoming.slices[i]); + result = tsi_handshaker_process_bytes_from_peer( + h->handshaker, GPR_SLICE_START_PTR(h->incoming.slices[i]), + &consumed_slice_size); + if (!tsi_handshaker_is_in_progress(h->handshaker)) break; + } + + if (tsi_handshaker_is_in_progress(h->handshaker)) { + /* We may need more data. */ + if (result == TSI_INCOMPLETE_DATA) { + grpc_endpoint_read(exec_ctx, h->wrapped_endpoint, &h->incoming, + &h->on_handshake_data_received_from_peer); + return; + } else { + send_handshake_bytes_to_peer(exec_ctx, h); + return; + } + } + + if (result != TSI_OK) { + gpr_log(GPR_ERROR, "Handshake failed with error %s", + tsi_result_to_string(result)); + security_handshake_done(exec_ctx, h, 0); + return; + } + + /* Handshake is done and successful this point. */ + has_left_overs_in_current_slice = + (consumed_slice_size < GPR_SLICE_LENGTH(h->incoming.slices[i])); + num_left_overs = + (has_left_overs_in_current_slice ? 1 : 0) + h->incoming.count - i - 1; + if (num_left_overs == 0) { + check_peer(exec_ctx, h); + return; + } + + /* Put the leftovers in our buffer (ownership transfered). */ + if (has_left_overs_in_current_slice) { + gpr_slice_buffer_add( + &h->left_overs, + gpr_slice_split_tail(&h->incoming.slices[i], consumed_slice_size)); + gpr_slice_unref( + h->incoming.slices[i]); /* split_tail above increments refcount. */ + } + gpr_slice_buffer_addn( + &h->left_overs, &h->incoming.slices[i + 1], + num_left_overs - (size_t)has_left_overs_in_current_slice); + check_peer(exec_ctx, h); +} + +/* If handshake is NULL, the handshake is done. */ +static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx, + void *handshake, bool success) { + grpc_security_handshake *h = handshake; + + /* Make sure that write is OK. */ + if (!success) { + gpr_log(GPR_ERROR, "Write failed."); + if (handshake != NULL) security_handshake_done(exec_ctx, h, 0); + return; + } + + /* We may be done. */ + if (tsi_handshaker_is_in_progress(h->handshaker)) { + /* TODO(klempner,jboeuf): This should probably use the client setup + deadline */ + grpc_endpoint_read(exec_ctx, h->wrapped_endpoint, &h->incoming, + &h->on_handshake_data_received_from_peer); + } else { + check_peer(exec_ctx, h); + } +} + +void grpc_do_security_handshake(grpc_exec_ctx *exec_ctx, + tsi_handshaker *handshaker, + grpc_security_connector *connector, + bool is_client_side, + grpc_endpoint *nonsecure_endpoint, + grpc_security_handshake_done_cb cb, + void *user_data) { + grpc_security_connector_handshake_list *handshake_node; + grpc_security_handshake *h = gpr_malloc(sizeof(grpc_security_handshake)); + memset(h, 0, sizeof(grpc_security_handshake)); + h->handshaker = handshaker; + h->connector = GRPC_SECURITY_CONNECTOR_REF(connector, "handshake"); + h->is_client_side = is_client_side; + h->handshake_buffer_size = GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE; + h->handshake_buffer = gpr_malloc(h->handshake_buffer_size); + h->wrapped_endpoint = nonsecure_endpoint; + h->user_data = user_data; + h->cb = cb; + grpc_closure_init(&h->on_handshake_data_sent_to_peer, + on_handshake_data_sent_to_peer, h); + grpc_closure_init(&h->on_handshake_data_received_from_peer, + on_handshake_data_received_from_peer, h); + gpr_slice_buffer_init(&h->left_overs); + gpr_slice_buffer_init(&h->outgoing); + gpr_slice_buffer_init(&h->incoming); + if (!is_client_side) { + grpc_server_security_connector *server_connector = + (grpc_server_security_connector *)connector; + handshake_node = gpr_malloc(sizeof(grpc_security_connector_handshake_list)); + handshake_node->handshake = h; + gpr_mu_lock(&server_connector->mu); + handshake_node->next = server_connector->handshaking_handshakes; + server_connector->handshaking_handshakes = handshake_node; + gpr_mu_unlock(&server_connector->mu); + } + send_handshake_bytes_to_peer(exec_ctx, h); +} + +void grpc_security_handshake_shutdown(grpc_exec_ctx *exec_ctx, + void *handshake) { + grpc_security_handshake *h = handshake; + grpc_endpoint_shutdown(exec_ctx, h->wrapped_endpoint); +} diff --git a/src/core/lib/security/handshake.h b/src/core/lib/security/handshake.h new file mode 100644 index 0000000000..4872045874 --- /dev/null +++ b/src/core/lib/security/handshake.h @@ -0,0 +1,51 @@ +/* + * + * Copyright 2015-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_SECURITY_HANDSHAKE_H +#define GRPC_CORE_SECURITY_HANDSHAKE_H + +#include "src/core/iomgr/endpoint.h" +#include "src/core/security/security_connector.h" + +/* Calls the callback upon completion. Takes owership of handshaker. */ +void grpc_do_security_handshake(grpc_exec_ctx *exec_ctx, + tsi_handshaker *handshaker, + grpc_security_connector *connector, + bool is_client_side, + grpc_endpoint *nonsecure_endpoint, + grpc_security_handshake_done_cb cb, + void *user_data); + +void grpc_security_handshake_shutdown(grpc_exec_ctx *exec_ctx, void *handshake); + +#endif /* GRPC_CORE_SECURITY_HANDSHAKE_H */ diff --git a/src/core/lib/security/json_token.c b/src/core/lib/security/json_token.c new file mode 100644 index 0000000000..372e5bfc5a --- /dev/null +++ b/src/core/lib/security/json_token.c @@ -0,0 +1,411 @@ +/* + * + * Copyright 2015-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/security/json_token.h" + +#include + +#include +#include +#include + +#include "src/core/security/b64.h" +#include "src/core/support/string.h" + +#include +#include +#include + +/* --- Constants. --- */ + +/* 1 hour max. */ +gpr_timespec grpc_max_auth_token_lifetime() { + gpr_timespec out; + out.tv_sec = 3600; + out.tv_nsec = 0; + out.clock_type = GPR_TIMESPAN; + return out; +} + +#define GRPC_JWT_RSA_SHA256_ALGORITHM "RS256" +#define GRPC_JWT_TYPE "JWT" + +/* --- Override for testing. --- */ + +static grpc_jwt_encode_and_sign_override g_jwt_encode_and_sign_override = NULL; + +/* --- grpc_auth_json_key. --- */ + +static const char *json_get_string_property(const grpc_json *json, + const char *prop_name) { + grpc_json *child; + for (child = json->child; child != NULL; child = child->next) { + if (strcmp(child->key, prop_name) == 0) break; + } + if (child == NULL || child->type != GRPC_JSON_STRING) { + gpr_log(GPR_ERROR, "Invalid or missing %s property.", prop_name); + return NULL; + } + return child->value; +} + +static int set_json_key_string_property(const grpc_json *json, + const char *prop_name, + char **json_key_field) { + const char *prop_value = json_get_string_property(json, prop_name); + if (prop_value == NULL) return 0; + *json_key_field = gpr_strdup(prop_value); + return 1; +} + +int grpc_auth_json_key_is_valid(const grpc_auth_json_key *json_key) { + return (json_key != NULL) && + strcmp(json_key->type, GRPC_AUTH_JSON_TYPE_INVALID); +} + +grpc_auth_json_key grpc_auth_json_key_create_from_json(const grpc_json *json) { + grpc_auth_json_key result; + BIO *bio = NULL; + const char *prop_value; + int success = 0; + + memset(&result, 0, sizeof(grpc_auth_json_key)); + result.type = GRPC_AUTH_JSON_TYPE_INVALID; + if (json == NULL) { + gpr_log(GPR_ERROR, "Invalid json."); + goto end; + } + + prop_value = json_get_string_property(json, "type"); + if (prop_value == NULL || + strcmp(prop_value, GRPC_AUTH_JSON_TYPE_SERVICE_ACCOUNT)) { + goto end; + } + result.type = GRPC_AUTH_JSON_TYPE_SERVICE_ACCOUNT; + + if (!set_json_key_string_property(json, "private_key_id", + &result.private_key_id) || + !set_json_key_string_property(json, "client_id", &result.client_id) || + !set_json_key_string_property(json, "client_email", + &result.client_email)) { + goto end; + } + + prop_value = json_get_string_property(json, "private_key"); + if (prop_value == NULL) { + goto end; + } + bio = BIO_new(BIO_s_mem()); + success = BIO_puts(bio, prop_value); + if ((success < 0) || ((size_t)success != strlen(prop_value))) { + gpr_log(GPR_ERROR, "Could not write into openssl BIO."); + goto end; + } + result.private_key = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, ""); + if (result.private_key == NULL) { + gpr_log(GPR_ERROR, "Could not deserialize private key."); + goto end; + } + success = 1; + +end: + if (bio != NULL) BIO_free(bio); + if (!success) grpc_auth_json_key_destruct(&result); + return result; +} + +grpc_auth_json_key grpc_auth_json_key_create_from_string( + const char *json_string) { + char *scratchpad = gpr_strdup(json_string); + grpc_json *json = grpc_json_parse_string(scratchpad); + grpc_auth_json_key result = grpc_auth_json_key_create_from_json(json); + if (json != NULL) grpc_json_destroy(json); + gpr_free(scratchpad); + return result; +} + +void grpc_auth_json_key_destruct(grpc_auth_json_key *json_key) { + if (json_key == NULL) return; + json_key->type = GRPC_AUTH_JSON_TYPE_INVALID; + if (json_key->client_id != NULL) { + gpr_free(json_key->client_id); + json_key->client_id = NULL; + } + if (json_key->private_key_id != NULL) { + gpr_free(json_key->private_key_id); + json_key->private_key_id = NULL; + } + if (json_key->client_email != NULL) { + gpr_free(json_key->client_email); + json_key->client_email = NULL; + } + if (json_key->private_key != NULL) { + RSA_free(json_key->private_key); + json_key->private_key = NULL; + } +} + +/* --- jwt encoding and signature. --- */ + +static grpc_json *create_child(grpc_json *brother, grpc_json *parent, + const char *key, const char *value, + grpc_json_type type) { + grpc_json *child = grpc_json_create(type); + if (brother) brother->next = child; + if (!parent->child) parent->child = child; + child->parent = parent; + child->value = value; + child->key = key; + return child; +} + +static char *encoded_jwt_header(const char *key_id, const char *algorithm) { + grpc_json *json = grpc_json_create(GRPC_JSON_OBJECT); + grpc_json *child = NULL; + char *json_str = NULL; + char *result = NULL; + + child = create_child(NULL, json, "alg", algorithm, GRPC_JSON_STRING); + child = create_child(child, json, "typ", GRPC_JWT_TYPE, GRPC_JSON_STRING); + create_child(child, json, "kid", key_id, GRPC_JSON_STRING); + + json_str = grpc_json_dump_to_string(json, 0); + result = grpc_base64_encode(json_str, strlen(json_str), 1, 0); + gpr_free(json_str); + grpc_json_destroy(json); + return result; +} + +static char *encoded_jwt_claim(const grpc_auth_json_key *json_key, + const char *audience, + gpr_timespec token_lifetime, const char *scope) { + grpc_json *json = grpc_json_create(GRPC_JSON_OBJECT); + grpc_json *child = NULL; + char *json_str = NULL; + char *result = NULL; + gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME); + gpr_timespec expiration = gpr_time_add(now, token_lifetime); + char now_str[GPR_LTOA_MIN_BUFSIZE]; + char expiration_str[GPR_LTOA_MIN_BUFSIZE]; + if (gpr_time_cmp(token_lifetime, grpc_max_auth_token_lifetime()) > 0) { + gpr_log(GPR_INFO, "Cropping token lifetime to maximum allowed value."); + expiration = gpr_time_add(now, grpc_max_auth_token_lifetime()); + } + int64_ttoa(now.tv_sec, now_str); + int64_ttoa(expiration.tv_sec, expiration_str); + + child = + create_child(NULL, json, "iss", json_key->client_email, GRPC_JSON_STRING); + if (scope != NULL) { + child = create_child(child, json, "scope", scope, GRPC_JSON_STRING); + } else { + /* Unscoped JWTs need a sub field. */ + child = create_child(child, json, "sub", json_key->client_email, + GRPC_JSON_STRING); + } + + child = create_child(child, json, "aud", audience, GRPC_JSON_STRING); + child = create_child(child, json, "iat", now_str, GRPC_JSON_NUMBER); + create_child(child, json, "exp", expiration_str, GRPC_JSON_NUMBER); + + json_str = grpc_json_dump_to_string(json, 0); + result = grpc_base64_encode(json_str, strlen(json_str), 1, 0); + gpr_free(json_str); + grpc_json_destroy(json); + return result; +} + +static char *dot_concat_and_free_strings(char *str1, char *str2) { + size_t str1_len = strlen(str1); + size_t str2_len = strlen(str2); + size_t result_len = str1_len + 1 /* dot */ + str2_len; + char *result = gpr_malloc(result_len + 1 /* NULL terminated */); + char *current = result; + memcpy(current, str1, str1_len); + current += str1_len; + *(current++) = '.'; + memcpy(current, str2, str2_len); + current += str2_len; + GPR_ASSERT(current >= result); + GPR_ASSERT((uintptr_t)(current - result) == result_len); + *current = '\0'; + gpr_free(str1); + gpr_free(str2); + return result; +} + +const EVP_MD *openssl_digest_from_algorithm(const char *algorithm) { + if (strcmp(algorithm, GRPC_JWT_RSA_SHA256_ALGORITHM) == 0) { + return EVP_sha256(); + } else { + gpr_log(GPR_ERROR, "Unknown algorithm %s.", algorithm); + return NULL; + } +} + +char *compute_and_encode_signature(const grpc_auth_json_key *json_key, + const char *signature_algorithm, + const char *to_sign) { + const EVP_MD *md = openssl_digest_from_algorithm(signature_algorithm); + EVP_MD_CTX *md_ctx = NULL; + EVP_PKEY *key = EVP_PKEY_new(); + size_t sig_len = 0; + unsigned char *sig = NULL; + char *result = NULL; + if (md == NULL) return NULL; + md_ctx = EVP_MD_CTX_create(); + if (md_ctx == NULL) { + gpr_log(GPR_ERROR, "Could not create MD_CTX"); + goto end; + } + EVP_PKEY_set1_RSA(key, json_key->private_key); + if (EVP_DigestSignInit(md_ctx, NULL, md, NULL, key) != 1) { + gpr_log(GPR_ERROR, "DigestInit failed."); + goto end; + } + if (EVP_DigestSignUpdate(md_ctx, to_sign, strlen(to_sign)) != 1) { + gpr_log(GPR_ERROR, "DigestUpdate failed."); + goto end; + } + if (EVP_DigestSignFinal(md_ctx, NULL, &sig_len) != 1) { + gpr_log(GPR_ERROR, "DigestFinal (get signature length) failed."); + goto end; + } + sig = gpr_malloc(sig_len); + if (EVP_DigestSignFinal(md_ctx, sig, &sig_len) != 1) { + gpr_log(GPR_ERROR, "DigestFinal (signature compute) failed."); + goto end; + } + result = grpc_base64_encode(sig, sig_len, 1, 0); + +end: + if (key != NULL) EVP_PKEY_free(key); + if (md_ctx != NULL) EVP_MD_CTX_destroy(md_ctx); + if (sig != NULL) gpr_free(sig); + return result; +} + +char *grpc_jwt_encode_and_sign(const grpc_auth_json_key *json_key, + const char *audience, + gpr_timespec token_lifetime, const char *scope) { + if (g_jwt_encode_and_sign_override != NULL) { + return g_jwt_encode_and_sign_override(json_key, audience, token_lifetime, + scope); + } else { + const char *sig_algo = GRPC_JWT_RSA_SHA256_ALGORITHM; + char *to_sign = dot_concat_and_free_strings( + encoded_jwt_header(json_key->private_key_id, sig_algo), + encoded_jwt_claim(json_key, audience, token_lifetime, scope)); + char *sig = compute_and_encode_signature(json_key, sig_algo, to_sign); + if (sig == NULL) { + gpr_free(to_sign); + return NULL; + } + return dot_concat_and_free_strings(to_sign, sig); + } +} + +void grpc_jwt_encode_and_sign_set_override( + grpc_jwt_encode_and_sign_override func) { + g_jwt_encode_and_sign_override = func; +} + +/* --- grpc_auth_refresh_token --- */ + +int grpc_auth_refresh_token_is_valid( + const grpc_auth_refresh_token *refresh_token) { + return (refresh_token != NULL) && + strcmp(refresh_token->type, GRPC_AUTH_JSON_TYPE_INVALID); +} + +grpc_auth_refresh_token grpc_auth_refresh_token_create_from_json( + const grpc_json *json) { + grpc_auth_refresh_token result; + const char *prop_value; + int success = 0; + + memset(&result, 0, sizeof(grpc_auth_refresh_token)); + result.type = GRPC_AUTH_JSON_TYPE_INVALID; + if (json == NULL) { + gpr_log(GPR_ERROR, "Invalid json."); + goto end; + } + + prop_value = json_get_string_property(json, "type"); + if (prop_value == NULL || + strcmp(prop_value, GRPC_AUTH_JSON_TYPE_AUTHORIZED_USER)) { + goto end; + } + result.type = GRPC_AUTH_JSON_TYPE_AUTHORIZED_USER; + + if (!set_json_key_string_property(json, "client_secret", + &result.client_secret) || + !set_json_key_string_property(json, "client_id", &result.client_id) || + !set_json_key_string_property(json, "refresh_token", + &result.refresh_token)) { + goto end; + } + success = 1; + +end: + if (!success) grpc_auth_refresh_token_destruct(&result); + return result; +} + +grpc_auth_refresh_token grpc_auth_refresh_token_create_from_string( + const char *json_string) { + char *scratchpad = gpr_strdup(json_string); + grpc_json *json = grpc_json_parse_string(scratchpad); + grpc_auth_refresh_token result = + grpc_auth_refresh_token_create_from_json(json); + if (json != NULL) grpc_json_destroy(json); + gpr_free(scratchpad); + return result; +} + +void grpc_auth_refresh_token_destruct(grpc_auth_refresh_token *refresh_token) { + if (refresh_token == NULL) return; + refresh_token->type = GRPC_AUTH_JSON_TYPE_INVALID; + if (refresh_token->client_id != NULL) { + gpr_free(refresh_token->client_id); + refresh_token->client_id = NULL; + } + if (refresh_token->client_secret != NULL) { + gpr_free(refresh_token->client_secret); + refresh_token->client_secret = NULL; + } + if (refresh_token->refresh_token != NULL) { + gpr_free(refresh_token->refresh_token); + refresh_token->refresh_token = NULL; + } +} diff --git a/src/core/lib/security/json_token.h b/src/core/lib/security/json_token.h new file mode 100644 index 0000000000..d183f9b3a3 --- /dev/null +++ b/src/core/lib/security/json_token.h @@ -0,0 +1,118 @@ +/* + * + * Copyright 2015-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_SECURITY_JSON_TOKEN_H +#define GRPC_CORE_SECURITY_JSON_TOKEN_H + +#include +#include + +#include "src/core/json/json.h" + +/* --- Constants. --- */ + +#define GRPC_JWT_OAUTH2_AUDIENCE "https://www.googleapis.com/oauth2/v3/token" + +#define GRPC_AUTH_JSON_TYPE_INVALID "invalid" +#define GRPC_AUTH_JSON_TYPE_SERVICE_ACCOUNT "service_account" +#define GRPC_AUTH_JSON_TYPE_AUTHORIZED_USER "authorized_user" + +/* --- auth_json_key parsing. --- */ + +typedef struct { + const char *type; + char *private_key_id; + char *client_id; + char *client_email; + RSA *private_key; +} grpc_auth_json_key; + +/* Returns 1 if the object is valid, 0 otherwise. */ +int grpc_auth_json_key_is_valid(const grpc_auth_json_key *json_key); + +/* Creates a json_key object from string. Returns an invalid object if a parsing + error has been encountered. */ +grpc_auth_json_key grpc_auth_json_key_create_from_string( + const char *json_string); + +/* Creates a json_key object from parsed json. Returns an invalid object if a + parsing error has been encountered. */ +grpc_auth_json_key grpc_auth_json_key_create_from_json(const grpc_json *json); + +/* Destructs the object. */ +void grpc_auth_json_key_destruct(grpc_auth_json_key *json_key); + +/* --- json token encoding and signing. --- */ + +/* Caller is responsible for calling gpr_free on the returned value. May return + NULL on invalid input. The scope parameter may be NULL. */ +char *grpc_jwt_encode_and_sign(const grpc_auth_json_key *json_key, + const char *audience, + gpr_timespec token_lifetime, const char *scope); + +/* Override encode_and_sign function for testing. */ +typedef char *(*grpc_jwt_encode_and_sign_override)( + const grpc_auth_json_key *json_key, const char *audience, + gpr_timespec token_lifetime, const char *scope); + +/* Set a custom encode_and_sign override for testing. */ +void grpc_jwt_encode_and_sign_set_override( + grpc_jwt_encode_and_sign_override func); + +/* --- auth_refresh_token parsing. --- */ + +typedef struct { + const char *type; + char *client_id; + char *client_secret; + char *refresh_token; +} grpc_auth_refresh_token; + +/* Returns 1 if the object is valid, 0 otherwise. */ +int grpc_auth_refresh_token_is_valid( + const grpc_auth_refresh_token *refresh_token); + +/* Creates a refresh token object from string. Returns an invalid object if a + parsing error has been encountered. */ +grpc_auth_refresh_token grpc_auth_refresh_token_create_from_string( + const char *json_string); + +/* Creates a refresh token object from parsed json. Returns an invalid object if + a parsing error has been encountered. */ +grpc_auth_refresh_token grpc_auth_refresh_token_create_from_json( + const grpc_json *json); + +/* Destructs the object. */ +void grpc_auth_refresh_token_destruct(grpc_auth_refresh_token *refresh_token); + +#endif /* GRPC_CORE_SECURITY_JSON_TOKEN_H */ diff --git a/src/core/lib/security/jwt_verifier.c b/src/core/lib/security/jwt_verifier.c new file mode 100644 index 0000000000..0bb8e05306 --- /dev/null +++ b/src/core/lib/security/jwt_verifier.c @@ -0,0 +1,843 @@ +/* + * + * Copyright 2015-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/security/jwt_verifier.h" + +#include +#include + +#include "src/core/http/httpcli.h" +#include "src/core/security/b64.h" +#include "src/core/tsi/ssl_types.h" + +#include +#include +#include +#include +#include + +/* --- Utils. --- */ + +const char *grpc_jwt_verifier_status_to_string( + grpc_jwt_verifier_status status) { + switch (status) { + case GRPC_JWT_VERIFIER_OK: + return "OK"; + case GRPC_JWT_VERIFIER_BAD_SIGNATURE: + return "BAD_SIGNATURE"; + case GRPC_JWT_VERIFIER_BAD_FORMAT: + return "BAD_FORMAT"; + case GRPC_JWT_VERIFIER_BAD_AUDIENCE: + return "BAD_AUDIENCE"; + case GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR: + return "KEY_RETRIEVAL_ERROR"; + case GRPC_JWT_VERIFIER_TIME_CONSTRAINT_FAILURE: + return "TIME_CONSTRAINT_FAILURE"; + case GRPC_JWT_VERIFIER_GENERIC_ERROR: + return "GENERIC_ERROR"; + default: + return "UNKNOWN"; + } +} + +static const EVP_MD *evp_md_from_alg(const char *alg) { + if (strcmp(alg, "RS256") == 0) { + return EVP_sha256(); + } else if (strcmp(alg, "RS384") == 0) { + return EVP_sha384(); + } else if (strcmp(alg, "RS512") == 0) { + return EVP_sha512(); + } else { + return NULL; + } +} + +static grpc_json *parse_json_part_from_jwt(const char *str, size_t len, + gpr_slice *buffer) { + grpc_json *json; + + *buffer = grpc_base64_decode_with_len(str, len, 1); + if (GPR_SLICE_IS_EMPTY(*buffer)) { + gpr_log(GPR_ERROR, "Invalid base64."); + return NULL; + } + json = grpc_json_parse_string_with_len((char *)GPR_SLICE_START_PTR(*buffer), + GPR_SLICE_LENGTH(*buffer)); + if (json == NULL) { + gpr_slice_unref(*buffer); + gpr_log(GPR_ERROR, "JSON parsing error."); + } + return json; +} + +static const char *validate_string_field(const grpc_json *json, + const char *key) { + if (json->type != GRPC_JSON_STRING) { + gpr_log(GPR_ERROR, "Invalid %s field [%s]", key, json->value); + return NULL; + } + return json->value; +} + +static gpr_timespec validate_time_field(const grpc_json *json, + const char *key) { + gpr_timespec result = gpr_time_0(GPR_CLOCK_REALTIME); + if (json->type != GRPC_JSON_NUMBER) { + gpr_log(GPR_ERROR, "Invalid %s field [%s]", key, json->value); + return result; + } + result.tv_sec = strtol(json->value, NULL, 10); + return result; +} + +/* --- JOSE header. see http://tools.ietf.org/html/rfc7515#section-4 --- */ + +typedef struct { + const char *alg; + const char *kid; + const char *typ; + /* TODO(jboeuf): Add others as needed (jku, jwk, x5u, x5c and so on...). */ + gpr_slice buffer; +} jose_header; + +static void jose_header_destroy(jose_header *h) { + gpr_slice_unref(h->buffer); + gpr_free(h); +} + +/* Takes ownership of json and buffer. */ +static jose_header *jose_header_from_json(grpc_json *json, gpr_slice buffer) { + grpc_json *cur; + jose_header *h = gpr_malloc(sizeof(jose_header)); + memset(h, 0, sizeof(jose_header)); + h->buffer = buffer; + for (cur = json->child; cur != NULL; cur = cur->next) { + if (strcmp(cur->key, "alg") == 0) { + /* We only support RSA-1.5 signatures for now. + Beware of this if we add HMAC support: + https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/ + */ + if (cur->type != GRPC_JSON_STRING || strncmp(cur->value, "RS", 2) || + evp_md_from_alg(cur->value) == NULL) { + gpr_log(GPR_ERROR, "Invalid alg field [%s]", cur->value); + goto error; + } + h->alg = cur->value; + } else if (strcmp(cur->key, "typ") == 0) { + h->typ = validate_string_field(cur, "typ"); + if (h->typ == NULL) goto error; + } else if (strcmp(cur->key, "kid") == 0) { + h->kid = validate_string_field(cur, "kid"); + if (h->kid == NULL) goto error; + } + } + if (h->alg == NULL) { + gpr_log(GPR_ERROR, "Missing alg field."); + goto error; + } + grpc_json_destroy(json); + h->buffer = buffer; + return h; + +error: + grpc_json_destroy(json); + jose_header_destroy(h); + return NULL; +} + +/* --- JWT claims. see http://tools.ietf.org/html/rfc7519#section-4.1 */ + +struct grpc_jwt_claims { + /* Well known properties already parsed. */ + const char *sub; + const char *iss; + const char *aud; + const char *jti; + gpr_timespec iat; + gpr_timespec exp; + gpr_timespec nbf; + + grpc_json *json; + gpr_slice buffer; +}; + +void grpc_jwt_claims_destroy(grpc_jwt_claims *claims) { + grpc_json_destroy(claims->json); + gpr_slice_unref(claims->buffer); + gpr_free(claims); +} + +const grpc_json *grpc_jwt_claims_json(const grpc_jwt_claims *claims) { + if (claims == NULL) return NULL; + return claims->json; +} + +const char *grpc_jwt_claims_subject(const grpc_jwt_claims *claims) { + if (claims == NULL) return NULL; + return claims->sub; +} + +const char *grpc_jwt_claims_issuer(const grpc_jwt_claims *claims) { + if (claims == NULL) return NULL; + return claims->iss; +} + +const char *grpc_jwt_claims_id(const grpc_jwt_claims *claims) { + if (claims == NULL) return NULL; + return claims->jti; +} + +const char *grpc_jwt_claims_audience(const grpc_jwt_claims *claims) { + if (claims == NULL) return NULL; + return claims->aud; +} + +gpr_timespec grpc_jwt_claims_issued_at(const grpc_jwt_claims *claims) { + if (claims == NULL) return gpr_inf_past(GPR_CLOCK_REALTIME); + return claims->iat; +} + +gpr_timespec grpc_jwt_claims_expires_at(const grpc_jwt_claims *claims) { + if (claims == NULL) return gpr_inf_future(GPR_CLOCK_REALTIME); + return claims->exp; +} + +gpr_timespec grpc_jwt_claims_not_before(const grpc_jwt_claims *claims) { + if (claims == NULL) return gpr_inf_past(GPR_CLOCK_REALTIME); + return claims->nbf; +} + +/* Takes ownership of json and buffer even in case of failure. */ +grpc_jwt_claims *grpc_jwt_claims_from_json(grpc_json *json, gpr_slice buffer) { + grpc_json *cur; + grpc_jwt_claims *claims = gpr_malloc(sizeof(grpc_jwt_claims)); + memset(claims, 0, sizeof(grpc_jwt_claims)); + claims->json = json; + claims->buffer = buffer; + claims->iat = gpr_inf_past(GPR_CLOCK_REALTIME); + claims->nbf = gpr_inf_past(GPR_CLOCK_REALTIME); + claims->exp = gpr_inf_future(GPR_CLOCK_REALTIME); + + /* Per the spec, all fields are optional. */ + for (cur = json->child; cur != NULL; cur = cur->next) { + if (strcmp(cur->key, "sub") == 0) { + claims->sub = validate_string_field(cur, "sub"); + if (claims->sub == NULL) goto error; + } else if (strcmp(cur->key, "iss") == 0) { + claims->iss = validate_string_field(cur, "iss"); + if (claims->iss == NULL) goto error; + } else if (strcmp(cur->key, "aud") == 0) { + claims->aud = validate_string_field(cur, "aud"); + if (claims->aud == NULL) goto error; + } else if (strcmp(cur->key, "jti") == 0) { + claims->jti = validate_string_field(cur, "jti"); + if (claims->jti == NULL) goto error; + } else if (strcmp(cur->key, "iat") == 0) { + claims->iat = validate_time_field(cur, "iat"); + if (gpr_time_cmp(claims->iat, gpr_time_0(GPR_CLOCK_REALTIME)) == 0) + goto error; + } else if (strcmp(cur->key, "exp") == 0) { + claims->exp = validate_time_field(cur, "exp"); + if (gpr_time_cmp(claims->exp, gpr_time_0(GPR_CLOCK_REALTIME)) == 0) + goto error; + } else if (strcmp(cur->key, "nbf") == 0) { + claims->nbf = validate_time_field(cur, "nbf"); + if (gpr_time_cmp(claims->nbf, gpr_time_0(GPR_CLOCK_REALTIME)) == 0) + goto error; + } + } + return claims; + +error: + grpc_jwt_claims_destroy(claims); + return NULL; +} + +grpc_jwt_verifier_status grpc_jwt_claims_check(const grpc_jwt_claims *claims, + const char *audience) { + gpr_timespec skewed_now; + int audience_ok; + + GPR_ASSERT(claims != NULL); + + skewed_now = + gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), grpc_jwt_verifier_clock_skew); + if (gpr_time_cmp(skewed_now, claims->nbf) < 0) { + gpr_log(GPR_ERROR, "JWT is not valid yet."); + return GRPC_JWT_VERIFIER_TIME_CONSTRAINT_FAILURE; + } + skewed_now = + gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), grpc_jwt_verifier_clock_skew); + if (gpr_time_cmp(skewed_now, claims->exp) > 0) { + gpr_log(GPR_ERROR, "JWT is expired."); + return GRPC_JWT_VERIFIER_TIME_CONSTRAINT_FAILURE; + } + + if (audience == NULL) { + audience_ok = claims->aud == NULL; + } else { + audience_ok = claims->aud != NULL && strcmp(audience, claims->aud) == 0; + } + if (!audience_ok) { + gpr_log(GPR_ERROR, "Audience mismatch: expected %s and found %s.", + audience == NULL ? "NULL" : audience, + claims->aud == NULL ? "NULL" : claims->aud); + return GRPC_JWT_VERIFIER_BAD_AUDIENCE; + } + return GRPC_JWT_VERIFIER_OK; +} + +/* --- verifier_cb_ctx object. --- */ + +typedef struct { + grpc_jwt_verifier *verifier; + grpc_pollset *pollset; + jose_header *header; + grpc_jwt_claims *claims; + char *audience; + gpr_slice signature; + gpr_slice signed_data; + void *user_data; + grpc_jwt_verification_done_cb user_cb; +} verifier_cb_ctx; + +/* Takes ownership of the header, claims and signature. */ +static verifier_cb_ctx *verifier_cb_ctx_create( + grpc_jwt_verifier *verifier, grpc_pollset *pollset, jose_header *header, + grpc_jwt_claims *claims, const char *audience, gpr_slice signature, + const char *signed_jwt, size_t signed_jwt_len, void *user_data, + grpc_jwt_verification_done_cb cb) { + verifier_cb_ctx *ctx = gpr_malloc(sizeof(verifier_cb_ctx)); + memset(ctx, 0, sizeof(verifier_cb_ctx)); + ctx->verifier = verifier; + ctx->pollset = pollset; + ctx->header = header; + ctx->audience = gpr_strdup(audience); + ctx->claims = claims; + ctx->signature = signature; + ctx->signed_data = gpr_slice_from_copied_buffer(signed_jwt, signed_jwt_len); + ctx->user_data = user_data; + ctx->user_cb = cb; + return ctx; +} + +void verifier_cb_ctx_destroy(verifier_cb_ctx *ctx) { + if (ctx->audience != NULL) gpr_free(ctx->audience); + if (ctx->claims != NULL) grpc_jwt_claims_destroy(ctx->claims); + gpr_slice_unref(ctx->signature); + gpr_slice_unref(ctx->signed_data); + jose_header_destroy(ctx->header); + /* TODO: see what to do with claims... */ + gpr_free(ctx); +} + +/* --- grpc_jwt_verifier object. --- */ + +/* Clock skew defaults to one minute. */ +gpr_timespec grpc_jwt_verifier_clock_skew = {60, 0, GPR_TIMESPAN}; + +/* Max delay defaults to one minute. */ +gpr_timespec grpc_jwt_verifier_max_delay = {60, 0, GPR_TIMESPAN}; + +typedef struct { + char *email_domain; + char *key_url_prefix; +} email_key_mapping; + +struct grpc_jwt_verifier { + email_key_mapping *mappings; + size_t num_mappings; /* Should be very few, linear search ok. */ + size_t allocated_mappings; + grpc_httpcli_context http_ctx; +}; + +static grpc_json *json_from_http(const grpc_httpcli_response *response) { + grpc_json *json = NULL; + + if (response == NULL) { + gpr_log(GPR_ERROR, "HTTP response is NULL."); + return NULL; + } + if (response->status != 200) { + gpr_log(GPR_ERROR, "Call to http server failed with error %d.", + response->status); + return NULL; + } + + json = grpc_json_parse_string_with_len(response->body, response->body_length); + if (json == NULL) { + gpr_log(GPR_ERROR, "Invalid JSON found in response."); + } + return json; +} + +static const grpc_json *find_property_by_name(const grpc_json *json, + const char *name) { + const grpc_json *cur; + for (cur = json->child; cur != NULL; cur = cur->next) { + if (strcmp(cur->key, name) == 0) return cur; + } + return NULL; +} + +static EVP_PKEY *extract_pkey_from_x509(const char *x509_str) { + X509 *x509 = NULL; + EVP_PKEY *result = NULL; + BIO *bio = BIO_new(BIO_s_mem()); + size_t len = strlen(x509_str); + GPR_ASSERT(len < INT_MAX); + BIO_write(bio, x509_str, (int)len); + x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); + if (x509 == NULL) { + gpr_log(GPR_ERROR, "Unable to parse x509 cert."); + goto end; + } + result = X509_get_pubkey(x509); + if (result == NULL) { + gpr_log(GPR_ERROR, "Cannot find public key in X509 cert."); + } + +end: + BIO_free(bio); + if (x509 != NULL) X509_free(x509); + return result; +} + +static BIGNUM *bignum_from_base64(const char *b64) { + BIGNUM *result = NULL; + gpr_slice bin; + + if (b64 == NULL) return NULL; + bin = grpc_base64_decode(b64, 1); + if (GPR_SLICE_IS_EMPTY(bin)) { + gpr_log(GPR_ERROR, "Invalid base64 for big num."); + return NULL; + } + result = BN_bin2bn(GPR_SLICE_START_PTR(bin), + TSI_SIZE_AS_SIZE(GPR_SLICE_LENGTH(bin)), NULL); + gpr_slice_unref(bin); + return result; +} + +static EVP_PKEY *pkey_from_jwk(const grpc_json *json, const char *kty) { + const grpc_json *key_prop; + RSA *rsa = NULL; + EVP_PKEY *result = NULL; + + GPR_ASSERT(kty != NULL && json != NULL); + if (strcmp(kty, "RSA") != 0) { + gpr_log(GPR_ERROR, "Unsupported key type %s.", kty); + goto end; + } + rsa = RSA_new(); + if (rsa == NULL) { + gpr_log(GPR_ERROR, "Could not create rsa key."); + goto end; + } + for (key_prop = json->child; key_prop != NULL; key_prop = key_prop->next) { + if (strcmp(key_prop->key, "n") == 0) { + rsa->n = bignum_from_base64(validate_string_field(key_prop, "n")); + if (rsa->n == NULL) goto end; + } else if (strcmp(key_prop->key, "e") == 0) { + rsa->e = bignum_from_base64(validate_string_field(key_prop, "e")); + if (rsa->e == NULL) goto end; + } + } + if (rsa->e == NULL || rsa->n == NULL) { + gpr_log(GPR_ERROR, "Missing RSA public key field."); + goto end; + } + result = EVP_PKEY_new(); + EVP_PKEY_set1_RSA(result, rsa); /* uprefs rsa. */ + +end: + if (rsa != NULL) RSA_free(rsa); + return result; +} + +static EVP_PKEY *find_verification_key(const grpc_json *json, + const char *header_alg, + const char *header_kid) { + const grpc_json *jkey; + const grpc_json *jwk_keys; + /* Try to parse the json as a JWK set: + https://tools.ietf.org/html/rfc7517#section-5. */ + jwk_keys = find_property_by_name(json, "keys"); + if (jwk_keys == NULL) { + /* Use the google proprietary format which is: + { : , : , ... } */ + const grpc_json *cur = find_property_by_name(json, header_kid); + if (cur == NULL) return NULL; + return extract_pkey_from_x509(cur->value); + } + + if (jwk_keys->type != GRPC_JSON_ARRAY) { + gpr_log(GPR_ERROR, + "Unexpected value type of keys property in jwks key set."); + return NULL; + } + /* Key format is specified in: + https://tools.ietf.org/html/rfc7518#section-6. */ + for (jkey = jwk_keys->child; jkey != NULL; jkey = jkey->next) { + grpc_json *key_prop; + const char *alg = NULL; + const char *kid = NULL; + const char *kty = NULL; + + if (jkey->type != GRPC_JSON_OBJECT) continue; + for (key_prop = jkey->child; key_prop != NULL; key_prop = key_prop->next) { + if (strcmp(key_prop->key, "alg") == 0 && + key_prop->type == GRPC_JSON_STRING) { + alg = key_prop->value; + } else if (strcmp(key_prop->key, "kid") == 0 && + key_prop->type == GRPC_JSON_STRING) { + kid = key_prop->value; + } else if (strcmp(key_prop->key, "kty") == 0 && + key_prop->type == GRPC_JSON_STRING) { + kty = key_prop->value; + } + } + if (alg != NULL && kid != NULL && kty != NULL && + strcmp(kid, header_kid) == 0 && strcmp(alg, header_alg) == 0) { + return pkey_from_jwk(jkey, kty); + } + } + gpr_log(GPR_ERROR, + "Could not find matching key in key set for kid=%s and alg=%s", + header_kid, header_alg); + return NULL; +} + +static int verify_jwt_signature(EVP_PKEY *key, const char *alg, + gpr_slice signature, gpr_slice signed_data) { + EVP_MD_CTX *md_ctx = EVP_MD_CTX_create(); + const EVP_MD *md = evp_md_from_alg(alg); + int result = 0; + + GPR_ASSERT(md != NULL); /* Checked before. */ + if (md_ctx == NULL) { + gpr_log(GPR_ERROR, "Could not create EVP_MD_CTX."); + goto end; + } + if (EVP_DigestVerifyInit(md_ctx, NULL, md, NULL, key) != 1) { + gpr_log(GPR_ERROR, "EVP_DigestVerifyInit failed."); + goto end; + } + if (EVP_DigestVerifyUpdate(md_ctx, GPR_SLICE_START_PTR(signed_data), + GPR_SLICE_LENGTH(signed_data)) != 1) { + gpr_log(GPR_ERROR, "EVP_DigestVerifyUpdate failed."); + goto end; + } + if (EVP_DigestVerifyFinal(md_ctx, GPR_SLICE_START_PTR(signature), + GPR_SLICE_LENGTH(signature)) != 1) { + gpr_log(GPR_ERROR, "JWT signature verification failed."); + goto end; + } + result = 1; + +end: + if (md_ctx != NULL) EVP_MD_CTX_destroy(md_ctx); + return result; +} + +static void on_keys_retrieved(grpc_exec_ctx *exec_ctx, void *user_data, + const grpc_httpcli_response *response) { + grpc_json *json = json_from_http(response); + verifier_cb_ctx *ctx = (verifier_cb_ctx *)user_data; + EVP_PKEY *verification_key = NULL; + grpc_jwt_verifier_status status = GRPC_JWT_VERIFIER_GENERIC_ERROR; + grpc_jwt_claims *claims = NULL; + + if (json == NULL) { + status = GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR; + goto end; + } + verification_key = + find_verification_key(json, ctx->header->alg, ctx->header->kid); + if (verification_key == NULL) { + gpr_log(GPR_ERROR, "Could not find verification key with kid %s.", + ctx->header->kid); + status = GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR; + goto end; + } + + if (!verify_jwt_signature(verification_key, ctx->header->alg, ctx->signature, + ctx->signed_data)) { + status = GRPC_JWT_VERIFIER_BAD_SIGNATURE; + goto end; + } + + status = grpc_jwt_claims_check(ctx->claims, ctx->audience); + if (status == GRPC_JWT_VERIFIER_OK) { + /* Pass ownership. */ + claims = ctx->claims; + ctx->claims = NULL; + } + +end: + if (json != NULL) grpc_json_destroy(json); + if (verification_key != NULL) EVP_PKEY_free(verification_key); + ctx->user_cb(ctx->user_data, status, claims); + verifier_cb_ctx_destroy(ctx); +} + +static void on_openid_config_retrieved(grpc_exec_ctx *exec_ctx, void *user_data, + const grpc_httpcli_response *response) { + const grpc_json *cur; + grpc_json *json = json_from_http(response); + verifier_cb_ctx *ctx = (verifier_cb_ctx *)user_data; + grpc_httpcli_request req; + const char *jwks_uri; + + /* TODO(jboeuf): Cache the jwks_uri in order to avoid this hop next time. */ + if (json == NULL) goto error; + cur = find_property_by_name(json, "jwks_uri"); + if (cur == NULL) { + gpr_log(GPR_ERROR, "Could not find jwks_uri in openid config."); + goto error; + } + jwks_uri = validate_string_field(cur, "jwks_uri"); + if (jwks_uri == NULL) goto error; + if (strstr(jwks_uri, "https://") != jwks_uri) { + gpr_log(GPR_ERROR, "Invalid non https jwks_uri: %s.", jwks_uri); + goto error; + } + jwks_uri += 8; + req.handshaker = &grpc_httpcli_ssl; + req.host = gpr_strdup(jwks_uri); + req.http.path = strchr(jwks_uri, '/'); + if (req.http.path == NULL) { + req.http.path = ""; + } else { + *(req.host + (req.http.path - jwks_uri)) = '\0'; + } + grpc_httpcli_get( + exec_ctx, &ctx->verifier->http_ctx, ctx->pollset, &req, + gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), grpc_jwt_verifier_max_delay), + on_keys_retrieved, ctx); + grpc_json_destroy(json); + gpr_free(req.host); + return; + +error: + if (json != NULL) grpc_json_destroy(json); + ctx->user_cb(ctx->user_data, GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR, NULL); + verifier_cb_ctx_destroy(ctx); +} + +static email_key_mapping *verifier_get_mapping(grpc_jwt_verifier *v, + const char *email_domain) { + size_t i; + if (v->mappings == NULL) return NULL; + for (i = 0; i < v->num_mappings; i++) { + if (strcmp(email_domain, v->mappings[i].email_domain) == 0) { + return &v->mappings[i]; + } + } + return NULL; +} + +static void verifier_put_mapping(grpc_jwt_verifier *v, const char *email_domain, + const char *key_url_prefix) { + email_key_mapping *mapping = verifier_get_mapping(v, email_domain); + GPR_ASSERT(v->num_mappings < v->allocated_mappings); + if (mapping != NULL) { + gpr_free(mapping->key_url_prefix); + mapping->key_url_prefix = gpr_strdup(key_url_prefix); + return; + } + v->mappings[v->num_mappings].email_domain = gpr_strdup(email_domain); + v->mappings[v->num_mappings].key_url_prefix = gpr_strdup(key_url_prefix); + v->num_mappings++; + GPR_ASSERT(v->num_mappings <= v->allocated_mappings); +} + +/* Takes ownership of ctx. */ +static void retrieve_key_and_verify(grpc_exec_ctx *exec_ctx, + verifier_cb_ctx *ctx) { + const char *at_sign; + grpc_httpcli_response_cb http_cb; + char *path_prefix = NULL; + const char *iss; + grpc_httpcli_request req; + memset(&req, 0, sizeof(grpc_httpcli_request)); + req.handshaker = &grpc_httpcli_ssl; + + GPR_ASSERT(ctx != NULL && ctx->header != NULL && ctx->claims != NULL); + iss = ctx->claims->iss; + if (ctx->header->kid == NULL) { + gpr_log(GPR_ERROR, "Missing kid in jose header."); + goto error; + } + if (iss == NULL) { + gpr_log(GPR_ERROR, "Missing iss in claims."); + goto error; + } + + /* This code relies on: + https://openid.net/specs/openid-connect-discovery-1_0.html + Nobody seems to implement the account/email/webfinger part 2. of the spec + so we will rely instead on email/url mappings if we detect such an issuer. + Part 4, on the other hand is implemented by both google and salesforce. */ + + /* Very non-sophisticated way to detect an email address. Should be good + enough for now... */ + at_sign = strchr(iss, '@'); + if (at_sign != NULL) { + email_key_mapping *mapping; + const char *email_domain = at_sign + 1; + GPR_ASSERT(ctx->verifier != NULL); + mapping = verifier_get_mapping(ctx->verifier, email_domain); + if (mapping == NULL) { + gpr_log(GPR_ERROR, "Missing mapping for issuer email."); + goto error; + } + req.host = gpr_strdup(mapping->key_url_prefix); + path_prefix = strchr(req.host, '/'); + if (path_prefix == NULL) { + gpr_asprintf(&req.http.path, "/%s", iss); + } else { + *(path_prefix++) = '\0'; + gpr_asprintf(&req.http.path, "/%s/%s", path_prefix, iss); + } + http_cb = on_keys_retrieved; + } else { + req.host = gpr_strdup(strstr(iss, "https://") == iss ? iss + 8 : iss); + path_prefix = strchr(req.host, '/'); + if (path_prefix == NULL) { + req.http.path = gpr_strdup(GRPC_OPENID_CONFIG_URL_SUFFIX); + } else { + *(path_prefix++) = 0; + gpr_asprintf(&req.http.path, "/%s%s", path_prefix, + GRPC_OPENID_CONFIG_URL_SUFFIX); + } + http_cb = on_openid_config_retrieved; + } + + grpc_httpcli_get( + exec_ctx, &ctx->verifier->http_ctx, ctx->pollset, &req, + gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), grpc_jwt_verifier_max_delay), + http_cb, ctx); + gpr_free(req.host); + gpr_free(req.http.path); + return; + +error: + ctx->user_cb(ctx->user_data, GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR, NULL); + verifier_cb_ctx_destroy(ctx); +} + +void grpc_jwt_verifier_verify(grpc_exec_ctx *exec_ctx, + grpc_jwt_verifier *verifier, + grpc_pollset *pollset, const char *jwt, + const char *audience, + grpc_jwt_verification_done_cb cb, + void *user_data) { + const char *dot = NULL; + grpc_json *json; + jose_header *header = NULL; + grpc_jwt_claims *claims = NULL; + gpr_slice header_buffer; + gpr_slice claims_buffer; + gpr_slice signature; + size_t signed_jwt_len; + const char *cur = jwt; + + GPR_ASSERT(verifier != NULL && jwt != NULL && audience != NULL && cb != NULL); + dot = strchr(cur, '.'); + if (dot == NULL) goto error; + json = parse_json_part_from_jwt(cur, (size_t)(dot - cur), &header_buffer); + if (json == NULL) goto error; + header = jose_header_from_json(json, header_buffer); + if (header == NULL) goto error; + + cur = dot + 1; + dot = strchr(cur, '.'); + if (dot == NULL) goto error; + json = parse_json_part_from_jwt(cur, (size_t)(dot - cur), &claims_buffer); + if (json == NULL) goto error; + claims = grpc_jwt_claims_from_json(json, claims_buffer); + if (claims == NULL) goto error; + + signed_jwt_len = (size_t)(dot - jwt); + cur = dot + 1; + signature = grpc_base64_decode(cur, 1); + if (GPR_SLICE_IS_EMPTY(signature)) goto error; + retrieve_key_and_verify( + exec_ctx, + verifier_cb_ctx_create(verifier, pollset, header, claims, audience, + signature, jwt, signed_jwt_len, user_data, cb)); + return; + +error: + if (header != NULL) jose_header_destroy(header); + if (claims != NULL) grpc_jwt_claims_destroy(claims); + cb(user_data, GRPC_JWT_VERIFIER_BAD_FORMAT, NULL); +} + +grpc_jwt_verifier *grpc_jwt_verifier_create( + const grpc_jwt_verifier_email_domain_key_url_mapping *mappings, + size_t num_mappings) { + grpc_jwt_verifier *v = gpr_malloc(sizeof(grpc_jwt_verifier)); + memset(v, 0, sizeof(grpc_jwt_verifier)); + grpc_httpcli_context_init(&v->http_ctx); + + /* We know at least of one mapping. */ + v->allocated_mappings = 1 + num_mappings; + v->mappings = gpr_malloc(v->allocated_mappings * sizeof(email_key_mapping)); + verifier_put_mapping(v, GRPC_GOOGLE_SERVICE_ACCOUNTS_EMAIL_DOMAIN, + GRPC_GOOGLE_SERVICE_ACCOUNTS_KEY_URL_PREFIX); + /* User-Provided mappings. */ + if (mappings != NULL) { + size_t i; + for (i = 0; i < num_mappings; i++) { + verifier_put_mapping(v, mappings[i].email_domain, + mappings[i].key_url_prefix); + } + } + return v; +} + +void grpc_jwt_verifier_destroy(grpc_jwt_verifier *v) { + size_t i; + if (v == NULL) return; + grpc_httpcli_context_destroy(&v->http_ctx); + if (v->mappings != NULL) { + for (i = 0; i < v->num_mappings; i++) { + gpr_free(v->mappings[i].email_domain); + gpr_free(v->mappings[i].key_url_prefix); + } + gpr_free(v->mappings); + } + gpr_free(v); +} diff --git a/src/core/lib/security/jwt_verifier.h b/src/core/lib/security/jwt_verifier.h new file mode 100644 index 0000000000..d898d2193f --- /dev/null +++ b/src/core/lib/security/jwt_verifier.h @@ -0,0 +1,136 @@ +/* + * + * Copyright 2015-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_SECURITY_JWT_VERIFIER_H +#define GRPC_CORE_SECURITY_JWT_VERIFIER_H + +#include "src/core/iomgr/pollset.h" +#include "src/core/json/json.h" + +#include +#include + +/* --- Constants. --- */ + +#define GRPC_OPENID_CONFIG_URL_SUFFIX "/.well-known/openid-configuration" +#define GRPC_GOOGLE_SERVICE_ACCOUNTS_EMAIL_DOMAIN \ + "developer.gserviceaccount.com" +#define GRPC_GOOGLE_SERVICE_ACCOUNTS_KEY_URL_PREFIX \ + "www.googleapis.com/robot/v1/metadata/x509" + +/* --- grpc_jwt_verifier_status. --- */ + +typedef enum { + GRPC_JWT_VERIFIER_OK = 0, + GRPC_JWT_VERIFIER_BAD_SIGNATURE, + GRPC_JWT_VERIFIER_BAD_FORMAT, + GRPC_JWT_VERIFIER_BAD_AUDIENCE, + GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR, + GRPC_JWT_VERIFIER_TIME_CONSTRAINT_FAILURE, + GRPC_JWT_VERIFIER_GENERIC_ERROR +} grpc_jwt_verifier_status; + +const char *grpc_jwt_verifier_status_to_string(grpc_jwt_verifier_status status); + +/* --- grpc_jwt_claims. --- */ + +typedef struct grpc_jwt_claims grpc_jwt_claims; + +void grpc_jwt_claims_destroy(grpc_jwt_claims *claims); + +/* Returns the whole JSON tree of the claims. */ +const grpc_json *grpc_jwt_claims_json(const grpc_jwt_claims *claims); + +/* Access to registered claims in https://tools.ietf.org/html/rfc7519#page-9 */ +const char *grpc_jwt_claims_subject(const grpc_jwt_claims *claims); +const char *grpc_jwt_claims_issuer(const grpc_jwt_claims *claims); +const char *grpc_jwt_claims_id(const grpc_jwt_claims *claims); +const char *grpc_jwt_claims_audience(const grpc_jwt_claims *claims); +gpr_timespec grpc_jwt_claims_issued_at(const grpc_jwt_claims *claims); +gpr_timespec grpc_jwt_claims_expires_at(const grpc_jwt_claims *claims); +gpr_timespec grpc_jwt_claims_not_before(const grpc_jwt_claims *claims); + +/* --- grpc_jwt_verifier. --- */ + +typedef struct grpc_jwt_verifier grpc_jwt_verifier; + +typedef struct { + /* The email domain is the part after the @ sign. */ + const char *email_domain; + + /* The key url prefix will be used to get the public key from the issuer: + https:/// + Therefore the key_url_prefix must NOT contain https://. */ + const char *key_url_prefix; +} grpc_jwt_verifier_email_domain_key_url_mapping; + +/* Globals to control the verifier. Not thread-safe. */ +extern gpr_timespec grpc_jwt_verifier_clock_skew; +extern gpr_timespec grpc_jwt_verifier_max_delay; + +/* The verifier can be created with some custom mappings to help with key + discovery in the case where the issuer is an email address. + mappings can be NULL in which case num_mappings MUST be 0. + A verifier object has one built-in mapping (unless overridden): + GRPC_GOOGLE_SERVICE_ACCOUNTS_EMAIL_DOMAIN -> + GRPC_GOOGLE_SERVICE_ACCOUNTS_KEY_URL_PREFIX.*/ +grpc_jwt_verifier *grpc_jwt_verifier_create( + const grpc_jwt_verifier_email_domain_key_url_mapping *mappings, + size_t num_mappings); + +/*The verifier must not be destroyed if there are still outstanding callbacks.*/ +void grpc_jwt_verifier_destroy(grpc_jwt_verifier *verifier); + +/* User provided callback that will be called when the verification of the JWT + is done (maybe in another thread). + It is the responsibility of the callee to call grpc_jwt_claims_destroy on + the claims. */ +typedef void (*grpc_jwt_verification_done_cb)(void *user_data, + grpc_jwt_verifier_status status, + grpc_jwt_claims *claims); + +/* Verifies for the JWT for the given expected audience. */ +void grpc_jwt_verifier_verify(grpc_exec_ctx *exec_ctx, + grpc_jwt_verifier *verifier, + grpc_pollset *pollset, const char *jwt, + const char *audience, + grpc_jwt_verification_done_cb cb, + void *user_data); + +/* --- TESTING ONLY exposed functions. --- */ + +grpc_jwt_claims *grpc_jwt_claims_from_json(grpc_json *json, gpr_slice buffer); +grpc_jwt_verifier_status grpc_jwt_claims_check(const grpc_jwt_claims *claims, + const char *audience); + +#endif /* GRPC_CORE_SECURITY_JWT_VERIFIER_H */ diff --git a/src/core/lib/security/secure_endpoint.c b/src/core/lib/security/secure_endpoint.c new file mode 100644 index 0000000000..58b081dc4a --- /dev/null +++ b/src/core/lib/security/secure_endpoint.c @@ -0,0 +1,384 @@ +/* + * + * Copyright 2015-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/security/secure_endpoint.h" +#include +#include +#include +#include +#include +#include "src/core/debug/trace.h" +#include "src/core/support/string.h" +#include "src/core/tsi/transport_security_interface.h" + +#define STAGING_BUFFER_SIZE 8192 + +typedef struct { + grpc_endpoint base; + grpc_endpoint *wrapped_ep; + struct tsi_frame_protector *protector; + gpr_mu protector_mu; + /* saved upper level callbacks and user_data. */ + grpc_closure *read_cb; + grpc_closure *write_cb; + grpc_closure on_read; + gpr_slice_buffer *read_buffer; + gpr_slice_buffer source_buffer; + /* saved handshaker leftover data to unprotect. */ + gpr_slice_buffer leftover_bytes; + /* buffers for read and write */ + gpr_slice read_staging_buffer; + + gpr_slice write_staging_buffer; + gpr_slice_buffer output_buffer; + + gpr_refcount ref; +} secure_endpoint; + +int grpc_trace_secure_endpoint = 0; + +static void destroy(grpc_exec_ctx *exec_ctx, secure_endpoint *secure_ep) { + secure_endpoint *ep = secure_ep; + grpc_endpoint_destroy(exec_ctx, ep->wrapped_ep); + tsi_frame_protector_destroy(ep->protector); + gpr_slice_buffer_destroy(&ep->leftover_bytes); + gpr_slice_unref(ep->read_staging_buffer); + gpr_slice_unref(ep->write_staging_buffer); + gpr_slice_buffer_destroy(&ep->output_buffer); + gpr_slice_buffer_destroy(&ep->source_buffer); + gpr_mu_destroy(&ep->protector_mu); + gpr_free(ep); +} + +/*#define GRPC_SECURE_ENDPOINT_REFCOUNT_DEBUG*/ +#ifdef GRPC_SECURE_ENDPOINT_REFCOUNT_DEBUG +#define SECURE_ENDPOINT_UNREF(exec_ctx, ep, reason) \ + secure_endpoint_unref((exec_ctx), (ep), (reason), __FILE__, __LINE__) +#define SECURE_ENDPOINT_REF(ep, reason) \ + secure_endpoint_ref((ep), (reason), __FILE__, __LINE__) +static void secure_endpoint_unref(secure_endpoint *ep, + grpc_closure_list *closure_list, + const char *reason, const char *file, + int line) { + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "SECENDP unref %p : %s %d -> %d", + ep, reason, ep->ref.count, ep->ref.count - 1); + if (gpr_unref(&ep->ref)) { + destroy(exec_ctx, ep); + } +} + +static void secure_endpoint_ref(secure_endpoint *ep, const char *reason, + const char *file, int line) { + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "SECENDP ref %p : %s %d -> %d", + ep, reason, ep->ref.count, ep->ref.count + 1); + gpr_ref(&ep->ref); +} +#else +#define SECURE_ENDPOINT_UNREF(exec_ctx, ep, reason) \ + secure_endpoint_unref((exec_ctx), (ep)) +#define SECURE_ENDPOINT_REF(ep, reason) secure_endpoint_ref((ep)) +static void secure_endpoint_unref(grpc_exec_ctx *exec_ctx, + secure_endpoint *ep) { + if (gpr_unref(&ep->ref)) { + destroy(exec_ctx, ep); + } +} + +static void secure_endpoint_ref(secure_endpoint *ep) { gpr_ref(&ep->ref); } +#endif + +static void flush_read_staging_buffer(secure_endpoint *ep, uint8_t **cur, + uint8_t **end) { + gpr_slice_buffer_add(ep->read_buffer, ep->read_staging_buffer); + ep->read_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE); + *cur = GPR_SLICE_START_PTR(ep->read_staging_buffer); + *end = GPR_SLICE_END_PTR(ep->read_staging_buffer); +} + +static void call_read_cb(grpc_exec_ctx *exec_ctx, secure_endpoint *ep, + bool success) { + if (grpc_trace_secure_endpoint) { + size_t i; + for (i = 0; i < ep->read_buffer->count; i++) { + char *data = gpr_dump_slice(ep->read_buffer->slices[i], + GPR_DUMP_HEX | GPR_DUMP_ASCII); + gpr_log(GPR_DEBUG, "READ %p: %s", ep, data); + gpr_free(data); + } + } + ep->read_buffer = NULL; + grpc_exec_ctx_enqueue(exec_ctx, ep->read_cb, success, NULL); + SECURE_ENDPOINT_UNREF(exec_ctx, ep, "read"); +} + +static void on_read(grpc_exec_ctx *exec_ctx, void *user_data, bool success) { + unsigned i; + uint8_t keep_looping = 0; + tsi_result result = TSI_OK; + secure_endpoint *ep = (secure_endpoint *)user_data; + uint8_t *cur = GPR_SLICE_START_PTR(ep->read_staging_buffer); + uint8_t *end = GPR_SLICE_END_PTR(ep->read_staging_buffer); + + if (!success) { + gpr_slice_buffer_reset_and_unref(ep->read_buffer); + call_read_cb(exec_ctx, ep, 0); + return; + } + + /* TODO(yangg) check error, maybe bail out early */ + for (i = 0; i < ep->source_buffer.count; i++) { + gpr_slice encrypted = ep->source_buffer.slices[i]; + uint8_t *message_bytes = GPR_SLICE_START_PTR(encrypted); + size_t message_size = GPR_SLICE_LENGTH(encrypted); + + while (message_size > 0 || keep_looping) { + size_t unprotected_buffer_size_written = (size_t)(end - cur); + size_t processed_message_size = message_size; + gpr_mu_lock(&ep->protector_mu); + result = tsi_frame_protector_unprotect(ep->protector, message_bytes, + &processed_message_size, cur, + &unprotected_buffer_size_written); + gpr_mu_unlock(&ep->protector_mu); + if (result != TSI_OK) { + gpr_log(GPR_ERROR, "Decryption error: %s", + tsi_result_to_string(result)); + break; + } + message_bytes += processed_message_size; + message_size -= processed_message_size; + cur += unprotected_buffer_size_written; + + if (cur == end) { + flush_read_staging_buffer(ep, &cur, &end); + /* Force to enter the loop again to extract buffered bytes in protector. + The bytes could be buffered because of running out of staging_buffer. + If this happens at the end of all slices, doing another unprotect + avoids leaving data in the protector. */ + keep_looping = 1; + } else if (unprotected_buffer_size_written > 0) { + keep_looping = 1; + } else { + keep_looping = 0; + } + } + if (result != TSI_OK) break; + } + + if (cur != GPR_SLICE_START_PTR(ep->read_staging_buffer)) { + gpr_slice_buffer_add( + ep->read_buffer, + gpr_slice_split_head( + &ep->read_staging_buffer, + (size_t)(cur - GPR_SLICE_START_PTR(ep->read_staging_buffer)))); + } + + /* TODO(yangg) experiment with moving this block after read_cb to see if it + helps latency */ + gpr_slice_buffer_reset_and_unref(&ep->source_buffer); + + if (result != TSI_OK) { + gpr_slice_buffer_reset_and_unref(ep->read_buffer); + call_read_cb(exec_ctx, ep, 0); + return; + } + + call_read_cb(exec_ctx, ep, 1); +} + +static void endpoint_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep, + gpr_slice_buffer *slices, grpc_closure *cb) { + secure_endpoint *ep = (secure_endpoint *)secure_ep; + ep->read_cb = cb; + ep->read_buffer = slices; + gpr_slice_buffer_reset_and_unref(ep->read_buffer); + + SECURE_ENDPOINT_REF(ep, "read"); + if (ep->leftover_bytes.count) { + gpr_slice_buffer_swap(&ep->leftover_bytes, &ep->source_buffer); + GPR_ASSERT(ep->leftover_bytes.count == 0); + on_read(exec_ctx, ep, 1); + return; + } + + grpc_endpoint_read(exec_ctx, ep->wrapped_ep, &ep->source_buffer, + &ep->on_read); +} + +static void flush_write_staging_buffer(secure_endpoint *ep, uint8_t **cur, + uint8_t **end) { + gpr_slice_buffer_add(&ep->output_buffer, ep->write_staging_buffer); + ep->write_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE); + *cur = GPR_SLICE_START_PTR(ep->write_staging_buffer); + *end = GPR_SLICE_END_PTR(ep->write_staging_buffer); +} + +static void endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep, + gpr_slice_buffer *slices, grpc_closure *cb) { + unsigned i; + tsi_result result = TSI_OK; + secure_endpoint *ep = (secure_endpoint *)secure_ep; + uint8_t *cur = GPR_SLICE_START_PTR(ep->write_staging_buffer); + uint8_t *end = GPR_SLICE_END_PTR(ep->write_staging_buffer); + + gpr_slice_buffer_reset_and_unref(&ep->output_buffer); + + if (grpc_trace_secure_endpoint) { + for (i = 0; i < slices->count; i++) { + char *data = + gpr_dump_slice(slices->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII); + gpr_log(GPR_DEBUG, "WRITE %p: %s", ep, data); + gpr_free(data); + } + } + + for (i = 0; i < slices->count; i++) { + gpr_slice plain = slices->slices[i]; + uint8_t *message_bytes = GPR_SLICE_START_PTR(plain); + size_t message_size = GPR_SLICE_LENGTH(plain); + while (message_size > 0) { + size_t protected_buffer_size_to_send = (size_t)(end - cur); + size_t processed_message_size = message_size; + gpr_mu_lock(&ep->protector_mu); + result = tsi_frame_protector_protect(ep->protector, message_bytes, + &processed_message_size, cur, + &protected_buffer_size_to_send); + gpr_mu_unlock(&ep->protector_mu); + if (result != TSI_OK) { + gpr_log(GPR_ERROR, "Encryption error: %s", + tsi_result_to_string(result)); + break; + } + message_bytes += processed_message_size; + message_size -= processed_message_size; + cur += protected_buffer_size_to_send; + + if (cur == end) { + flush_write_staging_buffer(ep, &cur, &end); + } + } + if (result != TSI_OK) break; + } + if (result == TSI_OK) { + size_t still_pending_size; + do { + size_t protected_buffer_size_to_send = (size_t)(end - cur); + gpr_mu_lock(&ep->protector_mu); + result = tsi_frame_protector_protect_flush(ep->protector, cur, + &protected_buffer_size_to_send, + &still_pending_size); + gpr_mu_unlock(&ep->protector_mu); + if (result != TSI_OK) break; + cur += protected_buffer_size_to_send; + if (cur == end) { + flush_write_staging_buffer(ep, &cur, &end); + } + } while (still_pending_size > 0); + if (cur != GPR_SLICE_START_PTR(ep->write_staging_buffer)) { + gpr_slice_buffer_add( + &ep->output_buffer, + gpr_slice_split_head( + &ep->write_staging_buffer, + (size_t)(cur - GPR_SLICE_START_PTR(ep->write_staging_buffer)))); + } + } + + if (result != TSI_OK) { + /* TODO(yangg) do different things according to the error type? */ + gpr_slice_buffer_reset_and_unref(&ep->output_buffer); + grpc_exec_ctx_enqueue(exec_ctx, cb, false, NULL); + return; + } + + grpc_endpoint_write(exec_ctx, ep->wrapped_ep, &ep->output_buffer, cb); +} + +static void endpoint_shutdown(grpc_exec_ctx *exec_ctx, + grpc_endpoint *secure_ep) { + secure_endpoint *ep = (secure_endpoint *)secure_ep; + grpc_endpoint_shutdown(exec_ctx, ep->wrapped_ep); +} + +static void endpoint_destroy(grpc_exec_ctx *exec_ctx, + grpc_endpoint *secure_ep) { + secure_endpoint *ep = (secure_endpoint *)secure_ep; + SECURE_ENDPOINT_UNREF(exec_ctx, ep, "destroy"); +} + +static void endpoint_add_to_pollset(grpc_exec_ctx *exec_ctx, + grpc_endpoint *secure_ep, + grpc_pollset *pollset) { + secure_endpoint *ep = (secure_endpoint *)secure_ep; + grpc_endpoint_add_to_pollset(exec_ctx, ep->wrapped_ep, pollset); +} + +static void endpoint_add_to_pollset_set(grpc_exec_ctx *exec_ctx, + grpc_endpoint *secure_ep, + grpc_pollset_set *pollset_set) { + secure_endpoint *ep = (secure_endpoint *)secure_ep; + grpc_endpoint_add_to_pollset_set(exec_ctx, ep->wrapped_ep, pollset_set); +} + +static char *endpoint_get_peer(grpc_endpoint *secure_ep) { + secure_endpoint *ep = (secure_endpoint *)secure_ep; + return grpc_endpoint_get_peer(ep->wrapped_ep); +} + +static const grpc_endpoint_vtable vtable = { + endpoint_read, endpoint_write, + endpoint_add_to_pollset, endpoint_add_to_pollset_set, + endpoint_shutdown, endpoint_destroy, + endpoint_get_peer}; + +grpc_endpoint *grpc_secure_endpoint_create( + struct tsi_frame_protector *protector, grpc_endpoint *transport, + gpr_slice *leftover_slices, size_t leftover_nslices) { + size_t i; + secure_endpoint *ep = (secure_endpoint *)gpr_malloc(sizeof(secure_endpoint)); + ep->base.vtable = &vtable; + ep->wrapped_ep = transport; + ep->protector = protector; + gpr_slice_buffer_init(&ep->leftover_bytes); + for (i = 0; i < leftover_nslices; i++) { + gpr_slice_buffer_add(&ep->leftover_bytes, + gpr_slice_ref(leftover_slices[i])); + } + ep->write_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE); + ep->read_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE); + gpr_slice_buffer_init(&ep->output_buffer); + gpr_slice_buffer_init(&ep->source_buffer); + ep->read_buffer = NULL; + grpc_closure_init(&ep->on_read, on_read, ep); + gpr_mu_init(&ep->protector_mu); + gpr_ref_init(&ep->ref, 1); + return &ep->base; +} diff --git a/src/core/lib/security/secure_endpoint.h b/src/core/lib/security/secure_endpoint.h new file mode 100644 index 0000000000..7368f8424b --- /dev/null +++ b/src/core/lib/security/secure_endpoint.h @@ -0,0 +1,49 @@ +/* + * + * Copyright 2015-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_SECURITY_SECURE_ENDPOINT_H +#define GRPC_CORE_SECURITY_SECURE_ENDPOINT_H + +#include +#include "src/core/iomgr/endpoint.h" + +struct tsi_frame_protector; + +extern int grpc_trace_secure_endpoint; + +/* Takes ownership of protector and to_wrap, and refs leftover_slices. */ +grpc_endpoint *grpc_secure_endpoint_create( + struct tsi_frame_protector *protector, grpc_endpoint *to_wrap, + gpr_slice *leftover_slices, size_t leftover_nslices); + +#endif /* GRPC_CORE_SECURITY_SECURE_ENDPOINT_H */ diff --git a/src/core/lib/security/security_connector.c b/src/core/lib/security/security_connector.c new file mode 100644 index 0000000000..fbec263eed --- /dev/null +++ b/src/core/lib/security/security_connector.c @@ -0,0 +1,812 @@ +/* + * + * Copyright 2015-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/security/security_connector.h" + +#include +#include + +#include +#include +#include +#include +#include + +#include "src/core/security/credentials.h" +#include "src/core/security/handshake.h" +#include "src/core/security/secure_endpoint.h" +#include "src/core/security/security_context.h" +#include "src/core/support/env.h" +#include "src/core/support/load_file.h" +#include "src/core/support/string.h" +#include "src/core/transport/chttp2/alpn.h" +#include "src/core/tsi/fake_transport_security.h" +#include "src/core/tsi/ssl_transport_security.h" + +/* -- Constants. -- */ + +#ifndef INSTALL_PREFIX +static const char *installed_roots_path = "/usr/share/grpc/roots.pem"; +#else +static const char *installed_roots_path = + INSTALL_PREFIX "/share/grpc/roots.pem"; +#endif + +/* -- Overridden default roots. -- */ + +static grpc_ssl_roots_override_callback ssl_roots_override_cb = NULL; + +void grpc_set_ssl_roots_override_callback(grpc_ssl_roots_override_callback cb) { + ssl_roots_override_cb = cb; +} + +/* -- Cipher suites. -- */ + +/* Defines the cipher suites that we accept by default. All these cipher suites + are compliant with HTTP2. */ +#define GRPC_SSL_CIPHER_SUITES \ + "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-" \ + "SHA384:ECDHE-RSA-AES256-GCM-SHA384" + +static gpr_once cipher_suites_once = GPR_ONCE_INIT; +static const char *cipher_suites = NULL; + +static void init_cipher_suites(void) { + char *overridden = gpr_getenv("GRPC_SSL_CIPHER_SUITES"); + cipher_suites = overridden != NULL ? overridden : GRPC_SSL_CIPHER_SUITES; +} + +static const char *ssl_cipher_suites(void) { + gpr_once_init(&cipher_suites_once, init_cipher_suites); + return cipher_suites; +} + +/* -- Common methods. -- */ + +/* Returns the first property with that name. */ +const tsi_peer_property *tsi_peer_get_property_by_name(const tsi_peer *peer, + const char *name) { + size_t i; + if (peer == NULL) return NULL; + for (i = 0; i < peer->property_count; i++) { + const tsi_peer_property *property = &peer->properties[i]; + if (name == NULL && property->name == NULL) { + return property; + } + if (name != NULL && property->name != NULL && + strcmp(property->name, name) == 0) { + return property; + } + } + return NULL; +} + +void grpc_server_security_connector_shutdown( + grpc_exec_ctx *exec_ctx, grpc_server_security_connector *connector) { + grpc_security_connector_handshake_list *tmp; + gpr_mu_lock(&connector->mu); + while (connector->handshaking_handshakes) { + tmp = connector->handshaking_handshakes; + grpc_security_handshake_shutdown( + exec_ctx, connector->handshaking_handshakes->handshake); + connector->handshaking_handshakes = tmp->next; + gpr_free(tmp); + } + gpr_mu_unlock(&connector->mu); +} + +void grpc_channel_security_connector_do_handshake( + grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc, + grpc_endpoint *nonsecure_endpoint, grpc_security_handshake_done_cb cb, + void *user_data) { + if (sc == NULL || nonsecure_endpoint == NULL) { + cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL); + } else { + sc->do_handshake(exec_ctx, sc, nonsecure_endpoint, cb, user_data); + } +} + +void grpc_server_security_connector_do_handshake( + grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc, + grpc_tcp_server_acceptor *acceptor, grpc_endpoint *nonsecure_endpoint, + grpc_security_handshake_done_cb cb, void *user_data) { + if (sc == NULL || nonsecure_endpoint == NULL) { + cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL); + } else { + sc->do_handshake(exec_ctx, sc, acceptor, nonsecure_endpoint, cb, user_data); + } +} + +void grpc_security_connector_check_peer(grpc_exec_ctx *exec_ctx, + grpc_security_connector *sc, + tsi_peer peer, + grpc_security_peer_check_cb cb, + void *user_data) { + if (sc == NULL) { + cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL); + tsi_peer_destruct(&peer); + } else { + sc->vtable->check_peer(exec_ctx, sc, peer, cb, user_data); + } +} + +void grpc_channel_security_connector_check_call_host( + grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc, + const char *host, grpc_auth_context *auth_context, + grpc_security_call_host_check_cb cb, void *user_data) { + if (sc == NULL || sc->check_call_host == NULL) { + cb(exec_ctx, user_data, GRPC_SECURITY_ERROR); + } else { + sc->check_call_host(exec_ctx, sc, host, auth_context, cb, user_data); + } +} + +#ifdef GRPC_SECURITY_CONNECTOR_REFCOUNT_DEBUG +grpc_security_connector *grpc_security_connector_ref( + grpc_security_connector *sc, const char *file, int line, + const char *reason) { + if (sc == NULL) return NULL; + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, + "SECURITY_CONNECTOR:%p ref %d -> %d %s", sc, + (int)sc->refcount.count, (int)sc->refcount.count + 1, reason); +#else +grpc_security_connector *grpc_security_connector_ref( + grpc_security_connector *sc) { + if (sc == NULL) return NULL; +#endif + gpr_ref(&sc->refcount); + return sc; +} + +#ifdef GRPC_SECURITY_CONNECTOR_REFCOUNT_DEBUG +void grpc_security_connector_unref(grpc_security_connector *sc, + const char *file, int line, + const char *reason) { + if (sc == NULL) return; + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, + "SECURITY_CONNECTOR:%p unref %d -> %d %s", sc, + (int)sc->refcount.count, (int)sc->refcount.count - 1, reason); +#else +void grpc_security_connector_unref(grpc_security_connector *sc) { + if (sc == NULL) return; +#endif + if (gpr_unref(&sc->refcount)) sc->vtable->destroy(sc); +} + +static void connector_pointer_arg_destroy(void *p) { + GRPC_SECURITY_CONNECTOR_UNREF(p, "connector_pointer_arg"); +} + +static void *connector_pointer_arg_copy(void *p) { + return GRPC_SECURITY_CONNECTOR_REF(p, "connector_pointer_arg"); +} + +static int connector_pointer_cmp(void *a, void *b) { return GPR_ICMP(a, b); } + +static const grpc_arg_pointer_vtable connector_pointer_vtable = { + connector_pointer_arg_copy, connector_pointer_arg_destroy, + connector_pointer_cmp}; + +grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc) { + grpc_arg result; + result.type = GRPC_ARG_POINTER; + result.key = GRPC_SECURITY_CONNECTOR_ARG; + result.value.pointer.vtable = &connector_pointer_vtable; + result.value.pointer.p = sc; + return result; +} + +grpc_security_connector *grpc_security_connector_from_arg(const grpc_arg *arg) { + if (strcmp(arg->key, GRPC_SECURITY_CONNECTOR_ARG)) return NULL; + if (arg->type != GRPC_ARG_POINTER) { + gpr_log(GPR_ERROR, "Invalid type %d for arg %s", arg->type, + GRPC_SECURITY_CONNECTOR_ARG); + return NULL; + } + return arg->value.pointer.p; +} + +grpc_security_connector *grpc_find_security_connector_in_args( + const grpc_channel_args *args) { + size_t i; + if (args == NULL) return NULL; + for (i = 0; i < args->num_args; i++) { + grpc_security_connector *sc = + grpc_security_connector_from_arg(&args->args[i]); + if (sc != NULL) return sc; + } + return NULL; +} + +/* -- Fake implementation. -- */ + +static void fake_channel_destroy(grpc_security_connector *sc) { + grpc_channel_security_connector *c = (grpc_channel_security_connector *)sc; + grpc_call_credentials_unref(c->request_metadata_creds); + gpr_free(sc); +} + +static void fake_server_destroy(grpc_security_connector *sc) { + grpc_server_security_connector *c = (grpc_server_security_connector *)sc; + gpr_mu_destroy(&c->mu); + gpr_free(sc); +} + +static void fake_check_peer(grpc_exec_ctx *exec_ctx, + grpc_security_connector *sc, tsi_peer peer, + grpc_security_peer_check_cb cb, void *user_data) { + const char *prop_name; + grpc_security_status status = GRPC_SECURITY_OK; + grpc_auth_context *auth_context = NULL; + if (peer.property_count != 1) { + gpr_log(GPR_ERROR, "Fake peers should only have 1 property."); + status = GRPC_SECURITY_ERROR; + goto end; + } + prop_name = peer.properties[0].name; + if (prop_name == NULL || + strcmp(prop_name, TSI_CERTIFICATE_TYPE_PEER_PROPERTY)) { + gpr_log(GPR_ERROR, "Unexpected property in fake peer: %s.", + prop_name == NULL ? "" : prop_name); + status = GRPC_SECURITY_ERROR; + goto end; + } + if (strncmp(peer.properties[0].value.data, TSI_FAKE_CERTIFICATE_TYPE, + peer.properties[0].value.length)) { + gpr_log(GPR_ERROR, "Invalid value for cert type property."); + status = GRPC_SECURITY_ERROR; + goto end; + } + auth_context = grpc_auth_context_create(NULL); + grpc_auth_context_add_cstring_property( + auth_context, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME, + GRPC_FAKE_TRANSPORT_SECURITY_TYPE); + +end: + cb(exec_ctx, user_data, status, auth_context); + grpc_auth_context_unref(auth_context); + tsi_peer_destruct(&peer); +} + +static void fake_channel_check_call_host(grpc_exec_ctx *exec_ctx, + grpc_channel_security_connector *sc, + const char *host, + grpc_auth_context *auth_context, + grpc_security_call_host_check_cb cb, + void *user_data) { + cb(exec_ctx, user_data, GRPC_SECURITY_OK); +} + +static void fake_channel_do_handshake(grpc_exec_ctx *exec_ctx, + grpc_channel_security_connector *sc, + grpc_endpoint *nonsecure_endpoint, + grpc_security_handshake_done_cb cb, + void *user_data) { + grpc_do_security_handshake(exec_ctx, tsi_create_fake_handshaker(1), &sc->base, + true, nonsecure_endpoint, cb, user_data); +} + +static void fake_server_do_handshake(grpc_exec_ctx *exec_ctx, + grpc_server_security_connector *sc, + grpc_tcp_server_acceptor *acceptor, + grpc_endpoint *nonsecure_endpoint, + grpc_security_handshake_done_cb cb, + void *user_data) { + grpc_do_security_handshake(exec_ctx, tsi_create_fake_handshaker(0), &sc->base, + false, nonsecure_endpoint, cb, user_data); +} + +static grpc_security_connector_vtable fake_channel_vtable = { + fake_channel_destroy, fake_check_peer}; + +static grpc_security_connector_vtable fake_server_vtable = {fake_server_destroy, + fake_check_peer}; + +grpc_channel_security_connector *grpc_fake_channel_security_connector_create( + grpc_call_credentials *request_metadata_creds) { + grpc_channel_security_connector *c = gpr_malloc(sizeof(*c)); + memset(c, 0, sizeof(*c)); + gpr_ref_init(&c->base.refcount, 1); + c->base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME; + c->base.vtable = &fake_channel_vtable; + c->request_metadata_creds = grpc_call_credentials_ref(request_metadata_creds); + c->check_call_host = fake_channel_check_call_host; + c->do_handshake = fake_channel_do_handshake; + return c; +} + +grpc_server_security_connector *grpc_fake_server_security_connector_create( + void) { + grpc_server_security_connector *c = + gpr_malloc(sizeof(grpc_server_security_connector)); + memset(c, 0, sizeof(*c)); + gpr_ref_init(&c->base.refcount, 1); + c->base.vtable = &fake_server_vtable; + c->base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME; + c->do_handshake = fake_server_do_handshake; + gpr_mu_init(&c->mu); + return c; +} + +/* --- Ssl implementation. --- */ + +typedef struct { + grpc_channel_security_connector base; + tsi_ssl_handshaker_factory *handshaker_factory; + char *target_name; + char *overridden_target_name; +} grpc_ssl_channel_security_connector; + +typedef struct { + grpc_server_security_connector base; + tsi_ssl_handshaker_factory *handshaker_factory; +} grpc_ssl_server_security_connector; + +static void ssl_channel_destroy(grpc_security_connector *sc) { + grpc_ssl_channel_security_connector *c = + (grpc_ssl_channel_security_connector *)sc; + grpc_call_credentials_unref(c->base.request_metadata_creds); + if (c->handshaker_factory != NULL) { + tsi_ssl_handshaker_factory_destroy(c->handshaker_factory); + } + if (c->target_name != NULL) gpr_free(c->target_name); + if (c->overridden_target_name != NULL) gpr_free(c->overridden_target_name); + gpr_free(sc); +} + +static void ssl_server_destroy(grpc_security_connector *sc) { + grpc_ssl_server_security_connector *c = + (grpc_ssl_server_security_connector *)sc; + + if (c->handshaker_factory != NULL) { + tsi_ssl_handshaker_factory_destroy(c->handshaker_factory); + } + gpr_mu_destroy(&c->base.mu); + gpr_free(sc); +} + +static grpc_security_status ssl_create_handshaker( + tsi_ssl_handshaker_factory *handshaker_factory, bool is_client, + const char *peer_name, tsi_handshaker **handshaker) { + tsi_result result = TSI_OK; + if (handshaker_factory == NULL) return GRPC_SECURITY_ERROR; + result = tsi_ssl_handshaker_factory_create_handshaker( + handshaker_factory, is_client ? peer_name : NULL, handshaker); + if (result != TSI_OK) { + gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.", + tsi_result_to_string(result)); + return GRPC_SECURITY_ERROR; + } + return GRPC_SECURITY_OK; +} + +static void ssl_channel_do_handshake(grpc_exec_ctx *exec_ctx, + grpc_channel_security_connector *sc, + grpc_endpoint *nonsecure_endpoint, + grpc_security_handshake_done_cb cb, + void *user_data) { + grpc_ssl_channel_security_connector *c = + (grpc_ssl_channel_security_connector *)sc; + tsi_handshaker *handshaker; + grpc_security_status status = ssl_create_handshaker( + c->handshaker_factory, true, + c->overridden_target_name != NULL ? c->overridden_target_name + : c->target_name, + &handshaker); + if (status != GRPC_SECURITY_OK) { + cb(exec_ctx, user_data, status, NULL, NULL); + } else { + grpc_do_security_handshake(exec_ctx, handshaker, &sc->base, true, + nonsecure_endpoint, cb, user_data); + } +} + +static void ssl_server_do_handshake(grpc_exec_ctx *exec_ctx, + grpc_server_security_connector *sc, + grpc_tcp_server_acceptor *acceptor, + grpc_endpoint *nonsecure_endpoint, + grpc_security_handshake_done_cb cb, + void *user_data) { + grpc_ssl_server_security_connector *c = + (grpc_ssl_server_security_connector *)sc; + tsi_handshaker *handshaker; + grpc_security_status status = + ssl_create_handshaker(c->handshaker_factory, false, NULL, &handshaker); + if (status != GRPC_SECURITY_OK) { + cb(exec_ctx, user_data, status, NULL, NULL); + } else { + grpc_do_security_handshake(exec_ctx, handshaker, &sc->base, false, + nonsecure_endpoint, cb, user_data); + } +} + +static int ssl_host_matches_name(const tsi_peer *peer, const char *peer_name) { + char *allocated_name = NULL; + int r; + + if (strchr(peer_name, ':') != NULL) { + char *ignored_port; + gpr_split_host_port(peer_name, &allocated_name, &ignored_port); + gpr_free(ignored_port); + peer_name = allocated_name; + if (!peer_name) return 0; + } + r = tsi_ssl_peer_matches_name(peer, peer_name); + gpr_free(allocated_name); + return r; +} + +grpc_auth_context *tsi_ssl_peer_to_auth_context(const tsi_peer *peer) { + size_t i; + grpc_auth_context *ctx = NULL; + const char *peer_identity_property_name = NULL; + + /* The caller has checked the certificate type property. */ + GPR_ASSERT(peer->property_count >= 1); + ctx = grpc_auth_context_create(NULL); + grpc_auth_context_add_cstring_property( + ctx, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME, + GRPC_SSL_TRANSPORT_SECURITY_TYPE); + for (i = 0; i < peer->property_count; i++) { + const tsi_peer_property *prop = &peer->properties[i]; + if (prop->name == NULL) continue; + if (strcmp(prop->name, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY) == 0) { + /* If there is no subject alt name, have the CN as the identity. */ + if (peer_identity_property_name == NULL) { + peer_identity_property_name = GRPC_X509_CN_PROPERTY_NAME; + } + grpc_auth_context_add_property(ctx, GRPC_X509_CN_PROPERTY_NAME, + prop->value.data, prop->value.length); + } else if (strcmp(prop->name, + TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) { + peer_identity_property_name = GRPC_X509_SAN_PROPERTY_NAME; + grpc_auth_context_add_property(ctx, GRPC_X509_SAN_PROPERTY_NAME, + prop->value.data, prop->value.length); + } else if (strcmp(prop->name, TSI_X509_PEM_CERT_PROPERTY) == 0) { + grpc_auth_context_add_property(ctx, GRPC_X509_PEM_CERT_PROPERTY_NAME, + prop->value.data, prop->value.length); + } + } + if (peer_identity_property_name != NULL) { + GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name( + ctx, peer_identity_property_name) == 1); + } + return ctx; +} + +static grpc_security_status ssl_check_peer(grpc_security_connector *sc, + const char *peer_name, + const tsi_peer *peer, + grpc_auth_context **auth_context) { + /* Check the ALPN. */ + const tsi_peer_property *p = + tsi_peer_get_property_by_name(peer, TSI_SSL_ALPN_SELECTED_PROTOCOL); + if (p == NULL) { + gpr_log(GPR_ERROR, "Missing selected ALPN property."); + return GRPC_SECURITY_ERROR; + } + if (!grpc_chttp2_is_alpn_version_supported(p->value.data, p->value.length)) { + gpr_log(GPR_ERROR, "Invalid ALPN value."); + return GRPC_SECURITY_ERROR; + } + + /* Check the peer name if specified. */ + if (peer_name != NULL && !ssl_host_matches_name(peer, peer_name)) { + gpr_log(GPR_ERROR, "Peer name %s is not in peer certificate", peer_name); + return GRPC_SECURITY_ERROR; + } + *auth_context = tsi_ssl_peer_to_auth_context(peer); + return GRPC_SECURITY_OK; +} + +static void ssl_channel_check_peer(grpc_exec_ctx *exec_ctx, + grpc_security_connector *sc, tsi_peer peer, + grpc_security_peer_check_cb cb, + void *user_data) { + grpc_ssl_channel_security_connector *c = + (grpc_ssl_channel_security_connector *)sc; + grpc_security_status status; + grpc_auth_context *auth_context = NULL; + status = ssl_check_peer(sc, c->overridden_target_name != NULL + ? c->overridden_target_name + : c->target_name, + &peer, &auth_context); + cb(exec_ctx, user_data, status, auth_context); + grpc_auth_context_unref(auth_context); + tsi_peer_destruct(&peer); +} + +static void ssl_server_check_peer(grpc_exec_ctx *exec_ctx, + grpc_security_connector *sc, tsi_peer peer, + grpc_security_peer_check_cb cb, + void *user_data) { + grpc_auth_context *auth_context = NULL; + grpc_security_status status = ssl_check_peer(sc, NULL, &peer, &auth_context); + tsi_peer_destruct(&peer); + cb(exec_ctx, user_data, status, auth_context); + grpc_auth_context_unref(auth_context); +} + +static void add_shallow_auth_property_to_peer(tsi_peer *peer, + const grpc_auth_property *prop, + const char *tsi_prop_name) { + tsi_peer_property *tsi_prop = &peer->properties[peer->property_count++]; + tsi_prop->name = (char *)tsi_prop_name; + tsi_prop->value.data = prop->value; + tsi_prop->value.length = prop->value_length; +} + +tsi_peer tsi_shallow_peer_from_ssl_auth_context( + const grpc_auth_context *auth_context) { + size_t max_num_props = 0; + grpc_auth_property_iterator it; + const grpc_auth_property *prop; + tsi_peer peer; + memset(&peer, 0, sizeof(peer)); + + it = grpc_auth_context_property_iterator(auth_context); + while (grpc_auth_property_iterator_next(&it) != NULL) max_num_props++; + + if (max_num_props > 0) { + peer.properties = gpr_malloc(max_num_props * sizeof(tsi_peer_property)); + it = grpc_auth_context_property_iterator(auth_context); + while ((prop = grpc_auth_property_iterator_next(&it)) != NULL) { + if (strcmp(prop->name, GRPC_X509_SAN_PROPERTY_NAME) == 0) { + add_shallow_auth_property_to_peer( + &peer, prop, TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY); + } else if (strcmp(prop->name, GRPC_X509_CN_PROPERTY_NAME) == 0) { + add_shallow_auth_property_to_peer( + &peer, prop, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY); + } else if (strcmp(prop->name, GRPC_X509_PEM_CERT_PROPERTY_NAME) == 0) { + add_shallow_auth_property_to_peer(&peer, prop, + TSI_X509_PEM_CERT_PROPERTY); + } + } + } + return peer; +} + +void tsi_shallow_peer_destruct(tsi_peer *peer) { + if (peer->properties != NULL) gpr_free(peer->properties); +} + +static void ssl_channel_check_call_host(grpc_exec_ctx *exec_ctx, + grpc_channel_security_connector *sc, + const char *host, + grpc_auth_context *auth_context, + grpc_security_call_host_check_cb cb, + void *user_data) { + grpc_ssl_channel_security_connector *c = + (grpc_ssl_channel_security_connector *)sc; + grpc_security_status status = GRPC_SECURITY_ERROR; + tsi_peer peer = tsi_shallow_peer_from_ssl_auth_context(auth_context); + if (ssl_host_matches_name(&peer, host)) status = GRPC_SECURITY_OK; + + /* If the target name was overridden, then the original target_name was + 'checked' transitively during the previous peer check at the end of the + handshake. */ + if (c->overridden_target_name != NULL && strcmp(host, c->target_name) == 0) { + status = GRPC_SECURITY_OK; + } + cb(exec_ctx, user_data, status); + tsi_shallow_peer_destruct(&peer); +} + +static grpc_security_connector_vtable ssl_channel_vtable = { + ssl_channel_destroy, ssl_channel_check_peer}; + +static grpc_security_connector_vtable ssl_server_vtable = { + ssl_server_destroy, ssl_server_check_peer}; + +static gpr_slice compute_default_pem_root_certs_once(void) { + gpr_slice result = gpr_empty_slice(); + + /* First try to load the roots from the environment. */ + char *default_root_certs_path = + gpr_getenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR); + if (default_root_certs_path != NULL) { + result = gpr_load_file(default_root_certs_path, 0, NULL); + gpr_free(default_root_certs_path); + } + + /* Try overridden roots if needed. */ + grpc_ssl_roots_override_result ovrd_res = GRPC_SSL_ROOTS_OVERRIDE_FAIL; + if (GPR_SLICE_IS_EMPTY(result) && ssl_roots_override_cb != NULL) { + char *pem_root_certs = NULL; + ovrd_res = ssl_roots_override_cb(&pem_root_certs); + if (ovrd_res == GRPC_SSL_ROOTS_OVERRIDE_OK) { + GPR_ASSERT(pem_root_certs != NULL); + result = gpr_slice_new(pem_root_certs, strlen(pem_root_certs), gpr_free); + } + } + + /* Fall back to installed certs if needed. */ + if (GPR_SLICE_IS_EMPTY(result) && + ovrd_res != GRPC_SSL_ROOTS_OVERRIDE_FAIL_PERMANENTLY) { + result = gpr_load_file(installed_roots_path, 0, NULL); + } + return result; +} + +static gpr_slice default_pem_root_certs; + +static void init_default_pem_root_certs(void) { + default_pem_root_certs = compute_default_pem_root_certs_once(); +} + +gpr_slice grpc_get_default_ssl_roots_for_testing(void) { + return compute_default_pem_root_certs_once(); +} + +size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs) { + /* TODO(jboeuf@google.com): Maybe revisit the approach which consists in + loading all the roots once for the lifetime of the process. */ + static gpr_once once = GPR_ONCE_INIT; + gpr_once_init(&once, init_default_pem_root_certs); + *pem_root_certs = GPR_SLICE_START_PTR(default_pem_root_certs); + return GPR_SLICE_LENGTH(default_pem_root_certs); +} + +grpc_security_status grpc_ssl_channel_security_connector_create( + grpc_call_credentials *request_metadata_creds, + const grpc_ssl_config *config, const char *target_name, + const char *overridden_target_name, grpc_channel_security_connector **sc) { + size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions(); + const unsigned char **alpn_protocol_strings = + gpr_malloc(sizeof(const char *) * num_alpn_protocols); + unsigned char *alpn_protocol_string_lengths = + gpr_malloc(sizeof(unsigned char) * num_alpn_protocols); + tsi_result result = TSI_OK; + grpc_ssl_channel_security_connector *c; + size_t i; + const unsigned char *pem_root_certs; + size_t pem_root_certs_size; + char *port; + + for (i = 0; i < num_alpn_protocols; i++) { + alpn_protocol_strings[i] = + (const unsigned char *)grpc_chttp2_get_alpn_version_index(i); + alpn_protocol_string_lengths[i] = + (unsigned char)strlen(grpc_chttp2_get_alpn_version_index(i)); + } + + if (config == NULL || target_name == NULL) { + gpr_log(GPR_ERROR, "An ssl channel needs a config and a target name."); + goto error; + } + if (config->pem_root_certs == NULL) { + pem_root_certs_size = grpc_get_default_ssl_roots(&pem_root_certs); + if (pem_root_certs == NULL || pem_root_certs_size == 0) { + gpr_log(GPR_ERROR, "Could not get default pem root certs."); + goto error; + } + } else { + pem_root_certs = config->pem_root_certs; + pem_root_certs_size = config->pem_root_certs_size; + } + + c = gpr_malloc(sizeof(grpc_ssl_channel_security_connector)); + memset(c, 0, sizeof(grpc_ssl_channel_security_connector)); + + gpr_ref_init(&c->base.base.refcount, 1); + c->base.base.vtable = &ssl_channel_vtable; + c->base.base.url_scheme = GRPC_SSL_URL_SCHEME; + c->base.request_metadata_creds = + grpc_call_credentials_ref(request_metadata_creds); + c->base.check_call_host = ssl_channel_check_call_host; + c->base.do_handshake = ssl_channel_do_handshake; + gpr_split_host_port(target_name, &c->target_name, &port); + gpr_free(port); + if (overridden_target_name != NULL) { + c->overridden_target_name = gpr_strdup(overridden_target_name); + } + result = tsi_create_ssl_client_handshaker_factory( + config->pem_private_key, config->pem_private_key_size, + config->pem_cert_chain, config->pem_cert_chain_size, pem_root_certs, + pem_root_certs_size, ssl_cipher_suites(), alpn_protocol_strings, + alpn_protocol_string_lengths, (uint16_t)num_alpn_protocols, + &c->handshaker_factory); + if (result != TSI_OK) { + gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.", + tsi_result_to_string(result)); + ssl_channel_destroy(&c->base.base); + *sc = NULL; + goto error; + } + *sc = &c->base; + gpr_free((void *)alpn_protocol_strings); + gpr_free(alpn_protocol_string_lengths); + return GRPC_SECURITY_OK; + +error: + gpr_free((void *)alpn_protocol_strings); + gpr_free(alpn_protocol_string_lengths); + return GRPC_SECURITY_ERROR; +} + +grpc_security_status grpc_ssl_server_security_connector_create( + const grpc_ssl_server_config *config, grpc_server_security_connector **sc) { + size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions(); + const unsigned char **alpn_protocol_strings = + gpr_malloc(sizeof(const char *) * num_alpn_protocols); + unsigned char *alpn_protocol_string_lengths = + gpr_malloc(sizeof(unsigned char) * num_alpn_protocols); + tsi_result result = TSI_OK; + grpc_ssl_server_security_connector *c; + size_t i; + + for (i = 0; i < num_alpn_protocols; i++) { + alpn_protocol_strings[i] = + (const unsigned char *)grpc_chttp2_get_alpn_version_index(i); + alpn_protocol_string_lengths[i] = + (unsigned char)strlen(grpc_chttp2_get_alpn_version_index(i)); + } + + if (config == NULL || config->num_key_cert_pairs == 0) { + gpr_log(GPR_ERROR, "An SSL server needs a key and a cert."); + goto error; + } + c = gpr_malloc(sizeof(grpc_ssl_server_security_connector)); + memset(c, 0, sizeof(grpc_ssl_server_security_connector)); + + gpr_ref_init(&c->base.base.refcount, 1); + c->base.base.url_scheme = GRPC_SSL_URL_SCHEME; + c->base.base.vtable = &ssl_server_vtable; + result = tsi_create_ssl_server_handshaker_factory( + (const unsigned char **)config->pem_private_keys, + config->pem_private_keys_sizes, + (const unsigned char **)config->pem_cert_chains, + config->pem_cert_chains_sizes, config->num_key_cert_pairs, + config->pem_root_certs, config->pem_root_certs_size, + config->force_client_auth, ssl_cipher_suites(), alpn_protocol_strings, + alpn_protocol_string_lengths, (uint16_t)num_alpn_protocols, + &c->handshaker_factory); + if (result != TSI_OK) { + gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.", + tsi_result_to_string(result)); + ssl_server_destroy(&c->base.base); + *sc = NULL; + goto error; + } + gpr_mu_init(&c->base.mu); + c->base.do_handshake = ssl_server_do_handshake; + *sc = &c->base; + gpr_free((void *)alpn_protocol_strings); + gpr_free(alpn_protocol_string_lengths); + return GRPC_SECURITY_OK; + +error: + gpr_free((void *)alpn_protocol_strings); + gpr_free(alpn_protocol_string_lengths); + return GRPC_SECURITY_ERROR; +} diff --git a/src/core/lib/security/security_connector.h b/src/core/lib/security/security_connector.h new file mode 100644 index 0000000000..6f915ebb9d --- /dev/null +++ b/src/core/lib/security/security_connector.h @@ -0,0 +1,266 @@ +/* + * + * Copyright 2015-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_SECURITY_SECURITY_CONNECTOR_H +#define GRPC_CORE_SECURITY_SECURITY_CONNECTOR_H + +#include +#include "src/core/iomgr/endpoint.h" +#include "src/core/iomgr/tcp_server.h" +#include "src/core/tsi/transport_security_interface.h" + +/* --- status enum. --- */ + +typedef enum { GRPC_SECURITY_OK = 0, GRPC_SECURITY_ERROR } grpc_security_status; + +/* --- URL schemes. --- */ + +#define GRPC_SSL_URL_SCHEME "https" +#define GRPC_FAKE_SECURITY_URL_SCHEME "http+fake_security" + +/* --- security_connector object. --- + + A security connector object represents away to configure the underlying + transport security mechanism and check the resulting trusted peer. */ + +typedef struct grpc_security_connector grpc_security_connector; + +#define GRPC_SECURITY_CONNECTOR_ARG "grpc.security_connector" + +typedef void (*grpc_security_peer_check_cb)(grpc_exec_ctx *exec_ctx, + void *user_data, + grpc_security_status status, + grpc_auth_context *auth_context); + +/* Ownership of the secure_endpoint is transfered. */ +typedef void (*grpc_security_handshake_done_cb)( + grpc_exec_ctx *exec_ctx, void *user_data, grpc_security_status status, + grpc_endpoint *secure_endpoint, grpc_auth_context *auth_context); + +typedef struct { + void (*destroy)(grpc_security_connector *sc); + void (*check_peer)(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc, + tsi_peer peer, grpc_security_peer_check_cb cb, + void *user_data); +} grpc_security_connector_vtable; + +typedef struct grpc_security_connector_handshake_list { + void *handshake; + struct grpc_security_connector_handshake_list *next; +} grpc_security_connector_handshake_list; + +struct grpc_security_connector { + const grpc_security_connector_vtable *vtable; + gpr_refcount refcount; + const char *url_scheme; +}; + +/* Refcounting. */ +#ifdef GRPC_SECURITY_CONNECTOR_REFCOUNT_DEBUG +#define GRPC_SECURITY_CONNECTOR_REF(p, r) \ + grpc_security_connector_ref((p), __FILE__, __LINE__, (r)) +#define GRPC_SECURITY_CONNECTOR_UNREF(p, r) \ + grpc_security_connector_unref((p), __FILE__, __LINE__, (r)) +grpc_security_connector *grpc_security_connector_ref( + grpc_security_connector *policy, const char *file, int line, + const char *reason); +void grpc_security_connector_unref(grpc_security_connector *policy, + const char *file, int line, + const char *reason); +#else +#define GRPC_SECURITY_CONNECTOR_REF(p, r) grpc_security_connector_ref((p)) +#define GRPC_SECURITY_CONNECTOR_UNREF(p, r) grpc_security_connector_unref((p)) +grpc_security_connector *grpc_security_connector_ref( + grpc_security_connector *policy); +void grpc_security_connector_unref(grpc_security_connector *policy); +#endif + +/* Check the peer. Callee takes ownership of the peer object. + The callback will include the resulting auth_context. */ +void grpc_security_connector_check_peer(grpc_exec_ctx *exec_ctx, + grpc_security_connector *sc, + tsi_peer peer, + grpc_security_peer_check_cb cb, + void *user_data); + +/* Util to encapsulate the connector in a channel arg. */ +grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc); + +/* Util to get the connector from a channel arg. */ +grpc_security_connector *grpc_security_connector_from_arg(const grpc_arg *arg); + +/* Util to find the connector from channel args. */ +grpc_security_connector *grpc_find_security_connector_in_args( + const grpc_channel_args *args); + +/* --- channel_security_connector object. --- + + A channel security connector object represents away to configure the + underlying transport security mechanism on the client side. */ + +typedef struct grpc_channel_security_connector grpc_channel_security_connector; + +typedef void (*grpc_security_call_host_check_cb)(grpc_exec_ctx *exec_ctx, + void *user_data, + grpc_security_status status); + +struct grpc_channel_security_connector { + grpc_security_connector base; + grpc_call_credentials *request_metadata_creds; + void (*check_call_host)(grpc_exec_ctx *exec_ctx, + grpc_channel_security_connector *sc, const char *host, + grpc_auth_context *auth_context, + grpc_security_call_host_check_cb cb, void *user_data); + void (*do_handshake)(grpc_exec_ctx *exec_ctx, + grpc_channel_security_connector *sc, + grpc_endpoint *nonsecure_endpoint, + grpc_security_handshake_done_cb cb, void *user_data); +}; + +/* Checks that the host that will be set for a call is acceptable. */ +void grpc_channel_security_connector_check_call_host( + grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc, + const char *host, grpc_auth_context *auth_context, + grpc_security_call_host_check_cb cb, void *user_data); + +/* Handshake. */ +void grpc_channel_security_connector_do_handshake( + grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *connector, + grpc_endpoint *nonsecure_endpoint, grpc_security_handshake_done_cb cb, + void *user_data); + +/* --- server_security_connector object. --- + + A server security connector object represents away to configure the + underlying transport security mechanism on the server side. */ + +typedef struct grpc_server_security_connector grpc_server_security_connector; + +struct grpc_server_security_connector { + grpc_security_connector base; + gpr_mu mu; + grpc_security_connector_handshake_list *handshaking_handshakes; + const grpc_channel_args *channel_args; + void (*do_handshake)(grpc_exec_ctx *exec_ctx, + grpc_server_security_connector *sc, + grpc_tcp_server_acceptor *acceptor, + grpc_endpoint *nonsecure_endpoint, + grpc_security_handshake_done_cb cb, void *user_data); +}; + +void grpc_server_security_connector_do_handshake( + grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc, + grpc_tcp_server_acceptor *acceptor, grpc_endpoint *nonsecure_endpoint, + grpc_security_handshake_done_cb cb, void *user_data); + +void grpc_server_security_connector_shutdown( + grpc_exec_ctx *exec_ctx, grpc_server_security_connector *connector); + +/* --- Creation security connectors. --- */ + +/* For TESTING ONLY! + Creates a fake connector that emulates real channel security. */ +grpc_channel_security_connector *grpc_fake_channel_security_connector_create( + grpc_call_credentials *request_metadata_creds); + +/* For TESTING ONLY! + Creates a fake connector that emulates real server security. */ +grpc_server_security_connector *grpc_fake_server_security_connector_create( + void); + +/* Config for ssl clients. */ +typedef struct { + unsigned char *pem_private_key; + size_t pem_private_key_size; + unsigned char *pem_cert_chain; + size_t pem_cert_chain_size; + unsigned char *pem_root_certs; + size_t pem_root_certs_size; +} grpc_ssl_config; + +/* Creates an SSL channel_security_connector. + - request_metadata_creds is the credentials object which metadata + will be sent with each request. This parameter can be NULL. + - config is the SSL config to be used for the SSL channel establishment. + - is_client should be 0 for a server or a non-0 value for a client. + - secure_peer_name is the secure peer name that should be checked in + grpc_channel_security_connector_check_peer. This parameter may be NULL in + which case the peer name will not be checked. Note that if this parameter + is not NULL, then, pem_root_certs should not be NULL either. + - sc is a pointer on the connector to be created. + This function returns GRPC_SECURITY_OK in case of success or a + specific error code otherwise. +*/ +grpc_security_status grpc_ssl_channel_security_connector_create( + grpc_call_credentials *request_metadata_creds, + const grpc_ssl_config *config, const char *target_name, + const char *overridden_target_name, grpc_channel_security_connector **sc); + +/* Gets the default ssl roots. */ +size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs); + +/* Exposed for TESTING ONLY!. */ +gpr_slice grpc_get_default_ssl_roots_for_testing(void); + +/* Config for ssl servers. */ +typedef struct { + unsigned char **pem_private_keys; + size_t *pem_private_keys_sizes; + unsigned char **pem_cert_chains; + size_t *pem_cert_chains_sizes; + size_t num_key_cert_pairs; + unsigned char *pem_root_certs; + size_t pem_root_certs_size; + int force_client_auth; +} grpc_ssl_server_config; + +/* Creates an SSL server_security_connector. + - config is the SSL config to be used for the SSL channel establishment. + - sc is a pointer on the connector to be created. + This function returns GRPC_SECURITY_OK in case of success or a + specific error code otherwise. +*/ +grpc_security_status grpc_ssl_server_security_connector_create( + const grpc_ssl_server_config *config, grpc_server_security_connector **sc); + +/* Util. */ +const tsi_peer_property *tsi_peer_get_property_by_name(const tsi_peer *peer, + const char *name); + +/* Exposed for testing only. */ +grpc_auth_context *tsi_ssl_peer_to_auth_context(const tsi_peer *peer); +tsi_peer tsi_shallow_peer_from_ssl_auth_context( + const grpc_auth_context *auth_context); +void tsi_shallow_peer_destruct(tsi_peer *peer); + +#endif /* GRPC_CORE_SECURITY_SECURITY_CONNECTOR_H */ diff --git a/src/core/lib/security/security_context.c b/src/core/lib/security/security_context.c new file mode 100644 index 0000000000..f6afc0f633 --- /dev/null +++ b/src/core/lib/security/security_context.c @@ -0,0 +1,347 @@ +/* + * + * Copyright 2015-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 + +#include "src/core/security/security_context.h" +#include "src/core/support/string.h" +#include "src/core/surface/api_trace.h" +#include "src/core/surface/call.h" + +#include +#include +#include +#include + +/* --- grpc_call --- */ + +grpc_call_error grpc_call_set_credentials(grpc_call *call, + grpc_call_credentials *creds) { + grpc_client_security_context *ctx = NULL; + GRPC_API_TRACE("grpc_call_set_credentials(call=%p, creds=%p)", 2, + (call, creds)); + if (!grpc_call_is_client(call)) { + gpr_log(GPR_ERROR, "Method is client-side only."); + return GRPC_CALL_ERROR_NOT_ON_SERVER; + } + ctx = (grpc_client_security_context *)grpc_call_context_get( + call, GRPC_CONTEXT_SECURITY); + if (ctx == NULL) { + ctx = grpc_client_security_context_create(); + ctx->creds = grpc_call_credentials_ref(creds); + grpc_call_context_set(call, GRPC_CONTEXT_SECURITY, ctx, + grpc_client_security_context_destroy); + } else { + grpc_call_credentials_unref(ctx->creds); + ctx->creds = grpc_call_credentials_ref(creds); + } + return GRPC_CALL_OK; +} + +grpc_auth_context *grpc_call_auth_context(grpc_call *call) { + void *sec_ctx = grpc_call_context_get(call, GRPC_CONTEXT_SECURITY); + GRPC_API_TRACE("grpc_call_auth_context(call=%p)", 1, (call)); + if (sec_ctx == NULL) return NULL; + return grpc_call_is_client(call) + ? GRPC_AUTH_CONTEXT_REF( + ((grpc_client_security_context *)sec_ctx)->auth_context, + "grpc_call_auth_context client") + : GRPC_AUTH_CONTEXT_REF( + ((grpc_server_security_context *)sec_ctx)->auth_context, + "grpc_call_auth_context server"); +} + +void grpc_auth_context_release(grpc_auth_context *context) { + GRPC_API_TRACE("grpc_auth_context_release(context=%p)", 1, (context)); + GRPC_AUTH_CONTEXT_UNREF(context, "grpc_auth_context_unref"); +} + +/* --- grpc_client_security_context --- */ + +grpc_client_security_context *grpc_client_security_context_create(void) { + grpc_client_security_context *ctx = + gpr_malloc(sizeof(grpc_client_security_context)); + memset(ctx, 0, sizeof(grpc_client_security_context)); + return ctx; +} + +void grpc_client_security_context_destroy(void *ctx) { + grpc_client_security_context *c = (grpc_client_security_context *)ctx; + grpc_call_credentials_unref(c->creds); + GRPC_AUTH_CONTEXT_UNREF(c->auth_context, "client_security_context"); + gpr_free(ctx); +} + +/* --- grpc_server_security_context --- */ + +grpc_server_security_context *grpc_server_security_context_create(void) { + grpc_server_security_context *ctx = + gpr_malloc(sizeof(grpc_server_security_context)); + memset(ctx, 0, sizeof(grpc_server_security_context)); + return ctx; +} + +void grpc_server_security_context_destroy(void *ctx) { + grpc_server_security_context *c = (grpc_server_security_context *)ctx; + GRPC_AUTH_CONTEXT_UNREF(c->auth_context, "server_security_context"); + gpr_free(ctx); +} + +/* --- grpc_auth_context --- */ + +static grpc_auth_property_iterator empty_iterator = {NULL, 0, NULL}; + +grpc_auth_context *grpc_auth_context_create(grpc_auth_context *chained) { + grpc_auth_context *ctx = gpr_malloc(sizeof(grpc_auth_context)); + memset(ctx, 0, sizeof(grpc_auth_context)); + gpr_ref_init(&ctx->refcount, 1); + if (chained != NULL) { + ctx->chained = GRPC_AUTH_CONTEXT_REF(chained, "chained"); + ctx->peer_identity_property_name = + ctx->chained->peer_identity_property_name; + } + return ctx; +} + +#ifdef GRPC_AUTH_CONTEXT_REFCOUNT_DEBUG +grpc_auth_context *grpc_auth_context_ref(grpc_auth_context *ctx, + const char *file, int line, + const char *reason) { + if (ctx == NULL) return NULL; + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, + "AUTH_CONTEXT:%p ref %d -> %d %s", ctx, (int)ctx->refcount.count, + (int)ctx->refcount.count + 1, reason); +#else +grpc_auth_context *grpc_auth_context_ref(grpc_auth_context *ctx) { + if (ctx == NULL) return NULL; +#endif + gpr_ref(&ctx->refcount); + return ctx; +} + +#ifdef GRPC_AUTH_CONTEXT_REFCOUNT_DEBUG +void grpc_auth_context_unref(grpc_auth_context *ctx, const char *file, int line, + const char *reason) { + if (ctx == NULL) return; + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, + "AUTH_CONTEXT:%p unref %d -> %d %s", ctx, (int)ctx->refcount.count, + (int)ctx->refcount.count - 1, reason); +#else +void grpc_auth_context_unref(grpc_auth_context *ctx) { + if (ctx == NULL) return; +#endif + if (gpr_unref(&ctx->refcount)) { + size_t i; + GRPC_AUTH_CONTEXT_UNREF(ctx->chained, "chained"); + if (ctx->properties.array != NULL) { + for (i = 0; i < ctx->properties.count; i++) { + grpc_auth_property_reset(&ctx->properties.array[i]); + } + gpr_free(ctx->properties.array); + } + gpr_free(ctx); + } +} + +const char *grpc_auth_context_peer_identity_property_name( + const grpc_auth_context *ctx) { + GRPC_API_TRACE("grpc_auth_context_peer_identity_property_name(ctx=%p)", 1, + (ctx)); + return ctx->peer_identity_property_name; +} + +int grpc_auth_context_set_peer_identity_property_name(grpc_auth_context *ctx, + const char *name) { + grpc_auth_property_iterator it = + grpc_auth_context_find_properties_by_name(ctx, name); + const grpc_auth_property *prop = grpc_auth_property_iterator_next(&it); + GRPC_API_TRACE( + "grpc_auth_context_set_peer_identity_property_name(ctx=%p, name=%s)", 2, + (ctx, name)); + if (prop == NULL) { + gpr_log(GPR_ERROR, "Property name %s not found in auth context.", + name != NULL ? name : "NULL"); + return 0; + } + ctx->peer_identity_property_name = prop->name; + return 1; +} + +int grpc_auth_context_peer_is_authenticated(const grpc_auth_context *ctx) { + GRPC_API_TRACE("grpc_auth_context_peer_is_authenticated(ctx=%p)", 1, (ctx)); + return ctx->peer_identity_property_name == NULL ? 0 : 1; +} + +grpc_auth_property_iterator grpc_auth_context_property_iterator( + const grpc_auth_context *ctx) { + grpc_auth_property_iterator it = empty_iterator; + GRPC_API_TRACE("grpc_auth_context_property_iterator(ctx=%p)", 1, (ctx)); + if (ctx == NULL) return it; + it.ctx = ctx; + return it; +} + +const grpc_auth_property *grpc_auth_property_iterator_next( + grpc_auth_property_iterator *it) { + GRPC_API_TRACE("grpc_auth_property_iterator_next(it=%p)", 1, (it)); + if (it == NULL || it->ctx == NULL) return NULL; + while (it->index == it->ctx->properties.count) { + if (it->ctx->chained == NULL) return NULL; + it->ctx = it->ctx->chained; + it->index = 0; + } + if (it->name == NULL) { + return &it->ctx->properties.array[it->index++]; + } else { + while (it->index < it->ctx->properties.count) { + const grpc_auth_property *prop = &it->ctx->properties.array[it->index++]; + GPR_ASSERT(prop->name != NULL); + if (strcmp(it->name, prop->name) == 0) { + return prop; + } + } + /* We could not find the name, try another round. */ + return grpc_auth_property_iterator_next(it); + } +} + +grpc_auth_property_iterator grpc_auth_context_find_properties_by_name( + const grpc_auth_context *ctx, const char *name) { + grpc_auth_property_iterator it = empty_iterator; + GRPC_API_TRACE("grpc_auth_context_find_properties_by_name(ctx=%p, name=%s)", + 2, (ctx, name)); + if (ctx == NULL || name == NULL) return empty_iterator; + it.ctx = ctx; + it.name = name; + return it; +} + +grpc_auth_property_iterator grpc_auth_context_peer_identity( + const grpc_auth_context *ctx) { + GRPC_API_TRACE("grpc_auth_context_peer_identity(ctx=%p)", 1, (ctx)); + if (ctx == NULL) return empty_iterator; + return grpc_auth_context_find_properties_by_name( + ctx, ctx->peer_identity_property_name); +} + +static void ensure_auth_context_capacity(grpc_auth_context *ctx) { + if (ctx->properties.count == ctx->properties.capacity) { + ctx->properties.capacity = + GPR_MAX(ctx->properties.capacity + 8, ctx->properties.capacity * 2); + ctx->properties.array = + gpr_realloc(ctx->properties.array, + ctx->properties.capacity * sizeof(grpc_auth_property)); + } +} + +void grpc_auth_context_add_property(grpc_auth_context *ctx, const char *name, + const char *value, size_t value_length) { + grpc_auth_property *prop; + GRPC_API_TRACE( + "grpc_auth_context_add_property(ctx=%p, name=%s, value=%*.*s, " + "value_length=%lu)", + 6, (ctx, name, (int)value_length, (int)value_length, value, + (unsigned long)value_length)); + ensure_auth_context_capacity(ctx); + prop = &ctx->properties.array[ctx->properties.count++]; + prop->name = gpr_strdup(name); + prop->value = gpr_malloc(value_length + 1); + memcpy(prop->value, value, value_length); + prop->value[value_length] = '\0'; + prop->value_length = value_length; +} + +void grpc_auth_context_add_cstring_property(grpc_auth_context *ctx, + const char *name, + const char *value) { + grpc_auth_property *prop; + GRPC_API_TRACE( + "grpc_auth_context_add_cstring_property(ctx=%p, name=%s, value=%s)", 3, + (ctx, name, value)); + ensure_auth_context_capacity(ctx); + prop = &ctx->properties.array[ctx->properties.count++]; + prop->name = gpr_strdup(name); + prop->value = gpr_strdup(value); + prop->value_length = strlen(value); +} + +void grpc_auth_property_reset(grpc_auth_property *property) { + gpr_free(property->name); + gpr_free(property->value); + memset(property, 0, sizeof(grpc_auth_property)); +} + +static void auth_context_pointer_arg_destroy(void *p) { + GRPC_AUTH_CONTEXT_UNREF(p, "auth_context_pointer_arg"); +} + +static void *auth_context_pointer_arg_copy(void *p) { + return GRPC_AUTH_CONTEXT_REF(p, "auth_context_pointer_arg"); +} + +static int auth_context_pointer_cmp(void *a, void *b) { return GPR_ICMP(a, b); } + +static const grpc_arg_pointer_vtable auth_context_pointer_vtable = { + auth_context_pointer_arg_copy, auth_context_pointer_arg_destroy, + auth_context_pointer_cmp}; + +grpc_arg grpc_auth_context_to_arg(grpc_auth_context *p) { + grpc_arg arg; + memset(&arg, 0, sizeof(grpc_arg)); + arg.type = GRPC_ARG_POINTER; + arg.key = GRPC_AUTH_CONTEXT_ARG; + arg.value.pointer.p = p; + arg.value.pointer.vtable = &auth_context_pointer_vtable; + return arg; +} + +grpc_auth_context *grpc_auth_context_from_arg(const grpc_arg *arg) { + if (strcmp(arg->key, GRPC_AUTH_CONTEXT_ARG) != 0) return NULL; + if (arg->type != GRPC_ARG_POINTER) { + gpr_log(GPR_ERROR, "Invalid type %d for arg %s", arg->type, + GRPC_AUTH_CONTEXT_ARG); + return NULL; + } + return arg->value.pointer.p; +} + +grpc_auth_context *grpc_find_auth_context_in_args( + const grpc_channel_args *args) { + size_t i; + if (args == NULL) return NULL; + for (i = 0; i < args->num_args; i++) { + grpc_auth_context *p = grpc_auth_context_from_arg(&args->args[i]); + if (p != NULL) return p; + } + return NULL; +} diff --git a/src/core/lib/security/security_context.h b/src/core/lib/security/security_context.h new file mode 100644 index 0000000000..61601f538b --- /dev/null +++ b/src/core/lib/security/security_context.h @@ -0,0 +1,114 @@ +/* + * + * Copyright 2015-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_SECURITY_SECURITY_CONTEXT_H +#define GRPC_CORE_SECURITY_SECURITY_CONTEXT_H + +#include "src/core/iomgr/pollset.h" +#include "src/core/security/credentials.h" + +/* --- grpc_auth_context --- + + High level authentication context object. Can optionally be chained. */ + +/* Property names are always NULL terminated. */ + +typedef struct { + grpc_auth_property *array; + size_t count; + size_t capacity; +} grpc_auth_property_array; + +struct grpc_auth_context { + struct grpc_auth_context *chained; + grpc_auth_property_array properties; + gpr_refcount refcount; + const char *peer_identity_property_name; + grpc_pollset *pollset; +}; + +/* Creation. */ +grpc_auth_context *grpc_auth_context_create(grpc_auth_context *chained); + +/* Refcounting. */ +#ifdef GRPC_AUTH_CONTEXT_REFCOUNT_DEBUG +#define GRPC_AUTH_CONTEXT_REF(p, r) \ + grpc_auth_context_ref((p), __FILE__, __LINE__, (r)) +#define GRPC_AUTH_CONTEXT_UNREF(p, r) \ + grpc_auth_context_unref((p), __FILE__, __LINE__, (r)) +grpc_auth_context *grpc_auth_context_ref(grpc_auth_context *policy, + const char *file, int line, + const char *reason); +void grpc_auth_context_unref(grpc_auth_context *policy, const char *file, + int line, const char *reason); +#else +#define GRPC_AUTH_CONTEXT_REF(p, r) grpc_auth_context_ref((p)) +#define GRPC_AUTH_CONTEXT_UNREF(p, r) grpc_auth_context_unref((p)) +grpc_auth_context *grpc_auth_context_ref(grpc_auth_context *policy); +void grpc_auth_context_unref(grpc_auth_context *policy); +#endif + +void grpc_auth_property_reset(grpc_auth_property *property); + +/* --- grpc_client_security_context --- + + Internal client-side security context. */ + +typedef struct { + grpc_call_credentials *creds; + grpc_auth_context *auth_context; +} grpc_client_security_context; + +grpc_client_security_context *grpc_client_security_context_create(void); +void grpc_client_security_context_destroy(void *ctx); + +/* --- grpc_server_security_context --- + + Internal server-side security context. */ + +typedef struct { + grpc_auth_context *auth_context; +} grpc_server_security_context; + +grpc_server_security_context *grpc_server_security_context_create(void); +void grpc_server_security_context_destroy(void *ctx); + +/* --- Channel args for auth context --- */ +#define GRPC_AUTH_CONTEXT_ARG "grpc.auth_context" + +grpc_arg grpc_auth_context_to_arg(grpc_auth_context *c); +grpc_auth_context *grpc_auth_context_from_arg(const grpc_arg *arg); +grpc_auth_context *grpc_find_auth_context_in_args( + const grpc_channel_args *args); + +#endif /* GRPC_CORE_SECURITY_SECURITY_CONTEXT_H */ diff --git a/src/core/lib/security/server_auth_filter.c b/src/core/lib/security/server_auth_filter.c new file mode 100644 index 0000000000..f3c411d6d4 --- /dev/null +++ b/src/core/lib/security/server_auth_filter.c @@ -0,0 +1,264 @@ +/* + * + * Copyright 2015-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 + +#include "src/core/security/auth_filters.h" +#include "src/core/security/credentials.h" +#include "src/core/security/security_context.h" + +#include +#include + +typedef struct call_data { + grpc_metadata_batch *recv_initial_metadata; + /* Closure to call when finished with the auth_on_recv hook. */ + grpc_closure *on_done_recv; + /* Receive closures are chained: we inject this closure as the on_done_recv + up-call on transport_op, and remember to call our on_done_recv member after + handling it. */ + grpc_closure auth_on_recv; + grpc_transport_stream_op transport_op; + grpc_metadata_array md; + const grpc_metadata *consumed_md; + size_t num_consumed_md; + grpc_auth_context *auth_context; +} call_data; + +typedef struct channel_data { + grpc_auth_context *auth_context; + grpc_server_credentials *creds; +} channel_data; + +static grpc_metadata_array metadata_batch_to_md_array( + const grpc_metadata_batch *batch) { + grpc_linked_mdelem *l; + grpc_metadata_array result; + grpc_metadata_array_init(&result); + for (l = batch->list.head; l != NULL; l = l->next) { + grpc_metadata *usr_md = NULL; + grpc_mdelem *md = l->md; + grpc_mdstr *key = md->key; + grpc_mdstr *value = md->value; + if (result.count == result.capacity) { + result.capacity = GPR_MAX(result.capacity + 8, result.capacity * 2); + result.metadata = + gpr_realloc(result.metadata, result.capacity * sizeof(grpc_metadata)); + } + usr_md = &result.metadata[result.count++]; + usr_md->key = grpc_mdstr_as_c_string(key); + usr_md->value = grpc_mdstr_as_c_string(value); + usr_md->value_length = GPR_SLICE_LENGTH(value->slice); + } + return result; +} + +static grpc_mdelem *remove_consumed_md(void *user_data, grpc_mdelem *md) { + grpc_call_element *elem = user_data; + call_data *calld = elem->call_data; + size_t i; + for (i = 0; i < calld->num_consumed_md; i++) { + const grpc_metadata *consumed_md = &calld->consumed_md[i]; + /* Maybe we could do a pointer comparison but we do not have any guarantee + that the metadata processor used the same pointers for consumed_md in the + callback. */ + if (GPR_SLICE_LENGTH(md->key->slice) != strlen(consumed_md->key) || + GPR_SLICE_LENGTH(md->value->slice) != consumed_md->value_length) { + continue; + } + if (memcmp(GPR_SLICE_START_PTR(md->key->slice), consumed_md->key, + GPR_SLICE_LENGTH(md->key->slice)) == 0 && + memcmp(GPR_SLICE_START_PTR(md->value->slice), consumed_md->value, + GPR_SLICE_LENGTH(md->value->slice)) == 0) { + return NULL; /* Delete. */ + } + } + return md; +} + +/* called from application code */ +static void on_md_processing_done( + void *user_data, const grpc_metadata *consumed_md, size_t num_consumed_md, + const grpc_metadata *response_md, size_t num_response_md, + grpc_status_code status, const char *error_details) { + grpc_call_element *elem = user_data; + call_data *calld = elem->call_data; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + + /* TODO(jboeuf): Implement support for response_md. */ + if (response_md != NULL && num_response_md > 0) { + gpr_log(GPR_INFO, + "response_md in auth metadata processing not supported for now. " + "Ignoring..."); + } + + if (status == GRPC_STATUS_OK) { + calld->consumed_md = consumed_md; + calld->num_consumed_md = num_consumed_md; + grpc_metadata_batch_filter(calld->recv_initial_metadata, remove_consumed_md, + elem); + grpc_metadata_array_destroy(&calld->md); + calld->on_done_recv->cb(&exec_ctx, calld->on_done_recv->cb_arg, 1); + } else { + gpr_slice message; + grpc_transport_stream_op close_op; + memset(&close_op, 0, sizeof(close_op)); + grpc_metadata_array_destroy(&calld->md); + error_details = error_details != NULL + ? error_details + : "Authentication metadata processing failed."; + message = gpr_slice_from_copied_string(error_details); + calld->transport_op.send_initial_metadata = NULL; + if (calld->transport_op.send_message != NULL) { + grpc_byte_stream_destroy(&exec_ctx, calld->transport_op.send_message); + calld->transport_op.send_message = NULL; + } + calld->transport_op.send_trailing_metadata = NULL; + grpc_transport_stream_op_add_close(&close_op, status, &message); + grpc_call_next_op(&exec_ctx, elem, &close_op); + calld->on_done_recv->cb(&exec_ctx, calld->on_done_recv->cb_arg, 0); + } + + grpc_exec_ctx_finish(&exec_ctx); +} + +static void auth_on_recv(grpc_exec_ctx *exec_ctx, void *user_data, + bool success) { + grpc_call_element *elem = user_data; + call_data *calld = elem->call_data; + channel_data *chand = elem->channel_data; + if (success) { + if (chand->creds->processor.process != NULL) { + calld->md = metadata_batch_to_md_array(calld->recv_initial_metadata); + chand->creds->processor.process( + chand->creds->processor.state, calld->auth_context, + calld->md.metadata, calld->md.count, on_md_processing_done, elem); + return; + } + } + calld->on_done_recv->cb(exec_ctx, calld->on_done_recv->cb_arg, success); +} + +static void set_recv_ops_md_callbacks(grpc_call_element *elem, + grpc_transport_stream_op *op) { + call_data *calld = elem->call_data; + + if (op->recv_initial_metadata != NULL) { + /* substitute our callback for the higher callback */ + calld->recv_initial_metadata = op->recv_initial_metadata; + calld->on_done_recv = op->recv_initial_metadata_ready; + op->recv_initial_metadata_ready = &calld->auth_on_recv; + calld->transport_op = *op; + } +} + +/* Called either: + - in response to an API call (or similar) from above, to send something + - a network event (or similar) from below, to receive something + op contains type and call direction information, in addition to the data + that is being sent or received. */ +static void auth_start_transport_op(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + grpc_transport_stream_op *op) { + set_recv_ops_md_callbacks(elem, op); + grpc_call_next_op(exec_ctx, elem, op); +} + +/* Constructor for call_data */ +static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + grpc_call_element_args *args) { + /* grab pointers to our data from the call element */ + call_data *calld = elem->call_data; + channel_data *chand = elem->channel_data; + grpc_server_security_context *server_ctx = NULL; + + /* initialize members */ + memset(calld, 0, sizeof(*calld)); + grpc_closure_init(&calld->auth_on_recv, auth_on_recv, elem); + + if (args->context[GRPC_CONTEXT_SECURITY].value != NULL) { + args->context[GRPC_CONTEXT_SECURITY].destroy( + args->context[GRPC_CONTEXT_SECURITY].value); + } + + server_ctx = grpc_server_security_context_create(); + server_ctx->auth_context = grpc_auth_context_create(chand->auth_context); + calld->auth_context = server_ctx->auth_context; + + args->context[GRPC_CONTEXT_SECURITY].value = server_ctx; + args->context[GRPC_CONTEXT_SECURITY].destroy = + grpc_server_security_context_destroy; +} + +static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + grpc_pollset *pollset) {} + +/* Destructor for call_data */ +static void destroy_call_elem(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem) {} + +/* Constructor for channel_data */ +static void init_channel_elem(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem, + grpc_channel_element_args *args) { + grpc_auth_context *auth_context = + grpc_find_auth_context_in_args(args->channel_args); + grpc_server_credentials *creds = + grpc_find_server_credentials_in_args(args->channel_args); + /* grab pointers to our data from the channel element */ + channel_data *chand = elem->channel_data; + + GPR_ASSERT(!args->is_last); + GPR_ASSERT(auth_context != NULL); + GPR_ASSERT(creds != NULL); + + /* initialize members */ + chand->auth_context = + GRPC_AUTH_CONTEXT_REF(auth_context, "server_auth_filter"); + chand->creds = grpc_server_credentials_ref(creds); +} + +/* Destructor for channel data */ +static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem) { + /* grab pointers to our data from the channel element */ + channel_data *chand = elem->channel_data; + GRPC_AUTH_CONTEXT_UNREF(chand->auth_context, "server_auth_filter"); + grpc_server_credentials_unref(chand->creds); +} + +const grpc_channel_filter grpc_server_auth_filter = { + auth_start_transport_op, grpc_channel_next_op, sizeof(call_data), + init_call_elem, set_pollset, destroy_call_elem, + sizeof(channel_data), init_channel_elem, destroy_channel_elem, + grpc_call_next_get_peer, "server-auth"}; diff --git a/src/core/lib/security/server_secure_chttp2.c b/src/core/lib/security/server_secure_chttp2.c new file mode 100644 index 0000000000..da29ca934b --- /dev/null +++ b/src/core/lib/security/server_secure_chttp2.c @@ -0,0 +1,264 @@ +/* + * + * Copyright 2015-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 + +#include + +#include +#include +#include +#include +#include "src/core/channel/channel_args.h" +#include "src/core/channel/http_server_filter.h" +#include "src/core/iomgr/endpoint.h" +#include "src/core/iomgr/resolve_address.h" +#include "src/core/iomgr/tcp_server.h" +#include "src/core/security/auth_filters.h" +#include "src/core/security/credentials.h" +#include "src/core/security/security_connector.h" +#include "src/core/security/security_context.h" +#include "src/core/surface/api_trace.h" +#include "src/core/surface/server.h" +#include "src/core/transport/chttp2_transport.h" + +typedef struct grpc_server_secure_state { + grpc_server *server; + grpc_tcp_server *tcp; + grpc_server_security_connector *sc; + grpc_server_credentials *creds; + int is_shutdown; + gpr_mu mu; + gpr_refcount refcount; + grpc_closure destroy_closure; + grpc_closure *destroy_callback; +} grpc_server_secure_state; + +static void state_ref(grpc_server_secure_state *state) { + gpr_ref(&state->refcount); +} + +static void state_unref(grpc_server_secure_state *state) { + if (gpr_unref(&state->refcount)) { + /* ensure all threads have unlocked */ + gpr_mu_lock(&state->mu); + gpr_mu_unlock(&state->mu); + /* clean up */ + GRPC_SECURITY_CONNECTOR_UNREF(&state->sc->base, "server"); + grpc_server_credentials_unref(state->creds); + gpr_free(state); + } +} + +static void setup_transport(grpc_exec_ctx *exec_ctx, void *statep, + grpc_transport *transport, + grpc_auth_context *auth_context) { + grpc_server_secure_state *state = statep; + grpc_channel_args *args_copy; + grpc_arg args_to_add[2]; + args_to_add[0] = grpc_server_credentials_to_arg(state->creds); + args_to_add[1] = grpc_auth_context_to_arg(auth_context); + args_copy = grpc_channel_args_copy_and_add( + grpc_server_get_channel_args(state->server), args_to_add, + GPR_ARRAY_SIZE(args_to_add)); + grpc_server_setup_transport(exec_ctx, state->server, transport, args_copy); + grpc_channel_args_destroy(args_copy); +} + +static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *statep, + grpc_security_status status, + grpc_endpoint *secure_endpoint, + grpc_auth_context *auth_context) { + grpc_server_secure_state *state = statep; + grpc_transport *transport; + if (status == GRPC_SECURITY_OK) { + if (secure_endpoint) { + gpr_mu_lock(&state->mu); + if (!state->is_shutdown) { + transport = grpc_create_chttp2_transport( + exec_ctx, grpc_server_get_channel_args(state->server), + secure_endpoint, 0); + setup_transport(exec_ctx, state, transport, auth_context); + grpc_chttp2_transport_start_reading(exec_ctx, transport, NULL, 0); + } else { + /* We need to consume this here, because the server may already have + * gone away. */ + grpc_endpoint_destroy(exec_ctx, secure_endpoint); + } + gpr_mu_unlock(&state->mu); + } + } else { + gpr_log(GPR_ERROR, "Secure transport failed with error %d", status); + } + state_unref(state); +} + +static void on_accept(grpc_exec_ctx *exec_ctx, void *statep, grpc_endpoint *tcp, + grpc_tcp_server_acceptor *acceptor) { + grpc_server_secure_state *state = statep; + state_ref(state); + grpc_server_security_connector_do_handshake( + exec_ctx, state->sc, acceptor, tcp, on_secure_handshake_done, state); +} + +/* Server callback: start listening on our ports */ +static void start(grpc_exec_ctx *exec_ctx, grpc_server *server, void *statep, + grpc_pollset **pollsets, size_t pollset_count) { + grpc_server_secure_state *state = statep; + grpc_tcp_server_start(exec_ctx, state->tcp, pollsets, pollset_count, + on_accept, state); +} + +static void destroy_done(grpc_exec_ctx *exec_ctx, void *statep, bool success) { + grpc_server_secure_state *state = statep; + if (state->destroy_callback != NULL) { + state->destroy_callback->cb(exec_ctx, state->destroy_callback->cb_arg, + success); + } + grpc_server_security_connector_shutdown(exec_ctx, state->sc); + state_unref(state); +} + +/* Server callback: destroy the tcp listener (so we don't generate further + callbacks) */ +static void destroy(grpc_exec_ctx *exec_ctx, grpc_server *server, void *statep, + grpc_closure *callback) { + grpc_server_secure_state *state = statep; + grpc_tcp_server *tcp; + gpr_mu_lock(&state->mu); + state->is_shutdown = 1; + state->destroy_callback = callback; + tcp = state->tcp; + gpr_mu_unlock(&state->mu); + grpc_tcp_server_unref(exec_ctx, tcp); +} + +int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr, + grpc_server_credentials *creds) { + grpc_resolved_addresses *resolved = NULL; + grpc_tcp_server *tcp = NULL; + grpc_server_secure_state *state = NULL; + size_t i; + unsigned count = 0; + int port_num = -1; + int port_temp; + grpc_security_status status = GRPC_SECURITY_ERROR; + grpc_server_security_connector *sc = NULL; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + + GRPC_API_TRACE( + "grpc_server_add_secure_http2_port(" + "server=%p, addr=%s, creds=%p)", + 3, (server, addr, creds)); + + /* create security context */ + if (creds == NULL) goto error; + status = grpc_server_credentials_create_security_connector(creds, &sc); + if (status != GRPC_SECURITY_OK) { + gpr_log(GPR_ERROR, + "Unable to create secure server with credentials of type %s.", + creds->type); + goto error; + } + sc->channel_args = grpc_server_get_channel_args(server); + + /* resolve address */ + resolved = grpc_blocking_resolve_address(addr, "https"); + if (!resolved) { + goto error; + } + state = gpr_malloc(sizeof(*state)); + memset(state, 0, sizeof(*state)); + grpc_closure_init(&state->destroy_closure, destroy_done, state); + tcp = grpc_tcp_server_create(&state->destroy_closure); + if (!tcp) { + goto error; + } + + state->server = server; + state->tcp = tcp; + state->sc = sc; + state->creds = grpc_server_credentials_ref(creds); + state->is_shutdown = 0; + gpr_mu_init(&state->mu); + gpr_ref_init(&state->refcount, 1); + + for (i = 0; i < resolved->naddrs; i++) { + port_temp = grpc_tcp_server_add_port( + tcp, (struct sockaddr *)&resolved->addrs[i].addr, + resolved->addrs[i].len); + if (port_temp > 0) { + if (port_num == -1) { + port_num = port_temp; + } else { + GPR_ASSERT(port_num == port_temp); + } + count++; + } + } + if (count == 0) { + gpr_log(GPR_ERROR, "No address added out of total %d resolved", + resolved->naddrs); + goto error; + } + if (count != resolved->naddrs) { + gpr_log(GPR_ERROR, "Only %d addresses added out of total %d resolved", + count, resolved->naddrs); + /* if it's an error, don't we want to goto error; here ? */ + } + grpc_resolved_addresses_destroy(resolved); + + /* Register with the server only upon success */ + grpc_server_add_listener(&exec_ctx, server, state, start, destroy); + + grpc_exec_ctx_finish(&exec_ctx); + return port_num; + +/* Error path: cleanup and return */ +error: + if (resolved) { + grpc_resolved_addresses_destroy(resolved); + } + if (tcp) { + grpc_tcp_server_unref(&exec_ctx, tcp); + } else { + if (sc) { + GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "server"); + } + if (state) { + gpr_free(state); + } + } + grpc_exec_ctx_finish(&exec_ctx); + return 0; +} diff --git a/src/core/lib/statistics/census_init.c b/src/core/lib/statistics/census_init.c new file mode 100644 index 0000000000..b6a962f228 --- /dev/null +++ b/src/core/lib/statistics/census_init.c @@ -0,0 +1,48 @@ +/* + * + * Copyright 2015-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/statistics/census_interface.h" + +#include +#include "src/core/statistics/census_rpc_stats.h" +#include "src/core/statistics/census_tracing.h" + +void census_init(void) { + census_tracing_init(); + census_stats_store_init(); +} + +void census_shutdown(void) { + census_stats_store_shutdown(); + census_tracing_shutdown(); +} diff --git a/src/core/lib/statistics/census_interface.h b/src/core/lib/statistics/census_interface.h new file mode 100644 index 0000000000..ce8ff92cd4 --- /dev/null +++ b/src/core/lib/statistics/census_interface.h @@ -0,0 +1,76 @@ +/* + * + * Copyright 2015-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_STATISTICS_CENSUS_INTERFACE_H +#define GRPC_CORE_STATISTICS_CENSUS_INTERFACE_H + +#include + +/* Maximum length of an individual census trace annotation. */ +#define CENSUS_MAX_ANNOTATION_LENGTH 200 + +/* Structure of a census op id. Define as structure because 64bit integer is not + available on every platform for C89. */ +typedef struct census_op_id { + uint32_t upper; + uint32_t lower; +} census_op_id; + +typedef struct census_rpc_stats census_rpc_stats; + +/* Initializes Census library. No-op if Census is already initialized. */ +void census_init(void); + +/* Shutdown Census Library. */ +void census_shutdown(void); + +/* Annotates grpc method name on a census_op_id. The method name has the format + of /. Returns 0 iff + op_id and method_name are all valid. op_id is valid after its creation and + before calling census_tracing_end_op(). + + TODO(hongyu): Figure out valid characters set for service name and command + name and document requirements here.*/ +int census_add_method_tag(census_op_id op_id, const char *method_name); + +/* Annotates tracing information to a specific op_id. + Up to CENSUS_MAX_ANNOTATION_LENGTH bytes are recorded. */ +void census_tracing_print(census_op_id op_id, const char *annotation); + +/* Starts tracing for an RPC. Returns a locally unique census_op_id */ +census_op_id census_tracing_start_op(void); + +/* Ends tracing. Calling this function will invalidate the input op_id. */ +void census_tracing_end_op(census_op_id op_id); + +#endif /* GRPC_CORE_STATISTICS_CENSUS_INTERFACE_H */ diff --git a/src/core/lib/statistics/census_log.c b/src/core/lib/statistics/census_log.c new file mode 100644 index 0000000000..3802d1cc7a --- /dev/null +++ b/src/core/lib/statistics/census_log.c @@ -0,0 +1,603 @@ +/* + * + * Copyright 2015-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. + * + */ + +/* Available log space is divided up in blocks of + CENSUS_LOG_2_MAX_RECORD_SIZE bytes. A block can be in one of the + following three data structures: + - Free blocks (free_block_list) + - Blocks with unread data (dirty_block_list) + - Blocks currently attached to cores (core_local_blocks[]) + + census_log_start_write() moves a block from core_local_blocks[] to the + end of dirty_block_list when block: + - is out-of-space OR + - has an incomplete record (an incomplete record occurs when a thread calls + census_log_start_write() and is context-switched before calling + census_log_end_write() + So, blocks in dirty_block_list are ordered, from oldest to newest, by time + when block is detached from the core. + + census_log_read_next() first iterates over dirty_block_list and then + core_local_blocks[]. It moves completely read blocks from dirty_block_list + to free_block_list. Blocks in core_local_blocks[] are not freed, even when + completely read. + + If log is configured to discard old records and free_block_list is empty, + census_log_start_write() iterates over dirty_block_list to allocate a + new block. It moves the oldest available block (no pending read/write) to + core_local_blocks[]. + + core_local_block_struct is used to implement a map from core id to the block + associated with that core. This mapping is advisory. It is possible that the + block returned by this mapping is no longer associated with that core. This + mapping is updated, lazily, by census_log_start_write(). + + Locking in block struct: + + Exclusive g_log.lock must be held before calling any functions operatong on + block structs except census_log_start_write() and + census_log_end_write(). + + Writes to a block are serialized via writer_lock. + census_log_start_write() acquires this lock and + census_log_end_write() releases it. On failure to acquire the lock, + writer allocates a new block for the current core and updates + core_local_block accordingly. + + Simultaneous read and write access is allowed. Reader can safely read up to + committed bytes (bytes_committed). + + reader_lock protects the block, currently being read, from getting recycled. + start_read() acquires reader_lock and end_read() releases the lock. + + Read/write access to a block is disabled via try_disable_access(). It returns + with both writer_lock and reader_lock held. These locks are subsequently + released by enable_access() to enable access to the block. + + A note on naming: Most function/struct names are prepended by cl_ + (shorthand for census_log). Further, functions that manipulate structures + include the name of the structure, which will be passed as the first + argument. E.g. cl_block_initialize() will initialize a cl_block. +*/ +#include "src/core/statistics/census_log.h" +#include +#include +#include +#include +#include +#include +#include +#include + +/* End of platform specific code */ + +typedef struct census_log_block_list_struct { + struct census_log_block_list_struct *next; + struct census_log_block_list_struct *prev; + struct census_log_block *block; +} cl_block_list_struct; + +typedef struct census_log_block { + /* Pointer to underlying buffer */ + char *buffer; + gpr_atm writer_lock; + gpr_atm reader_lock; + /* Keeps completely written bytes. Declared atomic because accessed + simultaneously by reader and writer. */ + gpr_atm bytes_committed; + /* Bytes already read */ + int32_t bytes_read; + /* Links for list */ + cl_block_list_struct link; +/* We want this structure to be cacheline aligned. We assume the following + sizes for the various parts on 32/64bit systems: + type 32b size 64b size + char* 4 8 + 3x gpr_atm 12 24 + int32_t 4 8 (assumes padding) + cl_block_list_struct 12 24 + TOTAL 32 64 + + Depending on the size of our cacheline and the architecture, we + selectively add char buffering to this structure. The size is checked + via assert in census_log_initialize(). */ +#if defined(GPR_ARCH_64) +#define CL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 64) +#else +#if defined(GPR_ARCH_32) +#define CL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 32) +#else +#error "Unknown architecture" +#endif +#endif +#if CL_BLOCK_PAD_SIZE > 0 + char padding[CL_BLOCK_PAD_SIZE]; +#endif +} cl_block; + +/* A list of cl_blocks, doubly-linked through cl_block::link. */ +typedef struct census_log_block_list { + int32_t count; /* Number of items in list. */ + cl_block_list_struct ht; /* head/tail of linked list. */ +} cl_block_list; + +/* Cacheline aligned block pointers to avoid false sharing. Block pointer must + be initialized via set_block(), before calling other functions */ +typedef struct census_log_core_local_block { + gpr_atm block; +/* Ensure cachline alignment: we assume sizeof(gpr_atm) == 4 or 8 */ +#if defined(GPR_ARCH_64) +#define CL_CORE_LOCAL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 8) +#else +#if defined(GPR_ARCH_32) +#define CL_CORE_LOCAL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 4) +#else +#error "Unknown architecture" +#endif +#endif +#if CL_CORE_LOCAL_BLOCK_PAD_SIZE > 0 + char padding[CL_CORE_LOCAL_BLOCK_PAD_SIZE]; +#endif +} cl_core_local_block; + +struct census_log { + int discard_old_records; + /* Number of cores (aka hardware-contexts) */ + unsigned num_cores; + /* number of CENSUS_LOG_2_MAX_RECORD_SIZE blocks in log */ + int32_t num_blocks; + cl_block *blocks; /* Block metadata. */ + cl_core_local_block *core_local_blocks; /* Keeps core to block mappings. */ + gpr_mu lock; + int initialized; /* has log been initialized? */ + /* Keeps the state of the reader iterator. A value of 0 indicates that + iterator has reached the end. census_log_init_reader() resets the + value to num_core to restart iteration. */ + uint32_t read_iterator_state; + /* Points to the block being read. If non-NULL, the block is locked for + reading (block_being_read_->reader_lock is held). */ + cl_block *block_being_read; + /* A non-zero value indicates that log is full. */ + gpr_atm is_full; + char *buffer; + cl_block_list free_block_list; + cl_block_list dirty_block_list; + gpr_atm out_of_space_count; +}; + +/* Single internal log */ +static struct census_log g_log; + +/* Functions that operate on an atomic memory location used as a lock */ + +/* Returns non-zero if lock is acquired */ +static int cl_try_lock(gpr_atm *lock) { return gpr_atm_acq_cas(lock, 0, 1); } + +static void cl_unlock(gpr_atm *lock) { gpr_atm_rel_store(lock, 0); } + +/* Functions that operate on cl_core_local_block's */ + +static void cl_core_local_block_set_block(cl_core_local_block *clb, + cl_block *block) { + gpr_atm_rel_store(&clb->block, (gpr_atm)block); +} + +static cl_block *cl_core_local_block_get_block(cl_core_local_block *clb) { + return (cl_block *)gpr_atm_acq_load(&clb->block); +} + +/* Functions that operate on cl_block_list_struct's */ + +static void cl_block_list_struct_initialize(cl_block_list_struct *bls, + cl_block *block) { + bls->next = bls->prev = bls; + bls->block = block; +} + +/* Functions that operate on cl_block_list's */ + +static void cl_block_list_initialize(cl_block_list *list) { + list->count = 0; + cl_block_list_struct_initialize(&list->ht, NULL); +} + +/* Returns head of *this, or NULL if empty. */ +static cl_block *cl_block_list_head(cl_block_list *list) { + return list->ht.next->block; +} + +/* Insert element *e after *pos. */ +static void cl_block_list_insert(cl_block_list *list, cl_block_list_struct *pos, + cl_block_list_struct *e) { + list->count++; + e->next = pos->next; + e->prev = pos; + e->next->prev = e; + e->prev->next = e; +} + +/* Insert block at the head of the list */ +static void cl_block_list_insert_at_head(cl_block_list *list, cl_block *block) { + cl_block_list_insert(list, &list->ht, &block->link); +} + +/* Insert block at the tail of the list */ +static void cl_block_list_insert_at_tail(cl_block_list *list, cl_block *block) { + cl_block_list_insert(list, list->ht.prev, &block->link); +} + +/* Removes block *b. Requires *b be in the list. */ +static void cl_block_list_remove(cl_block_list *list, cl_block *b) { + list->count--; + b->link.next->prev = b->link.prev; + b->link.prev->next = b->link.next; +} + +/* Functions that operate on cl_block's */ + +static void cl_block_initialize(cl_block *block, char *buffer) { + block->buffer = buffer; + gpr_atm_rel_store(&block->writer_lock, 0); + gpr_atm_rel_store(&block->reader_lock, 0); + gpr_atm_rel_store(&block->bytes_committed, 0); + block->bytes_read = 0; + cl_block_list_struct_initialize(&block->link, block); +} + +/* Guards against exposing partially written buffer to the reader. */ +static void cl_block_set_bytes_committed(cl_block *block, + int32_t bytes_committed) { + gpr_atm_rel_store(&block->bytes_committed, bytes_committed); +} + +static int32_t cl_block_get_bytes_committed(cl_block *block) { + return gpr_atm_acq_load(&block->bytes_committed); +} + +/* Tries to disable future read/write access to this block. Succeeds if: + - no in-progress write AND + - no in-progress read AND + - 'discard_data' set to true OR no unread data + On success, clears the block state and returns with writer_lock_ and + reader_lock_ held. These locks are released by a subsequent + cl_block_access_enable() call. */ +static int cl_block_try_disable_access(cl_block *block, int discard_data) { + if (!cl_try_lock(&block->writer_lock)) { + return 0; + } + if (!cl_try_lock(&block->reader_lock)) { + cl_unlock(&block->writer_lock); + return 0; + } + if (!discard_data && + (block->bytes_read != cl_block_get_bytes_committed(block))) { + cl_unlock(&block->reader_lock); + cl_unlock(&block->writer_lock); + return 0; + } + cl_block_set_bytes_committed(block, 0); + block->bytes_read = 0; + return 1; +} + +static void cl_block_enable_access(cl_block *block) { + cl_unlock(&block->reader_lock); + cl_unlock(&block->writer_lock); +} + +/* Returns with writer_lock held. */ +static void *cl_block_start_write(cl_block *block, size_t size) { + int32_t bytes_committed; + if (!cl_try_lock(&block->writer_lock)) { + return NULL; + } + bytes_committed = cl_block_get_bytes_committed(block); + if (bytes_committed + size > CENSUS_LOG_MAX_RECORD_SIZE) { + cl_unlock(&block->writer_lock); + return NULL; + } + return block->buffer + bytes_committed; +} + +/* Releases writer_lock and increments committed bytes by 'bytes_written'. + 'bytes_written' must be <= 'size' specified in the corresponding + StartWrite() call. This function is thread-safe. */ +static void cl_block_end_write(cl_block *block, size_t bytes_written) { + cl_block_set_bytes_committed( + block, cl_block_get_bytes_committed(block) + bytes_written); + cl_unlock(&block->writer_lock); +} + +/* Returns a pointer to the first unread byte in buffer. The number of bytes + available are returned in 'bytes_available'. Acquires reader lock that is + released by a subsequent cl_block_end_read() call. Returns NULL if: + - read in progress + - no data available */ +static void *cl_block_start_read(cl_block *block, size_t *bytes_available) { + void *record; + if (!cl_try_lock(&block->reader_lock)) { + return NULL; + } + /* bytes_committed may change from under us. Use bytes_available to update + bytes_read below. */ + *bytes_available = cl_block_get_bytes_committed(block) - block->bytes_read; + if (*bytes_available == 0) { + cl_unlock(&block->reader_lock); + return NULL; + } + record = block->buffer + block->bytes_read; + block->bytes_read += *bytes_available; + return record; +} + +static void cl_block_end_read(cl_block *block) { + cl_unlock(&block->reader_lock); +} + +/* Internal functions operating on g_log */ + +/* Allocates a new free block (or recycles an available dirty block if log is + configured to discard old records). Returns NULL if out-of-space. */ +static cl_block *cl_allocate_block(void) { + cl_block *block = cl_block_list_head(&g_log.free_block_list); + if (block != NULL) { + cl_block_list_remove(&g_log.free_block_list, block); + return block; + } + if (!g_log.discard_old_records) { + /* No free block and log is configured to keep old records. */ + return NULL; + } + /* Recycle dirty block. Start from the oldest. */ + for (block = cl_block_list_head(&g_log.dirty_block_list); block != NULL; + block = block->link.next->block) { + if (cl_block_try_disable_access(block, 1 /* discard data */)) { + cl_block_list_remove(&g_log.dirty_block_list, block); + return block; + } + } + return NULL; +} + +/* Allocates a new block and updates core id => block mapping. 'old_block' + points to the block that the caller thinks is attached to + 'core_id'. 'old_block' may be NULL. Returns non-zero if: + - allocated a new block OR + - 'core_id' => 'old_block' mapping changed (another thread allocated a + block before lock was acquired). */ +static int cl_allocate_core_local_block(int32_t core_id, cl_block *old_block) { + /* Now that we have the lock, check if core-local mapping has changed. */ + cl_core_local_block *core_local_block = &g_log.core_local_blocks[core_id]; + cl_block *block = cl_core_local_block_get_block(core_local_block); + if ((block != NULL) && (block != old_block)) { + return 1; + } + if (block != NULL) { + cl_core_local_block_set_block(core_local_block, NULL); + cl_block_list_insert_at_tail(&g_log.dirty_block_list, block); + } + block = cl_allocate_block(); + if (block == NULL) { + gpr_atm_rel_store(&g_log.is_full, 1); + return 0; + } + cl_core_local_block_set_block(core_local_block, block); + cl_block_enable_access(block); + return 1; +} + +static cl_block *cl_get_block(void *record) { + uintptr_t p = (uintptr_t)((char *)record - g_log.buffer); + uintptr_t index = p >> CENSUS_LOG_2_MAX_RECORD_SIZE; + return &g_log.blocks[index]; +} + +/* Gets the next block to read and tries to free 'prev' block (if not NULL). + Returns NULL if reached the end. */ +static cl_block *cl_next_block_to_read(cl_block *prev) { + cl_block *block = NULL; + if (g_log.read_iterator_state == g_log.num_cores) { + /* We are traversing dirty list; find the next dirty block. */ + if (prev != NULL) { + /* Try to free the previous block if there is no unread data. This block + may have unread data if previously incomplete record completed between + read_next() calls. */ + block = prev->link.next->block; + if (cl_block_try_disable_access(prev, 0 /* do not discard data */)) { + cl_block_list_remove(&g_log.dirty_block_list, prev); + cl_block_list_insert_at_head(&g_log.free_block_list, prev); + gpr_atm_rel_store(&g_log.is_full, 0); + } + } else { + block = cl_block_list_head(&g_log.dirty_block_list); + } + if (block != NULL) { + return block; + } + /* We are done with the dirty list; moving on to core-local blocks. */ + } + while (g_log.read_iterator_state > 0) { + g_log.read_iterator_state--; + block = cl_core_local_block_get_block( + &g_log.core_local_blocks[g_log.read_iterator_state]); + if (block != NULL) { + return block; + } + } + return NULL; +} + +/* External functions: primary stats_log interface */ +void census_log_initialize(size_t size_in_mb, int discard_old_records) { + int32_t ix; + /* Check cacheline alignment. */ + GPR_ASSERT(sizeof(cl_block) % GPR_CACHELINE_SIZE == 0); + GPR_ASSERT(sizeof(cl_core_local_block) % GPR_CACHELINE_SIZE == 0); + GPR_ASSERT(!g_log.initialized); + g_log.discard_old_records = discard_old_records; + g_log.num_cores = gpr_cpu_num_cores(); + /* Ensure at least as many blocks as there are cores. */ + g_log.num_blocks = GPR_MAX( + g_log.num_cores, (size_in_mb << 20) >> CENSUS_LOG_2_MAX_RECORD_SIZE); + gpr_mu_init(&g_log.lock); + g_log.read_iterator_state = 0; + g_log.block_being_read = NULL; + gpr_atm_rel_store(&g_log.is_full, 0); + g_log.core_local_blocks = (cl_core_local_block *)gpr_malloc_aligned( + g_log.num_cores * sizeof(cl_core_local_block), GPR_CACHELINE_SIZE_LOG); + memset(g_log.core_local_blocks, 0, + g_log.num_cores * sizeof(cl_core_local_block)); + g_log.blocks = (cl_block *)gpr_malloc_aligned( + g_log.num_blocks * sizeof(cl_block), GPR_CACHELINE_SIZE_LOG); + memset(g_log.blocks, 0, g_log.num_blocks * sizeof(cl_block)); + g_log.buffer = gpr_malloc(g_log.num_blocks * CENSUS_LOG_MAX_RECORD_SIZE); + memset(g_log.buffer, 0, g_log.num_blocks * CENSUS_LOG_MAX_RECORD_SIZE); + cl_block_list_initialize(&g_log.free_block_list); + cl_block_list_initialize(&g_log.dirty_block_list); + for (ix = 0; ix < g_log.num_blocks; ++ix) { + cl_block *block = g_log.blocks + ix; + cl_block_initialize(block, + g_log.buffer + (CENSUS_LOG_MAX_RECORD_SIZE * ix)); + cl_block_try_disable_access(block, 1 /* discard data */); + cl_block_list_insert_at_tail(&g_log.free_block_list, block); + } + gpr_atm_rel_store(&g_log.out_of_space_count, 0); + g_log.initialized = 1; +} + +void census_log_shutdown(void) { + GPR_ASSERT(g_log.initialized); + gpr_mu_destroy(&g_log.lock); + gpr_free_aligned(g_log.core_local_blocks); + g_log.core_local_blocks = NULL; + gpr_free_aligned(g_log.blocks); + g_log.blocks = NULL; + gpr_free(g_log.buffer); + g_log.buffer = NULL; + g_log.initialized = 0; +} + +void *census_log_start_write(size_t size) { + /* Used to bound number of times block allocation is attempted. */ + int32_t attempts_remaining = g_log.num_blocks; + /* TODO(aveitch): move this inside the do loop when current_cpu is fixed */ + int32_t core_id = gpr_cpu_current_cpu(); + GPR_ASSERT(g_log.initialized); + if (size > CENSUS_LOG_MAX_RECORD_SIZE) { + return NULL; + } + do { + int allocated; + void *record = NULL; + cl_block *block = + cl_core_local_block_get_block(&g_log.core_local_blocks[core_id]); + if (block && (record = cl_block_start_write(block, size))) { + return record; + } + /* Need to allocate a new block. We are here if: + - No block associated with the core OR + - Write in-progress on the block OR + - block is out of space */ + if (gpr_atm_acq_load(&g_log.is_full)) { + gpr_atm_no_barrier_fetch_add(&g_log.out_of_space_count, 1); + return NULL; + } + gpr_mu_lock(&g_log.lock); + allocated = cl_allocate_core_local_block(core_id, block); + gpr_mu_unlock(&g_log.lock); + if (!allocated) { + gpr_atm_no_barrier_fetch_add(&g_log.out_of_space_count, 1); + return NULL; + } + } while (attempts_remaining--); + /* Give up. */ + gpr_atm_no_barrier_fetch_add(&g_log.out_of_space_count, 1); + return NULL; +} + +void census_log_end_write(void *record, size_t bytes_written) { + GPR_ASSERT(g_log.initialized); + cl_block_end_write(cl_get_block(record), bytes_written); +} + +void census_log_init_reader(void) { + GPR_ASSERT(g_log.initialized); + gpr_mu_lock(&g_log.lock); + /* If a block is locked for reading unlock it. */ + if (g_log.block_being_read != NULL) { + cl_block_end_read(g_log.block_being_read); + g_log.block_being_read = NULL; + } + g_log.read_iterator_state = g_log.num_cores; + gpr_mu_unlock(&g_log.lock); +} + +const void *census_log_read_next(size_t *bytes_available) { + GPR_ASSERT(g_log.initialized); + gpr_mu_lock(&g_log.lock); + if (g_log.block_being_read != NULL) { + cl_block_end_read(g_log.block_being_read); + } + do { + g_log.block_being_read = cl_next_block_to_read(g_log.block_being_read); + if (g_log.block_being_read != NULL) { + void *record = + cl_block_start_read(g_log.block_being_read, bytes_available); + if (record != NULL) { + gpr_mu_unlock(&g_log.lock); + return record; + } + } + } while (g_log.block_being_read != NULL); + gpr_mu_unlock(&g_log.lock); + return NULL; +} + +size_t census_log_remaining_space(void) { + size_t space; + GPR_ASSERT(g_log.initialized); + gpr_mu_lock(&g_log.lock); + if (g_log.discard_old_records) { + /* Remaining space is not meaningful; just return the entire log space. */ + space = g_log.num_blocks << CENSUS_LOG_2_MAX_RECORD_SIZE; + } else { + space = g_log.free_block_list.count * CENSUS_LOG_MAX_RECORD_SIZE; + } + gpr_mu_unlock(&g_log.lock); + return space; +} + +int census_log_out_of_space_count(void) { + GPR_ASSERT(g_log.initialized); + return gpr_atm_acq_load(&g_log.out_of_space_count); +} diff --git a/src/core/lib/statistics/census_log.h b/src/core/lib/statistics/census_log.h new file mode 100644 index 0000000000..e7ce0d4433 --- /dev/null +++ b/src/core/lib/statistics/census_log.h @@ -0,0 +1,91 @@ +/* + * + * Copyright 2015-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_STATISTICS_CENSUS_LOG_H +#define GRPC_CORE_STATISTICS_CENSUS_LOG_H + +#include + +/* Maximum record size, in bytes. */ +#define CENSUS_LOG_2_MAX_RECORD_SIZE 14 /* 2^14 = 16KB */ +#define CENSUS_LOG_MAX_RECORD_SIZE (1 << CENSUS_LOG_2_MAX_RECORD_SIZE) + +/* Initialize the statistics logging subsystem with the given log size. A log + size of 0 will result in the smallest possible log for the platform + (approximately CENSUS_LOG_MAX_RECORD_SIZE * gpr_cpu_num_cores()). If + discard_old_records is non-zero, then new records will displace older ones + when the log is full. This function must be called before any other + census_log functions. +*/ +void census_log_initialize(size_t size_in_mb, int discard_old_records); + +/* Shutdown the logging subsystem. Caller must ensure that: + - no in progress or future call to any census_log functions + - no incomplete records +*/ +void census_log_shutdown(void); + +/* Allocates and returns a 'size' bytes record and marks it in use. A + subsequent census_log_end_write() marks the record complete. The + 'bytes_written' census_log_end_write() argument must be <= + 'size'. Returns NULL if out-of-space AND: + - log is configured to keep old records OR + - all blocks are pinned by incomplete records. +*/ +void *census_log_start_write(size_t size); + +void census_log_end_write(void *record, size_t bytes_written); + +/* census_log_read_next() iterates over blocks with data and for each block + returns a pointer to the first unread byte. The number of bytes that can be + read are returned in 'bytes_available'. Reader is expected to read all + available data. Reading the data consumes it i.e. it cannot be read again. + census_log_read_next() returns NULL if the end is reached i.e last block + is read. census_log_init_reader() starts the iteration or aborts the + current iteration. +*/ +void census_log_init_reader(void); +const void *census_log_read_next(size_t *bytes_available); + +/* Returns estimated remaining space across all blocks, in bytes. If log is + configured to discard old records, returns total log space. Otherwise, + returns space available in empty blocks (partially filled blocks are + treated as full). +*/ +size_t census_log_remaining_space(void); + +/* Returns the number of times gprc_stats_log_start_write() failed due to + out-of-space. */ +int census_log_out_of_space_count(void); + +#endif /* GRPC_CORE_STATISTICS_CENSUS_LOG_H */ diff --git a/src/core/lib/statistics/census_rpc_stats.c b/src/core/lib/statistics/census_rpc_stats.c new file mode 100644 index 0000000000..c78d6fd612 --- /dev/null +++ b/src/core/lib/statistics/census_rpc_stats.c @@ -0,0 +1,253 @@ +/* + * + * Copyright 2015-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 + +#include +#include +#include +#include "src/core/statistics/census_interface.h" +#include "src/core/statistics/census_rpc_stats.h" +#include "src/core/statistics/census_tracing.h" +#include "src/core/statistics/hash_table.h" +#include "src/core/statistics/window_stats.h" +#include "src/core/support/murmur_hash.h" +#include "src/core/support/string.h" + +#define NUM_INTERVALS 3 +#define MINUTE_INTERVAL 0 +#define HOUR_INTERVAL 1 +#define TOTAL_INTERVAL 2 + +/* for easier typing */ +typedef census_per_method_rpc_stats per_method_stats; + +/* Ensure mu is only initialized once. */ +static gpr_once g_stats_store_mu_init = GPR_ONCE_INIT; +/* Guards two stats stores. */ +static gpr_mu g_mu; +static census_ht *g_client_stats_store = NULL; +static census_ht *g_server_stats_store = NULL; + +static void init_mutex(void) { gpr_mu_init(&g_mu); } + +static void init_mutex_once(void) { + gpr_once_init(&g_stats_store_mu_init, init_mutex); +} + +static int cmp_str_keys(const void *k1, const void *k2) { + return strcmp((const char *)k1, (const char *)k2); +} + +/* TODO(hongyu): replace it with cityhash64 */ +static uint64_t simple_hash(const void *k) { + size_t len = strlen(k); + uint64_t higher = gpr_murmur_hash3((const char *)k, len / 2, 0); + return higher << 32 | + gpr_murmur_hash3((const char *)k + len / 2, len - len / 2, 0); +} + +static void delete_stats(void *stats) { + census_window_stats_destroy((struct census_window_stats *)stats); +} + +static void delete_key(void *key) { gpr_free(key); } + +static const census_ht_option ht_opt = { + CENSUS_HT_POINTER /* key type */, 1999 /* n_of_buckets */, + simple_hash /* hash function */, cmp_str_keys /* key comparator */, + delete_stats /* data deleter */, delete_key /* key deleter */ +}; + +static void init_rpc_stats(void *stats) { + memset(stats, 0, sizeof(census_rpc_stats)); +} + +static void stat_add_proportion(double p, void *base, const void *addme) { + census_rpc_stats *b = (census_rpc_stats *)base; + census_rpc_stats *a = (census_rpc_stats *)addme; + b->cnt += p * a->cnt; + b->rpc_error_cnt += p * a->rpc_error_cnt; + b->app_error_cnt += p * a->app_error_cnt; + b->elapsed_time_ms += p * a->elapsed_time_ms; + b->api_request_bytes += p * a->api_request_bytes; + b->wire_request_bytes += p * a->wire_request_bytes; + b->api_response_bytes += p * a->api_response_bytes; + b->wire_response_bytes += p * a->wire_response_bytes; +} + +static void stat_add(void *base, const void *addme) { + stat_add_proportion(1.0, base, addme); +} + +static gpr_timespec min_hour_total_intervals[3] = { + {60, 0}, {3600, 0}, {36000000, 0}}; + +static const census_window_stats_stat_info window_stats_settings = { + sizeof(census_rpc_stats), init_rpc_stats, stat_add, stat_add_proportion}; + +census_rpc_stats *census_rpc_stats_create_empty(void) { + census_rpc_stats *ret = + (census_rpc_stats *)gpr_malloc(sizeof(census_rpc_stats)); + memset(ret, 0, sizeof(census_rpc_stats)); + return ret; +} + +void census_aggregated_rpc_stats_set_empty(census_aggregated_rpc_stats *data) { + int i = 0; + for (i = 0; i < data->num_entries; i++) { + if (data->stats[i].method != NULL) { + gpr_free((void *)data->stats[i].method); + } + } + if (data->stats != NULL) { + gpr_free(data->stats); + } + data->num_entries = 0; + data->stats = NULL; +} + +static void record_stats(census_ht *store, census_op_id op_id, + const census_rpc_stats *stats) { + gpr_mu_lock(&g_mu); + if (store != NULL) { + census_trace_obj *trace = NULL; + census_internal_lock_trace_store(); + trace = census_get_trace_obj_locked(op_id); + if (trace != NULL) { + const char *method_name = census_get_trace_method_name(trace); + struct census_window_stats *window_stats = NULL; + census_ht_key key; + key.ptr = (void *)method_name; + window_stats = census_ht_find(store, key); + census_internal_unlock_trace_store(); + if (window_stats == NULL) { + window_stats = census_window_stats_create(3, min_hour_total_intervals, + 30, &window_stats_settings); + key.ptr = gpr_strdup(key.ptr); + census_ht_insert(store, key, (void *)window_stats); + } + census_window_stats_add(window_stats, gpr_now(GPR_CLOCK_REALTIME), stats); + } else { + census_internal_unlock_trace_store(); + } + } + gpr_mu_unlock(&g_mu); +} + +void census_record_rpc_client_stats(census_op_id op_id, + const census_rpc_stats *stats) { + record_stats(g_client_stats_store, op_id, stats); +} + +void census_record_rpc_server_stats(census_op_id op_id, + const census_rpc_stats *stats) { + record_stats(g_server_stats_store, op_id, stats); +} + +/* Get stats from input stats store */ +static void get_stats(census_ht *store, census_aggregated_rpc_stats *data) { + GPR_ASSERT(data != NULL); + if (data->num_entries != 0) { + census_aggregated_rpc_stats_set_empty(data); + } + gpr_mu_lock(&g_mu); + if (store != NULL) { + size_t n; + unsigned i, j; + gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME); + census_ht_kv *kv = census_ht_get_all_elements(store, &n); + if (kv != NULL) { + data->num_entries = n; + data->stats = + (per_method_stats *)gpr_malloc(sizeof(per_method_stats) * n); + for (i = 0; i < n; i++) { + census_window_stats_sums sums[NUM_INTERVALS]; + for (j = 0; j < NUM_INTERVALS; j++) { + sums[j].statistic = (void *)census_rpc_stats_create_empty(); + } + data->stats[i].method = gpr_strdup(kv[i].k.ptr); + census_window_stats_get_sums(kv[i].v, now, sums); + data->stats[i].minute_stats = + *(census_rpc_stats *)sums[MINUTE_INTERVAL].statistic; + data->stats[i].hour_stats = + *(census_rpc_stats *)sums[HOUR_INTERVAL].statistic; + data->stats[i].total_stats = + *(census_rpc_stats *)sums[TOTAL_INTERVAL].statistic; + for (j = 0; j < NUM_INTERVALS; j++) { + gpr_free(sums[j].statistic); + } + } + gpr_free(kv); + } + } + gpr_mu_unlock(&g_mu); +} + +void census_get_client_stats(census_aggregated_rpc_stats *data) { + get_stats(g_client_stats_store, data); +} + +void census_get_server_stats(census_aggregated_rpc_stats *data) { + get_stats(g_server_stats_store, data); +} + +void census_stats_store_init(void) { + init_mutex_once(); + gpr_mu_lock(&g_mu); + if (g_client_stats_store == NULL && g_server_stats_store == NULL) { + g_client_stats_store = census_ht_create(&ht_opt); + g_server_stats_store = census_ht_create(&ht_opt); + } else { + gpr_log(GPR_ERROR, "Census stats store already initialized."); + } + gpr_mu_unlock(&g_mu); +} + +void census_stats_store_shutdown(void) { + init_mutex_once(); + gpr_mu_lock(&g_mu); + if (g_client_stats_store != NULL) { + census_ht_destroy(g_client_stats_store); + g_client_stats_store = NULL; + } else { + gpr_log(GPR_ERROR, "Census server stats store not initialized."); + } + if (g_server_stats_store != NULL) { + census_ht_destroy(g_server_stats_store); + g_server_stats_store = NULL; + } else { + gpr_log(GPR_ERROR, "Census client stats store not initialized."); + } + gpr_mu_unlock(&g_mu); +} diff --git a/src/core/lib/statistics/census_rpc_stats.h b/src/core/lib/statistics/census_rpc_stats.h new file mode 100644 index 0000000000..f7f220e45f --- /dev/null +++ b/src/core/lib/statistics/census_rpc_stats.h @@ -0,0 +1,101 @@ +/* + * + * Copyright 2015-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_STATISTICS_CENSUS_RPC_STATS_H +#define GRPC_CORE_STATISTICS_CENSUS_RPC_STATS_H + +#include +#include "src/core/statistics/census_interface.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct census_rpc_stats { + uint64_t cnt; + uint64_t rpc_error_cnt; + uint64_t app_error_cnt; + double elapsed_time_ms; + double api_request_bytes; + double wire_request_bytes; + double api_response_bytes; + double wire_response_bytes; +}; + +/* Creates an empty rpc stats object on heap. */ +census_rpc_stats *census_rpc_stats_create_empty(void); + +typedef struct census_per_method_rpc_stats { + const char *method; + census_rpc_stats minute_stats; /* cumulative stats in the past minute */ + census_rpc_stats hour_stats; /* cumulative stats in the past hour */ + census_rpc_stats total_stats; /* cumulative stats from last gc */ +} census_per_method_rpc_stats; + +typedef struct census_aggregated_rpc_stats { + int num_entries; + census_per_method_rpc_stats *stats; +} census_aggregated_rpc_stats; + +/* Initializes an aggregated rpc stats object to an empty state. */ +void census_aggregated_rpc_stats_set_empty(census_aggregated_rpc_stats *data); + +/* Records client side stats of a rpc. */ +void census_record_rpc_client_stats(census_op_id op_id, + const census_rpc_stats *stats); + +/* Records server side stats of a rpc. */ +void census_record_rpc_server_stats(census_op_id op_id, + const census_rpc_stats *stats); + +/* The following two functions are intended for inprocess query of + per-service per-method stats from grpc implementations. */ + +/* Populates *data_map with server side aggregated per-service per-method + stats. + DO NOT CALL from outside of grpc code. */ +void census_get_server_stats(census_aggregated_rpc_stats *data_map); + +/* Populates *data_map with client side aggregated per-service per-method + stats. + DO NOT CALL from outside of grpc code. */ +void census_get_client_stats(census_aggregated_rpc_stats *data_map); + +void census_stats_store_init(void); +void census_stats_store_shutdown(void); + +#ifdef __cplusplus +} +#endif + +#endif /* GRPC_CORE_STATISTICS_CENSUS_RPC_STATS_H */ diff --git a/src/core/lib/statistics/census_tracing.c b/src/core/lib/statistics/census_tracing.c new file mode 100644 index 0000000000..ad82498eba --- /dev/null +++ b/src/core/lib/statistics/census_tracing.c @@ -0,0 +1,241 @@ +/* + * + * Copyright 2015-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/statistics/census_tracing.h" +#include "src/core/statistics/census_interface.h" + +#include +#include + +#include +#include +#include +#include +#include "src/core/statistics/hash_table.h" +#include "src/core/support/string.h" + +void census_trace_obj_destroy(census_trace_obj *obj) { + census_trace_annotation *p = obj->annotations; + while (p != NULL) { + census_trace_annotation *next = p->next; + gpr_free(p); + p = next; + } + gpr_free(obj->method); + gpr_free(obj); +} + +static void delete_trace_obj(void *obj) { + census_trace_obj_destroy((census_trace_obj *)obj); +} + +static const census_ht_option ht_opt = { + CENSUS_HT_UINT64 /* key type */, + 571 /* n_of_buckets */, + NULL /* hash */, + NULL /* compare_keys */, + delete_trace_obj /* delete data */, + NULL /* delete key */ +}; + +static gpr_once g_init_mutex_once = GPR_ONCE_INIT; +static gpr_mu g_mu; /* Guards following two static variables. */ +static census_ht *g_trace_store = NULL; +static uint64_t g_id = 0; + +static census_ht_key op_id_as_key(census_op_id *id) { + return *(census_ht_key *)id; +} + +static uint64_t op_id_2_uint64(census_op_id *id) { + uint64_t ret; + memcpy(&ret, id, sizeof(census_op_id)); + return ret; +} + +static void init_mutex(void) { gpr_mu_init(&g_mu); } + +static void init_mutex_once(void) { + gpr_once_init(&g_init_mutex_once, init_mutex); +} + +census_op_id census_tracing_start_op(void) { + gpr_mu_lock(&g_mu); + { + census_trace_obj *ret = gpr_malloc(sizeof(census_trace_obj)); + memset(ret, 0, sizeof(census_trace_obj)); + g_id++; + memcpy(&ret->id, &g_id, sizeof(census_op_id)); + ret->rpc_stats.cnt = 1; + ret->ts = gpr_now(GPR_CLOCK_REALTIME); + census_ht_insert(g_trace_store, op_id_as_key(&ret->id), (void *)ret); + gpr_log(GPR_DEBUG, "Start tracing for id %lu", g_id); + gpr_mu_unlock(&g_mu); + return ret->id; + } +} + +int census_add_method_tag(census_op_id op_id, const char *method) { + int ret = 0; + census_trace_obj *trace = NULL; + gpr_mu_lock(&g_mu); + trace = census_ht_find(g_trace_store, op_id_as_key(&op_id)); + if (trace == NULL) { + ret = 1; + } else { + trace->method = gpr_strdup(method); + } + gpr_mu_unlock(&g_mu); + return ret; +} + +void census_tracing_print(census_op_id op_id, const char *anno_txt) { + census_trace_obj *trace = NULL; + gpr_mu_lock(&g_mu); + trace = census_ht_find(g_trace_store, op_id_as_key(&op_id)); + if (trace != NULL) { + census_trace_annotation *anno = gpr_malloc(sizeof(census_trace_annotation)); + anno->ts = gpr_now(GPR_CLOCK_REALTIME); + { + char *d = anno->txt; + const char *s = anno_txt; + int n = 0; + for (; n < CENSUS_MAX_ANNOTATION_LENGTH && *s != '\0'; ++n) { + *d++ = *s++; + } + *d = '\0'; + } + anno->next = trace->annotations; + trace->annotations = anno; + } + gpr_mu_unlock(&g_mu); +} + +void census_tracing_end_op(census_op_id op_id) { + census_trace_obj *trace = NULL; + gpr_mu_lock(&g_mu); + trace = census_ht_find(g_trace_store, op_id_as_key(&op_id)); + if (trace != NULL) { + trace->rpc_stats.elapsed_time_ms = gpr_timespec_to_micros( + gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), trace->ts)); + gpr_log(GPR_DEBUG, "End tracing for id %lu, method %s, latency %f us", + op_id_2_uint64(&op_id), trace->method, + trace->rpc_stats.elapsed_time_ms); + census_ht_erase(g_trace_store, op_id_as_key(&op_id)); + } + gpr_mu_unlock(&g_mu); +} + +void census_tracing_init(void) { + init_mutex_once(); + gpr_mu_lock(&g_mu); + if (g_trace_store == NULL) { + g_id = 1; + g_trace_store = census_ht_create(&ht_opt); + } else { + gpr_log(GPR_ERROR, "Census trace store already initialized."); + } + gpr_mu_unlock(&g_mu); +} + +void census_tracing_shutdown(void) { + gpr_mu_lock(&g_mu); + if (g_trace_store != NULL) { + census_ht_destroy(g_trace_store); + g_trace_store = NULL; + } else { + gpr_log(GPR_ERROR, "Census trace store is not initialized."); + } + gpr_mu_unlock(&g_mu); +} + +void census_internal_lock_trace_store(void) { gpr_mu_lock(&g_mu); } + +void census_internal_unlock_trace_store(void) { gpr_mu_unlock(&g_mu); } + +census_trace_obj *census_get_trace_obj_locked(census_op_id op_id) { + if (g_trace_store == NULL) { + gpr_log(GPR_ERROR, "Census trace store is not initialized."); + return NULL; + } + return (census_trace_obj *)census_ht_find(g_trace_store, + op_id_as_key(&op_id)); +} + +const char *census_get_trace_method_name(const census_trace_obj *trace) { + return trace->method; +} + +static census_trace_annotation *dup_annotation_chain( + census_trace_annotation *from) { + census_trace_annotation *ret = NULL; + census_trace_annotation **to = &ret; + for (; from != NULL; from = from->next) { + *to = gpr_malloc(sizeof(census_trace_annotation)); + memcpy(*to, from, sizeof(census_trace_annotation)); + to = &(*to)->next; + } + return ret; +} + +static census_trace_obj *trace_obj_dup(census_trace_obj *from) { + census_trace_obj *to = NULL; + GPR_ASSERT(from != NULL); + to = gpr_malloc(sizeof(census_trace_obj)); + to->id = from->id; + to->ts = from->ts; + to->rpc_stats = from->rpc_stats; + to->method = gpr_strdup(from->method); + to->annotations = dup_annotation_chain(from->annotations); + return to; +} + +census_trace_obj **census_get_active_ops(int *num_active_ops) { + census_trace_obj **ret = NULL; + gpr_mu_lock(&g_mu); + if (g_trace_store != NULL) { + size_t n = 0; + census_ht_kv *all_kvs = census_ht_get_all_elements(g_trace_store, &n); + *num_active_ops = (int)n; + if (n != 0) { + size_t i = 0; + ret = gpr_malloc(sizeof(census_trace_obj *) * n); + for (i = 0; i < n; i++) { + ret[i] = trace_obj_dup((census_trace_obj *)all_kvs[i].v); + } + } + gpr_free(all_kvs); + } + gpr_mu_unlock(&g_mu); + return ret; +} diff --git a/src/core/lib/statistics/census_tracing.h b/src/core/lib/statistics/census_tracing.h new file mode 100644 index 0000000000..b611e95bf4 --- /dev/null +++ b/src/core/lib/statistics/census_tracing.h @@ -0,0 +1,96 @@ +/* + * + * Copyright 2015-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_STATISTICS_CENSUS_TRACING_H +#define GRPC_CORE_STATISTICS_CENSUS_TRACING_H + +#include +#include "src/core/statistics/census_rpc_stats.h" + +/* WARNING: The data structures and APIs provided by this file are for GRPC + library's internal use ONLY. They might be changed in backward-incompatible + ways and are not subject to any deprecation policy. + They are not recommended for external use. + */ +#ifdef __cplusplus +extern "C" { +#endif + +/* Struct for a trace annotation. */ +typedef struct census_trace_annotation { + gpr_timespec ts; /* timestamp of the annotation */ + char txt[CENSUS_MAX_ANNOTATION_LENGTH + 1]; /* actual txt annotation */ + struct census_trace_annotation *next; +} census_trace_annotation; + +typedef struct census_trace_obj { + census_op_id id; + gpr_timespec ts; + census_rpc_stats rpc_stats; + char *method; + census_trace_annotation *annotations; +} census_trace_obj; + +/* Deletes trace object. */ +void census_trace_obj_destroy(census_trace_obj *obj); + +/* Initializes trace store. This function is thread safe. */ +void census_tracing_init(void); + +/* Shutsdown trace store. This function is thread safe. */ +void census_tracing_shutdown(void); + +/* Gets trace obj corresponding to the input op_id. Returns NULL if trace store + is not initialized or trace obj is not found. Requires trace store being + locked before calling this function. */ +census_trace_obj *census_get_trace_obj_locked(census_op_id op_id); + +/* The following two functions acquire and release the trace store global lock. + They are for census internal use only. */ +void census_internal_lock_trace_store(void); +void census_internal_unlock_trace_store(void); + +/* Gets method name associated with the input trace object. */ +const char *census_get_trace_method_name(const census_trace_obj *trace); + +/* Returns an array of pointers to trace objects of currently active operations + and fills in number of active operations. Returns NULL if there are no active + operations. + Caller owns the returned objects. */ +census_trace_obj **census_get_active_ops(int *num_active_ops); + +#ifdef __cplusplus +} +#endif + +#endif /* GRPC_CORE_STATISTICS_CENSUS_TRACING_H */ diff --git a/src/core/lib/statistics/hash_table.c b/src/core/lib/statistics/hash_table.c new file mode 100644 index 0000000000..3ef79c0d7d --- /dev/null +++ b/src/core/lib/statistics/hash_table.c @@ -0,0 +1,303 @@ +/* + * + * Copyright 2015-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/statistics/hash_table.h" + +#include +#include + +#include +#include +#include + +#define CENSUS_HT_NUM_BUCKETS 1999 + +/* A single hash table data entry */ +typedef struct ht_entry { + census_ht_key key; + void *data; + struct ht_entry *next; +} ht_entry; + +/* hash table bucket */ +typedef struct bucket { + /* NULL if bucket is empty */ + ht_entry *next; + /* -1 if all buckets are empty. */ + int32_t prev_non_empty_bucket; + /* -1 if all buckets are empty. */ + int32_t next_non_empty_bucket; +} bucket; + +struct unresizable_hash_table { + /* Number of entries in the table */ + size_t size; + /* Number of buckets */ + uint32_t num_buckets; + /* Array of buckets initialized at creation time. Memory consumption is + 16 bytes per bucket on a 64-bit platform. */ + bucket *buckets; + /* Index of the first non-empty bucket. -1 iff size == 0. */ + int32_t first_non_empty_bucket; + /* Index of the last non_empty bucket. -1 iff size == 0. */ + int32_t last_non_empty_bucket; + /* Immutable options of this hash table, initialized at creation time. */ + census_ht_option options; +}; + +typedef struct entry_locator { + int32_t bucket_idx; + int is_first_in_chain; + int found; + ht_entry *prev_entry; +} entry_locator; + +/* Asserts if option is not valid. */ +void check_options(const census_ht_option *option) { + GPR_ASSERT(option != NULL); + GPR_ASSERT(option->num_buckets > 0); + GPR_ASSERT(option->key_type == CENSUS_HT_UINT64 || + option->key_type == CENSUS_HT_POINTER); + if (option->key_type == CENSUS_HT_UINT64) { + GPR_ASSERT(option->hash == NULL); + } else if (option->key_type == CENSUS_HT_POINTER) { + GPR_ASSERT(option->hash != NULL); + GPR_ASSERT(option->compare_keys != NULL); + } +} + +#define REMOVE_NEXT(options, ptr) \ + do { \ + ht_entry *tmp = (ptr)->next; \ + (ptr)->next = tmp->next; \ + delete_entry(options, tmp); \ + } while (0) + +static void delete_entry(const census_ht_option *opt, ht_entry *p) { + if (opt->delete_data != NULL) { + opt->delete_data(p->data); + } + if (opt->delete_key != NULL) { + opt->delete_key(p->key.ptr); + } + gpr_free(p); +} + +static uint64_t hash(const census_ht_option *opt, census_ht_key key) { + return opt->key_type == CENSUS_HT_UINT64 ? key.val : opt->hash(key.ptr); +} + +census_ht *census_ht_create(const census_ht_option *option) { + int i; + census_ht *ret = NULL; + check_options(option); + ret = (census_ht *)gpr_malloc(sizeof(census_ht)); + ret->size = 0; + ret->num_buckets = option->num_buckets; + ret->buckets = (bucket *)gpr_malloc(sizeof(bucket) * ret->num_buckets); + ret->options = *option; + /* initialize each bucket */ + for (i = 0; i < ret->options.num_buckets; i++) { + ret->buckets[i].prev_non_empty_bucket = -1; + ret->buckets[i].next_non_empty_bucket = -1; + ret->buckets[i].next = NULL; + } + return ret; +} + +static int32_t find_bucket_idx(const census_ht *ht, census_ht_key key) { + return hash(&ht->options, key) % ht->num_buckets; +} + +static int keys_match(const census_ht_option *opt, const ht_entry *p, + const census_ht_key key) { + GPR_ASSERT(opt->key_type == CENSUS_HT_UINT64 || + opt->key_type == CENSUS_HT_POINTER); + if (opt->key_type == CENSUS_HT_UINT64) return p->key.val == key.val; + return !opt->compare_keys((p->key).ptr, key.ptr); +} + +static entry_locator ht_find(const census_ht *ht, census_ht_key key) { + entry_locator loc = {0, 0, 0, NULL}; + int32_t idx = 0; + ht_entry *ptr = NULL; + GPR_ASSERT(ht != NULL); + idx = find_bucket_idx(ht, key); + ptr = ht->buckets[idx].next; + if (ptr == NULL) { + /* bucket is empty */ + return loc; + } + if (keys_match(&ht->options, ptr, key)) { + loc.bucket_idx = idx; + loc.is_first_in_chain = 1; + loc.found = 1; + return loc; + } else { + for (; ptr->next != NULL; ptr = ptr->next) { + if (keys_match(&ht->options, ptr->next, key)) { + loc.bucket_idx = idx; + loc.is_first_in_chain = 0; + loc.found = 1; + loc.prev_entry = ptr; + return loc; + } + } + } + /* Could not find the key */ + return loc; +} + +void *census_ht_find(const census_ht *ht, census_ht_key key) { + entry_locator loc = ht_find(ht, key); + if (loc.found == 0) { + return NULL; + } + return loc.is_first_in_chain ? ht->buckets[loc.bucket_idx].next->data + : loc.prev_entry->next->data; +} + +void census_ht_insert(census_ht *ht, census_ht_key key, void *data) { + int32_t idx = find_bucket_idx(ht, key); + ht_entry *ptr = NULL; + entry_locator loc = ht_find(ht, key); + if (loc.found) { + /* Replace old value with new value. */ + ptr = loc.is_first_in_chain ? ht->buckets[loc.bucket_idx].next + : loc.prev_entry->next; + if (ht->options.delete_data != NULL) { + ht->options.delete_data(ptr->data); + } + ptr->data = data; + return; + } + + /* first entry in the table. */ + if (ht->size == 0) { + ht->buckets[idx].next_non_empty_bucket = -1; + ht->buckets[idx].prev_non_empty_bucket = -1; + ht->first_non_empty_bucket = idx; + ht->last_non_empty_bucket = idx; + } else if (ht->buckets[idx].next == NULL) { + /* first entry in the bucket. */ + ht->buckets[ht->last_non_empty_bucket].next_non_empty_bucket = idx; + ht->buckets[idx].prev_non_empty_bucket = ht->last_non_empty_bucket; + ht->buckets[idx].next_non_empty_bucket = -1; + ht->last_non_empty_bucket = idx; + } + ptr = (ht_entry *)gpr_malloc(sizeof(ht_entry)); + ptr->key = key; + ptr->data = data; + ptr->next = ht->buckets[idx].next; + ht->buckets[idx].next = ptr; + ht->size++; +} + +void census_ht_erase(census_ht *ht, census_ht_key key) { + entry_locator loc = ht_find(ht, key); + if (loc.found == 0) { + /* noop if not found */ + return; + } + ht->size--; + if (loc.is_first_in_chain) { + bucket *b = &ht->buckets[loc.bucket_idx]; + GPR_ASSERT(b->next != NULL); + /* The only entry in the bucket */ + if (b->next->next == NULL) { + int prev = b->prev_non_empty_bucket; + int next = b->next_non_empty_bucket; + if (prev != -1) { + ht->buckets[prev].next_non_empty_bucket = next; + } else { + ht->first_non_empty_bucket = next; + } + if (next != -1) { + ht->buckets[next].prev_non_empty_bucket = prev; + } else { + ht->last_non_empty_bucket = prev; + } + } + REMOVE_NEXT(&ht->options, b); + } else { + GPR_ASSERT(loc.prev_entry->next != NULL); + REMOVE_NEXT(&ht->options, loc.prev_entry); + } +} + +/* Returns NULL if input table is empty. */ +census_ht_kv *census_ht_get_all_elements(const census_ht *ht, size_t *num) { + census_ht_kv *ret = NULL; + int i = 0; + int32_t idx = -1; + GPR_ASSERT(ht != NULL && num != NULL); + *num = ht->size; + if (*num == 0) { + return NULL; + } + + ret = (census_ht_kv *)gpr_malloc(sizeof(census_ht_kv) * ht->size); + idx = ht->first_non_empty_bucket; + while (idx >= 0) { + ht_entry *ptr = ht->buckets[idx].next; + for (; ptr != NULL; ptr = ptr->next) { + ret[i].k = ptr->key; + ret[i].v = ptr->data; + i++; + } + idx = ht->buckets[idx].next_non_empty_bucket; + } + return ret; +} + +static void ht_delete_entry_chain(const census_ht_option *options, + ht_entry *first) { + if (first == NULL) { + return; + } + if (first->next != NULL) { + ht_delete_entry_chain(options, first->next); + } + delete_entry(options, first); +} + +void census_ht_destroy(census_ht *ht) { + unsigned i; + for (i = 0; i < ht->num_buckets; ++i) { + ht_delete_entry_chain(&ht->options, ht->buckets[i].next); + } + gpr_free(ht->buckets); + gpr_free(ht); +} + +size_t census_ht_get_size(const census_ht *ht) { return ht->size; } diff --git a/src/core/lib/statistics/hash_table.h b/src/core/lib/statistics/hash_table.h new file mode 100644 index 0000000000..f4bf2ba49a --- /dev/null +++ b/src/core/lib/statistics/hash_table.h @@ -0,0 +1,131 @@ +/* + * + * Copyright 2015-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_STATISTICS_HASH_TABLE_H +#define GRPC_CORE_STATISTICS_HASH_TABLE_H + +#include + +#include + +/* A chain based hash table with fixed number of buckets. + Your probably shouldn't use this code directly. It is implemented for the + use case in census trace store and stats store, where number of entries in + the table is in the scale of upto several thousands, entries are added and + removed from the table very frequently (~100k/s), the frequency of find() + operations is roughly several times of the frequency of insert() and erase() + Comparing to find(), the insert(), erase() and get_all_entries() operations + are much less freqent (<1/s). + + Per bucket memory overhead is about (8 + sizeof(intptr_t) bytes. + Per entry memory overhead is about (8 + 2 * sizeof(intptr_t) bytes. + + All functions are not thread-safe. Synchronization will be provided in the + upper layer (in trace store and stats store). +*/ + +/* Opaque hash table struct */ +typedef struct unresizable_hash_table census_ht; + +/* Currently, the hash_table can take two types of keys. (uint64 for trace + store and const char* for stats store). */ +typedef union { + uint64_t val; + void *ptr; +} census_ht_key; + +typedef enum census_ht_key_type { + CENSUS_HT_UINT64 = 0, + CENSUS_HT_POINTER = 1 +} census_ht_key_type; + +typedef struct census_ht_option { + /* Type of hash key */ + census_ht_key_type key_type; + /* Desired number of buckets, preferably a prime number */ + int32_t num_buckets; + /* Fucntion to calculate uint64 hash value of the key. Only takes effect if + key_type is POINTER. */ + uint64_t (*hash)(const void *); + /* Function to compare two keys, returns 0 iff equal. Only takes effect if + key_type is POINTER */ + int (*compare_keys)(const void *k1, const void *k2); + /* Value deleter. NULL if no specialized delete function is needed. */ + void (*delete_data)(void *); + /* Key deleter. NULL if table does not own the key. (e.g. key is part of the + value or key is not owned by the table.) */ + void (*delete_key)(void *); +} census_ht_option; + +/* Creates a hashtable with fixed number of buckets according to the settings + specified in 'options' arg. Function pointers "hash" and "compare_keys" must + be provided if key_type is POINTER. Asserts if fail to create. */ +census_ht *census_ht_create(const census_ht_option *options); + +/* Deletes hash table instance. Frees all dynamic memory owned by ht.*/ +void census_ht_destroy(census_ht *ht); + +/* Inserts the input key-val pair into hash_table. If an entry with the same key + exists in the table, the corresponding value will be overwritten by the input + val. */ +void census_ht_insert(census_ht *ht, census_ht_key key, void *val); + +/* Returns pointer to data, returns NULL if not found. */ +void *census_ht_find(const census_ht *ht, census_ht_key key); + +/* Erase hash table entry with input key. Noop if key is not found. */ +void census_ht_erase(census_ht *ht, census_ht_key key); + +typedef struct census_ht_kv { + census_ht_key k; + void *v; +} census_ht_kv; + +/* Returns an array of pointers to all values in the hash table. Order of the + elements can be arbitrary. Sets 'num' to the size of returned array. Caller + owns returned array. */ +census_ht_kv *census_ht_get_all_elements(const census_ht *ht, size_t *num); + +/* Returns number of elements kept. */ +size_t census_ht_get_size(const census_ht *ht); + +/* Functor applied on each key-value pair while iterating through entries in the + table. The functor should not mutate data. */ +typedef void (*census_ht_itr_cb)(census_ht_key key, const void *val_ptr, + void *state); + +/* Iterates through all key-value pairs in the hash_table. The callback function + should not invalidate data entries. */ +uint64_t census_ht_for_all(const census_ht *ht, census_ht_itr_cb); + +#endif /* GRPC_CORE_STATISTICS_HASH_TABLE_H */ diff --git a/src/core/lib/statistics/window_stats.c b/src/core/lib/statistics/window_stats.c new file mode 100644 index 0000000000..eb296865a0 --- /dev/null +++ b/src/core/lib/statistics/window_stats.c @@ -0,0 +1,316 @@ +/* + * + * Copyright 2015-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/statistics/window_stats.h" +#include +#include +#include +#include +#include +#include +#include + +/* typedefs make typing long names easier. Use cws (for census_window_stats) */ +typedef census_window_stats_stat_info cws_stat_info; +typedef struct census_window_stats_sum cws_sum; + +/* Each interval is composed of a number of buckets, which hold a count of + entries and a single statistic */ +typedef struct census_window_stats_bucket { + int64_t count; + void *statistic; +} cws_bucket; + +/* Each interval has a set of buckets, and the variables needed to keep + track of their current state */ +typedef struct census_window_stats_interval_stats { + /* The buckets. There will be 'granularity' + 1 of these. */ + cws_bucket *buckets; + /* Index of the bucket containing the smallest time interval. */ + int bottom_bucket; + /* The smallest time storable in the current window. */ + int64_t bottom; + /* The largest time storable in the current window + 1ns */ + int64_t top; + /* The width of each bucket in ns. */ + int64_t width; +} cws_interval_stats; + +typedef struct census_window_stats { + /* Number of intervals. */ + int nintervals; + /* Number of buckets in each interval. 'granularity' + 1. */ + int nbuckets; + /* Record of stat_info. */ + cws_stat_info stat_info; + /* Stats for each interval. */ + cws_interval_stats *interval_stats; + /* The time the newset stat was recorded. */ + int64_t newest_time; +} window_stats; + +/* Calculate an actual bucket index from a logical index 'IDX'. Other + parameters supply information on the interval struct and overall stats. */ +#define BUCKET_IDX(IS, IDX, WSTATS) \ + ((IS->bottom_bucket + (IDX)) % WSTATS->nbuckets) + +/* The maximum seconds value we can have in a valid timespec. More than this + will result in overflow in timespec_to_ns(). This works out to ~292 years. + TODO: consider using doubles instead of int64. */ +static int64_t max_seconds = (GPR_INT64_MAX - GPR_NS_PER_SEC) / GPR_NS_PER_SEC; + +static int64_t timespec_to_ns(const gpr_timespec ts) { + if (ts.tv_sec > max_seconds) { + return GPR_INT64_MAX - 1; + } + return ts.tv_sec * GPR_NS_PER_SEC + ts.tv_nsec; +} + +static void cws_initialize_statistic(void *statistic, + const cws_stat_info *stat_info) { + if (stat_info->stat_initialize == NULL) { + memset(statistic, 0, stat_info->stat_size); + } else { + stat_info->stat_initialize(statistic); + } +} + +/* Create and initialize a statistic */ +static void *cws_create_statistic(const cws_stat_info *stat_info) { + void *stat = gpr_malloc(stat_info->stat_size); + cws_initialize_statistic(stat, stat_info); + return stat; +} + +window_stats *census_window_stats_create(int nintervals, + const gpr_timespec intervals[], + int granularity, + const cws_stat_info *stat_info) { + window_stats *ret; + int i; + /* validate inputs */ + GPR_ASSERT(nintervals > 0 && granularity > 2 && intervals != NULL && + stat_info != NULL); + for (i = 0; i < nintervals; i++) { + int64_t ns = timespec_to_ns(intervals[i]); + GPR_ASSERT(intervals[i].tv_sec >= 0 && intervals[i].tv_nsec >= 0 && + intervals[i].tv_nsec < GPR_NS_PER_SEC && ns >= 100 && + granularity * 10 <= ns); + } + /* Allocate and initialize relevant data structures */ + ret = (window_stats *)gpr_malloc(sizeof(window_stats)); + ret->nintervals = nintervals; + ret->nbuckets = granularity + 1; + ret->stat_info = *stat_info; + ret->interval_stats = + (cws_interval_stats *)gpr_malloc(nintervals * sizeof(cws_interval_stats)); + for (i = 0; i < nintervals; i++) { + int64_t size_ns = timespec_to_ns(intervals[i]); + cws_interval_stats *is = ret->interval_stats + i; + cws_bucket *buckets = is->buckets = + (cws_bucket *)gpr_malloc(ret->nbuckets * sizeof(cws_bucket)); + int b; + for (b = 0; b < ret->nbuckets; b++) { + buckets[b].statistic = cws_create_statistic(stat_info); + buckets[b].count = 0; + } + is->bottom_bucket = 0; + is->bottom = 0; + is->width = size_ns / granularity; + /* Check for possible overflow issues, and maximize interval size if the + user requested something large enough. */ + if ((GPR_INT64_MAX - is->width) > size_ns) { + is->top = size_ns + is->width; + } else { + is->top = GPR_INT64_MAX; + is->width = GPR_INT64_MAX / (granularity + 1); + } + /* If size doesn't divide evenly, we can have a width slightly too small; + better to have it slightly large. */ + if ((size_ns - (granularity + 1) * is->width) > 0) { + is->width += 1; + } + } + ret->newest_time = 0; + return ret; +} + +/* When we try adding a measurement above the current interval range, we + need to "shift" the buckets sufficiently to cover the new range. */ +static void cws_shift_buckets(const window_stats *wstats, + cws_interval_stats *is, int64_t when_ns) { + int i; + /* number of bucket time widths to "shift" */ + int shift; + /* number of buckets to clear */ + int nclear; + GPR_ASSERT(when_ns >= is->top); + /* number of bucket time widths to "shift" */ + shift = ((when_ns - is->top) / is->width) + 1; + /* number of buckets to clear - limited by actual number of buckets */ + nclear = GPR_MIN(shift, wstats->nbuckets); + for (i = 0; i < nclear; i++) { + int b = BUCKET_IDX(is, i, wstats); + is->buckets[b].count = 0; + cws_initialize_statistic(is->buckets[b].statistic, &wstats->stat_info); + } + /* adjust top/bottom times and current bottom bucket */ + is->bottom_bucket = BUCKET_IDX(is, shift, wstats); + is->top += shift * is->width; + is->bottom += shift * is->width; +} + +void census_window_stats_add(window_stats *wstats, const gpr_timespec when, + const void *stat_value) { + int i; + int64_t when_ns = timespec_to_ns(when); + GPR_ASSERT(wstats->interval_stats != NULL); + for (i = 0; i < wstats->nintervals; i++) { + cws_interval_stats *is = wstats->interval_stats + i; + cws_bucket *bucket; + if (when_ns < is->bottom) { /* Below smallest time in interval: drop */ + continue; + } + if (when_ns >= is->top) { /* above limit: shift buckets */ + cws_shift_buckets(wstats, is, when_ns); + } + /* Add the stat. */ + GPR_ASSERT(is->bottom <= when_ns && when_ns < is->top); + bucket = is->buckets + + BUCKET_IDX(is, (when_ns - is->bottom) / is->width, wstats); + bucket->count++; + wstats->stat_info.stat_add(bucket->statistic, stat_value); + } + if (when_ns > wstats->newest_time) { + wstats->newest_time = when_ns; + } +} + +/* Add a specific bucket contents to an accumulating total. */ +static void cws_add_bucket_to_sum(cws_sum *sum, const cws_bucket *bucket, + const cws_stat_info *stat_info) { + sum->count += bucket->count; + stat_info->stat_add(sum->statistic, bucket->statistic); +} + +/* Add a proportion to an accumulating sum. */ +static void cws_add_proportion_to_sum(double p, cws_sum *sum, + const cws_bucket *bucket, + const cws_stat_info *stat_info) { + sum->count += p * bucket->count; + stat_info->stat_add_proportion(p, sum->statistic, bucket->statistic); +} + +void census_window_stats_get_sums(const window_stats *wstats, + const gpr_timespec when, cws_sum sums[]) { + int i; + int64_t when_ns = timespec_to_ns(when); + GPR_ASSERT(wstats->interval_stats != NULL); + for (i = 0; i < wstats->nintervals; i++) { + int when_bucket; + int new_bucket; + double last_proportion = 1.0; + double bottom_proportion; + cws_interval_stats *is = wstats->interval_stats + i; + cws_sum *sum = sums + i; + sum->count = 0; + cws_initialize_statistic(sum->statistic, &wstats->stat_info); + if (when_ns < is->bottom) { + continue; + } + if (when_ns >= is->top) { + cws_shift_buckets(wstats, is, when_ns); + } + /* Calculating the appropriate amount of which buckets to use can get + complicated. Essentially there are two cases: + 1) if the "top" bucket (new_bucket, where the newest additions to the + stats recorded are entered) corresponds to 'when', then we need + to take a proportion of it - (if when < newest_time) or the full + thing. We also (possibly) need to take a corresponding + proportion of the bottom bucket. + 2) Other cases, we just take a straight proportion. + */ + when_bucket = (when_ns - is->bottom) / is->width; + new_bucket = (wstats->newest_time - is->bottom) / is->width; + if (new_bucket == when_bucket) { + int64_t bottom_bucket_time = is->bottom + when_bucket * is->width; + if (when_ns < wstats->newest_time) { + last_proportion = (double)(when_ns - bottom_bucket_time) / + (double)(wstats->newest_time - bottom_bucket_time); + bottom_proportion = + (double)(is->width - (when_ns - bottom_bucket_time)) / is->width; + } else { + bottom_proportion = + (double)(is->width - (wstats->newest_time - bottom_bucket_time)) / + is->width; + } + } else { + last_proportion = + (double)(when_ns + 1 - is->bottom - when_bucket * is->width) / + is->width; + bottom_proportion = 1.0 - last_proportion; + } + cws_add_proportion_to_sum(last_proportion, sum, + is->buckets + BUCKET_IDX(is, when_bucket, wstats), + &wstats->stat_info); + if (when_bucket != 0) { /* last bucket isn't also bottom bucket */ + int b; + /* Add all of "bottom" bucket if we are looking at a subset of the + full interval, or a proportion if we are adding full interval. */ + cws_add_proportion_to_sum( + (when_bucket == wstats->nbuckets - 1 ? bottom_proportion : 1.0), sum, + is->buckets + is->bottom_bucket, &wstats->stat_info); + /* Add all the remaining buckets (everything but top and bottom). */ + for (b = 1; b < when_bucket; b++) { + cws_add_bucket_to_sum(sum, is->buckets + BUCKET_IDX(is, b, wstats), + &wstats->stat_info); + } + } + } +} + +void census_window_stats_destroy(window_stats *wstats) { + int i; + GPR_ASSERT(wstats->interval_stats != NULL); + for (i = 0; i < wstats->nintervals; i++) { + int b; + for (b = 0; b < wstats->nbuckets; b++) { + gpr_free(wstats->interval_stats[i].buckets[b].statistic); + } + gpr_free(wstats->interval_stats[i].buckets); + } + gpr_free(wstats->interval_stats); + /* Ensure any use-after free triggers assert. */ + wstats->interval_stats = NULL; + gpr_free(wstats); +} diff --git a/src/core/lib/statistics/window_stats.h b/src/core/lib/statistics/window_stats.h new file mode 100644 index 0000000000..774277180f --- /dev/null +++ b/src/core/lib/statistics/window_stats.h @@ -0,0 +1,173 @@ +/* + * + * Copyright 2015-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_STATISTICS_WINDOW_STATS_H +#define GRPC_CORE_STATISTICS_WINDOW_STATS_H + +#include + +/* Keep rolling sums of a user-defined statistic (containing a number of + measurements) over a a number of time intervals ("windows"). For example, + you can use a window_stats object to answer questions such as + "Approximately how many RPCs/s did I receive over the past minute, and + approximately how many bytes did I send out over that period?". + + The type of data to record, and the time intervals to keep are specified + when creating the object via a call to census_window_stats_create(). + + A window's interval is divided into one or more "buckets"; the interval + must be divisible by the number of buckets. Internally, these buckets + control the granularity of window_stats' measurements. Increasing the + number of buckets lets the object respond more quickly to changes in the + overall rate of data added into the object, at the cost of additional + memory usage. + + Here's some code which keeps one minute/hour measurements for two values + (latency in seconds and bytes transferred), with each interval divided into + 4 buckets. + + typedef struct my_stat { + double latency; + int bytes; + } my_stat; + + void add_my_stat(void* base, const void* addme) { + my_stat* b = (my_stat*)base; + const my_stat* a = (const my_stat*)addme; + b->latency += a->latency; + b->bytes += a->bytes; + } + + void add_proportion_my_stat(double p, void* base, const void* addme) { + (my_stat*)result->latency += p * (const my_stat*)base->latency; + (my_stat*)result->bytes += p * (const my_stat*)base->bytes; + } + + #define kNumIntervals 2 + #define kMinInterval 0 + #define kHourInterval 1 + #define kNumBuckets 4 + + const struct census_window_stats_stat_info kMyStatInfo + = { sizeof(my_stat), NULL, add_my_stat, add_proportion_my_stat }; + gpr_timespec intervals[kNumIntervals] = {{60, 0}, {3600, 0}}; + my_stat stat; + my_stat sums[kNumIntervals]; + census_window_stats_sums result[kNumIntervals]; + struct census_window_stats* stats + = census_window_stats_create(kNumIntervals, intervals, kNumBuckets, + &kMyStatInfo); + // Record a new event, taking 15.3ms, transferring 1784 bytes. + stat.latency = 0.153; + stat.bytes = 1784; + census_window_stats_add(stats, gpr_now(GPR_CLOCK_REALTIME), &stat); + // Get sums and print them out + result[kMinInterval].statistic = &sums[kMinInterval]; + result[kHourInterval].statistic = &sums[kHourInterval]; + census_window_stats_get_sums(stats, gpr_now(GPR_CLOCK_REALTIME), result); + printf("%d events/min, average time %gs, average bytes %g\n", + result[kMinInterval].count, + (my_stat*)result[kMinInterval].statistic->latency / + result[kMinInterval].count, + (my_stat*)result[kMinInterval].statistic->bytes / + result[kMinInterval].count + ); + printf("%d events/hr, average time %gs, average bytes %g\n", + result[kHourInterval].count, + (my_stat*)result[kHourInterval].statistic->latency / + result[kHourInterval].count, + (my_stat*)result[kHourInterval].statistic->bytes / + result[kHourInterval].count + ); +*/ + +/* Opaque structure for representing window_stats object */ +struct census_window_stats; + +/* Information provided by API user on the information they want to record */ +typedef struct census_window_stats_stat_info { + /* Number of bytes in user-defined object. */ + size_t stat_size; + /* Function to initialize a user-defined statistics object. If this is set + * to NULL, then the object will be zero-initialized. */ + void (*stat_initialize)(void *stat); + /* Function to add one user-defined statistics object ('addme') to 'base' */ + void (*stat_add)(void *base, const void *addme); + /* As for previous function, but only add a proportion 'p'. This API will + currently only use 'p' values in the range [0,1], but other values are + possible in the future, and should be supported. */ + void (*stat_add_proportion)(double p, void *base, const void *addme); +} census_window_stats_stat_info; + +/* Create a new window_stats object. 'nintervals' is the number of + 'intervals', and must be >=1. 'granularity' is the number of buckets, with + a larger number using more memory, but providing greater accuracy of + results. 'granularity should be > 2. We also require that each interval be + at least 10 * 'granularity' nanoseconds in size. 'stat_info' contains + information about the statistic to be gathered. Intervals greater than ~192 + years will be treated as essentially infinite in size. This function will + GPR_ASSERT() if the object cannot be created or any of the parameters have + invalid values. This function is thread-safe. */ +struct census_window_stats *census_window_stats_create( + int nintervals, const gpr_timespec intervals[], int granularity, + const census_window_stats_stat_info *stat_info); + +/* Add a new measurement (in 'stat_value'), as of a given time ('when'). + This function is thread-compatible. */ +void census_window_stats_add(struct census_window_stats *wstats, + const gpr_timespec when, const void *stat_value); + +/* Structure used to record a single intervals sum for a given statistic */ +typedef struct census_window_stats_sum { + /* Total count of samples. Note that because some internal interpolation + is performed, the count of samples returned for each interval may not be an + integral value. */ + double count; + /* Sum for statistic */ + void *statistic; +} census_window_stats_sums; + +/* Retrieve a set of all values stored in a window_stats object 'wstats'. The + number of 'sums' MUST be the same as the number 'nintervals' used in + census_window_stats_create(). This function is thread-compatible. */ +void census_window_stats_get_sums(const struct census_window_stats *wstats, + const gpr_timespec when, + struct census_window_stats_sum sums[]); + +/* Destroy a window_stats object. Once this function has been called, the + object will no longer be usable from any of the above functions (and + calling them will most likely result in a NULL-pointer dereference or + assertion failure). This function is thread-compatible. */ +void census_window_stats_destroy(struct census_window_stats *wstats); + +#endif /* GRPC_CORE_STATISTICS_WINDOW_STATS_H */ diff --git a/src/core/lib/support/alloc.c b/src/core/lib/support/alloc.c new file mode 100644 index 0000000000..fd9fb8f5e7 --- /dev/null +++ b/src/core/lib/support/alloc.c @@ -0,0 +1,90 @@ +/* + * + * Copyright 2015-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 + +#include +#include +#include +#include "src/core/profiling/timers.h" + +static gpr_allocation_functions g_alloc_functions = {malloc, realloc, free}; + +gpr_allocation_functions gpr_get_allocation_functions() { + return g_alloc_functions; +} + +void gpr_set_allocation_functions(gpr_allocation_functions functions) { + GPR_ASSERT(functions.malloc_fn != NULL); + GPR_ASSERT(functions.realloc_fn != NULL); + GPR_ASSERT(functions.free_fn != NULL); + g_alloc_functions = functions; +} + +void *gpr_malloc(size_t size) { + void *p; + GPR_TIMER_BEGIN("gpr_malloc", 0); + p = g_alloc_functions.malloc_fn(size); + if (!p) { + abort(); + } + GPR_TIMER_END("gpr_malloc", 0); + return p; +} + +void gpr_free(void *p) { + GPR_TIMER_BEGIN("gpr_free", 0); + g_alloc_functions.free_fn(p); + GPR_TIMER_END("gpr_free", 0); +} + +void *gpr_realloc(void *p, size_t size) { + GPR_TIMER_BEGIN("gpr_realloc", 0); + p = g_alloc_functions.realloc_fn(p, size); + if (!p) { + abort(); + } + GPR_TIMER_END("gpr_realloc", 0); + return p; +} + +void *gpr_malloc_aligned(size_t size, size_t alignment_log) { + size_t alignment = ((size_t)1) << alignment_log; + size_t extra = alignment - 1 + sizeof(void *); + void *p = gpr_malloc(size + extra); + void **ret = (void **)(((uintptr_t)p + extra) & ~(alignment - 1)); + ret[-1] = p; + return (void *)ret; +} + +void gpr_free_aligned(void *ptr) { gpr_free(((void **)ptr)[-1]); } diff --git a/src/core/lib/support/avl.c b/src/core/lib/support/avl.c new file mode 100644 index 0000000000..f378b3ee17 --- /dev/null +++ b/src/core/lib/support/avl.c @@ -0,0 +1,288 @@ +/* + * + * Copyright 2015-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 + +#include +#include + +#include +#include +#include + +gpr_avl gpr_avl_create(const gpr_avl_vtable *vtable) { + gpr_avl out; + out.vtable = vtable; + out.root = NULL; + return out; +} + +static gpr_avl_node *ref_node(gpr_avl_node *node) { + if (node) { + gpr_ref(&node->refs); + } + return node; +} + +static void unref_node(const gpr_avl_vtable *vtable, gpr_avl_node *node) { + if (node == NULL) { + return; + } + if (gpr_unref(&node->refs)) { + vtable->destroy_key(node->key); + vtable->destroy_value(node->value); + unref_node(vtable, node->left); + unref_node(vtable, node->right); + gpr_free(node); + } +} + +static long node_height(gpr_avl_node *node) { + return node == NULL ? 0 : node->height; +} + +#ifndef NDEBUG +static long calculate_height(gpr_avl_node *node) { + return node == NULL ? 0 : 1 + GPR_MAX(calculate_height(node->left), + calculate_height(node->right)); +} + +static gpr_avl_node *assert_invariants(gpr_avl_node *n) { + if (n == NULL) return NULL; + assert_invariants(n->left); + assert_invariants(n->right); + assert(calculate_height(n) == n->height); + assert(labs(node_height(n->left) - node_height(n->right)) <= 1); + return n; +} +#else +static gpr_avl_node *assert_invariants(gpr_avl_node *n) { return n; } +#endif + +gpr_avl_node *new_node(void *key, void *value, gpr_avl_node *left, + gpr_avl_node *right) { + gpr_avl_node *node = gpr_malloc(sizeof(*node)); + gpr_ref_init(&node->refs, 1); + node->key = key; + node->value = value; + node->left = assert_invariants(left); + node->right = assert_invariants(right); + node->height = 1 + GPR_MAX(node_height(left), node_height(right)); + return node; +} + +static gpr_avl_node *get(const gpr_avl_vtable *vtable, gpr_avl_node *node, + void *key) { + long cmp; + + if (node == NULL) { + return NULL; + } + + cmp = vtable->compare_keys(node->key, key); + if (cmp == 0) { + return node; + } else if (cmp > 0) { + return get(vtable, node->left, key); + } else { + return get(vtable, node->right, key); + } +} + +void *gpr_avl_get(gpr_avl avl, void *key) { + gpr_avl_node *node = get(avl.vtable, avl.root, key); + return node ? node->value : NULL; +} + +static gpr_avl_node *rotate_left(const gpr_avl_vtable *vtable, void *key, + void *value, gpr_avl_node *left, + gpr_avl_node *right) { + gpr_avl_node *n = + new_node(vtable->copy_key(right->key), vtable->copy_value(right->value), + new_node(key, value, left, ref_node(right->left)), + ref_node(right->right)); + unref_node(vtable, right); + return n; +} + +static gpr_avl_node *rotate_right(const gpr_avl_vtable *vtable, void *key, + void *value, gpr_avl_node *left, + gpr_avl_node *right) { + gpr_avl_node *n = new_node( + vtable->copy_key(left->key), vtable->copy_value(left->value), + ref_node(left->left), new_node(key, value, ref_node(left->right), right)); + unref_node(vtable, left); + return n; +} + +static gpr_avl_node *rotate_left_right(const gpr_avl_vtable *vtable, void *key, + void *value, gpr_avl_node *left, + gpr_avl_node *right) { + /* rotate_right(..., rotate_left(left), right) */ + gpr_avl_node *n = new_node( + vtable->copy_key(left->right->key), + vtable->copy_value(left->right->value), + new_node(vtable->copy_key(left->key), vtable->copy_value(left->value), + ref_node(left->left), ref_node(left->right->left)), + new_node(key, value, ref_node(left->right->right), right)); + unref_node(vtable, left); + return n; +} + +static gpr_avl_node *rotate_right_left(const gpr_avl_vtable *vtable, void *key, + void *value, gpr_avl_node *left, + gpr_avl_node *right) { + /* rotate_left(..., left, rotate_right(right)) */ + gpr_avl_node *n = new_node( + vtable->copy_key(right->left->key), + vtable->copy_value(right->left->value), + new_node(key, value, left, ref_node(right->left->left)), + new_node(vtable->copy_key(right->key), vtable->copy_value(right->value), + ref_node(right->left->right), ref_node(right->right))); + unref_node(vtable, right); + return n; +} + +static gpr_avl_node *rebalance(const gpr_avl_vtable *vtable, void *key, + void *value, gpr_avl_node *left, + gpr_avl_node *right) { + switch (node_height(left) - node_height(right)) { + case 2: + if (node_height(left->left) - node_height(left->right) == -1) { + return assert_invariants( + rotate_left_right(vtable, key, value, left, right)); + } else { + return assert_invariants(rotate_right(vtable, key, value, left, right)); + } + case -2: + if (node_height(right->left) - node_height(right->right) == 1) { + return assert_invariants( + rotate_right_left(vtable, key, value, left, right)); + } else { + return assert_invariants(rotate_left(vtable, key, value, left, right)); + } + default: + return assert_invariants(new_node(key, value, left, right)); + } +} + +static gpr_avl_node *add(const gpr_avl_vtable *vtable, gpr_avl_node *node, + void *key, void *value) { + long cmp; + if (node == NULL) { + return new_node(key, value, NULL, NULL); + } + cmp = vtable->compare_keys(node->key, key); + if (cmp == 0) { + return new_node(key, value, ref_node(node->left), ref_node(node->right)); + } else if (cmp > 0) { + return rebalance( + vtable, vtable->copy_key(node->key), vtable->copy_value(node->value), + add(vtable, node->left, key, value), ref_node(node->right)); + } else { + return rebalance(vtable, vtable->copy_key(node->key), + vtable->copy_value(node->value), ref_node(node->left), + add(vtable, node->right, key, value)); + } +} + +gpr_avl gpr_avl_add(gpr_avl avl, void *key, void *value) { + gpr_avl_node *old_root = avl.root; + avl.root = add(avl.vtable, avl.root, key, value); + assert_invariants(avl.root); + unref_node(avl.vtable, old_root); + return avl; +} + +static gpr_avl_node *in_order_head(gpr_avl_node *node) { + while (node->left != NULL) { + node = node->left; + } + return node; +} + +static gpr_avl_node *in_order_tail(gpr_avl_node *node) { + while (node->right != NULL) { + node = node->right; + } + return node; +} + +static gpr_avl_node *remove(const gpr_avl_vtable *vtable, gpr_avl_node *node, + void *key) { + long cmp; + if (node == NULL) { + return NULL; + } + cmp = vtable->compare_keys(node->key, key); + if (cmp == 0) { + if (node->left == NULL) { + return ref_node(node->right); + } else if (node->right == NULL) { + return ref_node(node->left); + } else if (node->left->height < node->right->height) { + gpr_avl_node *h = in_order_head(node->right); + return rebalance(vtable, vtable->copy_key(h->key), + vtable->copy_value(h->value), ref_node(node->left), + remove(vtable, node->right, h->key)); + } else { + gpr_avl_node *h = in_order_tail(node->left); + return rebalance( + vtable, vtable->copy_key(h->key), vtable->copy_value(h->value), + remove(vtable, node->left, h->key), ref_node(node->right)); + } + } else if (cmp > 0) { + return rebalance(vtable, vtable->copy_key(node->key), + vtable->copy_value(node->value), + remove(vtable, node->left, key), ref_node(node->right)); + } else { + return rebalance(vtable, vtable->copy_key(node->key), + vtable->copy_value(node->value), ref_node(node->left), + remove(vtable, node->right, key)); + } +} + +gpr_avl gpr_avl_remove(gpr_avl avl, void *key) { + gpr_avl_node *old_root = avl.root; + avl.root = remove(avl.vtable, avl.root, key); + assert_invariants(avl.root); + unref_node(avl.vtable, old_root); + return avl; +} + +gpr_avl gpr_avl_ref(gpr_avl avl) { + ref_node(avl.root); + return avl; +} + +void gpr_avl_unref(gpr_avl avl) { unref_node(avl.vtable, avl.root); } diff --git a/src/core/lib/support/backoff.c b/src/core/lib/support/backoff.c new file mode 100644 index 0000000000..4ccfb774ed --- /dev/null +++ b/src/core/lib/support/backoff.c @@ -0,0 +1,76 @@ +/* + * + * 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/support/backoff.h" + +#include + +void gpr_backoff_init(gpr_backoff *backoff, double multiplier, double jitter, + int64_t min_timeout_millis, int64_t max_timeout_millis) { + backoff->multiplier = multiplier; + backoff->jitter = jitter; + backoff->min_timeout_millis = min_timeout_millis; + backoff->max_timeout_millis = max_timeout_millis; + backoff->rng_state = (uint32_t)gpr_now(GPR_CLOCK_REALTIME).tv_nsec; +} + +gpr_timespec gpr_backoff_begin(gpr_backoff *backoff, gpr_timespec now) { + backoff->current_timeout_millis = backoff->min_timeout_millis; + return gpr_time_add( + now, gpr_time_from_millis(backoff->current_timeout_millis, GPR_TIMESPAN)); +} + +/* Generate a random number between 0 and 1. */ +static double generate_uniform_random_number(uint32_t *rng_state) { + *rng_state = (1103515245 * *rng_state + 12345) % ((uint32_t)1 << 31); + return *rng_state / (double)((uint32_t)1 << 31); +} + +gpr_timespec gpr_backoff_step(gpr_backoff *backoff, gpr_timespec now) { + double new_timeout_millis = + backoff->multiplier * (double)backoff->current_timeout_millis; + double jitter_range = backoff->jitter * new_timeout_millis; + double jitter = + (2 * generate_uniform_random_number(&backoff->rng_state) - 1) * + jitter_range; + backoff->current_timeout_millis = + GPR_CLAMP((int64_t)(new_timeout_millis + jitter), + backoff->min_timeout_millis, backoff->max_timeout_millis); + return gpr_time_add( + now, gpr_time_from_millis(backoff->current_timeout_millis, GPR_TIMESPAN)); +} + +void gpr_backoff_reset(gpr_backoff *backoff) { + // forces step() to return a timeout of min_timeout_millis + backoff->current_timeout_millis = 0; +} diff --git a/src/core/lib/support/backoff.h b/src/core/lib/support/backoff.h new file mode 100644 index 0000000000..0f933c3149 --- /dev/null +++ b/src/core/lib/support/backoff.h @@ -0,0 +1,68 @@ +/* + * + * 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_SUPPORT_BACKOFF_H +#define GRPC_CORE_SUPPORT_BACKOFF_H + +#include + +typedef struct { + /// const: multiplier between retry attempts + double multiplier; + /// const: amount to randomize backoffs + double jitter; + /// const: minimum time between retries in milliseconds + int64_t min_timeout_millis; + /// const: maximum time between retries in milliseconds + int64_t max_timeout_millis; + + /// random number generator + uint32_t rng_state; + + /// current retry timeout in milliseconds + int64_t current_timeout_millis; +} gpr_backoff; + +/// Initialize backoff machinery - does not need to be destroyed +void gpr_backoff_init(gpr_backoff *backoff, double multiplier, double jitter, + int64_t min_timeout_millis, int64_t max_timeout_millis); + +/// Begin retry loop: returns a timespec for the NEXT retry +gpr_timespec gpr_backoff_begin(gpr_backoff *backoff, gpr_timespec now); +/// Step a retry loop: returns a timespec for the NEXT retry +gpr_timespec gpr_backoff_step(gpr_backoff *backoff, gpr_timespec now); +/// Reset the backoff, so the next gpr_backoff_step will be a gpr_backoff_begin +/// instead +void gpr_backoff_reset(gpr_backoff *backoff); + +#endif /* GRPC_CORE_SUPPORT_BACKOFF_H */ diff --git a/src/core/lib/support/block_annotate.h b/src/core/lib/support/block_annotate.h new file mode 100644 index 0000000000..79a18039f4 --- /dev/null +++ b/src/core/lib/support/block_annotate.h @@ -0,0 +1,48 @@ +/* + * + * Copyright 2015-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_SUPPORT_BLOCK_ANNOTATE_H +#define GRPC_CORE_SUPPORT_BLOCK_ANNOTATE_H + +/* These annotations identify the beginning and end of regions where + the code may block for reasons other than synchronization functions. + These include poll, epoll, and getaddrinfo. */ + +#define GRPC_SCHEDULING_START_BLOCKING_REGION \ + do { \ + } while (0) +#define GRPC_SCHEDULING_END_BLOCKING_REGION \ + do { \ + } while (0) + +#endif /* GRPC_CORE_SUPPORT_BLOCK_ANNOTATE_H */ diff --git a/src/core/lib/support/cmdline.c b/src/core/lib/support/cmdline.c new file mode 100644 index 0000000000..eff46a1655 --- /dev/null +++ b/src/core/lib/support/cmdline.c @@ -0,0 +1,347 @@ +/* + * + * Copyright 2015-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 + +#include +#include +#include + +#include +#include +#include +#include "src/core/support/string.h" + +typedef enum { ARGTYPE_INT, ARGTYPE_BOOL, ARGTYPE_STRING } argtype; + +typedef struct arg { + const char *name; + const char *help; + argtype type; + void *value; + struct arg *next; +} arg; + +struct gpr_cmdline { + const char *description; + arg *args; + const char *argv0; + + const char *extra_arg_name; + const char *extra_arg_help; + void (*extra_arg)(void *user_data, const char *arg); + void *extra_arg_user_data; + + int (*state)(gpr_cmdline *cl, char *arg); + arg *cur_arg; + + int survive_failure; +}; + +static int normal_state(gpr_cmdline *cl, char *arg); + +gpr_cmdline *gpr_cmdline_create(const char *description) { + gpr_cmdline *cl = gpr_malloc(sizeof(gpr_cmdline)); + memset(cl, 0, sizeof(gpr_cmdline)); + + cl->description = description; + cl->state = normal_state; + + return cl; +} + +void gpr_cmdline_set_survive_failure(gpr_cmdline *cl) { + cl->survive_failure = 1; +} + +void gpr_cmdline_destroy(gpr_cmdline *cl) { + while (cl->args) { + arg *a = cl->args; + cl->args = a->next; + gpr_free(a); + } + gpr_free(cl); +} + +static void add_arg(gpr_cmdline *cl, const char *name, const char *help, + argtype type, void *value) { + arg *a; + + for (a = cl->args; a; a = a->next) { + GPR_ASSERT(0 != strcmp(a->name, name)); + } + + a = gpr_malloc(sizeof(arg)); + memset(a, 0, sizeof(arg)); + a->name = name; + a->help = help; + a->type = type; + a->value = value; + a->next = cl->args; + cl->args = a; +} + +void gpr_cmdline_add_int(gpr_cmdline *cl, const char *name, const char *help, + int *value) { + add_arg(cl, name, help, ARGTYPE_INT, value); +} + +void gpr_cmdline_add_flag(gpr_cmdline *cl, const char *name, const char *help, + int *value) { + add_arg(cl, name, help, ARGTYPE_BOOL, value); +} + +void gpr_cmdline_add_string(gpr_cmdline *cl, const char *name, const char *help, + char **value) { + add_arg(cl, name, help, ARGTYPE_STRING, value); +} + +void gpr_cmdline_on_extra_arg( + gpr_cmdline *cl, const char *name, const char *help, + void (*on_extra_arg)(void *user_data, const char *arg), void *user_data) { + GPR_ASSERT(!cl->extra_arg); + GPR_ASSERT(on_extra_arg); + + cl->extra_arg = on_extra_arg; + cl->extra_arg_user_data = user_data; + cl->extra_arg_name = name; + cl->extra_arg_help = help; +} + +/* recursively descend argument list, adding the last element + to s first - so that arguments are added in the order they were + added to the list by api calls */ +static void add_args_to_usage(gpr_strvec *s, arg *a) { + char *tmp; + + if (!a) return; + add_args_to_usage(s, a->next); + + switch (a->type) { + case ARGTYPE_BOOL: + gpr_asprintf(&tmp, " [--%s|--no-%s]", a->name, a->name); + gpr_strvec_add(s, tmp); + break; + case ARGTYPE_STRING: + gpr_asprintf(&tmp, " [--%s=string]", a->name); + gpr_strvec_add(s, tmp); + break; + case ARGTYPE_INT: + gpr_asprintf(&tmp, " [--%s=int]", a->name); + gpr_strvec_add(s, tmp); + break; + } +} + +char *gpr_cmdline_usage_string(gpr_cmdline *cl, const char *argv0) { + /* TODO(ctiller): make this prettier */ + gpr_strvec s; + char *tmp; + const char *name = strrchr(argv0, '/'); + + if (name) { + name++; + } else { + name = argv0; + } + + gpr_strvec_init(&s); + + gpr_asprintf(&tmp, "Usage: %s", name); + gpr_strvec_add(&s, tmp); + add_args_to_usage(&s, cl->args); + if (cl->extra_arg) { + gpr_asprintf(&tmp, " [%s...]", cl->extra_arg_name); + gpr_strvec_add(&s, tmp); + } + gpr_strvec_add(&s, gpr_strdup("\n")); + + tmp = gpr_strvec_flatten(&s, NULL); + gpr_strvec_destroy(&s); + return tmp; +} + +static int print_usage_and_die(gpr_cmdline *cl) { + char *usage = gpr_cmdline_usage_string(cl, cl->argv0); + fprintf(stderr, "%s", usage); + gpr_free(usage); + if (!cl->survive_failure) { + exit(1); + } + return 0; +} + +static int extra_state(gpr_cmdline *cl, char *str) { + if (!cl->extra_arg) { + return print_usage_and_die(cl); + } + cl->extra_arg(cl->extra_arg_user_data, str); + return 1; +} + +static arg *find_arg(gpr_cmdline *cl, char *name) { + arg *a; + + for (a = cl->args; a; a = a->next) { + if (0 == strcmp(a->name, name)) { + break; + } + } + + if (!a) { + fprintf(stderr, "Unknown argument: %s\n", name); + return NULL; + } + + return a; +} + +static int value_state(gpr_cmdline *cl, char *str) { + long intval; + char *end; + + GPR_ASSERT(cl->cur_arg); + + switch (cl->cur_arg->type) { + case ARGTYPE_INT: + intval = strtol(str, &end, 0); + if (*end || intval < INT_MIN || intval > INT_MAX) { + fprintf(stderr, "expected integer, got '%s' for %s\n", str, + cl->cur_arg->name); + return print_usage_and_die(cl); + } + *(int *)cl->cur_arg->value = (int)intval; + break; + case ARGTYPE_BOOL: + if (0 == strcmp(str, "1") || 0 == strcmp(str, "true")) { + *(int *)cl->cur_arg->value = 1; + } else if (0 == strcmp(str, "0") || 0 == strcmp(str, "false")) { + *(int *)cl->cur_arg->value = 0; + } else { + fprintf(stderr, "expected boolean, got '%s' for %s\n", str, + cl->cur_arg->name); + return print_usage_and_die(cl); + } + break; + case ARGTYPE_STRING: + *(char **)cl->cur_arg->value = str; + break; + } + + cl->state = normal_state; + return 1; +} + +static int normal_state(gpr_cmdline *cl, char *str) { + char *eq = NULL; + char *tmp = NULL; + char *arg_name = NULL; + int r = 1; + + if (0 == strcmp(str, "-help") || 0 == strcmp(str, "--help") || + 0 == strcmp(str, "-h")) { + return print_usage_and_die(cl); + } + + cl->cur_arg = NULL; + + if (str[0] == '-') { + if (str[1] == '-') { + if (str[2] == 0) { + /* handle '--' to move to just extra args */ + cl->state = extra_state; + return 1; + } + str += 2; + } else { + str += 1; + } + /* first byte of str is now past the leading '-' or '--' */ + if (str[0] == 'n' && str[1] == 'o' && str[2] == '-') { + /* str is of the form '--no-foo' - it's a flag disable */ + str += 3; + cl->cur_arg = find_arg(cl, str); + if (cl->cur_arg == NULL) { + return print_usage_and_die(cl); + } + if (cl->cur_arg->type != ARGTYPE_BOOL) { + fprintf(stderr, "%s is not a flag argument\n", str); + return print_usage_and_die(cl); + } + *(int *)cl->cur_arg->value = 0; + return 1; /* early out */ + } + eq = strchr(str, '='); + if (eq != NULL) { + /* copy the string into a temp buffer and extract the name */ + tmp = arg_name = gpr_malloc((size_t)(eq - str + 1)); + memcpy(arg_name, str, (size_t)(eq - str)); + arg_name[eq - str] = 0; + } else { + arg_name = str; + } + cl->cur_arg = find_arg(cl, arg_name); + if (cl->cur_arg == NULL) { + return print_usage_and_die(cl); + } + if (eq != NULL) { + /* str was of the type --foo=value, parse the value */ + r = value_state(cl, eq + 1); + } else if (cl->cur_arg->type != ARGTYPE_BOOL) { + /* flag types don't have a '--foo value' variant, other types do */ + cl->state = value_state; + } else { + /* flag parameter: just set the value */ + *(int *)cl->cur_arg->value = 1; + } + } else { + r = extra_state(cl, str); + } + + gpr_free(tmp); + return r; +} + +int gpr_cmdline_parse(gpr_cmdline *cl, int argc, char **argv) { + int i; + + GPR_ASSERT(argc >= 1); + cl->argv0 = argv[0]; + + for (i = 1; i < argc; i++) { + if (!cl->state(cl, argv[i])) { + return 0; + } + } + return 1; +} diff --git a/src/core/lib/support/cpu_iphone.c b/src/core/lib/support/cpu_iphone.c new file mode 100644 index 0000000000..82b49b47bc --- /dev/null +++ b/src/core/lib/support/cpu_iphone.c @@ -0,0 +1,49 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +#ifdef GPR_CPU_IPHONE + +/* Probably 2 instead of 1, but see comment on gpr_cpu_current_cpu. */ +unsigned gpr_cpu_num_cores(void) { return 1; } + +/* Most code that's using this is using it to shard across work queues. So + unless profiling shows it's a problem or there appears a way to detect the + currently running CPU core, let's have it shard the default way. + Note that the interface in cpu.h lets gpr_cpu_num_cores return 0, but doing + it makes it impossible for gpr_cpu_current_cpu to satisfy its stated range, + and some code might be relying on it. */ +unsigned gpr_cpu_current_cpu(void) { return 0; } + +#endif /* GPR_CPU_IPHONE */ diff --git a/src/core/lib/support/cpu_linux.c b/src/core/lib/support/cpu_linux.c new file mode 100644 index 0000000000..5597df2d03 --- /dev/null +++ b/src/core/lib/support/cpu_linux.c @@ -0,0 +1,78 @@ +/* + * + * Copyright 2015-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 _GNU_SOURCE +#define _GNU_SOURCE +#endif /* _GNU_SOURCE */ + +#include + +#ifdef GPR_CPU_LINUX + +#include +#include +#include +#include + +#include +#include +#include + +static int ncpus = 0; + +static void init_num_cpus() { + /* This must be signed. sysconf returns -1 when the number cannot be + determined */ + ncpus = (int)sysconf(_SC_NPROCESSORS_ONLN); + if (ncpus < 1) { + gpr_log(GPR_ERROR, "Cannot determine number of CPUs: assuming 1"); + ncpus = 1; + } +} + +unsigned gpr_cpu_num_cores(void) { + static gpr_once once = GPR_ONCE_INIT; + gpr_once_init(&once, init_num_cpus); + return (unsigned)ncpus; +} + +unsigned gpr_cpu_current_cpu(void) { + int cpu = sched_getcpu(); + if (cpu < 0) { + gpr_log(GPR_ERROR, "Error determining current CPU: %s\n", strerror(errno)); + return 0; + } + return (unsigned)cpu; +} + +#endif /* GPR_CPU_LINUX */ diff --git a/src/core/lib/support/cpu_posix.c b/src/core/lib/support/cpu_posix.c new file mode 100644 index 0000000000..e508ddd8ca --- /dev/null +++ b/src/core/lib/support/cpu_posix.c @@ -0,0 +1,77 @@ +/* + * + * Copyright 2015-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 + +#ifdef GPR_CPU_POSIX + +#include +#include +#include + +#include +#include + +static __thread char magic_thread_local; + +static long ncpus = 0; + +static void init_ncpus() { + ncpus = sysconf(_SC_NPROCESSORS_ONLN); + if (ncpus < 1 || ncpus > INT32_MAX) { + gpr_log(GPR_ERROR, "Cannot determine number of CPUs: assuming 1"); + ncpus = 1; + } +} + +unsigned gpr_cpu_num_cores(void) { + static gpr_once once = GPR_ONCE_INIT; + gpr_once_init(&once, init_ncpus); + return (unsigned)ncpus; +} + +/* This is a cheap, but good enough, pointer hash for sharding things: */ +static size_t shard_ptr(const void *info) { + size_t x = (size_t)info; + return ((x >> 4) ^ (x >> 9) ^ (x >> 14)) % gpr_cpu_num_cores(); +} + +unsigned gpr_cpu_current_cpu(void) { + /* NOTE: there's no way I know to return the actual cpu index portably... + most code that's using this is using it to shard across work queues though, + so here we use thread identity instead to achieve a similar though not + identical effect */ + return (unsigned)shard_ptr(&magic_thread_local); +} + +#endif /* GPR_CPU_POSIX */ diff --git a/src/core/lib/support/cpu_windows.c b/src/core/lib/support/cpu_windows.c new file mode 100644 index 0000000000..ce32eb0a9d --- /dev/null +++ b/src/core/lib/support/cpu_windows.c @@ -0,0 +1,47 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +#ifdef GPR_WIN32 +#include + +unsigned gpr_cpu_num_cores(void) { + SYSTEM_INFO si; + GetSystemInfo(&si); + return si.dwNumberOfProcessors; +} + +unsigned gpr_cpu_current_cpu(void) { return GetCurrentProcessorNumber(); } + +#endif /* GPR_WIN32 */ diff --git a/src/core/lib/support/env.h b/src/core/lib/support/env.h new file mode 100644 index 0000000000..2902456947 --- /dev/null +++ b/src/core/lib/support/env.h @@ -0,0 +1,60 @@ +/* + * + * Copyright 2015-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_SUPPORT_ENV_H +#define GRPC_CORE_SUPPORT_ENV_H + +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Env utility functions */ + +/* Gets the environment variable value with the specified name. + Returns a newly allocated string. It is the responsability of the caller to + gpr_free the return value if not NULL (which means that the environment + variable exists). */ +char *gpr_getenv(const char *name); + +/* Sets the the environment with the specified name to the specified value. */ +void gpr_setenv(const char *name, const char *value); + +#ifdef __cplusplus +} +#endif + +#endif /* GRPC_CORE_SUPPORT_ENV_H */ diff --git a/src/core/lib/support/env_linux.c b/src/core/lib/support/env_linux.c new file mode 100644 index 0000000000..fe51f846b7 --- /dev/null +++ b/src/core/lib/support/env_linux.c @@ -0,0 +1,89 @@ +/* + * + * Copyright 2015-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. + * + */ + +/* for secure_getenv. */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include + +#ifdef GPR_LINUX_ENV + +#include "src/core/support/env.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include "src/core/support/string.h" + +char *gpr_getenv(const char *name) { +#if defined(GPR_BACKWARDS_COMPATIBILITY_MODE) + typedef char *(*getenv_type)(const char *); + static getenv_type getenv_func = NULL; + /* Check to see which getenv variant is supported (go from most + * to least secure) */ + const char *names[] = {"secure_getenv", "__secure_getenv", "getenv"}; + for (size_t i = 0; getenv_func == NULL && i < GPR_ARRAY_SIZE(names); i++) { + getenv_func = (getenv_type)dlsym(RTLD_DEFAULT, names[i]); + if (getenv_func != NULL && strstr(names[i], "secure") == NULL) { + gpr_log(GPR_DEBUG, + "Warning: insecure environment read function '%s' used", + names[i]); + } + } + char *result = getenv_func(name); + return result == NULL ? result : gpr_strdup(result); +#elif __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 17) + char *result = secure_getenv(name); + return result == NULL ? result : gpr_strdup(result); +#else + gpr_log(GPR_DEBUG, "Warning: insecure environment read function '%s' used", + "getenv"); + char *result = getenv(name); + return result == NULL ? result : gpr_strdup(result); +#endif +} + +void gpr_setenv(const char *name, const char *value) { + int res = setenv(name, value, 1); + GPR_ASSERT(res == 0); +} + +#endif /* GPR_LINUX_ENV */ diff --git a/src/core/lib/support/env_posix.c b/src/core/lib/support/env_posix.c new file mode 100644 index 0000000000..256212be76 --- /dev/null +++ b/src/core/lib/support/env_posix.c @@ -0,0 +1,57 @@ +/* + * + * Copyright 2015-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 + +#ifdef GPR_POSIX_ENV + +#include "src/core/support/env.h" + +#include + +#include + +#include +#include "src/core/support/string.h" + +char *gpr_getenv(const char *name) { + char *result = getenv(name); + return result == NULL ? result : gpr_strdup(result); +} + +void gpr_setenv(const char *name, const char *value) { + int res = setenv(name, value, 1); + GPR_ASSERT(res == 0); +} + +#endif /* GPR_POSIX_ENV */ diff --git a/src/core/lib/support/env_win32.c b/src/core/lib/support/env_win32.c new file mode 100644 index 0000000000..10258283ba --- /dev/null +++ b/src/core/lib/support/env_win32.c @@ -0,0 +1,73 @@ +/* + * + * Copyright 2015-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 + +#ifdef GPR_WIN32 + +#include "src/core/support/env.h" +#include "src/core/support/string.h" + +#ifdef __MINGW32__ +errno_t getenv_s(size_t *size_needed, char *buffer, size_t size, + const char *varname); +#else +#include +#endif + +#include +#include +#include + +char *gpr_getenv(const char *name) { + size_t size; + char *result = NULL; + errno_t err; + + err = getenv_s(&size, NULL, 0, name); + if (err || (size == 0)) return NULL; + result = gpr_malloc(size); + err = getenv_s(&size, result, size, name); + if (err) { + gpr_free(result); + return NULL; + } + return result; +} + +void gpr_setenv(const char *name, const char *value) { + errno_t res = _putenv_s(name, value); + GPR_ASSERT(res == 0); +} + +#endif /* GPR_WIN32 */ diff --git a/src/core/lib/support/histogram.c b/src/core/lib/support/histogram.c new file mode 100644 index 0000000000..62227be1a6 --- /dev/null +++ b/src/core/lib/support/histogram.c @@ -0,0 +1,244 @@ +/* + * + * Copyright 2015-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 + +#include +#include +#include + +#include +#include +#include +#include + +/* Histograms are stored with exponentially increasing bucket sizes. + The first bucket is [0, m) where m = 1 + resolution + Bucket n (n>=1) contains [m**n, m**(n+1)) + There are sufficient buckets to reach max_bucket_start */ + +struct gpr_histogram { + /* Sum of all values seen so far */ + double sum; + /* Sum of squares of all values seen so far */ + double sum_of_squares; + /* number of values seen so far */ + double count; + /* m in the description */ + double multiplier; + double one_on_log_multiplier; + /* minimum value seen */ + double min_seen; + /* maximum value seen */ + double max_seen; + /* maximum representable value */ + double max_possible; + /* number of buckets */ + size_t num_buckets; + /* the buckets themselves */ + uint32_t *buckets; +}; + +/* determine a bucket index given a value - does no bounds checking */ +static size_t bucket_for_unchecked(gpr_histogram *h, double x) { + return (size_t)(log(x) * h->one_on_log_multiplier); +} + +/* bounds checked version of the above */ +static size_t bucket_for(gpr_histogram *h, double x) { + size_t bucket = bucket_for_unchecked(h, GPR_CLAMP(x, 1.0, h->max_possible)); + GPR_ASSERT(bucket < h->num_buckets); + return bucket; +} + +/* at what value does a bucket start? */ +static double bucket_start(gpr_histogram *h, double x) { + return pow(h->multiplier, x); +} + +gpr_histogram *gpr_histogram_create(double resolution, + double max_bucket_start) { + gpr_histogram *h = gpr_malloc(sizeof(gpr_histogram)); + GPR_ASSERT(resolution > 0.0); + GPR_ASSERT(max_bucket_start > resolution); + h->sum = 0.0; + h->sum_of_squares = 0.0; + h->multiplier = 1.0 + resolution; + h->one_on_log_multiplier = 1.0 / log(1.0 + resolution); + h->max_possible = max_bucket_start; + h->count = 0.0; + h->min_seen = max_bucket_start; + h->max_seen = 0.0; + h->num_buckets = bucket_for_unchecked(h, max_bucket_start) + 1; + GPR_ASSERT(h->num_buckets > 1); + GPR_ASSERT(h->num_buckets < 100000000); + h->buckets = gpr_malloc(sizeof(uint32_t) * h->num_buckets); + memset(h->buckets, 0, sizeof(uint32_t) * h->num_buckets); + return h; +} + +void gpr_histogram_destroy(gpr_histogram *h) { + gpr_free(h->buckets); + gpr_free(h); +} + +void gpr_histogram_add(gpr_histogram *h, double x) { + h->sum += x; + h->sum_of_squares += x * x; + h->count++; + if (x < h->min_seen) { + h->min_seen = x; + } + if (x > h->max_seen) { + h->max_seen = x; + } + h->buckets[bucket_for(h, x)]++; +} + +int gpr_histogram_merge(gpr_histogram *dst, const gpr_histogram *src) { + if ((dst->num_buckets != src->num_buckets) || + (dst->multiplier != src->multiplier)) { + /* Fail because these histograms don't match */ + return 0; + } + gpr_histogram_merge_contents(dst, src->buckets, src->num_buckets, + src->min_seen, src->max_seen, src->sum, + src->sum_of_squares, src->count); + return 1; +} + +void gpr_histogram_merge_contents(gpr_histogram *dst, const uint32_t *data, + size_t data_count, double min_seen, + double max_seen, double sum, + double sum_of_squares, double count) { + size_t i; + GPR_ASSERT(dst->num_buckets == data_count); + dst->sum += sum; + dst->sum_of_squares += sum_of_squares; + dst->count += count; + if (min_seen < dst->min_seen) { + dst->min_seen = min_seen; + } + if (max_seen > dst->max_seen) { + dst->max_seen = max_seen; + } + for (i = 0; i < dst->num_buckets; i++) { + dst->buckets[i] += data[i]; + } +} + +static double threshold_for_count_below(gpr_histogram *h, double count_below) { + double count_so_far; + double lower_bound; + double upper_bound; + size_t lower_idx; + size_t upper_idx; + + if (h->count == 0) { + return 0.0; + } + + if (count_below <= 0) { + return h->min_seen; + } + if (count_below >= h->count) { + return h->max_seen; + } + + /* find the lowest bucket that gets us above count_below */ + count_so_far = 0.0; + for (lower_idx = 0; lower_idx < h->num_buckets; lower_idx++) { + count_so_far += h->buckets[lower_idx]; + if (count_so_far >= count_below) { + break; + } + } + if (count_so_far == count_below) { + /* this bucket hits the threshold exactly... we should be midway through + any run of zero values following the bucket */ + for (upper_idx = lower_idx + 1; upper_idx < h->num_buckets; upper_idx++) { + if (h->buckets[upper_idx]) { + break; + } + } + return (bucket_start(h, (double)lower_idx) + + bucket_start(h, (double)upper_idx)) / + 2.0; + } else { + /* treat values as uniform throughout the bucket, and find where this value + should lie */ + lower_bound = bucket_start(h, (double)lower_idx); + upper_bound = bucket_start(h, (double)(lower_idx + 1)); + return GPR_CLAMP(upper_bound - + (upper_bound - lower_bound) * + (count_so_far - count_below) / + h->buckets[lower_idx], + h->min_seen, h->max_seen); + } +} + +double gpr_histogram_percentile(gpr_histogram *h, double percentile) { + return threshold_for_count_below(h, h->count * percentile / 100.0); +} + +double gpr_histogram_mean(gpr_histogram *h) { + GPR_ASSERT(h->count != 0); + return h->sum / h->count; +} + +double gpr_histogram_stddev(gpr_histogram *h) { + return sqrt(gpr_histogram_variance(h)); +} + +double gpr_histogram_variance(gpr_histogram *h) { + if (h->count == 0) return 0.0; + return (h->sum_of_squares * h->count - h->sum * h->sum) / + (h->count * h->count); +} + +double gpr_histogram_maximum(gpr_histogram *h) { return h->max_seen; } + +double gpr_histogram_minimum(gpr_histogram *h) { return h->min_seen; } + +double gpr_histogram_count(gpr_histogram *h) { return h->count; } + +double gpr_histogram_sum(gpr_histogram *h) { return h->sum; } + +double gpr_histogram_sum_of_squares(gpr_histogram *h) { + return h->sum_of_squares; +} + +const uint32_t *gpr_histogram_get_contents(gpr_histogram *h, size_t *size) { + *size = h->num_buckets; + return h->buckets; +} diff --git a/src/core/lib/support/host_port.c b/src/core/lib/support/host_port.c new file mode 100644 index 0000000000..31243a7221 --- /dev/null +++ b/src/core/lib/support/host_port.c @@ -0,0 +1,110 @@ +/* + * + * Copyright 2015-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 + +#include + +#include +#include +#include +#include "src/core/support/string.h" + +int gpr_join_host_port(char **out, const char *host, int port) { + if (host[0] != '[' && strchr(host, ':') != NULL) { + /* IPv6 literals must be enclosed in brackets. */ + return gpr_asprintf(out, "[%s]:%d", host, port); + } else { + /* Ordinary non-bracketed host:port. */ + return gpr_asprintf(out, "%s:%d", host, port); + } +} + +int gpr_split_host_port(const char *name, char **host, char **port) { + const char *host_start; + size_t host_len; + const char *port_start; + + *host = NULL; + *port = NULL; + + if (name[0] == '[') { + /* Parse a bracketed host, typically an IPv6 literal. */ + const char *rbracket = strchr(name, ']'); + if (rbracket == NULL) { + /* Unmatched [ */ + return 0; + } + if (rbracket[1] == '\0') { + /* ] */ + port_start = NULL; + } else if (rbracket[1] == ':') { + /* ]: */ + port_start = rbracket + 2; + } else { + /* ] */ + return 0; + } + host_start = name + 1; + host_len = (size_t)(rbracket - host_start); + if (memchr(host_start, ':', host_len) == NULL) { + /* Require all bracketed hosts to contain a colon, because a hostname or + IPv4 address should never use brackets. */ + return 0; + } + } else { + const char *colon = strchr(name, ':'); + if (colon != NULL && strchr(colon + 1, ':') == NULL) { + /* Exactly 1 colon. Split into host:port. */ + host_start = name; + host_len = (size_t)(colon - name); + port_start = colon + 1; + } else { + /* 0 or 2+ colons. Bare hostname or IPv6 litearal. */ + host_start = name; + host_len = strlen(name); + port_start = NULL; + } + } + + /* Allocate return values. */ + *host = gpr_malloc(host_len + 1); + memcpy(*host, host_start, host_len); + (*host)[host_len] = '\0'; + + if (port_start != NULL) { + *port = gpr_strdup(port_start); + } + + return 1; +} diff --git a/src/core/lib/support/load_file.c b/src/core/lib/support/load_file.c new file mode 100644 index 0000000000..650bd62ccb --- /dev/null +++ b/src/core/lib/support/load_file.c @@ -0,0 +1,91 @@ +/* + * + * Copyright 2015-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/support/load_file.h" + +#include +#include + +#include +#include +#include + +#include "src/core/support/block_annotate.h" +#include "src/core/support/string.h" + +gpr_slice gpr_load_file(const char *filename, int add_null_terminator, + int *success) { + unsigned char *contents = NULL; + size_t contents_size = 0; + char *error_msg = NULL; + gpr_slice result = gpr_empty_slice(); + FILE *file; + size_t bytes_read = 0; + + GRPC_SCHEDULING_START_BLOCKING_REGION; + file = fopen(filename, "rb"); + if (file == NULL) { + gpr_asprintf(&error_msg, "Could not open file %s (error = %s).", filename, + strerror(errno)); + GPR_ASSERT(error_msg != NULL); + goto end; + } + fseek(file, 0, SEEK_END); + /* Converting to size_t on the assumption that it will not fail */ + contents_size = (size_t)ftell(file); + fseek(file, 0, SEEK_SET); + contents = gpr_malloc(contents_size + (add_null_terminator ? 1 : 0)); + bytes_read = fread(contents, 1, contents_size, file); + if (bytes_read < contents_size) { + GPR_ASSERT(ferror(file)); + gpr_asprintf(&error_msg, "Error %s occured while reading file %s.", + strerror(errno), filename); + GPR_ASSERT(error_msg != NULL); + goto end; + } + if (success != NULL) *success = 1; + if (add_null_terminator) { + contents[contents_size++] = 0; + } + result = gpr_slice_new(contents, contents_size, gpr_free); + +end: + if (error_msg != NULL) { + gpr_log(GPR_ERROR, "%s", error_msg); + gpr_free(error_msg); + if (success != NULL) *success = 0; + } + if (file != NULL) fclose(file); + GRPC_SCHEDULING_END_BLOCKING_REGION; + return result; +} diff --git a/src/core/lib/support/load_file.h b/src/core/lib/support/load_file.h new file mode 100644 index 0000000000..5896654e9a --- /dev/null +++ b/src/core/lib/support/load_file.h @@ -0,0 +1,55 @@ +/* + * + * Copyright 2015-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_SUPPORT_LOAD_FILE_H +#define GRPC_CORE_SUPPORT_LOAD_FILE_H + +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Loads the content of a file into a slice. add_null_terminator will add + a NULL terminator if non-zero. The success parameter, if not NULL, + will be set to 1 in case of success and 0 in case of failure. */ +gpr_slice gpr_load_file(const char *filename, int add_null_terminator, + int *success); + +#ifdef __cplusplus +} +#endif + +#endif /* GRPC_CORE_SUPPORT_LOAD_FILE_H */ diff --git a/src/core/lib/support/log.c b/src/core/lib/support/log.c new file mode 100644 index 0000000000..04156a5b1f --- /dev/null +++ b/src/core/lib/support/log.c @@ -0,0 +1,66 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include + +#include +#include + +extern void gpr_default_log(gpr_log_func_args *args); +static gpr_log_func g_log_func = gpr_default_log; + +const char *gpr_log_severity_string(gpr_log_severity severity) { + switch (severity) { + case GPR_LOG_SEVERITY_DEBUG: + return "D"; + case GPR_LOG_SEVERITY_INFO: + return "I"; + case GPR_LOG_SEVERITY_ERROR: + return "E"; + } + GPR_UNREACHABLE_CODE(return "UNKNOWN"); +} + +void gpr_log_message(const char *file, int line, gpr_log_severity severity, + const char *message) { + gpr_log_func_args lfargs; + memset(&lfargs, 0, sizeof(lfargs)); + lfargs.file = file; + lfargs.line = line; + lfargs.severity = severity; + lfargs.message = message; + g_log_func(&lfargs); +} + +void gpr_set_log_function(gpr_log_func f) { g_log_func = f; } diff --git a/src/core/lib/support/log_android.c b/src/core/lib/support/log_android.c new file mode 100644 index 0000000000..640c9d7099 --- /dev/null +++ b/src/core/lib/support/log_android.c @@ -0,0 +1,87 @@ +/* + * + * Copyright 2015-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 + +#ifdef GPR_ANDROID + +#include +#include +#include +#include +#include +#include + +static android_LogPriority severity_to_log_priority(gpr_log_severity severity) { + switch (severity) { + case GPR_LOG_SEVERITY_DEBUG: + return ANDROID_LOG_DEBUG; + case GPR_LOG_SEVERITY_INFO: + return ANDROID_LOG_INFO; + case GPR_LOG_SEVERITY_ERROR: + return ANDROID_LOG_ERROR; + } + return ANDROID_LOG_DEFAULT; +} + +void gpr_log(const char *file, int line, gpr_log_severity severity, + const char *format, ...) { + char *message = NULL; + va_list args; + va_start(args, format); + vasprintf(&message, format, args); + va_end(args); + gpr_log_message(file, line, severity, message); + free(message); +} + +void gpr_default_log(gpr_log_func_args *args) { + char *final_slash; + const char *display_file; + char *output = NULL; + + final_slash = strrchr(args->file, '/'); + if (final_slash == NULL) + display_file = args->file; + else + display_file = final_slash + 1; + + asprintf(&output, "%s:%d] %s", display_file, args->line, args->message); + + __android_log_write(severity_to_log_priority(args->severity), "GRPC", output); + + /* allocated by asprintf => use free, not gpr_free */ + free(output); +} + +#endif /* GPR_ANDROID */ diff --git a/src/core/lib/support/log_linux.c b/src/core/lib/support/log_linux.c new file mode 100644 index 0000000000..e60512c526 --- /dev/null +++ b/src/core/lib/support/log_linux.c @@ -0,0 +1,105 @@ +/* + * + * Copyright 2015-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 _POSIX_SOURCE +#define _POSIX_SOURCE +#endif + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include + +#ifdef GPR_LINUX + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static long gettid(void) { return syscall(__NR_gettid); } + +void gpr_log(const char *file, int line, gpr_log_severity severity, + const char *format, ...) { + char *message = NULL; + va_list args; + va_start(args, format); + if (vasprintf(&message, format, args) == -1) { + va_end(args); + return; + } + va_end(args); + gpr_log_message(file, line, severity, message); + free(message); +} + +void gpr_default_log(gpr_log_func_args *args) { + char *final_slash; + char *prefix; + const char *display_file; + char time_buffer[64]; + time_t timer; + gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME); + struct tm tm; + + timer = (time_t)now.tv_sec; + final_slash = strrchr(args->file, '/'); + if (final_slash == NULL) + display_file = args->file; + else + display_file = final_slash + 1; + + if (!localtime_r(&timer, &tm)) { + strcpy(time_buffer, "error:localtime"); + } else if (0 == + strftime(time_buffer, sizeof(time_buffer), "%m%d %H:%M:%S", &tm)) { + strcpy(time_buffer, "error:strftime"); + } + + gpr_asprintf(&prefix, "%s%s.%09d %7tu %s:%d]", + gpr_log_severity_string(args->severity), time_buffer, + (int)(now.tv_nsec), gettid(), display_file, args->line); + + fprintf(stderr, "%-60s %s\n", prefix, args->message); + gpr_free(prefix); +} + +#endif diff --git a/src/core/lib/support/log_posix.c b/src/core/lib/support/log_posix.c new file mode 100644 index 0000000000..7429dd0a2c --- /dev/null +++ b/src/core/lib/support/log_posix.c @@ -0,0 +1,102 @@ +/* + * + * Copyright 2015-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 + +#if defined(GPR_POSIX_LOG) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static intptr_t gettid(void) { return (intptr_t)pthread_self(); } + +void gpr_log(const char *file, int line, gpr_log_severity severity, + const char *format, ...) { + char buf[64]; + char *allocated = NULL; + char *message = NULL; + int ret; + va_list args; + va_start(args, format); + ret = vsnprintf(buf, sizeof(buf), format, args); + va_end(args); + if (ret < 0) { + message = NULL; + } else if ((size_t)ret <= sizeof(buf) - 1) { + message = buf; + } else { + message = allocated = gpr_malloc((size_t)ret + 1); + va_start(args, format); + vsnprintf(message, (size_t)(ret + 1), format, args); + va_end(args); + } + gpr_log_message(file, line, severity, message); + gpr_free(allocated); +} + +void gpr_default_log(gpr_log_func_args *args) { + char *final_slash; + const char *display_file; + char time_buffer[64]; + time_t timer; + gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME); + struct tm tm; + + timer = (time_t)now.tv_sec; + final_slash = strrchr(args->file, '/'); + if (final_slash == NULL) + display_file = args->file; + else + display_file = final_slash + 1; + + if (!localtime_r(&timer, &tm)) { + strcpy(time_buffer, "error:localtime"); + } else if (0 == + strftime(time_buffer, sizeof(time_buffer), "%m%d %H:%M:%S", &tm)) { + strcpy(time_buffer, "error:strftime"); + } + + fprintf(stderr, "%s%s.%09d %7tu %s:%d] %s\n", + gpr_log_severity_string(args->severity), time_buffer, + (int)(now.tv_nsec), gettid(), display_file, args->line, + args->message); +} + +#endif /* defined(GPR_POSIX_LOG) */ diff --git a/src/core/lib/support/log_win32.c b/src/core/lib/support/log_win32.c new file mode 100644 index 0000000000..89ec0917d5 --- /dev/null +++ b/src/core/lib/support/log_win32.c @@ -0,0 +1,126 @@ +/* + * + * Copyright 2015-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 + +#ifdef GPR_WIN32 + +#include +#include + +#include +#include +#include +#include +#include + +#include "src/core/support/string.h" +#include "src/core/support/string_win32.h" + +void gpr_log(const char *file, int line, gpr_log_severity severity, + const char *format, ...) { + char *message = NULL; + va_list args; + int ret; + + /* Determine the length. */ + va_start(args, format); + ret = _vscprintf(format, args); + va_end(args); + if (ret < 0) { + message = NULL; + } else { + /* Allocate a new buffer, with space for the NUL terminator. */ + size_t strp_buflen = (size_t)ret + 1; + message = gpr_malloc(strp_buflen); + + /* Print to the buffer. */ + va_start(args, format); + ret = vsnprintf_s(message, strp_buflen, _TRUNCATE, format, args); + va_end(args); + if ((size_t)ret != strp_buflen - 1) { + /* This should never happen. */ + gpr_free(message); + message = NULL; + } + } + + gpr_log_message(file, line, severity, message); + gpr_free(message); +} + +/* Simple starter implementation */ +void gpr_default_log(gpr_log_func_args *args) { + char *final_slash; + const char *display_file; + char time_buffer[64]; + time_t timer; + gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME); + struct tm tm; + + timer = (time_t)now.tv_sec; + final_slash = strrchr(args->file, '\\'); + if (final_slash == NULL) + display_file = args->file; + else + display_file = final_slash + 1; + + if (localtime_s(&tm, &timer)) { + strcpy(time_buffer, "error:localtime"); + } else if (0 == + strftime(time_buffer, sizeof(time_buffer), "%m%d %H:%M:%S", &tm)) { + strcpy(time_buffer, "error:strftime"); + } + + fprintf(stderr, "%s%s.%09u %5lu %s:%d] %s\n", + gpr_log_severity_string(args->severity), time_buffer, + (int)(now.tv_nsec), GetCurrentThreadId(), display_file, args->line, + args->message); + fflush(stderr); +} + +char *gpr_format_message(int messageid) { + LPTSTR tmessage; + char *message; + DWORD status = FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, (DWORD)messageid, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)(&tmessage), 0, NULL); + if (status == 0) return gpr_strdup("Unable to retrieve error string"); + message = gpr_tchar_to_char(tmessage); + LocalFree(tmessage); + return message; +} + +#endif /* GPR_WIN32 */ diff --git a/src/core/lib/support/murmur_hash.c b/src/core/lib/support/murmur_hash.c new file mode 100644 index 0000000000..a5261c0cc0 --- /dev/null +++ b/src/core/lib/support/murmur_hash.c @@ -0,0 +1,96 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/support/murmur_hash.h" + +#define ROTL32(x, r) ((x) << (r)) | ((x) >> (32 - (r))) + +#define FMIX32(h) \ + (h) ^= (h) >> 16; \ + (h) *= 0x85ebca6b; \ + (h) ^= (h) >> 13; \ + (h) *= 0xc2b2ae35; \ + (h) ^= (h) >> 16; + +/* Block read - if your platform needs to do endian-swapping or can only + handle aligned reads, do the conversion here */ +#define GETBLOCK32(p, i) (p)[(i)] + +uint32_t gpr_murmur_hash3(const void *key, size_t len, uint32_t seed) { + const uint8_t *data = (const uint8_t *)key; + const size_t nblocks = len / 4; + int i; + + uint32_t h1 = seed; + uint32_t k1; + + const uint32_t c1 = 0xcc9e2d51; + const uint32_t c2 = 0x1b873593; + + const uint32_t *blocks = ((const uint32_t *)key) + nblocks; + const uint8_t *tail = (const uint8_t *)(data + nblocks * 4); + + /* body */ + for (i = -(int)nblocks; i; i++) { + k1 = GETBLOCK32(blocks, i); + + k1 *= c1; + k1 = ROTL32(k1, 15); + k1 *= c2; + + h1 ^= k1; + h1 = ROTL32(h1, 13); + h1 = h1 * 5 + 0xe6546b64; + } + + k1 = 0; + + /* tail */ + switch (len & 3) { + case 3: + k1 ^= ((uint32_t)tail[2]) << 16; + case 2: + k1 ^= ((uint32_t)tail[1]) << 8; + case 1: + k1 ^= tail[0]; + k1 *= c1; + k1 = ROTL32(k1, 15); + k1 *= c2; + h1 ^= k1; + }; + + /* finalization */ + h1 ^= (uint32_t)len; + FMIX32(h1); + return h1; +} diff --git a/src/core/lib/support/murmur_hash.h b/src/core/lib/support/murmur_hash.h new file mode 100644 index 0000000000..0f0b399e5d --- /dev/null +++ b/src/core/lib/support/murmur_hash.h @@ -0,0 +1,44 @@ +/* + * + * Copyright 2015-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_SUPPORT_MURMUR_HASH_H +#define GRPC_CORE_SUPPORT_MURMUR_HASH_H + +#include + +#include + +/* compute the hash of key (length len) */ +uint32_t gpr_murmur_hash3(const void *key, size_t len, uint32_t seed); + +#endif /* GRPC_CORE_SUPPORT_MURMUR_HASH_H */ diff --git a/src/core/lib/support/slice.c b/src/core/lib/support/slice.c new file mode 100644 index 0000000000..b9a7c77bda --- /dev/null +++ b/src/core/lib/support/slice.c @@ -0,0 +1,343 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include + +#include + +gpr_slice gpr_empty_slice(void) { + gpr_slice out; + out.refcount = 0; + out.data.inlined.length = 0; + return out; +} + +gpr_slice gpr_slice_ref(gpr_slice slice) { + if (slice.refcount) { + slice.refcount->ref(slice.refcount); + } + return slice; +} + +void gpr_slice_unref(gpr_slice slice) { + if (slice.refcount) { + slice.refcount->unref(slice.refcount); + } +} + +/* gpr_slice_from_static_string support structure - a refcount that does + nothing */ +static void noop_ref_or_unref(void *unused) {} + +static gpr_slice_refcount noop_refcount = {noop_ref_or_unref, + noop_ref_or_unref}; + +gpr_slice gpr_slice_from_static_string(const char *s) { + gpr_slice slice; + slice.refcount = &noop_refcount; + slice.data.refcounted.bytes = (uint8_t *)s; + slice.data.refcounted.length = strlen(s); + return slice; +} + +/* gpr_slice_new support structures - we create a refcount object extended + with the user provided data pointer & destroy function */ +typedef struct new_slice_refcount { + gpr_slice_refcount rc; + gpr_refcount refs; + void (*user_destroy)(void *); + void *user_data; +} new_slice_refcount; + +static void new_slice_ref(void *p) { + new_slice_refcount *r = p; + gpr_ref(&r->refs); +} + +static void new_slice_unref(void *p) { + new_slice_refcount *r = p; + if (gpr_unref(&r->refs)) { + r->user_destroy(r->user_data); + gpr_free(r); + } +} + +gpr_slice gpr_slice_new(void *p, size_t len, void (*destroy)(void *)) { + gpr_slice slice; + new_slice_refcount *rc = gpr_malloc(sizeof(new_slice_refcount)); + gpr_ref_init(&rc->refs, 1); + rc->rc.ref = new_slice_ref; + rc->rc.unref = new_slice_unref; + rc->user_destroy = destroy; + rc->user_data = p; + + slice.refcount = &rc->rc; + slice.data.refcounted.bytes = p; + slice.data.refcounted.length = len; + return slice; +} + +/* gpr_slice_new_with_len support structures - we create a refcount object + extended with the user provided data pointer & destroy function */ +typedef struct new_with_len_slice_refcount { + gpr_slice_refcount rc; + gpr_refcount refs; + void *user_data; + size_t user_length; + void (*user_destroy)(void *, size_t); +} new_with_len_slice_refcount; + +static void new_with_len_ref(void *p) { + new_with_len_slice_refcount *r = p; + gpr_ref(&r->refs); +} + +static void new_with_len_unref(void *p) { + new_with_len_slice_refcount *r = p; + if (gpr_unref(&r->refs)) { + r->user_destroy(r->user_data, r->user_length); + gpr_free(r); + } +} + +gpr_slice gpr_slice_new_with_len(void *p, size_t len, + void (*destroy)(void *, size_t)) { + gpr_slice slice; + new_with_len_slice_refcount *rc = + gpr_malloc(sizeof(new_with_len_slice_refcount)); + gpr_ref_init(&rc->refs, 1); + rc->rc.ref = new_with_len_ref; + rc->rc.unref = new_with_len_unref; + rc->user_destroy = destroy; + rc->user_data = p; + rc->user_length = len; + + slice.refcount = &rc->rc; + slice.data.refcounted.bytes = p; + slice.data.refcounted.length = len; + return slice; +} + +gpr_slice gpr_slice_from_copied_buffer(const char *source, size_t length) { + gpr_slice slice = gpr_slice_malloc(length); + memcpy(GPR_SLICE_START_PTR(slice), source, length); + return slice; +} + +gpr_slice gpr_slice_from_copied_string(const char *source) { + return gpr_slice_from_copied_buffer(source, strlen(source)); +} + +typedef struct { + gpr_slice_refcount base; + gpr_refcount refs; +} malloc_refcount; + +static void malloc_ref(void *p) { + malloc_refcount *r = p; + gpr_ref(&r->refs); +} + +static void malloc_unref(void *p) { + malloc_refcount *r = p; + if (gpr_unref(&r->refs)) { + gpr_free(r); + } +} + +gpr_slice gpr_slice_malloc(size_t length) { + gpr_slice slice; + + if (length > sizeof(slice.data.inlined.bytes)) { + /* Memory layout used by the slice created here: + + +-----------+----------------------------------------------------------+ + | refcount | bytes | + +-----------+----------------------------------------------------------+ + + refcount is a malloc_refcount + bytes is an array of bytes of the requested length + Both parts are placed in the same allocation returned from gpr_malloc */ + malloc_refcount *rc = gpr_malloc(sizeof(malloc_refcount) + length); + + /* Initial refcount on rc is 1 - and it's up to the caller to release + this reference. */ + gpr_ref_init(&rc->refs, 1); + + rc->base.ref = malloc_ref; + rc->base.unref = malloc_unref; + + /* Build up the slice to be returned. */ + /* The slices refcount points back to the allocated block. */ + slice.refcount = &rc->base; + /* The data bytes are placed immediately after the refcount struct */ + slice.data.refcounted.bytes = (uint8_t *)(rc + 1); + /* And the length of the block is set to the requested length */ + slice.data.refcounted.length = length; + } else { + /* small slice: just inline the data */ + slice.refcount = NULL; + slice.data.inlined.length = (uint8_t)length; + } + return slice; +} + +gpr_slice gpr_slice_sub_no_ref(gpr_slice source, size_t begin, size_t end) { + gpr_slice subset; + + GPR_ASSERT(end >= begin); + + if (source.refcount) { + /* Enforce preconditions */ + GPR_ASSERT(source.data.refcounted.length >= end); + + /* Build the result */ + subset.refcount = source.refcount; + /* Point into the source array */ + subset.data.refcounted.bytes = source.data.refcounted.bytes + begin; + subset.data.refcounted.length = end - begin; + } else { + /* Enforce preconditions */ + GPR_ASSERT(source.data.inlined.length >= end); + subset.refcount = NULL; + subset.data.inlined.length = (uint8_t)(end - begin); + memcpy(subset.data.inlined.bytes, source.data.inlined.bytes + begin, + end - begin); + } + return subset; +} + +gpr_slice gpr_slice_sub(gpr_slice source, size_t begin, size_t end) { + gpr_slice subset; + + if (end - begin <= sizeof(subset.data.inlined.bytes)) { + subset.refcount = NULL; + subset.data.inlined.length = (uint8_t)(end - begin); + memcpy(subset.data.inlined.bytes, GPR_SLICE_START_PTR(source) + begin, + end - begin); + } else { + subset = gpr_slice_sub_no_ref(source, begin, end); + /* Bump the refcount */ + subset.refcount->ref(subset.refcount); + } + return subset; +} + +gpr_slice gpr_slice_split_tail(gpr_slice *source, size_t split) { + gpr_slice tail; + + if (source->refcount == NULL) { + /* inlined data, copy it out */ + GPR_ASSERT(source->data.inlined.length >= split); + tail.refcount = NULL; + tail.data.inlined.length = (uint8_t)(source->data.inlined.length - split); + memcpy(tail.data.inlined.bytes, source->data.inlined.bytes + split, + tail.data.inlined.length); + source->data.inlined.length = (uint8_t)split; + } else { + size_t tail_length = source->data.refcounted.length - split; + GPR_ASSERT(source->data.refcounted.length >= split); + if (tail_length < sizeof(tail.data.inlined.bytes)) { + /* Copy out the bytes - it'll be cheaper than refcounting */ + tail.refcount = NULL; + tail.data.inlined.length = (uint8_t)tail_length; + memcpy(tail.data.inlined.bytes, source->data.refcounted.bytes + split, + tail_length); + } else { + /* Build the result */ + tail.refcount = source->refcount; + /* Bump the refcount */ + tail.refcount->ref(tail.refcount); + /* Point into the source array */ + tail.data.refcounted.bytes = source->data.refcounted.bytes + split; + tail.data.refcounted.length = tail_length; + } + source->data.refcounted.length = split; + } + + return tail; +} + +gpr_slice gpr_slice_split_head(gpr_slice *source, size_t split) { + gpr_slice head; + + if (source->refcount == NULL) { + GPR_ASSERT(source->data.inlined.length >= split); + + head.refcount = NULL; + head.data.inlined.length = (uint8_t)split; + memcpy(head.data.inlined.bytes, source->data.inlined.bytes, split); + source->data.inlined.length = + (uint8_t)(source->data.inlined.length - split); + memmove(source->data.inlined.bytes, source->data.inlined.bytes + split, + source->data.inlined.length); + } else if (split < sizeof(head.data.inlined.bytes)) { + GPR_ASSERT(source->data.refcounted.length >= split); + + head.refcount = NULL; + head.data.inlined.length = (uint8_t)split; + memcpy(head.data.inlined.bytes, source->data.refcounted.bytes, split); + source->data.refcounted.bytes += split; + source->data.refcounted.length -= split; + } else { + GPR_ASSERT(source->data.refcounted.length >= split); + + /* Build the result */ + head.refcount = source->refcount; + /* Bump the refcount */ + head.refcount->ref(head.refcount); + /* Point into the source array */ + head.data.refcounted.bytes = source->data.refcounted.bytes; + head.data.refcounted.length = split; + source->data.refcounted.bytes += split; + source->data.refcounted.length -= split; + } + + return head; +} + +int gpr_slice_cmp(gpr_slice a, gpr_slice b) { + int d = (int)(GPR_SLICE_LENGTH(a) - GPR_SLICE_LENGTH(b)); + if (d != 0) return d; + return memcmp(GPR_SLICE_START_PTR(a), GPR_SLICE_START_PTR(b), + GPR_SLICE_LENGTH(a)); +} + +int gpr_slice_str_cmp(gpr_slice a, const char *b) { + size_t b_length = strlen(b); + int d = (int)(GPR_SLICE_LENGTH(a) - b_length); + if (d != 0) return d; + return memcmp(GPR_SLICE_START_PTR(a), b, b_length); +} diff --git a/src/core/lib/support/slice_buffer.c b/src/core/lib/support/slice_buffer.c new file mode 100644 index 0000000000..66f111d767 --- /dev/null +++ b/src/core/lib/support/slice_buffer.c @@ -0,0 +1,282 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include + +#include + +#include +#include +#include + +/* grow a buffer; requires GRPC_SLICE_BUFFER_INLINE_ELEMENTS > 1 */ +#define GROW(x) (3 * (x) / 2) + +static void maybe_embiggen(gpr_slice_buffer *sb) { + if (sb->count == sb->capacity) { + sb->capacity = GROW(sb->capacity); + GPR_ASSERT(sb->capacity > sb->count); + if (sb->slices == sb->inlined) { + sb->slices = gpr_malloc(sb->capacity * sizeof(gpr_slice)); + memcpy(sb->slices, sb->inlined, sb->count * sizeof(gpr_slice)); + } else { + sb->slices = gpr_realloc(sb->slices, sb->capacity * sizeof(gpr_slice)); + } + } +} + +void gpr_slice_buffer_init(gpr_slice_buffer *sb) { + sb->count = 0; + sb->length = 0; + sb->capacity = GRPC_SLICE_BUFFER_INLINE_ELEMENTS; + sb->slices = sb->inlined; +} + +void gpr_slice_buffer_destroy(gpr_slice_buffer *sb) { + gpr_slice_buffer_reset_and_unref(sb); + if (sb->slices != sb->inlined) { + gpr_free(sb->slices); + } +} + +uint8_t *gpr_slice_buffer_tiny_add(gpr_slice_buffer *sb, size_t n) { + gpr_slice *back; + uint8_t *out; + + sb->length += n; + + if (sb->count == 0) goto add_new; + back = &sb->slices[sb->count - 1]; + if (back->refcount) goto add_new; + if ((back->data.inlined.length + n) > sizeof(back->data.inlined.bytes)) + goto add_new; + out = back->data.inlined.bytes + back->data.inlined.length; + back->data.inlined.length = (uint8_t)(back->data.inlined.length + n); + return out; + +add_new: + maybe_embiggen(sb); + back = &sb->slices[sb->count]; + sb->count++; + back->refcount = NULL; + back->data.inlined.length = (uint8_t)n; + return back->data.inlined.bytes; +} + +size_t gpr_slice_buffer_add_indexed(gpr_slice_buffer *sb, gpr_slice s) { + size_t out = sb->count; + maybe_embiggen(sb); + sb->slices[out] = s; + sb->length += GPR_SLICE_LENGTH(s); + sb->count = out + 1; + return out; +} + +void gpr_slice_buffer_add(gpr_slice_buffer *sb, gpr_slice s) { + size_t n = sb->count; + /* if both the last slice in the slice buffer and the slice being added + are inlined (that is, that they carry their data inside the slice data + structure), and the back slice is not full, then concatenate directly + into the back slice, preventing many small slices being passed into + writes */ + if (!s.refcount && n) { + gpr_slice *back = &sb->slices[n - 1]; + if (!back->refcount && back->data.inlined.length < GPR_SLICE_INLINED_SIZE) { + if (s.data.inlined.length + back->data.inlined.length <= + GPR_SLICE_INLINED_SIZE) { + memcpy(back->data.inlined.bytes + back->data.inlined.length, + s.data.inlined.bytes, s.data.inlined.length); + back->data.inlined.length = + (uint8_t)(back->data.inlined.length + s.data.inlined.length); + } else { + size_t cp1 = GPR_SLICE_INLINED_SIZE - back->data.inlined.length; + memcpy(back->data.inlined.bytes + back->data.inlined.length, + s.data.inlined.bytes, cp1); + back->data.inlined.length = GPR_SLICE_INLINED_SIZE; + maybe_embiggen(sb); + back = &sb->slices[n]; + sb->count = n + 1; + back->refcount = NULL; + back->data.inlined.length = (uint8_t)(s.data.inlined.length - cp1); + memcpy(back->data.inlined.bytes, s.data.inlined.bytes + cp1, + s.data.inlined.length - cp1); + } + sb->length += s.data.inlined.length; + return; /* early out */ + } + } + gpr_slice_buffer_add_indexed(sb, s); +} + +void gpr_slice_buffer_addn(gpr_slice_buffer *sb, gpr_slice *s, size_t n) { + size_t i; + for (i = 0; i < n; i++) { + gpr_slice_buffer_add(sb, s[i]); + } +} + +void gpr_slice_buffer_pop(gpr_slice_buffer *sb) { + if (sb->count != 0) { + size_t count = --sb->count; + sb->length -= GPR_SLICE_LENGTH(sb->slices[count]); + } +} + +void gpr_slice_buffer_reset_and_unref(gpr_slice_buffer *sb) { + size_t i; + + for (i = 0; i < sb->count; i++) { + gpr_slice_unref(sb->slices[i]); + } + + sb->count = 0; + sb->length = 0; +} + +void gpr_slice_buffer_swap(gpr_slice_buffer *a, gpr_slice_buffer *b) { + GPR_SWAP(size_t, a->count, b->count); + GPR_SWAP(size_t, a->capacity, b->capacity); + GPR_SWAP(size_t, a->length, b->length); + + if (a->slices == a->inlined) { + if (b->slices == b->inlined) { + /* swap contents of inlined buffer */ + gpr_slice temp[GRPC_SLICE_BUFFER_INLINE_ELEMENTS]; + memcpy(temp, a->slices, b->count * sizeof(gpr_slice)); + memcpy(a->slices, b->slices, a->count * sizeof(gpr_slice)); + memcpy(b->slices, temp, b->count * sizeof(gpr_slice)); + } else { + /* a is inlined, b is not - copy a inlined into b, fix pointers */ + a->slices = b->slices; + b->slices = b->inlined; + memcpy(b->slices, a->inlined, b->count * sizeof(gpr_slice)); + } + } else if (b->slices == b->inlined) { + /* b is inlined, a is not - copy b inlined int a, fix pointers */ + b->slices = a->slices; + a->slices = a->inlined; + memcpy(a->slices, b->inlined, a->count * sizeof(gpr_slice)); + } else { + /* no inlining: easy swap */ + GPR_SWAP(gpr_slice *, a->slices, b->slices); + } +} + +void gpr_slice_buffer_move_into(gpr_slice_buffer *src, gpr_slice_buffer *dst) { + /* anything to move? */ + if (src->count == 0) { + return; + } + /* anything in dst? */ + if (dst->count == 0) { + gpr_slice_buffer_swap(src, dst); + return; + } + /* both buffers have data - copy, and reset src */ + gpr_slice_buffer_addn(dst, src->slices, src->count); + src->count = 0; + src->length = 0; +} + +void gpr_slice_buffer_move_first(gpr_slice_buffer *src, size_t n, + gpr_slice_buffer *dst) { + size_t src_idx; + size_t output_len = dst->length + n; + size_t new_input_len = src->length - n; + GPR_ASSERT(src->length >= n); + if (src->length == n) { + gpr_slice_buffer_move_into(src, dst); + return; + } + src_idx = 0; + while (src_idx < src->capacity) { + gpr_slice slice = src->slices[src_idx]; + size_t slice_len = GPR_SLICE_LENGTH(slice); + if (n > slice_len) { + gpr_slice_buffer_add(dst, slice); + n -= slice_len; + src_idx++; + } else if (n == slice_len) { + gpr_slice_buffer_add(dst, slice); + src_idx++; + break; + } else { /* n < slice_len */ + src->slices[src_idx] = gpr_slice_split_tail(&slice, n); + GPR_ASSERT(GPR_SLICE_LENGTH(slice) == n); + GPR_ASSERT(GPR_SLICE_LENGTH(src->slices[src_idx]) == slice_len - n); + gpr_slice_buffer_add(dst, slice); + break; + } + } + GPR_ASSERT(dst->length == output_len); + memmove(src->slices, src->slices + src_idx, + sizeof(gpr_slice) * (src->count - src_idx)); + src->count -= src_idx; + src->length = new_input_len; + GPR_ASSERT(src->count > 0); +} + +void gpr_slice_buffer_trim_end(gpr_slice_buffer *sb, size_t n, + gpr_slice_buffer *garbage) { + GPR_ASSERT(n <= sb->length); + sb->length -= n; + for (;;) { + size_t idx = sb->count - 1; + gpr_slice slice = sb->slices[idx]; + size_t slice_len = GPR_SLICE_LENGTH(slice); + if (slice_len > n) { + sb->slices[idx] = gpr_slice_split_head(&slice, slice_len - n); + gpr_slice_buffer_add_indexed(garbage, slice); + return; + } else if (slice_len == n) { + gpr_slice_buffer_add_indexed(garbage, slice); + sb->count = idx; + return; + } else { + gpr_slice_buffer_add_indexed(garbage, slice); + n -= slice_len; + sb->count = idx; + } + } +} + +gpr_slice gpr_slice_buffer_take_first(gpr_slice_buffer *sb) { + gpr_slice slice; + GPR_ASSERT(sb->count > 0); + slice = sb->slices[0]; + memmove(&sb->slices[0], &sb->slices[1], (sb->count - 1) * sizeof(gpr_slice)); + sb->count--; + sb->length -= GPR_SLICE_LENGTH(slice); + return slice; +} diff --git a/src/core/lib/support/stack_lockfree.c b/src/core/lib/support/stack_lockfree.c new file mode 100644 index 0000000000..8e0bbfaee8 --- /dev/null +++ b/src/core/lib/support/stack_lockfree.c @@ -0,0 +1,185 @@ +/* + * + * Copyright 2015-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/support/stack_lockfree.h" + +#include +#include + +#include +#include +#include +#include + +/* The lockfree node structure is a single architecture-level + word that allows for an atomic CAS to set it up. */ +struct lockfree_node_contents { + /* next thing to look at. Actual index for head, next index otherwise */ + uint16_t index; +#ifdef GPR_ARCH_64 + uint16_t pad; + uint32_t aba_ctr; +#else +#ifdef GPR_ARCH_32 + uint16_t aba_ctr; +#else +#error Unsupported bit width architecture +#endif +#endif +}; + +/* Use a union to make sure that these are in the same bits as an atm word */ +typedef union lockfree_node { + gpr_atm atm; + struct lockfree_node_contents contents; +} lockfree_node; + +/* make sure that entries aligned to 8-bytes */ +#define ENTRY_ALIGNMENT_BITS 3 +/* reserve this entry as invalid */ +#define INVALID_ENTRY_INDEX ((1 << 16) - 1) + +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(size_t entries) { + gpr_stack_lockfree *stack; + stack = gpr_malloc(sizeof(*stack)); + /* Since we only allocate 16 bits to represent an entry number, + * make sure that we are within the desired range */ + /* Reserve the highest entry number as a dummy */ + GPR_ASSERT(entries < INVALID_ENTRY_INDEX); + stack->entries = gpr_malloc_aligned(entries * sizeof(stack->entries[0]), + ENTRY_ALIGNMENT_BITS); + /* Clear out all entries */ + memset(stack->entries, 0, entries * sizeof(stack->entries[0])); + memset(&stack->head, 0, sizeof(stack->head)); +#ifndef NDEBUG + memset(&stack->pushed, 0, sizeof(stack->pushed)); +#endif + + GPR_ASSERT(sizeof(stack->entries->atm) == sizeof(stack->entries->contents)); + + /* Point the head at reserved dummy entry */ + stack->head.contents.index = INVALID_ENTRY_INDEX; +/* Fill in the pad and aba_ctr to avoid confusing memcheck tools */ +#ifdef GPR_ARCH_64 + stack->head.contents.pad = 0; +#endif + stack->head.contents.aba_ctr = 0; + return stack; +} + +void gpr_stack_lockfree_destroy(gpr_stack_lockfree *stack) { + gpr_free_aligned(stack->entries); + gpr_free(stack); +} + +int gpr_stack_lockfree_push(gpr_stack_lockfree *stack, int entry) { + lockfree_node head; + lockfree_node newhead; + lockfree_node curent; + lockfree_node newent; + + /* First fill in the entry's index and aba ctr for new head */ + newhead.contents.index = (uint16_t)entry; +#ifdef GPR_ARCH_64 + /* Fill in the pad to avoid confusing memcheck tools */ + newhead.contents.pad = 0; +#endif + + /* Also post-increment the aba_ctr */ + curent.atm = gpr_atm_no_barrier_load(&stack->entries[entry].atm); + newhead.contents.aba_ctr = ++curent.contents.aba_ctr; + gpr_atm_no_barrier_store(&stack->entries[entry].atm, curent.atm); + +#ifndef NDEBUG + /* Check for double push */ + { + int pushed_index = entry / (int)(8 * sizeof(gpr_atm)); + int pushed_bit = entry % (int)(8 * sizeof(gpr_atm)); + gpr_atm old_val; + + old_val = gpr_atm_no_barrier_fetch_add(&stack->pushed[pushed_index], + ((gpr_atm)1 << pushed_bit)); + GPR_ASSERT((old_val & (((gpr_atm)1) << pushed_bit)) == 0); + } +#endif + + do { + /* Atomically get the existing head value for use */ + head.atm = gpr_atm_no_barrier_load(&(stack->head.atm)); + /* Point to it */ + newent.atm = gpr_atm_no_barrier_load(&stack->entries[entry].atm); + newent.contents.index = head.contents.index; + gpr_atm_no_barrier_store(&stack->entries[entry].atm, newent.atm); + } while (!gpr_atm_rel_cas(&(stack->head.atm), head.atm, newhead.atm)); + /* Use rel_cas above to make sure that entry index is set properly */ + return head.contents.index == INVALID_ENTRY_INDEX; +} + +int gpr_stack_lockfree_pop(gpr_stack_lockfree *stack) { + lockfree_node head; + lockfree_node newhead; + + do { + head.atm = gpr_atm_acq_load(&(stack->head.atm)); + if (head.contents.index == INVALID_ENTRY_INDEX) { + return -1; + } + newhead.atm = + gpr_atm_no_barrier_load(&(stack->entries[head.contents.index].atm)); + + } while (!gpr_atm_no_barrier_cas(&(stack->head.atm), head.atm, newhead.atm)); +#ifndef NDEBUG + /* Check for valid pop */ + { + int pushed_index = head.contents.index / (8 * sizeof(gpr_atm)); + int pushed_bit = head.contents.index % (8 * sizeof(gpr_atm)); + gpr_atm old_val; + + old_val = gpr_atm_no_barrier_fetch_add(&stack->pushed[pushed_index], + -((gpr_atm)1 << pushed_bit)); + GPR_ASSERT((old_val & (((gpr_atm)1) << pushed_bit)) != 0); + } +#endif + + return head.contents.index; +} diff --git a/src/core/lib/support/stack_lockfree.h b/src/core/lib/support/stack_lockfree.h new file mode 100644 index 0000000000..d6fd06d67c --- /dev/null +++ b/src/core/lib/support/stack_lockfree.h @@ -0,0 +1,53 @@ +/* + * + * Copyright 2015-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_SUPPORT_STACK_LOCKFREE_H +#define GRPC_CORE_SUPPORT_STACK_LOCKFREE_H + +#include + +typedef struct gpr_stack_lockfree gpr_stack_lockfree; + +/* This stack must specify the maximum number of entries to track. + The current implementation only allows up to 65534 entries */ +gpr_stack_lockfree *gpr_stack_lockfree_create(size_t entries); +void gpr_stack_lockfree_destroy(gpr_stack_lockfree *stack); + +/* Pass in a valid entry number for the next stack entry */ +/* Returns 1 if this is the first element on the stack, 0 otherwise */ +int gpr_stack_lockfree_push(gpr_stack_lockfree *, int entry); + +/* Returns -1 on empty or the actual entry number */ +int gpr_stack_lockfree_pop(gpr_stack_lockfree *stack); + +#endif /* GRPC_CORE_SUPPORT_STACK_LOCKFREE_H */ diff --git a/src/core/lib/support/string.c b/src/core/lib/support/string.c new file mode 100644 index 0000000000..1f541de40f --- /dev/null +++ b/src/core/lib/support/string.c @@ -0,0 +1,296 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/support/string.h" + +#include +#include +#include + +#include +#include +#include +#include + +char *gpr_strdup(const char *src) { + char *dst; + size_t len; + + if (!src) { + return NULL; + } + + len = strlen(src) + 1; + dst = gpr_malloc(len); + + memcpy(dst, src, len); + + return dst; +} + +typedef struct { + size_t capacity; + size_t length; + char *data; +} dump_out; + +static dump_out dump_out_create(void) { + dump_out r = {0, 0, NULL}; + return r; +} + +static void dump_out_append(dump_out *out, char c) { + if (out->length == out->capacity) { + out->capacity = GPR_MAX(8, 2 * out->capacity); + out->data = gpr_realloc(out->data, out->capacity); + } + out->data[out->length++] = c; +} + +static void hexdump(dump_out *out, const char *buf, size_t len) { + static const char hex[16] = "0123456789abcdef"; + + const uint8_t *const beg = (const uint8_t *)buf; + const uint8_t *const end = beg + len; + const uint8_t *cur; + + for (cur = beg; cur != end; ++cur) { + if (cur != beg) dump_out_append(out, ' '); + dump_out_append(out, hex[*cur >> 4]); + dump_out_append(out, hex[*cur & 0xf]); + } +} + +static void asciidump(dump_out *out, const char *buf, size_t len) { + const uint8_t *const beg = (const uint8_t *)buf; + const uint8_t *const end = beg + len; + const uint8_t *cur; + int out_was_empty = (out->length == 0); + if (!out_was_empty) { + dump_out_append(out, ' '); + dump_out_append(out, '\''); + } + for (cur = beg; cur != end; ++cur) { + dump_out_append(out, (char)(isprint(*cur) ? *(char *)cur : '.')); + } + if (!out_was_empty) { + dump_out_append(out, '\''); + } +} + +char *gpr_dump(const char *buf, size_t len, uint32_t flags) { + dump_out out = dump_out_create(); + if (flags & GPR_DUMP_HEX) { + hexdump(&out, buf, len); + } + if (flags & GPR_DUMP_ASCII) { + asciidump(&out, buf, len); + } + dump_out_append(&out, 0); + return out.data; +} + +char *gpr_dump_slice(gpr_slice s, uint32_t flags) { + return gpr_dump((const char *)GPR_SLICE_START_PTR(s), GPR_SLICE_LENGTH(s), + flags); +} + +int gpr_parse_bytes_to_uint32(const char *buf, size_t len, uint32_t *result) { + uint32_t out = 0; + uint32_t new; + size_t i; + + if (len == 0) return 0; /* must have some bytes */ + + for (i = 0; i < len; i++) { + if (buf[i] < '0' || buf[i] > '9') return 0; /* bad char */ + new = 10 * out + (uint32_t)(buf[i] - '0'); + if (new < out) return 0; /* overflow */ + out = new; + } + + *result = out; + return 1; +} + +void gpr_reverse_bytes(char *str, int len) { + char *p1, *p2; + for (p1 = str, p2 = str + len - 1; p2 > p1; ++p1, --p2) { + char temp = *p1; + *p1 = *p2; + *p2 = temp; + } +} + +int gpr_ltoa(long value, char *string) { + long sign; + int i = 0; + + if (value == 0) { + string[0] = '0'; + string[1] = 0; + return 1; + } + + sign = value < 0 ? -1 : 1; + while (value) { + string[i++] = (char)('0' + sign * (value % 10)); + value /= 10; + } + if (sign < 0) string[i++] = '-'; + gpr_reverse_bytes(string, i); + string[i] = 0; + return i; +} + +int int64_ttoa(int64_t value, char *string) { + int64_t sign; + int i = 0; + + if (value == 0) { + string[0] = '0'; + string[1] = 0; + return 1; + } + + sign = value < 0 ? -1 : 1; + while (value) { + string[i++] = (char)('0' + sign * (value % 10)); + value /= 10; + } + if (sign < 0) string[i++] = '-'; + gpr_reverse_bytes(string, i); + string[i] = 0; + return i; +} + +char *gpr_strjoin(const char **strs, size_t nstrs, size_t *final_length) { + return gpr_strjoin_sep(strs, nstrs, "", final_length); +} + +char *gpr_strjoin_sep(const char **strs, size_t nstrs, const char *sep, + size_t *final_length) { + const size_t sep_len = strlen(sep); + size_t out_length = 0; + size_t i; + char *out; + for (i = 0; i < nstrs; i++) { + out_length += strlen(strs[i]); + } + out_length += 1; /* null terminator */ + if (nstrs > 0) { + out_length += sep_len * (nstrs - 1); /* separators */ + } + out = gpr_malloc(out_length); + out_length = 0; + for (i = 0; i < nstrs; i++) { + const size_t slen = strlen(strs[i]); + if (i != 0) { + memcpy(out + out_length, sep, sep_len); + out_length += sep_len; + } + memcpy(out + out_length, strs[i], slen); + out_length += slen; + } + out[out_length] = 0; + if (final_length != NULL) { + *final_length = out_length; + } + return out; +} + +/** Finds the initial (\a begin) and final (\a end) offsets of the next + * substring from \a str + \a read_offset until the next \a sep or the end of \a + * str. + * + * Returns 1 and updates \a begin and \a end. Returns 0 otherwise. */ +static int slice_find_separator_offset(const gpr_slice str, const char *sep, + const size_t read_offset, size_t *begin, + size_t *end) { + size_t i; + const uint8_t *str_ptr = GPR_SLICE_START_PTR(str) + read_offset; + const size_t str_len = GPR_SLICE_LENGTH(str) - read_offset; + const size_t sep_len = strlen(sep); + if (str_len < sep_len) { + return 0; + } + + for (i = 0; i <= str_len - sep_len; i++) { + if (memcmp(str_ptr + i, sep, sep_len) == 0) { + *begin = read_offset; + *end = read_offset + i; + return 1; + } + } + return 0; +} + +void gpr_slice_split(gpr_slice str, const char *sep, gpr_slice_buffer *dst) { + const size_t sep_len = strlen(sep); + size_t begin, end; + + GPR_ASSERT(sep_len > 0); + + if (slice_find_separator_offset(str, sep, 0, &begin, &end) != 0) { + do { + gpr_slice_buffer_add_indexed(dst, gpr_slice_sub(str, begin, end)); + } while (slice_find_separator_offset(str, sep, end + sep_len, &begin, + &end) != 0); + gpr_slice_buffer_add_indexed( + dst, gpr_slice_sub(str, end + sep_len, GPR_SLICE_LENGTH(str))); + } else { /* no sep found, add whole input */ + gpr_slice_buffer_add_indexed(dst, gpr_slice_ref(str)); + } +} + +void gpr_strvec_init(gpr_strvec *sv) { memset(sv, 0, sizeof(*sv)); } + +void gpr_strvec_destroy(gpr_strvec *sv) { + size_t i; + for (i = 0; i < sv->count; i++) { + gpr_free(sv->strs[i]); + } + gpr_free(sv->strs); +} + +void gpr_strvec_add(gpr_strvec *sv, char *str) { + if (sv->count == sv->capacity) { + sv->capacity = GPR_MAX(sv->capacity + 8, sv->capacity * 2); + sv->strs = gpr_realloc(sv->strs, sizeof(char *) * sv->capacity); + } + sv->strs[sv->count++] = str; +} + +char *gpr_strvec_flatten(gpr_strvec *sv, size_t *final_length) { + return gpr_strjoin((const char **)sv->strs, sv->count, final_length); +} diff --git a/src/core/lib/support/string.h b/src/core/lib/support/string.h new file mode 100644 index 0000000000..8ff16882ab --- /dev/null +++ b/src/core/lib/support/string.h @@ -0,0 +1,121 @@ +/* + * + * Copyright 2015-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_SUPPORT_STRING_H +#define GRPC_CORE_SUPPORT_STRING_H + +#include + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* String utility functions */ + +/* Flags for gpr_dump function. */ +#define GPR_DUMP_HEX 0x00000001 +#define GPR_DUMP_ASCII 0x00000002 + +/* Converts array buf, of length len, into a C string according to the flags. + Result should be freed with gpr_free() */ +char *gpr_dump(const char *buf, size_t len, uint32_t flags); + +/* Calls gpr_dump on a slice. */ +char *gpr_dump_slice(gpr_slice slice, uint32_t flags); + +/* Parses an array of bytes into an integer (base 10). Returns 1 on success, + 0 on failure. */ +int gpr_parse_bytes_to_uint32(const char *data, size_t length, + uint32_t *result); + +/* Minimum buffer size for calling ltoa */ +#define GPR_LTOA_MIN_BUFSIZE (3 * sizeof(long)) + +/* Convert a long to a string in base 10; returns the length of the + output string (or 0 on failure). + output must be at least GPR_LTOA_MIN_BUFSIZE bytes long. */ +int gpr_ltoa(long value, char *output); + +/* Minimum buffer size for calling int64toa */ +#define GPR_INT64TOA_MIN_BUFSIZE (3 * sizeof(int64_t)) + +/* Convert an int64 to a string in base 10; returns the length of the +output string (or 0 on failure). +output must be at least GPR_INT64TOA_MIN_BUFSIZE bytes long. +NOTE: This function ensures sufficient bit width even on Win x64, +where long is 32bit is size.*/ +int int64_ttoa(int64_t value, char *output); + +/* Reverse a run of bytes */ +void gpr_reverse_bytes(char *str, int len); + +/* Join a set of strings, returning the resulting string. + Total combined length (excluding null terminator) is returned in total_length + if it is non-null. */ +char *gpr_strjoin(const char **strs, size_t nstrs, size_t *total_length); + +/* Join a set of strings using a separator, returning the resulting string. + Total combined length (excluding null terminator) is returned in total_length + if it is non-null. */ +char *gpr_strjoin_sep(const char **strs, size_t nstrs, const char *sep, + size_t *total_length); + +/** Split \a str by the separator \a sep. Results are stored in \a dst, which + * should be a properly initialized instance. */ +void gpr_slice_split(gpr_slice str, const char *sep, gpr_slice_buffer *dst); + +/* A vector of strings... for building up a final string one piece at a time */ +typedef struct { + char **strs; + size_t count; + size_t capacity; +} gpr_strvec; + +/* Initialize/destroy */ +void gpr_strvec_init(gpr_strvec *strs); +void gpr_strvec_destroy(gpr_strvec *strs); +/* Add a string to a strvec, takes ownership of the string */ +void gpr_strvec_add(gpr_strvec *strs, char *add); +/* Return a joined string with all added substrings, optionally setting + total_length as per gpr_strjoin */ +char *gpr_strvec_flatten(gpr_strvec *strs, size_t *total_length); + +#ifdef __cplusplus +} +#endif + +#endif /* GRPC_CORE_SUPPORT_STRING_H */ diff --git a/src/core/lib/support/string_posix.c b/src/core/lib/support/string_posix.c new file mode 100644 index 0000000000..a73b3106a5 --- /dev/null +++ b/src/core/lib/support/string_posix.c @@ -0,0 +1,86 @@ +/* + * + * Copyright 2015-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 + +#ifdef GPR_POSIX_STRING + +#include +#include +#include + +#include + +int gpr_asprintf(char **strp, const char *format, ...) { + va_list args; + int ret; + char buf[64]; + size_t strp_buflen; + + /* Use a constant-sized buffer to determine the length. */ + va_start(args, format); + ret = vsnprintf(buf, sizeof(buf), format, args); + va_end(args); + if (ret < 0) { + *strp = NULL; + return -1; + } + + /* Allocate a new buffer, with space for the NUL terminator. */ + strp_buflen = (size_t)ret + 1; + if ((*strp = gpr_malloc(strp_buflen)) == NULL) { + /* This shouldn't happen, because gpr_malloc() calls abort(). */ + return -1; + } + + /* Return early if we have all the bytes. */ + if (strp_buflen <= sizeof(buf)) { + memcpy(*strp, buf, strp_buflen); + return ret; + } + + /* Try again using the larger buffer. */ + va_start(args, format); + ret = vsnprintf(*strp, strp_buflen, format, args); + va_end(args); + if ((size_t)ret == strp_buflen - 1) { + return ret; + } + + /* This should never happen. */ + gpr_free(*strp); + *strp = NULL; + return -1; +} + +#endif /* GPR_POSIX_STRING */ diff --git a/src/core/lib/support/string_win32.c b/src/core/lib/support/string_win32.c new file mode 100644 index 0000000000..0780907994 --- /dev/null +++ b/src/core/lib/support/string_win32.c @@ -0,0 +1,109 @@ +/* + * + * Copyright 2015-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. + * + */ + +/* Posix code for gpr snprintf support. */ + +#include + +#ifdef GPR_WIN32 + +#include +#include +#include + +#include + +#include "src/core/support/string.h" + +int gpr_asprintf(char **strp, const char *format, ...) { + va_list args; + int ret; + size_t strp_buflen; + + /* Determine the length. */ + va_start(args, format); + ret = _vscprintf(format, args); + va_end(args); + if (ret < 0) { + *strp = NULL; + return -1; + } + + /* Allocate a new buffer, with space for the NUL terminator. */ + strp_buflen = (size_t)ret + 1; + if ((*strp = gpr_malloc(strp_buflen)) == NULL) { + /* This shouldn't happen, because gpr_malloc() calls abort(). */ + return -1; + } + + /* Print to the buffer. */ + va_start(args, format); + ret = vsnprintf_s(*strp, strp_buflen, _TRUNCATE, format, args); + va_end(args); + if ((size_t)ret == strp_buflen - 1) { + return ret; + } + + /* This should never happen. */ + gpr_free(*strp); + *strp = NULL; + return -1; +} + +#if defined UNICODE || defined _UNICODE +LPTSTR +gpr_char_to_tchar(LPCSTR input) { + LPTSTR ret; + int needed = MultiByteToWideChar(CP_UTF8, 0, input, -1, NULL, 0); + if (needed <= 0) return NULL; + ret = gpr_malloc((unsigned)needed * sizeof(TCHAR)); + MultiByteToWideChar(CP_UTF8, 0, input, -1, ret, needed); + return ret; +} + +LPSTR +gpr_tchar_to_char(LPCTSTR input) { + LPSTR ret; + int needed = WideCharToMultiByte(CP_UTF8, 0, input, -1, NULL, 0, NULL, NULL); + if (needed <= 0) return NULL; + ret = gpr_malloc((unsigned)needed); + WideCharToMultiByte(CP_UTF8, 0, input, -1, ret, needed, NULL, NULL); + return ret; +} +#else +char *gpr_tchar_to_char(LPTSTR input) { return gpr_strdup(input); } + +char *gpr_char_to_tchar(LPTSTR input) { return gpr_strdup(input); } +#endif + +#endif /* GPR_WIN32 */ diff --git a/src/core/lib/support/string_win32.h b/src/core/lib/support/string_win32.h new file mode 100644 index 0000000000..c9ae8d9932 --- /dev/null +++ b/src/core/lib/support/string_win32.h @@ -0,0 +1,47 @@ +/* + * + * Copyright 2015-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_SUPPORT_STRING_WIN32_H +#define GRPC_CORE_SUPPORT_STRING_WIN32_H + +#include + +#ifdef GPR_WIN32 + +/* These allocate new strings using gpr_malloc to convert from and to utf-8. */ +LPTSTR gpr_char_to_tchar(LPCSTR input); +LPSTR gpr_tchar_to_char(LPCTSTR input); + +#endif /* GPR_WIN32 */ + +#endif /* GRPC_CORE_SUPPORT_STRING_WIN32_H */ diff --git a/src/core/lib/support/subprocess_posix.c b/src/core/lib/support/subprocess_posix.c new file mode 100644 index 0000000000..662e7dd999 --- /dev/null +++ b/src/core/lib/support/subprocess_posix.c @@ -0,0 +1,112 @@ +/* + * + * Copyright 2015-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 + +#ifdef GPR_POSIX_SUBPROCESS + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +struct gpr_subprocess { + int pid; + int joined; +}; + +const char *gpr_subprocess_binary_extension() { return ""; } + +gpr_subprocess *gpr_subprocess_create(int argc, const char **argv) { + gpr_subprocess *r; + int pid; + char **exec_args; + + pid = fork(); + if (pid == -1) { + return NULL; + } else if (pid == 0) { + exec_args = gpr_malloc(((size_t)argc + 1) * sizeof(char *)); + memcpy(exec_args, argv, (size_t)argc * sizeof(char *)); + exec_args[argc] = NULL; + execv(exec_args[0], exec_args); + /* if we reach here, an error has occurred */ + gpr_log(GPR_ERROR, "execv '%s' failed: %s", exec_args[0], strerror(errno)); + _exit(1); + return NULL; + } else { + r = gpr_malloc(sizeof(gpr_subprocess)); + memset(r, 0, sizeof(*r)); + r->pid = pid; + return r; + } +} + +void gpr_subprocess_destroy(gpr_subprocess *p) { + if (!p->joined) { + kill(p->pid, SIGKILL); + gpr_subprocess_join(p); + } + gpr_free(p); +} + +int gpr_subprocess_join(gpr_subprocess *p) { + int status; +retry: + if (waitpid(p->pid, &status, 0) == -1) { + if (errno == EINTR) { + goto retry; + } + gpr_log(GPR_ERROR, "waitpid failed: %s", strerror(errno)); + return -1; + } + return status; +} + +void gpr_subprocess_interrupt(gpr_subprocess *p) { + if (!p->joined) { + kill(p->pid, SIGINT); + } +} + +#endif /* GPR_POSIX_SUBPROCESS */ diff --git a/src/core/lib/support/subprocess_windows.c b/src/core/lib/support/subprocess_windows.c new file mode 100644 index 0000000000..6afbefeb2b --- /dev/null +++ b/src/core/lib/support/subprocess_windows.c @@ -0,0 +1,141 @@ +/* + * + * 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 + +#ifdef GPR_WINDOWS_SUBPROCESS + +#include +#include +#include + +#include +#include +#include +#include "src/core/support/string.h" +#include "src/core/support/string_win32.h" + +struct gpr_subprocess { + PROCESS_INFORMATION pi; + int joined; + int interrupted; +}; + +const char *gpr_subprocess_binary_extension() { return ".exe"; } + +gpr_subprocess *gpr_subprocess_create(int argc, const char **argv) { + gpr_subprocess *r; + + STARTUPINFO si; + PROCESS_INFORMATION pi; + + char *args = gpr_strjoin_sep(argv, (size_t)argc, " ", NULL); + TCHAR *args_tchar; + + args_tchar = gpr_char_to_tchar(args); + gpr_free(args); + + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + memset(&pi, 0, sizeof(pi)); + + if (!CreateProcess(NULL, args_tchar, NULL, NULL, FALSE, + CREATE_NEW_PROCESS_GROUP, NULL, NULL, &si, &pi)) { + gpr_free(args_tchar); + return NULL; + } + gpr_free(args_tchar); + + r = gpr_malloc(sizeof(gpr_subprocess)); + memset(r, 0, sizeof(*r)); + r->pi = pi; + return r; +} + +void gpr_subprocess_destroy(gpr_subprocess *p) { + if (p) { + if (!p->joined) { + gpr_subprocess_interrupt(p); + gpr_subprocess_join(p); + } + if (p->pi.hProcess) { + CloseHandle(p->pi.hProcess); + } + if (p->pi.hThread) { + CloseHandle(p->pi.hThread); + } + gpr_free(p); + } +} + +int gpr_subprocess_join(gpr_subprocess *p) { + DWORD dwExitCode; + if (GetExitCodeProcess(p->pi.hProcess, &dwExitCode)) { + if (dwExitCode == STILL_ACTIVE) { + if (WaitForSingleObject(p->pi.hProcess, INFINITE) == WAIT_OBJECT_0) { + p->joined = 1; + goto getExitCode; + } + return -1; // failed to join + } else { + goto getExitCode; + } + } else { + return -1; // failed to get exit code + } + +getExitCode: + if (p->interrupted) { + return 0; + } + if (GetExitCodeProcess(p->pi.hProcess, &dwExitCode)) { + return (int)dwExitCode; + } else { + return -1; // failed to get exit code + } +} + +void gpr_subprocess_interrupt(gpr_subprocess *p) { + DWORD dwExitCode; + if (GetExitCodeProcess(p->pi.hProcess, &dwExitCode)) { + if (dwExitCode == STILL_ACTIVE) { + gpr_log(GPR_INFO, "sending ctrl-break"); + GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, p->pi.dwProcessId); + p->joined = 1; + p->interrupted = 1; + } + } + return; +} + +#endif /* GPR_WINDOWS_SUBPROCESS */ diff --git a/src/core/lib/support/sync.c b/src/core/lib/support/sync.c new file mode 100644 index 0000000000..800cf20287 --- /dev/null +++ b/src/core/lib/support/sync.c @@ -0,0 +1,127 @@ +/* + * + * Copyright 2015-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. + * + */ + +/* Generic implementation of synchronization primitives. */ + +#include +#include +#include + +/* Number of mutexes to allocate for events, to avoid lock contention. + Should be a prime. */ +enum { event_sync_partitions = 31 }; + +/* Events are partitioned by address to avoid lock contention. */ +static struct sync_array_s { + gpr_mu mu; + gpr_cv cv; +} sync_array[event_sync_partitions]; + +/* This routine is executed once on first use, via event_once */ +static gpr_once event_once = GPR_ONCE_INIT; +static void event_initialize(void) { + int i; + for (i = 0; i != event_sync_partitions; i++) { + gpr_mu_init(&sync_array[i].mu); + gpr_cv_init(&sync_array[i].cv); + } +} + +/* Hash ev into an element of sync_array[]. */ +static struct sync_array_s *hash(gpr_event *ev) { + return &sync_array[((uintptr_t)ev) % event_sync_partitions]; +} + +void gpr_event_init(gpr_event *ev) { + gpr_once_init(&event_once, &event_initialize); + ev->state = 0; +} + +void gpr_event_set(gpr_event *ev, void *value) { + struct sync_array_s *s = hash(ev); + gpr_mu_lock(&s->mu); + GPR_ASSERT(gpr_atm_acq_load(&ev->state) == 0); + gpr_atm_rel_store(&ev->state, (gpr_atm)value); + gpr_cv_broadcast(&s->cv); + gpr_mu_unlock(&s->mu); + GPR_ASSERT(value != NULL); +} + +void *gpr_event_get(gpr_event *ev) { + return (void *)gpr_atm_acq_load(&ev->state); +} + +void *gpr_event_wait(gpr_event *ev, gpr_timespec abs_deadline) { + void *result = (void *)gpr_atm_acq_load(&ev->state); + if (result == NULL) { + struct sync_array_s *s = hash(ev); + gpr_mu_lock(&s->mu); + do { + result = (void *)gpr_atm_acq_load(&ev->state); + } while (result == NULL && !gpr_cv_wait(&s->cv, &s->mu, abs_deadline)); + gpr_mu_unlock(&s->mu); + } + return result; +} + +void gpr_ref_init(gpr_refcount *r, int n) { gpr_atm_rel_store(&r->count, n); } + +void gpr_ref(gpr_refcount *r) { gpr_atm_no_barrier_fetch_add(&r->count, 1); } + +void gpr_ref_non_zero(gpr_refcount *r) { + gpr_atm prior = gpr_atm_no_barrier_fetch_add(&r->count, 1); + GPR_ASSERT(prior > 0); +} + +void gpr_refn(gpr_refcount *r, int n) { + gpr_atm_no_barrier_fetch_add(&r->count, n); +} + +int gpr_unref(gpr_refcount *r) { + gpr_atm prior = gpr_atm_full_fetch_add(&r->count, -1); + GPR_ASSERT(prior > 0); + return prior == 1; +} + +void gpr_stats_init(gpr_stats_counter *c, intptr_t n) { + gpr_atm_rel_store(&c->value, n); +} + +void gpr_stats_inc(gpr_stats_counter *c, intptr_t inc) { + gpr_atm_no_barrier_fetch_add(&c->value, inc); +} + +intptr_t gpr_stats_read(const gpr_stats_counter *c) { + /* don't need acquire-load, but we have no no-barrier load yet */ + return gpr_atm_acq_load(&c->value); +} diff --git a/src/core/lib/support/sync_posix.c b/src/core/lib/support/sync_posix.c new file mode 100644 index 0000000000..be4d0ac1c9 --- /dev/null +++ b/src/core/lib/support/sync_posix.c @@ -0,0 +1,104 @@ +/* + * + * Copyright 2015-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 + +#ifdef GPR_POSIX_SYNC + +#include +#include +#include +#include +#include +#include "src/core/profiling/timers.h" + +void gpr_mu_init(gpr_mu* mu) { GPR_ASSERT(pthread_mutex_init(mu, NULL) == 0); } + +void gpr_mu_destroy(gpr_mu* mu) { GPR_ASSERT(pthread_mutex_destroy(mu) == 0); } + +void gpr_mu_lock(gpr_mu* mu) { + GPR_TIMER_BEGIN("gpr_mu_lock", 0); + GPR_ASSERT(pthread_mutex_lock(mu) == 0); + GPR_TIMER_END("gpr_mu_lock", 0); +} + +void gpr_mu_unlock(gpr_mu* mu) { + GPR_TIMER_BEGIN("gpr_mu_unlock", 0); + GPR_ASSERT(pthread_mutex_unlock(mu) == 0); + GPR_TIMER_END("gpr_mu_unlock", 0); +} + +int gpr_mu_trylock(gpr_mu* mu) { + int err; + GPR_TIMER_BEGIN("gpr_mu_trylock", 0); + err = pthread_mutex_trylock(mu); + GPR_ASSERT(err == 0 || err == EBUSY); + GPR_TIMER_END("gpr_mu_trylock", 0); + return err == 0; +} + +/*----------------------------------------*/ + +void gpr_cv_init(gpr_cv* cv) { GPR_ASSERT(pthread_cond_init(cv, NULL) == 0); } + +void gpr_cv_destroy(gpr_cv* cv) { GPR_ASSERT(pthread_cond_destroy(cv) == 0); } + +int gpr_cv_wait(gpr_cv* cv, gpr_mu* mu, gpr_timespec abs_deadline) { + int err = 0; + if (gpr_time_cmp(abs_deadline, gpr_inf_future(abs_deadline.clock_type)) == + 0) { + err = pthread_cond_wait(cv, mu); + } else { + struct timespec abs_deadline_ts; + abs_deadline = gpr_convert_clock_type(abs_deadline, GPR_CLOCK_REALTIME); + abs_deadline_ts.tv_sec = (time_t)abs_deadline.tv_sec; + abs_deadline_ts.tv_nsec = abs_deadline.tv_nsec; + err = pthread_cond_timedwait(cv, mu, &abs_deadline_ts); + } + GPR_ASSERT(err == 0 || err == ETIMEDOUT || err == EAGAIN); + return err == ETIMEDOUT; +} + +void gpr_cv_signal(gpr_cv* cv) { GPR_ASSERT(pthread_cond_signal(cv) == 0); } + +void gpr_cv_broadcast(gpr_cv* cv) { + GPR_ASSERT(pthread_cond_broadcast(cv) == 0); +} + +/*----------------------------------------*/ + +void gpr_once_init(gpr_once* once, void (*init_function)(void)) { + GPR_ASSERT(pthread_once(once, init_function) == 0); +} + +#endif /* GRP_POSIX_SYNC */ diff --git a/src/core/lib/support/sync_win32.c b/src/core/lib/support/sync_win32.c new file mode 100644 index 0000000000..41998ebcb6 --- /dev/null +++ b/src/core/lib/support/sync_win32.c @@ -0,0 +1,133 @@ +/* + * + * Copyright 2015-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. + * + */ + +/* Win32 code for gpr synchronization support. */ + +#include + +#ifdef GPR_WIN32 + +#include +#include +#include + +void gpr_mu_init(gpr_mu *mu) { + InitializeCriticalSection(&mu->cs); + mu->locked = 0; +} + +void gpr_mu_destroy(gpr_mu *mu) { DeleteCriticalSection(&mu->cs); } + +void gpr_mu_lock(gpr_mu *mu) { + EnterCriticalSection(&mu->cs); + GPR_ASSERT(!mu->locked); + mu->locked = 1; +} + +void gpr_mu_unlock(gpr_mu *mu) { + mu->locked = 0; + LeaveCriticalSection(&mu->cs); +} + +int gpr_mu_trylock(gpr_mu *mu) { + int result = TryEnterCriticalSection(&mu->cs); + if (result) { + if (mu->locked) { /* This thread already holds the lock. */ + LeaveCriticalSection(&mu->cs); /* Decrement lock count. */ + result = 0; /* Indicate failure */ + } + mu->locked = 1; + } + return result; +} + +/*----------------------------------------*/ + +void gpr_cv_init(gpr_cv *cv) { InitializeConditionVariable(cv); } + +void gpr_cv_destroy(gpr_cv *cv) { + /* Condition variables don't need destruction in Win32. */ +} + +int gpr_cv_wait(gpr_cv *cv, gpr_mu *mu, gpr_timespec abs_deadline) { + int timeout = 0; + DWORD timeout_max_ms; + mu->locked = 0; + if (gpr_time_cmp(abs_deadline, gpr_inf_future(abs_deadline.clock_type)) == + 0) { + SleepConditionVariableCS(cv, &mu->cs, INFINITE); + } else { + abs_deadline = gpr_convert_clock_type(abs_deadline, GPR_CLOCK_REALTIME); + gpr_timespec now = gpr_now(abs_deadline.clock_type); + int64_t now_ms = (int64_t)now.tv_sec * 1000 + now.tv_nsec / 1000000; + int64_t deadline_ms = + (int64_t)abs_deadline.tv_sec * 1000 + abs_deadline.tv_nsec / 1000000; + if (now_ms >= deadline_ms) { + timeout = 1; + } else { + if ((deadline_ms - now_ms) >= INFINITE) { + timeout_max_ms = INFINITE - 1; + } else { + timeout_max_ms = (DWORD)(deadline_ms - now_ms); + } + timeout = (SleepConditionVariableCS(cv, &mu->cs, timeout_max_ms) == 0 && + GetLastError() == ERROR_TIMEOUT); + } + } + mu->locked = 1; + return timeout; +} + +void gpr_cv_signal(gpr_cv *cv) { WakeConditionVariable(cv); } + +void gpr_cv_broadcast(gpr_cv *cv) { WakeAllConditionVariable(cv); } + +/*----------------------------------------*/ + +static void *dummy; +struct run_once_func_arg { + void (*init_function)(void); +}; +static BOOL CALLBACK run_once_func(gpr_once *once, void *v, void **pv) { + struct run_once_func_arg *arg = v; + (*arg->init_function)(); + return 1; +} + +void gpr_once_init(gpr_once *once, void (*init_function)(void)) { + struct run_once_func_arg arg; + arg.init_function = init_function; + InitOnceExecuteOnce(once, run_once_func, &arg, &dummy); +} + +#endif /* GPR_WIN32 */ diff --git a/src/core/lib/support/thd.c b/src/core/lib/support/thd.c new file mode 100644 index 0000000000..41daeb5d0e --- /dev/null +++ b/src/core/lib/support/thd.c @@ -0,0 +1,64 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* Posix implementation for gpr threads. */ + +#include + +#include + +enum { GPR_THD_JOINABLE = 1 }; + +gpr_thd_options gpr_thd_options_default(void) { + gpr_thd_options options; + memset(&options, 0, sizeof(options)); + return options; +} + +void gpr_thd_options_set_detached(gpr_thd_options* options) { + options->flags &= ~GPR_THD_JOINABLE; +} + +void gpr_thd_options_set_joinable(gpr_thd_options* options) { + options->flags |= GPR_THD_JOINABLE; +} + +int gpr_thd_options_is_detached(const gpr_thd_options* options) { + if (!options) return 1; + return (options->flags & GPR_THD_JOINABLE) == 0; +} + +int gpr_thd_options_is_joinable(const gpr_thd_options* options) { + if (!options) return 0; + return (options->flags & GPR_THD_JOINABLE) == GPR_THD_JOINABLE; +} diff --git a/src/core/lib/support/thd_internal.h b/src/core/lib/support/thd_internal.h new file mode 100644 index 0000000000..33b904e59b --- /dev/null +++ b/src/core/lib/support/thd_internal.h @@ -0,0 +1,39 @@ +/* + * + * Copyright 2015-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_SUPPORT_THD_INTERNAL_H +#define GRPC_CORE_SUPPORT_THD_INTERNAL_H + +/* Internal interfaces between modules within the gpr support library. */ + +#endif /* GRPC_CORE_SUPPORT_THD_INTERNAL_H */ diff --git a/src/core/lib/support/thd_posix.c b/src/core/lib/support/thd_posix.c new file mode 100644 index 0000000000..4d874d3656 --- /dev/null +++ b/src/core/lib/support/thd_posix.c @@ -0,0 +1,94 @@ +/* + * + * Copyright 2015-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. + * + */ + +/* Posix implementation for gpr threads. */ + +#include + +#ifdef GPR_POSIX_SYNC + +#include +#include +#include +#include +#include +#include +#include + +struct thd_arg { + void (*body)(void *arg); /* body of a thread */ + void *arg; /* argument to a thread */ +}; + +/* Body of every thread started via gpr_thd_new. */ +static void *thread_body(void *v) { + struct thd_arg a = *(struct thd_arg *)v; + free(v); + (*a.body)(a.arg); + return NULL; +} + +int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg, + const gpr_thd_options *options) { + int thread_started; + pthread_attr_t attr; + pthread_t p; + /* don't use gpr_malloc as we may cause an infinite recursion with + * the profiling code */ + struct thd_arg *a = malloc(sizeof(*a)); + GPR_ASSERT(a != NULL); + a->body = thd_body; + a->arg = arg; + + GPR_ASSERT(pthread_attr_init(&attr) == 0); + if (gpr_thd_options_is_detached(options)) { + GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) == + 0); + } else { + GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) == + 0); + } + thread_started = (pthread_create(&p, &attr, &thread_body, a) == 0); + GPR_ASSERT(pthread_attr_destroy(&attr) == 0); + if (!thread_started) { + free(a); + } + *t = (gpr_thd_id)p; + return thread_started; +} + +gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)pthread_self(); } + +void gpr_thd_join(gpr_thd_id t) { pthread_join((pthread_t)t, NULL); } + +#endif /* GPR_POSIX_SYNC */ diff --git a/src/core/lib/support/thd_win32.c b/src/core/lib/support/thd_win32.c new file mode 100644 index 0000000000..630eb7f625 --- /dev/null +++ b/src/core/lib/support/thd_win32.c @@ -0,0 +1,117 @@ +/* + * + * Copyright 2015-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. + * + */ + +/* Windows implementation for gpr threads. */ + +#include + +#ifdef GPR_WIN32 + +#include +#include +#include +#include + +#if defined(_MSC_VER) +#define thread_local __declspec(thread) +#elif defined(__GNUC__) +#define thread_local __thread +#else +#error "Unknown compiler - please file a bug report" +#endif + +struct thd_info { + void (*body)(void *arg); /* body of a thread */ + void *arg; /* argument to a thread */ + HANDLE join_event; /* if joinable, the join event */ + int joinable; /* true if not detached */ +}; + +static thread_local struct thd_info *g_thd_info; + +/* Destroys a thread info */ +static void destroy_thread(struct thd_info *t) { + if (t->joinable) CloseHandle(t->join_event); + gpr_free(t); +} + +/* Body of every thread started via gpr_thd_new. */ +static DWORD WINAPI thread_body(void *v) { + g_thd_info = (struct thd_info *)v; + g_thd_info->body(g_thd_info->arg); + if (g_thd_info->joinable) { + BOOL ret = SetEvent(g_thd_info->join_event); + GPR_ASSERT(ret); + } else { + destroy_thread(g_thd_info); + } + return 0; +} + +int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg, + const gpr_thd_options *options) { + HANDLE handle; + struct thd_info *info = gpr_malloc(sizeof(*info)); + info->body = thd_body; + info->arg = arg; + *t = 0; + if (gpr_thd_options_is_joinable(options)) { + info->joinable = 1; + info->join_event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (info->join_event == NULL) { + gpr_free(info); + return 0; + } + } else { + info->joinable = 0; + } + handle = CreateThread(NULL, 64 * 1024, thread_body, info, 0, NULL); + if (handle == NULL) { + destroy_thread(info); + } else { + *t = (gpr_thd_id)info; + CloseHandle(handle); + } + return handle != NULL; +} + +gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)g_thd_info; } + +void gpr_thd_join(gpr_thd_id t) { + struct thd_info *info = (struct thd_info *)t; + DWORD ret = WaitForSingleObject(info->join_event, INFINITE); + GPR_ASSERT(ret == WAIT_OBJECT_0); + destroy_thread(info); +} + +#endif /* GPR_WIN32 */ diff --git a/src/core/lib/support/time.c b/src/core/lib/support/time.c new file mode 100644 index 0000000000..0e2c8fcf1a --- /dev/null +++ b/src/core/lib/support/time.c @@ -0,0 +1,304 @@ +/* + * + * Copyright 2015-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. + * + */ + +/* Generic implementation of time calls. */ + +#include +#include +#include +#include +#include + +int gpr_time_cmp(gpr_timespec a, gpr_timespec b) { + int cmp = (a.tv_sec > b.tv_sec) - (a.tv_sec < b.tv_sec); + GPR_ASSERT(a.clock_type == b.clock_type); + if (cmp == 0) { + cmp = (a.tv_nsec > b.tv_nsec) - (a.tv_nsec < b.tv_nsec); + } + return cmp; +} + +gpr_timespec gpr_time_min(gpr_timespec a, gpr_timespec b) { + return gpr_time_cmp(a, b) < 0 ? a : b; +} + +gpr_timespec gpr_time_max(gpr_timespec a, gpr_timespec b) { + return gpr_time_cmp(a, b) > 0 ? a : b; +} + +gpr_timespec gpr_time_0(gpr_clock_type type) { + gpr_timespec out; + out.tv_sec = 0; + out.tv_nsec = 0; + out.clock_type = type; + return out; +} + +gpr_timespec gpr_inf_future(gpr_clock_type type) { + gpr_timespec out; + out.tv_sec = INT64_MAX; + out.tv_nsec = 0; + out.clock_type = type; + return out; +} + +gpr_timespec gpr_inf_past(gpr_clock_type type) { + gpr_timespec out; + out.tv_sec = INT64_MIN; + out.tv_nsec = 0; + out.clock_type = type; + return out; +} + +/* TODO(ctiller): consider merging _nanos, _micros, _millis into a single + function for maintainability. Similarly for _seconds, _minutes, and _hours */ + +gpr_timespec gpr_time_from_nanos(int64_t ns, gpr_clock_type type) { + gpr_timespec result; + result.clock_type = type; + if (ns == INT64_MAX) { + result = gpr_inf_future(type); + } else if (ns == INT64_MIN) { + result = gpr_inf_past(type); + } else if (ns >= 0) { + result.tv_sec = ns / GPR_NS_PER_SEC; + result.tv_nsec = (int32_t)(ns - result.tv_sec * GPR_NS_PER_SEC); + } else { + /* Calculation carefully formulated to avoid any possible under/overflow. */ + result.tv_sec = (-(999999999 - (ns + GPR_NS_PER_SEC)) / GPR_NS_PER_SEC) - 1; + result.tv_nsec = (int32_t)(ns - result.tv_sec * GPR_NS_PER_SEC); + } + return result; +} + +gpr_timespec gpr_time_from_micros(int64_t us, gpr_clock_type type) { + gpr_timespec result; + result.clock_type = type; + if (us == INT64_MAX) { + result = gpr_inf_future(type); + } else if (us == INT64_MIN) { + result = gpr_inf_past(type); + } else if (us >= 0) { + result.tv_sec = us / 1000000; + result.tv_nsec = (int32_t)((us - result.tv_sec * 1000000) * 1000); + } else { + /* Calculation carefully formulated to avoid any possible under/overflow. */ + result.tv_sec = (-(999999 - (us + 1000000)) / 1000000) - 1; + result.tv_nsec = (int32_t)((us - result.tv_sec * 1000000) * 1000); + } + return result; +} + +gpr_timespec gpr_time_from_millis(int64_t ms, gpr_clock_type type) { + gpr_timespec result; + result.clock_type = type; + if (ms == INT64_MAX) { + result = gpr_inf_future(type); + } else if (ms == INT64_MIN) { + result = gpr_inf_past(type); + } else if (ms >= 0) { + result.tv_sec = ms / 1000; + result.tv_nsec = (int32_t)((ms - result.tv_sec * 1000) * 1000000); + } else { + /* Calculation carefully formulated to avoid any possible under/overflow. */ + result.tv_sec = (-(999 - (ms + 1000)) / 1000) - 1; + result.tv_nsec = (int32_t)((ms - result.tv_sec * 1000) * 1000000); + } + return result; +} + +gpr_timespec gpr_time_from_seconds(int64_t s, gpr_clock_type type) { + gpr_timespec result; + result.clock_type = type; + if (s == INT64_MAX) { + result = gpr_inf_future(type); + } else if (s == INT64_MIN) { + result = gpr_inf_past(type); + } else { + result.tv_sec = s; + result.tv_nsec = 0; + } + return result; +} + +gpr_timespec gpr_time_from_minutes(int64_t m, gpr_clock_type type) { + gpr_timespec result; + result.clock_type = type; + if (m >= INT64_MAX / 60) { + result = gpr_inf_future(type); + } else if (m <= INT64_MIN / 60) { + result = gpr_inf_past(type); + } else { + result.tv_sec = m * 60; + result.tv_nsec = 0; + } + return result; +} + +gpr_timespec gpr_time_from_hours(int64_t h, gpr_clock_type type) { + gpr_timespec result; + result.clock_type = type; + if (h >= INT64_MAX / 3600) { + result = gpr_inf_future(type); + } else if (h <= INT64_MIN / 3600) { + result = gpr_inf_past(type); + } else { + result.tv_sec = h * 3600; + result.tv_nsec = 0; + } + return result; +} + +gpr_timespec gpr_time_add(gpr_timespec a, gpr_timespec b) { + gpr_timespec sum; + int64_t inc = 0; + GPR_ASSERT(b.clock_type == GPR_TIMESPAN); + sum.clock_type = a.clock_type; + sum.tv_nsec = a.tv_nsec + b.tv_nsec; + if (sum.tv_nsec >= GPR_NS_PER_SEC) { + sum.tv_nsec -= GPR_NS_PER_SEC; + inc++; + } + if (a.tv_sec == INT64_MAX || a.tv_sec == INT64_MIN) { + sum = a; + } else if (b.tv_sec == INT64_MAX || + (b.tv_sec >= 0 && a.tv_sec >= INT64_MAX - b.tv_sec)) { + sum = gpr_inf_future(sum.clock_type); + } else if (b.tv_sec == INT64_MIN || + (b.tv_sec <= 0 && a.tv_sec <= INT64_MIN - b.tv_sec)) { + sum = gpr_inf_past(sum.clock_type); + } else { + sum.tv_sec = a.tv_sec + b.tv_sec; + if (inc != 0 && sum.tv_sec == INT64_MAX - 1) { + sum = gpr_inf_future(sum.clock_type); + } else { + sum.tv_sec += inc; + } + } + return sum; +} + +gpr_timespec gpr_time_sub(gpr_timespec a, gpr_timespec b) { + gpr_timespec diff; + int64_t dec = 0; + if (b.clock_type == GPR_TIMESPAN) { + diff.clock_type = a.clock_type; + } else { + GPR_ASSERT(a.clock_type == b.clock_type); + diff.clock_type = GPR_TIMESPAN; + } + diff.tv_nsec = a.tv_nsec - b.tv_nsec; + if (diff.tv_nsec < 0) { + diff.tv_nsec += GPR_NS_PER_SEC; + dec++; + } + if (a.tv_sec == INT64_MAX || a.tv_sec == INT64_MIN) { + diff = a; + } else if (b.tv_sec == INT64_MIN || + (b.tv_sec <= 0 && a.tv_sec >= INT64_MAX + b.tv_sec)) { + diff = gpr_inf_future(GPR_CLOCK_REALTIME); + } else if (b.tv_sec == INT64_MAX || + (b.tv_sec >= 0 && a.tv_sec <= INT64_MIN + b.tv_sec)) { + diff = gpr_inf_past(GPR_CLOCK_REALTIME); + } else { + diff.tv_sec = a.tv_sec - b.tv_sec; + if (dec != 0 && diff.tv_sec == INT64_MIN + 1) { + diff = gpr_inf_past(GPR_CLOCK_REALTIME); + } else { + diff.tv_sec -= dec; + } + } + return diff; +} + +int gpr_time_similar(gpr_timespec a, gpr_timespec b, gpr_timespec threshold) { + int cmp_ab; + + GPR_ASSERT(a.clock_type == b.clock_type); + GPR_ASSERT(threshold.clock_type == GPR_TIMESPAN); + + cmp_ab = gpr_time_cmp(a, b); + if (cmp_ab == 0) return 1; + if (cmp_ab < 0) { + return gpr_time_cmp(gpr_time_sub(b, a), threshold) <= 0; + } else { + return gpr_time_cmp(gpr_time_sub(a, b), threshold) <= 0; + } +} + +int32_t gpr_time_to_millis(gpr_timespec t) { + if (t.tv_sec >= 2147483) { + if (t.tv_sec == 2147483 && t.tv_nsec < 648 * GPR_NS_PER_MS) { + return 2147483 * GPR_MS_PER_SEC + t.tv_nsec / GPR_NS_PER_MS; + } + return 2147483647; + } else if (t.tv_sec <= -2147483) { + /* TODO(ctiller): correct handling here (it's so far in the past do we + care?) */ + return -2147483647; + } else { + return (int32_t)(t.tv_sec * GPR_MS_PER_SEC + t.tv_nsec / GPR_NS_PER_MS); + } +} + +double gpr_timespec_to_micros(gpr_timespec t) { + return (double)t.tv_sec * GPR_US_PER_SEC + t.tv_nsec * 1e-3; +} + +gpr_timespec gpr_convert_clock_type(gpr_timespec t, gpr_clock_type clock_type) { + if (t.clock_type == clock_type) { + return t; + } + + if (t.tv_nsec == 0) { + if (t.tv_sec == INT64_MAX) { + t.clock_type = clock_type; + return t; + } + if (t.tv_sec == INT64_MIN) { + t.clock_type = clock_type; + return t; + } + } + + if (clock_type == GPR_TIMESPAN) { + return gpr_time_sub(t, gpr_now(t.clock_type)); + } + + if (t.clock_type == GPR_TIMESPAN) { + return gpr_time_add(gpr_now(clock_type), t); + } + + return gpr_time_add(gpr_now(clock_type), + gpr_time_sub(t, gpr_now(t.clock_type))); +} diff --git a/src/core/lib/support/time_posix.c b/src/core/lib/support/time_posix.c new file mode 100644 index 0000000000..f999e08cb0 --- /dev/null +++ b/src/core/lib/support/time_posix.c @@ -0,0 +1,170 @@ +/* + * + * Copyright 2015-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 +#include + +#ifdef GPR_POSIX_TIME + +#include +#include +#include +#ifdef __linux__ +#include +#endif +#include +#include +#include "src/core/support/block_annotate.h" + +static struct timespec timespec_from_gpr(gpr_timespec gts) { + struct timespec rv; + if (sizeof(time_t) < sizeof(int64_t)) { + /* fine to assert, as this is only used in gpr_sleep_until */ + GPR_ASSERT(gts.tv_sec <= INT32_MAX && gts.tv_sec >= INT32_MIN); + } + rv.tv_sec = (time_t)gts.tv_sec; + rv.tv_nsec = gts.tv_nsec; + return rv; +} + +#if _POSIX_TIMERS > 0 +static gpr_timespec gpr_from_timespec(struct timespec ts, + gpr_clock_type clock_type) { + /* + * timespec.tv_sec can have smaller size than gpr_timespec.tv_sec, + * but we are only using this function to implement gpr_now + * so there's no need to handle "infinity" values. + */ + gpr_timespec rv; + rv.tv_sec = ts.tv_sec; + rv.tv_nsec = (int32_t)ts.tv_nsec; + rv.clock_type = clock_type; + return rv; +} + +/** maps gpr_clock_type --> clockid_t for clock_gettime */ +static const clockid_t clockid_for_gpr_clock[] = {CLOCK_MONOTONIC, + CLOCK_REALTIME}; + +void gpr_time_init(void) { gpr_precise_clock_init(); } + +gpr_timespec gpr_now(gpr_clock_type clock_type) { + struct timespec now; + GPR_ASSERT(clock_type != GPR_TIMESPAN); + if (clock_type == GPR_CLOCK_PRECISE) { + gpr_timespec ret; + gpr_precise_clock_now(&ret); + return ret; + } else { +#if defined(GPR_BACKWARDS_COMPATIBILITY_MODE) && defined(__linux__) + /* avoid ABI problems by invoking syscalls directly */ + syscall(SYS_clock_gettime, clockid_for_gpr_clock[clock_type], &now); +#else + clock_gettime(clockid_for_gpr_clock[clock_type], &now); +#endif + return gpr_from_timespec(now, clock_type); + } +} +#else +/* For some reason Apple's OSes haven't implemented clock_gettime. */ + +#include +#include +#include + +static double g_time_scale; +static uint64_t g_time_start; + +void gpr_time_init(void) { + mach_timebase_info_data_t tb = {0, 1}; + gpr_precise_clock_init(); + mach_timebase_info(&tb); + g_time_scale = tb.numer; + g_time_scale /= tb.denom; + g_time_start = mach_absolute_time(); +} + +gpr_timespec gpr_now(gpr_clock_type clock) { + gpr_timespec now; + struct timeval now_tv; + double now_dbl; + + now.clock_type = clock; + switch (clock) { + case GPR_CLOCK_REALTIME: + gettimeofday(&now_tv, NULL); + now.tv_sec = now_tv.tv_sec; + now.tv_nsec = now_tv.tv_usec * 1000; + break; + case GPR_CLOCK_MONOTONIC: + now_dbl = (mach_absolute_time() - g_time_start) * g_time_scale; + now.tv_sec = (int64_t)(now_dbl * 1e-9); + now.tv_nsec = (int32_t)(now_dbl - ((double)now.tv_sec) * 1e9); + break; + case GPR_CLOCK_PRECISE: + gpr_precise_clock_now(&now); + break; + case GPR_TIMESPAN: + abort(); + } + + return now; +} +#endif + +void gpr_sleep_until(gpr_timespec until) { + gpr_timespec now; + gpr_timespec delta; + struct timespec delta_ts; + int ns_result; + + for (;;) { + /* We could simplify by using clock_nanosleep instead, but it might be + * slightly less portable. */ + now = gpr_now(until.clock_type); + if (gpr_time_cmp(until, now) <= 0) { + return; + } + + delta = gpr_time_sub(until, now); + delta_ts = timespec_from_gpr(delta); + GRPC_SCHEDULING_START_BLOCKING_REGION; + ns_result = nanosleep(&delta_ts, NULL); + GRPC_SCHEDULING_END_BLOCKING_REGION; + if (ns_result == 0) { + break; + } + } +} + +#endif /* GPR_POSIX_TIME */ diff --git a/src/core/lib/support/time_precise.c b/src/core/lib/support/time_precise.c new file mode 100644 index 0000000000..a2cf74bc84 --- /dev/null +++ b/src/core/lib/support/time_precise.c @@ -0,0 +1,89 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include + +#ifdef GRPC_TIMERS_RDTSC +#if defined(__i386__) +static void gpr_get_cycle_counter(long long int *clk) { + long long int ret; + __asm__ volatile("rdtsc" : "=A"(ret)); + *clk = ret; +} + +// ---------------------------------------------------------------- +#elif defined(__x86_64__) || defined(__amd64__) +static void gpr_get_cycle_counter(long long int *clk) { + unsigned long long low, high; + __asm__ volatile("rdtsc" : "=a"(low), "=d"(high)); + *clk = (long long)(high << 32) | (long long)low; +} +#endif + +static double cycles_per_second = 0; +static long long int start_cycle; +void gpr_precise_clock_init(void) { + time_t start; + long long end_cycle; + gpr_log(GPR_DEBUG, "Calibrating timers"); + start = time(NULL); + while (time(NULL) == start) + ; + gpr_get_cycle_counter(&start_cycle); + while (time(NULL) <= start + 10) + ; + gpr_get_cycle_counter(&end_cycle); + cycles_per_second = (double)(end_cycle - start_cycle) / 10.0; + gpr_log(GPR_DEBUG, "... cycles_per_second = %f\n", cycles_per_second); +} + +void gpr_precise_clock_now(gpr_timespec *clk) { + long long int counter; + double secs; + gpr_get_cycle_counter(&counter); + secs = (double)(counter - start_cycle) / cycles_per_second; + clk->clock_type = GPR_CLOCK_PRECISE; + clk->tv_sec = (int64_t)secs; + clk->tv_nsec = (int32_t)(1e9 * (secs - (double)clk->tv_sec)); +} + +#else /* GRPC_TIMERS_RDTSC */ +void gpr_precise_clock_init(void) {} + +void gpr_precise_clock_now(gpr_timespec *clk) { + *clk = gpr_now(GPR_CLOCK_REALTIME); + clk->clock_type = GPR_CLOCK_PRECISE; +} +#endif /* GRPC_TIMERS_RDTSC */ diff --git a/src/core/lib/support/time_precise.h b/src/core/lib/support/time_precise.h new file mode 100644 index 0000000000..871c99a623 --- /dev/null +++ b/src/core/lib/support/time_precise.h @@ -0,0 +1,42 @@ +/* + * + * Copyright 2015-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_SUPPORT_TIME_PRECISE_H +#define GRPC_CORE_SUPPORT_TIME_PRECISE_H + +#include + +void gpr_precise_clock_init(void); +void gpr_precise_clock_now(gpr_timespec *clk); + +#endif /* GRPC_CORE_SUPPORT_TIME_PRECISE_H */ diff --git a/src/core/lib/support/time_win32.c b/src/core/lib/support/time_win32.c new file mode 100644 index 0000000000..2c344d3f3b --- /dev/null +++ b/src/core/lib/support/time_win32.c @@ -0,0 +1,110 @@ +/* + * + * Copyright 2015-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. + * + */ + +/* Win32 code for gpr time support. */ + +#include + +#ifdef GPR_WIN32 + +#include +#include +#include +#include +#include +#include + +#include "src/core/support/block_annotate.h" + +static LARGE_INTEGER g_start_time; +static double g_time_scale; + +void gpr_time_init(void) { + LARGE_INTEGER frequency; + QueryPerformanceFrequency(&frequency); + QueryPerformanceCounter(&g_start_time); + g_time_scale = 1.0 / (double)frequency.QuadPart; +} + +gpr_timespec gpr_now(gpr_clock_type clock) { + gpr_timespec now_tv; + LONGLONG diff; + struct _timeb now_tb; + LARGE_INTEGER timestamp; + double now_dbl; + now_tv.clock_type = clock; + switch (clock) { + case GPR_CLOCK_REALTIME: + _ftime_s(&now_tb); + now_tv.tv_sec = (int64_t)now_tb.time; + now_tv.tv_nsec = now_tb.millitm * 1000000; + break; + case GPR_CLOCK_MONOTONIC: + case GPR_CLOCK_PRECISE: + QueryPerformanceCounter(×tamp); + diff = timestamp.QuadPart - g_start_time.QuadPart; + now_dbl = (double)diff * g_time_scale; + now_tv.tv_sec = (int64_t)now_dbl; + now_tv.tv_nsec = (int32_t)((now_dbl - (double)now_tv.tv_sec) * 1e9); + break; + case GPR_TIMESPAN: + abort(); + break; + } + return now_tv; +} + +void gpr_sleep_until(gpr_timespec until) { + gpr_timespec now; + gpr_timespec delta; + int64_t sleep_millis; + + for (;;) { + /* We could simplify by using clock_nanosleep instead, but it might be + * slightly less portable. */ + now = gpr_now(until.clock_type); + if (gpr_time_cmp(until, now) <= 0) { + return; + } + + delta = gpr_time_sub(until, now); + sleep_millis = + delta.tv_sec * GPR_MS_PER_SEC + delta.tv_nsec / GPR_NS_PER_MS; + GPR_ASSERT((sleep_millis >= 0) && (sleep_millis <= INT_MAX)); + GRPC_SCHEDULING_START_BLOCKING_REGION; + Sleep((DWORD)sleep_millis); + GRPC_SCHEDULING_END_BLOCKING_REGION; + } +} + +#endif /* GPR_WIN32 */ diff --git a/src/core/lib/support/tls_pthread.c b/src/core/lib/support/tls_pthread.c new file mode 100644 index 0000000000..9683a6e547 --- /dev/null +++ b/src/core/lib/support/tls_pthread.c @@ -0,0 +1,45 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +#ifdef GPR_PTHREAD_TLS + +#include + +intptr_t gpr_tls_set(struct gpr_pthread_thread_local *tls, intptr_t value) { + GPR_ASSERT(0 == pthread_setspecific(tls->key, (void *)value)); + return value; +} + +#endif /* GPR_PTHREAD_TLS */ diff --git a/src/core/lib/support/tmpfile.h b/src/core/lib/support/tmpfile.h new file mode 100644 index 0000000000..df6f8692bb --- /dev/null +++ b/src/core/lib/support/tmpfile.h @@ -0,0 +1,55 @@ +/* + * + * Copyright 2015-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_SUPPORT_TMPFILE_H +#define GRPC_CORE_SUPPORT_TMPFILE_H + +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Creates a temporary file from a prefix. + If tmp_filename is not NULL, *tmp_filename is assigned the name of the + created file and it is the responsibility of the caller to gpr_free it + unless an error occurs in which case it will be set to NULL. */ +FILE *gpr_tmpfile(const char *prefix, char **tmp_filename); + +#ifdef __cplusplus +} +#endif + +#endif /* GRPC_CORE_SUPPORT_TMPFILE_H */ diff --git a/src/core/lib/support/tmpfile_posix.c b/src/core/lib/support/tmpfile_posix.c new file mode 100644 index 0000000000..b16eeacf9d --- /dev/null +++ b/src/core/lib/support/tmpfile_posix.c @@ -0,0 +1,85 @@ +/* + * + * Copyright 2015-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 + +#ifdef GPR_POSIX_FILE + +#include "src/core/support/tmpfile.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include "src/core/support/string.h" + +FILE *gpr_tmpfile(const char *prefix, char **tmp_filename) { + FILE *result = NULL; + char *template; + int fd; + + if (tmp_filename != NULL) *tmp_filename = NULL; + + gpr_asprintf(&template, "/tmp/%s_XXXXXX", prefix); + GPR_ASSERT(template != NULL); + + fd = mkstemp(template); + if (fd == -1) { + gpr_log(GPR_ERROR, "mkstemp failed for template %s with error %s.", + template, strerror(errno)); + goto end; + } + result = fdopen(fd, "w+"); + if (result == NULL) { + gpr_log(GPR_ERROR, "Could not open file %s from fd %d (error = %s).", + template, fd, strerror(errno)); + unlink(template); + close(fd); + goto end; + } + +end: + if (result != NULL && tmp_filename != NULL) { + *tmp_filename = template; + } else { + gpr_free(template); + } + return result; +} + +#endif /* GPR_POSIX_FILE */ diff --git a/src/core/lib/support/tmpfile_win32.c b/src/core/lib/support/tmpfile_win32.c new file mode 100644 index 0000000000..3000f0029f --- /dev/null +++ b/src/core/lib/support/tmpfile_win32.c @@ -0,0 +1,84 @@ +/* + * + * Copyright 2015-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 + +#ifdef GPR_WIN32 + +#include +#include +#include +#include + +#include +#include +#include + +#include "src/core/support/string_win32.h" +#include "src/core/support/tmpfile.h" + +FILE *gpr_tmpfile(const char *prefix, char **tmp_filename_out) { + FILE *result = NULL; + LPTSTR template_string = NULL; + TCHAR tmp_path[MAX_PATH]; + TCHAR tmp_filename[MAX_PATH]; + DWORD status; + UINT success; + + if (tmp_filename_out != NULL) *tmp_filename_out = NULL; + + /* Convert our prefix to TCHAR. */ + template_string = gpr_char_to_tchar(prefix); + GPR_ASSERT(template_string); + + /* Get the path to the best temporary folder available. */ + status = GetTempPath(MAX_PATH, tmp_path); + if (status == 0 || status > MAX_PATH) goto end; + + /* Generate a unique filename with our template + temporary path. */ + success = GetTempFileName(tmp_path, template_string, 0, tmp_filename); + if (!success) goto end; + + /* Open a file there. */ + if (_tfopen_s(&result, tmp_filename, TEXT("wb+")) != 0) goto end; + +end: + if (result && tmp_filename_out) { + *tmp_filename_out = gpr_tchar_to_char(tmp_filename); + } + + gpr_free(template_string); + return result; +} + +#endif /* GPR_WIN32 */ diff --git a/src/core/lib/support/wrap_memcpy.c b/src/core/lib/support/wrap_memcpy.c new file mode 100644 index 0000000000..15c289f7b8 --- /dev/null +++ b/src/core/lib/support/wrap_memcpy.c @@ -0,0 +1,53 @@ +/* + * + * 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 + +/* Provide a wrapped memcpy for targets that need to be backwards + * compatible with older libc's. + * + * Enable by setting LDFLAGS=-Wl,-wrap,memcpy when linking. + */ + +#ifdef __linux__ +#ifdef __x86_64__ +__asm__(".symver memcpy,memcpy@GLIBC_2.2.5"); +void *__wrap_memcpy(void *destination, const void *source, size_t num) { + return memcpy(destination, source, num); +} +#else /* !__x86_64__ */ +void *__wrap_memcpy(void *destination, const void *source, size_t num) { + return memmove(destination, source, num); +} +#endif +#endif diff --git a/src/core/lib/surface/alarm.c b/src/core/lib/surface/alarm.c new file mode 100644 index 0000000000..1085285f95 --- /dev/null +++ b/src/core/lib/surface/alarm.c @@ -0,0 +1,84 @@ +/* + * + * Copyright 2015-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 +#include +#include "src/core/iomgr/timer.h" +#include "src/core/surface/completion_queue.h" + +struct grpc_alarm { + grpc_timer alarm; + grpc_cq_completion completion; + /** completion queue where events about this alarm will be posted */ + grpc_completion_queue *cq; + /** user supplied tag */ + void *tag; +}; + +static void do_nothing_end_completion(grpc_exec_ctx *exec_ctx, void *arg, + grpc_cq_completion *c) {} + +static void alarm_cb(grpc_exec_ctx *exec_ctx, void *arg, bool success) { + grpc_alarm *alarm = arg; + grpc_cq_end_op(exec_ctx, alarm->cq, alarm->tag, success, + do_nothing_end_completion, NULL, &alarm->completion); +} + +grpc_alarm *grpc_alarm_create(grpc_completion_queue *cq, gpr_timespec deadline, + void *tag) { + grpc_alarm *alarm = gpr_malloc(sizeof(grpc_alarm)); + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + + GRPC_CQ_INTERNAL_REF(cq, "alarm"); + alarm->cq = cq; + alarm->tag = tag; + + grpc_cq_begin_op(cq, tag); + grpc_timer_init(&exec_ctx, &alarm->alarm, + gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC), + alarm_cb, alarm, gpr_now(GPR_CLOCK_MONOTONIC)); + grpc_exec_ctx_finish(&exec_ctx); + return alarm; +} + +void grpc_alarm_cancel(grpc_alarm *alarm) { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_timer_cancel(&exec_ctx, &alarm->alarm); + grpc_exec_ctx_finish(&exec_ctx); +} + +void grpc_alarm_destroy(grpc_alarm *alarm) { + grpc_alarm_cancel(alarm); + GRPC_CQ_INTERNAL_UNREF(alarm->cq, "alarm"); + gpr_free(alarm); +} diff --git a/src/core/lib/surface/api_trace.c b/src/core/lib/surface/api_trace.c new file mode 100644 index 0000000000..9f0b900d46 --- /dev/null +++ b/src/core/lib/surface/api_trace.c @@ -0,0 +1,36 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (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/api_trace.h" + +int grpc_api_trace = 0; diff --git a/src/core/lib/surface/api_trace.h b/src/core/lib/surface/api_trace.h new file mode 100644 index 0000000000..af53829de4 --- /dev/null +++ b/src/core/lib/surface/api_trace.h @@ -0,0 +1,65 @@ +/* + * + * Copyright 2015-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_SURFACE_API_TRACE_H +#define GRPC_CORE_SURFACE_API_TRACE_H + +#include +#include "src/core/debug/trace.h" + +extern int grpc_api_trace; + +/* Provide unwrapping macros because we're in C89 and variadic macros weren't + introduced until C99... */ +#define GRPC_API_TRACE_UNWRAP0() +#define GRPC_API_TRACE_UNWRAP1(a) , a +#define GRPC_API_TRACE_UNWRAP2(a, b) , a, b +#define GRPC_API_TRACE_UNWRAP3(a, b, c) , a, b, c +#define GRPC_API_TRACE_UNWRAP4(a, b, c, d) , a, b, c, d +#define GRPC_API_TRACE_UNWRAP5(a, b, c, d, e) , a, b, c, d, e +#define GRPC_API_TRACE_UNWRAP6(a, b, c, d, e, f) , a, b, c, d, e, f +#define GRPC_API_TRACE_UNWRAP7(a, b, c, d, e, f, g) , a, b, c, d, e, f, g +#define GRPC_API_TRACE_UNWRAP8(a, b, c, d, e, f, g, h) , a, b, c, d, e, f, g, h +#define GRPC_API_TRACE_UNWRAP9(a, b, c, d, e, f, g, h, i) \ + , a, b, c, d, e, f, g, h, i +#define GRPC_API_TRACE_UNWRAP10(a, b, c, d, e, f, g, h, i, j) \ + , a, b, c, d, e, f, g, h, i, j + +/* Due to the limitations of C89's preprocessor, the arity of the var-arg list + 'nargs' must be specified. */ +#define GRPC_API_TRACE(fmt, nargs, args) \ + if (grpc_api_trace) { \ + gpr_log(GPR_INFO, fmt GRPC_API_TRACE_UNWRAP##nargs args); \ + } + +#endif /* GRPC_CORE_SURFACE_API_TRACE_H */ diff --git a/src/core/lib/surface/byte_buffer.c b/src/core/lib/surface/byte_buffer.c new file mode 100644 index 0000000000..fb39c4531d --- /dev/null +++ b/src/core/lib/surface/byte_buffer.c @@ -0,0 +1,97 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include + +grpc_byte_buffer *grpc_raw_byte_buffer_create(gpr_slice *slices, + size_t nslices) { + return grpc_raw_compressed_byte_buffer_create(slices, nslices, + GRPC_COMPRESS_NONE); +} + +grpc_byte_buffer *grpc_raw_compressed_byte_buffer_create( + gpr_slice *slices, size_t nslices, grpc_compression_algorithm compression) { + size_t i; + grpc_byte_buffer *bb = malloc(sizeof(grpc_byte_buffer)); + bb->type = GRPC_BB_RAW; + bb->data.raw.compression = compression; + gpr_slice_buffer_init(&bb->data.raw.slice_buffer); + for (i = 0; i < nslices; i++) { + gpr_slice_ref(slices[i]); + gpr_slice_buffer_add(&bb->data.raw.slice_buffer, slices[i]); + } + return bb; +} + +grpc_byte_buffer *grpc_raw_byte_buffer_from_reader( + grpc_byte_buffer_reader *reader) { + grpc_byte_buffer *bb = malloc(sizeof(grpc_byte_buffer)); + gpr_slice slice; + bb->type = GRPC_BB_RAW; + bb->data.raw.compression = GRPC_COMPRESS_NONE; + gpr_slice_buffer_init(&bb->data.raw.slice_buffer); + + while (grpc_byte_buffer_reader_next(reader, &slice)) { + gpr_slice_buffer_add(&bb->data.raw.slice_buffer, slice); + } + return bb; +} + +grpc_byte_buffer *grpc_byte_buffer_copy(grpc_byte_buffer *bb) { + switch (bb->type) { + case GRPC_BB_RAW: + return grpc_raw_byte_buffer_create(bb->data.raw.slice_buffer.slices, + bb->data.raw.slice_buffer.count); + } + GPR_UNREACHABLE_CODE(return NULL); +} + +void grpc_byte_buffer_destroy(grpc_byte_buffer *bb) { + if (!bb) return; + switch (bb->type) { + case GRPC_BB_RAW: + gpr_slice_buffer_destroy(&bb->data.raw.slice_buffer); + break; + } + free(bb); +} + +size_t grpc_byte_buffer_length(grpc_byte_buffer *bb) { + switch (bb->type) { + case GRPC_BB_RAW: + return bb->data.raw.slice_buffer.length; + } + GPR_UNREACHABLE_CODE(return 0); +} diff --git a/src/core/lib/surface/byte_buffer_reader.c b/src/core/lib/surface/byte_buffer_reader.c new file mode 100644 index 0000000000..4a418faaed --- /dev/null +++ b/src/core/lib/surface/byte_buffer_reader.c @@ -0,0 +1,123 @@ +/* + * + * Copyright 2015-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 +#include + +#include +#include +#include +#include +#include +#include + +#include "src/core/compression/message_compress.h" + +static int is_compressed(grpc_byte_buffer *buffer) { + switch (buffer->type) { + case GRPC_BB_RAW: + if (buffer->data.raw.compression == GRPC_COMPRESS_NONE) { + return 0 /* GPR_FALSE */; + } + break; + } + return 1 /* GPR_TRUE */; +} + +void grpc_byte_buffer_reader_init(grpc_byte_buffer_reader *reader, + grpc_byte_buffer *buffer) { + gpr_slice_buffer decompressed_slices_buffer; + reader->buffer_in = buffer; + switch (reader->buffer_in->type) { + case GRPC_BB_RAW: + gpr_slice_buffer_init(&decompressed_slices_buffer); + if (is_compressed(reader->buffer_in)) { + grpc_msg_decompress(reader->buffer_in->data.raw.compression, + &reader->buffer_in->data.raw.slice_buffer, + &decompressed_slices_buffer); + reader->buffer_out = + grpc_raw_byte_buffer_create(decompressed_slices_buffer.slices, + decompressed_slices_buffer.count); + gpr_slice_buffer_destroy(&decompressed_slices_buffer); + } else { /* not compressed, use the input buffer as output */ + reader->buffer_out = reader->buffer_in; + } + reader->current.index = 0; + break; + } +} + +void grpc_byte_buffer_reader_destroy(grpc_byte_buffer_reader *reader) { + switch (reader->buffer_in->type) { + case GRPC_BB_RAW: + /* keeping the same if-else structure as in the init function */ + if (is_compressed(reader->buffer_in)) { + grpc_byte_buffer_destroy(reader->buffer_out); + } + break; + } +} + +int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader *reader, + gpr_slice *slice) { + switch (reader->buffer_in->type) { + case GRPC_BB_RAW: { + gpr_slice_buffer *slice_buffer; + slice_buffer = &reader->buffer_out->data.raw.slice_buffer; + if (reader->current.index < slice_buffer->count) { + *slice = gpr_slice_ref(slice_buffer->slices[reader->current.index]); + reader->current.index += 1; + return 1; + } + break; + } + } + return 0; +} + +gpr_slice grpc_byte_buffer_reader_readall(grpc_byte_buffer_reader *reader) { + gpr_slice in_slice; + size_t bytes_read = 0; + const size_t input_size = grpc_byte_buffer_length(reader->buffer_out); + gpr_slice out_slice = gpr_slice_malloc(input_size); + uint8_t *const outbuf = GPR_SLICE_START_PTR(out_slice); /* just an alias */ + + while (grpc_byte_buffer_reader_next(reader, &in_slice) != 0) { + const size_t slice_length = GPR_SLICE_LENGTH(in_slice); + memcpy(&(outbuf[bytes_read]), GPR_SLICE_START_PTR(in_slice), slice_length); + bytes_read += slice_length; + gpr_slice_unref(in_slice); + GPR_ASSERT(bytes_read <= input_size); + } + return out_slice; +} diff --git a/src/core/lib/surface/call.c b/src/core/lib/surface/call.c new file mode 100644 index 0000000000..6f1cd1df10 --- /dev/null +++ b/src/core/lib/surface/call.c @@ -0,0 +1,1491 @@ +/* + * + * Copyright 2015-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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "src/core/channel/channel_stack.h" +#include "src/core/compression/algorithm_metadata.h" +#include "src/core/iomgr/timer.h" +#include "src/core/profiling/timers.h" +#include "src/core/support/string.h" +#include "src/core/surface/api_trace.h" +#include "src/core/surface/call.h" +#include "src/core/surface/channel.h" +#include "src/core/surface/completion_queue.h" +#include "src/core/transport/static_metadata.h" + +/** The maximum number of concurrent batches possible. + Based upon the maximum number of individually queueable ops in the batch + api: + - initial metadata send + - message send + - status/close send (depending on client/server) + - initial metadata recv + - message recv + - status/close recv (depending on client/server) */ +#define MAX_CONCURRENT_BATCHES 6 + +typedef struct { + grpc_ioreq_completion_func on_complete; + void *user_data; + int success; +} completed_request; + +#define MAX_SEND_EXTRA_METADATA_COUNT 3 + +/* Status data for a request can come from several sources; this + enumerates them all, and acts as a priority sorting for which + status to return to the application - earlier entries override + later ones */ +typedef enum { + /* Status came from the application layer overriding whatever + the wire says */ + STATUS_FROM_API_OVERRIDE = 0, + /* Status was created by some internal channel stack operation */ + STATUS_FROM_CORE, + /* Status came from 'the wire' - or somewhere below the surface + layer */ + STATUS_FROM_WIRE, + /* Status came from the server sending status */ + STATUS_FROM_SERVER_STATUS, + STATUS_SOURCE_COUNT +} status_source; + +typedef struct { + uint8_t is_set; + grpc_status_code code; + grpc_mdstr *details; +} received_status; + +/* How far through the GRPC stream have we read? */ +typedef enum { + /* We are still waiting for initial metadata to complete */ + READ_STATE_INITIAL = 0, + /* We have gotten initial metadata, and are reading either + messages or trailing metadata */ + READ_STATE_GOT_INITIAL_METADATA, + /* The stream is closed for reading */ + READ_STATE_READ_CLOSED, + /* The stream is closed for reading & writing */ + READ_STATE_STREAM_CLOSED +} read_state; + +typedef enum { + WRITE_STATE_INITIAL = 0, + WRITE_STATE_STARTED, + WRITE_STATE_WRITE_CLOSED +} write_state; + +typedef struct batch_control { + grpc_call *call; + grpc_cq_completion cq_completion; + grpc_closure finish_batch; + void *notify_tag; + gpr_refcount steps_to_complete; + + uint8_t send_initial_metadata; + uint8_t send_message; + uint8_t send_final_op; + uint8_t recv_initial_metadata; + uint8_t recv_message; + uint8_t recv_final_op; + uint8_t is_notify_tag_closure; + uint8_t success; +} batch_control; + +struct grpc_call { + grpc_completion_queue *cq; + grpc_channel *channel; + grpc_call *parent; + grpc_call *first_child; + /* TODO(ctiller): share with cq if possible? */ + gpr_mu mu; + + /* client or server call */ + uint8_t is_client; + /* is the alarm set */ + uint8_t have_alarm; + /** has grpc_call_destroy been called */ + uint8_t destroy_called; + /** flag indicating that cancellation is inherited */ + uint8_t cancellation_is_inherited; + /** bitmask of live batches */ + uint8_t used_batches; + /** which ops are in-flight */ + uint8_t sent_initial_metadata; + uint8_t sending_message; + uint8_t sent_final_op; + uint8_t received_initial_metadata; + uint8_t receiving_message; + uint8_t received_final_op; + + /* have we received initial metadata */ + bool has_initial_md_been_received; + + batch_control active_batches[MAX_CONCURRENT_BATCHES]; + + /* first idx: is_receiving, second idx: is_trailing */ + grpc_metadata_batch metadata_batch[2][2]; + + /* Buffered read metadata waiting to be returned to the application. + Element 0 is initial metadata, element 1 is trailing metadata. */ + grpc_metadata_array *buffered_metadata[2]; + + /* Received call statuses from various sources */ + received_status status[STATUS_SOURCE_COUNT]; + + /* Compression algorithm for the call */ + grpc_compression_algorithm compression_algorithm; + /* Supported encodings (compression algorithms), a bitset */ + uint32_t encodings_accepted_by_peer; + + /* Contexts for various subsystems (security, tracing, ...). */ + grpc_call_context_element context[GRPC_CONTEXT_COUNT]; + + /* Deadline alarm - if have_alarm is non-zero */ + grpc_timer alarm; + + /* for the client, extra metadata is initial metadata; for the + server, it's trailing metadata */ + grpc_linked_mdelem send_extra_metadata[MAX_SEND_EXTRA_METADATA_COUNT]; + int send_extra_metadata_count; + gpr_timespec send_deadline; + + /** siblings: children of the same parent form a list, and this list is + protected under + parent->mu */ + grpc_call *sibling_next; + grpc_call *sibling_prev; + + grpc_slice_buffer_stream sending_stream; + grpc_byte_stream *receiving_stream; + grpc_byte_buffer **receiving_buffer; + gpr_slice receiving_slice; + grpc_closure receiving_slice_ready; + grpc_closure receiving_stream_ready; + grpc_closure receiving_initial_metadata_ready; + uint32_t test_only_last_message_flags; + + union { + struct { + grpc_status_code *status; + char **status_details; + size_t *status_details_capacity; + } client; + struct { + int *cancelled; + } server; + } final_op; + + struct { + void *bctlp; + bool success; + } saved_receiving_stream_ready_ctx; +}; + +#define CALL_STACK_FROM_CALL(call) ((grpc_call_stack *)((call) + 1)) +#define CALL_FROM_CALL_STACK(call_stack) (((grpc_call *)(call_stack)) - 1) +#define CALL_ELEM_FROM_CALL(call, idx) \ + grpc_call_stack_element(CALL_STACK_FROM_CALL(call), idx) +#define CALL_FROM_TOP_ELEM(top_elem) \ + CALL_FROM_CALL_STACK(grpc_call_stack_from_top_element(top_elem)) + +static void set_deadline_alarm(grpc_exec_ctx *exec_ctx, grpc_call *call, + gpr_timespec deadline); +static void execute_op(grpc_exec_ctx *exec_ctx, grpc_call *call, + grpc_transport_stream_op *op); +static grpc_call_error cancel_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, + bool success); + +grpc_call *grpc_call_create(grpc_channel *channel, grpc_call *parent_call, + uint32_t propagation_mask, + grpc_completion_queue *cq, + const void *server_transport_data, + grpc_mdelem **add_initial_metadata, + size_t add_initial_metadata_count, + gpr_timespec send_deadline) { + size_t i, j; + grpc_channel_stack *channel_stack = grpc_channel_get_channel_stack(channel); + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_call *call; + GPR_TIMER_BEGIN("grpc_call_create", 0); + call = gpr_malloc(sizeof(grpc_call) + channel_stack->call_stack_size); + memset(call, 0, sizeof(grpc_call)); + gpr_mu_init(&call->mu); + call->channel = channel; + call->cq = cq; + call->parent = parent_call; + call->is_client = server_transport_data == NULL; + if (call->is_client) { + GPR_ASSERT(add_initial_metadata_count < MAX_SEND_EXTRA_METADATA_COUNT); + for (i = 0; i < add_initial_metadata_count; i++) { + call->send_extra_metadata[i].md = add_initial_metadata[i]; + } + call->send_extra_metadata_count = (int)add_initial_metadata_count; + } else { + GPR_ASSERT(add_initial_metadata_count == 0); + call->send_extra_metadata_count = 0; + } + for (i = 0; i < 2; i++) { + for (j = 0; j < 2; j++) { + call->metadata_batch[i][j].deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC); + } + } + call->send_deadline = send_deadline; + GRPC_CHANNEL_INTERNAL_REF(channel, "call"); + /* initial refcount dropped by grpc_call_destroy */ + grpc_call_stack_init(&exec_ctx, channel_stack, 1, destroy_call, call, + call->context, server_transport_data, + CALL_STACK_FROM_CALL(call)); + if (cq != NULL) { + GRPC_CQ_INTERNAL_REF(cq, "bind"); + grpc_call_stack_set_pollset(&exec_ctx, CALL_STACK_FROM_CALL(call), + grpc_cq_pollset(cq)); + } + if (parent_call != NULL) { + GRPC_CALL_INTERNAL_REF(parent_call, "child"); + GPR_ASSERT(call->is_client); + GPR_ASSERT(!parent_call->is_client); + + gpr_mu_lock(&parent_call->mu); + + if (propagation_mask & GRPC_PROPAGATE_DEADLINE) { + send_deadline = gpr_time_min( + gpr_convert_clock_type(send_deadline, + parent_call->send_deadline.clock_type), + parent_call->send_deadline); + } + /* for now GRPC_PROPAGATE_TRACING_CONTEXT *MUST* be passed with + * GRPC_PROPAGATE_STATS_CONTEXT */ + /* TODO(ctiller): This should change to use the appropriate census start_op + * call. */ + if (propagation_mask & GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT) { + GPR_ASSERT(propagation_mask & GRPC_PROPAGATE_CENSUS_STATS_CONTEXT); + grpc_call_context_set(call, GRPC_CONTEXT_TRACING, + parent_call->context[GRPC_CONTEXT_TRACING].value, + NULL); + } else { + GPR_ASSERT(propagation_mask & GRPC_PROPAGATE_CENSUS_STATS_CONTEXT); + } + if (propagation_mask & GRPC_PROPAGATE_CANCELLATION) { + call->cancellation_is_inherited = 1; + } + + if (parent_call->first_child == NULL) { + parent_call->first_child = call; + call->sibling_next = call->sibling_prev = call; + } else { + call->sibling_next = parent_call->first_child; + call->sibling_prev = parent_call->first_child->sibling_prev; + call->sibling_next->sibling_prev = call->sibling_prev->sibling_next = + call; + } + + gpr_mu_unlock(&parent_call->mu); + } + if (gpr_time_cmp(send_deadline, gpr_inf_future(send_deadline.clock_type)) != + 0) { + set_deadline_alarm(&exec_ctx, call, send_deadline); + } + grpc_exec_ctx_finish(&exec_ctx); + GPR_TIMER_END("grpc_call_create", 0); + return call; +} + +void grpc_call_set_completion_queue(grpc_exec_ctx *exec_ctx, grpc_call *call, + grpc_completion_queue *cq) { + GPR_ASSERT(cq); + call->cq = cq; + GRPC_CQ_INTERNAL_REF(cq, "bind"); + grpc_call_stack_set_pollset(exec_ctx, CALL_STACK_FROM_CALL(call), + grpc_cq_pollset(cq)); +} + +#ifdef GRPC_STREAM_REFCOUNT_DEBUG +#define REF_REASON reason +#define REF_ARG , const char *reason +#else +#define REF_REASON "" +#define REF_ARG +#endif +void grpc_call_internal_ref(grpc_call *c REF_ARG) { + GRPC_CALL_STACK_REF(CALL_STACK_FROM_CALL(c), REF_REASON); +} +void grpc_call_internal_unref(grpc_exec_ctx *exec_ctx, grpc_call *c REF_ARG) { + GRPC_CALL_STACK_UNREF(exec_ctx, CALL_STACK_FROM_CALL(c), REF_REASON); +} + +static void destroy_call(grpc_exec_ctx *exec_ctx, void *call, bool success) { + size_t i; + int ii; + grpc_call *c = call; + GPR_TIMER_BEGIN("destroy_call", 0); + for (i = 0; i < 2; i++) { + grpc_metadata_batch_destroy( + &c->metadata_batch[1 /* is_receiving */][i /* is_initial */]); + } + if (c->receiving_stream != NULL) { + grpc_byte_stream_destroy(exec_ctx, c->receiving_stream); + } + grpc_call_stack_destroy(exec_ctx, CALL_STACK_FROM_CALL(c)); + GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, c->channel, "call"); + gpr_mu_destroy(&c->mu); + for (i = 0; i < STATUS_SOURCE_COUNT; i++) { + if (c->status[i].details) { + GRPC_MDSTR_UNREF(c->status[i].details); + } + } + for (ii = 0; ii < c->send_extra_metadata_count; ii++) { + GRPC_MDELEM_UNREF(c->send_extra_metadata[ii].md); + } + for (i = 0; i < GRPC_CONTEXT_COUNT; i++) { + if (c->context[i].destroy) { + c->context[i].destroy(c->context[i].value); + } + } + if (c->cq) { + GRPC_CQ_INTERNAL_UNREF(c->cq, "bind"); + } + gpr_free(c); + GPR_TIMER_END("destroy_call", 0); +} + +static void set_status_code(grpc_call *call, status_source source, + uint32_t status) { + if (call->status[source].is_set) return; + + call->status[source].is_set = 1; + call->status[source].code = (grpc_status_code)status; + + /* TODO(ctiller): what to do about the flush that was previously here */ +} + +static void set_compression_algorithm(grpc_call *call, + grpc_compression_algorithm algo) { + call->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; + gpr_mu_unlock(&call->mu); + return algorithm; +} + +uint32_t grpc_call_test_only_get_message_flags(grpc_call *call) { + uint32_t flags; + gpr_mu_lock(&call->mu); + flags = call->test_only_last_message_flags; + gpr_mu_unlock(&call->mu); + return flags; +} + +static void destroy_encodings_accepted_by_peer(void *p) { return; } + +static void set_encodings_accepted_by_peer(grpc_call *call, grpc_mdelem *mdel) { + size_t i; + grpc_compression_algorithm algorithm; + gpr_slice_buffer accept_encoding_parts; + gpr_slice accept_encoding_slice; + void *accepted_user_data; + + accepted_user_data = + grpc_mdelem_get_user_data(mdel, destroy_encodings_accepted_by_peer); + if (accepted_user_data != NULL) { + call->encodings_accepted_by_peer = + (uint32_t)(((uintptr_t)accepted_user_data) - 1); + return; + } + + accept_encoding_slice = mdel->value->slice; + gpr_slice_buffer_init(&accept_encoding_parts); + gpr_slice_split(accept_encoding_slice, ",", &accept_encoding_parts); + + /* No need to zero call->encodings_accepted_by_peer: grpc_call_create already + * zeroes the whole grpc_call */ + /* Always support no compression */ + GPR_BITSET(&call->encodings_accepted_by_peer, GRPC_COMPRESS_NONE); + for (i = 0; i < accept_encoding_parts.count; i++) { + const gpr_slice *accept_encoding_entry_slice = + &accept_encoding_parts.slices[i]; + if (grpc_compression_algorithm_parse( + (const char *)GPR_SLICE_START_PTR(*accept_encoding_entry_slice), + GPR_SLICE_LENGTH(*accept_encoding_entry_slice), &algorithm)) { + GPR_BITSET(&call->encodings_accepted_by_peer, algorithm); + } else { + char *accept_encoding_entry_str = + gpr_dump_slice(*accept_encoding_entry_slice, GPR_DUMP_ASCII); + gpr_log(GPR_ERROR, + "Invalid entry in accept encoding metadata: '%s'. Ignoring.", + accept_encoding_entry_str); + gpr_free(accept_encoding_entry_str); + } + } + + gpr_slice_buffer_destroy(&accept_encoding_parts); + + grpc_mdelem_set_user_data( + mdel, destroy_encodings_accepted_by_peer, + (void *)(((uintptr_t)call->encodings_accepted_by_peer) + 1)); +} + +uint32_t grpc_call_test_only_get_encodings_accepted_by_peer(grpc_call *call) { + uint32_t encodings_accepted_by_peer; + gpr_mu_lock(&call->mu); + encodings_accepted_by_peer = call->encodings_accepted_by_peer; + gpr_mu_unlock(&call->mu); + return encodings_accepted_by_peer; +} + +static void set_status_details(grpc_call *call, status_source source, + grpc_mdstr *status) { + if (call->status[source].details != NULL) { + GRPC_MDSTR_UNREF(call->status[source].details); + } + call->status[source].details = status; +} + +static void get_final_status(grpc_call *call, + void (*set_value)(grpc_status_code code, + void *user_data), + void *set_value_user_data) { + int i; + for (i = 0; i < STATUS_SOURCE_COUNT; i++) { + if (call->status[i].is_set) { + set_value(call->status[i].code, set_value_user_data); + return; + } + } + if (call->is_client) { + set_value(GRPC_STATUS_UNKNOWN, set_value_user_data); + } else { + set_value(GRPC_STATUS_OK, set_value_user_data); + } +} + +static void get_final_details(grpc_call *call, char **out_details, + size_t *out_details_capacity) { + int i; + for (i = 0; i < STATUS_SOURCE_COUNT; i++) { + if (call->status[i].is_set) { + if (call->status[i].details) { + gpr_slice details = call->status[i].details->slice; + size_t len = GPR_SLICE_LENGTH(details); + if (len + 1 > *out_details_capacity) { + *out_details_capacity = + GPR_MAX(len + 1, *out_details_capacity * 3 / 2); + *out_details = gpr_realloc(*out_details, *out_details_capacity); + } + memcpy(*out_details, GPR_SLICE_START_PTR(details), len); + (*out_details)[len] = 0; + } else { + goto no_details; + } + return; + } + } + +no_details: + if (0 == *out_details_capacity) { + *out_details_capacity = 8; + *out_details = gpr_malloc(*out_details_capacity); + } + **out_details = 0; +} + +static grpc_linked_mdelem *linked_from_md(grpc_metadata *md) { + return (grpc_linked_mdelem *)&md->internal_data; +} + +static int prepare_application_metadata(grpc_call *call, int count, + grpc_metadata *metadata, + int is_trailing, + int prepend_extra_metadata) { + int i; + grpc_metadata_batch *batch = + &call->metadata_batch[0 /* is_receiving */][is_trailing]; + if (prepend_extra_metadata) { + if (call->send_extra_metadata_count == 0) { + prepend_extra_metadata = 0; + } else { + for (i = 0; i < call->send_extra_metadata_count; i++) { + GRPC_MDELEM_REF(call->send_extra_metadata[i].md); + } + for (i = 1; i < call->send_extra_metadata_count; i++) { + call->send_extra_metadata[i].prev = &call->send_extra_metadata[i - 1]; + } + for (i = 0; i < call->send_extra_metadata_count - 1; i++) { + call->send_extra_metadata[i].next = &call->send_extra_metadata[i + 1]; + } + } + } + for (i = 0; i < count; i++) { + grpc_metadata *md = &metadata[i]; + 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( + md->key, (const uint8_t *)md->value, md->value_length); + if (!grpc_header_key_is_legal(grpc_mdstr_as_c_string(l->md->key), + GRPC_MDSTR_LENGTH(l->md->key))) { + gpr_log(GPR_ERROR, "attempt to send invalid metadata key: %s", + grpc_mdstr_as_c_string(l->md->key)); + return 0; + } else if (!grpc_is_binary_header(grpc_mdstr_as_c_string(l->md->key), + GRPC_MDSTR_LENGTH(l->md->key)) && + !grpc_header_nonbin_value_is_legal( + grpc_mdstr_as_c_string(l->md->value), + GRPC_MDSTR_LENGTH(l->md->value))) { + gpr_log(GPR_ERROR, "attempt to send invalid metadata value"); + return 0; + } + } + for (i = 1; i < count; i++) { + linked_from_md(&metadata[i])->prev = linked_from_md(&metadata[i - 1]); + } + for (i = 0; i < count - 1; i++) { + linked_from_md(&metadata[i])->next = linked_from_md(&metadata[i + 1]); + } + switch (prepend_extra_metadata * 2 + (count != 0)) { + case 0: + /* no prepend, no metadata => nothing to do */ + batch->list.head = batch->list.tail = NULL; + break; + case 1: + /* metadata, but no prepend */ + batch->list.head = linked_from_md(&metadata[0]); + batch->list.tail = linked_from_md(&metadata[count - 1]); + 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]; + batch->list.tail = + &call->send_extra_metadata[call->send_extra_metadata_count - 1]; + batch->list.head->prev = NULL; + batch->list.tail->next = NULL; + break; + case 3: + /* prepend AND md */ + 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 = + &call->send_extra_metadata[call->send_extra_metadata_count - 1]; + batch->list.tail = linked_from_md(&metadata[count - 1]); + batch->list.head->prev = NULL; + batch->list.tail->next = NULL; + break; + default: + GPR_UNREACHABLE_CODE(return 0); + } + + return 1; +} + +void grpc_call_destroy(grpc_call *c) { + int cancel; + grpc_call *parent = c->parent; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + + GPR_TIMER_BEGIN("grpc_call_destroy", 0); + GRPC_API_TRACE("grpc_call_destroy(c=%p)", 1, (c)); + + if (parent) { + gpr_mu_lock(&parent->mu); + if (c == parent->first_child) { + parent->first_child = c->sibling_next; + if (c == parent->first_child) { + parent->first_child = NULL; + } + c->sibling_prev->sibling_next = c->sibling_next; + c->sibling_next->sibling_prev = c->sibling_prev; + } + gpr_mu_unlock(&parent->mu); + GRPC_CALL_INTERNAL_UNREF(&exec_ctx, parent, "child"); + } + + gpr_mu_lock(&c->mu); + GPR_ASSERT(!c->destroy_called); + c->destroy_called = 1; + if (c->have_alarm) { + grpc_timer_cancel(&exec_ctx, &c->alarm); + } + cancel = !c->received_final_op; + gpr_mu_unlock(&c->mu); + if (cancel) grpc_call_cancel(c, NULL); + GRPC_CALL_INTERNAL_UNREF(&exec_ctx, c, "destroy"); + grpc_exec_ctx_finish(&exec_ctx); + GPR_TIMER_END("grpc_call_destroy", 0); +} + +grpc_call_error grpc_call_cancel(grpc_call *call, void *reserved) { + GRPC_API_TRACE("grpc_call_cancel(call=%p, reserved=%p)", 2, (call, reserved)); + GPR_ASSERT(!reserved); + return grpc_call_cancel_with_status(call, GRPC_STATUS_CANCELLED, "Cancelled", + NULL); +} + +grpc_call_error grpc_call_cancel_with_status(grpc_call *c, + grpc_status_code status, + const char *description, + void *reserved) { + grpc_call_error r; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + GRPC_API_TRACE( + "grpc_call_cancel_with_status(" + "c=%p, status=%d, description=%s, reserved=%p)", + 4, (c, (int)status, description, reserved)); + GPR_ASSERT(reserved == NULL); + gpr_mu_lock(&c->mu); + r = cancel_with_status(&exec_ctx, c, status, description); + gpr_mu_unlock(&c->mu); + grpc_exec_ctx_finish(&exec_ctx); + return r; +} + +typedef struct cancel_closure { + grpc_closure closure; + grpc_call *call; + grpc_status_code status; +} cancel_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 send_cancel(grpc_exec_ctx *exec_ctx, void *ccp, bool success) { + grpc_transport_stream_op op; + cancel_closure *cc = ccp; + memset(&op, 0, sizeof(op)); + op.cancel_with_status = cc->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); +} + +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)); + + GPR_ASSERT(status != GRPC_STATUS_OK); + + set_status_code(c, STATUS_FROM_API_OVERRIDE, (uint32_t)status); + set_status_details(c, STATUS_FROM_API_OVERRIDE, details); + + 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); + + return GRPC_CALL_OK; +} + +static void execute_op(grpc_exec_ctx *exec_ctx, grpc_call *call, + grpc_transport_stream_op *op) { + grpc_call_element *elem; + + GPR_TIMER_BEGIN("execute_op", 0); + elem = CALL_ELEM_FROM_CALL(call, 0); + op->context = call->context; + elem->filter->start_transport_stream_op(exec_ctx, elem, op); + GPR_TIMER_END("execute_op", 0); +} + +char *grpc_call_get_peer(grpc_call *call) { + grpc_call_element *elem = CALL_ELEM_FROM_CALL(call, 0); + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + char *result; + GRPC_API_TRACE("grpc_call_get_peer(%p)", 1, (call)); + result = elem->filter->get_peer(&exec_ctx, elem); + if (result == NULL) { + result = grpc_channel_get_target(call->channel); + } + if (result == NULL) { + result = gpr_strdup("unknown"); + } + grpc_exec_ctx_finish(&exec_ctx); + return result; +} + +grpc_call *grpc_call_from_top_element(grpc_call_element *elem) { + return CALL_FROM_TOP_ELEM(elem); +} + +static void call_alarm(grpc_exec_ctx *exec_ctx, void *arg, bool success) { + grpc_call *call = arg; + gpr_mu_lock(&call->mu); + call->have_alarm = 0; + if (success) { + cancel_with_status(exec_ctx, call, GRPC_STATUS_DEADLINE_EXCEEDED, + "Deadline Exceeded"); + } + gpr_mu_unlock(&call->mu); + GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, "alarm"); +} + +static void set_deadline_alarm(grpc_exec_ctx *exec_ctx, grpc_call *call, + gpr_timespec deadline) { + if (call->have_alarm) { + gpr_log(GPR_ERROR, "Attempt to set deadline alarm twice"); + assert(0); + return; + } + GRPC_CALL_INTERNAL_REF(call, "alarm"); + call->have_alarm = 1; + call->send_deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC); + grpc_timer_init(exec_ctx, &call->alarm, call->send_deadline, call_alarm, call, + gpr_now(GPR_CLOCK_MONOTONIC)); +} + +/* we offset status by a small amount when storing it into transport metadata + as metadata cannot store a 0 value (which is used as OK for grpc_status_codes + */ +#define STATUS_OFFSET 1 +static void destroy_status(void *ignored) {} + +static uint32_t decode_status(grpc_mdelem *md) { + uint32_t status; + void *user_data; + if (md == GRPC_MDELEM_GRPC_STATUS_0) return 0; + if (md == GRPC_MDELEM_GRPC_STATUS_1) return 1; + if (md == GRPC_MDELEM_GRPC_STATUS_2) return 2; + user_data = grpc_mdelem_get_user_data(md, destroy_status); + if (user_data != NULL) { + status = ((uint32_t)(intptr_t)user_data) - STATUS_OFFSET; + } else { + if (!gpr_parse_bytes_to_uint32(grpc_mdstr_as_c_string(md->value), + GPR_SLICE_LENGTH(md->value->slice), + &status)) { + status = GRPC_STATUS_UNKNOWN; /* could not parse status code */ + } + grpc_mdelem_set_user_data(md, destroy_status, + (void *)(intptr_t)(status + STATUS_OFFSET)); + } + return status; +} + +static uint32_t decode_compression(grpc_mdelem *md) { + grpc_compression_algorithm algorithm = + grpc_compression_algorithm_from_mdstr(md->value); + if (algorithm == GRPC_COMPRESS_ALGORITHMS_COUNT) { + const char *md_c_str = grpc_mdstr_as_c_string(md->value); + gpr_log(GPR_ERROR, "Invalid compression algorithm: '%s'", md_c_str); + } + return algorithm; +} + +static grpc_mdelem *recv_common_filter(grpc_call *call, grpc_mdelem *elem) { + if (elem->key == GRPC_MDSTR_GRPC_STATUS) { + GPR_TIMER_BEGIN("status", 0); + set_status_code(call, STATUS_FROM_WIRE, decode_status(elem)); + GPR_TIMER_END("status", 0); + return NULL; + } else if (elem->key == GRPC_MDSTR_GRPC_MESSAGE) { + GPR_TIMER_BEGIN("status-details", 0); + set_status_details(call, STATUS_FROM_WIRE, GRPC_MDSTR_REF(elem->value)); + GPR_TIMER_END("status-details", 0); + return NULL; + } + return elem; +} + +static grpc_mdelem *publish_app_metadata(grpc_call *call, grpc_mdelem *elem, + int is_trailing) { + grpc_metadata_array *dest; + grpc_metadata *mdusr; + GPR_TIMER_BEGIN("publish_app_metadata", 0); + dest = call->buffered_metadata[is_trailing]; + if (dest->count == dest->capacity) { + dest->capacity = GPR_MAX(dest->capacity + 8, dest->capacity * 2); + dest->metadata = + gpr_realloc(dest->metadata, sizeof(grpc_metadata) * dest->capacity); + } + mdusr = &dest->metadata[dest->count++]; + mdusr->key = grpc_mdstr_as_c_string(elem->key); + mdusr->value = grpc_mdstr_as_c_string(elem->value); + mdusr->value_length = GPR_SLICE_LENGTH(elem->value->slice); + GPR_TIMER_END("publish_app_metadata", 0); + return elem; +} + +static grpc_mdelem *recv_initial_filter(void *callp, grpc_mdelem *elem) { + grpc_call *call = callp; + elem = recv_common_filter(call, 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); + return NULL; + } else if (elem->key == GRPC_MDSTR_GRPC_ACCEPT_ENCODING) { + GPR_TIMER_BEGIN("encodings_accepted_by_peer", 0); + set_encodings_accepted_by_peer(call, elem); + GPR_TIMER_END("encodings_accepted_by_peer", 0); + return NULL; + } else { + return publish_app_metadata(call, elem, 0); + } +} + +static grpc_mdelem *recv_trailing_filter(void *callp, grpc_mdelem *elem) { + grpc_call *call = callp; + elem = recv_common_filter(call, elem); + if (elem == NULL) { + return NULL; + } else { + return publish_app_metadata(call, elem, 1); + } +} + +grpc_call_stack *grpc_call_get_call_stack(grpc_call *call) { + return CALL_STACK_FROM_CALL(call); +} + +/* + * BATCH API IMPLEMENTATION + */ + +static void set_status_value_directly(grpc_status_code status, void *dest) { + *(grpc_status_code *)dest = status; +} + +static void set_cancelled_value(grpc_status_code status, void *dest) { + *(int *)dest = (status != GRPC_STATUS_OK); +} + +static int are_write_flags_valid(uint32_t flags) { + /* check that only bits in GRPC_WRITE_(INTERNAL?)_USED_MASK are set */ + const uint32_t allowed_write_positions = + (GRPC_WRITE_USED_MASK | GRPC_WRITE_INTERNAL_USED_MASK); + const uint32_t invalid_positions = ~allowed_write_positions; + return !(flags & invalid_positions); +} + +static batch_control *allocate_batch_control(grpc_call *call) { + size_t i; + for (i = 0; i < MAX_CONCURRENT_BATCHES; i++) { + if ((call->used_batches & (1 << i)) == 0) { + call->used_batches = (uint8_t)(call->used_batches | (uint8_t)(1 << i)); + return &call->active_batches[i]; + } + } + return NULL; +} + +static void finish_batch_completion(grpc_exec_ctx *exec_ctx, void *user_data, + grpc_cq_completion *storage) { + batch_control *bctl = user_data; + grpc_call *call = bctl->call; + gpr_mu_lock(&call->mu); + call->used_batches = (uint8_t)( + call->used_batches & ~(uint8_t)(1 << (bctl - call->active_batches))); + gpr_mu_unlock(&call->mu); + GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, "completion"); +} + +static void post_batch_completion(grpc_exec_ctx *exec_ctx, + batch_control *bctl) { + grpc_call *call = bctl->call; + if (bctl->is_notify_tag_closure) { + grpc_exec_ctx_enqueue(exec_ctx, bctl->notify_tag, bctl->success, NULL); + gpr_mu_lock(&call->mu); + bctl->call->used_batches = + (uint8_t)(bctl->call->used_batches & + ~(uint8_t)(1 << (bctl - bctl->call->active_batches))); + gpr_mu_unlock(&call->mu); + GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, "completion"); + } else { + grpc_cq_end_op(exec_ctx, bctl->call->cq, bctl->notify_tag, bctl->success, + finish_batch_completion, bctl, &bctl->cq_completion); + } +} + +static void continue_receiving_slices(grpc_exec_ctx *exec_ctx, + batch_control *bctl) { + grpc_call *call = bctl->call; + for (;;) { + size_t remaining = call->receiving_stream->length - + (*call->receiving_buffer)->data.raw.slice_buffer.length; + if (remaining == 0) { + call->receiving_message = 0; + grpc_byte_stream_destroy(exec_ctx, call->receiving_stream); + call->receiving_stream = NULL; + if (gpr_unref(&bctl->steps_to_complete)) { + post_batch_completion(exec_ctx, bctl); + } + return; + } + if (grpc_byte_stream_next(exec_ctx, call->receiving_stream, + &call->receiving_slice, remaining, + &call->receiving_slice_ready)) { + gpr_slice_buffer_add(&(*call->receiving_buffer)->data.raw.slice_buffer, + call->receiving_slice); + } else { + return; + } + } +} + +static void receiving_slice_ready(grpc_exec_ctx *exec_ctx, void *bctlp, + bool success) { + batch_control *bctl = bctlp; + grpc_call *call = bctl->call; + + if (success) { + gpr_slice_buffer_add(&(*call->receiving_buffer)->data.raw.slice_buffer, + call->receiving_slice); + continue_receiving_slices(exec_ctx, bctl); + } else { + grpc_byte_stream_destroy(exec_ctx, call->receiving_stream); + call->receiving_stream = NULL; + grpc_byte_buffer_destroy(*call->receiving_buffer); + *call->receiving_buffer = NULL; + if (gpr_unref(&bctl->steps_to_complete)) { + post_batch_completion(exec_ctx, bctl); + } + } +} + +static void process_data_after_md(grpc_exec_ctx *exec_ctx, batch_control *bctl, + bool success) { + grpc_call *call = bctl->call; + if (call->receiving_stream == NULL) { + *call->receiving_buffer = NULL; + call->receiving_message = 0; + if (gpr_unref(&bctl->steps_to_complete)) { + post_batch_completion(exec_ctx, bctl); + } + } else if (call->receiving_stream->length > + grpc_channel_get_max_message_length(call->channel)) { + cancel_with_status(exec_ctx, call, GRPC_STATUS_INTERNAL, + "Max message size exceeded"); + grpc_byte_stream_destroy(exec_ctx, call->receiving_stream); + call->receiving_stream = NULL; + *call->receiving_buffer = NULL; + call->receiving_message = 0; + if (gpr_unref(&bctl->steps_to_complete)) { + post_batch_completion(exec_ctx, 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->receiving_buffer = grpc_raw_compressed_byte_buffer_create( + NULL, 0, call->compression_algorithm); + } else { + *call->receiving_buffer = grpc_raw_byte_buffer_create(NULL, 0); + } + grpc_closure_init(&call->receiving_slice_ready, receiving_slice_ready, + bctl); + continue_receiving_slices(exec_ctx, bctl); + /* early out */ + return; + } +} + +static void receiving_stream_ready(grpc_exec_ctx *exec_ctx, void *bctlp, + bool success) { + batch_control *bctl = bctlp; + grpc_call *call = bctl->call; + + gpr_mu_lock(&bctl->call->mu); + if (bctl->call->has_initial_md_been_received) { + gpr_mu_unlock(&bctl->call->mu); + process_data_after_md(exec_ctx, bctlp, success); + } else { + call->saved_receiving_stream_ready_ctx.bctlp = bctlp; + call->saved_receiving_stream_ready_ctx.success = success; + gpr_mu_unlock(&bctl->call->mu); + } +} + +static void receiving_initial_metadata_ready(grpc_exec_ctx *exec_ctx, + void *bctlp, bool success) { + batch_control *bctl = bctlp; + grpc_call *call = bctl->call; + + gpr_mu_lock(&call->mu); + + grpc_metadata_batch *md = + &call->metadata_batch[1 /* is_receiving */][0 /* is_trailing */]; + grpc_metadata_batch_filter(md, recv_initial_filter, call); + call->has_initial_md_been_received = true; + + if (gpr_time_cmp(md->deadline, gpr_inf_future(md->deadline.clock_type)) != + 0 && + !call->is_client) { + GPR_TIMER_BEGIN("set_deadline_alarm", 0); + set_deadline_alarm(exec_ctx, call, md->deadline); + GPR_TIMER_END("set_deadline_alarm", 0); + } + + if (call->saved_receiving_stream_ready_ctx.bctlp != NULL) { + grpc_closure *saved_rsr_closure = grpc_closure_create( + receiving_stream_ready, call->saved_receiving_stream_ready_ctx.bctlp); + grpc_exec_ctx_enqueue(exec_ctx, saved_rsr_closure, + call->saved_receiving_stream_ready_ctx.success, NULL); + call->saved_receiving_stream_ready_ctx.bctlp = NULL; + } + + gpr_mu_unlock(&call->mu); + + if (gpr_unref(&bctl->steps_to_complete)) { + post_batch_completion(exec_ctx, bctl); + } +} + +static void finish_batch(grpc_exec_ctx *exec_ctx, void *bctlp, bool success) { + batch_control *bctl = bctlp; + grpc_call *call = bctl->call; + grpc_call *child_call; + grpc_call *next_child_call; + + gpr_mu_lock(&call->mu); + if (bctl->send_initial_metadata) { + grpc_metadata_batch_destroy( + &call->metadata_batch[0 /* is_receiving */][0 /* is_trailing */]); + } + if (bctl->send_message) { + call->sending_message = 0; + } + if (bctl->send_final_op) { + grpc_metadata_batch_destroy( + &call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */]); + } + if (bctl->recv_final_op) { + grpc_metadata_batch *md = + &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */]; + grpc_metadata_batch_filter(md, recv_trailing_filter, call); + + if (call->have_alarm) { + grpc_timer_cancel(exec_ctx, &call->alarm); + } + /* propagate cancellation to any interested children */ + child_call = call->first_child; + if (child_call != NULL) { + do { + next_child_call = child_call->sibling_next; + if (child_call->cancellation_is_inherited) { + GRPC_CALL_INTERNAL_REF(child_call, "propagate_cancel"); + grpc_call_cancel(child_call, NULL); + GRPC_CALL_INTERNAL_UNREF(exec_ctx, child_call, "propagate_cancel"); + } + child_call = next_child_call; + } while (child_call != call->first_child); + } + + if (call->is_client) { + get_final_status(call, set_status_value_directly, + call->final_op.client.status); + get_final_details(call, call->final_op.client.status_details, + call->final_op.client.status_details_capacity); + } else { + get_final_status(call, set_cancelled_value, + call->final_op.server.cancelled); + } + + success = 1; + } + bctl->success = success != 0; + gpr_mu_unlock(&call->mu); + if (gpr_unref(&bctl->steps_to_complete)) { + post_batch_completion(exec_ctx, bctl); + } +} + +static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx, + grpc_call *call, const grpc_op *ops, + size_t nops, void *notify_tag, + int is_notify_tag_closure) { + grpc_transport_stream_op stream_op; + size_t i; + const grpc_op *op; + batch_control *bctl; + int num_completion_callbacks_needed = 1; + grpc_call_error error = GRPC_CALL_OK; + + GPR_TIMER_BEGIN("grpc_call_start_batch", 0); + + GRPC_CALL_LOG_BATCH(GPR_INFO, call, ops, nops, notify_tag); + + memset(&stream_op, 0, sizeof(stream_op)); + + /* TODO(ctiller): this feels like it could be made lock-free */ + gpr_mu_lock(&call->mu); + bctl = allocate_batch_control(call); + memset(bctl, 0, sizeof(*bctl)); + bctl->call = call; + bctl->notify_tag = notify_tag; + bctl->is_notify_tag_closure = (uint8_t)(is_notify_tag_closure != 0); + + if (nops == 0) { + GRPC_CALL_INTERNAL_REF(call, "completion"); + bctl->success = 1; + if (!is_notify_tag_closure) { + grpc_cq_begin_op(call->cq, notify_tag); + } + gpr_mu_unlock(&call->mu); + post_batch_completion(exec_ctx, bctl); + error = GRPC_CALL_OK; + goto done; + } + + /* rewrite batch ops into a transport op */ + for (i = 0; i < nops; i++) { + op = &ops[i]; + if (op->reserved != NULL) { + error = GRPC_CALL_ERROR; + goto done_with_error; + } + switch (op->op) { + case GRPC_OP_SEND_INITIAL_METADATA: + /* Flag validation: currently allow no flags */ + if (op->flags != 0) { + error = GRPC_CALL_ERROR_INVALID_FLAGS; + goto done_with_error; + } + if (call->sent_initial_metadata) { + error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; + goto done_with_error; + } + if (op->data.send_initial_metadata.count > INT_MAX) { + error = GRPC_CALL_ERROR_INVALID_METADATA; + goto done_with_error; + } + bctl->send_initial_metadata = 1; + 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)) { + error = GRPC_CALL_ERROR_INVALID_METADATA; + goto done_with_error; + } + /* TODO(ctiller): just make these the same variable? */ + call->metadata_batch[0][0].deadline = call->send_deadline; + stream_op.send_initial_metadata = + &call->metadata_batch[0 /* is_receiving */][0 /* is_trailing */]; + break; + case GRPC_OP_SEND_MESSAGE: + if (!are_write_flags_valid(op->flags)) { + error = GRPC_CALL_ERROR_INVALID_FLAGS; + goto done_with_error; + } + if (op->data.send_message == NULL) { + error = GRPC_CALL_ERROR_INVALID_MESSAGE; + goto done_with_error; + } + if (call->sending_message) { + error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; + goto done_with_error; + } + bctl->send_message = 1; + call->sending_message = 1; + grpc_slice_buffer_stream_init( + &call->sending_stream, + &op->data.send_message->data.raw.slice_buffer, op->flags); + stream_op.send_message = &call->sending_stream.base; + break; + case GRPC_OP_SEND_CLOSE_FROM_CLIENT: + /* Flag validation: currently allow no flags */ + if (op->flags != 0) { + error = GRPC_CALL_ERROR_INVALID_FLAGS; + goto done_with_error; + } + if (!call->is_client) { + error = GRPC_CALL_ERROR_NOT_ON_SERVER; + goto done_with_error; + } + if (call->sent_final_op) { + error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; + goto done_with_error; + } + bctl->send_final_op = 1; + call->sent_final_op = 1; + stream_op.send_trailing_metadata = + &call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */]; + break; + case GRPC_OP_SEND_STATUS_FROM_SERVER: + /* Flag validation: currently allow no flags */ + if (op->flags != 0) { + error = GRPC_CALL_ERROR_INVALID_FLAGS; + goto done_with_error; + } + if (call->is_client) { + error = GRPC_CALL_ERROR_NOT_ON_CLIENT; + goto done_with_error; + } + if (call->sent_final_op) { + error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; + goto done_with_error; + } + if (op->data.send_status_from_server.trailing_metadata_count > + INT_MAX) { + error = GRPC_CALL_ERROR_INVALID_METADATA; + goto done_with_error; + } + bctl->send_final_op = 1; + call->sent_final_op = 1; + call->send_extra_metadata_count = 1; + call->send_extra_metadata[0].md = grpc_channel_get_reffed_status_elem( + call->channel, op->data.send_status_from_server.status); + if (op->data.send_status_from_server.status_details != NULL) { + call->send_extra_metadata[1].md = grpc_mdelem_from_metadata_strings( + GRPC_MDSTR_GRPC_MESSAGE, + grpc_mdstr_from_string( + op->data.send_status_from_server.status_details)); + call->send_extra_metadata_count++; + set_status_details( + call, STATUS_FROM_API_OVERRIDE, + GRPC_MDSTR_REF(call->send_extra_metadata[1].md->value)); + } + set_status_code(call, STATUS_FROM_API_OVERRIDE, + (uint32_t)op->data.send_status_from_server.status); + 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)) { + error = GRPC_CALL_ERROR_INVALID_METADATA; + goto done_with_error; + } + stream_op.send_trailing_metadata = + &call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */]; + break; + case GRPC_OP_RECV_INITIAL_METADATA: + /* Flag validation: currently allow no flags */ + if (op->flags != 0) { + error = GRPC_CALL_ERROR_INVALID_FLAGS; + goto done_with_error; + } + if (call->received_initial_metadata) { + error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; + goto done_with_error; + } + call->received_initial_metadata = 1; + call->buffered_metadata[0] = op->data.recv_initial_metadata; + grpc_closure_init(&call->receiving_initial_metadata_ready, + receiving_initial_metadata_ready, bctl); + bctl->recv_initial_metadata = 1; + stream_op.recv_initial_metadata = + &call->metadata_batch[1 /* is_receiving */][0 /* is_trailing */]; + stream_op.recv_initial_metadata_ready = + &call->receiving_initial_metadata_ready; + num_completion_callbacks_needed++; + break; + case GRPC_OP_RECV_MESSAGE: + /* Flag validation: currently allow no flags */ + if (op->flags != 0) { + error = GRPC_CALL_ERROR_INVALID_FLAGS; + goto done_with_error; + } + if (call->receiving_message) { + error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; + goto done_with_error; + } + call->receiving_message = 1; + bctl->recv_message = 1; + call->receiving_buffer = op->data.recv_message; + stream_op.recv_message = &call->receiving_stream; + grpc_closure_init(&call->receiving_stream_ready, receiving_stream_ready, + bctl); + stream_op.recv_message_ready = &call->receiving_stream_ready; + num_completion_callbacks_needed++; + break; + case GRPC_OP_RECV_STATUS_ON_CLIENT: + /* Flag validation: currently allow no flags */ + if (op->flags != 0) { + error = GRPC_CALL_ERROR_INVALID_FLAGS; + goto done_with_error; + } + if (!call->is_client) { + error = GRPC_CALL_ERROR_NOT_ON_SERVER; + goto done_with_error; + } + if (call->received_final_op) { + error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; + goto done_with_error; + } + call->received_final_op = 1; + call->buffered_metadata[1] = + op->data.recv_status_on_client.trailing_metadata; + call->final_op.client.status = op->data.recv_status_on_client.status; + call->final_op.client.status_details = + op->data.recv_status_on_client.status_details; + call->final_op.client.status_details_capacity = + op->data.recv_status_on_client.status_details_capacity; + bctl->recv_final_op = 1; + stream_op.recv_trailing_metadata = + &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */]; + break; + case GRPC_OP_RECV_CLOSE_ON_SERVER: + /* Flag validation: currently allow no flags */ + if (op->flags != 0) { + error = GRPC_CALL_ERROR_INVALID_FLAGS; + goto done_with_error; + } + if (call->is_client) { + error = GRPC_CALL_ERROR_NOT_ON_CLIENT; + goto done_with_error; + } + if (call->received_final_op) { + error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; + goto done_with_error; + } + call->received_final_op = 1; + call->final_op.server.cancelled = + op->data.recv_close_on_server.cancelled; + bctl->recv_final_op = 1; + stream_op.recv_trailing_metadata = + &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */]; + break; + } + } + + GRPC_CALL_INTERNAL_REF(call, "completion"); + if (!is_notify_tag_closure) { + grpc_cq_begin_op(call->cq, notify_tag); + } + gpr_ref_init(&bctl->steps_to_complete, num_completion_callbacks_needed); + + stream_op.context = call->context; + grpc_closure_init(&bctl->finish_batch, finish_batch, bctl); + stream_op.on_complete = &bctl->finish_batch; + gpr_mu_unlock(&call->mu); + + execute_op(exec_ctx, call, &stream_op); + +done: + GPR_TIMER_END("grpc_call_start_batch", 0); + return error; + +done_with_error: + /* reverse any mutations that occured */ + if (bctl->send_initial_metadata) { + call->sent_initial_metadata = 0; + grpc_metadata_batch_clear(&call->metadata_batch[0][0]); + } + if (bctl->send_message) { + call->sending_message = 0; + grpc_byte_stream_destroy(exec_ctx, &call->sending_stream.base); + } + if (bctl->send_final_op) { + call->sent_final_op = 0; + grpc_metadata_batch_clear(&call->metadata_batch[0][1]); + } + if (bctl->recv_initial_metadata) { + call->received_initial_metadata = 0; + } + if (bctl->recv_message) { + call->receiving_message = 0; + } + if (bctl->recv_final_op) { + call->received_final_op = 0; + } + gpr_mu_unlock(&call->mu); + goto done; +} + +grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops, + size_t nops, void *tag, void *reserved) { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_call_error err; + + GRPC_API_TRACE( + "grpc_call_start_batch(call=%p, ops=%p, nops=%lu, tag=%p, reserved=%p)", + 5, (call, ops, (unsigned long)nops, tag, reserved)); + + if (reserved != NULL) { + err = GRPC_CALL_ERROR; + } else { + err = call_start_batch(&exec_ctx, call, ops, nops, tag, 0); + } + + grpc_exec_ctx_finish(&exec_ctx); + return err; +} + +grpc_call_error grpc_call_start_batch_and_execute(grpc_exec_ctx *exec_ctx, + grpc_call *call, + const grpc_op *ops, + size_t nops, + grpc_closure *closure) { + return call_start_batch(exec_ctx, call, ops, nops, closure, 1); +} + +void grpc_call_context_set(grpc_call *call, grpc_context_index elem, + void *value, void (*destroy)(void *value)) { + if (call->context[elem].destroy) { + call->context[elem].destroy(call->context[elem].value); + } + call->context[elem].value = value; + call->context[elem].destroy = destroy; +} + +void *grpc_call_context_get(grpc_call *call, grpc_context_index elem) { + return call->context[elem].value; +} + +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; + gpr_mu_unlock(&call->mu); + return grpc_compression_algorithm_for_level(level, accepted_encodings); +} diff --git a/src/core/lib/surface/call.h b/src/core/lib/surface/call.h new file mode 100644 index 0000000000..d2edf03d45 --- /dev/null +++ b/src/core/lib/surface/call.h @@ -0,0 +1,116 @@ +/* + * + * Copyright 2015-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_SURFACE_CALL_H +#define GRPC_CORE_SURFACE_CALL_H + +#include "src/core/channel/channel_stack.h" +#include "src/core/channel/context.h" +#include "src/core/surface/api_trace.h" +#include "src/core/surface/surface_trace.h" + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*grpc_ioreq_completion_func)(grpc_exec_ctx *exec_ctx, + grpc_call *call, int success, + void *user_data); + +grpc_call *grpc_call_create(grpc_channel *channel, grpc_call *parent_call, + uint32_t propagation_mask, + grpc_completion_queue *cq, + const void *server_transport_data, + grpc_mdelem **add_initial_metadata, + size_t add_initial_metadata_count, + gpr_timespec send_deadline); + +void grpc_call_set_completion_queue(grpc_exec_ctx *exec_ctx, grpc_call *call, + grpc_completion_queue *cq); + +#ifdef GRPC_STREAM_REFCOUNT_DEBUG +void grpc_call_internal_ref(grpc_call *call, const char *reason); +void grpc_call_internal_unref(grpc_exec_ctx *exec_ctx, grpc_call *call, + const char *reason); +#define GRPC_CALL_INTERNAL_REF(call, reason) \ + grpc_call_internal_ref(call, reason) +#define GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, reason) \ + grpc_call_internal_unref(exec_ctx, call, reason) +#else +void grpc_call_internal_ref(grpc_call *call); +void grpc_call_internal_unref(grpc_exec_ctx *exec_ctx, grpc_call *call); +#define GRPC_CALL_INTERNAL_REF(call, reason) grpc_call_internal_ref(call) +#define GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, reason) \ + grpc_call_internal_unref(exec_ctx, call) +#endif + +grpc_call_stack *grpc_call_get_call_stack(grpc_call *call); + +grpc_call_error grpc_call_start_batch_and_execute(grpc_exec_ctx *exec_ctx, + grpc_call *call, + const grpc_op *ops, + size_t nops, + grpc_closure *closure); + +/* Given the top call_element, get the call object. */ +grpc_call *grpc_call_from_top_element(grpc_call_element *surface_element); + +void grpc_call_log_batch(char *file, int line, gpr_log_severity severity, + grpc_call *call, const grpc_op *ops, size_t nops, + void *tag); + +/* Set a context pointer. + No thread safety guarantees are made wrt this value. */ +void grpc_call_context_set(grpc_call *call, grpc_context_index elem, + void *value, void (*destroy)(void *value)); +/* Get a context pointer. */ +void *grpc_call_context_get(grpc_call *call, grpc_context_index elem); + +#define GRPC_CALL_LOG_BATCH(sev, call, ops, nops, tag) \ + if (grpc_api_trace) grpc_call_log_batch(sev, call, ops, nops, tag) + +uint8_t grpc_call_is_client(grpc_call *call); + +/* Return an appropriate compression algorithm for the requested compression \a + * level in the context of \a call. */ +grpc_compression_algorithm grpc_call_compression_for_level( + grpc_call *call, grpc_compression_level level); + +#ifdef __cplusplus +} +#endif + +#endif /* GRPC_CORE_SURFACE_CALL_H */ diff --git a/src/core/lib/surface/call_details.c b/src/core/lib/surface/call_details.c new file mode 100644 index 0000000000..60f0029819 --- /dev/null +++ b/src/core/lib/surface/call_details.c @@ -0,0 +1,50 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include + +#include + +#include "src/core/surface/api_trace.h" + +void grpc_call_details_init(grpc_call_details* cd) { + GRPC_API_TRACE("grpc_call_details_init(cd=%p)", 1, (cd)); + memset(cd, 0, sizeof(*cd)); +} + +void grpc_call_details_destroy(grpc_call_details* cd) { + GRPC_API_TRACE("grpc_call_details_destroy(cd=%p)", 1, (cd)); + gpr_free(cd->method); + gpr_free(cd->host); +} diff --git a/src/core/lib/surface/call_log_batch.c b/src/core/lib/surface/call_log_batch.c new file mode 100644 index 0000000000..044211616c --- /dev/null +++ b/src/core/lib/surface/call_log_batch.c @@ -0,0 +1,118 @@ +/* + * + * Copyright 2015-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/surface/call.h" + +#include +#include +#include "src/core/support/string.h" + +static void add_metadata(gpr_strvec *b, const grpc_metadata *md, size_t count) { + size_t i; + for (i = 0; i < count; i++) { + gpr_strvec_add(b, gpr_strdup("\nkey=")); + gpr_strvec_add(b, gpr_strdup(md[i].key)); + + gpr_strvec_add(b, gpr_strdup(" value=")); + gpr_strvec_add(b, gpr_dump(md[i].value, md[i].value_length, + GPR_DUMP_HEX | GPR_DUMP_ASCII)); + } +} + +char *grpc_op_string(const grpc_op *op) { + char *tmp; + char *out; + + gpr_strvec b; + gpr_strvec_init(&b); + + switch (op->op) { + case GRPC_OP_SEND_INITIAL_METADATA: + gpr_strvec_add(&b, gpr_strdup("SEND_INITIAL_METADATA")); + add_metadata(&b, op->data.send_initial_metadata.metadata, + op->data.send_initial_metadata.count); + break; + case GRPC_OP_SEND_MESSAGE: + gpr_asprintf(&tmp, "SEND_MESSAGE ptr=%p", op->data.send_message); + gpr_strvec_add(&b, tmp); + break; + case GRPC_OP_SEND_CLOSE_FROM_CLIENT: + gpr_strvec_add(&b, gpr_strdup("SEND_CLOSE_FROM_CLIENT")); + break; + case GRPC_OP_SEND_STATUS_FROM_SERVER: + gpr_asprintf(&tmp, "SEND_STATUS_FROM_SERVER status=%d details=%s", + op->data.send_status_from_server.status, + op->data.send_status_from_server.status_details); + gpr_strvec_add(&b, tmp); + add_metadata(&b, op->data.send_status_from_server.trailing_metadata, + op->data.send_status_from_server.trailing_metadata_count); + break; + case GRPC_OP_RECV_INITIAL_METADATA: + gpr_asprintf(&tmp, "RECV_INITIAL_METADATA ptr=%p", + op->data.recv_initial_metadata); + gpr_strvec_add(&b, tmp); + break; + case GRPC_OP_RECV_MESSAGE: + gpr_asprintf(&tmp, "RECV_MESSAGE ptr=%p", op->data.recv_message); + gpr_strvec_add(&b, tmp); + break; + case GRPC_OP_RECV_STATUS_ON_CLIENT: + gpr_asprintf(&tmp, + "RECV_STATUS_ON_CLIENT metadata=%p status=%p details=%p", + op->data.recv_status_on_client.trailing_metadata, + op->data.recv_status_on_client.status, + op->data.recv_status_on_client.status_details); + gpr_strvec_add(&b, tmp); + break; + case GRPC_OP_RECV_CLOSE_ON_SERVER: + gpr_asprintf(&tmp, "RECV_CLOSE_ON_SERVER cancelled=%p", + op->data.recv_close_on_server.cancelled); + gpr_strvec_add(&b, tmp); + } + out = gpr_strvec_flatten(&b, NULL); + gpr_strvec_destroy(&b); + + return out; +} + +void grpc_call_log_batch(char *file, int line, gpr_log_severity severity, + grpc_call *call, const grpc_op *ops, size_t nops, + void *tag) { + char *tmp; + size_t i; + for (i = 0; i < nops; i++) { + tmp = grpc_op_string(&ops[i]); + gpr_log(file, line, severity, "ops[%d]: %s", i, tmp); + gpr_free(tmp); + } +} diff --git a/src/core/lib/surface/call_test_only.h b/src/core/lib/surface/call_test_only.h new file mode 100644 index 0000000000..fdc43a383b --- /dev/null +++ b/src/core/lib/surface/call_test_only.h @@ -0,0 +1,64 @@ +/* + * + * Copyright 2015-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_SURFACE_CALL_TEST_ONLY_H +#define GRPC_CORE_SURFACE_CALL_TEST_ONLY_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Return the compression algorithm from \a call. + * + * \warning This function should \b only be used in test code. */ +grpc_compression_algorithm grpc_call_test_only_get_compression_algorithm( + grpc_call *call); + +/** Return the message flags from \a call. + * + * \warning This function should \b only be used in test code. */ +uint32_t grpc_call_test_only_get_message_flags(grpc_call *call); + +/** Returns a bitset for the encodings (compression algorithms) supported by \a + * call's peer. + * + * To be indexed by grpc_compression_algorithm enum values. */ +uint32_t grpc_call_test_only_get_encodings_accepted_by_peer(grpc_call *call); + +#ifdef __cplusplus +} +#endif + +#endif /* GRPC_CORE_SURFACE_CALL_TEST_ONLY_H */ diff --git a/src/core/lib/surface/channel.c b/src/core/lib/surface/channel.c new file mode 100644 index 0000000000..0010b64c7d --- /dev/null +++ b/src/core/lib/surface/channel.c @@ -0,0 +1,324 @@ +/* + * + * Copyright 2015-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/surface/channel.h" + +#include +#include + +#include +#include +#include + +#include "src/core/client_config/resolver_registry.h" +#include "src/core/iomgr/iomgr.h" +#include "src/core/support/string.h" +#include "src/core/surface/api_trace.h" +#include "src/core/surface/call.h" +#include "src/core/surface/channel_init.h" +#include "src/core/surface/init.h" +#include "src/core/transport/static_metadata.h" + +/** Cache grpc-status: X mdelems for X = 0..NUM_CACHED_STATUS_ELEMS. + * Avoids needing to take a metadata context lock for sending status + * if the status code is <= NUM_CACHED_STATUS_ELEMS. + * Sized to allow the most commonly used codes to fit in + * (OK, Cancelled, Unknown). */ +#define NUM_CACHED_STATUS_ELEMS 3 + +typedef struct registered_call { + grpc_mdelem *path; + grpc_mdelem *authority; + struct registered_call *next; +} registered_call; + +struct grpc_channel { + int is_client; + uint32_t max_message_length; + grpc_mdelem *default_authority; + + gpr_mu registered_call_mu; + registered_call *registered_calls; + char *target; +}; + +#define CHANNEL_STACK_FROM_CHANNEL(c) ((grpc_channel_stack *)((c) + 1)) +#define CHANNEL_FROM_CHANNEL_STACK(channel_stack) \ + (((grpc_channel *)(channel_stack)) - 1) +#define CHANNEL_FROM_TOP_ELEM(top_elem) \ + CHANNEL_FROM_CHANNEL_STACK(grpc_channel_stack_from_top_element(top_elem)) + +/* the protobuf library will (by default) start warning at 100megs */ +#define DEFAULT_MAX_MESSAGE_LENGTH (100 * 1024 * 1024) + +static void destroy_channel(grpc_exec_ctx *exec_ctx, void *arg, bool success); + +grpc_channel *grpc_channel_create(grpc_exec_ctx *exec_ctx, const char *target, + const grpc_channel_args *args, + grpc_channel_stack_type channel_stack_type, + grpc_transport *optional_transport) { + bool is_client = grpc_channel_stack_type_is_client(channel_stack_type); + + grpc_channel *channel = grpc_channel_init_create_stack( + exec_ctx, channel_stack_type, sizeof(grpc_channel), args, 1, + destroy_channel, NULL, optional_transport); + + memset(channel, 0, sizeof(*channel)); + channel->target = gpr_strdup(target); + channel->is_client = is_client; + gpr_mu_init(&channel->registered_call_mu); + channel->registered_calls = NULL; + + channel->max_message_length = DEFAULT_MAX_MESSAGE_LENGTH; + if (args) { + for (size_t i = 0; i < args->num_args; i++) { + if (0 == strcmp(args->args[i].key, GRPC_ARG_MAX_MESSAGE_LENGTH)) { + if (args->args[i].type != GRPC_ARG_INTEGER) { + gpr_log(GPR_ERROR, "%s ignored: it must be an integer", + GRPC_ARG_MAX_MESSAGE_LENGTH); + } else if (args->args[i].value.integer < 0) { + gpr_log(GPR_ERROR, "%s ignored: it must be >= 0", + GRPC_ARG_MAX_MESSAGE_LENGTH); + } else { + channel->max_message_length = (uint32_t)args->args[i].value.integer; + } + } else if (0 == strcmp(args->args[i].key, GRPC_ARG_DEFAULT_AUTHORITY)) { + if (args->args[i].type != GRPC_ARG_STRING) { + gpr_log(GPR_ERROR, "%s ignored: it must be a string", + GRPC_ARG_DEFAULT_AUTHORITY); + } else { + if (channel->default_authority) { + /* setting this takes precedence over anything else */ + GRPC_MDELEM_UNREF(channel->default_authority); + } + channel->default_authority = grpc_mdelem_from_strings( + ":authority", args->args[i].value.string); + } + } else if (0 == + strcmp(args->args[i].key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG)) { + if (args->args[i].type != GRPC_ARG_STRING) { + gpr_log(GPR_ERROR, "%s ignored: it must be a string", + GRPC_SSL_TARGET_NAME_OVERRIDE_ARG); + } else { + if (channel->default_authority) { + /* other ways of setting this (notably ssl) take precedence */ + gpr_log(GPR_ERROR, + "%s ignored: default host already set some other way", + GRPC_SSL_TARGET_NAME_OVERRIDE_ARG); + } else { + channel->default_authority = grpc_mdelem_from_strings( + ":authority", args->args[i].value.string); + } + } + } + } + } + + if (channel->is_client && channel->default_authority == NULL && + target != NULL) { + char *default_authority = grpc_get_default_authority(target); + if (default_authority) { + channel->default_authority = + grpc_mdelem_from_strings(":authority", default_authority); + } + gpr_free(default_authority); + } + + return channel; +} + +char *grpc_channel_get_target(grpc_channel *channel) { + GRPC_API_TRACE("grpc_channel_get_target(channel=%p)", 1, (channel)); + return gpr_strdup(channel->target); +} + +static grpc_call *grpc_channel_create_call_internal( + grpc_channel *channel, grpc_call *parent_call, uint32_t propagation_mask, + grpc_completion_queue *cq, grpc_mdelem *path_mdelem, + grpc_mdelem *authority_mdelem, gpr_timespec deadline) { + grpc_mdelem *send_metadata[2]; + size_t num_metadata = 0; + + GPR_ASSERT(channel->is_client); + + send_metadata[num_metadata++] = path_mdelem; + if (authority_mdelem != NULL) { + send_metadata[num_metadata++] = authority_mdelem; + } else if (channel->default_authority != NULL) { + send_metadata[num_metadata++] = GRPC_MDELEM_REF(channel->default_authority); + } + + return grpc_call_create(channel, parent_call, propagation_mask, cq, NULL, + send_metadata, num_metadata, deadline); +} + +grpc_call *grpc_channel_create_call(grpc_channel *channel, + grpc_call *parent_call, + uint32_t propagation_mask, + grpc_completion_queue *cq, + const char *method, const char *host, + gpr_timespec deadline, void *reserved) { + GRPC_API_TRACE( + "grpc_channel_create_call(" + "channel=%p, parent_call=%p, propagation_mask=%x, cq=%p, method=%s, " + "host=%s, " + "deadline=gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, " + "reserved=%p)", + 10, (channel, parent_call, (unsigned)propagation_mask, cq, method, host, + (long long)deadline.tv_sec, (int)deadline.tv_nsec, + (int)deadline.clock_type, reserved)); + GPR_ASSERT(!reserved); + return grpc_channel_create_call_internal( + channel, parent_call, propagation_mask, cq, + grpc_mdelem_from_metadata_strings(GRPC_MDSTR_PATH, + grpc_mdstr_from_string(method)), + host ? grpc_mdelem_from_metadata_strings(GRPC_MDSTR_AUTHORITY, + grpc_mdstr_from_string(host)) + : NULL, + deadline); +} + +void *grpc_channel_register_call(grpc_channel *channel, const char *method, + const char *host, void *reserved) { + registered_call *rc = gpr_malloc(sizeof(registered_call)); + GRPC_API_TRACE( + "grpc_channel_register_call(channel=%p, method=%s, host=%s, reserved=%p)", + 4, (channel, method, host, reserved)); + GPR_ASSERT(!reserved); + rc->path = grpc_mdelem_from_metadata_strings(GRPC_MDSTR_PATH, + grpc_mdstr_from_string(method)); + rc->authority = host ? grpc_mdelem_from_metadata_strings( + GRPC_MDSTR_AUTHORITY, grpc_mdstr_from_string(host)) + : NULL; + gpr_mu_lock(&channel->registered_call_mu); + rc->next = channel->registered_calls; + channel->registered_calls = rc; + gpr_mu_unlock(&channel->registered_call_mu); + return rc; +} + +grpc_call *grpc_channel_create_registered_call( + grpc_channel *channel, grpc_call *parent_call, uint32_t propagation_mask, + grpc_completion_queue *completion_queue, void *registered_call_handle, + gpr_timespec deadline, void *reserved) { + registered_call *rc = registered_call_handle; + GRPC_API_TRACE( + "grpc_channel_create_registered_call(" + "channel=%p, parent_call=%p, propagation_mask=%x, completion_queue=%p, " + "registered_call_handle=%p, " + "deadline=gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, " + "reserved=%p)", + 9, (channel, parent_call, (unsigned)propagation_mask, completion_queue, + registered_call_handle, (long long)deadline.tv_sec, + (int)deadline.tv_nsec, (int)deadline.clock_type, reserved)); + GPR_ASSERT(!reserved); + return grpc_channel_create_call_internal( + channel, parent_call, propagation_mask, completion_queue, + GRPC_MDELEM_REF(rc->path), + rc->authority ? GRPC_MDELEM_REF(rc->authority) : NULL, deadline); +} + +#ifdef GRPC_STREAM_REFCOUNT_DEBUG +#define REF_REASON reason +#define REF_ARG , const char *reason +#else +#define REF_REASON "" +#define REF_ARG +#endif +void grpc_channel_internal_ref(grpc_channel *c REF_ARG) { + GRPC_CHANNEL_STACK_REF(CHANNEL_STACK_FROM_CHANNEL(c), REF_REASON); +} + +void grpc_channel_internal_unref(grpc_exec_ctx *exec_ctx, + grpc_channel *c REF_ARG) { + GRPC_CHANNEL_STACK_UNREF(exec_ctx, CHANNEL_STACK_FROM_CHANNEL(c), REF_REASON); +} + +static void destroy_channel(grpc_exec_ctx *exec_ctx, void *arg, + bool iomgr_success) { + grpc_channel *channel = arg; + grpc_channel_stack_destroy(exec_ctx, CHANNEL_STACK_FROM_CHANNEL(channel)); + while (channel->registered_calls) { + registered_call *rc = channel->registered_calls; + channel->registered_calls = rc->next; + GRPC_MDELEM_UNREF(rc->path); + if (rc->authority) { + GRPC_MDELEM_UNREF(rc->authority); + } + gpr_free(rc); + } + if (channel->default_authority != NULL) { + GRPC_MDELEM_UNREF(channel->default_authority); + } + gpr_mu_destroy(&channel->registered_call_mu); + gpr_free(channel->target); + gpr_free(channel); +} + +void grpc_channel_destroy(grpc_channel *channel) { + grpc_transport_op op; + grpc_channel_element *elem; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + GRPC_API_TRACE("grpc_channel_destroy(channel=%p)", 1, (channel)); + memset(&op, 0, sizeof(op)); + op.disconnect = 1; + elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CHANNEL(channel), 0); + elem->filter->start_transport_op(&exec_ctx, elem, &op); + + GRPC_CHANNEL_INTERNAL_UNREF(&exec_ctx, channel, "channel"); + + grpc_exec_ctx_finish(&exec_ctx); +} + +grpc_channel_stack *grpc_channel_get_channel_stack(grpc_channel *channel) { + return CHANNEL_STACK_FROM_CHANNEL(channel); +} + +grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel, int i) { + char tmp[GPR_LTOA_MIN_BUFSIZE]; + switch (i) { + case 0: + return GRPC_MDELEM_GRPC_STATUS_0; + case 1: + return GRPC_MDELEM_GRPC_STATUS_1; + case 2: + return GRPC_MDELEM_GRPC_STATUS_2; + } + gpr_ltoa(i, tmp); + return grpc_mdelem_from_metadata_strings(GRPC_MDSTR_GRPC_STATUS, + grpc_mdstr_from_string(tmp)); +} + +uint32_t grpc_channel_get_max_message_length(grpc_channel *channel) { + return channel->max_message_length; +} diff --git a/src/core/lib/surface/channel.h b/src/core/lib/surface/channel.h new file mode 100644 index 0000000000..6a803ffe23 --- /dev/null +++ b/src/core/lib/surface/channel.h @@ -0,0 +1,75 @@ +/* + * + * Copyright 2015-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_SURFACE_CHANNEL_H +#define GRPC_CORE_SURFACE_CHANNEL_H + +#include "src/core/channel/channel_stack.h" +#include "src/core/client_config/subchannel_factory.h" +#include "src/core/surface/channel_stack_type.h" + +grpc_channel *grpc_channel_create(grpc_exec_ctx *exec_ctx, const char *target, + const grpc_channel_args *args, + grpc_channel_stack_type channel_stack_type, + grpc_transport *optional_transport); + +/** Get a (borrowed) pointer to this channels underlying channel stack */ +grpc_channel_stack *grpc_channel_get_channel_stack(grpc_channel *channel); + +/** Get a grpc_mdelem of grpc-status: X where X is the numeric value of + status_code. + + The returned elem is owned by the caller. */ +grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel, + int status_code); +uint32_t grpc_channel_get_max_message_length(grpc_channel *channel); + +#ifdef GRPC_STREAM_REFCOUNT_DEBUG +void grpc_channel_internal_ref(grpc_channel *channel, const char *reason); +void grpc_channel_internal_unref(grpc_exec_ctx *exec_ctx, grpc_channel *channel, + const char *reason); +#define GRPC_CHANNEL_INTERNAL_REF(channel, reason) \ + grpc_channel_internal_ref(channel, reason) +#define GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, channel, reason) \ + grpc_channel_internal_unref(exec_ctx, channel, reason) +#else +void grpc_channel_internal_ref(grpc_channel *channel); +void grpc_channel_internal_unref(grpc_exec_ctx *exec_ctx, + grpc_channel *channel); +#define GRPC_CHANNEL_INTERNAL_REF(channel, reason) \ + grpc_channel_internal_ref(channel) +#define GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, channel, reason) \ + grpc_channel_internal_unref(exec_ctx, channel) +#endif + +#endif /* GRPC_CORE_SURFACE_CHANNEL_H */ diff --git a/src/core/lib/surface/channel_connectivity.c b/src/core/lib/surface/channel_connectivity.c new file mode 100644 index 0000000000..18267939ed --- /dev/null +++ b/src/core/lib/surface/channel_connectivity.c @@ -0,0 +1,207 @@ +/* + * + * Copyright 2015-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/surface/channel.h" + +#include +#include + +#include "src/core/channel/client_channel.h" +#include "src/core/iomgr/timer.h" +#include "src/core/surface/api_trace.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)); + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_connectivity_state state; + GRPC_API_TRACE( + "grpc_channel_check_connectivity_state(channel=%p, try_to_connect=%d)", 2, + (channel, try_to_connect)); + if (client_channel_elem->filter == &grpc_client_channel_filter) { + state = grpc_client_channel_check_connectivity_state( + &exec_ctx, client_channel_elem, try_to_connect); + grpc_exec_ctx_finish(&exec_ctx); + return state; + } + gpr_log(GPR_ERROR, + "grpc_channel_check_connectivity_state called on something that is " + "not a (u)client channel, but '%s'", + client_channel_elem->filter->name); + grpc_exec_ctx_finish(&exec_ctx); + return GRPC_CHANNEL_FATAL_FAILURE; +} + +typedef enum { + WAITING, + CALLING_BACK, + CALLING_BACK_AND_FINISHED, + CALLED_BACK +} callback_phase; + +typedef struct { + gpr_mu mu; + callback_phase phase; + int success; + grpc_closure on_complete; + grpc_timer alarm; + grpc_connectivity_state state; + grpc_completion_queue *cq; + grpc_cq_completion completion_storage; + grpc_channel *channel; + void *tag; +} state_watcher; + +static void delete_state_watcher(grpc_exec_ctx *exec_ctx, state_watcher *w) { + grpc_channel_element *client_channel_elem = grpc_channel_stack_last_element( + grpc_channel_get_channel_stack(w->channel)); + if (client_channel_elem->filter == &grpc_client_channel_filter) { + GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, w->channel, + "watch_channel_connectivity"); + } else { + abort(); + } + gpr_mu_destroy(&w->mu); + gpr_free(w); +} + +static void finished_completion(grpc_exec_ctx *exec_ctx, 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_UNREACHABLE_CODE(return ); + 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(exec_ctx, w); + } +} + +static void partly_done(grpc_exec_ctx *exec_ctx, state_watcher *w, + int due_to_completion) { + int delete = 0; + + if (due_to_completion) { + grpc_timer_cancel(exec_ctx, &w->alarm); + } + + gpr_mu_lock(&w->mu); + if (due_to_completion) { + w->success = 1; + } + switch (w->phase) { + case WAITING: + w->phase = CALLING_BACK; + grpc_cq_end_op(exec_ctx, 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_UNREACHABLE_CODE(return ); + case CALLED_BACK: + delete = 1; + break; + } + gpr_mu_unlock(&w->mu); + + if (delete) { + delete_state_watcher(exec_ctx, w); + } +} + +static void watch_complete(grpc_exec_ctx *exec_ctx, void *pw, bool success) { + partly_done(exec_ctx, pw, 1); +} + +static void timeout_complete(grpc_exec_ctx *exec_ctx, void *pw, bool success) { + partly_done(exec_ctx, pw, 0); +} + +void grpc_channel_watch_connectivity_state( + grpc_channel *channel, grpc_connectivity_state last_observed_state, + gpr_timespec deadline, grpc_completion_queue *cq, void *tag) { + grpc_channel_element *client_channel_elem = + grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel)); + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + state_watcher *w = gpr_malloc(sizeof(*w)); + + GRPC_API_TRACE( + "grpc_channel_watch_connectivity_state(" + "channel=%p, last_observed_state=%d, " + "deadline=gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, " + "cq=%p, tag=%p)", + 7, (channel, (int)last_observed_state, (long long)deadline.tv_sec, + (int)deadline.tv_nsec, (int)deadline.clock_type, cq, tag)); + + grpc_cq_begin_op(cq, tag); + + gpr_mu_init(&w->mu); + grpc_closure_init(&w->on_complete, watch_complete, w); + w->phase = WAITING; + w->state = last_observed_state; + w->success = 0; + w->cq = cq; + w->tag = tag; + w->channel = channel; + + grpc_timer_init(&exec_ctx, &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) { + GRPC_CHANNEL_INTERNAL_REF(channel, "watch_channel_connectivity"); + grpc_client_channel_watch_connectivity_state(&exec_ctx, client_channel_elem, + grpc_cq_pollset(cq), &w->state, + &w->on_complete); + } else { + abort(); + } + + grpc_exec_ctx_finish(&exec_ctx); +} diff --git a/src/core/lib/surface/channel_create.c b/src/core/lib/surface/channel_create.c new file mode 100644 index 0000000000..123447c8ed --- /dev/null +++ b/src/core/lib/surface/channel_create.c @@ -0,0 +1,223 @@ +/* + * + * Copyright 2015-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 + +#include +#include + +#include +#include +#include + +#include "src/core/census/grpc_filter.h" +#include "src/core/channel/channel_args.h" +#include "src/core/channel/client_channel.h" +#include "src/core/channel/compress_filter.h" +#include "src/core/channel/http_client_filter.h" +#include "src/core/client_config/resolver_registry.h" +#include "src/core/iomgr/tcp_client.h" +#include "src/core/surface/api_trace.h" +#include "src/core/surface/channel.h" +#include "src/core/transport/chttp2_transport.h" + +typedef struct { + grpc_connector base; + gpr_refcount refs; + + grpc_closure *notify; + grpc_connect_in_args args; + grpc_connect_out_args *result; + grpc_closure initial_string_sent; + gpr_slice_buffer initial_string_buffer; + + grpc_endpoint *tcp; + + grpc_closure connected; +} connector; + +static void connector_ref(grpc_connector *con) { + connector *c = (connector *)con; + gpr_ref(&c->refs); +} + +static void connector_unref(grpc_exec_ctx *exec_ctx, grpc_connector *con) { + connector *c = (connector *)con; + if (gpr_unref(&c->refs)) { + /* c->initial_string_buffer does not need to be destroyed */ + gpr_free(c); + } +} + +static void on_initial_connect_string_sent(grpc_exec_ctx *exec_ctx, void *arg, + bool success) { + connector_unref(exec_ctx, arg); +} + +static void connected(grpc_exec_ctx *exec_ctx, void *arg, bool success) { + connector *c = arg; + grpc_closure *notify; + grpc_endpoint *tcp = c->tcp; + if (tcp != NULL) { + if (!GPR_SLICE_IS_EMPTY(c->args.initial_connect_string)) { + grpc_closure_init(&c->initial_string_sent, on_initial_connect_string_sent, + c); + gpr_slice_buffer_init(&c->initial_string_buffer); + gpr_slice_buffer_add(&c->initial_string_buffer, + c->args.initial_connect_string); + connector_ref(arg); + grpc_endpoint_write(exec_ctx, tcp, &c->initial_string_buffer, + &c->initial_string_sent); + } + c->result->transport = + grpc_create_chttp2_transport(exec_ctx, c->args.channel_args, tcp, 1); + grpc_chttp2_transport_start_reading(exec_ctx, c->result->transport, NULL, + 0); + GPR_ASSERT(c->result->transport); + c->result->channel_args = c->args.channel_args; + } else { + memset(c->result, 0, sizeof(*c->result)); + } + notify = c->notify; + c->notify = NULL; + notify->cb(exec_ctx, notify->cb_arg, 1); +} + +static void connector_shutdown(grpc_exec_ctx *exec_ctx, grpc_connector *con) {} + +static void connector_connect(grpc_exec_ctx *exec_ctx, grpc_connector *con, + const grpc_connect_in_args *args, + grpc_connect_out_args *result, + grpc_closure *notify) { + connector *c = (connector *)con; + GPR_ASSERT(c->notify == NULL); + GPR_ASSERT(notify->cb); + c->notify = notify; + c->args = *args; + c->result = result; + c->tcp = NULL; + grpc_closure_init(&c->connected, connected, c); + grpc_tcp_client_connect(exec_ctx, &c->connected, &c->tcp, + args->interested_parties, args->addr, args->addr_len, + args->deadline); +} + +static const grpc_connector_vtable connector_vtable = { + connector_ref, connector_unref, connector_shutdown, connector_connect}; + +typedef struct { + grpc_subchannel_factory base; + gpr_refcount refs; + grpc_channel_args *merge_args; + grpc_channel *master; +} subchannel_factory; + +static void subchannel_factory_ref(grpc_subchannel_factory *scf) { + subchannel_factory *f = (subchannel_factory *)scf; + gpr_ref(&f->refs); +} + +static void subchannel_factory_unref(grpc_exec_ctx *exec_ctx, + grpc_subchannel_factory *scf) { + subchannel_factory *f = (subchannel_factory *)scf; + if (gpr_unref(&f->refs)) { + GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, f->master, "subchannel_factory"); + grpc_channel_args_destroy(f->merge_args); + gpr_free(f); + } +} + +static grpc_subchannel *subchannel_factory_create_subchannel( + grpc_exec_ctx *exec_ctx, grpc_subchannel_factory *scf, + grpc_subchannel_args *args) { + subchannel_factory *f = (subchannel_factory *)scf; + connector *c = gpr_malloc(sizeof(*c)); + grpc_channel_args *final_args = + grpc_channel_args_merge(args->args, f->merge_args); + grpc_subchannel *s; + memset(c, 0, sizeof(*c)); + c->base.vtable = &connector_vtable; + gpr_ref_init(&c->refs, 1); + args->args = final_args; + s = grpc_subchannel_create(exec_ctx, &c->base, args); + grpc_connector_unref(exec_ctx, &c->base); + grpc_channel_args_destroy(final_args); + return s; +} + +static const grpc_subchannel_factory_vtable subchannel_factory_vtable = { + subchannel_factory_ref, subchannel_factory_unref, + subchannel_factory_create_subchannel}; + +/* Create a client channel: + Asynchronously: - resolve target + - connect to it (trying alternatives as presented) + - perform handshakes */ +grpc_channel *grpc_insecure_channel_create(const char *target, + const grpc_channel_args *args, + void *reserved) { + grpc_channel *channel = NULL; + grpc_resolver *resolver; + subchannel_factory *f; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + GRPC_API_TRACE( + "grpc_insecure_channel_create(target=%p, args=%p, reserved=%p)", 3, + (target, args, reserved)); + GPR_ASSERT(!reserved); + + channel = + grpc_channel_create(&exec_ctx, target, args, GRPC_CLIENT_CHANNEL, NULL); + + f = gpr_malloc(sizeof(*f)); + f->base.vtable = &subchannel_factory_vtable; + gpr_ref_init(&f->refs, 1); + 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) { + GRPC_CHANNEL_INTERNAL_UNREF(&exec_ctx, f->master, "subchannel_factory"); + grpc_subchannel_factory_unref(&exec_ctx, &f->base); + grpc_exec_ctx_finish(&exec_ctx); + return NULL; + } + + grpc_client_channel_set_resolver( + &exec_ctx, grpc_channel_get_channel_stack(channel), resolver); + GRPC_RESOLVER_UNREF(&exec_ctx, resolver, "create"); + grpc_subchannel_factory_unref(&exec_ctx, &f->base); + + grpc_exec_ctx_finish(&exec_ctx); + + return channel; +} diff --git a/src/core/lib/surface/channel_init.c b/src/core/lib/surface/channel_init.c new file mode 100644 index 0000000000..ac962f3972 --- /dev/null +++ b/src/core/lib/surface/channel_init.c @@ -0,0 +1,146 @@ +/* + * + * 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/surface/channel_init.h" + +#include +#include + +typedef struct stage_slot { + grpc_channel_init_stage fn; + void *arg; + int priority; + size_t insertion_order; +} stage_slot; + +typedef struct stage_slots { + stage_slot *slots; + size_t num_slots; + size_t cap_slots; +} stage_slots; + +static stage_slots g_slots[GRPC_NUM_CHANNEL_STACK_TYPES]; +static bool g_finalized; + +void grpc_channel_init_init(void) { + for (int i = 0; i < GRPC_NUM_CHANNEL_STACK_TYPES; i++) { + g_slots[i].slots = NULL; + g_slots[i].num_slots = 0; + g_slots[i].cap_slots = 0; + } + g_finalized = false; +} + +void grpc_channel_init_register_stage(grpc_channel_stack_type type, + int priority, + grpc_channel_init_stage stage, + void *stage_arg) { + GPR_ASSERT(!g_finalized); + if (g_slots[type].cap_slots == g_slots[type].num_slots) { + g_slots[type].cap_slots = GPR_MAX(8, 3 * g_slots[type].cap_slots / 2); + g_slots[type].slots = + gpr_realloc(g_slots[type].slots, + g_slots[type].cap_slots * sizeof(*g_slots[type].slots)); + } + stage_slot *s = &g_slots[type].slots[g_slots[type].num_slots++]; + s->insertion_order = g_slots[type].num_slots; + s->priority = priority; + s->fn = stage; + s->arg = stage_arg; +} + +static int compare_slots(const void *a, const void *b) { + const stage_slot *sa = a; + const stage_slot *sb = b; + + int c = GPR_ICMP(sa->priority, sb->priority); + if (c != 0) return c; + return GPR_ICMP(sa->insertion_order, sb->insertion_order); +} + +void grpc_channel_init_finalize(void) { + GPR_ASSERT(!g_finalized); + for (int i = 0; i < GRPC_NUM_CHANNEL_STACK_TYPES; i++) { + qsort(g_slots[i].slots, g_slots[i].num_slots, sizeof(*g_slots[i].slots), + compare_slots); + } + g_finalized = true; +} + +void grpc_channel_init_shutdown(void) { + for (int i = 0; i < GRPC_NUM_CHANNEL_STACK_TYPES; i++) { + gpr_free(g_slots[i].slots); + g_slots[i].slots = (void *)(uintptr_t)0xdeadbeef; + } +} + +static const char *name_for_type(grpc_channel_stack_type type) { + switch (type) { + case GRPC_CLIENT_CHANNEL: + return "CLIENT_CHANNEL"; + case GRPC_CLIENT_SUBCHANNEL: + return "CLIENT_SUBCHANNEL"; + case GRPC_SERVER_CHANNEL: + return "SERVER_CHANNEL"; + case GRPC_CLIENT_LAME_CHANNEL: + return "CLIENT_LAME_CHANNEL"; + case GRPC_CLIENT_DIRECT_CHANNEL: + return "CLIENT_DIRECT_CHANNEL"; + case GRPC_NUM_CHANNEL_STACK_TYPES: + break; + } + GPR_UNREACHABLE_CODE(return "UNKNOWN"); +} + +void *grpc_channel_init_create_stack( + grpc_exec_ctx *exec_ctx, grpc_channel_stack_type type, size_t prefix_bytes, + const grpc_channel_args *args, int initial_refs, grpc_iomgr_cb_func destroy, + void *destroy_arg, grpc_transport *transport) { + GPR_ASSERT(g_finalized); + + grpc_channel_stack_builder *builder = grpc_channel_stack_builder_create(); + grpc_channel_stack_builder_set_name(builder, name_for_type(type)); + grpc_channel_stack_builder_set_channel_arguments(builder, args); + grpc_channel_stack_builder_set_transport(builder, transport); + + for (size_t i = 0; i < g_slots[type].num_slots; i++) { + const stage_slot *slot = &g_slots[type].slots[i]; + if (!slot->fn(builder, slot->arg)) { + grpc_channel_stack_builder_destroy(builder); + return NULL; + } + } + + return grpc_channel_stack_builder_finish(exec_ctx, builder, prefix_bytes, + initial_refs, destroy, destroy_arg); +} diff --git a/src/core/lib/surface/channel_init.h b/src/core/lib/surface/channel_init.h new file mode 100644 index 0000000000..06faef6ddb --- /dev/null +++ b/src/core/lib/surface/channel_init.h @@ -0,0 +1,86 @@ +/* + * + * 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_SURFACE_CHANNEL_INIT_H +#define GRPC_CORE_SURFACE_CHANNEL_INIT_H + +#include "src/core/channel/channel_stack_builder.h" +#include "src/core/surface/channel_stack_type.h" +#include "src/core/transport/transport.h" + +/// This module provides a way for plugins (and the grpc core library itself) +/// to register mutators for channel stacks. +/// It also provides a universal entry path to run those mutators to build +/// a channel stack for various subsystems. + +/// One stage of mutation: call functions against \a builder to influence the +/// finally constructed channel stack +typedef bool (*grpc_channel_init_stage)(grpc_channel_stack_builder *builder, + void *arg); + +/// Global initialization of the system +void grpc_channel_init_init(void); + +/// Register one stage of mutators. +/// Stages are run in priority order (lowest to highest), and then in +/// registration order (in the case of a tie). +/// Stages are registered against one of the pre-determined channel stack +/// types. +void grpc_channel_init_register_stage(grpc_channel_stack_type type, + int priority, + grpc_channel_init_stage stage_fn, + void *stage_arg); + +/// Finalize registration. No more calls to grpc_channel_init_register_stage are +/// allowed. +void grpc_channel_init_finalize(void); +/// Shutdown the channel init system +void grpc_channel_init_shutdown(void); + +/// Construct a channel stack of some sort: see channel_stack.h for details +/// \a type is the type of channel stack to create +/// \a prefix_bytes is the number of bytes before the channel stack to allocate +/// \a args are configuration arguments for the channel stack +/// \a initial_refs is the initial refcount to give the channel stack +/// \a destroy and \a destroy_arg specify how to destroy the channel stack +/// if destroy_arg is NULL, the returned value from this function will be +/// substituted +/// \a optional_transport is either NULL or a constructed transport object +/// Returns a pointer to the base of the memory allocated (the actual channel +/// stack object will be prefix_bytes past that pointer) +void *grpc_channel_init_create_stack( + grpc_exec_ctx *exec_ctx, grpc_channel_stack_type type, size_t prefix_bytes, + const grpc_channel_args *args, int initial_refs, grpc_iomgr_cb_func destroy, + void *destroy_arg, grpc_transport *optional_transport); + +#endif /* GRPC_CORE_SURFACE_CHANNEL_INIT_H */ diff --git a/src/core/lib/surface/channel_ping.c b/src/core/lib/surface/channel_ping.c new file mode 100644 index 0000000000..983f1c8a66 --- /dev/null +++ b/src/core/lib/surface/channel_ping.c @@ -0,0 +1,79 @@ +/* + * + * Copyright 2015-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/surface/channel.h" + +#include + +#include +#include + +#include "src/core/surface/api_trace.h" +#include "src/core/surface/completion_queue.h" + +typedef struct { + grpc_closure closure; + void *tag; + grpc_completion_queue *cq; + grpc_cq_completion completion_storage; +} ping_result; + +static void ping_destroy(grpc_exec_ctx *exec_ctx, void *arg, + grpc_cq_completion *storage) { + gpr_free(arg); +} + +static void ping_done(grpc_exec_ctx *exec_ctx, void *arg, bool success) { + ping_result *pr = arg; + grpc_cq_end_op(exec_ctx, pr->cq, pr->tag, success, ping_destroy, pr, + &pr->completion_storage); +} + +void grpc_channel_ping(grpc_channel *channel, grpc_completion_queue *cq, + void *tag, void *reserved) { + grpc_transport_op op; + ping_result *pr = gpr_malloc(sizeof(*pr)); + grpc_channel_element *top_elem = + grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0); + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + GPR_ASSERT(reserved == NULL); + memset(&op, 0, sizeof(op)); + pr->tag = tag; + pr->cq = cq; + grpc_closure_init(&pr->closure, ping_done, pr); + op.send_ping = &pr->closure; + op.bind_pollset = grpc_cq_pollset(cq); + grpc_cq_begin_op(cq, tag); + top_elem->filter->start_transport_op(&exec_ctx, top_elem, &op); + grpc_exec_ctx_finish(&exec_ctx); +} diff --git a/src/core/lib/surface/channel_stack_type.c b/src/core/lib/surface/channel_stack_type.c new file mode 100644 index 0000000000..1a6e949ffe --- /dev/null +++ b/src/core/lib/surface/channel_stack_type.c @@ -0,0 +1,54 @@ +/* + * + * 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/surface/channel_stack_type.h" +#include +#include + +bool grpc_channel_stack_type_is_client(grpc_channel_stack_type type) { + switch (type) { + case GRPC_CLIENT_CHANNEL: + return true; + case GRPC_CLIENT_SUBCHANNEL: + return true; + case GRPC_CLIENT_LAME_CHANNEL: + return true; + case GRPC_CLIENT_DIRECT_CHANNEL: + return true; + case GRPC_SERVER_CHANNEL: + return false; + case GRPC_NUM_CHANNEL_STACK_TYPES: + break; + } + GPR_UNREACHABLE_CODE(return true;); +} diff --git a/src/core/lib/surface/channel_stack_type.h b/src/core/lib/surface/channel_stack_type.h new file mode 100644 index 0000000000..75a1b9c072 --- /dev/null +++ b/src/core/lib/surface/channel_stack_type.h @@ -0,0 +1,58 @@ +/* + * + * Copyright 2015-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_SURFACE_CHANNEL_STACK_TYPE_H +#define GRPC_CORE_SURFACE_CHANNEL_STACK_TYPE_H + +#include + +typedef enum { + // normal top-half client channel with load-balancing, connection management + GRPC_CLIENT_CHANNEL, + // bottom-half of a client channel: everything that happens post-load + // balancing (bound to a specific transport) + GRPC_CLIENT_SUBCHANNEL, + // a permanently broken client channel + GRPC_CLIENT_LAME_CHANNEL, + // a directly connected client channel (without load-balancing, directly talks + // to a transport) + GRPC_CLIENT_DIRECT_CHANNEL, + // server side channel + GRPC_SERVER_CHANNEL, + // must be last + GRPC_NUM_CHANNEL_STACK_TYPES +} grpc_channel_stack_type; + +bool grpc_channel_stack_type_is_client(grpc_channel_stack_type type); + +#endif /* GRPC_CORE_SURFACE_CHANNEL_STACK_TYPE_H */ diff --git a/src/core/lib/surface/completion_queue.c b/src/core/lib/surface/completion_queue.c new file mode 100644 index 0000000000..b22818ea87 --- /dev/null +++ b/src/core/lib/surface/completion_queue.c @@ -0,0 +1,512 @@ +/* + * + * Copyright 2015-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/surface/completion_queue.h" + +#include +#include + +#include +#include +#include +#include + +#include "src/core/iomgr/pollset.h" +#include "src/core/iomgr/timer.h" +#include "src/core/profiling/timers.h" +#include "src/core/support/string.h" +#include "src/core/surface/api_trace.h" +#include "src/core/surface/call.h" +#include "src/core/surface/event_string.h" +#include "src/core/surface/surface_trace.h" + +typedef struct { + grpc_pollset_worker **worker; + void *tag; +} plucker; + +/* Completion queue structure */ +struct grpc_completion_queue { + /** owned by pollset */ + gpr_mu *mu; + /** completed events */ + grpc_cq_completion completed_head; + grpc_cq_completion *completed_tail; + /** Number of pending events (+1 if we're not shutdown) */ + gpr_refcount pending_events; + /** Once owning_refs drops to zero, we will destroy the cq */ + gpr_refcount owning_refs; + /** 0 initially, 1 once we've begun shutting down */ + int shutdown; + int shutdown_called; + int is_server_cq; + int num_pluckers; + plucker pluckers[GRPC_MAX_COMPLETION_QUEUE_PLUCKERS]; + grpc_closure pollset_shutdown_done; + +#ifndef NDEBUG + void **outstanding_tags; + size_t outstanding_tag_count; + size_t outstanding_tag_capacity; +#endif + + grpc_completion_queue *next_free; +}; + +#define POLLSET_FROM_CQ(cq) ((grpc_pollset *)(cq + 1)) + +static gpr_mu g_freelist_mu; +static grpc_completion_queue *g_freelist; + +static void on_pollset_shutdown_done(grpc_exec_ctx *exec_ctx, void *cc, + bool success); + +void grpc_cq_global_init(void) { gpr_mu_init(&g_freelist_mu); } + +void grpc_cq_global_shutdown(void) { + gpr_mu_destroy(&g_freelist_mu); + while (g_freelist) { + grpc_completion_queue *next = g_freelist->next_free; + grpc_pollset_destroy(POLLSET_FROM_CQ(g_freelist)); +#ifndef NDEBUG + gpr_free(g_freelist->outstanding_tags); +#endif + gpr_free(g_freelist); + g_freelist = next; + } +} + +struct grpc_cq_alarm { + grpc_timer alarm; + grpc_cq_completion completion; + /** completion queue where events about this alarm will be posted */ + grpc_completion_queue *cq; + /** user supplied tag */ + void *tag; +}; + +grpc_completion_queue *grpc_completion_queue_create(void *reserved) { + grpc_completion_queue *cc; + GPR_ASSERT(!reserved); + + GPR_TIMER_BEGIN("grpc_completion_queue_create", 0); + + GRPC_API_TRACE("grpc_completion_queue_create(reserved=%p)", 1, (reserved)); + + gpr_mu_lock(&g_freelist_mu); + if (g_freelist == NULL) { + gpr_mu_unlock(&g_freelist_mu); + + cc = gpr_malloc(sizeof(grpc_completion_queue) + grpc_pollset_size()); + grpc_pollset_init(POLLSET_FROM_CQ(cc), &cc->mu); +#ifndef NDEBUG + cc->outstanding_tags = NULL; + cc->outstanding_tag_capacity = 0; +#endif + } else { + cc = g_freelist; + g_freelist = g_freelist->next_free; + gpr_mu_unlock(&g_freelist_mu); + /* pollset already initialized */ + } + + /* Initial ref is dropped by grpc_completion_queue_shutdown */ + gpr_ref_init(&cc->pending_events, 1); + /* One for destroy(), one for pollset_shutdown */ + gpr_ref_init(&cc->owning_refs, 2); + cc->completed_tail = &cc->completed_head; + cc->completed_head.next = (uintptr_t)cc->completed_tail; + cc->shutdown = 0; + cc->shutdown_called = 0; + cc->is_server_cq = 0; + cc->num_pluckers = 0; +#ifndef NDEBUG + cc->outstanding_tag_count = 0; +#endif + grpc_closure_init(&cc->pollset_shutdown_done, on_pollset_shutdown_done, cc); + + GPR_TIMER_END("grpc_completion_queue_create", 0); + + return cc; +} + +#ifdef GRPC_CQ_REF_COUNT_DEBUG +void grpc_cq_internal_ref(grpc_completion_queue *cc, const char *reason, + const char *file, int line) { + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "CQ:%p ref %d -> %d %s", cc, + (int)cc->owning_refs.count, (int)cc->owning_refs.count + 1, reason); +#else +void grpc_cq_internal_ref(grpc_completion_queue *cc) { +#endif + gpr_ref(&cc->owning_refs); +} + +static void on_pollset_shutdown_done(grpc_exec_ctx *exec_ctx, void *arg, + bool success) { + grpc_completion_queue *cc = arg; + GRPC_CQ_INTERNAL_UNREF(cc, "pollset_destroy"); +} + +#ifdef GRPC_CQ_REF_COUNT_DEBUG +void grpc_cq_internal_unref(grpc_completion_queue *cc, const char *reason, + const char *file, int line) { + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "CQ:%p unref %d -> %d %s", cc, + (int)cc->owning_refs.count, (int)cc->owning_refs.count - 1, reason); +#else +void grpc_cq_internal_unref(grpc_completion_queue *cc) { +#endif + if (gpr_unref(&cc->owning_refs)) { + GPR_ASSERT(cc->completed_head.next == (uintptr_t)&cc->completed_head); + grpc_pollset_reset(POLLSET_FROM_CQ(cc)); + gpr_mu_lock(&g_freelist_mu); + cc->next_free = g_freelist; + g_freelist = cc; + gpr_mu_unlock(&g_freelist_mu); + } +} + +void grpc_cq_begin_op(grpc_completion_queue *cc, void *tag) { +#ifndef NDEBUG + gpr_mu_lock(cc->mu); + GPR_ASSERT(!cc->shutdown_called); + if (cc->outstanding_tag_count == cc->outstanding_tag_capacity) { + cc->outstanding_tag_capacity = GPR_MAX(4, 2 * cc->outstanding_tag_capacity); + cc->outstanding_tags = + gpr_realloc(cc->outstanding_tags, sizeof(*cc->outstanding_tags) * + cc->outstanding_tag_capacity); + } + cc->outstanding_tags[cc->outstanding_tag_count++] = tag; + gpr_mu_unlock(cc->mu); +#endif + gpr_ref(&cc->pending_events); +} + +/* Signal the end of an operation - if this is the last waiting-to-be-queued + event, then enter shutdown mode */ +/* Queue a GRPC_OP_COMPLETED operation */ +void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc, + void *tag, int success, + void (*done)(grpc_exec_ctx *exec_ctx, void *done_arg, + grpc_cq_completion *storage), + void *done_arg, grpc_cq_completion *storage) { + int shutdown; + int i; + grpc_pollset_worker *pluck_worker; +#ifndef NDEBUG + int found = 0; +#endif + + GPR_TIMER_BEGIN("grpc_cq_end_op", 0); + + storage->tag = tag; + storage->done = done; + storage->done_arg = done_arg; + storage->next = + ((uintptr_t)&cc->completed_head) | ((uintptr_t)(success != 0)); + + gpr_mu_lock(cc->mu); +#ifndef NDEBUG + for (i = 0; i < (int)cc->outstanding_tag_count; i++) { + if (cc->outstanding_tags[i] == tag) { + cc->outstanding_tag_count--; + GPR_SWAP(void *, cc->outstanding_tags[i], + cc->outstanding_tags[cc->outstanding_tag_count]); + found = 1; + break; + } + } + GPR_ASSERT(found); +#endif + shutdown = gpr_unref(&cc->pending_events); + if (!shutdown) { + cc->completed_tail->next = + ((uintptr_t)storage) | (1u & (uintptr_t)cc->completed_tail->next); + cc->completed_tail = storage; + pluck_worker = NULL; + for (i = 0; i < cc->num_pluckers; i++) { + if (cc->pluckers[i].tag == tag) { + pluck_worker = *cc->pluckers[i].worker; + break; + } + } + grpc_pollset_kick(POLLSET_FROM_CQ(cc), pluck_worker); + gpr_mu_unlock(cc->mu); + } else { + cc->completed_tail->next = + ((uintptr_t)storage) | (1u & (uintptr_t)cc->completed_tail->next); + cc->completed_tail = storage; + GPR_ASSERT(!cc->shutdown); + GPR_ASSERT(cc->shutdown_called); + cc->shutdown = 1; + grpc_pollset_shutdown(exec_ctx, POLLSET_FROM_CQ(cc), + &cc->pollset_shutdown_done); + gpr_mu_unlock(cc->mu); + } + + GPR_TIMER_END("grpc_cq_end_op", 0); +} + +grpc_event grpc_completion_queue_next(grpc_completion_queue *cc, + gpr_timespec deadline, void *reserved) { + grpc_event ret; + grpc_pollset_worker *worker = NULL; + int first_loop = 1; + gpr_timespec now; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + + GPR_TIMER_BEGIN("grpc_completion_queue_next", 0); + + GRPC_API_TRACE( + "grpc_completion_queue_next(" + "cc=%p, " + "deadline=gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, " + "reserved=%p)", + 5, (cc, (long long)deadline.tv_sec, (int)deadline.tv_nsec, + (int)deadline.clock_type, reserved)); + GPR_ASSERT(!reserved); + + deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC); + + GRPC_CQ_INTERNAL_REF(cc, "next"); + gpr_mu_lock(cc->mu); + for (;;) { + if (cc->completed_tail != &cc->completed_head) { + grpc_cq_completion *c = (grpc_cq_completion *)cc->completed_head.next; + cc->completed_head.next = c->next & ~(uintptr_t)1; + if (c == cc->completed_tail) { + cc->completed_tail = &cc->completed_head; + } + gpr_mu_unlock(cc->mu); + ret.type = GRPC_OP_COMPLETE; + ret.success = c->next & 1u; + ret.tag = c->tag; + c->done(&exec_ctx, c->done_arg, c); + break; + } + if (cc->shutdown) { + gpr_mu_unlock(cc->mu); + memset(&ret, 0, sizeof(ret)); + ret.type = GRPC_QUEUE_SHUTDOWN; + break; + } + now = gpr_now(GPR_CLOCK_MONOTONIC); + if (!first_loop && gpr_time_cmp(now, deadline) >= 0) { + gpr_mu_unlock(cc->mu); + memset(&ret, 0, sizeof(ret)); + ret.type = GRPC_QUEUE_TIMEOUT; + break; + } + first_loop = 0; + /* Check alarms - these are a global resource so we just ping + each time through on every pollset. + May update deadline to ensure timely wakeups. + TODO(ctiller): can this work be localized? */ + gpr_timespec iteration_deadline = deadline; + if (grpc_timer_check(&exec_ctx, now, &iteration_deadline)) { + GPR_TIMER_MARK("alarm_triggered", 0); + gpr_mu_unlock(cc->mu); + grpc_exec_ctx_flush(&exec_ctx); + gpr_mu_lock(cc->mu); + continue; + } else { + grpc_pollset_work(&exec_ctx, POLLSET_FROM_CQ(cc), &worker, now, + iteration_deadline); + } + } + GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret); + GRPC_CQ_INTERNAL_UNREF(cc, "next"); + grpc_exec_ctx_finish(&exec_ctx); + + GPR_TIMER_END("grpc_completion_queue_next", 0); + + return ret; +} + +static int add_plucker(grpc_completion_queue *cc, void *tag, + grpc_pollset_worker **worker) { + if (cc->num_pluckers == GRPC_MAX_COMPLETION_QUEUE_PLUCKERS) { + return 0; + } + cc->pluckers[cc->num_pluckers].tag = tag; + cc->pluckers[cc->num_pluckers].worker = worker; + cc->num_pluckers++; + return 1; +} + +static void del_plucker(grpc_completion_queue *cc, void *tag, + grpc_pollset_worker **worker) { + int i; + for (i = 0; i < cc->num_pluckers; i++) { + if (cc->pluckers[i].tag == tag && cc->pluckers[i].worker == worker) { + cc->num_pluckers--; + GPR_SWAP(plucker, cc->pluckers[i], cc->pluckers[cc->num_pluckers]); + return; + } + } + GPR_UNREACHABLE_CODE(return ); +} + +grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag, + gpr_timespec deadline, void *reserved) { + grpc_event ret; + grpc_cq_completion *c; + grpc_cq_completion *prev; + grpc_pollset_worker *worker = NULL; + gpr_timespec now; + int first_loop = 1; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + + GPR_TIMER_BEGIN("grpc_completion_queue_pluck", 0); + + GRPC_API_TRACE( + "grpc_completion_queue_pluck(" + "cc=%p, tag=%p, " + "deadline=gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, " + "reserved=%p)", + 6, (cc, tag, (long long)deadline.tv_sec, (int)deadline.tv_nsec, + (int)deadline.clock_type, reserved)); + GPR_ASSERT(!reserved); + + deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC); + + GRPC_CQ_INTERNAL_REF(cc, "pluck"); + gpr_mu_lock(cc->mu); + for (;;) { + prev = &cc->completed_head; + while ((c = (grpc_cq_completion *)(prev->next & ~(uintptr_t)1)) != + &cc->completed_head) { + if (c->tag == tag) { + prev->next = (prev->next & (uintptr_t)1) | (c->next & ~(uintptr_t)1); + if (c == cc->completed_tail) { + cc->completed_tail = prev; + } + gpr_mu_unlock(cc->mu); + ret.type = GRPC_OP_COMPLETE; + ret.success = c->next & 1u; + ret.tag = c->tag; + c->done(&exec_ctx, c->done_arg, c); + goto done; + } + prev = c; + } + if (cc->shutdown) { + gpr_mu_unlock(cc->mu); + memset(&ret, 0, sizeof(ret)); + ret.type = GRPC_QUEUE_SHUTDOWN; + break; + } + if (!add_plucker(cc, tag, &worker)) { + gpr_log(GPR_DEBUG, + "Too many outstanding grpc_completion_queue_pluck calls: maximum " + "is %d", + GRPC_MAX_COMPLETION_QUEUE_PLUCKERS); + gpr_mu_unlock(cc->mu); + memset(&ret, 0, sizeof(ret)); + /* TODO(ctiller): should we use a different result here */ + ret.type = GRPC_QUEUE_TIMEOUT; + break; + } + now = gpr_now(GPR_CLOCK_MONOTONIC); + if (!first_loop && gpr_time_cmp(now, deadline) >= 0) { + del_plucker(cc, tag, &worker); + gpr_mu_unlock(cc->mu); + memset(&ret, 0, sizeof(ret)); + ret.type = GRPC_QUEUE_TIMEOUT; + break; + } + first_loop = 0; + /* Check alarms - these are a global resource so we just ping + each time through on every pollset. + May update deadline to ensure timely wakeups. + TODO(ctiller): can this work be localized? */ + gpr_timespec iteration_deadline = deadline; + if (grpc_timer_check(&exec_ctx, now, &iteration_deadline)) { + GPR_TIMER_MARK("alarm_triggered", 0); + gpr_mu_unlock(cc->mu); + grpc_exec_ctx_flush(&exec_ctx); + gpr_mu_lock(cc->mu); + } else { + grpc_pollset_work(&exec_ctx, POLLSET_FROM_CQ(cc), &worker, now, + iteration_deadline); + } + del_plucker(cc, tag, &worker); + } +done: + GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret); + GRPC_CQ_INTERNAL_UNREF(cc, "pluck"); + grpc_exec_ctx_finish(&exec_ctx); + + GPR_TIMER_END("grpc_completion_queue_pluck", 0); + + return ret; +} + +/* Shutdown simply drops a ref that we reserved at creation time; if we drop + to zero here, then enter shutdown mode and wake up any waiters */ +void grpc_completion_queue_shutdown(grpc_completion_queue *cc) { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + GPR_TIMER_BEGIN("grpc_completion_queue_shutdown", 0); + GRPC_API_TRACE("grpc_completion_queue_shutdown(cc=%p)", 1, (cc)); + gpr_mu_lock(cc->mu); + if (cc->shutdown_called) { + gpr_mu_unlock(cc->mu); + GPR_TIMER_END("grpc_completion_queue_shutdown", 0); + return; + } + cc->shutdown_called = 1; + if (gpr_unref(&cc->pending_events)) { + GPR_ASSERT(!cc->shutdown); + cc->shutdown = 1; + grpc_pollset_shutdown(&exec_ctx, POLLSET_FROM_CQ(cc), + &cc->pollset_shutdown_done); + } + gpr_mu_unlock(cc->mu); + grpc_exec_ctx_finish(&exec_ctx); + GPR_TIMER_END("grpc_completion_queue_shutdown", 0); +} + +void grpc_completion_queue_destroy(grpc_completion_queue *cc) { + GRPC_API_TRACE("grpc_completion_queue_destroy(cc=%p)", 1, (cc)); + GPR_TIMER_BEGIN("grpc_completion_queue_destroy", 0); + grpc_completion_queue_shutdown(cc); + GRPC_CQ_INTERNAL_UNREF(cc, "destroy"); + GPR_TIMER_END("grpc_completion_queue_destroy", 0); +} + +grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cc) { + return POLLSET_FROM_CQ(cc); +} + +void grpc_cq_mark_server_cq(grpc_completion_queue *cc) { cc->is_server_cq = 1; } + +int grpc_cq_is_server_cq(grpc_completion_queue *cc) { return cc->is_server_cq; } diff --git a/src/core/lib/surface/completion_queue.h b/src/core/lib/surface/completion_queue.h new file mode 100644 index 0000000000..213d89c079 --- /dev/null +++ b/src/core/lib/surface/completion_queue.h @@ -0,0 +1,91 @@ +/* + * + * Copyright 2015-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_SURFACE_COMPLETION_QUEUE_H +#define GRPC_CORE_SURFACE_COMPLETION_QUEUE_H + +/* Internal API for completion queues */ + +#include +#include "src/core/iomgr/pollset.h" + +typedef struct grpc_cq_completion { + /** user supplied tag */ + void *tag; + /** done callback - called when this queue element is no longer + needed by the completion queue */ + void (*done)(grpc_exec_ctx *exec_ctx, void *done_arg, + struct grpc_cq_completion *c); + void *done_arg; + /** next pointer; low bit is used to indicate success or not */ + uintptr_t next; +} grpc_cq_completion; + +#ifdef GRPC_CQ_REF_COUNT_DEBUG +void grpc_cq_internal_ref(grpc_completion_queue *cc, const char *reason, + const char *file, int line); +void grpc_cq_internal_unref(grpc_completion_queue *cc, const char *reason, + const char *file, int line); +#define GRPC_CQ_INTERNAL_REF(cc, reason) \ + grpc_cq_internal_ref(cc, reason, __FILE__, __LINE__) +#define GRPC_CQ_INTERNAL_UNREF(cc, reason) \ + grpc_cq_internal_unref(cc, reason, __FILE__, __LINE__) +#else +void grpc_cq_internal_ref(grpc_completion_queue *cc); +void grpc_cq_internal_unref(grpc_completion_queue *cc); +#define GRPC_CQ_INTERNAL_REF(cc, reason) grpc_cq_internal_ref(cc) +#define GRPC_CQ_INTERNAL_UNREF(cc, reason) grpc_cq_internal_unref(cc) +#endif + +/* Flag that an operation is beginning: the completion channel will not finish + shutdown until a corrensponding grpc_cq_end_* call is made. + \a tag is currently used only in debug builds. */ +void grpc_cq_begin_op(grpc_completion_queue *cc, void *tag); + +/* Queue a GRPC_OP_COMPLETED operation; tag must correspond to the tag passed to + grpc_cq_begin_op */ +void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc, + void *tag, int success, + void (*done)(grpc_exec_ctx *exec_ctx, void *done_arg, + grpc_cq_completion *storage), + void *done_arg, grpc_cq_completion *storage); + +grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cc); + +void grpc_cq_mark_server_cq(grpc_completion_queue *cc); +int grpc_cq_is_server_cq(grpc_completion_queue *cc); + +void grpc_cq_global_init(void); +void grpc_cq_global_shutdown(void); + +#endif /* GRPC_CORE_SURFACE_COMPLETION_QUEUE_H */ diff --git a/src/core/lib/surface/event_string.c b/src/core/lib/surface/event_string.c new file mode 100644 index 0000000000..85a372b9ad --- /dev/null +++ b/src/core/lib/surface/event_string.c @@ -0,0 +1,81 @@ +/* + * + * Copyright 2015-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/surface/event_string.h" + +#include + +#include +#include +#include "src/core/support/string.h" + +static void addhdr(gpr_strvec *buf, grpc_event *ev) { + char *tmp; + gpr_asprintf(&tmp, "tag:%p", ev->tag); + gpr_strvec_add(buf, tmp); +} + +static const char *errstr(int success) { return success ? "OK" : "ERROR"; } + +static void adderr(gpr_strvec *buf, int success) { + char *tmp; + gpr_asprintf(&tmp, " %s", errstr(success)); + gpr_strvec_add(buf, tmp); +} + +char *grpc_event_string(grpc_event *ev) { + char *out; + gpr_strvec buf; + + if (ev == NULL) return gpr_strdup("null"); + + gpr_strvec_init(&buf); + + switch (ev->type) { + case GRPC_QUEUE_TIMEOUT: + gpr_strvec_add(&buf, gpr_strdup("QUEUE_TIMEOUT")); + break; + case GRPC_QUEUE_SHUTDOWN: + gpr_strvec_add(&buf, gpr_strdup("QUEUE_SHUTDOWN")); + break; + case GRPC_OP_COMPLETE: + gpr_strvec_add(&buf, gpr_strdup("OP_COMPLETE: ")); + addhdr(&buf, ev); + adderr(&buf, ev->success); + break; + } + + out = gpr_strvec_flatten(&buf, NULL); + gpr_strvec_destroy(&buf); + return out; +} diff --git a/src/core/lib/surface/event_string.h b/src/core/lib/surface/event_string.h new file mode 100644 index 0000000000..d0598cecca --- /dev/null +++ b/src/core/lib/surface/event_string.h @@ -0,0 +1,42 @@ +/* + * + * Copyright 2015-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_SURFACE_EVENT_STRING_H +#define GRPC_CORE_SURFACE_EVENT_STRING_H + +#include + +/* Returns a string describing an event. Must be later freed with gpr_free() */ +char *grpc_event_string(grpc_event *ev); + +#endif /* GRPC_CORE_SURFACE_EVENT_STRING_H */ diff --git a/src/core/lib/surface/init.c b/src/core/lib/surface/init.c new file mode 100644 index 0000000000..3c4db3e6cc --- /dev/null +++ b/src/core/lib/surface/init.c @@ -0,0 +1,239 @@ +/* + * + * Copyright 2015-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 + +#include +#include + +#include +#include +#include +/* TODO(ctiller): find another way? - better not to include census here */ +#include "src/core/census/grpc_plugin.h" +#include "src/core/channel/channel_stack.h" +#include "src/core/channel/client_channel.h" +#include "src/core/channel/compress_filter.h" +#include "src/core/channel/connected_channel.h" +#include "src/core/channel/http_client_filter.h" +#include "src/core/channel/http_server_filter.h" +#include "src/core/client_config/lb_policies/pick_first.h" +#include "src/core/client_config/lb_policies/round_robin.h" +#include "src/core/client_config/lb_policy_registry.h" +#include "src/core/client_config/resolver_registry.h" +#include "src/core/client_config/resolvers/dns_resolver.h" +#include "src/core/client_config/resolvers/sockaddr_resolver.h" +#include "src/core/client_config/subchannel.h" +#include "src/core/client_config/subchannel_index.h" +#include "src/core/debug/trace.h" +#include "src/core/iomgr/executor.h" +#include "src/core/iomgr/iomgr.h" +#include "src/core/profiling/timers.h" +#include "src/core/surface/api_trace.h" +#include "src/core/surface/call.h" +#include "src/core/surface/channel_init.h" +#include "src/core/surface/completion_queue.h" +#include "src/core/surface/init.h" +#include "src/core/surface/lame_client.h" +#include "src/core/surface/server.h" +#include "src/core/surface/surface_trace.h" +#include "src/core/transport/chttp2_transport.h" +#include "src/core/transport/connectivity_state.h" +#include "src/core/transport/transport_impl.h" + +#ifndef GRPC_DEFAULT_NAME_PREFIX +#define GRPC_DEFAULT_NAME_PREFIX "dns:///" +#endif + +#define MAX_PLUGINS 128 + +static gpr_once g_basic_init = GPR_ONCE_INIT; +static gpr_mu g_init_mu; +static int g_initializations; + +static void do_basic_init(void) { + gpr_mu_init(&g_init_mu); + /* TODO(ctiller): ideally remove this strict linkage */ + grpc_register_plugin(census_grpc_plugin_init, census_grpc_plugin_destroy); + g_initializations = 0; +} + +static bool append_filter(grpc_channel_stack_builder *builder, void *arg) { + return grpc_channel_stack_builder_append_filter( + builder, (const grpc_channel_filter *)arg, NULL, NULL); +} + +static bool prepend_filter(grpc_channel_stack_builder *builder, void *arg) { + return grpc_channel_stack_builder_prepend_filter( + builder, (const grpc_channel_filter *)arg, NULL, NULL); +} + +static bool maybe_add_http_filter(grpc_channel_stack_builder *builder, + void *arg) { + grpc_transport *t = grpc_channel_stack_builder_get_transport(builder); + if (t && strstr(t->vtable->name, "http")) { + return grpc_channel_stack_builder_prepend_filter( + builder, (const grpc_channel_filter *)arg, NULL, NULL); + } + return true; +} + +static void register_builtin_channel_init() { + grpc_channel_init_register_stage(GRPC_CLIENT_CHANNEL, INT_MAX, prepend_filter, + (void *)&grpc_compress_filter); + grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL, INT_MAX, + prepend_filter, + (void *)&grpc_compress_filter); + grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX, prepend_filter, + (void *)&grpc_compress_filter); + grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL, INT_MAX, + maybe_add_http_filter, + (void *)&grpc_http_client_filter); + grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL, INT_MAX, + grpc_add_connected_filter, NULL); + grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL, INT_MAX, + maybe_add_http_filter, + (void *)&grpc_http_client_filter); + grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL, INT_MAX, + grpc_add_connected_filter, NULL); + grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX, + maybe_add_http_filter, + (void *)&grpc_http_server_filter); + grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX, + grpc_add_connected_filter, NULL); + grpc_channel_init_register_stage(GRPC_CLIENT_CHANNEL, INT_MAX, append_filter, + (void *)&grpc_client_channel_filter); + grpc_channel_init_register_stage(GRPC_CLIENT_LAME_CHANNEL, INT_MAX, + append_filter, (void *)&grpc_lame_filter); + grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX, prepend_filter, + (void *)&grpc_server_top_filter); +} + +typedef struct grpc_plugin { + void (*init)(); + void (*destroy)(); +} grpc_plugin; + +static grpc_plugin g_all_of_the_plugins[MAX_PLUGINS]; +static int g_number_of_plugins = 0; + +void grpc_register_plugin(void (*init)(void), void (*destroy)(void)) { + GRPC_API_TRACE("grpc_register_plugin(init=%p, destroy=%p)", 2, + ((void *)(intptr_t)init, (void *)(intptr_t)destroy)); + GPR_ASSERT(g_number_of_plugins != MAX_PLUGINS); + g_all_of_the_plugins[g_number_of_plugins].init = init; + g_all_of_the_plugins[g_number_of_plugins].destroy = destroy; + g_number_of_plugins++; +} + +void grpc_init(void) { + int i; + gpr_once_init(&g_basic_init, do_basic_init); + + gpr_mu_lock(&g_init_mu); + if (++g_initializations == 1) { + gpr_time_init(); + grpc_mdctx_global_init(); + grpc_channel_init_init(); + grpc_lb_policy_registry_init(grpc_pick_first_lb_factory_create()); + grpc_register_lb_policy(grpc_pick_first_lb_factory_create()); + grpc_register_lb_policy(grpc_round_robin_lb_factory_create()); + grpc_resolver_registry_init(GRPC_DEFAULT_NAME_PREFIX); + grpc_register_resolver_type(grpc_dns_resolver_factory_create()); + grpc_register_resolver_type(grpc_ipv4_resolver_factory_create()); + grpc_register_resolver_type(grpc_ipv6_resolver_factory_create()); +#ifdef GPR_POSIX_SOCKET + grpc_register_resolver_type(grpc_unix_resolver_factory_create()); +#endif + grpc_register_tracer("api", &grpc_api_trace); + grpc_register_tracer("channel", &grpc_trace_channel); + grpc_register_tracer("http", &grpc_http_trace); + grpc_register_tracer("flowctl", &grpc_flowctl_trace); + grpc_register_tracer("connectivity_state", &grpc_connectivity_state_trace); + grpc_register_tracer("channel_stack_builder", + &grpc_trace_channel_stack_builder); + grpc_security_pre_init(); + grpc_iomgr_init(); + grpc_executor_init(); + grpc_tracer_init("GRPC_TRACE"); + gpr_timers_global_init(); + grpc_cq_global_init(); + grpc_subchannel_index_init(); + for (i = 0; i < g_number_of_plugins; i++) { + if (g_all_of_the_plugins[i].init != NULL) { + g_all_of_the_plugins[i].init(); + } + } + /* register channel finalization AFTER all plugins, to ensure that it's run + * at the appropriate time */ + grpc_register_security_filters(); + register_builtin_channel_init(); + /* no more changes to channel init pipelines */ + grpc_channel_init_finalize(); + } + gpr_mu_unlock(&g_init_mu); + GRPC_API_TRACE("grpc_init(void)", 0, ()); +} + +void grpc_shutdown(void) { + int i; + GRPC_API_TRACE("grpc_shutdown(void)", 0, ()); + gpr_mu_lock(&g_init_mu); + if (--g_initializations == 0) { + grpc_executor_shutdown(); + grpc_cq_global_shutdown(); + grpc_iomgr_shutdown(); + grpc_subchannel_index_shutdown(); + gpr_timers_global_destroy(); + grpc_tracer_shutdown(); + grpc_resolver_registry_shutdown(); + grpc_lb_policy_registry_shutdown(); + for (i = 0; i < g_number_of_plugins; i++) { + if (g_all_of_the_plugins[i].destroy != NULL) { + g_all_of_the_plugins[i].destroy(); + } + } + grpc_channel_init_shutdown(); + grpc_mdctx_global_shutdown(); + } + gpr_mu_unlock(&g_init_mu); +} + +int grpc_is_initialized(void) { + int r; + gpr_once_init(&g_basic_init, do_basic_init); + gpr_mu_lock(&g_init_mu); + r = g_initializations > 0; + gpr_mu_unlock(&g_init_mu); + return r; +} diff --git a/src/core/lib/surface/init.h b/src/core/lib/surface/init.h new file mode 100644 index 0000000000..5e358c7022 --- /dev/null +++ b/src/core/lib/surface/init.h @@ -0,0 +1,41 @@ +/* + * + * Copyright 2015-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_SURFACE_INIT_H +#define GRPC_CORE_SURFACE_INIT_H + +void grpc_register_security_filters(void); +void grpc_security_pre_init(void); +int grpc_is_initialized(void); + +#endif /* GRPC_CORE_SURFACE_INIT_H */ diff --git a/src/core/lib/surface/init_secure.c b/src/core/lib/surface/init_secure.c new file mode 100644 index 0000000000..e0d66a8d46 --- /dev/null +++ b/src/core/lib/surface/init_secure.c @@ -0,0 +1,89 @@ +/* + * + * Copyright 2015-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/surface/init.h" + +#include +#include + +#include "src/core/debug/trace.h" +#include "src/core/security/auth_filters.h" +#include "src/core/security/credentials.h" +#include "src/core/security/secure_endpoint.h" +#include "src/core/security/security_connector.h" +#include "src/core/surface/channel_init.h" +#include "src/core/tsi/transport_security_interface.h" + +void grpc_security_pre_init(void) { + grpc_register_tracer("secure_endpoint", &grpc_trace_secure_endpoint); + grpc_register_tracer("transport_security", &tsi_tracing_enabled); +} + +static bool maybe_prepend_client_auth_filter( + grpc_channel_stack_builder *builder, void *arg) { + const grpc_channel_args *args = + grpc_channel_stack_builder_get_channel_arguments(builder); + if (args) { + for (size_t i = 0; i < args->num_args; i++) { + if (0 == strcmp(GRPC_SECURITY_CONNECTOR_ARG, args->args[i].key)) { + return grpc_channel_stack_builder_prepend_filter( + builder, &grpc_client_auth_filter, NULL, NULL); + } + } + } + return true; +} + +static bool maybe_prepend_server_auth_filter( + grpc_channel_stack_builder *builder, void *arg) { + const grpc_channel_args *args = + grpc_channel_stack_builder_get_channel_arguments(builder); + if (args) { + for (size_t i = 0; i < args->num_args; i++) { + if (0 == strcmp(GRPC_SERVER_CREDENTIALS_ARG, args->args[i].key)) { + return grpc_channel_stack_builder_prepend_filter( + builder, &grpc_server_auth_filter, NULL, NULL); + } + } + } + return true; +} + +void grpc_register_security_filters(void) { + grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL, INT_MAX, + maybe_prepend_client_auth_filter, NULL); + grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL, INT_MAX, + maybe_prepend_client_auth_filter, NULL); + grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX, + maybe_prepend_server_auth_filter, NULL); +} diff --git a/src/core/lib/surface/init_unsecure.c b/src/core/lib/surface/init_unsecure.c new file mode 100644 index 0000000000..278fcc83ac --- /dev/null +++ b/src/core/lib/surface/init_unsecure.c @@ -0,0 +1,38 @@ +/* + * + * Copyright 2015-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/surface/init.h" + +void grpc_security_pre_init(void) {} + +void grpc_register_security_filters(void) {} diff --git a/src/core/lib/surface/lame_client.c b/src/core/lib/surface/lame_client.c new file mode 100644 index 0000000000..25f3a74349 --- /dev/null +++ b/src/core/lib/surface/lame_client.c @@ -0,0 +1,155 @@ +/* + * + * Copyright 2015-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/surface/lame_client.h" + +#include + +#include + +#include +#include +#include "src/core/channel/channel_stack.h" +#include "src/core/support/string.h" +#include "src/core/surface/api_trace.h" +#include "src/core/surface/call.h" +#include "src/core/surface/channel.h" + +typedef struct { + grpc_linked_mdelem status; + grpc_linked_mdelem details; +} call_data; + +typedef struct { + grpc_status_code error_code; + const char *error_message; +} channel_data; + +static void fill_metadata(grpc_call_element *elem, grpc_metadata_batch *mdb) { + call_data *calld = elem->call_data; + channel_data *chand = elem->channel_data; + char tmp[GPR_LTOA_MIN_BUFSIZE]; + gpr_ltoa(chand->error_code, tmp); + calld->status.md = grpc_mdelem_from_strings("grpc-status", tmp); + calld->details.md = + grpc_mdelem_from_strings("grpc-message", chand->error_message); + calld->status.prev = calld->details.next = NULL; + calld->status.next = &calld->details; + calld->details.prev = &calld->status; + mdb->list.head = &calld->status; + mdb->list.tail = &calld->details; + mdb->deadline = gpr_inf_future(GPR_CLOCK_REALTIME); +} + +static void lame_start_transport_stream_op(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + grpc_transport_stream_op *op) { + GRPC_CALL_LOG_OP(GPR_INFO, elem, op); + if (op->recv_initial_metadata != NULL) { + fill_metadata(elem, op->recv_initial_metadata); + } else if (op->recv_trailing_metadata != NULL) { + fill_metadata(elem, op->recv_trailing_metadata); + } + grpc_transport_stream_op_finish_with_failure(exec_ctx, op); +} + +static char *lame_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) { + return NULL; +} + +static void lame_start_transport_op(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem, + grpc_transport_op *op) { + if (op->on_connectivity_state_change) { + GPR_ASSERT(*op->connectivity_state != GRPC_CHANNEL_FATAL_FAILURE); + *op->connectivity_state = GRPC_CHANNEL_FATAL_FAILURE; + op->on_connectivity_state_change->cb( + exec_ctx, op->on_connectivity_state_change->cb_arg, 1); + } + if (op->on_consumed != NULL) { + op->on_consumed->cb(exec_ctx, op->on_consumed->cb_arg, 1); + } +} + +static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + grpc_call_element_args *args) {} + +static void destroy_call_elem(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem) {} + +static void init_channel_elem(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem, + grpc_channel_element_args *args) { + GPR_ASSERT(args->is_first); + GPR_ASSERT(args->is_last); +} + +static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem) {} + +const grpc_channel_filter grpc_lame_filter = { + lame_start_transport_stream_op, + lame_start_transport_op, + sizeof(call_data), + init_call_elem, + grpc_call_stack_ignore_set_pollset, + destroy_call_elem, + sizeof(channel_data), + init_channel_elem, + destroy_channel_elem, + lame_get_peer, + "lame-client", +}; + +#define CHANNEL_STACK_FROM_CHANNEL(c) ((grpc_channel_stack *)((c) + 1)) + +grpc_channel *grpc_lame_client_channel_create(const char *target, + grpc_status_code error_code, + const char *error_message) { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_channel_element *elem; + channel_data *chand; + grpc_channel *channel = grpc_channel_create(&exec_ctx, target, NULL, + GRPC_CLIENT_LAME_CHANNEL, NULL); + elem = grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0); + GRPC_API_TRACE( + "grpc_lame_client_channel_create(target=%s, error_code=%d, " + "error_message=%s)", + 3, (target, (int)error_code, error_message)); + GPR_ASSERT(elem->filter == &grpc_lame_filter); + chand = (channel_data *)elem->channel_data; + chand->error_code = error_code; + chand->error_message = error_message; + grpc_exec_ctx_finish(&exec_ctx); + return channel; +} diff --git a/src/core/lib/surface/lame_client.h b/src/core/lib/surface/lame_client.h new file mode 100644 index 0000000000..3f3abd2ffe --- /dev/null +++ b/src/core/lib/surface/lame_client.h @@ -0,0 +1,41 @@ +/* + * + * 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_SURFACE_LAME_CLIENT_H +#define GRPC_CORE_SURFACE_LAME_CLIENT_H + +#include "src/core/channel/channel_stack.h" + +extern const grpc_channel_filter grpc_lame_filter; + +#endif /* GRPC_CORE_SURFACE_LAME_CLIENT_H */ diff --git a/src/core/lib/surface/metadata_array.c b/src/core/lib/surface/metadata_array.c new file mode 100644 index 0000000000..4c7bf17835 --- /dev/null +++ b/src/core/lib/surface/metadata_array.c @@ -0,0 +1,49 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include + +#include + +#include "src/core/surface/api_trace.h" + +void grpc_metadata_array_init(grpc_metadata_array* array) { + GRPC_API_TRACE("grpc_metadata_array_init(array=%p)", 1, (array)); + memset(array, 0, sizeof(*array)); +} + +void grpc_metadata_array_destroy(grpc_metadata_array* array) { + GRPC_API_TRACE("grpc_metadata_array_destroy(array=%p)", 1, (array)); + gpr_free(array->metadata); +} diff --git a/src/core/lib/surface/secure_channel_create.c b/src/core/lib/surface/secure_channel_create.c new file mode 100644 index 0000000000..cc752227ee --- /dev/null +++ b/src/core/lib/surface/secure_channel_create.c @@ -0,0 +1,319 @@ +/* + * + * Copyright 2015-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 + +#include +#include + +#include +#include +#include + +#include "src/core/channel/channel_args.h" +#include "src/core/channel/client_channel.h" +#include "src/core/client_config/resolver_registry.h" +#include "src/core/iomgr/tcp_client.h" +#include "src/core/security/auth_filters.h" +#include "src/core/security/credentials.h" +#include "src/core/security/security_context.h" +#include "src/core/surface/api_trace.h" +#include "src/core/surface/channel.h" +#include "src/core/transport/chttp2_transport.h" +#include "src/core/tsi/transport_security_interface.h" + +typedef struct { + grpc_connector base; + gpr_refcount refs; + + grpc_channel_security_connector *security_connector; + + grpc_closure *notify; + grpc_connect_in_args args; + grpc_connect_out_args *result; + grpc_closure initial_string_sent; + gpr_slice_buffer initial_string_buffer; + + gpr_mu mu; + grpc_endpoint *connecting_endpoint; + grpc_endpoint *newly_connecting_endpoint; + + grpc_closure connected_closure; +} connector; + +static void connector_ref(grpc_connector *con) { + connector *c = (connector *)con; + gpr_ref(&c->refs); +} + +static void connector_unref(grpc_exec_ctx *exec_ctx, grpc_connector *con) { + connector *c = (connector *)con; + if (gpr_unref(&c->refs)) { + /* c->initial_string_buffer does not need to be destroyed */ + gpr_free(c); + } +} + +static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *arg, + grpc_security_status status, + grpc_endpoint *secure_endpoint, + grpc_auth_context *auth_context) { + connector *c = arg; + grpc_closure *notify; + grpc_channel_args *args_copy = NULL; + gpr_mu_lock(&c->mu); + if (c->connecting_endpoint == NULL) { + memset(c->result, 0, sizeof(*c->result)); + gpr_mu_unlock(&c->mu); + } else if (status != GRPC_SECURITY_OK) { + gpr_log(GPR_ERROR, "Secure handshake failed with error %d.", status); + memset(c->result, 0, sizeof(*c->result)); + c->connecting_endpoint = NULL; + gpr_mu_unlock(&c->mu); + } else { + grpc_arg auth_context_arg; + c->connecting_endpoint = NULL; + gpr_mu_unlock(&c->mu); + c->result->transport = grpc_create_chttp2_transport( + exec_ctx, c->args.channel_args, secure_endpoint, 1); + grpc_chttp2_transport_start_reading(exec_ctx, c->result->transport, NULL, + 0); + auth_context_arg = grpc_auth_context_to_arg(auth_context); + args_copy = grpc_channel_args_copy_and_add(c->args.channel_args, + &auth_context_arg, 1); + c->result->channel_args = args_copy; + } + notify = c->notify; + c->notify = NULL; + /* look at c->args which are connector args. */ + notify->cb(exec_ctx, notify->cb_arg, 1); + if (args_copy != NULL) grpc_channel_args_destroy(args_copy); +} + +static void on_initial_connect_string_sent(grpc_exec_ctx *exec_ctx, void *arg, + bool success) { + connector *c = arg; + grpc_channel_security_connector_do_handshake(exec_ctx, c->security_connector, + c->connecting_endpoint, + on_secure_handshake_done, c); +} + +static void connected(grpc_exec_ctx *exec_ctx, void *arg, bool success) { + connector *c = arg; + grpc_closure *notify; + grpc_endpoint *tcp = c->newly_connecting_endpoint; + if (tcp != NULL) { + gpr_mu_lock(&c->mu); + GPR_ASSERT(c->connecting_endpoint == NULL); + c->connecting_endpoint = tcp; + gpr_mu_unlock(&c->mu); + if (!GPR_SLICE_IS_EMPTY(c->args.initial_connect_string)) { + grpc_closure_init(&c->initial_string_sent, on_initial_connect_string_sent, + c); + gpr_slice_buffer_init(&c->initial_string_buffer); + gpr_slice_buffer_add(&c->initial_string_buffer, + c->args.initial_connect_string); + grpc_endpoint_write(exec_ctx, tcp, &c->initial_string_buffer, + &c->initial_string_sent); + } else { + grpc_channel_security_connector_do_handshake( + exec_ctx, c->security_connector, tcp, on_secure_handshake_done, c); + } + } else { + memset(c->result, 0, sizeof(*c->result)); + notify = c->notify; + c->notify = NULL; + notify->cb(exec_ctx, notify->cb_arg, 1); + } +} + +static void connector_shutdown(grpc_exec_ctx *exec_ctx, grpc_connector *con) { + connector *c = (connector *)con; + grpc_endpoint *ep; + gpr_mu_lock(&c->mu); + ep = c->connecting_endpoint; + c->connecting_endpoint = NULL; + gpr_mu_unlock(&c->mu); + if (ep) { + grpc_endpoint_shutdown(exec_ctx, ep); + } +} + +static void connector_connect(grpc_exec_ctx *exec_ctx, grpc_connector *con, + const grpc_connect_in_args *args, + grpc_connect_out_args *result, + grpc_closure *notify) { + connector *c = (connector *)con; + GPR_ASSERT(c->notify == NULL); + GPR_ASSERT(notify->cb); + c->notify = notify; + c->args = *args; + c->result = result; + gpr_mu_lock(&c->mu); + GPR_ASSERT(c->connecting_endpoint == NULL); + gpr_mu_unlock(&c->mu); + grpc_closure_init(&c->connected_closure, connected, c); + grpc_tcp_client_connect( + exec_ctx, &c->connected_closure, &c->newly_connecting_endpoint, + args->interested_parties, args->addr, args->addr_len, args->deadline); +} + +static const grpc_connector_vtable connector_vtable = { + connector_ref, connector_unref, connector_shutdown, connector_connect}; + +typedef struct { + grpc_subchannel_factory base; + gpr_refcount refs; + grpc_channel_args *merge_args; + grpc_channel_security_connector *security_connector; + grpc_channel *master; +} subchannel_factory; + +static void subchannel_factory_ref(grpc_subchannel_factory *scf) { + subchannel_factory *f = (subchannel_factory *)scf; + gpr_ref(&f->refs); +} + +static void subchannel_factory_unref(grpc_exec_ctx *exec_ctx, + grpc_subchannel_factory *scf) { + subchannel_factory *f = (subchannel_factory *)scf; + if (gpr_unref(&f->refs)) { + GRPC_SECURITY_CONNECTOR_UNREF(&f->security_connector->base, + "subchannel_factory"); + GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, f->master, "subchannel_factory"); + grpc_channel_args_destroy(f->merge_args); + gpr_free(f); + } +} + +static grpc_subchannel *subchannel_factory_create_subchannel( + grpc_exec_ctx *exec_ctx, grpc_subchannel_factory *scf, + grpc_subchannel_args *args) { + subchannel_factory *f = (subchannel_factory *)scf; + connector *c = gpr_malloc(sizeof(*c)); + grpc_channel_args *final_args = + grpc_channel_args_merge(args->args, f->merge_args); + grpc_subchannel *s; + memset(c, 0, sizeof(*c)); + c->base.vtable = &connector_vtable; + c->security_connector = f->security_connector; + gpr_mu_init(&c->mu); + gpr_ref_init(&c->refs, 1); + args->args = final_args; + s = grpc_subchannel_create(exec_ctx, &c->base, args); + grpc_connector_unref(exec_ctx, &c->base); + grpc_channel_args_destroy(final_args); + return s; +} + +static const grpc_subchannel_factory_vtable subchannel_factory_vtable = { + subchannel_factory_ref, subchannel_factory_unref, + subchannel_factory_create_subchannel}; + +/* Create a secure client channel: + Asynchronously: - resolve target + - connect to it (trying alternatives as presented) + - perform handshakes */ +grpc_channel *grpc_secure_channel_create(grpc_channel_credentials *creds, + const char *target, + const grpc_channel_args *args, + void *reserved) { + grpc_channel *channel; + grpc_arg connector_arg; + grpc_channel_args *args_copy; + grpc_channel_args *new_args_from_connector; + grpc_channel_security_connector *security_connector; + grpc_resolver *resolver; + subchannel_factory *f; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + + GRPC_API_TRACE( + "grpc_secure_channel_create(creds=%p, target=%s, args=%p, " + "reserved=%p)", + 4, (creds, target, args, reserved)); + GPR_ASSERT(reserved == NULL); + + if (grpc_find_security_connector_in_args(args) != NULL) { + gpr_log(GPR_ERROR, "Cannot set security context in channel args."); + grpc_exec_ctx_finish(&exec_ctx); + return grpc_lame_client_channel_create( + target, GRPC_STATUS_INVALID_ARGUMENT, + "Security connector exists in channel args."); + } + + if (grpc_channel_credentials_create_security_connector( + creds, target, args, &security_connector, &new_args_from_connector) != + GRPC_SECURITY_OK) { + grpc_exec_ctx_finish(&exec_ctx); + return grpc_lame_client_channel_create( + target, GRPC_STATUS_INVALID_ARGUMENT, + "Failed to create security connector."); + } + + connector_arg = grpc_security_connector_to_arg(&security_connector->base); + args_copy = grpc_channel_args_copy_and_add( + new_args_from_connector != NULL ? new_args_from_connector : args, + &connector_arg, 1); + + channel = grpc_channel_create(&exec_ctx, target, args_copy, + GRPC_CLIENT_CHANNEL, NULL); + + f = gpr_malloc(sizeof(*f)); + f->base.vtable = &subchannel_factory_vtable; + gpr_ref_init(&f->refs, 1); + GRPC_SECURITY_CONNECTOR_REF(&security_connector->base, "subchannel_factory"); + f->security_connector = security_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) { + grpc_client_channel_set_resolver( + &exec_ctx, grpc_channel_get_channel_stack(channel), resolver); + GRPC_RESOLVER_UNREF(&exec_ctx, resolver, "create"); + } + grpc_subchannel_factory_unref(&exec_ctx, &f->base); + GRPC_SECURITY_CONNECTOR_UNREF(&security_connector->base, "channel_create"); + grpc_channel_args_destroy(args_copy); + if (new_args_from_connector != NULL) { + grpc_channel_args_destroy(new_args_from_connector); + } + + if (!resolver) { + GRPC_CHANNEL_INTERNAL_UNREF(&exec_ctx, channel, "subchannel_factory"); + channel = NULL; + } + grpc_exec_ctx_finish(&exec_ctx); + + return channel; +} diff --git a/src/core/lib/surface/server.c b/src/core/lib/surface/server.c new file mode 100644 index 0000000000..a92f2b3e38 --- /dev/null +++ b/src/core/lib/surface/server.c @@ -0,0 +1,1319 @@ +/* + * + * Copyright 2015-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/surface/server.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include "src/core/channel/channel_args.h" +#include "src/core/channel/connected_channel.h" +#include "src/core/iomgr/iomgr.h" +#include "src/core/support/stack_lockfree.h" +#include "src/core/support/string.h" +#include "src/core/surface/api_trace.h" +#include "src/core/surface/call.h" +#include "src/core/surface/channel.h" +#include "src/core/surface/completion_queue.h" +#include "src/core/surface/init.h" +#include "src/core/transport/metadata.h" +#include "src/core/transport/static_metadata.h" + +typedef struct listener { + void *arg; + void (*start)(grpc_exec_ctx *exec_ctx, grpc_server *server, void *arg, + grpc_pollset **pollsets, size_t pollset_count); + void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_server *server, void *arg, + grpc_closure *closure); + struct listener *next; + grpc_closure destroy_done; +} listener; + +typedef struct call_data call_data; +typedef struct channel_data channel_data; +typedef struct registered_method registered_method; + +typedef struct { + call_data *next; + call_data *prev; +} call_link; + +typedef enum { BATCH_CALL, REGISTERED_CALL } requested_call_type; + +typedef struct requested_call { + requested_call_type type; + void *tag; + grpc_server *server; + grpc_completion_queue *cq_bound_to_call; + grpc_completion_queue *cq_for_notification; + grpc_call **call; + grpc_cq_completion completion; + grpc_metadata_array *initial_metadata; + union { + struct { + grpc_call_details *details; + } batch; + struct { + registered_method *registered_method; + gpr_timespec *deadline; + grpc_byte_buffer **optional_payload; + } registered; + } data; + grpc_closure publish; +} requested_call; + +typedef struct channel_registered_method { + registered_method *server_registered_method; + grpc_mdstr *method; + grpc_mdstr *host; +} channel_registered_method; + +struct channel_data { + grpc_server *server; + grpc_connectivity_state connectivity_state; + grpc_channel *channel; + /* linked list of all channels on a server */ + channel_data *next; + channel_data *prev; + channel_registered_method *registered_methods; + uint32_t registered_method_slots; + uint32_t registered_method_max_probes; + grpc_closure finish_destroy_channel_closure; + grpc_closure channel_connectivity_changed; +}; + +typedef struct shutdown_tag { + void *tag; + grpc_completion_queue *cq; + grpc_cq_completion completion; +} shutdown_tag; + +typedef enum { + /* waiting for metadata */ + NOT_STARTED, + /* inital metadata read, not flow controlled in yet */ + PENDING, + /* flow controlled in, on completion queue */ + ACTIVATED, + /* cancelled before being queued */ + ZOMBIED +} call_state; + +typedef struct request_matcher request_matcher; + +struct call_data { + grpc_call *call; + + /** protects state */ + gpr_mu mu_state; + /** the current state of a call - see call_state */ + call_state state; + + grpc_mdstr *path; + grpc_mdstr *host; + gpr_timespec deadline; + + grpc_completion_queue *cq_new; + + grpc_metadata_batch *recv_initial_metadata; + grpc_metadata_array initial_metadata; + + grpc_closure got_initial_metadata; + grpc_closure server_on_recv_initial_metadata; + grpc_closure kill_zombie_closure; + grpc_closure *on_done_recv_initial_metadata; + + call_data *pending_next; +}; + +struct request_matcher { + call_data *pending_head; + call_data *pending_tail; + gpr_stack_lockfree *requests; +}; + +struct registered_method { + char *method; + char *host; + request_matcher request_matcher; + registered_method *next; +}; + +typedef struct { + grpc_channel **channels; + size_t num_channels; +} channel_broadcaster; + +struct grpc_server { + grpc_channel_args *channel_args; + + grpc_completion_queue **cqs; + grpc_pollset **pollsets; + size_t cq_count; + + /* The two following mutexes control access to server-state + mu_global controls access to non-call-related state (e.g., channel state) + mu_call controls access to call-related state (e.g., the call lists) + + If they are ever required to be nested, you must lock mu_global + before mu_call. This is currently used in shutdown processing + (grpc_server_shutdown_and_notify and maybe_finish_shutdown) */ + gpr_mu mu_global; /* mutex for server and channel state */ + gpr_mu mu_call; /* mutex for call-specific state */ + + registered_method *registered_methods; + request_matcher unregistered_request_matcher; + /** free list of available requested_calls indices */ + gpr_stack_lockfree *request_freelist; + /** requested call backing data */ + requested_call *requested_calls; + size_t max_requested_calls; + + gpr_atm shutdown_flag; + uint8_t shutdown_published; + size_t num_shutdown_tags; + shutdown_tag *shutdown_tags; + + channel_data root_channel_data; + + listener *listeners; + int listeners_destroyed; + gpr_refcount internal_refcount; + + /** when did we print the last shutdown progress message */ + gpr_timespec last_shutdown_message_time; +}; + +#define SERVER_FROM_CALL_ELEM(elem) \ + (((channel_data *)(elem)->channel_data)->server) + +static void begin_call(grpc_exec_ctx *exec_ctx, grpc_server *server, + call_data *calld, requested_call *rc); +static void fail_call(grpc_exec_ctx *exec_ctx, grpc_server *server, + requested_call *rc); +/* Before calling maybe_finish_shutdown, we must hold mu_global and not + hold mu_call */ +static void maybe_finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_server *server); + +/* + * channel broadcaster + */ + +/* assumes server locked */ +static void channel_broadcaster_init(grpc_server *s, channel_broadcaster *cb) { + channel_data *c; + size_t count = 0; + for (c = s->root_channel_data.next; c != &s->root_channel_data; c = c->next) { + count++; + } + cb->num_channels = count; + cb->channels = gpr_malloc(sizeof(*cb->channels) * cb->num_channels); + count = 0; + for (c = s->root_channel_data.next; c != &s->root_channel_data; c = c->next) { + cb->channels[count++] = c->channel; + GRPC_CHANNEL_INTERNAL_REF(c->channel, "broadcast"); + } +} + +struct shutdown_cleanup_args { + grpc_closure closure; + gpr_slice slice; +}; + +static void shutdown_cleanup(grpc_exec_ctx *exec_ctx, void *arg, + bool iomgr_status_ignored) { + struct shutdown_cleanup_args *a = arg; + gpr_slice_unref(a->slice); + gpr_free(a); +} + +static void send_shutdown(grpc_exec_ctx *exec_ctx, grpc_channel *channel, + int send_goaway, int send_disconnect) { + grpc_transport_op op; + struct shutdown_cleanup_args *sc; + grpc_channel_element *elem; + + memset(&op, 0, sizeof(op)); + op.send_goaway = send_goaway; + sc = gpr_malloc(sizeof(*sc)); + sc->slice = gpr_slice_from_copied_string("Server shutdown"); + op.goaway_message = &sc->slice; + op.goaway_status = GRPC_STATUS_OK; + op.disconnect = send_disconnect; + grpc_closure_init(&sc->closure, shutdown_cleanup, sc); + op.on_consumed = &sc->closure; + + elem = grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0); + elem->filter->start_transport_op(exec_ctx, elem, &op); +} + +static void channel_broadcaster_shutdown(grpc_exec_ctx *exec_ctx, + channel_broadcaster *cb, + int send_goaway, + int force_disconnect) { + size_t i; + + for (i = 0; i < cb->num_channels; i++) { + send_shutdown(exec_ctx, cb->channels[i], send_goaway, force_disconnect); + GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, cb->channels[i], "broadcast"); + } + gpr_free(cb->channels); +} + +/* + * request_matcher + */ + +static void request_matcher_init(request_matcher *rm, size_t entries) { + memset(rm, 0, sizeof(*rm)); + rm->requests = gpr_stack_lockfree_create(entries); +} + +static void request_matcher_destroy(request_matcher *rm) { + GPR_ASSERT(gpr_stack_lockfree_pop(rm->requests) == -1); + gpr_stack_lockfree_destroy(rm->requests); +} + +static void kill_zombie(grpc_exec_ctx *exec_ctx, void *elem, bool success) { + grpc_call_destroy(grpc_call_from_top_element(elem)); +} + +static void request_matcher_zombify_all_pending_calls(grpc_exec_ctx *exec_ctx, + request_matcher *rm) { + while (rm->pending_head) { + call_data *calld = rm->pending_head; + rm->pending_head = calld->pending_next; + gpr_mu_lock(&calld->mu_state); + calld->state = ZOMBIED; + gpr_mu_unlock(&calld->mu_state); + grpc_closure_init( + &calld->kill_zombie_closure, kill_zombie, + grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0)); + grpc_exec_ctx_enqueue(exec_ctx, &calld->kill_zombie_closure, true, NULL); + } +} + +static void request_matcher_kill_requests(grpc_exec_ctx *exec_ctx, + grpc_server *server, + request_matcher *rm) { + int request_id; + while ((request_id = gpr_stack_lockfree_pop(rm->requests)) != -1) { + fail_call(exec_ctx, server, &server->requested_calls[request_id]); + } +} + +/* + * server proper + */ + +static void server_ref(grpc_server *server) { + gpr_ref(&server->internal_refcount); +} + +static void server_delete(grpc_exec_ctx *exec_ctx, grpc_server *server) { + registered_method *rm; + size_t i; + grpc_channel_args_destroy(server->channel_args); + gpr_mu_destroy(&server->mu_global); + gpr_mu_destroy(&server->mu_call); + while ((rm = server->registered_methods) != NULL) { + server->registered_methods = rm->next; + request_matcher_destroy(&rm->request_matcher); + gpr_free(rm->method); + gpr_free(rm->host); + gpr_free(rm); + } + for (i = 0; i < server->cq_count; i++) { + GRPC_CQ_INTERNAL_UNREF(server->cqs[i], "server"); + } + request_matcher_destroy(&server->unregistered_request_matcher); + gpr_stack_lockfree_destroy(server->request_freelist); + gpr_free(server->cqs); + gpr_free(server->pollsets); + gpr_free(server->shutdown_tags); + gpr_free(server->requested_calls); + gpr_free(server); +} + +static void server_unref(grpc_exec_ctx *exec_ctx, grpc_server *server) { + if (gpr_unref(&server->internal_refcount)) { + server_delete(exec_ctx, server); + } +} + +static int is_channel_orphaned(channel_data *chand) { + return chand->next == chand; +} + +static void orphan_channel(channel_data *chand) { + chand->next->prev = chand->prev; + chand->prev->next = chand->next; + chand->next = chand->prev = chand; +} + +static void finish_destroy_channel(grpc_exec_ctx *exec_ctx, void *cd, + bool success) { + channel_data *chand = cd; + grpc_server *server = chand->server; + GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, chand->channel, "server"); + server_unref(exec_ctx, server); +} + +static void destroy_channel(grpc_exec_ctx *exec_ctx, channel_data *chand) { + if (is_channel_orphaned(chand)) return; + GPR_ASSERT(chand->server != NULL); + orphan_channel(chand); + server_ref(chand->server); + maybe_finish_shutdown(exec_ctx, chand->server); + chand->finish_destroy_channel_closure.cb = finish_destroy_channel; + chand->finish_destroy_channel_closure.cb_arg = chand; + + grpc_transport_op op; + memset(&op, 0, sizeof(op)); + op.set_accept_stream = true; + op.on_consumed = &chand->finish_destroy_channel_closure; + grpc_channel_next_op(exec_ctx, + grpc_channel_stack_element( + grpc_channel_get_channel_stack(chand->channel), 0), + &op); +} + +static void finish_start_new_rpc(grpc_exec_ctx *exec_ctx, grpc_server *server, + grpc_call_element *elem, request_matcher *rm) { + call_data *calld = elem->call_data; + int request_id; + + if (gpr_atm_acq_load(&server->shutdown_flag)) { + gpr_mu_lock(&calld->mu_state); + calld->state = ZOMBIED; + gpr_mu_unlock(&calld->mu_state); + grpc_closure_init(&calld->kill_zombie_closure, kill_zombie, elem); + grpc_exec_ctx_enqueue(exec_ctx, &calld->kill_zombie_closure, true, NULL); + return; + } + + request_id = gpr_stack_lockfree_pop(rm->requests); + if (request_id == -1) { + gpr_mu_lock(&server->mu_call); + gpr_mu_lock(&calld->mu_state); + calld->state = PENDING; + gpr_mu_unlock(&calld->mu_state); + if (rm->pending_head == NULL) { + rm->pending_tail = rm->pending_head = calld; + } else { + rm->pending_tail->pending_next = calld; + rm->pending_tail = calld; + } + calld->pending_next = NULL; + gpr_mu_unlock(&server->mu_call); + } else { + gpr_mu_lock(&calld->mu_state); + calld->state = ACTIVATED; + gpr_mu_unlock(&calld->mu_state); + begin_call(exec_ctx, server, calld, &server->requested_calls[request_id]); + } +} + +static void start_new_rpc(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) { + channel_data *chand = elem->channel_data; + call_data *calld = elem->call_data; + grpc_server *server = chand->server; + uint32_t i; + uint32_t hash; + channel_registered_method *rm; + + if (chand->registered_methods && calld->path && calld->host) { + /* TODO(ctiller): unify these two searches */ + /* check for an exact match with host */ + hash = GRPC_MDSTR_KV_HASH(calld->host->hash, calld->path->hash); + for (i = 0; i <= chand->registered_method_max_probes; i++) { + rm = &chand->registered_methods[(hash + i) % + chand->registered_method_slots]; + if (!rm) break; + if (rm->host != calld->host) continue; + if (rm->method != calld->path) continue; + finish_start_new_rpc(exec_ctx, server, elem, + &rm->server_registered_method->request_matcher); + return; + } + /* check for a wildcard method definition (no host set) */ + hash = GRPC_MDSTR_KV_HASH(0, calld->path->hash); + for (i = 0; i <= chand->registered_method_max_probes; i++) { + rm = &chand->registered_methods[(hash + i) % + chand->registered_method_slots]; + if (!rm) break; + if (rm->host != NULL) continue; + if (rm->method != calld->path) continue; + finish_start_new_rpc(exec_ctx, server, elem, + &rm->server_registered_method->request_matcher); + return; + } + } + finish_start_new_rpc(exec_ctx, server, elem, + &server->unregistered_request_matcher); +} + +static int num_listeners(grpc_server *server) { + listener *l; + int n = 0; + for (l = server->listeners; l; l = l->next) { + n++; + } + return n; +} + +static void done_shutdown_event(grpc_exec_ctx *exec_ctx, void *server, + grpc_cq_completion *completion) { + server_unref(exec_ctx, server); +} + +static int num_channels(grpc_server *server) { + channel_data *chand; + int n = 0; + for (chand = server->root_channel_data.next; + chand != &server->root_channel_data; chand = chand->next) { + n++; + } + return n; +} + +static void kill_pending_work_locked(grpc_exec_ctx *exec_ctx, + grpc_server *server) { + registered_method *rm; + request_matcher_kill_requests(exec_ctx, server, + &server->unregistered_request_matcher); + request_matcher_zombify_all_pending_calls( + exec_ctx, &server->unregistered_request_matcher); + for (rm = server->registered_methods; rm; rm = rm->next) { + request_matcher_kill_requests(exec_ctx, server, &rm->request_matcher); + request_matcher_zombify_all_pending_calls(exec_ctx, &rm->request_matcher); + } +} + +static void maybe_finish_shutdown(grpc_exec_ctx *exec_ctx, + grpc_server *server) { + size_t i; + if (!gpr_atm_acq_load(&server->shutdown_flag) || server->shutdown_published) { + return; + } + + kill_pending_work_locked(exec_ctx, server); + + if (server->root_channel_data.next != &server->root_channel_data || + server->listeners_destroyed < num_listeners(server)) { + if (gpr_time_cmp(gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), + server->last_shutdown_message_time), + gpr_time_from_seconds(1, GPR_TIMESPAN)) >= 0) { + server->last_shutdown_message_time = gpr_now(GPR_CLOCK_REALTIME); + gpr_log(GPR_DEBUG, + "Waiting for %d channels and %d/%d listeners to be destroyed" + " before shutting down server", + num_channels(server), + num_listeners(server) - server->listeners_destroyed, + num_listeners(server)); + } + return; + } + server->shutdown_published = 1; + for (i = 0; i < server->num_shutdown_tags; i++) { + server_ref(server); + grpc_cq_end_op(exec_ctx, server->shutdown_tags[i].cq, + server->shutdown_tags[i].tag, 1, done_shutdown_event, server, + &server->shutdown_tags[i].completion); + } +} + +static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) { + grpc_call_element *elem = user_data; + call_data *calld = elem->call_data; + if (md->key == GRPC_MDSTR_PATH) { + calld->path = GRPC_MDSTR_REF(md->value); + return NULL; + } else if (md->key == GRPC_MDSTR_AUTHORITY) { + calld->host = GRPC_MDSTR_REF(md->value); + return NULL; + } + return md; +} + +static void server_on_recv_initial_metadata(grpc_exec_ctx *exec_ctx, void *ptr, + bool success) { + grpc_call_element *elem = ptr; + call_data *calld = elem->call_data; + gpr_timespec op_deadline; + + grpc_metadata_batch_filter(calld->recv_initial_metadata, server_filter, elem); + op_deadline = calld->recv_initial_metadata->deadline; + if (0 != gpr_time_cmp(op_deadline, gpr_inf_future(op_deadline.clock_type))) { + calld->deadline = op_deadline; + } + if (calld->host && calld->path) { + /* do nothing */ + } else { + success = 0; + } + + calld->on_done_recv_initial_metadata->cb( + exec_ctx, calld->on_done_recv_initial_metadata->cb_arg, success); +} + +static void server_mutate_op(grpc_call_element *elem, + grpc_transport_stream_op *op) { + call_data *calld = elem->call_data; + + if (op->recv_initial_metadata != NULL) { + calld->recv_initial_metadata = op->recv_initial_metadata; + calld->on_done_recv_initial_metadata = op->recv_initial_metadata_ready; + op->recv_initial_metadata_ready = &calld->server_on_recv_initial_metadata; + } +} + +static void server_start_transport_stream_op(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem, + grpc_transport_stream_op *op) { + GRPC_CALL_LOG_OP(GPR_INFO, elem, op); + server_mutate_op(elem, op); + grpc_call_next_op(exec_ctx, elem, op); +} + +static void got_initial_metadata(grpc_exec_ctx *exec_ctx, void *ptr, + bool success) { + grpc_call_element *elem = ptr; + call_data *calld = elem->call_data; + if (success) { + start_new_rpc(exec_ctx, elem); + } else { + gpr_mu_lock(&calld->mu_state); + if (calld->state == NOT_STARTED) { + calld->state = ZOMBIED; + gpr_mu_unlock(&calld->mu_state); + grpc_closure_init(&calld->kill_zombie_closure, kill_zombie, elem); + grpc_exec_ctx_enqueue(exec_ctx, &calld->kill_zombie_closure, true, NULL); + } else if (calld->state == PENDING) { + calld->state = ZOMBIED; + gpr_mu_unlock(&calld->mu_state); + /* zombied call will be destroyed when it's removed from the pending + queue... later */ + } else { + gpr_mu_unlock(&calld->mu_state); + } + } +} + +static void accept_stream(grpc_exec_ctx *exec_ctx, void *cd, + grpc_transport *transport, + const void *transport_server_data) { + channel_data *chand = cd; + /* create a call */ + grpc_call *call = + grpc_call_create(chand->channel, NULL, 0, NULL, transport_server_data, + NULL, 0, gpr_inf_future(GPR_CLOCK_MONOTONIC)); + grpc_call_element *elem = + grpc_call_stack_element(grpc_call_get_call_stack(call), 0); + call_data *calld = elem->call_data; + grpc_op op; + memset(&op, 0, sizeof(op)); + op.op = GRPC_OP_RECV_INITIAL_METADATA; + op.data.recv_initial_metadata = &calld->initial_metadata; + grpc_closure_init(&calld->got_initial_metadata, got_initial_metadata, elem); + grpc_call_start_batch_and_execute(exec_ctx, call, &op, 1, + &calld->got_initial_metadata); +} + +static void channel_connectivity_changed(grpc_exec_ctx *exec_ctx, void *cd, + bool iomgr_status_ignored) { + channel_data *chand = cd; + grpc_server *server = chand->server; + if (chand->connectivity_state != GRPC_CHANNEL_FATAL_FAILURE) { + grpc_transport_op op; + memset(&op, 0, sizeof(op)); + op.on_connectivity_state_change = &chand->channel_connectivity_changed, + op.connectivity_state = &chand->connectivity_state; + grpc_channel_next_op(exec_ctx, + grpc_channel_stack_element( + grpc_channel_get_channel_stack(chand->channel), 0), + &op); + } else { + gpr_mu_lock(&server->mu_global); + destroy_channel(exec_ctx, chand); + gpr_mu_unlock(&server->mu_global); + GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, chand->channel, "connectivity"); + } +} + +static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, + grpc_call_element_args *args) { + call_data *calld = elem->call_data; + channel_data *chand = elem->channel_data; + memset(calld, 0, sizeof(call_data)); + calld->deadline = gpr_inf_future(GPR_CLOCK_REALTIME); + calld->call = grpc_call_from_top_element(elem); + gpr_mu_init(&calld->mu_state); + + grpc_closure_init(&calld->server_on_recv_initial_metadata, + server_on_recv_initial_metadata, elem); + + server_ref(chand->server); +} + +static void destroy_call_elem(grpc_exec_ctx *exec_ctx, + grpc_call_element *elem) { + channel_data *chand = elem->channel_data; + call_data *calld = elem->call_data; + + GPR_ASSERT(calld->state != PENDING); + + if (calld->host) { + GRPC_MDSTR_UNREF(calld->host); + } + if (calld->path) { + GRPC_MDSTR_UNREF(calld->path); + } + grpc_metadata_array_destroy(&calld->initial_metadata); + + gpr_mu_destroy(&calld->mu_state); + + server_unref(exec_ctx, chand->server); +} + +static void init_channel_elem(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem, + grpc_channel_element_args *args) { + channel_data *chand = elem->channel_data; + GPR_ASSERT(args->is_first); + GPR_ASSERT(!args->is_last); + chand->server = NULL; + chand->channel = NULL; + chand->next = chand->prev = chand; + chand->registered_methods = NULL; + chand->connectivity_state = GRPC_CHANNEL_IDLE; + grpc_closure_init(&chand->channel_connectivity_changed, + channel_connectivity_changed, chand); +} + +static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, + grpc_channel_element *elem) { + size_t i; + channel_data *chand = elem->channel_data; + if (chand->registered_methods) { + for (i = 0; i < chand->registered_method_slots; i++) { + if (chand->registered_methods[i].method) { + GRPC_MDSTR_UNREF(chand->registered_methods[i].method); + } + if (chand->registered_methods[i].host) { + GRPC_MDSTR_UNREF(chand->registered_methods[i].host); + } + } + gpr_free(chand->registered_methods); + } + if (chand->server) { + gpr_mu_lock(&chand->server->mu_global); + chand->next->prev = chand->prev; + chand->prev->next = chand->next; + chand->next = chand->prev = chand; + maybe_finish_shutdown(exec_ctx, chand->server); + gpr_mu_unlock(&chand->server->mu_global); + server_unref(exec_ctx, chand->server); + } +} + +const grpc_channel_filter grpc_server_top_filter = { + server_start_transport_stream_op, + grpc_channel_next_op, + sizeof(call_data), + init_call_elem, + grpc_call_stack_ignore_set_pollset, + destroy_call_elem, + sizeof(channel_data), + init_channel_elem, + destroy_channel_elem, + grpc_call_next_get_peer, + "server", +}; + +void grpc_server_register_completion_queue(grpc_server *server, + grpc_completion_queue *cq, + void *reserved) { + size_t i, n; + GRPC_API_TRACE( + "grpc_server_register_completion_queue(server=%p, cq=%p, reserved=%p)", 3, + (server, cq, reserved)); + GPR_ASSERT(!reserved); + for (i = 0; i < server->cq_count; i++) { + if (server->cqs[i] == cq) return; + } + GRPC_CQ_INTERNAL_REF(cq, "server"); + grpc_cq_mark_server_cq(cq); + n = server->cq_count++; + server->cqs = gpr_realloc(server->cqs, + server->cq_count * sizeof(grpc_completion_queue *)); + server->cqs[n] = cq; +} + +grpc_server *grpc_server_create(const grpc_channel_args *args, void *reserved) { + size_t i; + + GRPC_API_TRACE("grpc_server_create(%p, %p)", 2, (args, reserved)); + + grpc_server *server = gpr_malloc(sizeof(grpc_server)); + + GPR_ASSERT(grpc_is_initialized() && "call grpc_init()"); + + memset(server, 0, sizeof(grpc_server)); + + gpr_mu_init(&server->mu_global); + gpr_mu_init(&server->mu_call); + + /* decremented by grpc_server_destroy */ + gpr_ref_init(&server->internal_refcount, 1); + server->root_channel_data.next = server->root_channel_data.prev = + &server->root_channel_data; + + /* TODO(ctiller): expose a channel_arg for this */ + server->max_requested_calls = 32768; + server->request_freelist = + gpr_stack_lockfree_create(server->max_requested_calls); + for (i = 0; i < (size_t)server->max_requested_calls; i++) { + gpr_stack_lockfree_push(server->request_freelist, (int)i); + } + request_matcher_init(&server->unregistered_request_matcher, + server->max_requested_calls); + server->requested_calls = gpr_malloc(server->max_requested_calls * + sizeof(*server->requested_calls)); + + server->channel_args = grpc_channel_args_copy(args); + + return server; +} + +static int streq(const char *a, const char *b) { + if (a == NULL && b == NULL) return 1; + if (a == NULL) return 0; + if (b == NULL) return 0; + return 0 == strcmp(a, b); +} + +void *grpc_server_register_method(grpc_server *server, const char *method, + const char *host) { + registered_method *m; + GRPC_API_TRACE("grpc_server_register_method(server=%p, method=%s, host=%s)", + 3, (server, method, host)); + if (!method) { + gpr_log(GPR_ERROR, + "grpc_server_register_method method string cannot be NULL"); + return NULL; + } + for (m = server->registered_methods; m; m = m->next) { + if (streq(m->method, method) && streq(m->host, host)) { + gpr_log(GPR_ERROR, "duplicate registration for %s@%s", method, + host ? host : "*"); + return NULL; + } + } + m = gpr_malloc(sizeof(registered_method)); + memset(m, 0, sizeof(*m)); + request_matcher_init(&m->request_matcher, server->max_requested_calls); + m->method = gpr_strdup(method); + m->host = gpr_strdup(host); + m->next = server->registered_methods; + server->registered_methods = m; + return m; +} + +void grpc_server_start(grpc_server *server) { + listener *l; + size_t i; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + + GRPC_API_TRACE("grpc_server_start(server=%p)", 1, (server)); + + server->pollsets = gpr_malloc(sizeof(grpc_pollset *) * server->cq_count); + for (i = 0; i < server->cq_count; i++) { + server->pollsets[i] = grpc_cq_pollset(server->cqs[i]); + } + + for (l = server->listeners; l; l = l->next) { + l->start(&exec_ctx, server, l->arg, server->pollsets, server->cq_count); + } + + grpc_exec_ctx_finish(&exec_ctx); +} + +void grpc_server_setup_transport(grpc_exec_ctx *exec_ctx, grpc_server *s, + grpc_transport *transport, + const grpc_channel_args *args) { + size_t i; + size_t num_registered_methods; + size_t alloc; + registered_method *rm; + channel_registered_method *crm; + grpc_channel *channel; + channel_data *chand; + grpc_mdstr *host; + grpc_mdstr *method; + uint32_t hash; + size_t slots; + uint32_t probes; + uint32_t max_probes = 0; + grpc_transport_op op; + + for (i = 0; i < s->cq_count; i++) { + memset(&op, 0, sizeof(op)); + op.bind_pollset = grpc_cq_pollset(s->cqs[i]); + grpc_transport_perform_op(exec_ctx, transport, &op); + } + + channel = + grpc_channel_create(exec_ctx, NULL, args, GRPC_SERVER_CHANNEL, transport); + chand = (channel_data *)grpc_channel_stack_element( + grpc_channel_get_channel_stack(channel), 0) + ->channel_data; + chand->server = s; + server_ref(s); + chand->channel = channel; + + num_registered_methods = 0; + for (rm = s->registered_methods; rm; rm = rm->next) { + num_registered_methods++; + } + /* build a lookup table phrased in terms of mdstr's in this channels context + to quickly find registered methods */ + if (num_registered_methods > 0) { + slots = 2 * num_registered_methods; + alloc = sizeof(channel_registered_method) * slots; + chand->registered_methods = gpr_malloc(alloc); + memset(chand->registered_methods, 0, alloc); + for (rm = s->registered_methods; rm; rm = rm->next) { + host = rm->host ? grpc_mdstr_from_string(rm->host) : NULL; + method = grpc_mdstr_from_string(rm->method); + hash = GRPC_MDSTR_KV_HASH(host ? host->hash : 0, method->hash); + for (probes = 0; chand->registered_methods[(hash + probes) % slots] + .server_registered_method != NULL; + probes++) + ; + if (probes > max_probes) max_probes = probes; + crm = &chand->registered_methods[(hash + probes) % slots]; + crm->server_registered_method = rm; + crm->host = host; + crm->method = method; + } + GPR_ASSERT(slots <= UINT32_MAX); + chand->registered_method_slots = (uint32_t)slots; + chand->registered_method_max_probes = max_probes; + } + + gpr_mu_lock(&s->mu_global); + chand->next = &s->root_channel_data; + chand->prev = chand->next->prev; + chand->next->prev = chand->prev->next = chand; + gpr_mu_unlock(&s->mu_global); + + GRPC_CHANNEL_INTERNAL_REF(channel, "connectivity"); + memset(&op, 0, sizeof(op)); + op.set_accept_stream = true; + op.set_accept_stream_fn = accept_stream; + op.set_accept_stream_user_data = chand; + op.on_connectivity_state_change = &chand->channel_connectivity_changed; + op.connectivity_state = &chand->connectivity_state; + op.disconnect = gpr_atm_acq_load(&s->shutdown_flag) != 0; + grpc_transport_perform_op(exec_ctx, transport, &op); +} + +void done_published_shutdown(grpc_exec_ctx *exec_ctx, void *done_arg, + grpc_cq_completion *storage) { + (void)done_arg; + gpr_free(storage); +} + +static void listener_destroy_done(grpc_exec_ctx *exec_ctx, void *s, + bool success) { + grpc_server *server = s; + gpr_mu_lock(&server->mu_global); + server->listeners_destroyed++; + maybe_finish_shutdown(exec_ctx, server); + gpr_mu_unlock(&server->mu_global); +} + +void grpc_server_shutdown_and_notify(grpc_server *server, + grpc_completion_queue *cq, void *tag) { + listener *l; + shutdown_tag *sdt; + channel_broadcaster broadcaster; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + + GRPC_API_TRACE("grpc_server_shutdown_and_notify(server=%p, cq=%p, tag=%p)", 3, + (server, cq, tag)); + + /* lock, and gather up some stuff to do */ + gpr_mu_lock(&server->mu_global); + grpc_cq_begin_op(cq, tag); + if (server->shutdown_published) { + grpc_cq_end_op(&exec_ctx, cq, tag, 1, done_published_shutdown, NULL, + gpr_malloc(sizeof(grpc_cq_completion))); + gpr_mu_unlock(&server->mu_global); + goto done; + } + server->shutdown_tags = + gpr_realloc(server->shutdown_tags, + sizeof(shutdown_tag) * (server->num_shutdown_tags + 1)); + sdt = &server->shutdown_tags[server->num_shutdown_tags++]; + sdt->tag = tag; + sdt->cq = cq; + if (gpr_atm_acq_load(&server->shutdown_flag)) { + gpr_mu_unlock(&server->mu_global); + goto done; + } + + server->last_shutdown_message_time = gpr_now(GPR_CLOCK_REALTIME); + + channel_broadcaster_init(server, &broadcaster); + + gpr_atm_rel_store(&server->shutdown_flag, 1); + + /* collect all unregistered then registered calls */ + gpr_mu_lock(&server->mu_call); + kill_pending_work_locked(&exec_ctx, server); + gpr_mu_unlock(&server->mu_call); + + maybe_finish_shutdown(&exec_ctx, server); + gpr_mu_unlock(&server->mu_global); + + /* Shutdown listeners */ + for (l = server->listeners; l; l = l->next) { + grpc_closure_init(&l->destroy_done, listener_destroy_done, server); + l->destroy(&exec_ctx, server, l->arg, &l->destroy_done); + } + + channel_broadcaster_shutdown(&exec_ctx, &broadcaster, 1, 0); + +done: + grpc_exec_ctx_finish(&exec_ctx); +} + +void grpc_server_cancel_all_calls(grpc_server *server) { + channel_broadcaster broadcaster; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + + GRPC_API_TRACE("grpc_server_cancel_all_calls(server=%p)", 1, (server)); + + gpr_mu_lock(&server->mu_global); + channel_broadcaster_init(server, &broadcaster); + gpr_mu_unlock(&server->mu_global); + + channel_broadcaster_shutdown(&exec_ctx, &broadcaster, 0, 1); + grpc_exec_ctx_finish(&exec_ctx); +} + +void grpc_server_destroy(grpc_server *server) { + listener *l; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + + GRPC_API_TRACE("grpc_server_destroy(server=%p)", 1, (server)); + + gpr_mu_lock(&server->mu_global); + GPR_ASSERT(gpr_atm_acq_load(&server->shutdown_flag) || !server->listeners); + GPR_ASSERT(server->listeners_destroyed == num_listeners(server)); + + while (server->listeners) { + l = server->listeners; + server->listeners = l->next; + gpr_free(l); + } + + gpr_mu_unlock(&server->mu_global); + + server_unref(&exec_ctx, server); + grpc_exec_ctx_finish(&exec_ctx); +} + +void grpc_server_add_listener( + grpc_exec_ctx *exec_ctx, grpc_server *server, void *arg, + void (*start)(grpc_exec_ctx *exec_ctx, grpc_server *server, void *arg, + grpc_pollset **pollsets, size_t pollset_count), + void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_server *server, void *arg, + grpc_closure *on_done)) { + listener *l = gpr_malloc(sizeof(listener)); + l->arg = arg; + l->start = start; + l->destroy = destroy; + l->next = server->listeners; + server->listeners = l; +} + +static grpc_call_error queue_call_request(grpc_exec_ctx *exec_ctx, + grpc_server *server, + requested_call *rc) { + call_data *calld = NULL; + request_matcher *rm = NULL; + int request_id; + if (gpr_atm_acq_load(&server->shutdown_flag)) { + fail_call(exec_ctx, server, rc); + return GRPC_CALL_OK; + } + request_id = gpr_stack_lockfree_pop(server->request_freelist); + if (request_id == -1) { + /* out of request ids: just fail this one */ + fail_call(exec_ctx, server, rc); + return GRPC_CALL_OK; + } + switch (rc->type) { + case BATCH_CALL: + rm = &server->unregistered_request_matcher; + break; + case REGISTERED_CALL: + rm = &rc->data.registered.registered_method->request_matcher; + break; + } + server->requested_calls[request_id] = *rc; + gpr_free(rc); + if (gpr_stack_lockfree_push(rm->requests, request_id)) { + /* this was the first queued request: we need to lock and start + matching calls */ + gpr_mu_lock(&server->mu_call); + while ((calld = rm->pending_head) != NULL) { + request_id = gpr_stack_lockfree_pop(rm->requests); + if (request_id == -1) break; + rm->pending_head = calld->pending_next; + gpr_mu_unlock(&server->mu_call); + gpr_mu_lock(&calld->mu_state); + if (calld->state == ZOMBIED) { + gpr_mu_unlock(&calld->mu_state); + grpc_closure_init( + &calld->kill_zombie_closure, kill_zombie, + grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0)); + grpc_exec_ctx_enqueue(exec_ctx, &calld->kill_zombie_closure, true, + NULL); + } else { + GPR_ASSERT(calld->state == PENDING); + calld->state = ACTIVATED; + gpr_mu_unlock(&calld->mu_state); + begin_call(exec_ctx, server, calld, + &server->requested_calls[request_id]); + } + gpr_mu_lock(&server->mu_call); + } + gpr_mu_unlock(&server->mu_call); + } + return GRPC_CALL_OK; +} + +grpc_call_error grpc_server_request_call( + grpc_server *server, grpc_call **call, grpc_call_details *details, + grpc_metadata_array *initial_metadata, + grpc_completion_queue *cq_bound_to_call, + grpc_completion_queue *cq_for_notification, void *tag) { + grpc_call_error error; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + requested_call *rc = gpr_malloc(sizeof(*rc)); + GRPC_API_TRACE( + "grpc_server_request_call(" + "server=%p, call=%p, details=%p, initial_metadata=%p, " + "cq_bound_to_call=%p, cq_for_notification=%p, tag=%p)", + 7, (server, call, details, initial_metadata, cq_bound_to_call, + cq_for_notification, tag)); + if (!grpc_cq_is_server_cq(cq_for_notification)) { + gpr_free(rc); + error = GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE; + goto done; + } + grpc_cq_begin_op(cq_for_notification, tag); + details->reserved = NULL; + rc->type = BATCH_CALL; + rc->server = server; + rc->tag = tag; + rc->cq_bound_to_call = cq_bound_to_call; + rc->cq_for_notification = cq_for_notification; + rc->call = call; + rc->data.batch.details = details; + rc->initial_metadata = initial_metadata; + error = queue_call_request(&exec_ctx, server, rc); +done: + grpc_exec_ctx_finish(&exec_ctx); + return error; +} + +grpc_call_error grpc_server_request_registered_call( + grpc_server *server, void *rmp, grpc_call **call, gpr_timespec *deadline, + grpc_metadata_array *initial_metadata, grpc_byte_buffer **optional_payload, + grpc_completion_queue *cq_bound_to_call, + grpc_completion_queue *cq_for_notification, void *tag) { + grpc_call_error error; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + requested_call *rc = gpr_malloc(sizeof(*rc)); + registered_method *rm = rmp; + GRPC_API_TRACE( + "grpc_server_request_registered_call(" + "server=%p, rmp=%p, call=%p, deadline=%p, initial_metadata=%p, " + "optional_payload=%p, cq_bound_to_call=%p, cq_for_notification=%p, " + "tag=%p)", + 9, (server, rmp, call, deadline, initial_metadata, optional_payload, + cq_bound_to_call, cq_for_notification, tag)); + if (!grpc_cq_is_server_cq(cq_for_notification)) { + gpr_free(rc); + error = GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE; + goto done; + } + grpc_cq_begin_op(cq_for_notification, tag); + rc->type = REGISTERED_CALL; + rc->server = server; + rc->tag = tag; + rc->cq_bound_to_call = cq_bound_to_call; + rc->cq_for_notification = cq_for_notification; + rc->call = call; + rc->data.registered.registered_method = rm; + rc->data.registered.deadline = deadline; + rc->initial_metadata = initial_metadata; + rc->data.registered.optional_payload = optional_payload; + error = queue_call_request(&exec_ctx, server, rc); +done: + grpc_exec_ctx_finish(&exec_ctx); + return error; +} + +static void publish_registered_or_batch(grpc_exec_ctx *exec_ctx, + void *user_data, bool success); + +static void cpstr(char **dest, size_t *capacity, grpc_mdstr *value) { + gpr_slice slice = value->slice; + size_t len = GPR_SLICE_LENGTH(slice); + + if (len + 1 > *capacity) { + *capacity = GPR_MAX(len + 1, *capacity * 2); + *dest = gpr_realloc(*dest, *capacity); + } + memcpy(*dest, grpc_mdstr_as_c_string(value), len + 1); +} + +static void begin_call(grpc_exec_ctx *exec_ctx, grpc_server *server, + call_data *calld, requested_call *rc) { + grpc_op ops[1]; + grpc_op *op = ops; + + memset(ops, 0, sizeof(ops)); + + /* called once initial metadata has been read by the call, but BEFORE + the ioreq to fetch it out of the call has been executed. + This means metadata related fields can be relied on in calld, but to + fill in the metadata array passed by the client, we need to perform + an ioreq op, that should complete immediately. */ + + grpc_call_set_completion_queue(exec_ctx, calld->call, rc->cq_bound_to_call); + grpc_closure_init(&rc->publish, publish_registered_or_batch, rc); + *rc->call = calld->call; + calld->cq_new = rc->cq_for_notification; + GPR_SWAP(grpc_metadata_array, *rc->initial_metadata, calld->initial_metadata); + switch (rc->type) { + case BATCH_CALL: + GPR_ASSERT(calld->host != NULL); + GPR_ASSERT(calld->path != NULL); + cpstr(&rc->data.batch.details->host, + &rc->data.batch.details->host_capacity, calld->host); + cpstr(&rc->data.batch.details->method, + &rc->data.batch.details->method_capacity, calld->path); + rc->data.batch.details->deadline = calld->deadline; + break; + case REGISTERED_CALL: + *rc->data.registered.deadline = calld->deadline; + if (rc->data.registered.optional_payload) { + op->op = GRPC_OP_RECV_MESSAGE; + op->data.recv_message = rc->data.registered.optional_payload; + op++; + } + break; + default: + GPR_UNREACHABLE_CODE(return ); + } + + GRPC_CALL_INTERNAL_REF(calld->call, "server"); + grpc_call_start_batch_and_execute(exec_ctx, calld->call, ops, + (size_t)(op - ops), &rc->publish); +} + +static void done_request_event(grpc_exec_ctx *exec_ctx, void *req, + grpc_cq_completion *c) { + requested_call *rc = req; + grpc_server *server = rc->server; + + if (rc >= server->requested_calls && + rc < server->requested_calls + server->max_requested_calls) { + GPR_ASSERT(rc - server->requested_calls <= INT_MAX); + gpr_stack_lockfree_push(server->request_freelist, + (int)(rc - server->requested_calls)); + } else { + gpr_free(req); + } + + server_unref(exec_ctx, server); +} + +static void fail_call(grpc_exec_ctx *exec_ctx, grpc_server *server, + requested_call *rc) { + *rc->call = NULL; + rc->initial_metadata->count = 0; + + server_ref(server); + grpc_cq_end_op(exec_ctx, rc->cq_for_notification, rc->tag, 0, + done_request_event, rc, &rc->completion); +} + +static void publish_registered_or_batch(grpc_exec_ctx *exec_ctx, void *prc, + bool success) { + requested_call *rc = prc; + grpc_call *call = *rc->call; + grpc_call_element *elem = + grpc_call_stack_element(grpc_call_get_call_stack(call), 0); + call_data *calld = elem->call_data; + channel_data *chand = elem->channel_data; + server_ref(chand->server); + grpc_cq_end_op(exec_ctx, calld->cq_new, rc->tag, success, done_request_event, + rc, &rc->completion); + GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, "server"); +} + +const grpc_channel_args *grpc_server_get_channel_args(grpc_server *server) { + return server->channel_args; +} + +int grpc_server_has_open_connections(grpc_server *server) { + int r; + gpr_mu_lock(&server->mu_global); + r = server->root_channel_data.next != &server->root_channel_data; + gpr_mu_unlock(&server->mu_global); + return r; +} diff --git a/src/core/lib/surface/server.h b/src/core/lib/surface/server.h new file mode 100644 index 0000000000..cd62eadd7f --- /dev/null +++ b/src/core/lib/surface/server.h @@ -0,0 +1,62 @@ +/* + * + * Copyright 2015-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_SURFACE_SERVER_H +#define GRPC_CORE_SURFACE_SERVER_H + +#include +#include "src/core/channel/channel_stack.h" +#include "src/core/transport/transport.h" + +extern const grpc_channel_filter grpc_server_top_filter; + +/* Add a listener to the server: when the server starts, it will call start, + and when it shuts down, it will call destroy */ +void grpc_server_add_listener( + grpc_exec_ctx *exec_ctx, grpc_server *server, void *listener, + void (*start)(grpc_exec_ctx *exec_ctx, grpc_server *server, void *arg, + grpc_pollset **pollsets, size_t npollsets), + void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_server *server, void *arg, + grpc_closure *on_done)); + +/* Setup a transport - creates a channel stack, binds the transport to the + server */ +void grpc_server_setup_transport(grpc_exec_ctx *exec_ctx, grpc_server *server, + grpc_transport *transport, + const grpc_channel_args *args); + +const grpc_channel_args *grpc_server_get_channel_args(grpc_server *server); + +int grpc_server_has_open_connections(grpc_server *server); + +#endif /* GRPC_CORE_SURFACE_SERVER_H */ diff --git a/src/core/lib/surface/server_chttp2.c b/src/core/lib/surface/server_chttp2.c new file mode 100644 index 0000000000..546760ecfa --- /dev/null +++ b/src/core/lib/surface/server_chttp2.c @@ -0,0 +1,146 @@ +/* + * + * Copyright 2015-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 + +#include +#include +#include +#include "src/core/channel/http_server_filter.h" +#include "src/core/iomgr/resolve_address.h" +#include "src/core/iomgr/tcp_server.h" +#include "src/core/surface/api_trace.h" +#include "src/core/surface/server.h" +#include "src/core/transport/chttp2_transport.h" + +static void setup_transport(grpc_exec_ctx *exec_ctx, void *server, + grpc_transport *transport) { + grpc_server_setup_transport(exec_ctx, server, transport, + grpc_server_get_channel_args(server)); +} + +static void new_transport(grpc_exec_ctx *exec_ctx, void *server, + grpc_endpoint *tcp, + grpc_tcp_server_acceptor *acceptor) { + /* + * Beware that the call to grpc_create_chttp2_transport() has to happen before + * grpc_tcp_server_destroy(). This is fine here, but similar code + * asynchronously doing a handshake instead of calling grpc_tcp_server_start() + * (as in server_secure_chttp2.c) needs to add synchronization to avoid this + * case. + */ + grpc_transport *transport = grpc_create_chttp2_transport( + exec_ctx, grpc_server_get_channel_args(server), tcp, 0); + setup_transport(exec_ctx, server, transport); + grpc_chttp2_transport_start_reading(exec_ctx, transport, NULL, 0); +} + +/* Server callback: start listening on our ports */ +static void start(grpc_exec_ctx *exec_ctx, grpc_server *server, void *tcpp, + grpc_pollset **pollsets, size_t pollset_count) { + grpc_tcp_server *tcp = tcpp; + grpc_tcp_server_start(exec_ctx, tcp, pollsets, pollset_count, new_transport, + server); +} + +/* Server callback: destroy the tcp listener (so we don't generate further + callbacks) */ +static void destroy(grpc_exec_ctx *exec_ctx, grpc_server *server, void *tcpp, + grpc_closure *destroy_done) { + grpc_tcp_server *tcp = tcpp; + grpc_tcp_server_unref(exec_ctx, tcp); + grpc_exec_ctx_enqueue(exec_ctx, destroy_done, true, NULL); +} + +int grpc_server_add_insecure_http2_port(grpc_server *server, const char *addr) { + grpc_resolved_addresses *resolved = NULL; + grpc_tcp_server *tcp = NULL; + size_t i; + unsigned count = 0; + int port_num = -1; + int port_temp; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + + GRPC_API_TRACE("grpc_server_add_insecure_http2_port(server=%p, addr=%s)", 2, + (server, addr)); + + resolved = grpc_blocking_resolve_address(addr, "http"); + if (!resolved) { + goto error; + } + + tcp = grpc_tcp_server_create(NULL); + GPR_ASSERT(tcp); + + for (i = 0; i < resolved->naddrs; i++) { + port_temp = grpc_tcp_server_add_port( + tcp, (struct sockaddr *)&resolved->addrs[i].addr, + resolved->addrs[i].len); + if (port_temp > 0) { + if (port_num == -1) { + port_num = port_temp; + } else { + GPR_ASSERT(port_num == port_temp); + } + count++; + } + } + if (count == 0) { + gpr_log(GPR_ERROR, "No address added out of total %d resolved", + resolved->naddrs); + goto error; + } + if (count != resolved->naddrs) { + gpr_log(GPR_ERROR, "Only %d addresses added out of total %d resolved", + count, resolved->naddrs); + } + grpc_resolved_addresses_destroy(resolved); + + /* Register with the server only upon success */ + grpc_server_add_listener(&exec_ctx, server, tcp, start, destroy); + goto done; + +/* Error path: cleanup and return */ +error: + if (resolved) { + grpc_resolved_addresses_destroy(resolved); + } + if (tcp) { + grpc_tcp_server_unref(&exec_ctx, tcp); + } + port_num = 0; + +done: + grpc_exec_ctx_finish(&exec_ctx); + return port_num; +} diff --git a/src/core/lib/surface/surface_trace.h b/src/core/lib/surface/surface_trace.h new file mode 100644 index 0000000000..a55a88e44d --- /dev/null +++ b/src/core/lib/surface/surface_trace.h @@ -0,0 +1,48 @@ +/* + * + * Copyright 2015-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_SURFACE_SURFACE_TRACE_H +#define GRPC_CORE_SURFACE_SURFACE_TRACE_H + +#include +#include "src/core/debug/trace.h" +#include "src/core/surface/api_trace.h" + +#define GRPC_SURFACE_TRACE_RETURNED_EVENT(cq, event) \ + if (grpc_api_trace) { \ + char *_ev = grpc_event_string(event); \ + gpr_log(GPR_INFO, "RETURN_EVENT[%p]: %s", cq, _ev); \ + gpr_free(_ev); \ + } + +#endif /* GRPC_CORE_SURFACE_SURFACE_TRACE_H */ diff --git a/src/core/lib/surface/validate_metadata.c b/src/core/lib/surface/validate_metadata.c new file mode 100644 index 0000000000..bf4126867f --- /dev/null +++ b/src/core/lib/surface/validate_metadata.c @@ -0,0 +1,73 @@ +/* + * + * 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 +#include + +#include + +static int conforms_to(const char *s, size_t len, const uint8_t *legal_bits) { + const char *p = s; + const char *e = s + len; + for (; p != e; p++) { + int idx = *p; + int byte = idx / 8; + int bit = idx % 8; + if ((legal_bits[byte] & (1 << bit)) == 0) return 0; + } + return 1; +} + +int grpc_header_key_is_legal(const char *key, size_t length) { + static const uint8_t legal_header_bits[256 / 8] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xff, 0x03, 0x00, 0x00, 0x00, + 0x80, 0xfe, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + if (length == 0) { + return 0; + } + return conforms_to(key, length, legal_header_bits); +} + +int grpc_header_nonbin_value_is_legal(const char *value, size_t length) { + static const uint8_t legal_header_bits[256 / 8] = { + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + return conforms_to(value, length, legal_header_bits); +} + +int grpc_is_binary_header(const char *key, size_t length) { + if (length < 5) return 0; + return 0 == memcmp(key + length - 4, "-bin", 4); +} diff --git a/src/core/lib/surface/version.c b/src/core/lib/surface/version.c new file mode 100644 index 0000000000..7723f39401 --- /dev/null +++ b/src/core/lib/surface/version.c @@ -0,0 +1,39 @@ +/* + * + * Copyright 2015-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. + * + */ + +/* This file is autogenerated from: + templates/src/core/surface/version.c.template */ + +#include + +const char *grpc_version_string(void) { return "0.14.0-dev"; } diff --git a/src/core/lib/transport/byte_stream.c b/src/core/lib/transport/byte_stream.c new file mode 100644 index 0000000000..8e6fb2cbef --- /dev/null +++ b/src/core/lib/transport/byte_stream.c @@ -0,0 +1,78 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/transport/byte_stream.h" + +#include + +#include + +int grpc_byte_stream_next(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *byte_stream, gpr_slice *slice, + size_t max_size_hint, grpc_closure *on_complete) { + return byte_stream->next(exec_ctx, byte_stream, slice, max_size_hint, + on_complete); +} + +void grpc_byte_stream_destroy(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *byte_stream) { + byte_stream->destroy(exec_ctx, byte_stream); +} + +/* slice_buffer_stream */ + +static int slice_buffer_stream_next(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *byte_stream, + gpr_slice *slice, size_t max_size_hint, + grpc_closure *on_complete) { + grpc_slice_buffer_stream *stream = (grpc_slice_buffer_stream *)byte_stream; + GPR_ASSERT(stream->cursor < stream->backing_buffer->count); + *slice = gpr_slice_ref(stream->backing_buffer->slices[stream->cursor]); + stream->cursor++; + return 1; +} + +static void slice_buffer_stream_destroy(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *byte_stream) {} + +void grpc_slice_buffer_stream_init(grpc_slice_buffer_stream *stream, + gpr_slice_buffer *slice_buffer, + uint32_t flags) { + GPR_ASSERT(slice_buffer->length <= UINT32_MAX); + stream->base.length = (uint32_t)slice_buffer->length; + stream->base.flags = flags; + stream->base.next = slice_buffer_stream_next; + stream->base.destroy = slice_buffer_stream_destroy; + stream->backing_buffer = slice_buffer; + stream->cursor = 0; +} diff --git a/src/core/lib/transport/byte_stream.h b/src/core/lib/transport/byte_stream.h new file mode 100644 index 0000000000..ab42d07e7e --- /dev/null +++ b/src/core/lib/transport/byte_stream.h @@ -0,0 +1,89 @@ +/* + * + * Copyright 2015-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_TRANSPORT_BYTE_STREAM_H +#define GRPC_CORE_TRANSPORT_BYTE_STREAM_H + +#include +#include "src/core/iomgr/exec_ctx.h" + +/** Internal bit flag for grpc_begin_message's \a flags signaling the use of + * compression for the message */ +#define GRPC_WRITE_INTERNAL_COMPRESS (0x80000000u) +/** Mask of all valid internal flags. */ +#define GRPC_WRITE_INTERNAL_USED_MASK (GRPC_WRITE_INTERNAL_COMPRESS) + +struct grpc_byte_stream; +typedef struct grpc_byte_stream grpc_byte_stream; + +struct grpc_byte_stream { + uint32_t length; + uint32_t flags; + int (*next)(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream, + gpr_slice *slice, size_t max_size_hint, + grpc_closure *on_complete); + void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream); +}; + +/* returns 1 if the bytes are available immediately (in which case + * on_complete will not be called), 0 if the bytes will be available + * asynchronously. + * + * on entry, *remaining can be set as a hint as to the maximum number + * of bytes that would be acceptable to read. + * + * fills *buffer, *length, *remaining with the bytes, length of bytes + * and length of data remaining to be read before either returning 1 + * or calling on_complete. + * + * once a slice is returned into *slice, it is owned by the caller. + */ +int grpc_byte_stream_next(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *byte_stream, gpr_slice *slice, + size_t max_size_hint, grpc_closure *on_complete); + +void grpc_byte_stream_destroy(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *byte_stream); + +/* grpc_byte_stream that wraps a slice buffer */ +typedef struct grpc_slice_buffer_stream { + grpc_byte_stream base; + gpr_slice_buffer *backing_buffer; + size_t cursor; +} grpc_slice_buffer_stream; + +void grpc_slice_buffer_stream_init(grpc_slice_buffer_stream *stream, + gpr_slice_buffer *slice_buffer, + uint32_t flags); + +#endif /* GRPC_CORE_TRANSPORT_BYTE_STREAM_H */ diff --git a/src/core/lib/transport/chttp2/alpn.c b/src/core/lib/transport/chttp2/alpn.c new file mode 100644 index 0000000000..69da4e6718 --- /dev/null +++ b/src/core/lib/transport/chttp2/alpn.c @@ -0,0 +1,56 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/transport/chttp2/alpn.h" +#include +#include + +/* in order of preference */ +static const char *const supported_versions[] = {"h2"}; + +int grpc_chttp2_is_alpn_version_supported(const char *version, size_t size) { + size_t i; + for (i = 0; i < GPR_ARRAY_SIZE(supported_versions); i++) { + if (!strncmp(version, supported_versions[i], size)) return 1; + } + return 0; +} + +size_t grpc_chttp2_num_alpn_versions(void) { + return GPR_ARRAY_SIZE(supported_versions); +} + +const char *grpc_chttp2_get_alpn_version_index(size_t i) { + GPR_ASSERT(i < GPR_ARRAY_SIZE(supported_versions)); + return supported_versions[i]; +} diff --git a/src/core/lib/transport/chttp2/alpn.h b/src/core/lib/transport/chttp2/alpn.h new file mode 100644 index 0000000000..68010e3155 --- /dev/null +++ b/src/core/lib/transport/chttp2/alpn.h @@ -0,0 +1,49 @@ +/* + * + * Copyright 2015-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_TRANSPORT_CHTTP2_ALPN_H +#define GRPC_CORE_TRANSPORT_CHTTP2_ALPN_H + +#include + +/* Retuns 1 if the version is supported, 0 otherwise. */ +int grpc_chttp2_is_alpn_version_supported(const char *version, size_t size); + +/* Returns the number of protocol versions to advertise */ +size_t grpc_chttp2_num_alpn_versions(void); + +/* Returns the protocol version at index i (0 <= i < + * grpc_chttp2_num_alpn_versions()) */ +const char *grpc_chttp2_get_alpn_version_index(size_t i); + +#endif /* GRPC_CORE_TRANSPORT_CHTTP2_ALPN_H */ diff --git a/src/core/lib/transport/chttp2/bin_encoder.c b/src/core/lib/transport/chttp2/bin_encoder.c new file mode 100644 index 0000000000..3d31162499 --- /dev/null +++ b/src/core/lib/transport/chttp2/bin_encoder.c @@ -0,0 +1,233 @@ +/* + * + * Copyright 2015-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/transport/chttp2/bin_encoder.h" + +#include + +#include +#include "src/core/transport/chttp2/huffsyms.h" + +static const char alphabet[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +typedef struct { + uint16_t bits; + uint8_t length; +} b64_huff_sym; + +static const b64_huff_sym huff_alphabet[64] = { + {0x21, 6}, {0x5d, 7}, {0x5e, 7}, {0x5f, 7}, {0x60, 7}, {0x61, 7}, + {0x62, 7}, {0x63, 7}, {0x64, 7}, {0x65, 7}, {0x66, 7}, {0x67, 7}, + {0x68, 7}, {0x69, 7}, {0x6a, 7}, {0x6b, 7}, {0x6c, 7}, {0x6d, 7}, + {0x6e, 7}, {0x6f, 7}, {0x70, 7}, {0x71, 7}, {0x72, 7}, {0xfc, 8}, + {0x73, 7}, {0xfd, 8}, {0x3, 5}, {0x23, 6}, {0x4, 5}, {0x24, 6}, + {0x5, 5}, {0x25, 6}, {0x26, 6}, {0x27, 6}, {0x6, 5}, {0x74, 7}, + {0x75, 7}, {0x28, 6}, {0x29, 6}, {0x2a, 6}, {0x7, 5}, {0x2b, 6}, + {0x76, 7}, {0x2c, 6}, {0x8, 5}, {0x9, 5}, {0x2d, 6}, {0x77, 7}, + {0x78, 7}, {0x79, 7}, {0x7a, 7}, {0x7b, 7}, {0x0, 5}, {0x1, 5}, + {0x2, 5}, {0x19, 6}, {0x1a, 6}, {0x1b, 6}, {0x1c, 6}, {0x1d, 6}, + {0x1e, 6}, {0x1f, 6}, {0x7fb, 11}, {0x18, 6}}; + +static const uint8_t tail_xtra[3] = {0, 2, 3}; + +gpr_slice grpc_chttp2_base64_encode(gpr_slice input) { + size_t input_length = GPR_SLICE_LENGTH(input); + size_t input_triplets = input_length / 3; + size_t tail_case = input_length % 3; + size_t output_length = input_triplets * 4 + tail_xtra[tail_case]; + gpr_slice output = gpr_slice_malloc(output_length); + uint8_t *in = GPR_SLICE_START_PTR(input); + char *out = (char *)GPR_SLICE_START_PTR(output); + size_t i; + + /* encode full triplets */ + for (i = 0; i < input_triplets; i++) { + out[0] = alphabet[in[0] >> 2]; + out[1] = alphabet[((in[0] & 0x3) << 4) | (in[1] >> 4)]; + out[2] = alphabet[((in[1] & 0xf) << 2) | (in[2] >> 6)]; + out[3] = alphabet[in[2] & 0x3f]; + out += 4; + in += 3; + } + + /* encode the remaining bytes */ + switch (tail_case) { + case 0: + break; + case 1: + out[0] = alphabet[in[0] >> 2]; + out[1] = alphabet[(in[0] & 0x3) << 4]; + out += 2; + in += 1; + break; + case 2: + out[0] = alphabet[in[0] >> 2]; + out[1] = alphabet[((in[0] & 0x3) << 4) | (in[1] >> 4)]; + out[2] = alphabet[(in[1] & 0xf) << 2]; + out += 3; + in += 2; + break; + } + + GPR_ASSERT(out == (char *)GPR_SLICE_END_PTR(output)); + GPR_ASSERT(in == GPR_SLICE_END_PTR(input)); + return output; +} + +gpr_slice grpc_chttp2_huffman_compress(gpr_slice input) { + size_t nbits; + uint8_t *in; + uint8_t *out; + gpr_slice output; + uint32_t temp = 0; + uint32_t temp_length = 0; + + nbits = 0; + for (in = GPR_SLICE_START_PTR(input); in != GPR_SLICE_END_PTR(input); ++in) { + nbits += grpc_chttp2_huffsyms[*in].length; + } + + output = gpr_slice_malloc(nbits / 8 + (nbits % 8 != 0)); + out = GPR_SLICE_START_PTR(output); + for (in = GPR_SLICE_START_PTR(input); in != GPR_SLICE_END_PTR(input); ++in) { + int sym = *in; + temp <<= grpc_chttp2_huffsyms[sym].length; + temp |= grpc_chttp2_huffsyms[sym].bits; + temp_length += grpc_chttp2_huffsyms[sym].length; + + while (temp_length > 8) { + temp_length -= 8; + *out++ = (uint8_t)(temp >> temp_length); + } + } + + if (temp_length) { + /* NB: the following integer arithmetic operation needs to be in its + * expanded form due to the "integral promotion" performed (see section + * 3.2.1.1 of the C89 draft standard). A cast to the smaller container type + * is then required to avoid the compiler warning */ + *out++ = (uint8_t)((uint8_t)(temp << (8u - temp_length)) | + (uint8_t)(0xffu >> temp_length)); + } + + GPR_ASSERT(out == GPR_SLICE_END_PTR(output)); + + return output; +} + +typedef struct { + uint32_t temp; + uint32_t temp_length; + uint8_t *out; +} huff_out; + +static void enc_flush_some(huff_out *out) { + while (out->temp_length > 8) { + out->temp_length -= 8; + *out->out++ = (uint8_t)(out->temp >> out->temp_length); + } +} + +static void enc_add2(huff_out *out, uint8_t a, uint8_t b) { + b64_huff_sym sa = huff_alphabet[a]; + b64_huff_sym sb = huff_alphabet[b]; + out->temp = (out->temp << (sa.length + sb.length)) | + ((uint32_t)sa.bits << sb.length) | sb.bits; + out->temp_length += (uint32_t)sa.length + (uint32_t)sb.length; + enc_flush_some(out); +} + +static void enc_add1(huff_out *out, uint8_t a) { + b64_huff_sym sa = huff_alphabet[a]; + out->temp = (out->temp << sa.length) | sa.bits; + out->temp_length += sa.length; + enc_flush_some(out); +} + +gpr_slice grpc_chttp2_base64_encode_and_huffman_compress(gpr_slice input) { + size_t input_length = GPR_SLICE_LENGTH(input); + size_t input_triplets = input_length / 3; + size_t tail_case = input_length % 3; + size_t output_syms = input_triplets * 4 + tail_xtra[tail_case]; + size_t max_output_bits = 11 * output_syms; + size_t max_output_length = max_output_bits / 8 + (max_output_bits % 8 != 0); + gpr_slice output = gpr_slice_malloc(max_output_length); + uint8_t *in = GPR_SLICE_START_PTR(input); + uint8_t *start_out = GPR_SLICE_START_PTR(output); + huff_out out; + size_t i; + + out.temp = 0; + out.temp_length = 0; + out.out = start_out; + + /* encode full triplets */ + for (i = 0; i < input_triplets; i++) { + enc_add2(&out, in[0] >> 2, (uint8_t)((in[0] & 0x3) << 4) | (in[1] >> 4)); + enc_add2(&out, (uint8_t)((in[1] & 0xf) << 2) | (in[2] >> 6), + (uint8_t)(in[2] & 0x3f)); + in += 3; + } + + /* encode the remaining bytes */ + switch (tail_case) { + case 0: + break; + case 1: + enc_add2(&out, in[0] >> 2, (uint8_t)((in[0] & 0x3) << 4)); + in += 1; + break; + case 2: + enc_add2(&out, in[0] >> 2, + (uint8_t)((in[0] & 0x3) << 4) | (uint8_t)(in[1] >> 4)); + enc_add1(&out, (uint8_t)((in[1] & 0xf) << 2)); + in += 2; + break; + } + + if (out.temp_length) { + /* NB: the following integer arithmetic operation needs to be in its + * expanded form due to the "integral promotion" performed (see section + * 3.2.1.1 of the C89 draft standard). A cast to the smaller container type + * is then required to avoid the compiler warning */ + *out.out++ = (uint8_t)((uint8_t)(out.temp << (8u - out.temp_length)) | + (uint8_t)(0xffu >> out.temp_length)); + } + + GPR_ASSERT(out.out <= GPR_SLICE_END_PTR(output)); + GPR_SLICE_SET_LENGTH(output, out.out - start_out); + + GPR_ASSERT(in == GPR_SLICE_END_PTR(input)); + return output; +} diff --git a/src/core/lib/transport/chttp2/bin_encoder.h b/src/core/lib/transport/chttp2/bin_encoder.h new file mode 100644 index 0000000000..edb6f2dad1 --- /dev/null +++ b/src/core/lib/transport/chttp2/bin_encoder.h @@ -0,0 +1,54 @@ +/* + * + * Copyright 2015-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_TRANSPORT_CHTTP2_BIN_ENCODER_H +#define GRPC_CORE_TRANSPORT_CHTTP2_BIN_ENCODER_H + +#include + +/* base64 encode a slice. Returns a new slice, does not take ownership of the + input */ +gpr_slice grpc_chttp2_base64_encode(gpr_slice input); + +/* Compress a slice with the static huffman encoder detailed in the hpack + standard. Returns a new slice, does not take ownership of the input */ +gpr_slice grpc_chttp2_huffman_compress(gpr_slice input); + +/* equivalent to: + gpr_slice x = grpc_chttp2_base64_encode(input); + gpr_slice y = grpc_chttp2_huffman_compress(x); + gpr_slice_unref(x); + return y; */ +gpr_slice grpc_chttp2_base64_encode_and_huffman_compress(gpr_slice input); + +#endif /* GRPC_CORE_TRANSPORT_CHTTP2_BIN_ENCODER_H */ diff --git a/src/core/lib/transport/chttp2/frame.h b/src/core/lib/transport/chttp2/frame.h new file mode 100644 index 0000000000..560a6675af --- /dev/null +++ b/src/core/lib/transport/chttp2/frame.h @@ -0,0 +1,69 @@ +/* + * + * Copyright 2015-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_TRANSPORT_CHTTP2_FRAME_H +#define GRPC_CORE_TRANSPORT_CHTTP2_FRAME_H + +#include +#include + +/* Common definitions for frame handling in the chttp2 transport */ + +typedef enum { + GRPC_CHTTP2_PARSE_OK, + GRPC_CHTTP2_STREAM_ERROR, + GRPC_CHTTP2_CONNECTION_ERROR +} grpc_chttp2_parse_error; + +/* defined in internal.h */ +typedef struct grpc_chttp2_stream_parsing grpc_chttp2_stream_parsing; +typedef struct grpc_chttp2_transport_parsing grpc_chttp2_transport_parsing; + +#define GRPC_CHTTP2_FRAME_DATA 0 +#define GRPC_CHTTP2_FRAME_HEADER 1 +#define GRPC_CHTTP2_FRAME_CONTINUATION 9 +#define GRPC_CHTTP2_FRAME_RST_STREAM 3 +#define GRPC_CHTTP2_FRAME_SETTINGS 4 +#define GRPC_CHTTP2_FRAME_PING 6 +#define GRPC_CHTTP2_FRAME_GOAWAY 7 +#define GRPC_CHTTP2_FRAME_WINDOW_UPDATE 8 + +#define GRPC_CHTTP2_MAX_PAYLOAD_LENGTH ((1 << 14) - 1) + +#define GRPC_CHTTP2_DATA_FLAG_END_STREAM 1 +#define GRPC_CHTTP2_FLAG_ACK 1 +#define GRPC_CHTTP2_DATA_FLAG_END_HEADERS 4 +#define GRPC_CHTTP2_DATA_FLAG_PADDED 8 +#define GRPC_CHTTP2_FLAG_HAS_PRIORITY 0x20 + +#endif /* GRPC_CORE_TRANSPORT_CHTTP2_FRAME_H */ diff --git a/src/core/lib/transport/chttp2/frame_data.c b/src/core/lib/transport/chttp2/frame_data.c new file mode 100644 index 0000000000..6cc6d4eaf2 --- /dev/null +++ b/src/core/lib/transport/chttp2/frame_data.c @@ -0,0 +1,248 @@ +/* + * + * Copyright 2015-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/transport/chttp2/frame_data.h" + +#include + +#include +#include +#include +#include "src/core/support/string.h" +#include "src/core/transport/chttp2/internal.h" +#include "src/core/transport/transport.h" + +grpc_chttp2_parse_error grpc_chttp2_data_parser_init( + grpc_chttp2_data_parser *parser) { + parser->state = GRPC_CHTTP2_DATA_FH_0; + parser->parsing_frame = NULL; + return GRPC_CHTTP2_PARSE_OK; +} + +void grpc_chttp2_data_parser_destroy(grpc_exec_ctx *exec_ctx, + grpc_chttp2_data_parser *parser) { + grpc_byte_stream *bs; + if (parser->parsing_frame) { + grpc_chttp2_incoming_byte_stream_finished(exec_ctx, parser->parsing_frame, + 0, 1); + } + while ( + (bs = grpc_chttp2_incoming_frame_queue_pop(&parser->incoming_frames))) { + grpc_byte_stream_destroy(exec_ctx, bs); + } +} + +grpc_chttp2_parse_error grpc_chttp2_data_parser_begin_frame( + grpc_chttp2_data_parser *parser, uint8_t flags) { + if (flags & ~GRPC_CHTTP2_DATA_FLAG_END_STREAM) { + gpr_log(GPR_ERROR, "unsupported data flags: 0x%02x", flags); + return GRPC_CHTTP2_STREAM_ERROR; + } + + if (flags & GRPC_CHTTP2_DATA_FLAG_END_STREAM) { + parser->is_last_frame = 1; + } else { + parser->is_last_frame = 0; + } + + return GRPC_CHTTP2_PARSE_OK; +} + +void grpc_chttp2_incoming_frame_queue_merge( + grpc_chttp2_incoming_frame_queue *head_dst, + grpc_chttp2_incoming_frame_queue *tail_src) { + if (tail_src->head == NULL) { + return; + } + + if (head_dst->head == NULL) { + *head_dst = *tail_src; + memset(tail_src, 0, sizeof(*tail_src)); + return; + } + + head_dst->tail->next_message = tail_src->head; + head_dst->tail = tail_src->tail; + memset(tail_src, 0, sizeof(*tail_src)); +} + +grpc_byte_stream *grpc_chttp2_incoming_frame_queue_pop( + grpc_chttp2_incoming_frame_queue *q) { + grpc_byte_stream *out; + if (q->head == NULL) { + return NULL; + } + out = &q->head->base; + if (q->head == q->tail) { + memset(q, 0, sizeof(*q)); + } else { + q->head = q->head->next_message; + } + return out; +} + +void grpc_chttp2_encode_data(uint32_t id, gpr_slice_buffer *inbuf, + uint32_t write_bytes, int is_eof, + gpr_slice_buffer *outbuf) { + gpr_slice hdr; + uint8_t *p; + + hdr = gpr_slice_malloc(9); + p = GPR_SLICE_START_PTR(hdr); + GPR_ASSERT(write_bytes < (1 << 24)); + *p++ = (uint8_t)(write_bytes >> 16); + *p++ = (uint8_t)(write_bytes >> 8); + *p++ = (uint8_t)(write_bytes); + *p++ = GRPC_CHTTP2_FRAME_DATA; + *p++ = is_eof ? GRPC_CHTTP2_DATA_FLAG_END_STREAM : 0; + *p++ = (uint8_t)(id >> 24); + *p++ = (uint8_t)(id >> 16); + *p++ = (uint8_t)(id >> 8); + *p++ = (uint8_t)(id); + gpr_slice_buffer_add(outbuf, hdr); + + gpr_slice_buffer_move_first(inbuf, write_bytes, outbuf); +} + +grpc_chttp2_parse_error grpc_chttp2_data_parser_parse( + grpc_exec_ctx *exec_ctx, void *parser, + grpc_chttp2_transport_parsing *transport_parsing, + grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { + uint8_t *const beg = GPR_SLICE_START_PTR(slice); + uint8_t *const end = GPR_SLICE_END_PTR(slice); + uint8_t *cur = beg; + grpc_chttp2_data_parser *p = parser; + uint32_t message_flags; + grpc_chttp2_incoming_byte_stream *incoming_byte_stream; + + if (is_last && p->is_last_frame) { + stream_parsing->received_close = 1; + } + + if (cur == end) { + return GRPC_CHTTP2_PARSE_OK; + } + + switch (p->state) { + fh_0: + case GRPC_CHTTP2_DATA_FH_0: + p->frame_type = *cur; + switch (p->frame_type) { + case 0: + p->is_frame_compressed = 0; /* GPR_FALSE */ + break; + case 1: + p->is_frame_compressed = 1; /* GPR_TRUE */ + break; + default: + gpr_log(GPR_ERROR, "Bad GRPC frame type 0x%02x", p->frame_type); + return GRPC_CHTTP2_STREAM_ERROR; + } + if (++cur == end) { + p->state = GRPC_CHTTP2_DATA_FH_1; + return GRPC_CHTTP2_PARSE_OK; + } + /* fallthrough */ + case GRPC_CHTTP2_DATA_FH_1: + p->frame_size = ((uint32_t)*cur) << 24; + if (++cur == end) { + p->state = GRPC_CHTTP2_DATA_FH_2; + return GRPC_CHTTP2_PARSE_OK; + } + /* fallthrough */ + case GRPC_CHTTP2_DATA_FH_2: + p->frame_size |= ((uint32_t)*cur) << 16; + if (++cur == end) { + p->state = GRPC_CHTTP2_DATA_FH_3; + return GRPC_CHTTP2_PARSE_OK; + } + /* fallthrough */ + case GRPC_CHTTP2_DATA_FH_3: + p->frame_size |= ((uint32_t)*cur) << 8; + if (++cur == end) { + p->state = GRPC_CHTTP2_DATA_FH_4; + return GRPC_CHTTP2_PARSE_OK; + } + /* fallthrough */ + case GRPC_CHTTP2_DATA_FH_4: + p->frame_size |= ((uint32_t)*cur); + p->state = GRPC_CHTTP2_DATA_FRAME; + ++cur; + message_flags = 0; + if (p->is_frame_compressed) { + message_flags |= GRPC_WRITE_INTERNAL_COMPRESS; + } + p->parsing_frame = incoming_byte_stream = + grpc_chttp2_incoming_byte_stream_create( + exec_ctx, transport_parsing, stream_parsing, p->frame_size, + message_flags, &p->incoming_frames); + /* fallthrough */ + case GRPC_CHTTP2_DATA_FRAME: + if (cur == end) { + grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, + stream_parsing); + return GRPC_CHTTP2_PARSE_OK; + } + grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, + stream_parsing); + if ((uint32_t)(end - cur) == p->frame_size) { + grpc_chttp2_incoming_byte_stream_push( + exec_ctx, p->parsing_frame, + gpr_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg))); + grpc_chttp2_incoming_byte_stream_finished(exec_ctx, p->parsing_frame, 1, + 1); + p->parsing_frame = NULL; + p->state = GRPC_CHTTP2_DATA_FH_0; + return GRPC_CHTTP2_PARSE_OK; + } else if ((uint32_t)(end - cur) > p->frame_size) { + grpc_chttp2_incoming_byte_stream_push( + exec_ctx, p->parsing_frame, + gpr_slice_sub(slice, (size_t)(cur - beg), + (size_t)(cur + p->frame_size - beg))); + grpc_chttp2_incoming_byte_stream_finished(exec_ctx, p->parsing_frame, 1, + 1); + p->parsing_frame = NULL; + cur += p->frame_size; + goto fh_0; /* loop */ + } else { + grpc_chttp2_incoming_byte_stream_push( + exec_ctx, p->parsing_frame, + gpr_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg))); + GPR_ASSERT((size_t)(end - cur) <= p->frame_size); + p->frame_size -= (uint32_t)(end - cur); + return GRPC_CHTTP2_PARSE_OK; + } + } + + GPR_UNREACHABLE_CODE(return GRPC_CHTTP2_CONNECTION_ERROR); +} diff --git a/src/core/lib/transport/chttp2/frame_data.h b/src/core/lib/transport/chttp2/frame_data.h new file mode 100644 index 0000000000..9dbaa60d44 --- /dev/null +++ b/src/core/lib/transport/chttp2/frame_data.h @@ -0,0 +1,101 @@ +/* + * + * Copyright 2015-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_TRANSPORT_CHTTP2_FRAME_DATA_H +#define GRPC_CORE_TRANSPORT_CHTTP2_FRAME_DATA_H + +/* Parser for GRPC streams embedded in DATA frames */ + +#include +#include +#include "src/core/iomgr/exec_ctx.h" +#include "src/core/transport/byte_stream.h" +#include "src/core/transport/chttp2/frame.h" + +typedef enum { + GRPC_CHTTP2_DATA_FH_0, + GRPC_CHTTP2_DATA_FH_1, + GRPC_CHTTP2_DATA_FH_2, + GRPC_CHTTP2_DATA_FH_3, + GRPC_CHTTP2_DATA_FH_4, + GRPC_CHTTP2_DATA_FRAME +} grpc_chttp2_stream_state; + +typedef struct grpc_chttp2_incoming_byte_stream + grpc_chttp2_incoming_byte_stream; + +typedef struct grpc_chttp2_incoming_frame_queue { + grpc_chttp2_incoming_byte_stream *head; + grpc_chttp2_incoming_byte_stream *tail; +} grpc_chttp2_incoming_frame_queue; + +typedef struct { + grpc_chttp2_stream_state state; + uint8_t is_last_frame; + uint8_t frame_type; + uint32_t frame_size; + + int is_frame_compressed; + grpc_chttp2_incoming_frame_queue incoming_frames; + grpc_chttp2_incoming_byte_stream *parsing_frame; +} grpc_chttp2_data_parser; + +void grpc_chttp2_incoming_frame_queue_merge( + grpc_chttp2_incoming_frame_queue *head_dst, + grpc_chttp2_incoming_frame_queue *tail_src); +grpc_byte_stream *grpc_chttp2_incoming_frame_queue_pop( + grpc_chttp2_incoming_frame_queue *q); + +/* initialize per-stream state for data frame parsing */ +grpc_chttp2_parse_error grpc_chttp2_data_parser_init( + grpc_chttp2_data_parser *parser); + +void grpc_chttp2_data_parser_destroy(grpc_exec_ctx *exec_ctx, + grpc_chttp2_data_parser *parser); + +/* start processing a new data frame */ +grpc_chttp2_parse_error grpc_chttp2_data_parser_begin_frame( + grpc_chttp2_data_parser *parser, uint8_t flags); + +/* handle a slice of a data frame - is_last indicates the last slice of a + frame */ +grpc_chttp2_parse_error grpc_chttp2_data_parser_parse( + grpc_exec_ctx *exec_ctx, void *parser, + grpc_chttp2_transport_parsing *transport_parsing, + grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); + +void grpc_chttp2_encode_data(uint32_t id, gpr_slice_buffer *inbuf, + uint32_t write_bytes, int is_eof, + gpr_slice_buffer *outbuf); + +#endif /* GRPC_CORE_TRANSPORT_CHTTP2_FRAME_DATA_H */ diff --git a/src/core/lib/transport/chttp2/frame_goaway.c b/src/core/lib/transport/chttp2/frame_goaway.c new file mode 100644 index 0000000000..2fa525e989 --- /dev/null +++ b/src/core/lib/transport/chttp2/frame_goaway.c @@ -0,0 +1,193 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/transport/chttp2/frame_goaway.h" +#include "src/core/transport/chttp2/internal.h" + +#include + +#include +#include + +void grpc_chttp2_goaway_parser_init(grpc_chttp2_goaway_parser *p) { + p->debug_data = NULL; +} + +void grpc_chttp2_goaway_parser_destroy(grpc_chttp2_goaway_parser *p) { + gpr_free(p->debug_data); +} + +grpc_chttp2_parse_error grpc_chttp2_goaway_parser_begin_frame( + grpc_chttp2_goaway_parser *p, uint32_t length, uint8_t flags) { + if (length < 8) { + gpr_log(GPR_ERROR, "goaway frame too short (%d bytes)", length); + return GRPC_CHTTP2_CONNECTION_ERROR; + } + + gpr_free(p->debug_data); + p->debug_length = length - 8; + p->debug_data = gpr_malloc(p->debug_length); + p->debug_pos = 0; + p->state = GRPC_CHTTP2_GOAWAY_LSI0; + return GRPC_CHTTP2_PARSE_OK; +} + +grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse( + grpc_exec_ctx *exec_ctx, void *parser, + grpc_chttp2_transport_parsing *transport_parsing, + grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { + uint8_t *const beg = GPR_SLICE_START_PTR(slice); + uint8_t *const end = GPR_SLICE_END_PTR(slice); + uint8_t *cur = beg; + grpc_chttp2_goaway_parser *p = parser; + + switch (p->state) { + case GRPC_CHTTP2_GOAWAY_LSI0: + if (cur == end) { + p->state = GRPC_CHTTP2_GOAWAY_LSI0; + return GRPC_CHTTP2_PARSE_OK; + } + p->last_stream_id = ((uint32_t)*cur) << 24; + ++cur; + /* fallthrough */ + case GRPC_CHTTP2_GOAWAY_LSI1: + if (cur == end) { + p->state = GRPC_CHTTP2_GOAWAY_LSI1; + return GRPC_CHTTP2_PARSE_OK; + } + p->last_stream_id |= ((uint32_t)*cur) << 16; + ++cur; + /* fallthrough */ + case GRPC_CHTTP2_GOAWAY_LSI2: + if (cur == end) { + p->state = GRPC_CHTTP2_GOAWAY_LSI2; + return GRPC_CHTTP2_PARSE_OK; + } + p->last_stream_id |= ((uint32_t)*cur) << 8; + ++cur; + /* fallthrough */ + case GRPC_CHTTP2_GOAWAY_LSI3: + if (cur == end) { + p->state = GRPC_CHTTP2_GOAWAY_LSI3; + return GRPC_CHTTP2_PARSE_OK; + } + p->last_stream_id |= ((uint32_t)*cur); + ++cur; + /* fallthrough */ + case GRPC_CHTTP2_GOAWAY_ERR0: + if (cur == end) { + p->state = GRPC_CHTTP2_GOAWAY_ERR0; + return GRPC_CHTTP2_PARSE_OK; + } + p->error_code = ((uint32_t)*cur) << 24; + ++cur; + /* fallthrough */ + case GRPC_CHTTP2_GOAWAY_ERR1: + if (cur == end) { + p->state = GRPC_CHTTP2_GOAWAY_ERR1; + return GRPC_CHTTP2_PARSE_OK; + } + p->error_code |= ((uint32_t)*cur) << 16; + ++cur; + /* fallthrough */ + case GRPC_CHTTP2_GOAWAY_ERR2: + if (cur == end) { + p->state = GRPC_CHTTP2_GOAWAY_ERR2; + return GRPC_CHTTP2_PARSE_OK; + } + p->error_code |= ((uint32_t)*cur) << 8; + ++cur; + /* fallthrough */ + case GRPC_CHTTP2_GOAWAY_ERR3: + if (cur == end) { + p->state = GRPC_CHTTP2_GOAWAY_ERR3; + return GRPC_CHTTP2_PARSE_OK; + } + p->error_code |= ((uint32_t)*cur); + ++cur; + /* fallthrough */ + case GRPC_CHTTP2_GOAWAY_DEBUG: + memcpy(p->debug_data + p->debug_pos, cur, (size_t)(end - cur)); + GPR_ASSERT((size_t)(end - cur) < UINT32_MAX - p->debug_pos); + p->debug_pos += (uint32_t)(end - cur); + p->state = GRPC_CHTTP2_GOAWAY_DEBUG; + if (is_last) { + transport_parsing->goaway_received = 1; + transport_parsing->goaway_last_stream_index = p->last_stream_id; + gpr_slice_unref(transport_parsing->goaway_text); + transport_parsing->goaway_error = (grpc_status_code)p->error_code; + transport_parsing->goaway_text = + gpr_slice_new(p->debug_data, p->debug_length, gpr_free); + p->debug_data = NULL; + } + return GRPC_CHTTP2_PARSE_OK; + } + GPR_UNREACHABLE_CODE(return GRPC_CHTTP2_CONNECTION_ERROR); +} + +void grpc_chttp2_goaway_append(uint32_t last_stream_id, uint32_t error_code, + gpr_slice debug_data, + gpr_slice_buffer *slice_buffer) { + gpr_slice header = gpr_slice_malloc(9 + 4 + 4); + uint8_t *p = GPR_SLICE_START_PTR(header); + uint32_t frame_length; + GPR_ASSERT(GPR_SLICE_LENGTH(debug_data) < UINT32_MAX - 4 - 4); + frame_length = 4 + 4 + (uint32_t)GPR_SLICE_LENGTH(debug_data); + + /* frame header: length */ + *p++ = (uint8_t)(frame_length >> 16); + *p++ = (uint8_t)(frame_length >> 8); + *p++ = (uint8_t)(frame_length); + /* frame header: type */ + *p++ = GRPC_CHTTP2_FRAME_GOAWAY; + /* frame header: flags */ + *p++ = 0; + /* frame header: stream id */ + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + /* payload: last stream id */ + *p++ = (uint8_t)(last_stream_id >> 24); + *p++ = (uint8_t)(last_stream_id >> 16); + *p++ = (uint8_t)(last_stream_id >> 8); + *p++ = (uint8_t)(last_stream_id); + /* payload: error code */ + *p++ = (uint8_t)(error_code >> 24); + *p++ = (uint8_t)(error_code >> 16); + *p++ = (uint8_t)(error_code >> 8); + *p++ = (uint8_t)(error_code); + GPR_ASSERT(p == GPR_SLICE_END_PTR(header)); + gpr_slice_buffer_add(slice_buffer, header); + gpr_slice_buffer_add(slice_buffer, debug_data); +} diff --git a/src/core/lib/transport/chttp2/frame_goaway.h b/src/core/lib/transport/chttp2/frame_goaway.h new file mode 100644 index 0000000000..b980e47723 --- /dev/null +++ b/src/core/lib/transport/chttp2/frame_goaway.h @@ -0,0 +1,77 @@ +/* + * + * Copyright 2015-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_TRANSPORT_CHTTP2_FRAME_GOAWAY_H +#define GRPC_CORE_TRANSPORT_CHTTP2_FRAME_GOAWAY_H + +#include +#include +#include +#include "src/core/iomgr/exec_ctx.h" +#include "src/core/transport/chttp2/frame.h" + +typedef enum { + GRPC_CHTTP2_GOAWAY_LSI0, + GRPC_CHTTP2_GOAWAY_LSI1, + GRPC_CHTTP2_GOAWAY_LSI2, + GRPC_CHTTP2_GOAWAY_LSI3, + GRPC_CHTTP2_GOAWAY_ERR0, + GRPC_CHTTP2_GOAWAY_ERR1, + GRPC_CHTTP2_GOAWAY_ERR2, + GRPC_CHTTP2_GOAWAY_ERR3, + GRPC_CHTTP2_GOAWAY_DEBUG +} grpc_chttp2_goaway_parse_state; + +typedef struct { + grpc_chttp2_goaway_parse_state state; + uint32_t last_stream_id; + uint32_t error_code; + char *debug_data; + uint32_t debug_length; + uint32_t debug_pos; +} grpc_chttp2_goaway_parser; + +void grpc_chttp2_goaway_parser_init(grpc_chttp2_goaway_parser *p); +void grpc_chttp2_goaway_parser_destroy(grpc_chttp2_goaway_parser *p); +grpc_chttp2_parse_error grpc_chttp2_goaway_parser_begin_frame( + grpc_chttp2_goaway_parser *parser, uint32_t length, uint8_t flags); +grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse( + grpc_exec_ctx *exec_ctx, void *parser, + grpc_chttp2_transport_parsing *transport_parsing, + grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); + +void grpc_chttp2_goaway_append(uint32_t last_stream_id, uint32_t error_code, + gpr_slice debug_data, + gpr_slice_buffer *slice_buffer); + +#endif /* GRPC_CORE_TRANSPORT_CHTTP2_FRAME_GOAWAY_H */ diff --git a/src/core/lib/transport/chttp2/frame_ping.c b/src/core/lib/transport/chttp2/frame_ping.c new file mode 100644 index 0000000000..c6ab522283 --- /dev/null +++ b/src/core/lib/transport/chttp2/frame_ping.c @@ -0,0 +1,97 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/transport/chttp2/frame_ping.h" +#include "src/core/transport/chttp2/internal.h" + +#include + +#include +#include + +gpr_slice grpc_chttp2_ping_create(uint8_t ack, uint8_t *opaque_8bytes) { + gpr_slice slice = gpr_slice_malloc(9 + 8); + uint8_t *p = GPR_SLICE_START_PTR(slice); + + *p++ = 0; + *p++ = 0; + *p++ = 8; + *p++ = GRPC_CHTTP2_FRAME_PING; + *p++ = ack ? 1 : 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + memcpy(p, opaque_8bytes, 8); + + return slice; +} + +grpc_chttp2_parse_error grpc_chttp2_ping_parser_begin_frame( + grpc_chttp2_ping_parser *parser, uint32_t length, uint8_t flags) { + if (flags & 0xfe || length != 8) { + gpr_log(GPR_ERROR, "invalid ping: length=%d, flags=%02x", length, flags); + return GRPC_CHTTP2_CONNECTION_ERROR; + } + parser->byte = 0; + parser->is_ack = flags; + return GRPC_CHTTP2_PARSE_OK; +} + +grpc_chttp2_parse_error grpc_chttp2_ping_parser_parse( + grpc_exec_ctx *exec_ctx, void *parser, + grpc_chttp2_transport_parsing *transport_parsing, + grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { + uint8_t *const beg = GPR_SLICE_START_PTR(slice); + uint8_t *const end = GPR_SLICE_END_PTR(slice); + uint8_t *cur = beg; + grpc_chttp2_ping_parser *p = parser; + + while (p->byte != 8 && cur != end) { + p->opaque_8bytes[p->byte] = *cur; + cur++; + p->byte++; + } + + if (p->byte == 8) { + GPR_ASSERT(is_last); + if (p->is_ack) { + grpc_chttp2_ack_ping(exec_ctx, transport_parsing, p->opaque_8bytes); + } else { + gpr_slice_buffer_add(&transport_parsing->qbuf, + grpc_chttp2_ping_create(1, p->opaque_8bytes)); + } + } + + return GRPC_CHTTP2_PARSE_OK; +} diff --git a/src/core/lib/transport/chttp2/frame_ping.h b/src/core/lib/transport/chttp2/frame_ping.h new file mode 100644 index 0000000000..2412cd7a6f --- /dev/null +++ b/src/core/lib/transport/chttp2/frame_ping.h @@ -0,0 +1,56 @@ +/* + * + * Copyright 2015-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_TRANSPORT_CHTTP2_FRAME_PING_H +#define GRPC_CORE_TRANSPORT_CHTTP2_FRAME_PING_H + +#include +#include "src/core/iomgr/exec_ctx.h" +#include "src/core/transport/chttp2/frame.h" + +typedef struct { + uint8_t byte; + uint8_t is_ack; + uint8_t opaque_8bytes[8]; +} grpc_chttp2_ping_parser; + +gpr_slice grpc_chttp2_ping_create(uint8_t ack, uint8_t *opaque_8bytes); + +grpc_chttp2_parse_error grpc_chttp2_ping_parser_begin_frame( + grpc_chttp2_ping_parser *parser, uint32_t length, uint8_t flags); +grpc_chttp2_parse_error grpc_chttp2_ping_parser_parse( + grpc_exec_ctx *exec_ctx, void *parser, + grpc_chttp2_transport_parsing *transport_parsing, + grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); + +#endif /* GRPC_CORE_TRANSPORT_CHTTP2_FRAME_PING_H */ diff --git a/src/core/lib/transport/chttp2/frame_rst_stream.c b/src/core/lib/transport/chttp2/frame_rst_stream.c new file mode 100644 index 0000000000..754529e4b9 --- /dev/null +++ b/src/core/lib/transport/chttp2/frame_rst_stream.c @@ -0,0 +1,99 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/transport/chttp2/frame_rst_stream.h" +#include "src/core/transport/chttp2/internal.h" + +#include + +#include "src/core/transport/chttp2/frame.h" + +gpr_slice grpc_chttp2_rst_stream_create(uint32_t id, uint32_t code) { + gpr_slice slice = gpr_slice_malloc(13); + uint8_t *p = GPR_SLICE_START_PTR(slice); + + *p++ = 0; + *p++ = 0; + *p++ = 4; + *p++ = GRPC_CHTTP2_FRAME_RST_STREAM; + *p++ = 0; + *p++ = (uint8_t)(id >> 24); + *p++ = (uint8_t)(id >> 16); + *p++ = (uint8_t)(id >> 8); + *p++ = (uint8_t)(id); + *p++ = (uint8_t)(code >> 24); + *p++ = (uint8_t)(code >> 16); + *p++ = (uint8_t)(code >> 8); + *p++ = (uint8_t)(code); + + return slice; +} + +grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_begin_frame( + grpc_chttp2_rst_stream_parser *parser, uint32_t length, uint8_t flags) { + if (length != 4) { + gpr_log(GPR_ERROR, "invalid rst_stream: length=%d, flags=%02x", length, + flags); + return GRPC_CHTTP2_CONNECTION_ERROR; + } + parser->byte = 0; + return GRPC_CHTTP2_PARSE_OK; +} + +grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_parse( + grpc_exec_ctx *exec_ctx, void *parser, + grpc_chttp2_transport_parsing *transport_parsing, + grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { + uint8_t *const beg = GPR_SLICE_START_PTR(slice); + uint8_t *const end = GPR_SLICE_END_PTR(slice); + uint8_t *cur = beg; + grpc_chttp2_rst_stream_parser *p = parser; + + while (p->byte != 4 && cur != end) { + p->reason_bytes[p->byte] = *cur; + cur++; + p->byte++; + } + + if (p->byte == 4) { + GPR_ASSERT(is_last); + stream_parsing->received_close = 1; + stream_parsing->saw_rst_stream = 1; + stream_parsing->rst_stream_reason = (((uint32_t)p->reason_bytes[0]) << 24) | + (((uint32_t)p->reason_bytes[1]) << 16) | + (((uint32_t)p->reason_bytes[2]) << 8) | + (((uint32_t)p->reason_bytes[3])); + } + + return GRPC_CHTTP2_PARSE_OK; +} diff --git a/src/core/lib/transport/chttp2/frame_rst_stream.h b/src/core/lib/transport/chttp2/frame_rst_stream.h new file mode 100644 index 0000000000..f725c5d767 --- /dev/null +++ b/src/core/lib/transport/chttp2/frame_rst_stream.h @@ -0,0 +1,55 @@ +/* + * + * Copyright 2015-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_TRANSPORT_CHTTP2_FRAME_RST_STREAM_H +#define GRPC_CORE_TRANSPORT_CHTTP2_FRAME_RST_STREAM_H + +#include +#include "src/core/iomgr/exec_ctx.h" +#include "src/core/transport/chttp2/frame.h" + +typedef struct { + uint8_t byte; + uint8_t reason_bytes[4]; +} grpc_chttp2_rst_stream_parser; + +gpr_slice grpc_chttp2_rst_stream_create(uint32_t stream_id, uint32_t code); + +grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_begin_frame( + grpc_chttp2_rst_stream_parser *parser, uint32_t length, uint8_t flags); +grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_parse( + grpc_exec_ctx *exec_ctx, void *parser, + grpc_chttp2_transport_parsing *transport_parsing, + grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); + +#endif /* GRPC_CORE_TRANSPORT_CHTTP2_FRAME_RST_STREAM_H */ diff --git a/src/core/lib/transport/chttp2/frame_settings.c b/src/core/lib/transport/chttp2/frame_settings.c new file mode 100644 index 0000000000..cc49dd4f69 --- /dev/null +++ b/src/core/lib/transport/chttp2/frame_settings.c @@ -0,0 +1,259 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/transport/chttp2/frame_settings.h" +#include "src/core/transport/chttp2/internal.h" + +#include + +#include +#include + +#include "src/core/debug/trace.h" +#include "src/core/transport/chttp2/frame.h" +#include "src/core/transport/chttp2/http2_errors.h" +#include "src/core/transport/chttp2_transport.h" + +#define MAX_MAX_HEADER_LIST_SIZE (1024 * 1024 * 1024) + +/* HTTP/2 mandated initial connection settings */ +const grpc_chttp2_setting_parameters + grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS] = { + {NULL, 0, 0, 0, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, + GRPC_CHTTP2_PROTOCOL_ERROR}, + {"HEADER_TABLE_SIZE", 4096, 0, 0xffffffff, + GRPC_CHTTP2_CLAMP_INVALID_VALUE, GRPC_CHTTP2_PROTOCOL_ERROR}, + {"ENABLE_PUSH", 1, 0, 1, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, + GRPC_CHTTP2_PROTOCOL_ERROR}, + {"MAX_CONCURRENT_STREAMS", 0xffffffffu, 0, 0xffffffffu, + GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, GRPC_CHTTP2_PROTOCOL_ERROR}, + {"INITIAL_WINDOW_SIZE", 65535, 0, 0x7fffffffu, + GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, + GRPC_CHTTP2_FLOW_CONTROL_ERROR}, + {"MAX_FRAME_SIZE", 16384, 16384, 16777215, + GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, GRPC_CHTTP2_PROTOCOL_ERROR}, + {"MAX_HEADER_LIST_SIZE", MAX_MAX_HEADER_LIST_SIZE, 0, + MAX_MAX_HEADER_LIST_SIZE, GRPC_CHTTP2_CLAMP_INVALID_VALUE, + GRPC_CHTTP2_PROTOCOL_ERROR}, +}; + +static uint8_t *fill_header(uint8_t *out, uint32_t length, uint8_t flags) { + *out++ = (uint8_t)(length >> 16); + *out++ = (uint8_t)(length >> 8); + *out++ = (uint8_t)(length); + *out++ = GRPC_CHTTP2_FRAME_SETTINGS; + *out++ = flags; + *out++ = 0; + *out++ = 0; + *out++ = 0; + *out++ = 0; + return out; +} + +gpr_slice grpc_chttp2_settings_create(uint32_t *old, const uint32_t *new, + uint32_t force_mask, size_t count) { + size_t i; + uint32_t n = 0; + gpr_slice output; + uint8_t *p; + + for (i = 0; i < count; i++) { + n += (new[i] != old[i] || (force_mask & (1u << i)) != 0); + } + + output = gpr_slice_malloc(9 + 6 * n); + p = fill_header(GPR_SLICE_START_PTR(output), 6 * n, 0); + + for (i = 0; i < count; i++) { + if (new[i] != old[i] || (force_mask & (1u << i)) != 0) { + GPR_ASSERT(i); + *p++ = (uint8_t)(i >> 8); + *p++ = (uint8_t)(i); + *p++ = (uint8_t)(new[i] >> 24); + *p++ = (uint8_t)(new[i] >> 16); + *p++ = (uint8_t)(new[i] >> 8); + *p++ = (uint8_t)(new[i]); + old[i] = new[i]; + } + } + + GPR_ASSERT(p == GPR_SLICE_END_PTR(output)); + + return output; +} + +gpr_slice grpc_chttp2_settings_ack_create(void) { + gpr_slice output = gpr_slice_malloc(9); + fill_header(GPR_SLICE_START_PTR(output), 0, GRPC_CHTTP2_FLAG_ACK); + return output; +} + +grpc_chttp2_parse_error grpc_chttp2_settings_parser_begin_frame( + grpc_chttp2_settings_parser *parser, uint32_t length, uint8_t flags, + uint32_t *settings) { + parser->target_settings = settings; + memcpy(parser->incoming_settings, settings, + GRPC_CHTTP2_NUM_SETTINGS * sizeof(uint32_t)); + parser->is_ack = 0; + parser->state = GRPC_CHTTP2_SPS_ID0; + if (flags == GRPC_CHTTP2_FLAG_ACK) { + parser->is_ack = 1; + if (length != 0) { + gpr_log(GPR_ERROR, "non-empty settings ack frame received"); + return GRPC_CHTTP2_CONNECTION_ERROR; + } + return GRPC_CHTTP2_PARSE_OK; + } else if (flags != 0) { + gpr_log(GPR_ERROR, "invalid flags on settings frame"); + return GRPC_CHTTP2_CONNECTION_ERROR; + } else if (length % 6 != 0) { + gpr_log(GPR_ERROR, "settings frames must be a multiple of six bytes"); + return GRPC_CHTTP2_CONNECTION_ERROR; + } else { + return GRPC_CHTTP2_PARSE_OK; + } +} + +grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse( + grpc_exec_ctx *exec_ctx, void *p, + grpc_chttp2_transport_parsing *transport_parsing, + grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { + grpc_chttp2_settings_parser *parser = p; + const uint8_t *cur = GPR_SLICE_START_PTR(slice); + const uint8_t *end = GPR_SLICE_END_PTR(slice); + + if (parser->is_ack) { + return GRPC_CHTTP2_PARSE_OK; + } + + for (;;) { + switch (parser->state) { + case GRPC_CHTTP2_SPS_ID0: + if (cur == end) { + parser->state = GRPC_CHTTP2_SPS_ID0; + if (is_last) { + transport_parsing->settings_updated = 1; + memcpy(parser->target_settings, parser->incoming_settings, + GRPC_CHTTP2_NUM_SETTINGS * sizeof(uint32_t)); + gpr_slice_buffer_add(&transport_parsing->qbuf, + grpc_chttp2_settings_ack_create()); + } + return GRPC_CHTTP2_PARSE_OK; + } + parser->id = (uint16_t)(((uint16_t)*cur) << 8); + cur++; + /* fallthrough */ + case GRPC_CHTTP2_SPS_ID1: + if (cur == end) { + parser->state = GRPC_CHTTP2_SPS_ID1; + return GRPC_CHTTP2_PARSE_OK; + } + parser->id = (uint16_t)(parser->id | (*cur)); + cur++; + /* fallthrough */ + case GRPC_CHTTP2_SPS_VAL0: + if (cur == end) { + parser->state = GRPC_CHTTP2_SPS_VAL0; + return GRPC_CHTTP2_PARSE_OK; + } + parser->value = ((uint32_t)*cur) << 24; + cur++; + /* fallthrough */ + case GRPC_CHTTP2_SPS_VAL1: + if (cur == end) { + parser->state = GRPC_CHTTP2_SPS_VAL1; + return GRPC_CHTTP2_PARSE_OK; + } + parser->value |= ((uint32_t)*cur) << 16; + cur++; + /* fallthrough */ + case GRPC_CHTTP2_SPS_VAL2: + if (cur == end) { + parser->state = GRPC_CHTTP2_SPS_VAL2; + return GRPC_CHTTP2_PARSE_OK; + } + parser->value |= ((uint32_t)*cur) << 8; + cur++; + /* fallthrough */ + case GRPC_CHTTP2_SPS_VAL3: + if (cur == end) { + parser->state = GRPC_CHTTP2_SPS_VAL3; + return GRPC_CHTTP2_PARSE_OK; + } else { + parser->state = GRPC_CHTTP2_SPS_ID0; + } + parser->value |= *cur; + cur++; + + if (parser->id > 0 && parser->id < GRPC_CHTTP2_NUM_SETTINGS) { + const grpc_chttp2_setting_parameters *sp = + &grpc_chttp2_settings_parameters[parser->id]; + if (parser->value < sp->min_value || parser->value > sp->max_value) { + switch (sp->invalid_value_behavior) { + case GRPC_CHTTP2_CLAMP_INVALID_VALUE: + parser->value = + GPR_CLAMP(parser->value, sp->min_value, sp->max_value); + break; + case GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE: + grpc_chttp2_goaway_append( + transport_parsing->last_incoming_stream_id, sp->error_value, + gpr_slice_from_static_string("HTTP2 settings error"), + &transport_parsing->qbuf); + gpr_log(GPR_ERROR, "invalid value %u passed for %s", + parser->value, sp->name); + return GRPC_CHTTP2_CONNECTION_ERROR; + } + } + if (parser->id == GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE && + parser->incoming_settings[parser->id] != parser->value) { + transport_parsing->initial_window_update = + (int64_t)parser->value - parser->incoming_settings[parser->id]; + if (grpc_http_trace) { + gpr_log(GPR_DEBUG, "adding %d for initial_window change", + (int)transport_parsing->initial_window_update); + } + } + parser->incoming_settings[parser->id] = parser->value; + if (grpc_http_trace) { + gpr_log(GPR_DEBUG, "CHTTP2:%s: got setting %d = %d", + transport_parsing->is_client ? "CLI" : "SVR", parser->id, + parser->value); + } + } else { + gpr_log(GPR_ERROR, "CHTTP2: Ignoring unknown setting %d (value %d)", + parser->id, parser->value); + } + break; + } + } +} diff --git a/src/core/lib/transport/chttp2/frame_settings.h b/src/core/lib/transport/chttp2/frame_settings.h new file mode 100644 index 0000000000..59dbff9b40 --- /dev/null +++ b/src/core/lib/transport/chttp2/frame_settings.h @@ -0,0 +1,103 @@ +/* + * + * Copyright 2015-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_TRANSPORT_CHTTP2_FRAME_SETTINGS_H +#define GRPC_CORE_TRANSPORT_CHTTP2_FRAME_SETTINGS_H + +#include +#include +#include "src/core/iomgr/exec_ctx.h" +#include "src/core/transport/chttp2/frame.h" + +typedef enum { + GRPC_CHTTP2_SPS_ID0, + GRPC_CHTTP2_SPS_ID1, + GRPC_CHTTP2_SPS_VAL0, + GRPC_CHTTP2_SPS_VAL1, + GRPC_CHTTP2_SPS_VAL2, + GRPC_CHTTP2_SPS_VAL3 +} grpc_chttp2_settings_parse_state; + +/* The things HTTP/2 defines as connection level settings */ +typedef enum { + GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE = 1, + GRPC_CHTTP2_SETTINGS_ENABLE_PUSH = 2, + GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS = 3, + GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE = 4, + GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE = 5, + GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE = 6, + GRPC_CHTTP2_NUM_SETTINGS +} grpc_chttp2_setting_id; + +typedef struct { + grpc_chttp2_settings_parse_state state; + uint32_t *target_settings; + uint8_t is_ack; + uint16_t id; + uint32_t value; + uint32_t incoming_settings[GRPC_CHTTP2_NUM_SETTINGS]; +} grpc_chttp2_settings_parser; + +typedef enum { + GRPC_CHTTP2_CLAMP_INVALID_VALUE, + GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE +} grpc_chttp2_invalid_value_behavior; + +typedef struct { + const char *name; + uint32_t default_value; + uint32_t min_value; + uint32_t max_value; + grpc_chttp2_invalid_value_behavior invalid_value_behavior; + uint32_t error_value; +} grpc_chttp2_setting_parameters; + +/* HTTP/2 mandated connection setting parameters */ +extern const grpc_chttp2_setting_parameters + grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS]; + +/* Create a settings frame by diffing old & new, and updating old to be new */ +gpr_slice grpc_chttp2_settings_create(uint32_t *old, const uint32_t *new, + uint32_t force_mask, size_t count); +/* Create an ack settings frame */ +gpr_slice grpc_chttp2_settings_ack_create(void); + +grpc_chttp2_parse_error grpc_chttp2_settings_parser_begin_frame( + grpc_chttp2_settings_parser *parser, uint32_t length, uint8_t flags, + uint32_t *settings); +grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse( + grpc_exec_ctx *exec_ctx, void *parser, + grpc_chttp2_transport_parsing *transport_parsing, + grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); + +#endif /* GRPC_CORE_TRANSPORT_CHTTP2_FRAME_SETTINGS_H */ diff --git a/src/core/lib/transport/chttp2/frame_window_update.c b/src/core/lib/transport/chttp2/frame_window_update.c new file mode 100644 index 0000000000..62d9bac117 --- /dev/null +++ b/src/core/lib/transport/chttp2/frame_window_update.c @@ -0,0 +1,113 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/transport/chttp2/frame_window_update.h" +#include "src/core/transport/chttp2/internal.h" + +#include + +gpr_slice grpc_chttp2_window_update_create(uint32_t id, + uint32_t window_update) { + gpr_slice slice = gpr_slice_malloc(13); + uint8_t *p = GPR_SLICE_START_PTR(slice); + + GPR_ASSERT(window_update); + + *p++ = 0; + *p++ = 0; + *p++ = 4; + *p++ = GRPC_CHTTP2_FRAME_WINDOW_UPDATE; + *p++ = 0; + *p++ = (uint8_t)(id >> 24); + *p++ = (uint8_t)(id >> 16); + *p++ = (uint8_t)(id >> 8); + *p++ = (uint8_t)(id); + *p++ = (uint8_t)(window_update >> 24); + *p++ = (uint8_t)(window_update >> 16); + *p++ = (uint8_t)(window_update >> 8); + *p++ = (uint8_t)(window_update); + + return slice; +} + +grpc_chttp2_parse_error grpc_chttp2_window_update_parser_begin_frame( + grpc_chttp2_window_update_parser *parser, uint32_t length, uint8_t flags) { + if (flags || length != 4) { + gpr_log(GPR_ERROR, "invalid window update: length=%d, flags=%02x", length, + flags); + return GRPC_CHTTP2_CONNECTION_ERROR; + } + parser->byte = 0; + parser->amount = 0; + return GRPC_CHTTP2_PARSE_OK; +} + +grpc_chttp2_parse_error grpc_chttp2_window_update_parser_parse( + grpc_exec_ctx *exec_ctx, void *parser, + grpc_chttp2_transport_parsing *transport_parsing, + grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { + uint8_t *const beg = GPR_SLICE_START_PTR(slice); + uint8_t *const end = GPR_SLICE_END_PTR(slice); + uint8_t *cur = beg; + grpc_chttp2_window_update_parser *p = parser; + + while (p->byte != 4 && cur != end) { + p->amount |= ((uint32_t)*cur) << (8 * (3 - p->byte)); + cur++; + p->byte++; + } + + if (p->byte == 4) { + uint32_t received_update = p->amount; + if (received_update == 0 || (received_update & 0x80000000u)) { + gpr_log(GPR_ERROR, "invalid window update bytes: %d", p->amount); + return GRPC_CHTTP2_CONNECTION_ERROR; + } + GPR_ASSERT(is_last); + + if (transport_parsing->incoming_stream_id != 0) { + if (stream_parsing != NULL) { + GRPC_CHTTP2_FLOW_CREDIT_STREAM("parse", transport_parsing, + stream_parsing, outgoing_window, + received_update); + grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, + stream_parsing); + } + } else { + GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parse", transport_parsing, + outgoing_window, received_update); + } + } + + return GRPC_CHTTP2_PARSE_OK; +} diff --git a/src/core/lib/transport/chttp2/frame_window_update.h b/src/core/lib/transport/chttp2/frame_window_update.h new file mode 100644 index 0000000000..9b7ca3ce63 --- /dev/null +++ b/src/core/lib/transport/chttp2/frame_window_update.h @@ -0,0 +1,56 @@ +/* + * + * Copyright 2015-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_TRANSPORT_CHTTP2_FRAME_WINDOW_UPDATE_H +#define GRPC_CORE_TRANSPORT_CHTTP2_FRAME_WINDOW_UPDATE_H + +#include +#include "src/core/iomgr/exec_ctx.h" +#include "src/core/transport/chttp2/frame.h" + +typedef struct { + uint8_t byte; + uint8_t is_connection_update; + uint32_t amount; +} grpc_chttp2_window_update_parser; + +gpr_slice grpc_chttp2_window_update_create(uint32_t id, uint32_t window_delta); + +grpc_chttp2_parse_error grpc_chttp2_window_update_parser_begin_frame( + grpc_chttp2_window_update_parser *parser, uint32_t length, uint8_t flags); +grpc_chttp2_parse_error grpc_chttp2_window_update_parser_parse( + grpc_exec_ctx *exec_ctx, void *parser, + grpc_chttp2_transport_parsing *transport_parsing, + grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); + +#endif /* GRPC_CORE_TRANSPORT_CHTTP2_FRAME_WINDOW_UPDATE_H */ diff --git a/src/core/lib/transport/chttp2/hpack_encoder.c b/src/core/lib/transport/chttp2/hpack_encoder.c new file mode 100644 index 0000000000..f30f574d06 --- /dev/null +++ b/src/core/lib/transport/chttp2/hpack_encoder.c @@ -0,0 +1,568 @@ +/* + * + * Copyright 2015-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/transport/chttp2/hpack_encoder.h" + +#include +#include + +/* This is here for grpc_is_binary_header + * TODO(murgatroid99): Remove this + */ +#include + +#include +#include +#include + +#include "src/core/transport/chttp2/bin_encoder.h" +#include "src/core/transport/chttp2/hpack_table.h" +#include "src/core/transport/chttp2/timeout_encoding.h" +#include "src/core/transport/chttp2/varint.h" +#include "src/core/transport/static_metadata.h" + +#define HASH_FRAGMENT_1(x) ((x)&255) +#define HASH_FRAGMENT_2(x) ((x >> 8) & 255) +#define HASH_FRAGMENT_3(x) ((x >> 16) & 255) +#define HASH_FRAGMENT_4(x) ((x >> 24) & 255) + +/* if the probability of this item being seen again is < 1/x then don't add + it to the table */ +#define ONE_ON_ADD_PROBABILITY 128 +/* don't consider adding anything bigger than this to the hpack table */ +#define MAX_DECODER_SPACE_USAGE 512 + +typedef struct { + int is_first_frame; + /* number of bytes in 'output' when we started the frame - used to calculate + frame length */ + size_t output_length_at_start_of_frame; + /* index (in output) of the header for the current frame */ + size_t header_idx; + /* have we seen a regular (non-colon-prefixed) header yet? */ + uint8_t seen_regular_header; + /* output stream id */ + uint32_t stream_id; + gpr_slice_buffer *output; +} framer_state; + +/* fills p (which is expected to be 9 bytes long) with a data frame header */ +static void fill_header(uint8_t *p, uint8_t type, uint32_t id, size_t len, + uint8_t flags) { + GPR_ASSERT(len < 16777316); + *p++ = (uint8_t)(len >> 16); + *p++ = (uint8_t)(len >> 8); + *p++ = (uint8_t)(len); + *p++ = type; + *p++ = flags; + *p++ = (uint8_t)(id >> 24); + *p++ = (uint8_t)(id >> 16); + *p++ = (uint8_t)(id >> 8); + *p++ = (uint8_t)(id); +} + +/* finish a frame - fill in the previously reserved header */ +static void finish_frame(framer_state *st, int is_header_boundary, + int is_last_in_stream) { + uint8_t type = 0xff; + type = st->is_first_frame ? GRPC_CHTTP2_FRAME_HEADER + : GRPC_CHTTP2_FRAME_CONTINUATION; + fill_header( + GPR_SLICE_START_PTR(st->output->slices[st->header_idx]), type, + st->stream_id, st->output->length - st->output_length_at_start_of_frame, + (uint8_t)((is_last_in_stream ? GRPC_CHTTP2_DATA_FLAG_END_STREAM : 0) | + (is_header_boundary ? GRPC_CHTTP2_DATA_FLAG_END_HEADERS : 0))); + st->is_first_frame = 0; +} + +/* begin a new frame: reserve off header space, remember how many bytes we'd + output before beginning */ +static void begin_frame(framer_state *st) { + st->header_idx = + gpr_slice_buffer_add_indexed(st->output, gpr_slice_malloc(9)); + st->output_length_at_start_of_frame = st->output->length; +} + +/* make sure that the current frame is of the type desired, and has sufficient + space to add at least about_to_add bytes -- finishes the current frame if + needed */ +static void ensure_space(framer_state *st, size_t need_bytes) { + if (st->output->length - st->output_length_at_start_of_frame + need_bytes <= + GRPC_CHTTP2_MAX_PAYLOAD_LENGTH) { + return; + } + finish_frame(st, 0, 0); + begin_frame(st); +} + +/* increment a filter count, halve all counts if one element reaches max */ +static void inc_filter(uint8_t idx, uint32_t *sum, uint8_t *elems) { + elems[idx]++; + if (elems[idx] < 255) { + (*sum)++; + } else { + int i; + *sum = 0; + for (i = 0; i < GRPC_CHTTP2_HPACKC_NUM_FILTERS; i++) { + elems[i] /= 2; + (*sum) += elems[i]; + } + } +} + +static void add_header_data(framer_state *st, gpr_slice slice) { + size_t len = GPR_SLICE_LENGTH(slice); + size_t remaining; + if (len == 0) return; + remaining = GRPC_CHTTP2_MAX_PAYLOAD_LENGTH + + st->output_length_at_start_of_frame - st->output->length; + if (len <= remaining) { + gpr_slice_buffer_add(st->output, slice); + } else { + gpr_slice_buffer_add(st->output, gpr_slice_split_head(&slice, remaining)); + finish_frame(st, 0, 0); + begin_frame(st); + add_header_data(st, slice); + } +} + +static uint8_t *add_tiny_header_data(framer_state *st, size_t len) { + ensure_space(st, len); + return gpr_slice_buffer_tiny_add(st->output, len); +} + +static void evict_entry(grpc_chttp2_hpack_compressor *c) { + c->tail_remote_index++; + GPR_ASSERT(c->tail_remote_index > 0); + GPR_ASSERT(c->table_size >= + c->table_elem_size[c->tail_remote_index % c->cap_table_elems]); + GPR_ASSERT(c->table_elems > 0); + c->table_size = + (uint16_t)(c->table_size - + c->table_elem_size[c->tail_remote_index % c->cap_table_elems]); + c->table_elems--; +} + +/* add an element to the decoder table */ +static void add_elem(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem) { + uint32_t key_hash = elem->key->hash; + uint32_t elem_hash = GRPC_MDSTR_KV_HASH(key_hash, elem->value->hash); + uint32_t new_index = c->tail_remote_index + c->table_elems + 1; + size_t elem_size = 32 + GPR_SLICE_LENGTH(elem->key->slice) + + GPR_SLICE_LENGTH(elem->value->slice); + + GPR_ASSERT(elem_size < 65536); + + if (elem_size > c->max_table_size) { + while (c->table_size > 0) { + evict_entry(c); + } + return; + } + + /* Reserve space for this element in the remote table: if this overflows + the current table, drop elements until it fits, matching the decompressor + algorithm */ + while (c->table_size + elem_size > c->max_table_size) { + evict_entry(c); + } + GPR_ASSERT(c->table_elems < c->max_table_size); + c->table_elem_size[new_index % c->cap_table_elems] = (uint16_t)elem_size; + c->table_size = (uint16_t)(c->table_size + elem_size); + c->table_elems++; + + /* Store this element into {entries,indices}_elem */ + if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == elem) { + /* already there: update with new index */ + c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index; + } else if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == elem) { + /* already there (cuckoo): update with new index */ + c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index; + } else if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == NULL) { + /* not there, but a free element: add */ + c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = GRPC_MDELEM_REF(elem); + c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index; + } else if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == NULL) { + /* not there (cuckoo), but a free element: add */ + c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = GRPC_MDELEM_REF(elem); + c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index; + } else if (c->indices_elems[HASH_FRAGMENT_2(elem_hash)] < + c->indices_elems[HASH_FRAGMENT_3(elem_hash)]) { + /* not there: replace oldest */ + GRPC_MDELEM_UNREF(c->entries_elems[HASH_FRAGMENT_2(elem_hash)]); + c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = GRPC_MDELEM_REF(elem); + c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index; + } else { + /* not there: replace oldest */ + GRPC_MDELEM_UNREF(c->entries_elems[HASH_FRAGMENT_3(elem_hash)]); + c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = GRPC_MDELEM_REF(elem); + c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index; + } + + /* do exactly the same for the key (so we can find by that again too) */ + + if (c->entries_keys[HASH_FRAGMENT_2(key_hash)] == elem->key) { + c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index; + } else if (c->entries_keys[HASH_FRAGMENT_3(key_hash)] == elem->key) { + c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index; + } else if (c->entries_keys[HASH_FRAGMENT_2(key_hash)] == NULL) { + c->entries_keys[HASH_FRAGMENT_2(key_hash)] = GRPC_MDSTR_REF(elem->key); + c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index; + } else if (c->entries_keys[HASH_FRAGMENT_3(key_hash)] == NULL) { + c->entries_keys[HASH_FRAGMENT_3(key_hash)] = GRPC_MDSTR_REF(elem->key); + c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index; + } else if (c->indices_keys[HASH_FRAGMENT_2(key_hash)] < + c->indices_keys[HASH_FRAGMENT_3(key_hash)]) { + GRPC_MDSTR_UNREF(c->entries_keys[HASH_FRAGMENT_2(key_hash)]); + c->entries_keys[HASH_FRAGMENT_2(key_hash)] = GRPC_MDSTR_REF(elem->key); + c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index; + } else { + GRPC_MDSTR_UNREF(c->entries_keys[HASH_FRAGMENT_3(key_hash)]); + c->entries_keys[HASH_FRAGMENT_3(key_hash)] = GRPC_MDSTR_REF(elem->key); + c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index; + } +} + +static void emit_indexed(grpc_chttp2_hpack_compressor *c, uint32_t elem_index, + framer_state *st) { + uint32_t len = GRPC_CHTTP2_VARINT_LENGTH(elem_index, 1); + GRPC_CHTTP2_WRITE_VARINT(elem_index, 1, 0x80, add_tiny_header_data(st, len), + len); +} + +static gpr_slice get_wire_value(grpc_mdelem *elem, uint8_t *huffman_prefix) { + if (grpc_is_binary_header((const char *)GPR_SLICE_START_PTR(elem->key->slice), + GPR_SLICE_LENGTH(elem->key->slice))) { + *huffman_prefix = 0x80; + return grpc_mdstr_as_base64_encoded_and_huffman_compressed(elem->value); + } + /* TODO(ctiller): opportunistically compress non-binary headers */ + *huffman_prefix = 0x00; + return elem->value->slice; +} + +static void emit_lithdr_incidx(grpc_chttp2_hpack_compressor *c, + uint32_t key_index, grpc_mdelem *elem, + framer_state *st) { + uint32_t len_pfx = GRPC_CHTTP2_VARINT_LENGTH(key_index, 2); + uint8_t huffman_prefix; + gpr_slice value_slice = get_wire_value(elem, &huffman_prefix); + size_t len_val = GPR_SLICE_LENGTH(value_slice); + uint32_t len_val_len; + GPR_ASSERT(len_val <= UINT32_MAX); + len_val_len = GRPC_CHTTP2_VARINT_LENGTH((uint32_t)len_val, 1); + GRPC_CHTTP2_WRITE_VARINT(key_index, 2, 0x40, + add_tiny_header_data(st, len_pfx), len_pfx); + GRPC_CHTTP2_WRITE_VARINT((uint32_t)len_val, 1, huffman_prefix, + add_tiny_header_data(st, len_val_len), len_val_len); + add_header_data(st, gpr_slice_ref(value_slice)); +} + +static void emit_lithdr_noidx(grpc_chttp2_hpack_compressor *c, + uint32_t key_index, grpc_mdelem *elem, + framer_state *st) { + uint32_t len_pfx = GRPC_CHTTP2_VARINT_LENGTH(key_index, 4); + uint8_t huffman_prefix; + gpr_slice value_slice = get_wire_value(elem, &huffman_prefix); + size_t len_val = GPR_SLICE_LENGTH(value_slice); + uint32_t len_val_len; + GPR_ASSERT(len_val <= UINT32_MAX); + len_val_len = GRPC_CHTTP2_VARINT_LENGTH((uint32_t)len_val, 1); + GRPC_CHTTP2_WRITE_VARINT(key_index, 4, 0x00, + add_tiny_header_data(st, len_pfx), len_pfx); + GRPC_CHTTP2_WRITE_VARINT((uint32_t)len_val, 1, huffman_prefix, + add_tiny_header_data(st, len_val_len), len_val_len); + add_header_data(st, gpr_slice_ref(value_slice)); +} + +static void emit_lithdr_incidx_v(grpc_chttp2_hpack_compressor *c, + grpc_mdelem *elem, framer_state *st) { + uint32_t len_key = (uint32_t)GPR_SLICE_LENGTH(elem->key->slice); + uint8_t huffman_prefix; + gpr_slice value_slice = get_wire_value(elem, &huffman_prefix); + uint32_t len_val = (uint32_t)GPR_SLICE_LENGTH(value_slice); + uint32_t len_key_len = GRPC_CHTTP2_VARINT_LENGTH(len_key, 1); + uint32_t len_val_len = GRPC_CHTTP2_VARINT_LENGTH(len_val, 1); + GPR_ASSERT(len_key <= UINT32_MAX); + GPR_ASSERT(GPR_SLICE_LENGTH(value_slice) <= UINT32_MAX); + *add_tiny_header_data(st, 1) = 0x40; + GRPC_CHTTP2_WRITE_VARINT(len_key, 1, 0x00, + add_tiny_header_data(st, len_key_len), len_key_len); + add_header_data(st, gpr_slice_ref(elem->key->slice)); + GRPC_CHTTP2_WRITE_VARINT(len_val, 1, huffman_prefix, + add_tiny_header_data(st, len_val_len), len_val_len); + add_header_data(st, gpr_slice_ref(value_slice)); +} + +static void emit_lithdr_noidx_v(grpc_chttp2_hpack_compressor *c, + grpc_mdelem *elem, framer_state *st) { + uint32_t len_key = (uint32_t)GPR_SLICE_LENGTH(elem->key->slice); + uint8_t huffman_prefix; + gpr_slice value_slice = get_wire_value(elem, &huffman_prefix); + uint32_t len_val = (uint32_t)GPR_SLICE_LENGTH(value_slice); + uint32_t len_key_len = GRPC_CHTTP2_VARINT_LENGTH(len_key, 1); + uint32_t len_val_len = GRPC_CHTTP2_VARINT_LENGTH(len_val, 1); + GPR_ASSERT(len_key <= UINT32_MAX); + GPR_ASSERT(GPR_SLICE_LENGTH(value_slice) <= UINT32_MAX); + *add_tiny_header_data(st, 1) = 0x00; + GRPC_CHTTP2_WRITE_VARINT(len_key, 1, 0x00, + add_tiny_header_data(st, len_key_len), len_key_len); + add_header_data(st, gpr_slice_ref(elem->key->slice)); + GRPC_CHTTP2_WRITE_VARINT(len_val, 1, huffman_prefix, + add_tiny_header_data(st, len_val_len), len_val_len); + add_header_data(st, gpr_slice_ref(value_slice)); +} + +static void emit_advertise_table_size_change(grpc_chttp2_hpack_compressor *c, + framer_state *st) { + uint32_t len = GRPC_CHTTP2_VARINT_LENGTH(c->max_table_size, 3); + GRPC_CHTTP2_WRITE_VARINT(c->max_table_size, 3, 0x20, + add_tiny_header_data(st, len), len); + c->advertise_table_size_change = 0; +} + +static uint32_t dynidx(grpc_chttp2_hpack_compressor *c, uint32_t elem_index) { + return 1 + GRPC_CHTTP2_LAST_STATIC_ENTRY + c->tail_remote_index + + c->table_elems - elem_index; +} + +/* encode an mdelem */ +static void hpack_enc(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem, + framer_state *st) { + uint32_t key_hash = elem->key->hash; + uint32_t elem_hash = GRPC_MDSTR_KV_HASH(key_hash, elem->value->hash); + size_t decoder_space_usage; + uint32_t indices_key; + int should_add_elem; + + GPR_ASSERT(GPR_SLICE_LENGTH(elem->key->slice) > 0); + if (GPR_SLICE_START_PTR(elem->key->slice)[0] != ':') { /* regular header */ + st->seen_regular_header = 1; + } else { + GPR_ASSERT( + st->seen_regular_header == 0 && + "Reserved header (colon-prefixed) happening after regular ones."); + } + + inc_filter(HASH_FRAGMENT_1(elem_hash), &c->filter_elems_sum, c->filter_elems); + + /* is this elem currently in the decoders table? */ + + if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == elem && + c->indices_elems[HASH_FRAGMENT_2(elem_hash)] > c->tail_remote_index) { + /* HIT: complete element (first cuckoo hash) */ + emit_indexed(c, dynidx(c, c->indices_elems[HASH_FRAGMENT_2(elem_hash)]), + st); + return; + } + + if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == elem && + c->indices_elems[HASH_FRAGMENT_3(elem_hash)] > c->tail_remote_index) { + /* HIT: complete element (second cuckoo hash) */ + emit_indexed(c, dynidx(c, c->indices_elems[HASH_FRAGMENT_3(elem_hash)]), + st); + return; + } + + /* should this elem be in the table? */ + decoder_space_usage = 32 + GPR_SLICE_LENGTH(elem->key->slice) + + GPR_SLICE_LENGTH(elem->value->slice); + should_add_elem = decoder_space_usage < MAX_DECODER_SPACE_USAGE && + c->filter_elems[HASH_FRAGMENT_1(elem_hash)] >= + c->filter_elems_sum / ONE_ON_ADD_PROBABILITY; + + /* no hits for the elem... maybe there's a key? */ + + indices_key = c->indices_keys[HASH_FRAGMENT_2(key_hash)]; + if (c->entries_keys[HASH_FRAGMENT_2(key_hash)] == elem->key && + indices_key > c->tail_remote_index) { + /* HIT: key (first cuckoo hash) */ + if (should_add_elem) { + emit_lithdr_incidx(c, dynidx(c, indices_key), elem, st); + add_elem(c, elem); + return; + } else { + emit_lithdr_noidx(c, dynidx(c, indices_key), elem, st); + return; + } + GPR_UNREACHABLE_CODE(return ); + } + + indices_key = c->indices_keys[HASH_FRAGMENT_3(key_hash)]; + if (c->entries_keys[HASH_FRAGMENT_3(key_hash)] == elem->key && + indices_key > c->tail_remote_index) { + /* HIT: key (first cuckoo hash) */ + if (should_add_elem) { + emit_lithdr_incidx(c, dynidx(c, indices_key), elem, st); + add_elem(c, elem); + return; + } else { + emit_lithdr_noidx(c, dynidx(c, indices_key), elem, st); + return; + } + GPR_UNREACHABLE_CODE(return ); + } + + /* no elem, key in the table... fall back to literal emission */ + + if (should_add_elem) { + emit_lithdr_incidx_v(c, elem, st); + add_elem(c, elem); + return; + } else { + emit_lithdr_noidx_v(c, elem, st); + return; + } + GPR_UNREACHABLE_CODE(return ); +} + +#define STRLEN_LIT(x) (sizeof(x) - 1) +#define TIMEOUT_KEY "grpc-timeout" + +static void deadline_enc(grpc_chttp2_hpack_compressor *c, gpr_timespec deadline, + framer_state *st) { + char timeout_str[GRPC_CHTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE]; + grpc_mdelem *mdelem; + grpc_chttp2_encode_timeout( + gpr_time_sub(deadline, gpr_now(deadline.clock_type)), timeout_str); + mdelem = grpc_mdelem_from_metadata_strings( + GRPC_MDSTR_GRPC_TIMEOUT, grpc_mdstr_from_string(timeout_str)); + hpack_enc(c, mdelem, st); + GRPC_MDELEM_UNREF(mdelem); +} + +static uint32_t elems_for_bytes(uint32_t bytes) { return (bytes + 31) / 32; } + +void grpc_chttp2_hpack_compressor_init(grpc_chttp2_hpack_compressor *c) { + memset(c, 0, sizeof(*c)); + c->max_table_size = GRPC_CHTTP2_HPACKC_INITIAL_TABLE_SIZE; + c->cap_table_elems = elems_for_bytes(c->max_table_size); + c->max_table_elems = c->cap_table_elems; + c->max_usable_size = GRPC_CHTTP2_HPACKC_INITIAL_TABLE_SIZE; + c->table_elem_size = + gpr_malloc(sizeof(*c->table_elem_size) * c->cap_table_elems); + memset(c->table_elem_size, 0, + sizeof(*c->table_elem_size) * c->cap_table_elems); +} + +void grpc_chttp2_hpack_compressor_destroy(grpc_chttp2_hpack_compressor *c) { + int i; + for (i = 0; i < GRPC_CHTTP2_HPACKC_NUM_VALUES; i++) { + if (c->entries_keys[i]) GRPC_MDSTR_UNREF(c->entries_keys[i]); + if (c->entries_elems[i]) GRPC_MDELEM_UNREF(c->entries_elems[i]); + } + gpr_free(c->table_elem_size); +} + +void grpc_chttp2_hpack_compressor_set_max_usable_size( + grpc_chttp2_hpack_compressor *c, uint32_t max_table_size) { + c->max_usable_size = max_table_size; + grpc_chttp2_hpack_compressor_set_max_table_size( + c, GPR_MIN(c->max_table_size, max_table_size)); +} + +static void rebuild_elems(grpc_chttp2_hpack_compressor *c, uint32_t new_cap) { + uint16_t *table_elem_size = gpr_malloc(sizeof(*table_elem_size) * new_cap); + uint32_t i; + + memset(table_elem_size, 0, sizeof(*table_elem_size) * new_cap); + GPR_ASSERT(c->table_elems <= new_cap); + + for (i = 0; i < c->table_elems; i++) { + uint32_t ofs = c->tail_remote_index + i + 1; + table_elem_size[ofs % new_cap] = + c->table_elem_size[ofs % c->cap_table_elems]; + } + + c->cap_table_elems = new_cap; + gpr_free(c->table_elem_size); + c->table_elem_size = table_elem_size; +} + +void grpc_chttp2_hpack_compressor_set_max_table_size( + grpc_chttp2_hpack_compressor *c, uint32_t max_table_size) { + max_table_size = GPR_MIN(max_table_size, c->max_usable_size); + if (max_table_size == c->max_table_size) { + return; + } + while (c->table_size > 0 && c->table_size > max_table_size) { + evict_entry(c); + } + c->max_table_size = max_table_size; + c->max_table_elems = elems_for_bytes(max_table_size); + if (c->max_table_elems > c->cap_table_elems) { + rebuild_elems(c, GPR_MAX(c->max_table_elems, 2 * c->cap_table_elems)); + } else if (c->max_table_elems < c->cap_table_elems / 3) { + uint32_t new_cap = GPR_MAX(c->max_table_elems, 16); + if (new_cap != c->cap_table_elems) { + rebuild_elems(c, new_cap); + } + } + c->advertise_table_size_change = 1; + gpr_log(GPR_DEBUG, "set max table size from encoder to %d", max_table_size); +} + +void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor *c, + uint32_t stream_id, + grpc_metadata_batch *metadata, int is_eof, + gpr_slice_buffer *outbuf) { + framer_state st; + grpc_linked_mdelem *l; + gpr_timespec deadline; + + GPR_ASSERT(stream_id != 0); + + st.seen_regular_header = 0; + st.stream_id = stream_id; + st.output = outbuf; + st.is_first_frame = 1; + + /* Encode a metadata batch; store the returned values, representing + a metadata element that needs to be unreffed back into the metadata + slot. THIS MAY NOT BE THE SAME ELEMENT (if a decoder table slot got + updated). After this loop, we'll do a batch unref of elements. */ + begin_frame(&st); + if (c->advertise_table_size_change != 0) { + emit_advertise_table_size_change(c, &st); + } + grpc_metadata_batch_assert_ok(metadata); + for (l = metadata->list.head; l; l = l->next) { + hpack_enc(c, l->md, &st); + } + deadline = metadata->deadline; + if (gpr_time_cmp(deadline, gpr_inf_future(deadline.clock_type)) != 0) { + deadline_enc(c, deadline, &st); + } + + finish_frame(&st, 1, is_eof); +} diff --git a/src/core/lib/transport/chttp2/hpack_encoder.h b/src/core/lib/transport/chttp2/hpack_encoder.h new file mode 100644 index 0000000000..6d86eb7c83 --- /dev/null +++ b/src/core/lib/transport/chttp2/hpack_encoder.h @@ -0,0 +1,95 @@ +/* + * + * Copyright 2015-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_TRANSPORT_CHTTP2_HPACK_ENCODER_H +#define GRPC_CORE_TRANSPORT_CHTTP2_HPACK_ENCODER_H + +#include +#include +#include +#include "src/core/transport/chttp2/frame.h" +#include "src/core/transport/metadata.h" +#include "src/core/transport/metadata_batch.h" + +#define GRPC_CHTTP2_HPACKC_NUM_FILTERS 256 +#define GRPC_CHTTP2_HPACKC_NUM_VALUES 256 +/* initial table size, per spec */ +#define GRPC_CHTTP2_HPACKC_INITIAL_TABLE_SIZE 4096 +/* maximum table size we'll actually use */ +#define GRPC_CHTTP2_HPACKC_MAX_TABLE_SIZE (1024 * 1024) + +typedef struct { + uint32_t filter_elems_sum; + uint32_t max_table_size; + uint32_t max_table_elems; + uint32_t cap_table_elems; + /** if non-zero, advertise to the decoder that we'll start using a table + of this size */ + uint8_t advertise_table_size_change; + /** maximum number of bytes we'll use for the decode table (to guard against + peers ooming us by setting decode table size high) */ + uint32_t max_usable_size; + /* one before the lowest usable table index */ + uint32_t tail_remote_index; + uint32_t table_size; + uint32_t table_elems; + + /* filter tables for elems: this tables provides an approximate + popularity count for particular hashes, and are used to determine whether + a new literal should be added to the compression table or not. + They track a single integer that counts how often a particular value has + been seen. When that count reaches max (255), all values are halved. */ + uint8_t filter_elems[GRPC_CHTTP2_HPACKC_NUM_FILTERS]; + + /* entry tables for keys & elems: these tables track values that have been + seen and *may* be in the decompressor table */ + grpc_mdstr *entries_keys[GRPC_CHTTP2_HPACKC_NUM_VALUES]; + grpc_mdelem *entries_elems[GRPC_CHTTP2_HPACKC_NUM_VALUES]; + uint32_t indices_keys[GRPC_CHTTP2_HPACKC_NUM_VALUES]; + uint32_t indices_elems[GRPC_CHTTP2_HPACKC_NUM_VALUES]; + + uint16_t *table_elem_size; +} grpc_chttp2_hpack_compressor; + +void grpc_chttp2_hpack_compressor_init(grpc_chttp2_hpack_compressor *c); +void grpc_chttp2_hpack_compressor_destroy(grpc_chttp2_hpack_compressor *c); +void grpc_chttp2_hpack_compressor_set_max_table_size( + grpc_chttp2_hpack_compressor *c, uint32_t max_table_size); +void grpc_chttp2_hpack_compressor_set_max_usable_size( + grpc_chttp2_hpack_compressor *c, uint32_t max_table_size); + +void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor *c, uint32_t id, + grpc_metadata_batch *metadata, int is_eof, + gpr_slice_buffer *outbuf); + +#endif /* GRPC_CORE_TRANSPORT_CHTTP2_HPACK_ENCODER_H */ diff --git a/src/core/lib/transport/chttp2/hpack_parser.c b/src/core/lib/transport/chttp2/hpack_parser.c new file mode 100644 index 0000000000..b6e36923cb --- /dev/null +++ b/src/core/lib/transport/chttp2/hpack_parser.c @@ -0,0 +1,1449 @@ +/* + * + * Copyright 2015-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/transport/chttp2/hpack_parser.h" +#include "src/core/transport/chttp2/internal.h" + +#include +#include +#include + +/* This is here for grpc_is_binary_header + * TODO(murgatroid99): Remove this + */ +#include + +#include +#include +#include +#include + +#include "src/core/profiling/timers.h" +#include "src/core/support/string.h" +#include "src/core/transport/chttp2/bin_encoder.h" + +typedef enum { + NOT_BINARY, + B64_BYTE0, + B64_BYTE1, + B64_BYTE2, + B64_BYTE3 +} binary_state; + +/* How parsing works: + + The parser object keeps track of a function pointer which represents the + current parse state. + + Each time new bytes are presented, we call into the current state, which + recursively parses until all bytes in the given chunk are exhausted. + + The parse state that terminates then saves its function pointer to be the + current state so that it can resume when more bytes are available. + + It's expected that most optimizing compilers will turn this code into + a set of indirect jumps, and so not waste stack space. */ + +/* forward declarations for parsing states */ +static int parse_begin(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end); +static int parse_error(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end); +static int parse_illegal_op(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end); + +static int parse_string_prefix(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end); +static int parse_key_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end); +static int parse_value_string_with_indexed_key(grpc_chttp2_hpack_parser *p, + const uint8_t *cur, + const uint8_t *end); +static int parse_value_string_with_literal_key(grpc_chttp2_hpack_parser *p, + const uint8_t *cur, + const uint8_t *end); + +static int parse_value0(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end); +static int parse_value1(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end); +static int parse_value2(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end); +static int parse_value3(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end); +static int parse_value4(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end); +static int parse_value5up(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end); + +static int parse_indexed_field(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end); +static int parse_indexed_field_x(grpc_chttp2_hpack_parser *p, + const uint8_t *cur, const uint8_t *end); +static int parse_lithdr_incidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end); +static int parse_lithdr_incidx_x(grpc_chttp2_hpack_parser *p, + const uint8_t *cur, const uint8_t *end); +static int parse_lithdr_incidx_v(grpc_chttp2_hpack_parser *p, + const uint8_t *cur, const uint8_t *end); +static int parse_lithdr_notidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end); +static int parse_lithdr_notidx_x(grpc_chttp2_hpack_parser *p, + const uint8_t *cur, const uint8_t *end); +static int parse_lithdr_notidx_v(grpc_chttp2_hpack_parser *p, + const uint8_t *cur, const uint8_t *end); +static int parse_lithdr_nvridx(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end); +static int parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser *p, + const uint8_t *cur, const uint8_t *end); +static int parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p, + const uint8_t *cur, const uint8_t *end); +static int parse_max_tbl_size(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end); +static int parse_max_tbl_size_x(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end); + +/* we translate the first byte of a hpack field into one of these decoding + cases, then use a lookup table to jump directly to the appropriate parser. + + _X => the integer index is all ones, meaning we need to do varint decoding + _V => the integer index is all zeros, meaning we need to decode an additional + string value */ +typedef enum { + INDEXED_FIELD, + INDEXED_FIELD_X, + LITHDR_INCIDX, + LITHDR_INCIDX_X, + LITHDR_INCIDX_V, + LITHDR_NOTIDX, + LITHDR_NOTIDX_X, + LITHDR_NOTIDX_V, + LITHDR_NVRIDX, + LITHDR_NVRIDX_X, + LITHDR_NVRIDX_V, + MAX_TBL_SIZE, + MAX_TBL_SIZE_X, + ILLEGAL +} first_byte_type; + +/* jump table of parse state functions -- order must match first_byte_type + above */ +static const grpc_chttp2_hpack_parser_state first_byte_action[] = { + parse_indexed_field, parse_indexed_field_x, parse_lithdr_incidx, + parse_lithdr_incidx_x, parse_lithdr_incidx_v, parse_lithdr_notidx, + parse_lithdr_notidx_x, parse_lithdr_notidx_v, parse_lithdr_nvridx, + parse_lithdr_nvridx_x, parse_lithdr_nvridx_v, parse_max_tbl_size, + parse_max_tbl_size_x, parse_illegal_op}; + +/* indexes the first byte to a parse state function - generated by + gen_hpack_tables.c */ +static const uint8_t first_byte_lut[256] = { + LITHDR_NOTIDX_V, LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX, + LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX, + LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX, + LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX_X, + LITHDR_NVRIDX_V, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, + LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, + LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, + LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX_X, + MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, + MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, + MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, + MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, + MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, + MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, + MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, + MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE_X, + LITHDR_INCIDX_V, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, + LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, + LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, + LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, + LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, + LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, + LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, + LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, + LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, + LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, + LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, + LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, + LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, + LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, + LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, + LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX_X, + ILLEGAL, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, + INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, + INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, + INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, + INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, + INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, + INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, + INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, + INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, + INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, + INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, + INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, + INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, + INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, + INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, + INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, + INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, + INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, + INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, + INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, + INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, + INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, + INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, + INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, + INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, + INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, + INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, + INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, + INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, + INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, + INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, + INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD_X, +}; + +/* state table for huffman decoding: given a state, gives an index/16 into + next_sub_tbl. Taking that index and adding the value of the nibble being + considered returns the next state. + + generated by gen_hpack_tables.c */ +static const uint8_t next_tbl[256] = { + 0, 1, 2, 3, 4, 1, 2, 5, 6, 1, 7, 8, 1, 3, 3, 9, 10, 11, 1, 1, + 1, 12, 1, 2, 13, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, + 14, 1, 15, 16, 1, 17, 1, 15, 2, 7, 3, 18, 19, 1, 1, 1, 1, 20, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 15, 2, 2, 7, 21, 1, 22, 1, 1, 1, 1, 1, + 1, 1, 1, 15, 2, 2, 2, 2, 2, 2, 23, 24, 25, 1, 1, 1, 1, 2, 2, 2, + 26, 3, 3, 27, 10, 28, 1, 1, 1, 1, 1, 1, 2, 3, 29, 10, 30, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 31, 1, 1, 1, 1, 1, 1, 1, 2, + 2, 2, 2, 2, 2, 2, 2, 32, 1, 1, 15, 33, 1, 34, 35, 9, 36, 1, 1, 1, + 1, 1, 1, 1, 37, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 26, 9, + 38, 1, 1, 1, 1, 1, 1, 1, 15, 2, 2, 2, 2, 26, 3, 3, 39, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 7, 3, 3, 3, 40, 2, + 41, 1, 1, 1, 42, 43, 1, 1, 44, 1, 1, 1, 1, 15, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 45, 46, 1, 1, 2, 2, 2, 35, 3, 3, 18, 47, 2, +}; + +/* next state, based upon current state and the current nibble: see above. + generated by gen_hpack_tables.c */ +static const int16_t next_sub_tbl[48 * 16] = { + 1, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, + 218, 2, 6, 10, 13, 14, 15, 16, 17, 2, 6, 10, 13, 14, 15, + 16, 17, 3, 7, 11, 24, 3, 7, 11, 24, 3, 7, 11, 24, 3, + 7, 11, 24, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, + 4, 8, 4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, + 199, 200, 201, 202, 203, 4, 8, 4, 8, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 9, 133, 134, 135, 136, 137, 138, 139, 140, + 141, 142, 143, 144, 145, 146, 147, 3, 7, 11, 24, 3, 7, 11, 24, + 4, 8, 4, 8, 4, 8, 4, 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 12, 132, 4, 8, 4, 8, 4, 8, + 4, 8, 4, 8, 4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 18, 19, 20, 21, 4, 8, 4, + 8, 4, 8, 4, 8, 4, 8, 0, 0, 0, 22, 23, 91, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 3, + 7, 11, 24, 3, 7, 11, 24, 0, 0, 0, 0, 0, 41, 42, 43, + 2, 6, 10, 13, 14, 15, 16, 17, 3, 7, 11, 24, 3, 7, 11, + 24, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 0, 0, + 44, 45, 2, 6, 10, 13, 14, 15, 16, 17, 46, 47, 48, 49, 50, + 51, 52, 57, 4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 53, 54, 55, 56, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 73, 75, 76, 77, 78, 79, 80, 81, 82, + 83, 84, 85, 86, 87, 88, 89, 90, 3, 7, 11, 24, 3, 7, 11, + 24, 3, 7, 11, 24, 0, 0, 0, 0, 3, 7, 11, 24, 3, 7, + 11, 24, 4, 8, 4, 8, 0, 0, 0, 92, 0, 0, 0, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 3, 7, 11, 24, + 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, + 8, 4, 8, 4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 4, + 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 0, 0, + 0, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, + 131, 2, 6, 10, 13, 14, 15, 16, 17, 4, 8, 4, 8, 4, 8, + 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 148, + 149, 150, 151, 3, 7, 11, 24, 4, 8, 4, 8, 0, 0, 0, 0, + 0, 0, 152, 153, 3, 7, 11, 24, 3, 7, 11, 24, 3, 7, 11, + 24, 154, 155, 156, 164, 3, 7, 11, 24, 3, 7, 11, 24, 3, 7, + 11, 24, 4, 8, 4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 157, 158, 159, 160, 161, 162, 163, 165, 166, 167, 168, 169, 170, 171, 172, + 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, + 188, 189, 190, 191, 192, 193, 194, 195, 196, 4, 8, 4, 8, 4, 8, + 4, 8, 4, 8, 4, 8, 4, 8, 197, 198, 4, 8, 4, 8, 4, + 8, 4, 8, 0, 0, 0, 0, 0, 0, 219, 220, 3, 7, 11, 24, + 4, 8, 4, 8, 4, 8, 0, 0, 221, 222, 223, 224, 3, 7, 11, + 24, 3, 7, 11, 24, 4, 8, 4, 8, 4, 8, 225, 228, 4, 8, + 4, 8, 4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 226, 227, 229, + 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, + 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 245, 246, 247, 248, 249, 250, 251, 252, + 253, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 255, +}; + +/* emission table: indexed like next_tbl, ultimately gives the byte to be + emitted, or -1 for no byte, or 256 for end of stream + + generated by gen_hpack_tables.c */ +static const uint16_t emit_tbl[256] = { + 0, 1, 2, 3, 4, 5, 6, 7, 0, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 0, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 0, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 0, + 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, + 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, + 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, + 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 0, + 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, + 0, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, + 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, + 219, 220, 221, 0, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, + 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, + 248, +}; + +/* generated by gen_hpack_tables.c */ +static const int16_t emit_sub_tbl[249 * 16] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 48, 48, 48, 48, 48, 48, 48, 48, 49, 49, 49, 49, 49, 49, + 49, 49, 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 97, + 97, 97, 97, 48, 48, 49, 49, 50, 50, 97, 97, 99, 99, 101, 101, + 105, 105, 111, 111, 48, 49, 50, 97, 99, 101, 105, 111, 115, 116, -1, + -1, -1, -1, -1, -1, 32, 32, 32, 32, 32, 32, 32, 32, 37, 37, + 37, 37, 37, 37, 37, 37, 99, 99, 99, 99, 101, 101, 101, 101, 105, + 105, 105, 105, 111, 111, 111, 111, 115, 115, 116, 116, 32, 37, 45, 46, + 47, 51, 52, 53, 54, 55, 56, 57, 61, 61, 61, 61, 61, 61, 61, + 61, 65, 65, 65, 65, 65, 65, 65, 65, 115, 115, 115, 115, 116, 116, + 116, 116, 32, 32, 37, 37, 45, 45, 46, 46, 61, 65, 95, 98, 100, + 102, 103, 104, 108, 109, 110, 112, 114, 117, -1, -1, 58, 58, 58, 58, + 58, 58, 58, 58, 66, 66, 66, 66, 66, 66, 66, 66, 47, 47, 51, + 51, 52, 52, 53, 53, 54, 54, 55, 55, 56, 56, 57, 57, 61, 61, + 65, 65, 95, 95, 98, 98, 100, 100, 102, 102, 103, 103, 104, 104, 108, + 108, 109, 109, 110, 110, 112, 112, 114, 114, 117, 117, 58, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 89, 106, 107, 113, 118, 119, 120, 121, 122, -1, -1, + -1, -1, 38, 38, 38, 38, 38, 38, 38, 38, 42, 42, 42, 42, 42, + 42, 42, 42, 44, 44, 44, 44, 44, 44, 44, 44, 59, 59, 59, 59, + 59, 59, 59, 59, 88, 88, 88, 88, 88, 88, 88, 88, 90, 90, 90, + 90, 90, 90, 90, 90, 33, 33, 34, 34, 40, 40, 41, 41, 63, 63, + 39, 43, 124, -1, -1, -1, 35, 35, 35, 35, 35, 35, 35, 35, 62, + 62, 62, 62, 62, 62, 62, 62, 0, 0, 0, 0, 36, 36, 36, 36, + 64, 64, 64, 64, 91, 91, 91, 91, 69, 69, 69, 69, 69, 69, 69, + 69, 70, 70, 70, 70, 70, 70, 70, 70, 71, 71, 71, 71, 71, 71, + 71, 71, 72, 72, 72, 72, 72, 72, 72, 72, 73, 73, 73, 73, 73, + 73, 73, 73, 74, 74, 74, 74, 74, 74, 74, 74, 75, 75, 75, 75, + 75, 75, 75, 75, 76, 76, 76, 76, 76, 76, 76, 76, 77, 77, 77, + 77, 77, 77, 77, 77, 78, 78, 78, 78, 78, 78, 78, 78, 79, 79, + 79, 79, 79, 79, 79, 79, 80, 80, 80, 80, 80, 80, 80, 80, 81, + 81, 81, 81, 81, 81, 81, 81, 82, 82, 82, 82, 82, 82, 82, 82, + 83, 83, 83, 83, 83, 83, 83, 83, 84, 84, 84, 84, 84, 84, 84, + 84, 85, 85, 85, 85, 85, 85, 85, 85, 86, 86, 86, 86, 86, 86, + 86, 86, 87, 87, 87, 87, 87, 87, 87, 87, 89, 89, 89, 89, 89, + 89, 89, 89, 106, 106, 106, 106, 106, 106, 106, 106, 107, 107, 107, 107, + 107, 107, 107, 107, 113, 113, 113, 113, 113, 113, 113, 113, 118, 118, 118, + 118, 118, 118, 118, 118, 119, 119, 119, 119, 119, 119, 119, 119, 120, 120, + 120, 120, 120, 120, 120, 120, 121, 121, 121, 121, 121, 121, 121, 121, 122, + 122, 122, 122, 122, 122, 122, 122, 38, 38, 38, 38, 42, 42, 42, 42, + 44, 44, 44, 44, 59, 59, 59, 59, 88, 88, 88, 88, 90, 90, 90, + 90, 33, 34, 40, 41, 63, -1, -1, -1, 39, 39, 39, 39, 39, 39, + 39, 39, 43, 43, 43, 43, 43, 43, 43, 43, 124, 124, 124, 124, 124, + 124, 124, 124, 35, 35, 35, 35, 62, 62, 62, 62, 0, 0, 36, 36, + 64, 64, 91, 91, 93, 93, 126, 126, 94, 125, -1, -1, 60, 60, 60, + 60, 60, 60, 60, 60, 96, 96, 96, 96, 96, 96, 96, 96, 123, 123, + 123, 123, 123, 123, 123, 123, -1, -1, -1, -1, -1, -1, -1, -1, 92, + 92, 92, 92, 92, 92, 92, 92, 195, 195, 195, 195, 195, 195, 195, 195, + 208, 208, 208, 208, 208, 208, 208, 208, 128, 128, 128, 128, 130, 130, 130, + 130, 131, 131, 131, 131, 162, 162, 162, 162, 184, 184, 184, 184, 194, 194, + 194, 194, 224, 224, 224, 224, 226, 226, 226, 226, 153, 153, 161, 161, 167, + 167, 172, 172, 176, 176, 177, 177, 179, 179, 209, 209, 216, 216, 217, 217, + 227, 227, 229, 229, 230, 230, 129, 132, 133, 134, 136, 146, 154, 156, 160, + 163, 164, 169, 170, 173, 178, 181, 185, 186, 187, 189, 190, 196, 198, 228, + 232, 233, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 135, + 135, 135, 135, 135, 135, 135, 135, 137, 137, 137, 137, 137, 137, 137, 137, + 138, 138, 138, 138, 138, 138, 138, 138, 139, 139, 139, 139, 139, 139, 139, + 139, 140, 140, 140, 140, 140, 140, 140, 140, 141, 141, 141, 141, 141, 141, + 141, 141, 143, 143, 143, 143, 143, 143, 143, 143, 147, 147, 147, 147, 147, + 147, 147, 147, 149, 149, 149, 149, 149, 149, 149, 149, 150, 150, 150, 150, + 150, 150, 150, 150, 151, 151, 151, 151, 151, 151, 151, 151, 152, 152, 152, + 152, 152, 152, 152, 152, 155, 155, 155, 155, 155, 155, 155, 155, 157, 157, + 157, 157, 157, 157, 157, 157, 158, 158, 158, 158, 158, 158, 158, 158, 165, + 165, 165, 165, 165, 165, 165, 165, 166, 166, 166, 166, 166, 166, 166, 166, + 168, 168, 168, 168, 168, 168, 168, 168, 174, 174, 174, 174, 174, 174, 174, + 174, 175, 175, 175, 175, 175, 175, 175, 175, 180, 180, 180, 180, 180, 180, + 180, 180, 182, 182, 182, 182, 182, 182, 182, 182, 183, 183, 183, 183, 183, + 183, 183, 183, 188, 188, 188, 188, 188, 188, 188, 188, 191, 191, 191, 191, + 191, 191, 191, 191, 197, 197, 197, 197, 197, 197, 197, 197, 231, 231, 231, + 231, 231, 231, 231, 231, 239, 239, 239, 239, 239, 239, 239, 239, 9, 9, + 9, 9, 142, 142, 142, 142, 144, 144, 144, 144, 145, 145, 145, 145, 148, + 148, 148, 148, 159, 159, 159, 159, 171, 171, 171, 171, 206, 206, 206, 206, + 215, 215, 215, 215, 225, 225, 225, 225, 236, 236, 236, 236, 237, 237, 237, + 237, 199, 199, 207, 207, 234, 234, 235, 235, 192, 193, 200, 201, 202, 205, + 210, 213, 218, 219, 238, 240, 242, 243, 255, -1, 203, 203, 203, 203, 203, + 203, 203, 203, 204, 204, 204, 204, 204, 204, 204, 204, 211, 211, 211, 211, + 211, 211, 211, 211, 212, 212, 212, 212, 212, 212, 212, 212, 214, 214, 214, + 214, 214, 214, 214, 214, 221, 221, 221, 221, 221, 221, 221, 221, 222, 222, + 222, 222, 222, 222, 222, 222, 223, 223, 223, 223, 223, 223, 223, 223, 241, + 241, 241, 241, 241, 241, 241, 241, 244, 244, 244, 244, 244, 244, 244, 244, + 245, 245, 245, 245, 245, 245, 245, 245, 246, 246, 246, 246, 246, 246, 246, + 246, 247, 247, 247, 247, 247, 247, 247, 247, 248, 248, 248, 248, 248, 248, + 248, 248, 250, 250, 250, 250, 250, 250, 250, 250, 251, 251, 251, 251, 251, + 251, 251, 251, 252, 252, 252, 252, 252, 252, 252, 252, 253, 253, 253, 253, + 253, 253, 253, 253, 254, 254, 254, 254, 254, 254, 254, 254, 2, 2, 2, + 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, + 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 11, 11, 11, 11, 12, + 12, 12, 12, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, + 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, + 20, 21, 21, 21, 21, 23, 23, 23, 23, 24, 24, 24, 24, 25, 25, + 25, 25, 26, 26, 26, 26, 27, 27, 27, 27, 28, 28, 28, 28, 29, + 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31, 127, 127, 127, 127, + 220, 220, 220, 220, 249, 249, 249, 249, 10, 13, 22, 256, 93, 93, 93, + 93, 126, 126, 126, 126, 94, 94, 125, 125, 60, 96, 123, -1, 92, 195, + 208, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 128, + 128, 128, 128, 128, 128, 128, 128, 130, 130, 130, 130, 130, 130, 130, 130, + 131, 131, 131, 131, 131, 131, 131, 131, 162, 162, 162, 162, 162, 162, 162, + 162, 184, 184, 184, 184, 184, 184, 184, 184, 194, 194, 194, 194, 194, 194, + 194, 194, 224, 224, 224, 224, 224, 224, 224, 224, 226, 226, 226, 226, 226, + 226, 226, 226, 153, 153, 153, 153, 161, 161, 161, 161, 167, 167, 167, 167, + 172, 172, 172, 172, 176, 176, 176, 176, 177, 177, 177, 177, 179, 179, 179, + 179, 209, 209, 209, 209, 216, 216, 216, 216, 217, 217, 217, 217, 227, 227, + 227, 227, 229, 229, 229, 229, 230, 230, 230, 230, 129, 129, 132, 132, 133, + 133, 134, 134, 136, 136, 146, 146, 154, 154, 156, 156, 160, 160, 163, 163, + 164, 164, 169, 169, 170, 170, 173, 173, 178, 178, 181, 181, 185, 185, 186, + 186, 187, 187, 189, 189, 190, 190, 196, 196, 198, 198, 228, 228, 232, 232, + 233, 233, 1, 135, 137, 138, 139, 140, 141, 143, 147, 149, 150, 151, 152, + 155, 157, 158, 165, 166, 168, 174, 175, 180, 182, 183, 188, 191, 197, 231, + 239, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 9, 9, 9, + 9, 9, 9, 9, 9, 142, 142, 142, 142, 142, 142, 142, 142, 144, 144, + 144, 144, 144, 144, 144, 144, 145, 145, 145, 145, 145, 145, 145, 145, 148, + 148, 148, 148, 148, 148, 148, 148, 159, 159, 159, 159, 159, 159, 159, 159, + 171, 171, 171, 171, 171, 171, 171, 171, 206, 206, 206, 206, 206, 206, 206, + 206, 215, 215, 215, 215, 215, 215, 215, 215, 225, 225, 225, 225, 225, 225, + 225, 225, 236, 236, 236, 236, 236, 236, 236, 236, 237, 237, 237, 237, 237, + 237, 237, 237, 199, 199, 199, 199, 207, 207, 207, 207, 234, 234, 234, 234, + 235, 235, 235, 235, 192, 192, 193, 193, 200, 200, 201, 201, 202, 202, 205, + 205, 210, 210, 213, 213, 218, 218, 219, 219, 238, 238, 240, 240, 242, 242, + 243, 243, 255, 255, 203, 204, 211, 212, 214, 221, 222, 223, 241, 244, 245, + 246, 247, 248, 250, 251, 252, 253, 254, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 2, 2, 2, 2, 2, 2, 2, + 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, + 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, + 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, + 12, 12, 12, 12, 12, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, + 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 17, + 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, + 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, + 20, 21, 21, 21, 21, 21, 21, 21, 21, 23, 23, 23, 23, 23, 23, + 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, + 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, + 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, + 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, + 31, 31, 31, 31, 31, 31, 127, 127, 127, 127, 127, 127, 127, 127, 220, + 220, 220, 220, 220, 220, 220, 220, 249, 249, 249, 249, 249, 249, 249, 249, + 10, 10, 13, 13, 22, 22, 256, 256, 67, 67, 67, 67, 67, 67, 67, + 67, 68, 68, 68, 68, 68, 68, 68, 68, 95, 95, 95, 95, 95, 95, + 95, 95, 98, 98, 98, 98, 98, 98, 98, 98, 100, 100, 100, 100, 100, + 100, 100, 100, 102, 102, 102, 102, 102, 102, 102, 102, 103, 103, 103, 103, + 103, 103, 103, 103, 104, 104, 104, 104, 104, 104, 104, 104, 108, 108, 108, + 108, 108, 108, 108, 108, 109, 109, 109, 109, 109, 109, 109, 109, 110, 110, + 110, 110, 110, 110, 110, 110, 112, 112, 112, 112, 112, 112, 112, 112, 114, + 114, 114, 114, 114, 114, 114, 114, 117, 117, 117, 117, 117, 117, 117, 117, + 58, 58, 58, 58, 66, 66, 66, 66, 67, 67, 67, 67, 68, 68, 68, + 68, 69, 69, 69, 69, 70, 70, 70, 70, 71, 71, 71, 71, 72, 72, + 72, 72, 73, 73, 73, 73, 74, 74, 74, 74, 75, 75, 75, 75, 76, + 76, 76, 76, 77, 77, 77, 77, 78, 78, 78, 78, 79, 79, 79, 79, + 80, 80, 80, 80, 81, 81, 81, 81, 82, 82, 82, 82, 83, 83, 83, + 83, 84, 84, 84, 84, 85, 85, 85, 85, 86, 86, 86, 86, 87, 87, + 87, 87, 89, 89, 89, 89, 106, 106, 106, 106, 107, 107, 107, 107, 113, + 113, 113, 113, 118, 118, 118, 118, 119, 119, 119, 119, 120, 120, 120, 120, + 121, 121, 121, 121, 122, 122, 122, 122, 38, 38, 42, 42, 44, 44, 59, + 59, 88, 88, 90, 90, -1, -1, -1, -1, 33, 33, 33, 33, 33, 33, + 33, 33, 34, 34, 34, 34, 34, 34, 34, 34, 40, 40, 40, 40, 40, + 40, 40, 40, 41, 41, 41, 41, 41, 41, 41, 41, 63, 63, 63, 63, + 63, 63, 63, 63, 39, 39, 39, 39, 43, 43, 43, 43, 124, 124, 124, + 124, 35, 35, 62, 62, 0, 36, 64, 91, 93, 126, -1, -1, 94, 94, + 94, 94, 94, 94, 94, 94, 125, 125, 125, 125, 125, 125, 125, 125, 60, + 60, 60, 60, 96, 96, 96, 96, 123, 123, 123, 123, -1, -1, -1, -1, + 92, 92, 92, 92, 195, 195, 195, 195, 208, 208, 208, 208, 128, 128, 130, + 130, 131, 131, 162, 162, 184, 184, 194, 194, 224, 224, 226, 226, 153, 161, + 167, 172, 176, 177, 179, 209, 216, 217, 227, 229, 230, -1, -1, -1, -1, + -1, -1, -1, 129, 129, 129, 129, 129, 129, 129, 129, 132, 132, 132, 132, + 132, 132, 132, 132, 133, 133, 133, 133, 133, 133, 133, 133, 134, 134, 134, + 134, 134, 134, 134, 134, 136, 136, 136, 136, 136, 136, 136, 136, 146, 146, + 146, 146, 146, 146, 146, 146, 154, 154, 154, 154, 154, 154, 154, 154, 156, + 156, 156, 156, 156, 156, 156, 156, 160, 160, 160, 160, 160, 160, 160, 160, + 163, 163, 163, 163, 163, 163, 163, 163, 164, 164, 164, 164, 164, 164, 164, + 164, 169, 169, 169, 169, 169, 169, 169, 169, 170, 170, 170, 170, 170, 170, + 170, 170, 173, 173, 173, 173, 173, 173, 173, 173, 178, 178, 178, 178, 178, + 178, 178, 178, 181, 181, 181, 181, 181, 181, 181, 181, 185, 185, 185, 185, + 185, 185, 185, 185, 186, 186, 186, 186, 186, 186, 186, 186, 187, 187, 187, + 187, 187, 187, 187, 187, 189, 189, 189, 189, 189, 189, 189, 189, 190, 190, + 190, 190, 190, 190, 190, 190, 196, 196, 196, 196, 196, 196, 196, 196, 198, + 198, 198, 198, 198, 198, 198, 198, 228, 228, 228, 228, 228, 228, 228, 228, + 232, 232, 232, 232, 232, 232, 232, 232, 233, 233, 233, 233, 233, 233, 233, + 233, 1, 1, 1, 1, 135, 135, 135, 135, 137, 137, 137, 137, 138, 138, + 138, 138, 139, 139, 139, 139, 140, 140, 140, 140, 141, 141, 141, 141, 143, + 143, 143, 143, 147, 147, 147, 147, 149, 149, 149, 149, 150, 150, 150, 150, + 151, 151, 151, 151, 152, 152, 152, 152, 155, 155, 155, 155, 157, 157, 157, + 157, 158, 158, 158, 158, 165, 165, 165, 165, 166, 166, 166, 166, 168, 168, + 168, 168, 174, 174, 174, 174, 175, 175, 175, 175, 180, 180, 180, 180, 182, + 182, 182, 182, 183, 183, 183, 183, 188, 188, 188, 188, 191, 191, 191, 191, + 197, 197, 197, 197, 231, 231, 231, 231, 239, 239, 239, 239, 9, 9, 142, + 142, 144, 144, 145, 145, 148, 148, 159, 159, 171, 171, 206, 206, 215, 215, + 225, 225, 236, 236, 237, 237, 199, 207, 234, 235, 192, 192, 192, 192, 192, + 192, 192, 192, 193, 193, 193, 193, 193, 193, 193, 193, 200, 200, 200, 200, + 200, 200, 200, 200, 201, 201, 201, 201, 201, 201, 201, 201, 202, 202, 202, + 202, 202, 202, 202, 202, 205, 205, 205, 205, 205, 205, 205, 205, 210, 210, + 210, 210, 210, 210, 210, 210, 213, 213, 213, 213, 213, 213, 213, 213, 218, + 218, 218, 218, 218, 218, 218, 218, 219, 219, 219, 219, 219, 219, 219, 219, + 238, 238, 238, 238, 238, 238, 238, 238, 240, 240, 240, 240, 240, 240, 240, + 240, 242, 242, 242, 242, 242, 242, 242, 242, 243, 243, 243, 243, 243, 243, + 243, 243, 255, 255, 255, 255, 255, 255, 255, 255, 203, 203, 203, 203, 204, + 204, 204, 204, 211, 211, 211, 211, 212, 212, 212, 212, 214, 214, 214, 214, + 221, 221, 221, 221, 222, 222, 222, 222, 223, 223, 223, 223, 241, 241, 241, + 241, 244, 244, 244, 244, 245, 245, 245, 245, 246, 246, 246, 246, 247, 247, + 247, 247, 248, 248, 248, 248, 250, 250, 250, 250, 251, 251, 251, 251, 252, + 252, 252, 252, 253, 253, 253, 253, 254, 254, 254, 254, 2, 2, 3, 3, + 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 11, 11, 12, 12, 14, + 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, + 30, 31, 31, 127, 127, 220, 220, 249, 249, -1, -1, 10, 10, 10, 10, + 10, 10, 10, 10, 13, 13, 13, 13, 13, 13, 13, 13, 22, 22, 22, + 22, 22, 22, 22, 22, 256, 256, 256, 256, 256, 256, 256, 256, 45, 45, + 45, 45, 45, 45, 45, 45, 46, 46, 46, 46, 46, 46, 46, 46, 47, + 47, 47, 47, 47, 47, 47, 47, 51, 51, 51, 51, 51, 51, 51, 51, + 52, 52, 52, 52, 52, 52, 52, 52, 53, 53, 53, 53, 53, 53, 53, + 53, 54, 54, 54, 54, 54, 54, 54, 54, 55, 55, 55, 55, 55, 55, + 55, 55, 56, 56, 56, 56, 56, 56, 56, 56, 57, 57, 57, 57, 57, + 57, 57, 57, 50, 50, 50, 50, 50, 50, 50, 50, 97, 97, 97, 97, + 97, 97, 97, 97, 99, 99, 99, 99, 99, 99, 99, 99, 101, 101, 101, + 101, 101, 101, 101, 101, 105, 105, 105, 105, 105, 105, 105, 105, 111, 111, + 111, 111, 111, 111, 111, 111, 115, 115, 115, 115, 115, 115, 115, 115, 116, + 116, 116, 116, 116, 116, 116, 116, 32, 32, 32, 32, 37, 37, 37, 37, + 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47, 51, 51, 51, + 51, 52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, + 55, 55, 56, 56, 56, 56, 57, 57, 57, 57, 61, 61, 61, 61, 65, + 65, 65, 65, 95, 95, 95, 95, 98, 98, 98, 98, 100, 100, 100, 100, + 102, 102, 102, 102, 103, 103, 103, 103, 104, 104, 104, 104, 108, 108, 108, + 108, 109, 109, 109, 109, 110, 110, 110, 110, 112, 112, 112, 112, 114, 114, + 114, 114, 117, 117, 117, 117, 58, 58, 66, 66, 67, 67, 68, 68, 69, + 69, 70, 70, 71, 71, 72, 72, 73, 73, 74, 74, 75, 75, 76, 76, + 77, 77, 78, 78, 79, 79, 80, 80, 81, 81, 82, 82, 83, 83, 84, + 84, 85, 85, 86, 86, 87, 87, 89, 89, 106, 106, 107, 107, 113, 113, + 118, 118, 119, 119, 120, 120, 121, 121, 122, 122, 38, 42, 44, 59, 88, + 90, -1, -1, 33, 33, 33, 33, 34, 34, 34, 34, 40, 40, 40, 40, + 41, 41, 41, 41, 63, 63, 63, 63, 39, 39, 43, 43, 124, 124, 35, + 62, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 36, 36, + 36, 36, 36, 36, 36, 36, 64, 64, 64, 64, 64, 64, 64, 64, 91, + 91, 91, 91, 91, 91, 91, 91, 93, 93, 93, 93, 93, 93, 93, 93, + 126, 126, 126, 126, 126, 126, 126, 126, 94, 94, 94, 94, 125, 125, 125, + 125, 60, 60, 96, 96, 123, 123, -1, -1, 92, 92, 195, 195, 208, 208, + 128, 130, 131, 162, 184, 194, 224, 226, -1, -1, 153, 153, 153, 153, 153, + 153, 153, 153, 161, 161, 161, 161, 161, 161, 161, 161, 167, 167, 167, 167, + 167, 167, 167, 167, 172, 172, 172, 172, 172, 172, 172, 172, 176, 176, 176, + 176, 176, 176, 176, 176, 177, 177, 177, 177, 177, 177, 177, 177, 179, 179, + 179, 179, 179, 179, 179, 179, 209, 209, 209, 209, 209, 209, 209, 209, 216, + 216, 216, 216, 216, 216, 216, 216, 217, 217, 217, 217, 217, 217, 217, 217, + 227, 227, 227, 227, 227, 227, 227, 227, 229, 229, 229, 229, 229, 229, 229, + 229, 230, 230, 230, 230, 230, 230, 230, 230, 129, 129, 129, 129, 132, 132, + 132, 132, 133, 133, 133, 133, 134, 134, 134, 134, 136, 136, 136, 136, 146, + 146, 146, 146, 154, 154, 154, 154, 156, 156, 156, 156, 160, 160, 160, 160, + 163, 163, 163, 163, 164, 164, 164, 164, 169, 169, 169, 169, 170, 170, 170, + 170, 173, 173, 173, 173, 178, 178, 178, 178, 181, 181, 181, 181, 185, 185, + 185, 185, 186, 186, 186, 186, 187, 187, 187, 187, 189, 189, 189, 189, 190, + 190, 190, 190, 196, 196, 196, 196, 198, 198, 198, 198, 228, 228, 228, 228, + 232, 232, 232, 232, 233, 233, 233, 233, 1, 1, 135, 135, 137, 137, 138, + 138, 139, 139, 140, 140, 141, 141, 143, 143, 147, 147, 149, 149, 150, 150, + 151, 151, 152, 152, 155, 155, 157, 157, 158, 158, 165, 165, 166, 166, 168, + 168, 174, 174, 175, 175, 180, 180, 182, 182, 183, 183, 188, 188, 191, 191, + 197, 197, 231, 231, 239, 239, 9, 142, 144, 145, 148, 159, 171, 206, 215, + 225, 236, 237, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 199, 199, + 199, 199, 199, 199, 199, 199, 207, 207, 207, 207, 207, 207, 207, 207, 234, + 234, 234, 234, 234, 234, 234, 234, 235, 235, 235, 235, 235, 235, 235, 235, + 192, 192, 192, 192, 193, 193, 193, 193, 200, 200, 200, 200, 201, 201, 201, + 201, 202, 202, 202, 202, 205, 205, 205, 205, 210, 210, 210, 210, 213, 213, + 213, 213, 218, 218, 218, 218, 219, 219, 219, 219, 238, 238, 238, 238, 240, + 240, 240, 240, 242, 242, 242, 242, 243, 243, 243, 243, 255, 255, 255, 255, + 203, 203, 204, 204, 211, 211, 212, 212, 214, 214, 221, 221, 222, 222, 223, + 223, 241, 241, 244, 244, 245, 245, 246, 246, 247, 247, 248, 248, 250, 250, + 251, 251, 252, 252, 253, 253, 254, 254, 2, 3, 4, 5, 6, 7, 8, + 11, 12, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 127, 220, 249, -1, 10, 10, 10, 10, 13, 13, 13, + 13, 22, 22, 22, 22, 256, 256, 256, 256, +}; + +static const uint8_t inverse_base64[256] = { + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, + 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, + 255, 64, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 255, 255, 255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, +}; + +/* emission helpers */ +static int on_hdr(grpc_chttp2_hpack_parser *p, grpc_mdelem *md, + int add_to_table) { + if (add_to_table) { + if (!grpc_chttp2_hptbl_add(&p->table, md)) { + return 0; + } + } + p->on_header(p->on_header_user_data, md); + return 1; +} + +static grpc_mdstr *take_string(grpc_chttp2_hpack_parser *p, + grpc_chttp2_hpack_parser_string *str) { + grpc_mdstr *s = grpc_mdstr_from_buffer((uint8_t *)str->str, str->length); + str->length = 0; + return s; +} + +/* jump to the next state */ +static int parse_next(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end) { + p->state = *p->next_state++; + return p->state(p, cur, end); +} + +/* begin parsing a header: all functionality is encoded into lookup tables + above */ +static int parse_begin(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end) { + if (cur == end) { + p->state = parse_begin; + return 1; + } + + return first_byte_action[first_byte_lut[*cur]](p, cur, end); +} + +/* stream dependency and prioritization data: we just skip it */ +static int parse_stream_weight(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end) { + if (cur == end) { + p->state = parse_stream_weight; + return 1; + } + + return p->after_prioritization(p, cur + 1, end); +} + +static int parse_stream_dep3(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end) { + if (cur == end) { + p->state = parse_stream_dep3; + return 1; + } + + return parse_stream_weight(p, cur + 1, end); +} + +static int parse_stream_dep2(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end) { + if (cur == end) { + p->state = parse_stream_dep2; + return 1; + } + + return parse_stream_dep3(p, cur + 1, end); +} + +static int parse_stream_dep1(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end) { + if (cur == end) { + p->state = parse_stream_dep1; + return 1; + } + + return parse_stream_dep2(p, cur + 1, end); +} + +static int parse_stream_dep0(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end) { + if (cur == end) { + p->state = parse_stream_dep0; + return 1; + } + + return parse_stream_dep1(p, cur + 1, end); +} + +/* emit an indexed field; for now just logs it to console; jumps to + begin the next field on completion */ +static int finish_indexed_field(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end) { + grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index); + if (md == NULL) { + gpr_log(GPR_ERROR, "Invalid HPACK index received: %d", p->index); + return 0; + } + GRPC_MDELEM_REF(md); + return on_hdr(p, md, 0) && parse_begin(p, cur, end); +} + +/* parse an indexed field with index < 127 */ +static int parse_indexed_field(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end) { + p->dynamic_table_update_allowed = 0; + p->index = (*cur) & 0x7f; + return finish_indexed_field(p, cur + 1, end); +} + +/* parse an indexed field with index >= 127 */ +static int parse_indexed_field_x(grpc_chttp2_hpack_parser *p, + const uint8_t *cur, const uint8_t *end) { + static const grpc_chttp2_hpack_parser_state and_then[] = { + finish_indexed_field}; + p->dynamic_table_update_allowed = 0; + p->next_state = and_then; + p->index = 0x7f; + p->parsing.value = &p->index; + return parse_value0(p, cur + 1, end); +} + +/* finish a literal header with incremental indexing: just log, and jump to ' + begin */ +static int finish_lithdr_incidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end) { + grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index); + GPR_ASSERT(md != NULL); /* handled in string parsing */ + return on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key), + take_string(p, &p->value)), + 1) && + parse_begin(p, cur, end); +} + +/* finish a literal header with incremental indexing with no index */ +static int finish_lithdr_incidx_v(grpc_chttp2_hpack_parser *p, + const uint8_t *cur, const uint8_t *end) { + return on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key), + take_string(p, &p->value)), + 1) && + parse_begin(p, cur, end); +} + +/* parse a literal header with incremental indexing; index < 63 */ +static int parse_lithdr_incidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end) { + static const grpc_chttp2_hpack_parser_state and_then[] = { + parse_value_string_with_indexed_key, finish_lithdr_incidx}; + p->dynamic_table_update_allowed = 0; + p->next_state = and_then; + p->index = (*cur) & 0x3f; + return parse_string_prefix(p, cur + 1, end); +} + +/* parse a literal header with incremental indexing; index >= 63 */ +static int parse_lithdr_incidx_x(grpc_chttp2_hpack_parser *p, + const uint8_t *cur, const uint8_t *end) { + static const grpc_chttp2_hpack_parser_state and_then[] = { + parse_string_prefix, parse_value_string_with_indexed_key, + finish_lithdr_incidx}; + p->dynamic_table_update_allowed = 0; + p->next_state = and_then; + p->index = 0x3f; + p->parsing.value = &p->index; + return parse_value0(p, cur + 1, end); +} + +/* parse a literal header with incremental indexing; index = 0 */ +static int parse_lithdr_incidx_v(grpc_chttp2_hpack_parser *p, + const uint8_t *cur, const uint8_t *end) { + static const grpc_chttp2_hpack_parser_state and_then[] = { + parse_key_string, parse_string_prefix, + parse_value_string_with_literal_key, finish_lithdr_incidx_v}; + p->dynamic_table_update_allowed = 0; + p->next_state = and_then; + return parse_string_prefix(p, cur + 1, end); +} + +/* finish a literal header without incremental indexing */ +static int finish_lithdr_notidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end) { + grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index); + GPR_ASSERT(md != NULL); /* handled in string parsing */ + return on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key), + take_string(p, &p->value)), + 0) && + parse_begin(p, cur, end); +} + +/* finish a literal header without incremental indexing with index = 0 */ +static int finish_lithdr_notidx_v(grpc_chttp2_hpack_parser *p, + const uint8_t *cur, const uint8_t *end) { + return on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key), + take_string(p, &p->value)), + 0) && + parse_begin(p, cur, end); +} + +/* parse a literal header without incremental indexing; index < 15 */ +static int parse_lithdr_notidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end) { + static const grpc_chttp2_hpack_parser_state and_then[] = { + parse_value_string_with_indexed_key, finish_lithdr_notidx}; + p->dynamic_table_update_allowed = 0; + p->next_state = and_then; + p->index = (*cur) & 0xf; + return parse_string_prefix(p, cur + 1, end); +} + +/* parse a literal header without incremental indexing; index >= 15 */ +static int parse_lithdr_notidx_x(grpc_chttp2_hpack_parser *p, + const uint8_t *cur, const uint8_t *end) { + static const grpc_chttp2_hpack_parser_state and_then[] = { + parse_string_prefix, parse_value_string_with_indexed_key, + finish_lithdr_notidx}; + p->dynamic_table_update_allowed = 0; + p->next_state = and_then; + p->index = 0xf; + p->parsing.value = &p->index; + return parse_value0(p, cur + 1, end); +} + +/* parse a literal header without incremental indexing; index == 0 */ +static int parse_lithdr_notidx_v(grpc_chttp2_hpack_parser *p, + const uint8_t *cur, const uint8_t *end) { + static const grpc_chttp2_hpack_parser_state and_then[] = { + parse_key_string, parse_string_prefix, + parse_value_string_with_literal_key, finish_lithdr_notidx_v}; + p->dynamic_table_update_allowed = 0; + p->next_state = and_then; + return parse_string_prefix(p, cur + 1, end); +} + +/* finish a literal header that is never indexed */ +static int finish_lithdr_nvridx(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end) { + grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index); + GPR_ASSERT(md != NULL); /* handled in string parsing */ + return on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key), + take_string(p, &p->value)), + 0) && + parse_begin(p, cur, end); +} + +/* finish a literal header that is never indexed with an extra value */ +static int finish_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p, + const uint8_t *cur, const uint8_t *end) { + return on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key), + take_string(p, &p->value)), + 0) && + parse_begin(p, cur, end); +} + +/* parse a literal header that is never indexed; index < 15 */ +static int parse_lithdr_nvridx(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end) { + static const grpc_chttp2_hpack_parser_state and_then[] = { + parse_value_string_with_indexed_key, finish_lithdr_nvridx}; + p->dynamic_table_update_allowed = 0; + p->next_state = and_then; + p->index = (*cur) & 0xf; + return parse_string_prefix(p, cur + 1, end); +} + +/* parse a literal header that is never indexed; index >= 15 */ +static int parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser *p, + const uint8_t *cur, const uint8_t *end) { + static const grpc_chttp2_hpack_parser_state and_then[] = { + parse_string_prefix, parse_value_string_with_indexed_key, + finish_lithdr_nvridx}; + p->dynamic_table_update_allowed = 0; + p->next_state = and_then; + p->index = 0xf; + p->parsing.value = &p->index; + return parse_value0(p, cur + 1, end); +} + +/* parse a literal header that is never indexed; index == 0 */ +static int parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p, + const uint8_t *cur, const uint8_t *end) { + static const grpc_chttp2_hpack_parser_state and_then[] = { + parse_key_string, parse_string_prefix, + parse_value_string_with_literal_key, finish_lithdr_nvridx_v}; + p->dynamic_table_update_allowed = 0; + p->next_state = and_then; + return parse_string_prefix(p, cur + 1, end); +} + +/* finish parsing a max table size change */ +static int finish_max_tbl_size(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end) { + gpr_log(GPR_INFO, "MAX TABLE SIZE: %d", p->index); + return grpc_chttp2_hptbl_set_current_table_size(&p->table, p->index) && + parse_begin(p, cur, end); +} + +/* parse a max table size change, max size < 15 */ +static int parse_max_tbl_size(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end) { + if (p->dynamic_table_update_allowed == 0) { + return 0; + } + p->dynamic_table_update_allowed--; + p->index = (*cur) & 0x1f; + return finish_max_tbl_size(p, cur + 1, end); +} + +/* parse a max table size change, max size >= 15 */ +static int parse_max_tbl_size_x(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end) { + static const grpc_chttp2_hpack_parser_state and_then[] = { + finish_max_tbl_size}; + if (p->dynamic_table_update_allowed == 0) { + return 0; + } + p->dynamic_table_update_allowed--; + p->next_state = and_then; + p->index = 0x1f; + p->parsing.value = &p->index; + return parse_value0(p, cur + 1, end); +} + +/* a parse error: jam the parse state into parse_error, and return error */ +static int parse_error(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end) { + p->state = parse_error; + return 0; +} + +static int parse_illegal_op(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end) { + GPR_ASSERT(cur != end); + gpr_log(GPR_DEBUG, "Illegal hpack op code %d", *cur); + return parse_error(p, cur, end); +} + +/* parse the 1st byte of a varint into p->parsing.value + no overflow is possible */ +static int parse_value0(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end) { + if (cur == end) { + p->state = parse_value0; + return 1; + } + + *p->parsing.value += (*cur) & 0x7f; + + if ((*cur) & 0x80) { + return parse_value1(p, cur + 1, end); + } else { + return parse_next(p, cur + 1, end); + } +} + +/* parse the 2nd byte of a varint into p->parsing.value + no overflow is possible */ +static int parse_value1(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end) { + if (cur == end) { + p->state = parse_value1; + return 1; + } + + *p->parsing.value += (((uint32_t)*cur) & 0x7f) << 7; + + if ((*cur) & 0x80) { + return parse_value2(p, cur + 1, end); + } else { + return parse_next(p, cur + 1, end); + } +} + +/* parse the 3rd byte of a varint into p->parsing.value + no overflow is possible */ +static int parse_value2(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end) { + if (cur == end) { + p->state = parse_value2; + return 1; + } + + *p->parsing.value += (((uint32_t)*cur) & 0x7f) << 14; + + if ((*cur) & 0x80) { + return parse_value3(p, cur + 1, end); + } else { + return parse_next(p, cur + 1, end); + } +} + +/* parse the 4th byte of a varint into p->parsing.value + no overflow is possible */ +static int parse_value3(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end) { + if (cur == end) { + p->state = parse_value3; + return 1; + } + + *p->parsing.value += (((uint32_t)*cur) & 0x7f) << 21; + + if ((*cur) & 0x80) { + return parse_value4(p, cur + 1, end); + } else { + return parse_next(p, cur + 1, end); + } +} + +/* parse the 5th byte of a varint into p->parsing.value + depending on the byte, we may overflow, and care must be taken */ +static int parse_value4(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end) { + uint8_t c; + uint32_t cur_value; + uint32_t add_value; + + if (cur == end) { + p->state = parse_value4; + return 1; + } + + c = (*cur) & 0x7f; + if (c > 0xf) { + goto error; + } + + cur_value = *p->parsing.value; + add_value = ((uint32_t)c) << 28; + if (add_value > 0xffffffffu - cur_value) { + goto error; + } + + *p->parsing.value = cur_value + add_value; + + if ((*cur) & 0x80) { + return parse_value5up(p, cur + 1, end); + } else { + return parse_next(p, cur + 1, end); + } + +error: + gpr_log(GPR_ERROR, + "integer overflow in hpack integer decoding: have 0x%08x, " + "got byte 0x%02x on byte 5", + *p->parsing.value, *cur); + return parse_error(p, cur, end); +} + +/* parse any trailing bytes in a varint: it's possible to append an arbitrary + number of 0x80's and not affect the value - a zero will terminate - and + anything else will overflow */ +static int parse_value5up(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end) { + while (cur != end && *cur == 0x80) { + ++cur; + } + + if (cur == end) { + p->state = parse_value5up; + return 1; + } + + if (*cur == 0) { + return parse_next(p, cur + 1, end); + } + + gpr_log(GPR_ERROR, + "integer overflow in hpack integer decoding: have 0x%08x, " + "got byte 0x%02x sometime after byte 5", + *p->parsing.value, *cur); + return parse_error(p, cur, end); +} + +/* parse a string prefix */ +static int parse_string_prefix(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end) { + if (cur == end) { + p->state = parse_string_prefix; + return 1; + } + + p->strlen = (*cur) & 0x7f; + p->huff = (*cur) >> 7; + if (p->strlen == 0x7f) { + p->parsing.value = &p->strlen; + return parse_value0(p, cur + 1, end); + } else { + return parse_next(p, cur + 1, end); + } +} + +/* append some bytes to a string */ +static void append_bytes(grpc_chttp2_hpack_parser_string *str, + const uint8_t *data, size_t length) { + if (length + str->length > str->capacity) { + GPR_ASSERT(str->length + length <= UINT32_MAX); + str->capacity = (uint32_t)(str->length + length); + str->str = gpr_realloc(str->str, str->capacity); + } + memcpy(str->str + str->length, data, length); + GPR_ASSERT(length <= UINT32_MAX - str->length); + str->length += (uint32_t)length; +} + +static int append_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end) { + grpc_chttp2_hpack_parser_string *str = p->parsing.str; + uint32_t bits; + uint8_t decoded[3]; + switch ((binary_state)p->binary) { + case NOT_BINARY: + append_bytes(str, cur, (size_t)(end - cur)); + return 1; + b64_byte0: + case B64_BYTE0: + if (cur == end) { + p->binary = B64_BYTE0; + return 1; + } + bits = inverse_base64[*cur]; + ++cur; + if (bits == 255) + return 0; + else if (bits == 64) + goto b64_byte0; + p->base64_buffer = bits << 18; + /* fallthrough */ + b64_byte1: + case B64_BYTE1: + if (cur == end) { + p->binary = B64_BYTE1; + return 1; + } + bits = inverse_base64[*cur]; + ++cur; + if (bits == 255) + return 0; + else if (bits == 64) + goto b64_byte1; + p->base64_buffer |= bits << 12; + /* fallthrough */ + b64_byte2: + case B64_BYTE2: + if (cur == end) { + p->binary = B64_BYTE2; + return 1; + } + bits = inverse_base64[*cur]; + ++cur; + if (bits == 255) + return 0; + else if (bits == 64) + goto b64_byte2; + p->base64_buffer |= bits << 6; + /* fallthrough */ + b64_byte3: + case B64_BYTE3: + if (cur == end) { + p->binary = B64_BYTE3; + return 1; + } + bits = inverse_base64[*cur]; + ++cur; + if (bits == 255) + return 0; + else if (bits == 64) + goto b64_byte3; + p->base64_buffer |= bits; + bits = p->base64_buffer; + decoded[0] = (uint8_t)(bits >> 16); + decoded[1] = (uint8_t)(bits >> 8); + decoded[2] = (uint8_t)(bits); + append_bytes(str, decoded, 3); + goto b64_byte0; + } + GPR_UNREACHABLE_CODE(return 1); +} + +/* append a null terminator to a string */ +static int finish_str(grpc_chttp2_hpack_parser *p) { + uint8_t terminator = 0; + uint8_t decoded[2]; + uint32_t bits; + grpc_chttp2_hpack_parser_string *str = p->parsing.str; + switch ((binary_state)p->binary) { + case NOT_BINARY: + break; + case B64_BYTE0: + break; + case B64_BYTE1: + gpr_log(GPR_ERROR, "illegal base64 encoding"); + return 0; /* illegal encoding */ + case B64_BYTE2: + bits = p->base64_buffer; + if (bits & 0xffff) { + gpr_log(GPR_ERROR, "trailing bits in base64 encoding: 0x%04x", + bits & 0xffff); + return 0; + } + decoded[0] = (uint8_t)(bits >> 16); + append_bytes(str, decoded, 1); + break; + case B64_BYTE3: + bits = p->base64_buffer; + if (bits & 0xff) { + gpr_log(GPR_ERROR, "trailing bits in base64 encoding: 0x%02x", + bits & 0xff); + return 0; + } + decoded[0] = (uint8_t)(bits >> 16); + decoded[1] = (uint8_t)(bits >> 8); + append_bytes(str, decoded, 2); + break; + } + append_bytes(str, &terminator, 1); + p->parsing.str->length--; /* don't actually count the null terminator */ + return 1; +} + +/* decode a nibble from a huffman encoded stream */ +static int huff_nibble(grpc_chttp2_hpack_parser *p, uint8_t nibble) { + int16_t emit = emit_sub_tbl[16 * emit_tbl[p->huff_state] + nibble]; + int16_t next = next_sub_tbl[16 * next_tbl[p->huff_state] + nibble]; + if (emit != -1) { + if (emit >= 0 && emit < 256) { + uint8_t c = (uint8_t)emit; + if (!append_string(p, &c, (&c) + 1)) return 0; + } else { + assert(emit == 256); + } + } + p->huff_state = next; + return 1; +} + +/* decode full bytes from a huffman encoded stream */ +static int add_huff_bytes(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end) { + for (; cur != end; ++cur) { + if (!huff_nibble(p, *cur >> 4) || !huff_nibble(p, *cur & 0xf)) return 0; + } + return 1; +} + +/* decode some string bytes based on the current decoding mode + (huffman or not) */ +static int add_str_bytes(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end) { + if (p->huff) { + return add_huff_bytes(p, cur, end); + } else { + return append_string(p, cur, end); + } +} + +/* parse a string - tries to do large chunks at a time */ +static int parse_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end) { + size_t remaining = p->strlen - p->strgot; + size_t given = (size_t)(end - cur); + if (remaining <= given) { + return add_str_bytes(p, cur, cur + remaining) && finish_str(p) && + parse_next(p, cur + remaining, end); + } else { + if (!add_str_bytes(p, cur, cur + given)) return 0; + GPR_ASSERT(given <= UINT32_MAX - p->strgot); + p->strgot += (uint32_t)given; + p->state = parse_string; + return 1; + } +} + +/* begin parsing a string - performs setup, calls parse_string */ +static int begin_parse_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end, uint8_t binary, + grpc_chttp2_hpack_parser_string *str) { + p->strgot = 0; + str->length = 0; + p->parsing.str = str; + p->huff_state = 0; + p->binary = binary; + return parse_string(p, cur, end); +} + +/* parse the key string */ +static int parse_key_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end) { + return begin_parse_string(p, cur, end, NOT_BINARY, &p->key); +} + +/* check if a key represents a binary header or not */ +typedef enum { BINARY_HEADER, PLAINTEXT_HEADER, ERROR_HEADER } is_binary_header; + +static is_binary_header is_binary_literal_header(grpc_chttp2_hpack_parser *p) { + return grpc_is_binary_header(p->key.str, p->key.length) ? BINARY_HEADER + : PLAINTEXT_HEADER; +} + +static is_binary_header is_binary_indexed_header(grpc_chttp2_hpack_parser *p) { + grpc_mdelem *elem = grpc_chttp2_hptbl_lookup(&p->table, p->index); + if (!elem) { + gpr_log(GPR_ERROR, "Invalid HPACK index received: %d", p->index); + return ERROR_HEADER; + } + return grpc_is_binary_header( + (const char *)GPR_SLICE_START_PTR(elem->key->slice), + GPR_SLICE_LENGTH(elem->key->slice)) + ? BINARY_HEADER + : PLAINTEXT_HEADER; +} + +/* parse the value string */ +static int parse_value_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end, is_binary_header type) { + switch (type) { + case BINARY_HEADER: + return begin_parse_string(p, cur, end, B64_BYTE0, &p->value); + case PLAINTEXT_HEADER: + return begin_parse_string(p, cur, end, NOT_BINARY, &p->value); + case ERROR_HEADER: + return 0; + } + /* Add code to prevent return without value error */ + GPR_UNREACHABLE_CODE(return 0); +} + +static int parse_value_string_with_indexed_key(grpc_chttp2_hpack_parser *p, + const uint8_t *cur, + const uint8_t *end) { + return parse_value_string(p, cur, end, is_binary_indexed_header(p)); +} + +static int parse_value_string_with_literal_key(grpc_chttp2_hpack_parser *p, + const uint8_t *cur, + const uint8_t *end) { + return parse_value_string(p, cur, end, is_binary_literal_header(p)); +} + +/* PUBLIC INTERFACE */ + +static void on_header_not_set(void *user_data, grpc_mdelem *md) { + GPR_UNREACHABLE_CODE(return ); +} + +void grpc_chttp2_hpack_parser_init(grpc_chttp2_hpack_parser *p) { + p->on_header = on_header_not_set; + p->on_header_user_data = NULL; + p->state = parse_begin; + p->key.str = NULL; + p->key.capacity = 0; + p->key.length = 0; + p->value.str = NULL; + p->value.capacity = 0; + p->value.length = 0; + p->dynamic_table_update_allowed = 2; + grpc_chttp2_hptbl_init(&p->table); +} + +void grpc_chttp2_hpack_parser_set_has_priority(grpc_chttp2_hpack_parser *p) { + p->after_prioritization = p->state; + p->state = parse_stream_dep0; +} + +void grpc_chttp2_hpack_parser_destroy(grpc_chttp2_hpack_parser *p) { + grpc_chttp2_hptbl_destroy(&p->table); + gpr_free(p->key.str); + gpr_free(p->value.str); +} + +int grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser *p, + const uint8_t *beg, const uint8_t *end) { + /* TODO(ctiller): limit the distance of end from beg, and perform multiple + steps in the event of a large chunk of data to limit + stack space usage when no tail call optimization is + available */ + return p->state(p, beg, end); +} + +grpc_chttp2_parse_error grpc_chttp2_header_parser_parse( + grpc_exec_ctx *exec_ctx, void *hpack_parser, + grpc_chttp2_transport_parsing *transport_parsing, + grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { + grpc_chttp2_hpack_parser *parser = hpack_parser; + GPR_TIMER_BEGIN("grpc_chttp2_hpack_parser_parse", 0); + if (!grpc_chttp2_hpack_parser_parse(parser, GPR_SLICE_START_PTR(slice), + GPR_SLICE_END_PTR(slice))) { + GPR_TIMER_END("grpc_chttp2_hpack_parser_parse", 0); + return GRPC_CHTTP2_CONNECTION_ERROR; + } + if (is_last) { + if (parser->is_boundary && parser->state != parse_begin) { + gpr_log(GPR_ERROR, + "end of header frame not aligned with a hpack record boundary"); + GPR_TIMER_END("grpc_chttp2_hpack_parser_parse", 0); + return GRPC_CHTTP2_CONNECTION_ERROR; + } + /* need to check for null stream: this can occur if we receive an invalid + stream id on a header */ + if (stream_parsing != NULL) { + if (parser->is_boundary) { + stream_parsing + ->got_metadata_on_parse[stream_parsing->header_frames_received] = 1; + stream_parsing->header_frames_received++; + grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, + stream_parsing); + } + if (parser->is_eof) { + stream_parsing->received_close = 1; + } + } + parser->on_header = on_header_not_set; + parser->on_header_user_data = NULL; + parser->is_boundary = 0xde; + parser->is_eof = 0xde; + parser->dynamic_table_update_allowed = 2; + } + GPR_TIMER_END("grpc_chttp2_hpack_parser_parse", 0); + return GRPC_CHTTP2_PARSE_OK; +} diff --git a/src/core/lib/transport/chttp2/hpack_parser.h b/src/core/lib/transport/chttp2/hpack_parser.h new file mode 100644 index 0000000000..6a6d136da2 --- /dev/null +++ b/src/core/lib/transport/chttp2/hpack_parser.h @@ -0,0 +1,116 @@ +/* + * + * Copyright 2015-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_TRANSPORT_CHTTP2_HPACK_PARSER_H +#define GRPC_CORE_TRANSPORT_CHTTP2_HPACK_PARSER_H + +#include + +#include +#include "src/core/iomgr/exec_ctx.h" +#include "src/core/transport/chttp2/frame.h" +#include "src/core/transport/chttp2/hpack_table.h" +#include "src/core/transport/metadata.h" + +typedef struct grpc_chttp2_hpack_parser grpc_chttp2_hpack_parser; + +typedef int (*grpc_chttp2_hpack_parser_state)(grpc_chttp2_hpack_parser *p, + const uint8_t *beg, + const uint8_t *end); + +typedef struct { + char *str; + uint32_t length; + uint32_t capacity; +} grpc_chttp2_hpack_parser_string; + +struct grpc_chttp2_hpack_parser { + /* user specified callback for each header output */ + void (*on_header)(void *user_data, grpc_mdelem *md); + void *on_header_user_data; + + /* current parse state - or a function that implements it */ + grpc_chttp2_hpack_parser_state state; + /* future states dependent on the opening op code */ + const grpc_chttp2_hpack_parser_state *next_state; + /* what to do after skipping prioritization data */ + grpc_chttp2_hpack_parser_state after_prioritization; + /* the value we're currently parsing */ + union { + uint32_t *value; + grpc_chttp2_hpack_parser_string *str; + } parsing; + /* string parameters for each chunk */ + grpc_chttp2_hpack_parser_string key; + grpc_chttp2_hpack_parser_string value; + /* parsed index */ + uint32_t index; + /* length of source bytes for the currently parsing string */ + uint32_t strlen; + /* number of source bytes read for the currently parsing string */ + uint32_t strgot; + /* huffman decoding state */ + int16_t huff_state; + /* is the string being decoded binary? */ + uint8_t binary; + /* is the current string huffman encoded? */ + uint8_t huff; + /* is a dynamic table update allowed? */ + uint8_t dynamic_table_update_allowed; + /* set by higher layers, used by grpc_chttp2_header_parser_parse to signal + it should append a metadata boundary at the end of frame */ + uint8_t is_boundary; + uint8_t is_eof; + uint32_t base64_buffer; + + /* hpack table */ + grpc_chttp2_hptbl table; +}; + +void grpc_chttp2_hpack_parser_init(grpc_chttp2_hpack_parser *p); +void grpc_chttp2_hpack_parser_destroy(grpc_chttp2_hpack_parser *p); + +void grpc_chttp2_hpack_parser_set_has_priority(grpc_chttp2_hpack_parser *p); + +/* returns 1 on success, 0 on error */ +int grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser *p, + const uint8_t *beg, const uint8_t *end); + +/* wraps grpc_chttp2_hpack_parser_parse to provide a frame level parser for + the transport */ +grpc_chttp2_parse_error grpc_chttp2_header_parser_parse( + grpc_exec_ctx *exec_ctx, void *hpack_parser, + grpc_chttp2_transport_parsing *transport_parsing, + grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); + +#endif /* GRPC_CORE_TRANSPORT_CHTTP2_HPACK_PARSER_H */ diff --git a/src/core/lib/transport/chttp2/hpack_table.c b/src/core/lib/transport/chttp2/hpack_table.c new file mode 100644 index 0000000000..f1ce3b84fd --- /dev/null +++ b/src/core/lib/transport/chttp2/hpack_table.c @@ -0,0 +1,361 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/transport/chttp2/hpack_table.h" + +#include +#include + +#include +#include + +#include "src/core/support/murmur_hash.h" + +static struct { + const char *key; + const char *value; +} static_table[] = { + /* 0: */ + {NULL, NULL}, + /* 1: */ + {":authority", ""}, + /* 2: */ + {":method", "GET"}, + /* 3: */ + {":method", "POST"}, + /* 4: */ + {":path", "/"}, + /* 5: */ + {":path", "/index.html"}, + /* 6: */ + {":scheme", "http"}, + /* 7: */ + {":scheme", "https"}, + /* 8: */ + {":status", "200"}, + /* 9: */ + {":status", "204"}, + /* 10: */ + {":status", "206"}, + /* 11: */ + {":status", "304"}, + /* 12: */ + {":status", "400"}, + /* 13: */ + {":status", "404"}, + /* 14: */ + {":status", "500"}, + /* 15: */ + {"accept-charset", ""}, + /* 16: */ + {"accept-encoding", "gzip, deflate"}, + /* 17: */ + {"accept-language", ""}, + /* 18: */ + {"accept-ranges", ""}, + /* 19: */ + {"accept", ""}, + /* 20: */ + {"access-control-allow-origin", ""}, + /* 21: */ + {"age", ""}, + /* 22: */ + {"allow", ""}, + /* 23: */ + {"authorization", ""}, + /* 24: */ + {"cache-control", ""}, + /* 25: */ + {"content-disposition", ""}, + /* 26: */ + {"content-encoding", ""}, + /* 27: */ + {"content-language", ""}, + /* 28: */ + {"content-length", ""}, + /* 29: */ + {"content-location", ""}, + /* 30: */ + {"content-range", ""}, + /* 31: */ + {"content-type", ""}, + /* 32: */ + {"cookie", ""}, + /* 33: */ + {"date", ""}, + /* 34: */ + {"etag", ""}, + /* 35: */ + {"expect", ""}, + /* 36: */ + {"expires", ""}, + /* 37: */ + {"from", ""}, + /* 38: */ + {"host", ""}, + /* 39: */ + {"if-match", ""}, + /* 40: */ + {"if-modified-since", ""}, + /* 41: */ + {"if-none-match", ""}, + /* 42: */ + {"if-range", ""}, + /* 43: */ + {"if-unmodified-since", ""}, + /* 44: */ + {"last-modified", ""}, + /* 45: */ + {"link", ""}, + /* 46: */ + {"location", ""}, + /* 47: */ + {"max-forwards", ""}, + /* 48: */ + {"proxy-authenticate", ""}, + /* 49: */ + {"proxy-authorization", ""}, + /* 50: */ + {"range", ""}, + /* 51: */ + {"referer", ""}, + /* 52: */ + {"refresh", ""}, + /* 53: */ + {"retry-after", ""}, + /* 54: */ + {"server", ""}, + /* 55: */ + {"set-cookie", ""}, + /* 56: */ + {"strict-transport-security", ""}, + /* 57: */ + {"transfer-encoding", ""}, + /* 58: */ + {"user-agent", ""}, + /* 59: */ + {"vary", ""}, + /* 60: */ + {"via", ""}, + /* 61: */ + {"www-authenticate", ""}, +}; + +static uint32_t entries_for_bytes(uint32_t bytes) { + return (bytes + GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD - 1) / + GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD; +} + +void grpc_chttp2_hptbl_init(grpc_chttp2_hptbl *tbl) { + size_t i; + + memset(tbl, 0, sizeof(*tbl)); + tbl->current_table_bytes = tbl->max_bytes = + GRPC_CHTTP2_INITIAL_HPACK_TABLE_SIZE; + tbl->max_entries = tbl->cap_entries = + entries_for_bytes(tbl->current_table_bytes); + tbl->ents = gpr_malloc(sizeof(*tbl->ents) * tbl->cap_entries); + memset(tbl->ents, 0, sizeof(*tbl->ents) * tbl->cap_entries); + for (i = 1; i <= GRPC_CHTTP2_LAST_STATIC_ENTRY; i++) { + tbl->static_ents[i - 1] = + grpc_mdelem_from_strings(static_table[i].key, static_table[i].value); + } +} + +void grpc_chttp2_hptbl_destroy(grpc_chttp2_hptbl *tbl) { + size_t i; + for (i = 0; i < GRPC_CHTTP2_LAST_STATIC_ENTRY; i++) { + GRPC_MDELEM_UNREF(tbl->static_ents[i]); + } + for (i = 0; i < tbl->num_ents; i++) { + GRPC_MDELEM_UNREF(tbl->ents[(tbl->first_ent + i) % tbl->cap_entries]); + } + gpr_free(tbl->ents); +} + +grpc_mdelem *grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl, + uint32_t tbl_index) { + /* Static table comes first, just return an entry from it */ + if (tbl_index <= GRPC_CHTTP2_LAST_STATIC_ENTRY) { + return tbl->static_ents[tbl_index - 1]; + } + /* Otherwise, find the value in the list of valid entries */ + tbl_index -= (GRPC_CHTTP2_LAST_STATIC_ENTRY + 1); + if (tbl_index < tbl->num_ents) { + uint32_t offset = + (tbl->num_ents - 1u - tbl_index + tbl->first_ent) % tbl->cap_entries; + return tbl->ents[offset]; + } + /* Invalid entry: return error */ + return NULL; +} + +/* Evict one element from the table */ +static void evict1(grpc_chttp2_hptbl *tbl) { + grpc_mdelem *first_ent = tbl->ents[tbl->first_ent]; + size_t elem_bytes = GPR_SLICE_LENGTH(first_ent->key->slice) + + GPR_SLICE_LENGTH(first_ent->value->slice) + + GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD; + GPR_ASSERT(elem_bytes <= tbl->mem_used); + tbl->mem_used -= (uint32_t)elem_bytes; + tbl->first_ent = ((tbl->first_ent + 1) % tbl->cap_entries); + tbl->num_ents--; + GRPC_MDELEM_UNREF(first_ent); +} + +static void rebuild_ents(grpc_chttp2_hptbl *tbl, uint32_t new_cap) { + grpc_mdelem **ents = gpr_malloc(sizeof(*ents) * new_cap); + uint32_t i; + + for (i = 0; i < tbl->num_ents; i++) { + ents[i] = tbl->ents[(tbl->first_ent + i) % tbl->cap_entries]; + } + gpr_free(tbl->ents); + tbl->ents = ents; + tbl->cap_entries = new_cap; + tbl->first_ent = 0; +} + +void grpc_chttp2_hptbl_set_max_bytes(grpc_chttp2_hptbl *tbl, + uint32_t max_bytes) { + if (tbl->max_bytes == max_bytes) { + return; + } + gpr_log(GPR_DEBUG, "Update hpack parser max size to %d", max_bytes); + while (tbl->mem_used > max_bytes) { + evict1(tbl); + } + tbl->max_bytes = max_bytes; +} + +int grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl, + uint32_t bytes) { + if (tbl->current_table_bytes == bytes) { + return 1; + } + if (bytes > tbl->max_bytes) { + gpr_log(GPR_ERROR, + "Attempt to make hpack table %d bytes when max is %d bytes", bytes, + tbl->max_bytes); + return 0; + } + gpr_log(GPR_DEBUG, "Update hpack parser table size to %d", bytes); + while (tbl->mem_used > bytes) { + evict1(tbl); + } + tbl->current_table_bytes = bytes; + tbl->max_entries = entries_for_bytes(bytes); + if (tbl->max_entries > tbl->cap_entries) { + rebuild_ents(tbl, GPR_MAX(tbl->max_entries, 2 * tbl->cap_entries)); + } else if (tbl->max_entries < tbl->cap_entries / 3) { + uint32_t new_cap = GPR_MAX(tbl->max_entries, 16u); + if (new_cap != tbl->cap_entries) { + rebuild_ents(tbl, new_cap); + } + } + return 1; +} + +int grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) { + /* determine how many bytes of buffer this entry represents */ + size_t elem_bytes = GPR_SLICE_LENGTH(md->key->slice) + + GPR_SLICE_LENGTH(md->value->slice) + + GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD; + + if (tbl->current_table_bytes > tbl->max_bytes) { + gpr_log(GPR_ERROR, + "HPACK max table size reduced to %d but not reflected by hpack " + "stream (still at %d)", + tbl->max_bytes, tbl->current_table_bytes); + return 0; + } + + /* we can't add elements bigger than the max table size */ + if (elem_bytes > tbl->current_table_bytes) { + /* HPACK draft 10 section 4.4 states: + * If the size of the new entry is less than or equal to the maximum + * size, that entry is added to the table. It is not an error to + * attempt to add an entry that is larger than the maximum size; an + * attempt to add an entry larger than the entire table causes + * the table + * to be emptied of all existing entries, and results in an + * empty table. + */ + while (tbl->num_ents) { + evict1(tbl); + } + return 1; + } + + /* evict entries to ensure no overflow */ + while (elem_bytes > (size_t)tbl->current_table_bytes - tbl->mem_used) { + evict1(tbl); + } + + /* copy the finalized entry in */ + tbl->ents[(tbl->first_ent + tbl->num_ents) % tbl->cap_entries] = + GRPC_MDELEM_REF(md); + + /* update accounting values */ + tbl->num_ents++; + tbl->mem_used += (uint32_t)elem_bytes; + return 1; +} + +grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find( + const grpc_chttp2_hptbl *tbl, grpc_mdelem *md) { + grpc_chttp2_hptbl_find_result r = {0, 0}; + uint32_t i; + + /* See if the string is in the static table */ + for (i = 0; i < GRPC_CHTTP2_LAST_STATIC_ENTRY; i++) { + grpc_mdelem *ent = tbl->static_ents[i]; + if (md->key != ent->key) continue; + r.index = i + 1u; + r.has_value = md->value == ent->value; + if (r.has_value) return r; + } + + /* Scan the dynamic table */ + for (i = 0; i < tbl->num_ents; i++) { + uint32_t idx = + (uint32_t)(tbl->num_ents - i + GRPC_CHTTP2_LAST_STATIC_ENTRY); + grpc_mdelem *ent = tbl->ents[(tbl->first_ent + i) % tbl->cap_entries]; + if (md->key != ent->key) continue; + r.index = idx; + r.has_value = md->value == ent->value; + if (r.has_value) return r; + } + + return r; +} diff --git a/src/core/lib/transport/chttp2/hpack_table.h b/src/core/lib/transport/chttp2/hpack_table.h new file mode 100644 index 0000000000..c984ca35e4 --- /dev/null +++ b/src/core/lib/transport/chttp2/hpack_table.h @@ -0,0 +1,108 @@ +/* + * + * Copyright 2015-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_TRANSPORT_CHTTP2_HPACK_TABLE_H +#define GRPC_CORE_TRANSPORT_CHTTP2_HPACK_TABLE_H + +#include +#include +#include "src/core/transport/metadata.h" + +/* HPACK header table */ + +/* last index in the static table */ +#define GRPC_CHTTP2_LAST_STATIC_ENTRY 61 + +/* Initial table size as per the spec */ +#define GRPC_CHTTP2_INITIAL_HPACK_TABLE_SIZE 4096 +/* Maximum table size that we'll use */ +#define GRPC_CHTTP2_MAX_HPACK_TABLE_SIZE GRPC_CHTTP2_INITIAL_HPACK_TABLE_SIZE +/* Per entry overhead bytes as per the spec */ +#define GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD 32 +#if 0 +/* Maximum number of entries we could possibly fit in the table, given defined + overheads */ +#define GRPC_CHTTP2_MAX_TABLE_COUNT \ + ((GRPC_CHTTP2_MAX_HPACK_TABLE_SIZE + GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD - 1) / \ + GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD) +#endif + +/* hpack decoder table */ +typedef struct { + /* the first used entry in ents */ + uint32_t first_ent; + /* how many entries are in the table */ + uint32_t num_ents; + /* the amount of memory used by the table, according to the hpack algorithm */ + uint32_t mem_used; + /* the max memory allowed to be used by the table, according to the hpack + algorithm */ + uint32_t max_bytes; + /* the currently agreed size of the table, according to the hpack algorithm */ + uint32_t current_table_bytes; + /* Maximum number of entries we could possibly fit in the table, given defined + overheads */ + uint32_t max_entries; + /* Number of entries allocated in ents */ + uint32_t cap_entries; + /* a circular buffer of headers - this is stored in the opposite order to + what hpack specifies, in order to simplify table management a little... + meaning lookups need to SUBTRACT from the end position */ + grpc_mdelem **ents; + grpc_mdelem *static_ents[GRPC_CHTTP2_LAST_STATIC_ENTRY]; +} grpc_chttp2_hptbl; + +/* initialize a hpack table */ +void grpc_chttp2_hptbl_init(grpc_chttp2_hptbl *tbl); +void grpc_chttp2_hptbl_destroy(grpc_chttp2_hptbl *tbl); +void grpc_chttp2_hptbl_set_max_bytes(grpc_chttp2_hptbl *tbl, + uint32_t max_bytes); +int grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl, + uint32_t bytes); + +/* lookup a table entry based on its hpack index */ +grpc_mdelem *grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl, + uint32_t index); +/* add a table entry to the index */ +int grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, + grpc_mdelem *md) GRPC_MUST_USE_RESULT; +/* Find a key/value pair in the table... returns the index in the table of the + most similar entry, or 0 if the value was not found */ +typedef struct { + uint32_t index; + int has_value; +} grpc_chttp2_hptbl_find_result; +grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find( + const grpc_chttp2_hptbl *tbl, grpc_mdelem *md); + +#endif /* GRPC_CORE_TRANSPORT_CHTTP2_HPACK_TABLE_H */ diff --git a/src/core/lib/transport/chttp2/hpack_tables.txt b/src/core/lib/transport/chttp2/hpack_tables.txt new file mode 100644 index 0000000000..08842a0267 --- /dev/null +++ b/src/core/lib/transport/chttp2/hpack_tables.txt @@ -0,0 +1,66 @@ +Static table, from the spec: + +-------+-----------------------------+---------------+ + | Index | Header Name | Header Value | + +-------+-----------------------------+---------------+ + | 1 | :authority | | + | 2 | :method | GET | + | 3 | :method | POST | + | 4 | :path | / | + | 5 | :path | /index.html | + | 6 | :scheme | http | + | 7 | :scheme | https | + | 8 | :status | 200 | + | 9 | :status | 204 | + | 10 | :status | 206 | + | 11 | :status | 304 | + | 12 | :status | 400 | + | 13 | :status | 404 | + | 14 | :status | 500 | + | 15 | accept-charset | | + | 16 | accept-encoding | gzip, deflate | + | 17 | accept-language | | + | 18 | accept-ranges | | + | 19 | accept | | + | 20 | access-control-allow-origin | | + | 21 | age | | + | 22 | allow | | + | 23 | authorization | | + | 24 | cache-control | | + | 25 | content-disposition | | + | 26 | content-encoding | | + | 27 | content-language | | + | 28 | content-length | | + | 29 | content-location | | + | 30 | content-range | | + | 31 | content-type | | + | 32 | cookie | | + | 33 | date | | + | 34 | etag | | + | 35 | expect | | + | 36 | expires | | + | 37 | from | | + | 38 | host | | + | 39 | if-match | | + | 40 | if-modified-since | | + | 41 | if-none-match | | + | 42 | if-range | | + | 43 | if-unmodified-since | | + | 44 | last-modified | | + | 45 | link | | + | 46 | location | | + | 47 | max-forwards | | + | 48 | proxy-authenticate | | + | 49 | proxy-authorization | | + | 50 | range | | + | 51 | referer | | + | 52 | refresh | | + | 53 | retry-after | | + | 54 | server | | + | 55 | set-cookie | | + | 56 | strict-transport-security | | + | 57 | transfer-encoding | | + | 58 | user-agent | | + | 59 | vary | | + | 60 | via | | + | 61 | www-authenticate | | + +-------+-----------------------------+---------------+ diff --git a/src/core/lib/transport/chttp2/http2_errors.h b/src/core/lib/transport/chttp2/http2_errors.h new file mode 100644 index 0000000000..4290df3d89 --- /dev/null +++ b/src/core/lib/transport/chttp2/http2_errors.h @@ -0,0 +1,56 @@ +/* + * + * Copyright 2015-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_TRANSPORT_CHTTP2_HTTP2_ERRORS_H +#define GRPC_CORE_TRANSPORT_CHTTP2_HTTP2_ERRORS_H + +/* error codes for RST_STREAM from http2 draft 14 section 7 */ +typedef enum { + GRPC_CHTTP2_NO_ERROR = 0x0, + GRPC_CHTTP2_PROTOCOL_ERROR = 0x1, + GRPC_CHTTP2_INTERNAL_ERROR = 0x2, + GRPC_CHTTP2_FLOW_CONTROL_ERROR = 0x3, + GRPC_CHTTP2_SETTINGS_TIMEOUT = 0x4, + GRPC_CHTTP2_STREAM_CLOSED = 0x5, + GRPC_CHTTP2_FRAME_SIZE_ERROR = 0x6, + GRPC_CHTTP2_REFUSED_STREAM = 0x7, + GRPC_CHTTP2_CANCEL = 0x8, + GRPC_CHTTP2_COMPRESSION_ERROR = 0x9, + GRPC_CHTTP2_CONNECT_ERROR = 0xa, + GRPC_CHTTP2_ENHANCE_YOUR_CALM = 0xb, + GRPC_CHTTP2_INADEQUATE_SECURITY = 0xc, + /* force use of a default clause */ + GRPC_CHTTP2__ERROR_DO_NOT_USE = -1 +} grpc_chttp2_error_code; + +#endif /* GRPC_CORE_TRANSPORT_CHTTP2_HTTP2_ERRORS_H */ diff --git a/src/core/lib/transport/chttp2/huffsyms.c b/src/core/lib/transport/chttp2/huffsyms.c new file mode 100644 index 0000000000..ebc85d3378 --- /dev/null +++ b/src/core/lib/transport/chttp2/huffsyms.c @@ -0,0 +1,105 @@ +/* + * + * Copyright 2015-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/transport/chttp2/huffsyms.h" + +/* Constants pulled from the HPACK spec, and converted to C using the vim + command: + :%s/.* \([0-9a-f]\+\) \[ *\([0-9]\+\)\]/{0x\1, \2},/g */ +const grpc_chttp2_huffsym grpc_chttp2_huffsyms[GRPC_CHTTP2_NUM_HUFFSYMS] = { + {0x1ff8, 13}, {0x7fffd8, 23}, {0xfffffe2, 28}, {0xfffffe3, 28}, + {0xfffffe4, 28}, {0xfffffe5, 28}, {0xfffffe6, 28}, {0xfffffe7, 28}, + {0xfffffe8, 28}, {0xffffea, 24}, {0x3ffffffc, 30}, {0xfffffe9, 28}, + {0xfffffea, 28}, {0x3ffffffd, 30}, {0xfffffeb, 28}, {0xfffffec, 28}, + {0xfffffed, 28}, {0xfffffee, 28}, {0xfffffef, 28}, {0xffffff0, 28}, + {0xffffff1, 28}, {0xffffff2, 28}, {0x3ffffffe, 30}, {0xffffff3, 28}, + {0xffffff4, 28}, {0xffffff5, 28}, {0xffffff6, 28}, {0xffffff7, 28}, + {0xffffff8, 28}, {0xffffff9, 28}, {0xffffffa, 28}, {0xffffffb, 28}, + {0x14, 6}, {0x3f8, 10}, {0x3f9, 10}, {0xffa, 12}, + {0x1ff9, 13}, {0x15, 6}, {0xf8, 8}, {0x7fa, 11}, + {0x3fa, 10}, {0x3fb, 10}, {0xf9, 8}, {0x7fb, 11}, + {0xfa, 8}, {0x16, 6}, {0x17, 6}, {0x18, 6}, + {0x0, 5}, {0x1, 5}, {0x2, 5}, {0x19, 6}, + {0x1a, 6}, {0x1b, 6}, {0x1c, 6}, {0x1d, 6}, + {0x1e, 6}, {0x1f, 6}, {0x5c, 7}, {0xfb, 8}, + {0x7ffc, 15}, {0x20, 6}, {0xffb, 12}, {0x3fc, 10}, + {0x1ffa, 13}, {0x21, 6}, {0x5d, 7}, {0x5e, 7}, + {0x5f, 7}, {0x60, 7}, {0x61, 7}, {0x62, 7}, + {0x63, 7}, {0x64, 7}, {0x65, 7}, {0x66, 7}, + {0x67, 7}, {0x68, 7}, {0x69, 7}, {0x6a, 7}, + {0x6b, 7}, {0x6c, 7}, {0x6d, 7}, {0x6e, 7}, + {0x6f, 7}, {0x70, 7}, {0x71, 7}, {0x72, 7}, + {0xfc, 8}, {0x73, 7}, {0xfd, 8}, {0x1ffb, 13}, + {0x7fff0, 19}, {0x1ffc, 13}, {0x3ffc, 14}, {0x22, 6}, + {0x7ffd, 15}, {0x3, 5}, {0x23, 6}, {0x4, 5}, + {0x24, 6}, {0x5, 5}, {0x25, 6}, {0x26, 6}, + {0x27, 6}, {0x6, 5}, {0x74, 7}, {0x75, 7}, + {0x28, 6}, {0x29, 6}, {0x2a, 6}, {0x7, 5}, + {0x2b, 6}, {0x76, 7}, {0x2c, 6}, {0x8, 5}, + {0x9, 5}, {0x2d, 6}, {0x77, 7}, {0x78, 7}, + {0x79, 7}, {0x7a, 7}, {0x7b, 7}, {0x7ffe, 15}, + {0x7fc, 11}, {0x3ffd, 14}, {0x1ffd, 13}, {0xffffffc, 28}, + {0xfffe6, 20}, {0x3fffd2, 22}, {0xfffe7, 20}, {0xfffe8, 20}, + {0x3fffd3, 22}, {0x3fffd4, 22}, {0x3fffd5, 22}, {0x7fffd9, 23}, + {0x3fffd6, 22}, {0x7fffda, 23}, {0x7fffdb, 23}, {0x7fffdc, 23}, + {0x7fffdd, 23}, {0x7fffde, 23}, {0xffffeb, 24}, {0x7fffdf, 23}, + {0xffffec, 24}, {0xffffed, 24}, {0x3fffd7, 22}, {0x7fffe0, 23}, + {0xffffee, 24}, {0x7fffe1, 23}, {0x7fffe2, 23}, {0x7fffe3, 23}, + {0x7fffe4, 23}, {0x1fffdc, 21}, {0x3fffd8, 22}, {0x7fffe5, 23}, + {0x3fffd9, 22}, {0x7fffe6, 23}, {0x7fffe7, 23}, {0xffffef, 24}, + {0x3fffda, 22}, {0x1fffdd, 21}, {0xfffe9, 20}, {0x3fffdb, 22}, + {0x3fffdc, 22}, {0x7fffe8, 23}, {0x7fffe9, 23}, {0x1fffde, 21}, + {0x7fffea, 23}, {0x3fffdd, 22}, {0x3fffde, 22}, {0xfffff0, 24}, + {0x1fffdf, 21}, {0x3fffdf, 22}, {0x7fffeb, 23}, {0x7fffec, 23}, + {0x1fffe0, 21}, {0x1fffe1, 21}, {0x3fffe0, 22}, {0x1fffe2, 21}, + {0x7fffed, 23}, {0x3fffe1, 22}, {0x7fffee, 23}, {0x7fffef, 23}, + {0xfffea, 20}, {0x3fffe2, 22}, {0x3fffe3, 22}, {0x3fffe4, 22}, + {0x7ffff0, 23}, {0x3fffe5, 22}, {0x3fffe6, 22}, {0x7ffff1, 23}, + {0x3ffffe0, 26}, {0x3ffffe1, 26}, {0xfffeb, 20}, {0x7fff1, 19}, + {0x3fffe7, 22}, {0x7ffff2, 23}, {0x3fffe8, 22}, {0x1ffffec, 25}, + {0x3ffffe2, 26}, {0x3ffffe3, 26}, {0x3ffffe4, 26}, {0x7ffffde, 27}, + {0x7ffffdf, 27}, {0x3ffffe5, 26}, {0xfffff1, 24}, {0x1ffffed, 25}, + {0x7fff2, 19}, {0x1fffe3, 21}, {0x3ffffe6, 26}, {0x7ffffe0, 27}, + {0x7ffffe1, 27}, {0x3ffffe7, 26}, {0x7ffffe2, 27}, {0xfffff2, 24}, + {0x1fffe4, 21}, {0x1fffe5, 21}, {0x3ffffe8, 26}, {0x3ffffe9, 26}, + {0xffffffd, 28}, {0x7ffffe3, 27}, {0x7ffffe4, 27}, {0x7ffffe5, 27}, + {0xfffec, 20}, {0xfffff3, 24}, {0xfffed, 20}, {0x1fffe6, 21}, + {0x3fffe9, 22}, {0x1fffe7, 21}, {0x1fffe8, 21}, {0x7ffff3, 23}, + {0x3fffea, 22}, {0x3fffeb, 22}, {0x1ffffee, 25}, {0x1ffffef, 25}, + {0xfffff4, 24}, {0xfffff5, 24}, {0x3ffffea, 26}, {0x7ffff4, 23}, + {0x3ffffeb, 26}, {0x7ffffe6, 27}, {0x3ffffec, 26}, {0x3ffffed, 26}, + {0x7ffffe7, 27}, {0x7ffffe8, 27}, {0x7ffffe9, 27}, {0x7ffffea, 27}, + {0x7ffffeb, 27}, {0xffffffe, 28}, {0x7ffffec, 27}, {0x7ffffed, 27}, + {0x7ffffee, 27}, {0x7ffffef, 27}, {0x7fffff0, 27}, {0x3ffffee, 26}, + {0x3fffffff, 30}, +}; diff --git a/src/core/lib/transport/chttp2/huffsyms.h b/src/core/lib/transport/chttp2/huffsyms.h new file mode 100644 index 0000000000..9c4f09dcf6 --- /dev/null +++ b/src/core/lib/transport/chttp2/huffsyms.h @@ -0,0 +1,48 @@ +/* + * + * Copyright 2015-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_TRANSPORT_CHTTP2_HUFFSYMS_H +#define GRPC_CORE_TRANSPORT_CHTTP2_HUFFSYMS_H + +/* HPACK static huffman table */ + +#define GRPC_CHTTP2_NUM_HUFFSYMS 257 + +typedef struct { + unsigned bits; + unsigned length; +} grpc_chttp2_huffsym; + +extern const grpc_chttp2_huffsym grpc_chttp2_huffsyms[GRPC_CHTTP2_NUM_HUFFSYMS]; + +#endif /* GRPC_CORE_TRANSPORT_CHTTP2_HUFFSYMS_H */ diff --git a/src/core/lib/transport/chttp2/incoming_metadata.c b/src/core/lib/transport/chttp2/incoming_metadata.c new file mode 100644 index 0000000000..315bc2faa1 --- /dev/null +++ b/src/core/lib/transport/chttp2/incoming_metadata.c @@ -0,0 +1,96 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/transport/chttp2/incoming_metadata.h" + +#include + +#include "src/core/transport/chttp2/internal.h" + +#include +#include + +void grpc_chttp2_incoming_metadata_buffer_init( + grpc_chttp2_incoming_metadata_buffer *buffer) { + buffer->deadline = gpr_inf_future(GPR_CLOCK_REALTIME); +} + +void grpc_chttp2_incoming_metadata_buffer_destroy( + grpc_chttp2_incoming_metadata_buffer *buffer) { + size_t i; + if (!buffer->published) { + for (i = 0; i < buffer->count; i++) { + GRPC_MDELEM_UNREF(buffer->elems[i].md); + } + } + gpr_free(buffer->elems); +} + +void grpc_chttp2_incoming_metadata_buffer_add( + grpc_chttp2_incoming_metadata_buffer *buffer, grpc_mdelem *elem) { + GPR_ASSERT(!buffer->published); + if (buffer->capacity == buffer->count) { + buffer->capacity = GPR_MAX(8, 2 * buffer->capacity); + buffer->elems = + gpr_realloc(buffer->elems, sizeof(*buffer->elems) * buffer->capacity); + } + buffer->elems[buffer->count++].md = elem; +} + +void grpc_chttp2_incoming_metadata_buffer_set_deadline( + grpc_chttp2_incoming_metadata_buffer *buffer, gpr_timespec deadline) { + GPR_ASSERT(!buffer->published); + buffer->deadline = deadline; +} + +void grpc_chttp2_incoming_metadata_buffer_publish( + grpc_chttp2_incoming_metadata_buffer *buffer, grpc_metadata_batch *batch) { + GPR_ASSERT(!buffer->published); + buffer->published = 1; + if (buffer->count > 0) { + size_t i; + for (i = 1; i < buffer->count; i++) { + buffer->elems[i].prev = &buffer->elems[i - 1]; + } + for (i = 0; i < buffer->count - 1; i++) { + buffer->elems[i].next = &buffer->elems[i + 1]; + } + buffer->elems[0].prev = NULL; + buffer->elems[buffer->count - 1].next = NULL; + batch->list.head = &buffer->elems[0]; + batch->list.tail = &buffer->elems[buffer->count - 1]; + } else { + batch->list.head = batch->list.tail = NULL; + } + batch->deadline = buffer->deadline; +} diff --git a/src/core/lib/transport/chttp2/incoming_metadata.h b/src/core/lib/transport/chttp2/incoming_metadata.h new file mode 100644 index 0000000000..52454f348c --- /dev/null +++ b/src/core/lib/transport/chttp2/incoming_metadata.h @@ -0,0 +1,60 @@ +/* + * + * Copyright 2015-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_TRANSPORT_CHTTP2_INCOMING_METADATA_H +#define GRPC_CORE_TRANSPORT_CHTTP2_INCOMING_METADATA_H + +#include "src/core/transport/transport.h" + +typedef struct { + grpc_linked_mdelem *elems; + size_t count; + size_t capacity; + gpr_timespec deadline; + int published; +} grpc_chttp2_incoming_metadata_buffer; + +/** assumes everything initially zeroed */ +void grpc_chttp2_incoming_metadata_buffer_init( + grpc_chttp2_incoming_metadata_buffer *buffer); +void grpc_chttp2_incoming_metadata_buffer_destroy( + grpc_chttp2_incoming_metadata_buffer *buffer); +void grpc_chttp2_incoming_metadata_buffer_publish( + grpc_chttp2_incoming_metadata_buffer *buffer, grpc_metadata_batch *batch); + +void grpc_chttp2_incoming_metadata_buffer_add( + grpc_chttp2_incoming_metadata_buffer *buffer, grpc_mdelem *elem); +void grpc_chttp2_incoming_metadata_buffer_set_deadline( + grpc_chttp2_incoming_metadata_buffer *buffer, gpr_timespec deadline); + +#endif /* GRPC_CORE_TRANSPORT_CHTTP2_INCOMING_METADATA_H */ diff --git a/src/core/lib/transport/chttp2/internal.h b/src/core/lib/transport/chttp2/internal.h new file mode 100644 index 0000000000..0690cb37cd --- /dev/null +++ b/src/core/lib/transport/chttp2/internal.h @@ -0,0 +1,780 @@ +/* + * + * Copyright 2015-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_TRANSPORT_CHTTP2_INTERNAL_H +#define GRPC_CORE_TRANSPORT_CHTTP2_INTERNAL_H + +#include +#include + +#include "src/core/iomgr/endpoint.h" +#include "src/core/transport/chttp2/frame.h" +#include "src/core/transport/chttp2/frame_data.h" +#include "src/core/transport/chttp2/frame_goaway.h" +#include "src/core/transport/chttp2/frame_ping.h" +#include "src/core/transport/chttp2/frame_rst_stream.h" +#include "src/core/transport/chttp2/frame_settings.h" +#include "src/core/transport/chttp2/frame_window_update.h" +#include "src/core/transport/chttp2/hpack_encoder.h" +#include "src/core/transport/chttp2/hpack_parser.h" +#include "src/core/transport/chttp2/incoming_metadata.h" +#include "src/core/transport/chttp2/stream_map.h" +#include "src/core/transport/connectivity_state.h" +#include "src/core/transport/transport_impl.h" + +typedef struct grpc_chttp2_transport grpc_chttp2_transport; +typedef struct grpc_chttp2_stream grpc_chttp2_stream; + +/* streams are kept in various linked lists depending on what things need to + happen to them... this enum labels each list */ +typedef enum { + GRPC_CHTTP2_LIST_ALL_STREAMS, + GRPC_CHTTP2_LIST_CHECK_READ_OPS, + GRPC_CHTTP2_LIST_UNANNOUNCED_INCOMING_WINDOW_AVAILABLE, + GRPC_CHTTP2_LIST_WRITABLE, + GRPC_CHTTP2_LIST_WRITING, + GRPC_CHTTP2_LIST_WRITTEN, + GRPC_CHTTP2_LIST_PARSING_SEEN, + GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_PARSING, + GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_WRITING, + GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT, + /* streams waiting for the outgoing window in the writing path, they will be + * merged to the stalled list or writable list under transport lock. */ + GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT, + /** streams that are waiting to start because there are too many concurrent + streams on the connection */ + GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY, + STREAM_LIST_COUNT /* must be last */ +} grpc_chttp2_stream_list_id; + +/* deframer state for the overall http2 stream of bytes */ +typedef enum { + /* prefix: one entry per http2 connection prefix byte */ + GRPC_DTS_CLIENT_PREFIX_0 = 0, + GRPC_DTS_CLIENT_PREFIX_1, + GRPC_DTS_CLIENT_PREFIX_2, + GRPC_DTS_CLIENT_PREFIX_3, + GRPC_DTS_CLIENT_PREFIX_4, + GRPC_DTS_CLIENT_PREFIX_5, + GRPC_DTS_CLIENT_PREFIX_6, + GRPC_DTS_CLIENT_PREFIX_7, + GRPC_DTS_CLIENT_PREFIX_8, + GRPC_DTS_CLIENT_PREFIX_9, + GRPC_DTS_CLIENT_PREFIX_10, + GRPC_DTS_CLIENT_PREFIX_11, + GRPC_DTS_CLIENT_PREFIX_12, + GRPC_DTS_CLIENT_PREFIX_13, + GRPC_DTS_CLIENT_PREFIX_14, + GRPC_DTS_CLIENT_PREFIX_15, + GRPC_DTS_CLIENT_PREFIX_16, + GRPC_DTS_CLIENT_PREFIX_17, + GRPC_DTS_CLIENT_PREFIX_18, + GRPC_DTS_CLIENT_PREFIX_19, + GRPC_DTS_CLIENT_PREFIX_20, + GRPC_DTS_CLIENT_PREFIX_21, + GRPC_DTS_CLIENT_PREFIX_22, + GRPC_DTS_CLIENT_PREFIX_23, + /* frame header byte 0... */ + /* must follow from the prefix states */ + GRPC_DTS_FH_0, + GRPC_DTS_FH_1, + GRPC_DTS_FH_2, + GRPC_DTS_FH_3, + GRPC_DTS_FH_4, + GRPC_DTS_FH_5, + GRPC_DTS_FH_6, + GRPC_DTS_FH_7, + /* ... frame header byte 8 */ + GRPC_DTS_FH_8, + /* inside a http2 frame */ + GRPC_DTS_FRAME +} grpc_chttp2_deframe_transport_state; + +typedef struct { + grpc_chttp2_stream *head; + grpc_chttp2_stream *tail; +} grpc_chttp2_stream_list; + +typedef struct { + grpc_chttp2_stream *next; + grpc_chttp2_stream *prev; +} grpc_chttp2_stream_link; + +/* We keep several sets of connection wide parameters */ +typedef enum { + /* The settings our peer has asked for (and we have acked) */ + GRPC_PEER_SETTINGS = 0, + /* The settings we'd like to have */ + GRPC_LOCAL_SETTINGS, + /* The settings we've published to our peer */ + GRPC_SENT_SETTINGS, + /* The settings the peer has acked */ + GRPC_ACKED_SETTINGS, + GRPC_NUM_SETTING_SETS +} grpc_chttp2_setting_set; + +/* Outstanding ping request data */ +typedef struct grpc_chttp2_outstanding_ping { + uint8_t id[8]; + grpc_closure *on_recv; + struct grpc_chttp2_outstanding_ping *next; + struct grpc_chttp2_outstanding_ping *prev; +} grpc_chttp2_outstanding_ping; + +/* forward declared in frame_data.h */ +struct grpc_chttp2_incoming_byte_stream { + grpc_byte_stream base; + gpr_refcount refs; + struct grpc_chttp2_incoming_byte_stream *next_message; + int failed; + + grpc_chttp2_transport *transport; + grpc_chttp2_stream *stream; + int is_tail; + gpr_slice_buffer slices; + grpc_closure *on_next; + gpr_slice *next; +}; + +typedef struct { + /** data to write next write */ + gpr_slice_buffer qbuf; + + /** window available for us to send to peer */ + int64_t outgoing_window; + /** window available to announce to peer */ + int64_t announce_incoming_window; + /** how much window would we like to have for incoming_window */ + uint32_t connection_window_target; + + /** have we seen a goaway */ + uint8_t seen_goaway; + /** have we sent a goaway */ + uint8_t sent_goaway; + + /** is this transport a client? */ + uint8_t is_client; + /** are the local settings dirty and need to be sent? */ + uint8_t dirtied_local_settings; + /** have local settings been sent? */ + uint8_t sent_local_settings; + /** bitmask of setting indexes to send out */ + uint32_t force_send_settings; + /** settings values */ + uint32_t settings[GRPC_NUM_SETTING_SETS][GRPC_CHTTP2_NUM_SETTINGS]; + + /** what is the next stream id to be allocated by this peer? + copied to next_stream_id in parsing when parsing commences */ + uint32_t next_stream_id; + + /** how far to lookahead in a stream? */ + uint32_t stream_lookahead; + + /** last received stream id */ + uint32_t last_incoming_stream_id; + + /** pings awaiting responses */ + grpc_chttp2_outstanding_ping pings; + /** next payload for an outgoing ping */ + uint64_t ping_counter; + + /** concurrent stream count: updated when not parsing, + so this is a strict over-estimation on the client */ + uint32_t concurrent_stream_count; +} grpc_chttp2_transport_global; + +typedef struct { + /** data to write now */ + gpr_slice_buffer outbuf; + /** hpack encoding */ + grpc_chttp2_hpack_compressor hpack_compressor; + int64_t outgoing_window; + /** is this a client? */ + uint8_t is_client; + /** callback for when writing is done */ + grpc_closure done_cb; +} grpc_chttp2_transport_writing; + +struct grpc_chttp2_transport_parsing { + /** is this transport a client? (boolean) */ + uint8_t is_client; + + /** were settings updated? */ + uint8_t settings_updated; + /** was a settings ack received? */ + uint8_t settings_ack_received; + /** was a goaway frame received? */ + uint8_t goaway_received; + + /** the last sent max_table_size setting */ + uint32_t last_sent_max_table_size; + + /** initial window change */ + int64_t initial_window_update; + + /** data to write later - after parsing */ + gpr_slice_buffer qbuf; + /** parser for headers */ + grpc_chttp2_hpack_parser hpack_parser; + /** simple one shot parsers */ + union { + grpc_chttp2_window_update_parser window_update; + grpc_chttp2_settings_parser settings; + grpc_chttp2_ping_parser ping; + grpc_chttp2_rst_stream_parser rst_stream; + } simple; + /** parser for goaway frames */ + grpc_chttp2_goaway_parser goaway_parser; + + /** window available for peer to send to us */ + int64_t incoming_window; + + /** next stream id available at the time of beginning parsing */ + uint32_t next_stream_id; + uint32_t last_incoming_stream_id; + + /* deframing */ + grpc_chttp2_deframe_transport_state deframe_state; + uint8_t incoming_frame_type; + uint8_t incoming_frame_flags; + uint8_t header_eof; + uint32_t expect_continuation_stream_id; + uint32_t incoming_frame_size; + uint32_t incoming_stream_id; + + /* active parser */ + void *parser_data; + grpc_chttp2_stream_parsing *incoming_stream; + grpc_chttp2_parse_error (*parser)( + grpc_exec_ctx *exec_ctx, void *parser_user_data, + grpc_chttp2_transport_parsing *transport_parsing, + grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); + + /* received settings */ + uint32_t settings[GRPC_CHTTP2_NUM_SETTINGS]; + + /* goaway data */ + grpc_status_code goaway_error; + uint32_t goaway_last_stream_index; + gpr_slice goaway_text; + + int64_t outgoing_window; +}; + +struct grpc_chttp2_transport { + grpc_transport base; /* must be first */ + grpc_endpoint *ep; + gpr_refcount refs; + char *peer_string; + + /** when this drops to zero it's safe to shutdown the endpoint */ + gpr_refcount shutdown_ep_refs; + + gpr_mu mu; + + /** is the transport destroying itself? */ + uint8_t destroying; + /** has the upper layer closed the transport? */ + uint8_t closed; + + /** is a thread currently writing */ + uint8_t writing_active; + /** is a thread currently parsing */ + uint8_t parsing_active; + + /** is there a read request to the endpoint outstanding? */ + uint8_t endpoint_reading; + + /** various lists of streams */ + grpc_chttp2_stream_list lists[STREAM_LIST_COUNT]; + + /** global state for reading/writing */ + grpc_chttp2_transport_global global; + /** state only accessible by the chain of execution that + set writing_active=1 */ + grpc_chttp2_transport_writing writing; + /** state only accessible by the chain of execution that + set parsing_active=1 */ + grpc_chttp2_transport_parsing parsing; + + /** maps stream id to grpc_chttp2_stream objects; + owned by the parsing thread when parsing */ + grpc_chttp2_stream_map parsing_stream_map; + + /** streams created by the client (possibly during parsing); + merged with parsing_stream_map during unlock when no + parsing is occurring */ + grpc_chttp2_stream_map new_stream_map; + + /** closure to execute writing */ + grpc_closure writing_action; + /** closure to finish reading from the endpoint */ + grpc_closure recv_data; + + /** incoming read bytes */ + gpr_slice_buffer read_buffer; + + /** address to place a newly accepted stream - set and unset by + grpc_chttp2_parsing_accept_stream; used by init_stream to + publish the accepted server stream */ + grpc_chttp2_stream **accepting_stream; + + struct { + /* accept stream callback */ + void (*accept_stream)(grpc_exec_ctx *exec_ctx, void *user_data, + grpc_transport *transport, const void *server_data); + void *accept_stream_user_data; + + /** connectivity tracking */ + grpc_connectivity_state_tracker state_tracker; + } channel_callback; + + /** Transport op to be applied post-parsing */ + grpc_transport_op *post_parsing_op; +}; + +typedef struct { + /** HTTP2 stream id for this stream, or zero if one has not been assigned */ + uint32_t id; + + /** window available for us to send to peer */ + int64_t outgoing_window; + /** The number of bytes the upper layers have offered to receive. + As the upper layer offers more bytes, this value increases. + As bytes are read, this value decreases. */ + uint32_t max_recv_bytes; + /** The number of bytes the upper layer has offered to read but we have + not yet announced to HTTP2 flow control. + As the upper layers offer to read more bytes, this value increases. + As we advertise incoming flow control window, this value decreases. */ + uint32_t unannounced_incoming_window_for_parse; + uint32_t unannounced_incoming_window_for_writing; + /** things the upper layers would like to send */ + grpc_metadata_batch *send_initial_metadata; + grpc_closure *send_initial_metadata_finished; + grpc_byte_stream *send_message; + grpc_closure *send_message_finished; + grpc_metadata_batch *send_trailing_metadata; + grpc_closure *send_trailing_metadata_finished; + + grpc_metadata_batch *recv_initial_metadata; + grpc_closure *recv_initial_metadata_ready; + grpc_byte_stream **recv_message; + grpc_closure *recv_message_ready; + grpc_metadata_batch *recv_trailing_metadata; + grpc_closure *recv_trailing_metadata_finished; + + /** when the application requests writes be closed, the write_closed is + 'queued'; when the close is flow controlled into the send path, we are + 'sending' it; when the write has been performed it is 'sent' */ + uint8_t write_closed; + /** is this stream reading half-closed (boolean) */ + uint8_t read_closed; + /** is this stream in the stream map? (boolean) */ + uint8_t in_stream_map; + /** has this stream seen an error? if 1, then pending incoming frames + can be thrown away */ + uint8_t seen_error; + + uint8_t published_initial_metadata; + uint8_t published_trailing_metadata; + uint8_t faked_trailing_metadata; + + grpc_chttp2_incoming_metadata_buffer received_initial_metadata; + grpc_chttp2_incoming_metadata_buffer received_trailing_metadata; + + grpc_chttp2_incoming_frame_queue incoming_frames; +} grpc_chttp2_stream_global; + +typedef struct { + /** HTTP2 stream id for this stream, or zero if one has not been assigned */ + uint32_t id; + uint8_t fetching; + bool sent_initial_metadata; + uint8_t sent_message; + uint8_t sent_trailing_metadata; + uint8_t read_closed; + /** send this initial metadata */ + grpc_metadata_batch *send_initial_metadata; + grpc_byte_stream *send_message; + grpc_metadata_batch *send_trailing_metadata; + int64_t outgoing_window; + /** how much window should we announce? */ + uint32_t announce_window; + gpr_slice_buffer flow_controlled_buffer; + gpr_slice fetching_slice; + size_t stream_fetched; + grpc_closure finished_fetch; +} grpc_chttp2_stream_writing; + +struct grpc_chttp2_stream_parsing { + /** HTTP2 stream id for this stream, or zero if one has not been assigned */ + uint32_t id; + /** has this stream received a close */ + uint8_t received_close; + /** saw a rst_stream */ + uint8_t saw_rst_stream; + /** how many header frames have we received? */ + uint8_t header_frames_received; + /** which metadata did we get (on this parse) */ + uint8_t got_metadata_on_parse[2]; + /** should we raise the seen_error flag in transport_global */ + uint8_t seen_error; + /** window available for peer to send to us */ + int64_t incoming_window; + /** parsing state for data frames */ + grpc_chttp2_data_parser data_parser; + /** reason give to rst_stream */ + uint32_t rst_stream_reason; + /** amount of window given */ + int64_t outgoing_window; + /** number of bytes received - reset at end of parse thread execution */ + int64_t received_bytes; + + /** incoming metadata */ + grpc_chttp2_incoming_metadata_buffer metadata_buffer[2]; +}; + +struct grpc_chttp2_stream { + grpc_stream_refcount *refcount; + grpc_chttp2_stream_global global; + grpc_chttp2_stream_writing writing; + grpc_chttp2_stream_parsing parsing; + + grpc_chttp2_stream_link links[STREAM_LIST_COUNT]; + uint8_t included[STREAM_LIST_COUNT]; +}; + +/** Transport writing call flow: + chttp2_transport.c calls grpc_chttp2_unlocking_check_writes to see if writes + are required; + if they are, chttp2_transport.c calls grpc_chttp2_perform_writes to do the + writes. + Once writes have been completed (meaning another write could potentially be + started), + grpc_chttp2_terminate_writing is called. This will call + grpc_chttp2_cleanup_writing, at which + point the write phase is complete. */ + +/** Someone is unlocking the transport mutex: check to see if writes + are required, and schedule them if so */ +int grpc_chttp2_unlocking_check_writes(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport_global *global, + grpc_chttp2_transport_writing *writing, + int is_parsing); +void grpc_chttp2_perform_writes( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing, + grpc_endpoint *endpoint); +void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx, + void *transport_writing, bool success); +void grpc_chttp2_cleanup_writing(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport_global *global, + grpc_chttp2_transport_writing *writing); + +void grpc_chttp2_prepare_to_read(grpc_chttp2_transport_global *global, + grpc_chttp2_transport_parsing *parsing); +/** Process one slice of incoming data; return 1 if the connection is still + viable after reading, or 0 if the connection should be torn down */ +int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport_parsing *transport_parsing, + gpr_slice slice); +void grpc_chttp2_publish_reads(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport_global *global, + grpc_chttp2_transport_parsing *parsing); + +bool grpc_chttp2_list_add_writable_stream( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global *stream_global); +/** Get a writable stream + returns non-zero if there was a stream available */ +int grpc_chttp2_list_pop_writable_stream( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_transport_writing *transport_writing, + grpc_chttp2_stream_global **stream_global, + grpc_chttp2_stream_writing **stream_writing); +bool grpc_chttp2_list_remove_writable_stream( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global *stream_global) GRPC_MUST_USE_RESULT; + +void grpc_chttp2_list_add_writing_stream( + grpc_chttp2_transport_writing *transport_writing, + grpc_chttp2_stream_writing *stream_writing); +int grpc_chttp2_list_have_writing_streams( + grpc_chttp2_transport_writing *transport_writing); +int grpc_chttp2_list_pop_writing_stream( + grpc_chttp2_transport_writing *transport_writing, + grpc_chttp2_stream_writing **stream_writing); + +void grpc_chttp2_list_add_written_stream( + grpc_chttp2_transport_writing *transport_writing, + grpc_chttp2_stream_writing *stream_writing); +int grpc_chttp2_list_pop_written_stream( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_transport_writing *transport_writing, + grpc_chttp2_stream_global **stream_global, + grpc_chttp2_stream_writing **stream_writing); + +void grpc_chttp2_list_add_parsing_seen_stream( + grpc_chttp2_transport_parsing *transport_parsing, + grpc_chttp2_stream_parsing *stream_parsing); +int grpc_chttp2_list_pop_parsing_seen_stream( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_transport_parsing *transport_parsing, + grpc_chttp2_stream_global **stream_global, + grpc_chttp2_stream_parsing **stream_parsing); + +void grpc_chttp2_list_add_waiting_for_concurrency( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global *stream_global); +int grpc_chttp2_list_pop_waiting_for_concurrency( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global **stream_global); + +void grpc_chttp2_list_add_check_read_ops( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global *stream_global); +int grpc_chttp2_list_pop_check_read_ops( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global **stream_global); + +void grpc_chttp2_list_add_writing_stalled_by_transport( + grpc_chttp2_transport_writing *transport_writing, + grpc_chttp2_stream_writing *stream_writing); +void grpc_chttp2_list_flush_writing_stalled_by_transport( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing, + bool is_window_available); + +void grpc_chttp2_list_add_stalled_by_transport( + grpc_chttp2_transport_writing *transport_writing, + grpc_chttp2_stream_writing *stream_writing); +int grpc_chttp2_list_pop_stalled_by_transport( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global **stream_global); +void grpc_chttp2_list_remove_stalled_by_transport( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global *stream_global); + +void grpc_chttp2_list_add_unannounced_incoming_window_available( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global *stream_global); +void grpc_chttp2_list_remove_unannounced_incoming_window_available( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global *stream_global); +int grpc_chttp2_list_pop_unannounced_incoming_window_available( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_transport_parsing *transport_parsing, + grpc_chttp2_stream_global **stream_global, + grpc_chttp2_stream_parsing **stream_parsing); + +void grpc_chttp2_list_add_closed_waiting_for_parsing( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global *stream_global); +int grpc_chttp2_list_pop_closed_waiting_for_parsing( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global **stream_global); + +void grpc_chttp2_list_add_closed_waiting_for_writing( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global *stream_global); +int grpc_chttp2_list_pop_closed_waiting_for_writing( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global **stream_global); + +grpc_chttp2_stream_parsing *grpc_chttp2_parsing_lookup_stream( + grpc_chttp2_transport_parsing *transport_parsing, uint32_t id); +grpc_chttp2_stream_parsing *grpc_chttp2_parsing_accept_stream( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, + uint32_t id); + +void grpc_chttp2_add_incoming_goaway( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, + uint32_t goaway_error, gpr_slice goaway_text); + +void grpc_chttp2_register_stream(grpc_chttp2_transport *t, + grpc_chttp2_stream *s); +/* returns 1 if this is the last stream, 0 otherwise */ +int grpc_chttp2_unregister_stream(grpc_chttp2_transport *t, + grpc_chttp2_stream *s) GRPC_MUST_USE_RESULT; +int grpc_chttp2_has_streams(grpc_chttp2_transport *t); +void grpc_chttp2_for_all_streams( + grpc_chttp2_transport_global *transport_global, void *user_data, + void (*cb)(grpc_chttp2_transport_global *transport_global, void *user_data, + grpc_chttp2_stream_global *stream_global)); + +void grpc_chttp2_parsing_become_skip_parser( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing); + +void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx, + grpc_closure **pclosure, int success); + +#define GRPC_CHTTP2_CLIENT_CONNECT_STRING "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" +#define GRPC_CHTTP2_CLIENT_CONNECT_STRLEN \ + (sizeof(GRPC_CHTTP2_CLIENT_CONNECT_STRING) - 1) + +extern int grpc_http_trace; +extern int grpc_flowctl_trace; + +#define GRPC_CHTTP2_IF_TRACING(stmt) \ + if (!(grpc_http_trace)) \ + ; \ + else \ + stmt + +typedef enum { + GRPC_CHTTP2_FLOWCTL_MOVE, + GRPC_CHTTP2_FLOWCTL_CREDIT, + GRPC_CHTTP2_FLOWCTL_DEBIT +} grpc_chttp2_flowctl_op; + +#define GRPC_CHTTP2_FLOW_MOVE_COMMON(phase, transport, id1, id2, dst_context, \ + dst_var, src_context, src_var) \ + do { \ + assert(id1 == id2); \ + if (grpc_flowctl_trace) { \ + grpc_chttp2_flowctl_trace( \ + __FILE__, __LINE__, phase, GRPC_CHTTP2_FLOWCTL_MOVE, #dst_context, \ + #dst_var, #src_context, #src_var, transport->is_client, id1, \ + dst_context->dst_var, src_context->src_var); \ + } \ + dst_context->dst_var += src_context->src_var; \ + src_context->src_var = 0; \ + } while (0) + +#define GRPC_CHTTP2_FLOW_MOVE_STREAM(phase, transport, dst_context, dst_var, \ + src_context, src_var) \ + GRPC_CHTTP2_FLOW_MOVE_COMMON(phase, transport, dst_context->id, \ + src_context->id, dst_context, dst_var, \ + src_context, src_var) +#define GRPC_CHTTP2_FLOW_MOVE_TRANSPORT(phase, dst_context, dst_var, \ + src_context, src_var) \ + GRPC_CHTTP2_FLOW_MOVE_COMMON(phase, dst_context, 0, 0, dst_context, dst_var, \ + src_context, src_var) + +#define GRPC_CHTTP2_FLOW_CREDIT_COMMON(phase, transport, id, dst_context, \ + dst_var, amount) \ + do { \ + if (grpc_flowctl_trace) { \ + grpc_chttp2_flowctl_trace(__FILE__, __LINE__, phase, \ + GRPC_CHTTP2_FLOWCTL_CREDIT, #dst_context, \ + #dst_var, NULL, #amount, transport->is_client, \ + id, dst_context->dst_var, amount); \ + } \ + dst_context->dst_var += amount; \ + } while (0) + +#define GRPC_CHTTP2_FLOW_CREDIT_STREAM(phase, transport, dst_context, dst_var, \ + amount) \ + GRPC_CHTTP2_FLOW_CREDIT_COMMON(phase, transport, dst_context->id, \ + dst_context, dst_var, amount) +#define GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT(phase, dst_context, dst_var, amount) \ + GRPC_CHTTP2_FLOW_CREDIT_COMMON(phase, dst_context, 0, dst_context, dst_var, \ + amount) + +#define GRPC_CHTTP2_FLOW_DEBIT_COMMON(phase, transport, id, dst_context, \ + dst_var, amount) \ + do { \ + if (grpc_flowctl_trace) { \ + grpc_chttp2_flowctl_trace(__FILE__, __LINE__, phase, \ + GRPC_CHTTP2_FLOWCTL_DEBIT, #dst_context, \ + #dst_var, NULL, #amount, transport->is_client, \ + id, dst_context->dst_var, amount); \ + } \ + dst_context->dst_var -= amount; \ + } while (0) + +#define GRPC_CHTTP2_FLOW_DEBIT_STREAM(phase, transport, dst_context, dst_var, \ + amount) \ + GRPC_CHTTP2_FLOW_DEBIT_COMMON(phase, transport, dst_context->id, \ + dst_context, dst_var, amount) +#define GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT(phase, dst_context, dst_var, amount) \ + GRPC_CHTTP2_FLOW_DEBIT_COMMON(phase, dst_context, 0, dst_context, dst_var, \ + amount) + +void grpc_chttp2_flowctl_trace(const char *file, int line, const char *phase, + grpc_chttp2_flowctl_op op, const char *context1, + const char *var1, const char *context2, + const char *var2, int is_client, + uint32_t stream_id, int64_t val1, int64_t val2); + +void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global *stream, + grpc_status_code status, gpr_slice *details); +void grpc_chttp2_mark_stream_closed( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global *stream_global, int close_reads, + int close_writes); +void grpc_chttp2_start_writing(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport_global *transport_global); + +#ifdef GRPC_STREAM_REFCOUNT_DEBUG +#define GRPC_CHTTP2_STREAM_REF(stream_global, reason) \ + grpc_chttp2_stream_ref(stream_global, reason) +#define GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, reason) \ + grpc_chttp2_stream_unref(exec_ctx, stream_global, reason) +void grpc_chttp2_stream_ref(grpc_chttp2_stream_global *stream_global, + const char *reason); +void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx, + grpc_chttp2_stream_global *stream_global, + const char *reason); +#else +#define GRPC_CHTTP2_STREAM_REF(stream_global, reason) \ + grpc_chttp2_stream_ref(stream_global) +#define GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, reason) \ + grpc_chttp2_stream_unref(exec_ctx, stream_global) +void grpc_chttp2_stream_ref(grpc_chttp2_stream_global *stream_global); +void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx, + grpc_chttp2_stream_global *stream_global); +#endif + +grpc_chttp2_incoming_byte_stream *grpc_chttp2_incoming_byte_stream_create( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, + grpc_chttp2_stream_parsing *stream_parsing, uint32_t frame_size, + uint32_t flags, grpc_chttp2_incoming_frame_queue *add_to_queue); +void grpc_chttp2_incoming_byte_stream_push(grpc_exec_ctx *exec_ctx, + grpc_chttp2_incoming_byte_stream *bs, + gpr_slice slice); +void grpc_chttp2_incoming_byte_stream_finished( + grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs, int success, + int from_parsing_thread); + +void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport_parsing *parsing, + const uint8_t *opaque_8bytes); + +/** add a ref to the stream and add it to the writable list; + ref will be dropped in writing.c */ +void grpc_chttp2_become_writable(grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global *stream_global); + +#endif /* GRPC_CORE_TRANSPORT_CHTTP2_INTERNAL_H */ diff --git a/src/core/lib/transport/chttp2/parsing.c b/src/core/lib/transport/chttp2/parsing.c new file mode 100644 index 0000000000..0516f39fa9 --- /dev/null +++ b/src/core/lib/transport/chttp2/parsing.c @@ -0,0 +1,866 @@ +/* + * + * Copyright 2015-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/transport/chttp2/internal.h" + +#include + +#include +#include +#include + +#include "src/core/profiling/timers.h" +#include "src/core/transport/chttp2/http2_errors.h" +#include "src/core/transport/chttp2/status_conversion.h" +#include "src/core/transport/chttp2/timeout_encoding.h" +#include "src/core/transport/static_metadata.h" + +static int init_frame_parser(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport_parsing *transport_parsing); +static int init_header_frame_parser( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, + int is_continuation); +static int init_data_frame_parser( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing); +static int init_rst_stream_parser( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing); +static int init_settings_frame_parser( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing); +static int init_window_update_frame_parser( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing); +static int init_ping_parser(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport_parsing *transport_parsing); +static int init_goaway_parser(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport_parsing *transport_parsing); +static int init_skip_frame_parser( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, + int is_header); + +static int parse_frame_slice(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport_parsing *transport_parsing, + gpr_slice slice, int is_last); + +void grpc_chttp2_prepare_to_read( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_transport_parsing *transport_parsing) { + grpc_chttp2_stream_global *stream_global; + grpc_chttp2_stream_parsing *stream_parsing; + + GPR_TIMER_BEGIN("grpc_chttp2_prepare_to_read", 0); + + transport_parsing->next_stream_id = transport_global->next_stream_id; + transport_parsing->last_sent_max_table_size = + transport_global->settings[GRPC_SENT_SETTINGS] + [GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE]; + + /* update the parsing view of incoming window */ + while (grpc_chttp2_list_pop_unannounced_incoming_window_available( + transport_global, transport_parsing, &stream_global, &stream_parsing)) { + GRPC_CHTTP2_FLOW_MOVE_STREAM("parse", transport_parsing, stream_parsing, + incoming_window, stream_global, + unannounced_incoming_window_for_parse); + } + + GPR_TIMER_END("grpc_chttp2_prepare_to_read", 0); +} + +void grpc_chttp2_publish_reads( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, + grpc_chttp2_transport_parsing *transport_parsing) { + grpc_chttp2_stream_global *stream_global; + grpc_chttp2_stream_parsing *stream_parsing; + int was_zero; + int is_zero; + + /* transport_parsing->last_incoming_stream_id is used as + last-grpc_chttp2_stream-id when + sending GOAWAY frame. + https://tools.ietf.org/html/draft-ietf-httpbis-http2-17#section-6.8 + says that last-grpc_chttp2_stream-id is peer-initiated grpc_chttp2_stream + ID. So, + since we don't have server pushed streams, client should send + GOAWAY last-grpc_chttp2_stream-id=0 in this case. */ + if (!transport_parsing->is_client) { + transport_global->last_incoming_stream_id = + transport_parsing->incoming_stream_id; + } + + /* update global settings */ + if (transport_parsing->settings_updated) { + memcpy(transport_global->settings[GRPC_PEER_SETTINGS], + transport_parsing->settings, sizeof(transport_parsing->settings)); + transport_parsing->settings_updated = 0; + } + + /* update settings based on ack if received */ + if (transport_parsing->settings_ack_received) { + memcpy(transport_global->settings[GRPC_ACKED_SETTINGS], + transport_global->settings[GRPC_SENT_SETTINGS], + GRPC_CHTTP2_NUM_SETTINGS * sizeof(uint32_t)); + transport_parsing->settings_ack_received = 0; + transport_global->sent_local_settings = 0; + } + + /* move goaway to the global state if we received one (it will be + published later */ + if (transport_parsing->goaway_received) { + grpc_chttp2_add_incoming_goaway(exec_ctx, transport_global, + (uint32_t)transport_parsing->goaway_error, + transport_parsing->goaway_text); + transport_parsing->goaway_text = gpr_empty_slice(); + transport_parsing->goaway_received = 0; + } + + /* propagate flow control tokens to global state */ + was_zero = transport_global->outgoing_window <= 0; + GRPC_CHTTP2_FLOW_MOVE_TRANSPORT("parsed", transport_global, outgoing_window, + transport_parsing, outgoing_window); + is_zero = transport_global->outgoing_window <= 0; + if (was_zero && !is_zero) { + while (grpc_chttp2_list_pop_stalled_by_transport(transport_global, + &stream_global)) { + grpc_chttp2_become_writable(transport_global, stream_global); + } + } + + if (transport_parsing->incoming_window < + transport_global->connection_window_target * 3 / 4) { + int64_t announce_bytes = transport_global->connection_window_target - + transport_parsing->incoming_window; + GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parsed", transport_global, + announce_incoming_window, announce_bytes); + GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parsed", transport_parsing, + incoming_window, announce_bytes); + } + + /* for each stream that saw an update, fixup global state */ + while (grpc_chttp2_list_pop_parsing_seen_stream( + transport_global, transport_parsing, &stream_global, &stream_parsing)) { + if (stream_parsing->seen_error) { + stream_global->seen_error = 1; + grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); + } + + /* update outgoing flow control window */ + was_zero = stream_global->outgoing_window <= 0; + GRPC_CHTTP2_FLOW_MOVE_STREAM("parsed", transport_global, stream_global, + outgoing_window, stream_parsing, + outgoing_window); + is_zero = stream_global->outgoing_window <= 0; + if (was_zero && !is_zero) { + grpc_chttp2_become_writable(transport_global, stream_global); + } + + stream_global->max_recv_bytes -= (uint32_t)GPR_MIN( + stream_global->max_recv_bytes, stream_parsing->received_bytes); + stream_parsing->received_bytes = 0; + + /* publish incoming stream ops */ + if (stream_global->incoming_frames.tail != NULL) { + stream_global->incoming_frames.tail->is_tail = 0; + } + if (stream_parsing->data_parser.incoming_frames.head != NULL) { + grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); + } + grpc_chttp2_incoming_frame_queue_merge( + &stream_global->incoming_frames, + &stream_parsing->data_parser.incoming_frames); + if (stream_global->incoming_frames.tail != NULL) { + stream_global->incoming_frames.tail->is_tail = 1; + } + + if (!stream_global->published_initial_metadata && + stream_parsing->got_metadata_on_parse[0]) { + stream_parsing->got_metadata_on_parse[0] = 0; + stream_global->published_initial_metadata = 1; + GPR_SWAP(grpc_chttp2_incoming_metadata_buffer, + stream_parsing->metadata_buffer[0], + stream_global->received_initial_metadata); + grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); + } + if (!stream_global->published_trailing_metadata && + stream_parsing->got_metadata_on_parse[1]) { + stream_parsing->got_metadata_on_parse[1] = 0; + stream_global->published_trailing_metadata = 1; + GPR_SWAP(grpc_chttp2_incoming_metadata_buffer, + stream_parsing->metadata_buffer[1], + stream_global->received_trailing_metadata); + grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); + } + + if (stream_parsing->saw_rst_stream) { + if (stream_parsing->rst_stream_reason != GRPC_CHTTP2_NO_ERROR) { + grpc_status_code status_code = grpc_chttp2_http2_error_to_grpc_status( + (grpc_chttp2_error_code)stream_parsing->rst_stream_reason); + char *status_details; + gpr_slice slice_details; + gpr_asprintf(&status_details, "Received RST_STREAM err=%d", + stream_parsing->rst_stream_reason); + slice_details = gpr_slice_from_copied_string(status_details); + gpr_free(status_details); + grpc_chttp2_fake_status(exec_ctx, transport_global, stream_global, + status_code, &slice_details); + } + grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, + 1, 1); + } + + if (stream_parsing->received_close) { + grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, + 1, 0); + } + } +} + +int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport_parsing *transport_parsing, + gpr_slice slice) { + uint8_t *beg = GPR_SLICE_START_PTR(slice); + uint8_t *end = GPR_SLICE_END_PTR(slice); + uint8_t *cur = beg; + + if (cur == end) return 1; + + switch (transport_parsing->deframe_state) { + case GRPC_DTS_CLIENT_PREFIX_0: + case GRPC_DTS_CLIENT_PREFIX_1: + case GRPC_DTS_CLIENT_PREFIX_2: + case GRPC_DTS_CLIENT_PREFIX_3: + case GRPC_DTS_CLIENT_PREFIX_4: + case GRPC_DTS_CLIENT_PREFIX_5: + case GRPC_DTS_CLIENT_PREFIX_6: + case GRPC_DTS_CLIENT_PREFIX_7: + case GRPC_DTS_CLIENT_PREFIX_8: + case GRPC_DTS_CLIENT_PREFIX_9: + case GRPC_DTS_CLIENT_PREFIX_10: + case GRPC_DTS_CLIENT_PREFIX_11: + case GRPC_DTS_CLIENT_PREFIX_12: + case GRPC_DTS_CLIENT_PREFIX_13: + case GRPC_DTS_CLIENT_PREFIX_14: + case GRPC_DTS_CLIENT_PREFIX_15: + case GRPC_DTS_CLIENT_PREFIX_16: + case GRPC_DTS_CLIENT_PREFIX_17: + case GRPC_DTS_CLIENT_PREFIX_18: + case GRPC_DTS_CLIENT_PREFIX_19: + case GRPC_DTS_CLIENT_PREFIX_20: + case GRPC_DTS_CLIENT_PREFIX_21: + case GRPC_DTS_CLIENT_PREFIX_22: + case GRPC_DTS_CLIENT_PREFIX_23: + while (cur != end && transport_parsing->deframe_state != GRPC_DTS_FH_0) { + if (*cur != GRPC_CHTTP2_CLIENT_CONNECT_STRING[transport_parsing + ->deframe_state]) { + gpr_log(GPR_INFO, + "Connect string mismatch: expected '%c' (%d) got '%c' (%d) " + "at byte %d", + GRPC_CHTTP2_CLIENT_CONNECT_STRING[transport_parsing + ->deframe_state], + (int)(uint8_t)GRPC_CHTTP2_CLIENT_CONNECT_STRING + [transport_parsing->deframe_state], + *cur, (int)*cur, transport_parsing->deframe_state); + return 0; + } + ++cur; + ++transport_parsing->deframe_state; + } + if (cur == end) { + return 1; + } + /* fallthrough */ + dts_fh_0: + case GRPC_DTS_FH_0: + GPR_ASSERT(cur < end); + transport_parsing->incoming_frame_size = ((uint32_t)*cur) << 16; + if (++cur == end) { + transport_parsing->deframe_state = GRPC_DTS_FH_1; + return 1; + } + /* fallthrough */ + case GRPC_DTS_FH_1: + GPR_ASSERT(cur < end); + transport_parsing->incoming_frame_size |= ((uint32_t)*cur) << 8; + if (++cur == end) { + transport_parsing->deframe_state = GRPC_DTS_FH_2; + return 1; + } + /* fallthrough */ + case GRPC_DTS_FH_2: + GPR_ASSERT(cur < end); + transport_parsing->incoming_frame_size |= *cur; + if (++cur == end) { + transport_parsing->deframe_state = GRPC_DTS_FH_3; + return 1; + } + /* fallthrough */ + case GRPC_DTS_FH_3: + GPR_ASSERT(cur < end); + transport_parsing->incoming_frame_type = *cur; + if (++cur == end) { + transport_parsing->deframe_state = GRPC_DTS_FH_4; + return 1; + } + /* fallthrough */ + case GRPC_DTS_FH_4: + GPR_ASSERT(cur < end); + transport_parsing->incoming_frame_flags = *cur; + if (++cur == end) { + transport_parsing->deframe_state = GRPC_DTS_FH_5; + return 1; + } + /* fallthrough */ + case GRPC_DTS_FH_5: + GPR_ASSERT(cur < end); + transport_parsing->incoming_stream_id = (((uint32_t)*cur) & 0x7f) << 24; + if (++cur == end) { + transport_parsing->deframe_state = GRPC_DTS_FH_6; + return 1; + } + /* fallthrough */ + case GRPC_DTS_FH_6: + GPR_ASSERT(cur < end); + transport_parsing->incoming_stream_id |= ((uint32_t)*cur) << 16; + if (++cur == end) { + transport_parsing->deframe_state = GRPC_DTS_FH_7; + return 1; + } + /* fallthrough */ + case GRPC_DTS_FH_7: + GPR_ASSERT(cur < end); + transport_parsing->incoming_stream_id |= ((uint32_t)*cur) << 8; + if (++cur == end) { + transport_parsing->deframe_state = GRPC_DTS_FH_8; + return 1; + } + /* fallthrough */ + case GRPC_DTS_FH_8: + GPR_ASSERT(cur < end); + transport_parsing->incoming_stream_id |= ((uint32_t)*cur); + transport_parsing->deframe_state = GRPC_DTS_FRAME; + if (!init_frame_parser(exec_ctx, transport_parsing)) { + return 0; + } + if (transport_parsing->incoming_stream_id) { + transport_parsing->last_incoming_stream_id = + transport_parsing->incoming_stream_id; + } + if (transport_parsing->incoming_frame_size == 0) { + if (!parse_frame_slice(exec_ctx, transport_parsing, gpr_empty_slice(), + 1)) { + return 0; + } + transport_parsing->incoming_stream = NULL; + if (++cur == end) { + transport_parsing->deframe_state = GRPC_DTS_FH_0; + return 1; + } + goto dts_fh_0; /* loop */ + } + if (++cur == end) { + return 1; + } + /* fallthrough */ + case GRPC_DTS_FRAME: + GPR_ASSERT(cur < end); + if ((uint32_t)(end - cur) == transport_parsing->incoming_frame_size) { + if (!parse_frame_slice(exec_ctx, transport_parsing, + gpr_slice_sub_no_ref(slice, (size_t)(cur - beg), + (size_t)(end - beg)), + 1)) { + return 0; + } + transport_parsing->deframe_state = GRPC_DTS_FH_0; + transport_parsing->incoming_stream = NULL; + return 1; + } else if ((uint32_t)(end - cur) > + transport_parsing->incoming_frame_size) { + size_t cur_offset = (size_t)(cur - beg); + if (!parse_frame_slice( + exec_ctx, transport_parsing, + gpr_slice_sub_no_ref( + slice, cur_offset, + cur_offset + transport_parsing->incoming_frame_size), + 1)) { + return 0; + } + cur += transport_parsing->incoming_frame_size; + transport_parsing->incoming_stream = NULL; + goto dts_fh_0; /* loop */ + } else { + if (!parse_frame_slice(exec_ctx, transport_parsing, + gpr_slice_sub_no_ref(slice, (size_t)(cur - beg), + (size_t)(end - beg)), + 0)) { + return 0; + } + transport_parsing->incoming_frame_size -= (uint32_t)(end - cur); + return 1; + } + GPR_UNREACHABLE_CODE(return 0); + } + + GPR_UNREACHABLE_CODE(return 0); +} + +static int init_frame_parser(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport_parsing *transport_parsing) { + if (transport_parsing->expect_continuation_stream_id != 0) { + if (transport_parsing->incoming_frame_type != + GRPC_CHTTP2_FRAME_CONTINUATION) { + gpr_log(GPR_ERROR, "Expected CONTINUATION frame, got frame type %02x", + transport_parsing->incoming_frame_type); + return 0; + } + if (transport_parsing->expect_continuation_stream_id != + transport_parsing->incoming_stream_id) { + gpr_log(GPR_ERROR, + "Expected CONTINUATION frame for grpc_chttp2_stream %08x, got " + "grpc_chttp2_stream %08x", + transport_parsing->expect_continuation_stream_id, + transport_parsing->incoming_stream_id); + return 0; + } + return init_header_frame_parser(exec_ctx, transport_parsing, 1); + } + switch (transport_parsing->incoming_frame_type) { + case GRPC_CHTTP2_FRAME_DATA: + return init_data_frame_parser(exec_ctx, transport_parsing); + case GRPC_CHTTP2_FRAME_HEADER: + return init_header_frame_parser(exec_ctx, transport_parsing, 0); + case GRPC_CHTTP2_FRAME_CONTINUATION: + gpr_log(GPR_ERROR, "Unexpected CONTINUATION frame"); + return 0; + case GRPC_CHTTP2_FRAME_RST_STREAM: + return init_rst_stream_parser(exec_ctx, transport_parsing); + case GRPC_CHTTP2_FRAME_SETTINGS: + return init_settings_frame_parser(exec_ctx, transport_parsing); + case GRPC_CHTTP2_FRAME_WINDOW_UPDATE: + return init_window_update_frame_parser(exec_ctx, transport_parsing); + case GRPC_CHTTP2_FRAME_PING: + return init_ping_parser(exec_ctx, transport_parsing); + case GRPC_CHTTP2_FRAME_GOAWAY: + return init_goaway_parser(exec_ctx, transport_parsing); + default: + gpr_log(GPR_ERROR, "Unknown frame type %02x", + transport_parsing->incoming_frame_type); + return init_skip_frame_parser(exec_ctx, transport_parsing, 0); + } +} + +static grpc_chttp2_parse_error skip_parser( + grpc_exec_ctx *exec_ctx, void *parser, + grpc_chttp2_transport_parsing *transport_parsing, + grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { + return GRPC_CHTTP2_PARSE_OK; +} + +static void skip_header(void *tp, grpc_mdelem *md) { GRPC_MDELEM_UNREF(md); } + +static int init_skip_frame_parser( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, + int is_header) { + if (is_header) { + uint8_t is_eoh = transport_parsing->expect_continuation_stream_id != 0; + transport_parsing->parser = grpc_chttp2_header_parser_parse; + transport_parsing->parser_data = &transport_parsing->hpack_parser; + transport_parsing->hpack_parser.on_header = skip_header; + transport_parsing->hpack_parser.on_header_user_data = NULL; + transport_parsing->hpack_parser.is_boundary = is_eoh; + transport_parsing->hpack_parser.is_eof = + (uint8_t)(is_eoh ? transport_parsing->header_eof : 0); + } else { + transport_parsing->parser = skip_parser; + } + return 1; +} + +void grpc_chttp2_parsing_become_skip_parser( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) { + init_skip_frame_parser( + exec_ctx, transport_parsing, + transport_parsing->parser == grpc_chttp2_header_parser_parse); +} + +static grpc_chttp2_parse_error update_incoming_window( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, + 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", + 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", + transport_parsing->incoming_frame_size, + stream_parsing->incoming_window); + return GRPC_CHTTP2_CONNECTION_ERROR; + } + + GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("parse", transport_parsing, incoming_window, + incoming_frame_size); + GRPC_CHTTP2_FLOW_DEBIT_STREAM("parse", transport_parsing, stream_parsing, + incoming_window, incoming_frame_size); + stream_parsing->received_bytes += incoming_frame_size; + + grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing); + + return GRPC_CHTTP2_PARSE_OK; +} + +static int init_data_frame_parser( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) { + grpc_chttp2_stream_parsing *stream_parsing = + grpc_chttp2_parsing_lookup_stream(transport_parsing, + transport_parsing->incoming_stream_id); + grpc_chttp2_parse_error err = GRPC_CHTTP2_PARSE_OK; + if (!stream_parsing || stream_parsing->received_close) + return init_skip_frame_parser(exec_ctx, transport_parsing, 0); + if (err == GRPC_CHTTP2_PARSE_OK) { + err = update_incoming_window(exec_ctx, transport_parsing, stream_parsing); + } + if (err == GRPC_CHTTP2_PARSE_OK) { + err = grpc_chttp2_data_parser_begin_frame( + &stream_parsing->data_parser, transport_parsing->incoming_frame_flags); + } + switch (err) { + case GRPC_CHTTP2_PARSE_OK: + transport_parsing->incoming_stream = stream_parsing; + transport_parsing->parser = grpc_chttp2_data_parser_parse; + transport_parsing->parser_data = &stream_parsing->data_parser; + return 1; + case GRPC_CHTTP2_STREAM_ERROR: + stream_parsing->received_close = 1; + stream_parsing->saw_rst_stream = 1; + stream_parsing->rst_stream_reason = GRPC_CHTTP2_PROTOCOL_ERROR; + gpr_slice_buffer_add( + &transport_parsing->qbuf, + grpc_chttp2_rst_stream_create(transport_parsing->incoming_stream_id, + GRPC_CHTTP2_PROTOCOL_ERROR)); + return init_skip_frame_parser(exec_ctx, transport_parsing, 0); + case GRPC_CHTTP2_CONNECTION_ERROR: + return 0; + } + GPR_UNREACHABLE_CODE(return 0); +} + +static void free_timeout(void *p) { gpr_free(p); } + +static void on_initial_header(void *tp, grpc_mdelem *md) { + grpc_chttp2_transport_parsing *transport_parsing = tp; + grpc_chttp2_stream_parsing *stream_parsing = + transport_parsing->incoming_stream; + + GPR_TIMER_BEGIN("on_initial_header", 0); + + GPR_ASSERT(stream_parsing); + + GRPC_CHTTP2_IF_TRACING(gpr_log( + GPR_INFO, "HTTP:%d:HDR:%s: %s: %s", stream_parsing->id, + transport_parsing->is_client ? "CLI" : "SVR", + grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value))); + + if (md->key == GRPC_MDSTR_GRPC_STATUS && md != GRPC_MDELEM_GRPC_STATUS_0) { + /* TODO(ctiller): check for a status like " 0" */ + stream_parsing->seen_error = 1; + } + + if (md->key == GRPC_MDSTR_GRPC_TIMEOUT) { + gpr_timespec *cached_timeout = grpc_mdelem_get_user_data(md, free_timeout); + if (!cached_timeout) { + /* not already parsed: parse it now, and store the result away */ + cached_timeout = gpr_malloc(sizeof(gpr_timespec)); + if (!grpc_chttp2_decode_timeout(grpc_mdstr_as_c_string(md->value), + cached_timeout)) { + gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'", + grpc_mdstr_as_c_string(md->value)); + *cached_timeout = gpr_inf_future(GPR_TIMESPAN); + } + grpc_mdelem_set_user_data(md, free_timeout, cached_timeout); + } + grpc_chttp2_incoming_metadata_buffer_set_deadline( + &stream_parsing->metadata_buffer[0], + gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), *cached_timeout)); + GRPC_MDELEM_UNREF(md); + } else { + grpc_chttp2_incoming_metadata_buffer_add( + &stream_parsing->metadata_buffer[0], md); + } + + grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing); + + GPR_TIMER_END("on_initial_header", 0); +} + +static void on_trailing_header(void *tp, grpc_mdelem *md) { + grpc_chttp2_transport_parsing *transport_parsing = tp; + grpc_chttp2_stream_parsing *stream_parsing = + transport_parsing->incoming_stream; + + GPR_TIMER_BEGIN("on_trailing_header", 0); + + GPR_ASSERT(stream_parsing); + + GRPC_CHTTP2_IF_TRACING(gpr_log( + GPR_INFO, "HTTP:%d:TRL:%s: %s: %s", stream_parsing->id, + transport_parsing->is_client ? "CLI" : "SVR", + grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value))); + + if (md->key == GRPC_MDSTR_GRPC_STATUS && md != GRPC_MDELEM_GRPC_STATUS_0) { + /* TODO(ctiller): check for a status like " 0" */ + stream_parsing->seen_error = 1; + } + + grpc_chttp2_incoming_metadata_buffer_add(&stream_parsing->metadata_buffer[1], + md); + + grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing); + + GPR_TIMER_END("on_trailing_header", 0); +} + +static int init_header_frame_parser( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, + int is_continuation) { + uint8_t is_eoh = (transport_parsing->incoming_frame_flags & + GRPC_CHTTP2_DATA_FLAG_END_HEADERS) != 0; + int via_accept = 0; + grpc_chttp2_stream_parsing *stream_parsing; + + /* TODO(ctiller): when to increment header_frames_received? */ + + if (is_eoh) { + transport_parsing->expect_continuation_stream_id = 0; + } else { + transport_parsing->expect_continuation_stream_id = + transport_parsing->incoming_stream_id; + } + + if (!is_continuation) { + transport_parsing->header_eof = (transport_parsing->incoming_frame_flags & + GRPC_CHTTP2_DATA_FLAG_END_STREAM) != 0; + } + + /* could be a new grpc_chttp2_stream or an existing grpc_chttp2_stream */ + stream_parsing = grpc_chttp2_parsing_lookup_stream( + transport_parsing, transport_parsing->incoming_stream_id); + if (stream_parsing == NULL) { + if (is_continuation) { + gpr_log(GPR_ERROR, + "grpc_chttp2_stream disbanded before CONTINUATION received"); + return init_skip_frame_parser(exec_ctx, transport_parsing, 1); + } + if (transport_parsing->is_client) { + if ((transport_parsing->incoming_stream_id & 1) && + transport_parsing->incoming_stream_id < + transport_parsing->next_stream_id) { + /* this is an old (probably cancelled) grpc_chttp2_stream */ + } else { + gpr_log(GPR_ERROR, + "ignoring new grpc_chttp2_stream creation on client"); + } + return init_skip_frame_parser(exec_ctx, transport_parsing, 1); + } else if (transport_parsing->last_incoming_stream_id > + transport_parsing->incoming_stream_id) { + gpr_log(GPR_ERROR, + "ignoring out of order new grpc_chttp2_stream request on server; " + "last grpc_chttp2_stream " + "id=%d, new grpc_chttp2_stream id=%d", + transport_parsing->last_incoming_stream_id, + transport_parsing->incoming_stream_id); + return init_skip_frame_parser(exec_ctx, transport_parsing, 1); + } else if ((transport_parsing->incoming_stream_id & 1) == 0) { + gpr_log(GPR_ERROR, + "ignoring grpc_chttp2_stream with non-client generated index %d", + transport_parsing->incoming_stream_id); + return init_skip_frame_parser(exec_ctx, transport_parsing, 1); + } + stream_parsing = transport_parsing->incoming_stream = + grpc_chttp2_parsing_accept_stream( + exec_ctx, transport_parsing, transport_parsing->incoming_stream_id); + if (stream_parsing == NULL) { + gpr_log(GPR_ERROR, "grpc_chttp2_stream not accepted"); + return init_skip_frame_parser(exec_ctx, transport_parsing, 1); + } + via_accept = 1; + } else { + transport_parsing->incoming_stream = stream_parsing; + } + GPR_ASSERT(stream_parsing != NULL && (via_accept == 0 || via_accept == 1)); + if (stream_parsing->received_close) { + gpr_log(GPR_ERROR, "skipping already closed grpc_chttp2_stream header"); + transport_parsing->incoming_stream = NULL; + return init_skip_frame_parser(exec_ctx, transport_parsing, 1); + } + transport_parsing->parser = grpc_chttp2_header_parser_parse; + transport_parsing->parser_data = &transport_parsing->hpack_parser; + switch (stream_parsing->header_frames_received) { + case 0: + transport_parsing->hpack_parser.on_header = on_initial_header; + break; + case 1: + transport_parsing->hpack_parser.on_header = on_trailing_header; + break; + case 2: + gpr_log(GPR_ERROR, "too many header frames received"); + return init_skip_frame_parser(exec_ctx, transport_parsing, 1); + } + transport_parsing->hpack_parser.on_header_user_data = transport_parsing; + transport_parsing->hpack_parser.is_boundary = is_eoh; + transport_parsing->hpack_parser.is_eof = + (uint8_t)(is_eoh ? transport_parsing->header_eof : 0); + if (!is_continuation && (transport_parsing->incoming_frame_flags & + GRPC_CHTTP2_FLAG_HAS_PRIORITY)) { + grpc_chttp2_hpack_parser_set_has_priority(&transport_parsing->hpack_parser); + } + return 1; +} + +static int init_window_update_frame_parser( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) { + int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_window_update_parser_begin_frame( + &transport_parsing->simple.window_update, + transport_parsing->incoming_frame_size, + transport_parsing->incoming_frame_flags); + if (transport_parsing->incoming_stream_id) { + transport_parsing->incoming_stream = grpc_chttp2_parsing_lookup_stream( + transport_parsing, transport_parsing->incoming_stream_id); + } + transport_parsing->parser = grpc_chttp2_window_update_parser_parse; + transport_parsing->parser_data = &transport_parsing->simple.window_update; + return ok; +} + +static int init_ping_parser(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport_parsing *transport_parsing) { + int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_ping_parser_begin_frame( + &transport_parsing->simple.ping, + transport_parsing->incoming_frame_size, + transport_parsing->incoming_frame_flags); + transport_parsing->parser = grpc_chttp2_ping_parser_parse; + transport_parsing->parser_data = &transport_parsing->simple.ping; + return ok; +} + +static int init_rst_stream_parser( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) { + int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_rst_stream_parser_begin_frame( + &transport_parsing->simple.rst_stream, + transport_parsing->incoming_frame_size, + transport_parsing->incoming_frame_flags); + transport_parsing->incoming_stream = grpc_chttp2_parsing_lookup_stream( + transport_parsing, transport_parsing->incoming_stream_id); + if (!transport_parsing->incoming_stream) { + return init_skip_frame_parser(exec_ctx, transport_parsing, 0); + } + transport_parsing->parser = grpc_chttp2_rst_stream_parser_parse; + transport_parsing->parser_data = &transport_parsing->simple.rst_stream; + return ok; +} + +static int init_goaway_parser( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) { + int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_goaway_parser_begin_frame( + &transport_parsing->goaway_parser, + transport_parsing->incoming_frame_size, + transport_parsing->incoming_frame_flags); + transport_parsing->parser = grpc_chttp2_goaway_parser_parse; + transport_parsing->parser_data = &transport_parsing->goaway_parser; + return ok; +} + +static int init_settings_frame_parser( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) { + int ok; + + if (transport_parsing->incoming_stream_id != 0) { + gpr_log(GPR_ERROR, "settings frame received for grpc_chttp2_stream %d", + transport_parsing->incoming_stream_id); + return 0; + } + + ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_settings_parser_begin_frame( + &transport_parsing->simple.settings, + transport_parsing->incoming_frame_size, + transport_parsing->incoming_frame_flags, + transport_parsing->settings); + if (!ok) { + return 0; + } + if (transport_parsing->incoming_frame_flags & GRPC_CHTTP2_FLAG_ACK) { + transport_parsing->settings_ack_received = 1; + grpc_chttp2_hptbl_set_max_bytes( + &transport_parsing->hpack_parser.table, + transport_parsing->last_sent_max_table_size); + } + transport_parsing->parser = grpc_chttp2_settings_parser_parse; + transport_parsing->parser_data = &transport_parsing->simple.settings; + return ok; +} + +/* +static int is_window_update_legal(int64_t window_update, int64_t window) { + return window + window_update < MAX_WINDOW; +} +*/ + +static int parse_frame_slice(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport_parsing *transport_parsing, + gpr_slice slice, int is_last) { + grpc_chttp2_stream_parsing *stream_parsing = + transport_parsing->incoming_stream; + switch (transport_parsing->parser(exec_ctx, transport_parsing->parser_data, + transport_parsing, stream_parsing, slice, + is_last)) { + case GRPC_CHTTP2_PARSE_OK: + if (stream_parsing) { + grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, + stream_parsing); + } + return 1; + case GRPC_CHTTP2_STREAM_ERROR: + grpc_chttp2_parsing_become_skip_parser(exec_ctx, transport_parsing); + if (stream_parsing) { + stream_parsing->saw_rst_stream = 1; + stream_parsing->rst_stream_reason = GRPC_CHTTP2_PROTOCOL_ERROR; + gpr_slice_buffer_add( + &transport_parsing->qbuf, + grpc_chttp2_rst_stream_create(transport_parsing->incoming_stream_id, + GRPC_CHTTP2_PROTOCOL_ERROR)); + } + return 1; + case GRPC_CHTTP2_CONNECTION_ERROR: + return 0; + } + GPR_UNREACHABLE_CODE(return 0); +} diff --git a/src/core/lib/transport/chttp2/status_conversion.c b/src/core/lib/transport/chttp2/status_conversion.c new file mode 100644 index 0000000000..bf214b017a --- /dev/null +++ b/src/core/lib/transport/chttp2/status_conversion.c @@ -0,0 +1,109 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/transport/chttp2/status_conversion.h" + +int grpc_chttp2_grpc_status_to_http2_error(grpc_status_code status) { + switch (status) { + case GRPC_STATUS_OK: + return GRPC_CHTTP2_NO_ERROR; + case GRPC_STATUS_CANCELLED: + return GRPC_CHTTP2_CANCEL; + case GRPC_STATUS_RESOURCE_EXHAUSTED: + return GRPC_CHTTP2_ENHANCE_YOUR_CALM; + case GRPC_STATUS_PERMISSION_DENIED: + return GRPC_CHTTP2_INADEQUATE_SECURITY; + case GRPC_STATUS_UNAVAILABLE: + return GRPC_CHTTP2_REFUSED_STREAM; + default: + return GRPC_CHTTP2_INTERNAL_ERROR; + } +} + +grpc_status_code grpc_chttp2_http2_error_to_grpc_status( + grpc_chttp2_error_code error) { + switch (error) { + case GRPC_CHTTP2_NO_ERROR: + /* should never be received */ + return GRPC_STATUS_INTERNAL; + case GRPC_CHTTP2_CANCEL: + return GRPC_STATUS_CANCELLED; + case GRPC_CHTTP2_ENHANCE_YOUR_CALM: + return GRPC_STATUS_RESOURCE_EXHAUSTED; + case GRPC_CHTTP2_INADEQUATE_SECURITY: + return GRPC_STATUS_PERMISSION_DENIED; + case GRPC_CHTTP2_REFUSED_STREAM: + return GRPC_STATUS_UNAVAILABLE; + default: + return GRPC_STATUS_INTERNAL; + } +} + +grpc_status_code grpc_chttp2_http2_status_to_grpc_status(int status) { + switch (status) { + /* these HTTP2 status codes are called out explicitly in status.proto */ + case 200: + return GRPC_STATUS_OK; + case 400: + return GRPC_STATUS_INVALID_ARGUMENT; + case 401: + return GRPC_STATUS_UNAUTHENTICATED; + case 403: + return GRPC_STATUS_PERMISSION_DENIED; + case 404: + return GRPC_STATUS_NOT_FOUND; + case 409: + return GRPC_STATUS_ABORTED; + case 412: + return GRPC_STATUS_FAILED_PRECONDITION; + case 429: + return GRPC_STATUS_RESOURCE_EXHAUSTED; + case 499: + return GRPC_STATUS_CANCELLED; + case 500: + return GRPC_STATUS_UNKNOWN; + case 501: + return GRPC_STATUS_UNIMPLEMENTED; + case 503: + return GRPC_STATUS_UNAVAILABLE; + case 504: + return GRPC_STATUS_DEADLINE_EXCEEDED; + /* everything else is unknown */ + default: + return GRPC_STATUS_UNKNOWN; + } +} + +int grpc_chttp2_grpc_status_to_http2_status(grpc_status_code status) { + return 200; +} diff --git a/src/core/lib/transport/chttp2/status_conversion.h b/src/core/lib/transport/chttp2/status_conversion.h new file mode 100644 index 0000000000..c6e066bb5d --- /dev/null +++ b/src/core/lib/transport/chttp2/status_conversion.h @@ -0,0 +1,50 @@ +/* + * + * Copyright 2015-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_TRANSPORT_CHTTP2_STATUS_CONVERSION_H +#define GRPC_CORE_TRANSPORT_CHTTP2_STATUS_CONVERSION_H + +#include +#include "src/core/transport/chttp2/http2_errors.h" + +/* Conversion of grpc status codes to http2 error codes (for RST_STREAM) */ +grpc_chttp2_error_code grpc_chttp2_grpc_status_to_http2_error( + grpc_status_code status); +grpc_status_code grpc_chttp2_http2_error_to_grpc_status( + grpc_chttp2_error_code error); + +/* Conversion of HTTP status codes (:status) to grpc status codes */ +grpc_status_code grpc_chttp2_http2_status_to_grpc_status(int status); +int grpc_chttp2_grpc_status_to_http2_status(grpc_status_code status); + +#endif /* GRPC_CORE_TRANSPORT_CHTTP2_STATUS_CONVERSION_H */ diff --git a/src/core/lib/transport/chttp2/stream_lists.c b/src/core/lib/transport/chttp2/stream_lists.c new file mode 100644 index 0000000000..60fe735cfc --- /dev/null +++ b/src/core/lib/transport/chttp2/stream_lists.c @@ -0,0 +1,442 @@ +/* + * + * Copyright 2015-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/transport/chttp2/internal.h" + +#include + +#define TRANSPORT_FROM_GLOBAL(tg) \ + ((grpc_chttp2_transport *)((char *)(tg)-offsetof(grpc_chttp2_transport, \ + global))) + +#define STREAM_FROM_GLOBAL(sg) \ + ((grpc_chttp2_stream *)((char *)(sg)-offsetof(grpc_chttp2_stream, global))) + +#define TRANSPORT_FROM_WRITING(tw) \ + ((grpc_chttp2_transport *)((char *)(tw)-offsetof(grpc_chttp2_transport, \ + writing))) + +#define STREAM_FROM_WRITING(sw) \ + ((grpc_chttp2_stream *)((char *)(sw)-offsetof(grpc_chttp2_stream, writing))) + +#define TRANSPORT_FROM_PARSING(tp) \ + ((grpc_chttp2_transport *)((char *)(tp)-offsetof(grpc_chttp2_transport, \ + parsing))) + +#define STREAM_FROM_PARSING(sp) \ + ((grpc_chttp2_stream *)((char *)(sp)-offsetof(grpc_chttp2_stream, parsing))) + +/* core list management */ + +static int stream_list_empty(grpc_chttp2_transport *t, + grpc_chttp2_stream_list_id id) { + return t->lists[id].head == NULL; +} + +static int stream_list_pop(grpc_chttp2_transport *t, + grpc_chttp2_stream **stream, + grpc_chttp2_stream_list_id id) { + grpc_chttp2_stream *s = t->lists[id].head; + if (s) { + grpc_chttp2_stream *new_head = s->links[id].next; + GPR_ASSERT(s->included[id]); + if (new_head) { + t->lists[id].head = new_head; + new_head->links[id].prev = NULL; + } else { + t->lists[id].head = NULL; + t->lists[id].tail = NULL; + } + s->included[id] = 0; + } + *stream = s; + return s != 0; +} + +static void stream_list_remove(grpc_chttp2_transport *t, grpc_chttp2_stream *s, + grpc_chttp2_stream_list_id id) { + GPR_ASSERT(s->included[id]); + s->included[id] = 0; + if (s->links[id].prev) { + s->links[id].prev->links[id].next = s->links[id].next; + } else { + GPR_ASSERT(t->lists[id].head == s); + t->lists[id].head = s->links[id].next; + } + if (s->links[id].next) { + s->links[id].next->links[id].prev = s->links[id].prev; + } else { + t->lists[id].tail = s->links[id].prev; + } +} + +static bool stream_list_maybe_remove(grpc_chttp2_transport *t, + grpc_chttp2_stream *s, + grpc_chttp2_stream_list_id id) { + if (s->included[id]) { + stream_list_remove(t, s, id); + return true; + } else { + return false; + } +} + +static void stream_list_add_tail(grpc_chttp2_transport *t, + grpc_chttp2_stream *s, + grpc_chttp2_stream_list_id id) { + grpc_chttp2_stream *old_tail; + GPR_ASSERT(!s->included[id]); + old_tail = t->lists[id].tail; + s->links[id].next = NULL; + s->links[id].prev = old_tail; + if (old_tail) { + old_tail->links[id].next = s; + } else { + t->lists[id].head = s; + } + t->lists[id].tail = s; + s->included[id] = 1; +} + +static bool stream_list_add(grpc_chttp2_transport *t, grpc_chttp2_stream *s, + grpc_chttp2_stream_list_id id) { + if (s->included[id]) { + return false; + } + stream_list_add_tail(t, s, id); + return true; +} + +/* wrappers for specializations */ + +bool grpc_chttp2_list_add_writable_stream( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global *stream_global) { + GPR_ASSERT(stream_global->id != 0); + return stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global), + STREAM_FROM_GLOBAL(stream_global), + GRPC_CHTTP2_LIST_WRITABLE); +} + +int grpc_chttp2_list_pop_writable_stream( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_transport_writing *transport_writing, + grpc_chttp2_stream_global **stream_global, + grpc_chttp2_stream_writing **stream_writing) { + grpc_chttp2_stream *stream; + int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream, + GRPC_CHTTP2_LIST_WRITABLE); + if (r != 0) { + *stream_global = &stream->global; + *stream_writing = &stream->writing; + } + return r; +} + +bool grpc_chttp2_list_remove_writable_stream( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global *stream_global) { + return stream_list_maybe_remove(TRANSPORT_FROM_GLOBAL(transport_global), + STREAM_FROM_GLOBAL(stream_global), + GRPC_CHTTP2_LIST_WRITABLE); +} + +void grpc_chttp2_list_add_writing_stream( + grpc_chttp2_transport_writing *transport_writing, + grpc_chttp2_stream_writing *stream_writing) { + GPR_ASSERT(stream_list_add(TRANSPORT_FROM_WRITING(transport_writing), + STREAM_FROM_WRITING(stream_writing), + GRPC_CHTTP2_LIST_WRITING)); +} + +int grpc_chttp2_list_have_writing_streams( + grpc_chttp2_transport_writing *transport_writing) { + return !stream_list_empty(TRANSPORT_FROM_WRITING(transport_writing), + GRPC_CHTTP2_LIST_WRITING); +} + +int grpc_chttp2_list_pop_writing_stream( + grpc_chttp2_transport_writing *transport_writing, + grpc_chttp2_stream_writing **stream_writing) { + grpc_chttp2_stream *stream; + int r = stream_list_pop(TRANSPORT_FROM_WRITING(transport_writing), &stream, + GRPC_CHTTP2_LIST_WRITING); + if (r != 0) { + *stream_writing = &stream->writing; + } + return r; +} + +void grpc_chttp2_list_add_written_stream( + grpc_chttp2_transport_writing *transport_writing, + grpc_chttp2_stream_writing *stream_writing) { + stream_list_add(TRANSPORT_FROM_WRITING(transport_writing), + STREAM_FROM_WRITING(stream_writing), + GRPC_CHTTP2_LIST_WRITTEN); +} + +int grpc_chttp2_list_pop_written_stream( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_transport_writing *transport_writing, + grpc_chttp2_stream_global **stream_global, + grpc_chttp2_stream_writing **stream_writing) { + grpc_chttp2_stream *stream; + int r = stream_list_pop(TRANSPORT_FROM_WRITING(transport_writing), &stream, + GRPC_CHTTP2_LIST_WRITTEN); + if (r != 0) { + *stream_global = &stream->global; + *stream_writing = &stream->writing; + } + return r; +} + +void grpc_chttp2_list_add_unannounced_incoming_window_available( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global *stream_global) { + GPR_ASSERT(stream_global->id != 0); + stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global), + STREAM_FROM_GLOBAL(stream_global), + GRPC_CHTTP2_LIST_UNANNOUNCED_INCOMING_WINDOW_AVAILABLE); +} + +void grpc_chttp2_list_remove_unannounced_incoming_window_available( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global *stream_global) { + stream_list_maybe_remove( + TRANSPORT_FROM_GLOBAL(transport_global), + STREAM_FROM_GLOBAL(stream_global), + GRPC_CHTTP2_LIST_UNANNOUNCED_INCOMING_WINDOW_AVAILABLE); +} + +int grpc_chttp2_list_pop_unannounced_incoming_window_available( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_transport_parsing *transport_parsing, + grpc_chttp2_stream_global **stream_global, + grpc_chttp2_stream_parsing **stream_parsing) { + grpc_chttp2_stream *stream; + int r = + stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream, + GRPC_CHTTP2_LIST_UNANNOUNCED_INCOMING_WINDOW_AVAILABLE); + if (r != 0) { + *stream_global = &stream->global; + *stream_parsing = &stream->parsing; + } + return r; +} + +void grpc_chttp2_list_add_parsing_seen_stream( + grpc_chttp2_transport_parsing *transport_parsing, + grpc_chttp2_stream_parsing *stream_parsing) { + stream_list_add(TRANSPORT_FROM_PARSING(transport_parsing), + STREAM_FROM_PARSING(stream_parsing), + GRPC_CHTTP2_LIST_PARSING_SEEN); +} + +int grpc_chttp2_list_pop_parsing_seen_stream( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_transport_parsing *transport_parsing, + grpc_chttp2_stream_global **stream_global, + grpc_chttp2_stream_parsing **stream_parsing) { + grpc_chttp2_stream *stream; + int r = stream_list_pop(TRANSPORT_FROM_PARSING(transport_parsing), &stream, + GRPC_CHTTP2_LIST_PARSING_SEEN); + if (r != 0) { + *stream_global = &stream->global; + *stream_parsing = &stream->parsing; + } + return r; +} + +void grpc_chttp2_list_add_waiting_for_concurrency( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global *stream_global) { + stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global), + STREAM_FROM_GLOBAL(stream_global), + GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY); +} + +int grpc_chttp2_list_pop_waiting_for_concurrency( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global **stream_global) { + grpc_chttp2_stream *stream; + int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream, + GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY); + if (r != 0) { + *stream_global = &stream->global; + } + return r; +} + +void grpc_chttp2_list_add_check_read_ops( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global *stream_global) { + stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global), + STREAM_FROM_GLOBAL(stream_global), + GRPC_CHTTP2_LIST_CHECK_READ_OPS); +} + +int grpc_chttp2_list_pop_check_read_ops( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global **stream_global) { + grpc_chttp2_stream *stream; + int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream, + GRPC_CHTTP2_LIST_CHECK_READ_OPS); + if (r != 0) { + *stream_global = &stream->global; + } + return r; +} + +void grpc_chttp2_list_add_writing_stalled_by_transport( + grpc_chttp2_transport_writing *transport_writing, + grpc_chttp2_stream_writing *stream_writing) { + grpc_chttp2_stream *stream = STREAM_FROM_WRITING(stream_writing); + if (!stream->included[GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT]) { + GRPC_CHTTP2_STREAM_REF(&stream->global, "chttp2_writing_stalled"); + } + stream_list_add(TRANSPORT_FROM_WRITING(transport_writing), stream, + GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT); +} + +void grpc_chttp2_list_flush_writing_stalled_by_transport( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing, + bool is_window_available) { + grpc_chttp2_stream *stream; + grpc_chttp2_transport *transport = TRANSPORT_FROM_WRITING(transport_writing); + while (stream_list_pop(transport, &stream, + GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT)) { + if (is_window_available) { + grpc_chttp2_become_writable(&transport->global, &stream->global); + } else { + grpc_chttp2_list_add_stalled_by_transport(transport_writing, + &stream->writing); + } + GRPC_CHTTP2_STREAM_UNREF(exec_ctx, &stream->global, + "chttp2_writing_stalled"); + } +} + +void grpc_chttp2_list_add_stalled_by_transport( + grpc_chttp2_transport_writing *transport_writing, + grpc_chttp2_stream_writing *stream_writing) { + stream_list_add(TRANSPORT_FROM_WRITING(transport_writing), + STREAM_FROM_WRITING(stream_writing), + GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT); +} + +int grpc_chttp2_list_pop_stalled_by_transport( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global **stream_global) { + grpc_chttp2_stream *stream; + int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream, + GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT); + if (r != 0) { + *stream_global = &stream->global; + } + return r; +} + +void grpc_chttp2_list_remove_stalled_by_transport( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global *stream_global) { + stream_list_maybe_remove(TRANSPORT_FROM_GLOBAL(transport_global), + STREAM_FROM_GLOBAL(stream_global), + GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT); +} + +void grpc_chttp2_list_add_closed_waiting_for_parsing( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global *stream_global) { + stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global), + STREAM_FROM_GLOBAL(stream_global), + GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_PARSING); +} + +int grpc_chttp2_list_pop_closed_waiting_for_parsing( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global **stream_global) { + grpc_chttp2_stream *stream; + int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream, + GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_PARSING); + if (r != 0) { + *stream_global = &stream->global; + } + return r; +} + +void grpc_chttp2_list_add_closed_waiting_for_writing( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global *stream_global) { + stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global), + STREAM_FROM_GLOBAL(stream_global), + GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_WRITING); +} + +int grpc_chttp2_list_pop_closed_waiting_for_writing( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global **stream_global) { + grpc_chttp2_stream *stream; + int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream, + GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_WRITING); + if (r != 0) { + *stream_global = &stream->global; + } + return r; +} + +void grpc_chttp2_register_stream(grpc_chttp2_transport *t, + grpc_chttp2_stream *s) { + stream_list_add_tail(t, s, GRPC_CHTTP2_LIST_ALL_STREAMS); +} + +int grpc_chttp2_unregister_stream(grpc_chttp2_transport *t, + grpc_chttp2_stream *s) { + stream_list_maybe_remove(t, s, GRPC_CHTTP2_LIST_ALL_STREAMS); + return stream_list_empty(t, GRPC_CHTTP2_LIST_ALL_STREAMS); +} + +int grpc_chttp2_has_streams(grpc_chttp2_transport *t) { + return !stream_list_empty(t, GRPC_CHTTP2_LIST_ALL_STREAMS); +} + +void grpc_chttp2_for_all_streams( + grpc_chttp2_transport_global *transport_global, void *user_data, + void (*cb)(grpc_chttp2_transport_global *transport_global, void *user_data, + grpc_chttp2_stream_global *stream_global)) { + grpc_chttp2_stream *s; + grpc_chttp2_transport *t = TRANSPORT_FROM_GLOBAL(transport_global); + for (s = t->lists[GRPC_CHTTP2_LIST_ALL_STREAMS].head; s != NULL; + s = s->links[GRPC_CHTTP2_LIST_ALL_STREAMS].next) { + cb(transport_global, user_data, &s->global); + } +} diff --git a/src/core/lib/transport/chttp2/stream_map.c b/src/core/lib/transport/chttp2/stream_map.c new file mode 100644 index 0000000000..555a16fb72 --- /dev/null +++ b/src/core/lib/transport/chttp2/stream_map.c @@ -0,0 +1,197 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/transport/chttp2/stream_map.h" + +#include + +#include +#include +#include + +void grpc_chttp2_stream_map_init(grpc_chttp2_stream_map *map, + size_t initial_capacity) { + GPR_ASSERT(initial_capacity > 1); + map->keys = gpr_malloc(sizeof(uint32_t) * initial_capacity); + map->values = gpr_malloc(sizeof(void *) * initial_capacity); + map->count = 0; + map->free = 0; + map->capacity = initial_capacity; +} + +void grpc_chttp2_stream_map_destroy(grpc_chttp2_stream_map *map) { + gpr_free(map->keys); + gpr_free(map->values); +} + +static size_t compact(uint32_t *keys, void **values, size_t count) { + size_t i, out; + + for (i = 0, out = 0; i < count; i++) { + if (values[i]) { + keys[out] = keys[i]; + values[out] = values[i]; + out++; + } + } + + return out; +} + +void grpc_chttp2_stream_map_add(grpc_chttp2_stream_map *map, uint32_t key, + void *value) { + size_t count = map->count; + size_t capacity = map->capacity; + uint32_t *keys = map->keys; + void **values = map->values; + + GPR_ASSERT(count == 0 || keys[count - 1] < key); + GPR_ASSERT(value); + + if (count == capacity) { + if (map->free > capacity / 4) { + count = compact(keys, values, count); + map->free = 0; + } else { + /* resize when less than 25% of the table is free, because compaction + won't help much */ + map->capacity = capacity = 3 * capacity / 2; + map->keys = keys = gpr_realloc(keys, capacity * sizeof(uint32_t)); + map->values = values = gpr_realloc(values, capacity * sizeof(void *)); + } + } + + keys[count] = key; + values[count] = value; + map->count = count + 1; +} + +void grpc_chttp2_stream_map_move_into(grpc_chttp2_stream_map *src, + grpc_chttp2_stream_map *dst) { + /* if src is empty we dont need to do anything */ + if (src->count == src->free) { + return; + } + /* if dst is empty we simply need to swap */ + if (dst->count == dst->free) { + GPR_SWAP(grpc_chttp2_stream_map, *src, *dst); + return; + } + /* the first element of src must be greater than the last of dst... + * however the maps may need compacting for this property to hold */ + if (src->keys[0] <= dst->keys[dst->count - 1]) { + src->count = compact(src->keys, src->values, src->count); + src->free = 0; + dst->count = compact(dst->keys, dst->values, dst->count); + dst->free = 0; + } + GPR_ASSERT(src->keys[0] > dst->keys[dst->count - 1]); + /* if dst doesn't have capacity, resize */ + if (dst->count + src->count > dst->capacity) { + dst->capacity = GPR_MAX(dst->capacity * 3 / 2, dst->count + src->count); + dst->keys = gpr_realloc(dst->keys, dst->capacity * sizeof(uint32_t)); + dst->values = gpr_realloc(dst->values, dst->capacity * sizeof(void *)); + } + memcpy(dst->keys + dst->count, src->keys, src->count * sizeof(uint32_t)); + memcpy(dst->values + dst->count, src->values, src->count * sizeof(void *)); + dst->count += src->count; + dst->free += src->free; + src->count = 0; + src->free = 0; +} + +static void **find(grpc_chttp2_stream_map *map, uint32_t key) { + size_t min_idx = 0; + size_t max_idx = map->count; + size_t mid_idx; + uint32_t *keys = map->keys; + void **values = map->values; + uint32_t mid_key; + + if (max_idx == 0) return NULL; + + while (min_idx < max_idx) { + /* find the midpoint, avoiding overflow */ + mid_idx = min_idx + ((max_idx - min_idx) / 2); + mid_key = keys[mid_idx]; + + if (mid_key < key) { + min_idx = mid_idx + 1; + } else if (mid_key > key) { + max_idx = mid_idx; + } else /* mid_key == key */ + { + return &values[mid_idx]; + } + } + + return NULL; +} + +void *grpc_chttp2_stream_map_delete(grpc_chttp2_stream_map *map, uint32_t key) { + void **pvalue = find(map, key); + void *out = NULL; + if (pvalue != NULL) { + out = *pvalue; + *pvalue = NULL; + map->free += (out != NULL); + /* recognize complete emptyness and ensure we can skip + * defragmentation later */ + if (map->free == map->count) { + map->free = map->count = 0; + } + } + return out; +} + +void *grpc_chttp2_stream_map_find(grpc_chttp2_stream_map *map, uint32_t key) { + void **pvalue = find(map, key); + return pvalue != NULL ? *pvalue : NULL; +} + +size_t grpc_chttp2_stream_map_size(grpc_chttp2_stream_map *map) { + return map->count - map->free; +} + +void grpc_chttp2_stream_map_for_each(grpc_chttp2_stream_map *map, + void (*f)(void *user_data, uint32_t key, + void *value), + void *user_data) { + size_t i; + + for (i = 0; i < map->count; i++) { + if (map->values[i]) { + f(user_data, map->keys[i], map->values[i]); + } + } +} diff --git a/src/core/lib/transport/chttp2/stream_map.h b/src/core/lib/transport/chttp2/stream_map.h new file mode 100644 index 0000000000..957a58a4f2 --- /dev/null +++ b/src/core/lib/transport/chttp2/stream_map.h @@ -0,0 +1,84 @@ +/* + * + * Copyright 2015-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_TRANSPORT_CHTTP2_STREAM_MAP_H +#define GRPC_CORE_TRANSPORT_CHTTP2_STREAM_MAP_H + +#include + +#include + +/* Data structure to map a uint32_t to a data object (represented by a void*) + + Represented as a sorted array of keys, and a corresponding array of values. + Lookups are performed with binary search. + Adds are restricted to strictly higher keys than previously seen (this is + guaranteed by http2). */ +typedef struct { + uint32_t *keys; + void **values; + size_t count; + size_t free; + size_t capacity; +} grpc_chttp2_stream_map; + +void grpc_chttp2_stream_map_init(grpc_chttp2_stream_map *map, + size_t initial_capacity); +void grpc_chttp2_stream_map_destroy(grpc_chttp2_stream_map *map); + +/* Add a new key: given http2 semantics, new keys must always be greater than + existing keys - this is asserted */ +void grpc_chttp2_stream_map_add(grpc_chttp2_stream_map *map, uint32_t key, + void *value); + +/* Delete an existing key - returns the previous value of the key if it existed, + or NULL otherwise */ +void *grpc_chttp2_stream_map_delete(grpc_chttp2_stream_map *map, uint32_t key); + +/* Move all elements of src into dst */ +void grpc_chttp2_stream_map_move_into(grpc_chttp2_stream_map *src, + grpc_chttp2_stream_map *dst); + +/* Return an existing key, or NULL if it does not exist */ +void *grpc_chttp2_stream_map_find(grpc_chttp2_stream_map *map, uint32_t key); + +/* How many (populated) entries are in the stream map? */ +size_t grpc_chttp2_stream_map_size(grpc_chttp2_stream_map *map); + +/* Callback on each stream */ +void grpc_chttp2_stream_map_for_each(grpc_chttp2_stream_map *map, + void (*f)(void *user_data, uint32_t key, + void *value), + void *user_data); + +#endif /* GRPC_CORE_TRANSPORT_CHTTP2_STREAM_MAP_H */ diff --git a/src/core/lib/transport/chttp2/timeout_encoding.c b/src/core/lib/transport/chttp2/timeout_encoding.c new file mode 100644 index 0000000000..c4802e050e --- /dev/null +++ b/src/core/lib/transport/chttp2/timeout_encoding.c @@ -0,0 +1,188 @@ +/* + * + * Copyright 2015-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/transport/chttp2/timeout_encoding.h" + +#include +#include + +#include +#include "src/core/support/string.h" + +static int64_t round_up(int64_t x, int64_t divisor) { + return (x / divisor + (x % divisor != 0)) * divisor; +} + +/* round an integer up to the next value with three significant figures */ +static int64_t round_up_to_three_sig_figs(int64_t x) { + if (x < 1000) return x; + if (x < 10000) return round_up(x, 10); + if (x < 100000) return round_up(x, 100); + if (x < 1000000) return round_up(x, 1000); + if (x < 10000000) return round_up(x, 10000); + if (x < 100000000) return round_up(x, 100000); + if (x < 1000000000) return round_up(x, 1000000); + return round_up(x, 10000000); +} + +/* encode our minimum viable timeout value */ +static void enc_tiny(char *buffer) { memcpy(buffer, "1n", 3); } + +static void enc_ext(char *buffer, int64_t value, char ext) { + int n = int64_ttoa(value, buffer); + buffer[n] = ext; + buffer[n + 1] = 0; +} + +static void enc_seconds(char *buffer, int64_t sec) { + if (sec % 3600 == 0) { + enc_ext(buffer, sec / 3600, 'H'); + } else if (sec % 60 == 0) { + enc_ext(buffer, sec / 60, 'M'); + } else { + enc_ext(buffer, sec, 'S'); + } +} + +static void enc_nanos(char *buffer, int64_t x) { + x = round_up_to_three_sig_figs(x); + if (x < 100000) { + if (x % 1000 == 0) { + enc_ext(buffer, x / 1000, 'u'); + } else { + enc_ext(buffer, x, 'n'); + } + } else if (x < 100000000) { + if (x % 1000000 == 0) { + enc_ext(buffer, x / 1000000, 'm'); + } else { + enc_ext(buffer, x / 1000, 'u'); + } + } else if (x < 1000000000) { + enc_ext(buffer, x / 1000000, 'm'); + } else { + /* note that this is only ever called with times of less than one second, + so if we reach here the time must have been rounded up to a whole second + (and no more) */ + memcpy(buffer, "1S", 3); + } +} + +static void enc_micros(char *buffer, int64_t x) { + x = round_up_to_three_sig_figs(x); + if (x < 100000) { + if (x % 1000 == 0) { + enc_ext(buffer, x / 1000, 'm'); + } else { + enc_ext(buffer, x, 'u'); + } + } else if (x < 100000000) { + if (x % 1000000 == 0) { + enc_ext(buffer, x / 1000000, 'S'); + } else { + enc_ext(buffer, x / 1000, 'm'); + } + } else { + enc_ext(buffer, x / 1000000, 'S'); + } +} + +void grpc_chttp2_encode_timeout(gpr_timespec timeout, char *buffer) { + if (timeout.tv_sec < 0) { + enc_tiny(buffer); + } else if (timeout.tv_sec == 0) { + enc_nanos(buffer, timeout.tv_nsec); + } else if (timeout.tv_sec < 1000 && timeout.tv_nsec != 0) { + enc_micros(buffer, + (int64_t)(timeout.tv_sec * 1000000) + + (timeout.tv_nsec / 1000 + (timeout.tv_nsec % 1000 != 0))); + } else { + enc_seconds(buffer, timeout.tv_sec + (timeout.tv_nsec != 0)); + } +} + +static int is_all_whitespace(const char *p) { + while (*p == ' ') p++; + return *p == 0; +} + +int grpc_chttp2_decode_timeout(const char *buffer, gpr_timespec *timeout) { + int32_t x = 0; + const uint8_t *p = (const uint8_t *)buffer; + int have_digit = 0; + /* skip whitespace */ + for (; *p == ' '; p++) + ; + /* decode numeric part */ + for (; *p >= '0' && *p <= '9'; p++) { + int32_t digit = (int32_t)(*p - (uint8_t)'0'); + have_digit = 1; + /* spec allows max. 8 digits, but we allow values up to 1,000,000,000 */ + if (x >= (100 * 1000 * 1000)) { + if (x != (100 * 1000 * 1000) || digit != 0) { + *timeout = gpr_inf_future(GPR_TIMESPAN); + return 1; + } + } + x = x * 10 + digit; + } + if (!have_digit) return 0; + /* skip whitespace */ + for (; *p == ' '; p++) + ; + /* decode unit specifier */ + switch (*p) { + case 'n': + *timeout = gpr_time_from_nanos(x, GPR_TIMESPAN); + break; + case 'u': + *timeout = gpr_time_from_micros(x, GPR_TIMESPAN); + break; + case 'm': + *timeout = gpr_time_from_millis(x, GPR_TIMESPAN); + break; + case 'S': + *timeout = gpr_time_from_seconds(x, GPR_TIMESPAN); + break; + case 'M': + *timeout = gpr_time_from_minutes(x, GPR_TIMESPAN); + break; + case 'H': + *timeout = gpr_time_from_hours(x, GPR_TIMESPAN); + break; + default: + return 0; + } + p++; + return is_all_whitespace((const char *)p); +} diff --git a/src/core/lib/transport/chttp2/timeout_encoding.h b/src/core/lib/transport/chttp2/timeout_encoding.h new file mode 100644 index 0000000000..f8e25226eb --- /dev/null +++ b/src/core/lib/transport/chttp2/timeout_encoding.h @@ -0,0 +1,47 @@ +/* + * + * Copyright 2015-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_TRANSPORT_CHTTP2_TIMEOUT_ENCODING_H +#define GRPC_CORE_TRANSPORT_CHTTP2_TIMEOUT_ENCODING_H + +#include +#include "src/core/support/string.h" + +#define GRPC_CHTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE (GPR_LTOA_MIN_BUFSIZE + 1) + +/* Encode/decode timeouts to the GRPC over HTTP2 format; + encoding may round up arbitrarily */ +void grpc_chttp2_encode_timeout(gpr_timespec timeout, char *buffer); +int grpc_chttp2_decode_timeout(const char *buffer, gpr_timespec *timeout); + +#endif /* GRPC_CORE_TRANSPORT_CHTTP2_TIMEOUT_ENCODING_H */ diff --git a/src/core/lib/transport/chttp2/varint.c b/src/core/lib/transport/chttp2/varint.c new file mode 100644 index 0000000000..1cc235e989 --- /dev/null +++ b/src/core/lib/transport/chttp2/varint.c @@ -0,0 +1,65 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/transport/chttp2/varint.h" + +uint32_t grpc_chttp2_hpack_varint_length(uint32_t tail_value) { + if (tail_value < (1 << 7)) { + return 2; + } else if (tail_value < (1 << 14)) { + return 3; + } else if (tail_value < (1 << 21)) { + return 4; + } else if (tail_value < (1 << 28)) { + return 5; + } else { + return 6; + } +} + +void grpc_chttp2_hpack_write_varint_tail(uint32_t tail_value, uint8_t* target, + uint32_t tail_length) { + switch (tail_length) { + case 5: + target[4] = (uint8_t)((tail_value >> 28) | 0x80); + case 4: + target[3] = (uint8_t)((tail_value >> 21) | 0x80); + case 3: + target[2] = (uint8_t)((tail_value >> 14) | 0x80); + case 2: + target[1] = (uint8_t)((tail_value >> 7) | 0x80); + case 1: + target[0] = (uint8_t)((tail_value) | 0x80); + } + target[tail_length - 1] &= 0x7f; +} diff --git a/src/core/lib/transport/chttp2/varint.h b/src/core/lib/transport/chttp2/varint.h new file mode 100644 index 0000000000..7ab9d22ab5 --- /dev/null +++ b/src/core/lib/transport/chttp2/varint.h @@ -0,0 +1,75 @@ +/* + * + * Copyright 2015-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_TRANSPORT_CHTTP2_VARINT_H +#define GRPC_CORE_TRANSPORT_CHTTP2_VARINT_H + +#include + +/* Helpers for hpack varint encoding */ + +/* length of a value that needs varint tail encoding (it's bigger than can be + bitpacked into the opcode byte) - returned value includes the length of the + opcode byte */ +uint32_t grpc_chttp2_hpack_varint_length(uint32_t tail_value); + +void grpc_chttp2_hpack_write_varint_tail(uint32_t tail_value, uint8_t* target, + uint32_t tail_length); + +/* maximum value that can be bitpacked with the opcode if the opcode has a + prefix + of length prefix_bits */ +#define GRPC_CHTTP2_MAX_IN_PREFIX(prefix_bits) \ + ((uint32_t)((1 << (8 - (prefix_bits))) - 1)) + +/* length required to bitpack a value */ +#define GRPC_CHTTP2_VARINT_LENGTH(n, prefix_bits) \ + ((n) < GRPC_CHTTP2_MAX_IN_PREFIX(prefix_bits) \ + ? 1u \ + : grpc_chttp2_hpack_varint_length( \ + (n)-GRPC_CHTTP2_MAX_IN_PREFIX(prefix_bits))) + +#define GRPC_CHTTP2_WRITE_VARINT(n, prefix_bits, prefix_or, target, length) \ + do { \ + uint8_t* tgt = target; \ + if ((length) == 1u) { \ + (tgt)[0] = (uint8_t)((prefix_or) | (n)); \ + } else { \ + (tgt)[0] = \ + (prefix_or) | (uint8_t)GRPC_CHTTP2_MAX_IN_PREFIX(prefix_bits); \ + grpc_chttp2_hpack_write_varint_tail( \ + (n)-GRPC_CHTTP2_MAX_IN_PREFIX(prefix_bits), (tgt) + 1, (length)-1); \ + } \ + } while (0) + +#endif /* GRPC_CORE_TRANSPORT_CHTTP2_VARINT_H */ diff --git a/src/core/lib/transport/chttp2/writing.c b/src/core/lib/transport/chttp2/writing.c new file mode 100644 index 0000000000..107725cbc7 --- /dev/null +++ b/src/core/lib/transport/chttp2/writing.c @@ -0,0 +1,350 @@ +/* + * + * Copyright 2015-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/transport/chttp2/internal.h" + +#include + +#include + +#include "src/core/profiling/timers.h" +#include "src/core/transport/chttp2/http2_errors.h" + +static void finalize_outbuf(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport_writing *transport_writing); + +int grpc_chttp2_unlocking_check_writes( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, + grpc_chttp2_transport_writing *transport_writing, int is_parsing) { + grpc_chttp2_stream_global *stream_global; + grpc_chttp2_stream_writing *stream_writing; + + GPR_TIMER_BEGIN("grpc_chttp2_unlocking_check_writes", 0); + + /* simple writes are queued to qbuf, and flushed here */ + gpr_slice_buffer_swap(&transport_global->qbuf, &transport_writing->outbuf); + GPR_ASSERT(transport_global->qbuf.count == 0); + + grpc_chttp2_hpack_compressor_set_max_table_size( + &transport_writing->hpack_compressor, + transport_global->settings[GRPC_PEER_SETTINGS] + [GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE]); + + if (transport_global->dirtied_local_settings && + !transport_global->sent_local_settings && !is_parsing) { + gpr_slice_buffer_add( + &transport_writing->outbuf, + grpc_chttp2_settings_create( + transport_global->settings[GRPC_SENT_SETTINGS], + transport_global->settings[GRPC_LOCAL_SETTINGS], + transport_global->force_send_settings, GRPC_CHTTP2_NUM_SETTINGS)); + transport_global->force_send_settings = 0; + transport_global->dirtied_local_settings = 0; + transport_global->sent_local_settings = 1; + } + + GRPC_CHTTP2_FLOW_MOVE_TRANSPORT("write", transport_writing, outgoing_window, + transport_global, outgoing_window); + bool is_window_available = transport_writing->outgoing_window > 0; + grpc_chttp2_list_flush_writing_stalled_by_transport( + exec_ctx, transport_writing, is_window_available); + + /* for each grpc_chttp2_stream that's become writable, frame it's data + (according to available window sizes) and add to the output buffer */ + while (grpc_chttp2_list_pop_writable_stream( + transport_global, transport_writing, &stream_global, &stream_writing)) { + bool sent_initial_metadata = stream_writing->sent_initial_metadata; + bool become_writable = false; + + stream_writing->id = stream_global->id; + stream_writing->read_closed = stream_global->read_closed; + + GRPC_CHTTP2_FLOW_MOVE_STREAM("write", transport_writing, stream_writing, + outgoing_window, stream_global, + outgoing_window); + + if (!sent_initial_metadata && stream_global->send_initial_metadata) { + stream_writing->send_initial_metadata = + stream_global->send_initial_metadata; + stream_global->send_initial_metadata = NULL; + become_writable = true; + sent_initial_metadata = true; + } + if (sent_initial_metadata) { + if (stream_global->send_message != NULL) { + gpr_slice hdr = gpr_slice_malloc(5); + uint8_t *p = GPR_SLICE_START_PTR(hdr); + uint32_t len = stream_global->send_message->length; + GPR_ASSERT(stream_writing->send_message == NULL); + p[0] = (stream_global->send_message->flags & + GRPC_WRITE_INTERNAL_COMPRESS) != 0; + p[1] = (uint8_t)(len >> 24); + p[2] = (uint8_t)(len >> 16); + p[3] = (uint8_t)(len >> 8); + p[4] = (uint8_t)(len); + gpr_slice_buffer_add(&stream_writing->flow_controlled_buffer, hdr); + if (stream_global->send_message->length > 0) { + stream_writing->send_message = stream_global->send_message; + } else { + stream_writing->send_message = NULL; + } + stream_writing->stream_fetched = 0; + stream_global->send_message = NULL; + } + if ((stream_writing->send_message != NULL || + stream_writing->flow_controlled_buffer.length > 0) && + stream_writing->outgoing_window > 0) { + if (transport_writing->outgoing_window > 0) { + become_writable = true; + } else { + grpc_chttp2_list_add_stalled_by_transport(transport_writing, + stream_writing); + } + } + if (stream_global->send_trailing_metadata) { + stream_writing->send_trailing_metadata = + stream_global->send_trailing_metadata; + stream_global->send_trailing_metadata = NULL; + become_writable = true; + } + } + + if (!stream_global->read_closed && + stream_global->unannounced_incoming_window_for_writing > 1024) { + GRPC_CHTTP2_FLOW_MOVE_STREAM("write", transport_global, stream_writing, + announce_window, stream_global, + unannounced_incoming_window_for_writing); + become_writable = true; + } + + if (become_writable) { + grpc_chttp2_list_add_writing_stream(transport_writing, stream_writing); + } else { + GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2_writing"); + } + } + + /* if the grpc_chttp2_transport is ready to send a window update, do so here + also; 3/4 is a magic number that will likely get tuned soon */ + if (transport_global->announce_incoming_window > 0) { + uint32_t announced = (uint32_t)GPR_MIN( + transport_global->announce_incoming_window, UINT32_MAX); + GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("write", transport_global, + announce_incoming_window, announced); + gpr_slice_buffer_add(&transport_writing->outbuf, + grpc_chttp2_window_update_create(0, announced)); + } + + GPR_TIMER_END("grpc_chttp2_unlocking_check_writes", 0); + + return transport_writing->outbuf.count > 0 || + grpc_chttp2_list_have_writing_streams(transport_writing); +} + +void grpc_chttp2_perform_writes( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing, + grpc_endpoint *endpoint) { + GPR_ASSERT(transport_writing->outbuf.count > 0 || + grpc_chttp2_list_have_writing_streams(transport_writing)); + + finalize_outbuf(exec_ctx, transport_writing); + + GPR_ASSERT(endpoint); + + if (transport_writing->outbuf.count > 0) { + grpc_endpoint_write(exec_ctx, endpoint, &transport_writing->outbuf, + &transport_writing->done_cb); + } else { + grpc_exec_ctx_enqueue(exec_ctx, &transport_writing->done_cb, true, NULL); + } +} + +static void finalize_outbuf(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport_writing *transport_writing) { + grpc_chttp2_stream_writing *stream_writing; + + GPR_TIMER_BEGIN("finalize_outbuf", 0); + + while ( + grpc_chttp2_list_pop_writing_stream(transport_writing, &stream_writing)) { + uint32_t max_outgoing = + (uint32_t)GPR_MIN(GRPC_CHTTP2_MAX_PAYLOAD_LENGTH, + GPR_MIN(stream_writing->outgoing_window, + transport_writing->outgoing_window)); + /* send initial metadata if it's available */ + if (stream_writing->send_initial_metadata != NULL) { + grpc_chttp2_encode_header( + &transport_writing->hpack_compressor, stream_writing->id, + stream_writing->send_initial_metadata, 0, &transport_writing->outbuf); + stream_writing->send_initial_metadata = NULL; + stream_writing->sent_initial_metadata = 1; + } + /* send any window updates */ + if (stream_writing->announce_window > 0 && + stream_writing->send_initial_metadata == NULL) { + uint32_t announce = stream_writing->announce_window; + gpr_slice_buffer_add( + &transport_writing->outbuf, + grpc_chttp2_window_update_create(stream_writing->id, + stream_writing->announce_window)); + GRPC_CHTTP2_FLOW_DEBIT_STREAM("write", transport_writing, stream_writing, + announce_window, announce); + stream_writing->announce_window = 0; + } + /* fetch any body bytes */ + while (!stream_writing->fetching && stream_writing->send_message && + stream_writing->flow_controlled_buffer.length < max_outgoing && + stream_writing->stream_fetched < + stream_writing->send_message->length) { + if (grpc_byte_stream_next(exec_ctx, stream_writing->send_message, + &stream_writing->fetching_slice, max_outgoing, + &stream_writing->finished_fetch)) { + stream_writing->stream_fetched += + GPR_SLICE_LENGTH(stream_writing->fetching_slice); + if (stream_writing->stream_fetched == + stream_writing->send_message->length) { + stream_writing->send_message = NULL; + } + gpr_slice_buffer_add(&stream_writing->flow_controlled_buffer, + stream_writing->fetching_slice); + } else { + stream_writing->fetching = 1; + } + } + /* send any body bytes */ + if (stream_writing->flow_controlled_buffer.length > 0) { + if (max_outgoing > 0) { + uint32_t send_bytes = (uint32_t)GPR_MIN( + max_outgoing, stream_writing->flow_controlled_buffer.length); + int is_last_data_frame = + stream_writing->send_message == NULL && + send_bytes == stream_writing->flow_controlled_buffer.length; + int is_last_frame = is_last_data_frame && + stream_writing->send_trailing_metadata != NULL && + grpc_metadata_batch_is_empty( + stream_writing->send_trailing_metadata); + grpc_chttp2_encode_data( + stream_writing->id, &stream_writing->flow_controlled_buffer, + send_bytes, is_last_frame, &transport_writing->outbuf); + GRPC_CHTTP2_FLOW_DEBIT_STREAM("write", transport_writing, + stream_writing, outgoing_window, + send_bytes); + GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("write", transport_writing, + outgoing_window, send_bytes); + if (is_last_frame) { + stream_writing->send_trailing_metadata = NULL; + stream_writing->sent_trailing_metadata = 1; + } + if (is_last_data_frame) { + GPR_ASSERT(stream_writing->send_message == NULL); + stream_writing->sent_message = 1; + } + } else if (transport_writing->outgoing_window == 0) { + grpc_chttp2_list_add_writing_stalled_by_transport(transport_writing, + stream_writing); + grpc_chttp2_list_add_written_stream(transport_writing, stream_writing); + } + } + /* send trailing metadata if it's available and we're ready for it */ + if (stream_writing->send_message == NULL && + stream_writing->flow_controlled_buffer.length == 0 && + stream_writing->send_trailing_metadata != NULL) { + if (grpc_metadata_batch_is_empty( + stream_writing->send_trailing_metadata)) { + grpc_chttp2_encode_data(stream_writing->id, + &stream_writing->flow_controlled_buffer, 0, 1, + &transport_writing->outbuf); + } else { + grpc_chttp2_encode_header(&transport_writing->hpack_compressor, + stream_writing->id, + stream_writing->send_trailing_metadata, 1, + &transport_writing->outbuf); + } + if (!transport_writing->is_client && !stream_writing->read_closed) { + gpr_slice_buffer_add(&transport_writing->outbuf, + grpc_chttp2_rst_stream_create( + stream_writing->id, GRPC_CHTTP2_NO_ERROR)); + } + stream_writing->send_trailing_metadata = NULL; + stream_writing->sent_trailing_metadata = 1; + } + /* if there's more to write, then loop, otherwise prepare to finish the + * write */ + if ((stream_writing->flow_controlled_buffer.length > 0 || + (stream_writing->send_message && !stream_writing->fetching)) && + stream_writing->outgoing_window > 0) { + if (transport_writing->outgoing_window > 0) { + grpc_chttp2_list_add_writing_stream(transport_writing, stream_writing); + } else { + grpc_chttp2_list_add_writing_stalled_by_transport(transport_writing, + stream_writing); + grpc_chttp2_list_add_written_stream(transport_writing, stream_writing); + } + } else { + grpc_chttp2_list_add_written_stream(transport_writing, stream_writing); + } + } + + GPR_TIMER_END("finalize_outbuf", 0); +} + +void grpc_chttp2_cleanup_writing( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, + grpc_chttp2_transport_writing *transport_writing) { + grpc_chttp2_stream_writing *stream_writing; + grpc_chttp2_stream_global *stream_global; + + while (grpc_chttp2_list_pop_written_stream( + transport_global, transport_writing, &stream_global, &stream_writing)) { + if (stream_writing->sent_initial_metadata) { + grpc_chttp2_complete_closure_step( + exec_ctx, &stream_global->send_initial_metadata_finished, 1); + } + if (stream_writing->sent_message) { + GPR_ASSERT(stream_writing->send_message == NULL); + grpc_chttp2_complete_closure_step( + exec_ctx, &stream_global->send_message_finished, 1); + stream_writing->sent_message = 0; + } + if (stream_writing->sent_trailing_metadata) { + grpc_chttp2_complete_closure_step( + exec_ctx, &stream_global->send_trailing_metadata_finished, 1); + } + if (stream_writing->sent_trailing_metadata) { + grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, + !transport_global->is_client, 1); + } + GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2_writing"); + } + gpr_slice_buffer_reset_and_unref(&transport_writing->outbuf); +} diff --git a/src/core/lib/transport/chttp2_transport.c b/src/core/lib/transport/chttp2_transport.c new file mode 100644 index 0000000000..b45bf31997 --- /dev/null +++ b/src/core/lib/transport/chttp2_transport.c @@ -0,0 +1,1785 @@ +/* + * + * Copyright 2015-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/transport/chttp2_transport.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "src/core/profiling/timers.h" +#include "src/core/support/string.h" +#include "src/core/transport/chttp2/http2_errors.h" +#include "src/core/transport/chttp2/internal.h" +#include "src/core/transport/chttp2/status_conversion.h" +#include "src/core/transport/chttp2/timeout_encoding.h" +#include "src/core/transport/static_metadata.h" +#include "src/core/transport/transport_impl.h" + +#define DEFAULT_WINDOW 65535 +#define DEFAULT_CONNECTION_WINDOW_TARGET (1024 * 1024) +#define MAX_WINDOW 0x7fffffffu + +#define MAX_CLIENT_STREAM_ID 0x7fffffffu + +int grpc_http_trace = 0; +int grpc_flowctl_trace = 0; + +#define TRANSPORT_FROM_WRITING(tw) \ + ((grpc_chttp2_transport *)((char *)(tw)-offsetof(grpc_chttp2_transport, \ + writing))) + +#define TRANSPORT_FROM_PARSING(tw) \ + ((grpc_chttp2_transport *)((char *)(tw)-offsetof(grpc_chttp2_transport, \ + parsing))) + +#define TRANSPORT_FROM_GLOBAL(tg) \ + ((grpc_chttp2_transport *)((char *)(tg)-offsetof(grpc_chttp2_transport, \ + global))) + +#define STREAM_FROM_GLOBAL(sg) \ + ((grpc_chttp2_stream *)((char *)(sg)-offsetof(grpc_chttp2_stream, global))) + +#define STREAM_FROM_PARSING(sg) \ + ((grpc_chttp2_stream *)((char *)(sg)-offsetof(grpc_chttp2_stream, parsing))) + +static const grpc_transport_vtable vtable; + +static void lock(grpc_chttp2_transport *t); +static void unlock(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t); + +/* forward declarations of various callbacks that we'll build closures around */ +static void writing_action(grpc_exec_ctx *exec_ctx, void *t, + bool iomgr_success_ignored); + +/** Set a transport level setting, and push it to our peer */ +static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id, + uint32_t value); + +/** Endpoint callback to process incoming data */ +static void recv_data(grpc_exec_ctx *exec_ctx, void *tp, bool success); + +/** Start disconnection chain */ +static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t); + +/** Perform a transport_op */ +static void perform_stream_op_locked( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global *stream_global, grpc_transport_stream_op *op); + +/** Cancel a stream: coming from the transport API */ +static void cancel_from_api(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global *stream_global, + grpc_status_code status); + +static void close_from_api(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global *stream_global, + grpc_status_code status, + gpr_slice *optional_message); + +/** Add endpoint from this transport to pollset */ +static void add_to_pollset_locked(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + grpc_pollset *pollset); +static void add_to_pollset_set_locked(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + grpc_pollset_set *pollset_set); + +/** Start new streams that have been created if we can */ +static void maybe_start_some_streams( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global); + +static void connectivity_state_set( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, + grpc_connectivity_state state, const char *reason); + +static void check_read_ops(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport_global *transport_global); + +static void incoming_byte_stream_update_flow_control( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global *stream_global, size_t max_size_hint, + size_t have_already); + +static void fail_pending_writes(grpc_exec_ctx *exec_ctx, + grpc_chttp2_stream_global *stream_global); + +/******************************************************************************* + * CONSTRUCTION/DESTRUCTION/REFCOUNTING + */ + +static void destruct_transport(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t) { + size_t i; + + gpr_mu_lock(&t->mu); + + GPR_ASSERT(t->ep == NULL); + + gpr_slice_buffer_destroy(&t->global.qbuf); + + gpr_slice_buffer_destroy(&t->writing.outbuf); + grpc_chttp2_hpack_compressor_destroy(&t->writing.hpack_compressor); + + gpr_slice_buffer_destroy(&t->parsing.qbuf); + gpr_slice_buffer_destroy(&t->read_buffer); + grpc_chttp2_hpack_parser_destroy(&t->parsing.hpack_parser); + grpc_chttp2_goaway_parser_destroy(&t->parsing.goaway_parser); + + for (i = 0; i < STREAM_LIST_COUNT; i++) { + GPR_ASSERT(t->lists[i].head == NULL); + GPR_ASSERT(t->lists[i].tail == NULL); + } + + GPR_ASSERT(grpc_chttp2_stream_map_size(&t->parsing_stream_map) == 0); + GPR_ASSERT(grpc_chttp2_stream_map_size(&t->new_stream_map) == 0); + + grpc_chttp2_stream_map_destroy(&t->parsing_stream_map); + grpc_chttp2_stream_map_destroy(&t->new_stream_map); + grpc_connectivity_state_destroy(exec_ctx, &t->channel_callback.state_tracker); + + gpr_mu_unlock(&t->mu); + gpr_mu_destroy(&t->mu); + + /* callback remaining pings: they're not allowed to call into the transpot, + and maybe they hold resources that need to be freed */ + while (t->global.pings.next != &t->global.pings) { + grpc_chttp2_outstanding_ping *ping = t->global.pings.next; + grpc_exec_ctx_enqueue(exec_ctx, ping->on_recv, false, NULL); + ping->next->prev = ping->prev; + ping->prev->next = ping->next; + gpr_free(ping); + } + + gpr_free(t->peer_string); + gpr_free(t); +} + +#ifdef REFCOUNTING_DEBUG +#define REF_TRANSPORT(t, r) ref_transport(t, r, __FILE__, __LINE__) +#define UNREF_TRANSPORT(cl, t, r) unref_transport(cl, t, r, __FILE__, __LINE__) +static void unref_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, + const char *reason, const char *file, int line) { + gpr_log(GPR_DEBUG, "chttp2:unref:%p %d->%d %s [%s:%d]", t, t->refs.count, + t->refs.count - 1, reason, file, line); + if (!gpr_unref(&t->refs)) return; + destruct_transport(exec_ctx, t); +} + +static void ref_transport(grpc_chttp2_transport *t, const char *reason, + const char *file, int line) { + gpr_log(GPR_DEBUG, "chttp2: ref:%p %d->%d %s [%s:%d]", t, t->refs.count, + t->refs.count + 1, reason, file, line); + gpr_ref(&t->refs); +} +#else +#define REF_TRANSPORT(t, r) ref_transport(t) +#define UNREF_TRANSPORT(cl, t, r) unref_transport(cl, t) +static void unref_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) { + if (!gpr_unref(&t->refs)) return; + destruct_transport(exec_ctx, t); +} + +static void ref_transport(grpc_chttp2_transport *t) { gpr_ref(&t->refs); } +#endif + +static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, + const grpc_channel_args *channel_args, + grpc_endpoint *ep, uint8_t is_client) { + size_t i; + int j; + + GPR_ASSERT(strlen(GRPC_CHTTP2_CLIENT_CONNECT_STRING) == + GRPC_CHTTP2_CLIENT_CONNECT_STRLEN); + + memset(t, 0, sizeof(*t)); + + t->base.vtable = &vtable; + t->ep = ep; + /* one ref is for destroy, the other for when ep becomes NULL */ + gpr_ref_init(&t->refs, 2); + /* ref is dropped at transport close() */ + gpr_ref_init(&t->shutdown_ep_refs, 1); + gpr_mu_init(&t->mu); + t->peer_string = grpc_endpoint_get_peer(ep); + t->endpoint_reading = 1; + t->global.next_stream_id = is_client ? 1 : 2; + t->global.is_client = is_client; + t->writing.outgoing_window = DEFAULT_WINDOW; + t->parsing.incoming_window = DEFAULT_WINDOW; + t->global.stream_lookahead = DEFAULT_WINDOW; + t->global.connection_window_target = DEFAULT_CONNECTION_WINDOW_TARGET; + t->global.ping_counter = 1; + t->global.pings.next = t->global.pings.prev = &t->global.pings; + t->parsing.is_client = is_client; + t->parsing.deframe_state = + is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0; + t->writing.is_client = is_client; + grpc_connectivity_state_init( + &t->channel_callback.state_tracker, GRPC_CHANNEL_READY, + is_client ? "client_transport" : "server_transport"); + + gpr_slice_buffer_init(&t->global.qbuf); + + gpr_slice_buffer_init(&t->writing.outbuf); + grpc_chttp2_hpack_compressor_init(&t->writing.hpack_compressor); + grpc_closure_init(&t->writing_action, writing_action, t); + + gpr_slice_buffer_init(&t->parsing.qbuf); + grpc_chttp2_goaway_parser_init(&t->parsing.goaway_parser); + grpc_chttp2_hpack_parser_init(&t->parsing.hpack_parser); + + grpc_closure_init(&t->writing.done_cb, grpc_chttp2_terminate_writing, + &t->writing); + grpc_closure_init(&t->recv_data, recv_data, t); + gpr_slice_buffer_init(&t->read_buffer); + + if (is_client) { + gpr_slice_buffer_add( + &t->global.qbuf, + gpr_slice_from_copied_string(GRPC_CHTTP2_CLIENT_CONNECT_STRING)); + } + /* 8 is a random stab in the dark as to a good initial size: it's small enough + that it shouldn't waste memory for infrequently used connections, yet + large enough that the exponential growth should happen nicely when it's + needed. + TODO(ctiller): tune this */ + grpc_chttp2_stream_map_init(&t->parsing_stream_map, 8); + grpc_chttp2_stream_map_init(&t->new_stream_map, 8); + + /* copy in initial settings to all setting sets */ + for (i = 0; i < GRPC_CHTTP2_NUM_SETTINGS; i++) { + t->parsing.settings[i] = grpc_chttp2_settings_parameters[i].default_value; + for (j = 0; j < GRPC_NUM_SETTING_SETS; j++) { + t->global.settings[j][i] = + grpc_chttp2_settings_parameters[i].default_value; + } + } + t->global.dirtied_local_settings = 1; + /* Hack: it's common for implementations to assume 65536 bytes initial send + window -- this should by rights be 0 */ + t->global.force_send_settings = 1 << GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; + t->global.sent_local_settings = 0; + + /* configure http2 the way we like it */ + if (is_client) { + push_setting(t, GRPC_CHTTP2_SETTINGS_ENABLE_PUSH, 0); + push_setting(t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 0); + } + push_setting(t, GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, DEFAULT_WINDOW); + + if (channel_args) { + for (i = 0; i < channel_args->num_args; i++) { + if (0 == + strcmp(channel_args->args[i].key, GRPC_ARG_MAX_CONCURRENT_STREAMS)) { + if (is_client) { + gpr_log(GPR_ERROR, "%s: is ignored on the client", + GRPC_ARG_MAX_CONCURRENT_STREAMS); + } else if (channel_args->args[i].type != GRPC_ARG_INTEGER) { + gpr_log(GPR_ERROR, "%s: must be an integer", + GRPC_ARG_MAX_CONCURRENT_STREAMS); + } else { + push_setting(t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, + (uint32_t)channel_args->args[i].value.integer); + } + } else if (0 == strcmp(channel_args->args[i].key, + GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER)) { + if (channel_args->args[i].type != GRPC_ARG_INTEGER) { + gpr_log(GPR_ERROR, "%s: must be an integer", + GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER); + } else if ((t->global.next_stream_id & 1) != + (channel_args->args[i].value.integer & 1)) { + gpr_log(GPR_ERROR, "%s: low bit must be %d on %s", + GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER, + t->global.next_stream_id & 1, + is_client ? "client" : "server"); + } else { + t->global.next_stream_id = + (uint32_t)channel_args->args[i].value.integer; + } + } else if (0 == strcmp(channel_args->args[i].key, + GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES)) { + if (channel_args->args[i].type != GRPC_ARG_INTEGER) { + gpr_log(GPR_ERROR, "%s: must be an integer", + GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES); + } else if (channel_args->args[i].value.integer <= 5) { + gpr_log(GPR_ERROR, "%s: must be at least 5", + GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES); + } else { + t->global.stream_lookahead = + (uint32_t)channel_args->args[i].value.integer; + } + } else if (0 == strcmp(channel_args->args[i].key, + GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER)) { + if (channel_args->args[i].type != GRPC_ARG_INTEGER) { + gpr_log(GPR_ERROR, "%s: must be an integer", + GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER); + } else if (channel_args->args[i].value.integer < 0) { + gpr_log(GPR_ERROR, "%s: must be non-negative", + GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER); + } else { + push_setting(t, GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE, + (uint32_t)channel_args->args[i].value.integer); + } + } else if (0 == strcmp(channel_args->args[i].key, + GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER)) { + if (channel_args->args[i].type != GRPC_ARG_INTEGER) { + gpr_log(GPR_ERROR, "%s: must be an integer", + GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER); + } else if (channel_args->args[i].value.integer < 0) { + gpr_log(GPR_ERROR, "%s: must be non-negative", + GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER); + } else { + grpc_chttp2_hpack_compressor_set_max_usable_size( + &t->writing.hpack_compressor, + (uint32_t)channel_args->args[i].value.integer); + } + } + } + } +} + +static void destroy_transport(grpc_exec_ctx *exec_ctx, grpc_transport *gt) { + grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; + + lock(t); + t->destroying = 1; + drop_connection(exec_ctx, t); + unlock(exec_ctx, t); + + UNREF_TRANSPORT(exec_ctx, t, "destroy"); +} + +/** block grpc_endpoint_shutdown being called until a paired + allow_endpoint_shutdown is made */ +static void prevent_endpoint_shutdown(grpc_chttp2_transport *t) { + GPR_ASSERT(t->ep); + gpr_ref(&t->shutdown_ep_refs); +} + +static void allow_endpoint_shutdown_locked(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t) { + if (gpr_unref(&t->shutdown_ep_refs)) { + if (t->ep) { + grpc_endpoint_shutdown(exec_ctx, t->ep); + } + } +} + +static void allow_endpoint_shutdown_unlocked(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t) { + if (gpr_unref(&t->shutdown_ep_refs)) { + gpr_mu_lock(&t->mu); + if (t->ep) { + grpc_endpoint_shutdown(exec_ctx, t->ep); + } + gpr_mu_unlock(&t->mu); + } +} + +static void destroy_endpoint(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t) { + grpc_endpoint_destroy(exec_ctx, t->ep); + t->ep = NULL; + /* safe because we'll still have the ref for write */ + UNREF_TRANSPORT(exec_ctx, t, "disconnect"); +} + +static void close_transport_locked(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t) { + if (!t->closed) { + t->closed = 1; + connectivity_state_set(exec_ctx, &t->global, GRPC_CHANNEL_FATAL_FAILURE, + "close_transport"); + if (t->ep) { + allow_endpoint_shutdown_locked(exec_ctx, t); + } + + /* flush writable stream list to avoid dangling references */ + grpc_chttp2_stream_global *stream_global; + grpc_chttp2_stream_writing *stream_writing; + while (grpc_chttp2_list_pop_writable_stream( + &t->global, &t->writing, &stream_global, &stream_writing)) { + GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2_writing"); + } + } +} + +#ifdef GRPC_STREAM_REFCOUNT_DEBUG +void grpc_chttp2_stream_ref(grpc_chttp2_stream_global *stream_global, + const char *reason) { + grpc_stream_ref(STREAM_FROM_GLOBAL(stream_global)->refcount, reason); +} +void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx, + grpc_chttp2_stream_global *stream_global, + const char *reason) { + grpc_stream_unref(exec_ctx, STREAM_FROM_GLOBAL(stream_global)->refcount, + reason); +} +#else +void grpc_chttp2_stream_ref(grpc_chttp2_stream_global *stream_global) { + grpc_stream_ref(STREAM_FROM_GLOBAL(stream_global)->refcount); +} +void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx, + grpc_chttp2_stream_global *stream_global) { + grpc_stream_unref(exec_ctx, STREAM_FROM_GLOBAL(stream_global)->refcount); +} +#endif + +static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, + grpc_stream *gs, grpc_stream_refcount *refcount, + const void *server_data) { + grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; + grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs; + + memset(s, 0, sizeof(*s)); + + s->refcount = refcount; + GRPC_CHTTP2_STREAM_REF(&s->global, "chttp2"); + + grpc_chttp2_incoming_metadata_buffer_init(&s->parsing.metadata_buffer[0]); + grpc_chttp2_incoming_metadata_buffer_init(&s->parsing.metadata_buffer[1]); + grpc_chttp2_incoming_metadata_buffer_init( + &s->global.received_initial_metadata); + grpc_chttp2_incoming_metadata_buffer_init( + &s->global.received_trailing_metadata); + grpc_chttp2_data_parser_init(&s->parsing.data_parser); + gpr_slice_buffer_init(&s->writing.flow_controlled_buffer); + + REF_TRANSPORT(t, "stream"); + + lock(t); + grpc_chttp2_register_stream(t, s); + if (server_data) { + GPR_ASSERT(t->parsing_active); + s->global.id = (uint32_t)(uintptr_t)server_data; + s->parsing.id = s->global.id; + s->global.outgoing_window = + t->global.settings[GRPC_PEER_SETTINGS] + [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; + s->parsing.incoming_window = s->global.max_recv_bytes = + t->global.settings[GRPC_SENT_SETTINGS] + [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; + *t->accepting_stream = s; + grpc_chttp2_stream_map_add(&t->parsing_stream_map, s->global.id, s); + s->global.in_stream_map = 1; + } + unlock(exec_ctx, t); + + return 0; +} + +static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, + grpc_stream *gs) { + grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; + grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs; + int i; + grpc_byte_stream *bs; + + GPR_TIMER_BEGIN("destroy_stream", 0); + + gpr_mu_lock(&t->mu); + + GPR_ASSERT((s->global.write_closed && s->global.read_closed) || + s->global.id == 0); + GPR_ASSERT(!s->global.in_stream_map); + if (grpc_chttp2_unregister_stream(t, s) && t->global.sent_goaway) { + close_transport_locked(exec_ctx, t); + } + if (!t->parsing_active && s->global.id) { + GPR_ASSERT(grpc_chttp2_stream_map_find(&t->parsing_stream_map, + s->global.id) == NULL); + } + + grpc_chttp2_list_remove_unannounced_incoming_window_available(&t->global, + &s->global); + grpc_chttp2_list_remove_stalled_by_transport(&t->global, &s->global); + + gpr_mu_unlock(&t->mu); + + for (i = 0; i < STREAM_LIST_COUNT; i++) { + if (s->included[i]) { + gpr_log(GPR_ERROR, "%s stream %d still included in list %d", + t->global.is_client ? "client" : "server", s->global.id, i); + abort(); + } + } + + while ( + (bs = grpc_chttp2_incoming_frame_queue_pop(&s->global.incoming_frames))) { + grpc_byte_stream_destroy(exec_ctx, bs); + } + + GPR_ASSERT(s->global.send_initial_metadata_finished == NULL); + GPR_ASSERT(s->global.send_message_finished == NULL); + GPR_ASSERT(s->global.send_trailing_metadata_finished == NULL); + GPR_ASSERT(s->global.recv_initial_metadata_ready == NULL); + GPR_ASSERT(s->global.recv_message_ready == NULL); + GPR_ASSERT(s->global.recv_trailing_metadata_finished == NULL); + grpc_chttp2_data_parser_destroy(exec_ctx, &s->parsing.data_parser); + grpc_chttp2_incoming_metadata_buffer_destroy(&s->parsing.metadata_buffer[0]); + grpc_chttp2_incoming_metadata_buffer_destroy(&s->parsing.metadata_buffer[1]); + grpc_chttp2_incoming_metadata_buffer_destroy( + &s->global.received_initial_metadata); + grpc_chttp2_incoming_metadata_buffer_destroy( + &s->global.received_trailing_metadata); + gpr_slice_buffer_destroy(&s->writing.flow_controlled_buffer); + + UNREF_TRANSPORT(exec_ctx, t, "stream"); + + GPR_TIMER_END("destroy_stream", 0); +} + +grpc_chttp2_stream_parsing *grpc_chttp2_parsing_lookup_stream( + grpc_chttp2_transport_parsing *transport_parsing, uint32_t id) { + grpc_chttp2_transport *t = TRANSPORT_FROM_PARSING(transport_parsing); + grpc_chttp2_stream *s = + grpc_chttp2_stream_map_find(&t->parsing_stream_map, id); + return s ? &s->parsing : NULL; +} + +grpc_chttp2_stream_parsing *grpc_chttp2_parsing_accept_stream( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, + uint32_t id) { + grpc_chttp2_stream *accepting; + grpc_chttp2_transport *t = TRANSPORT_FROM_PARSING(transport_parsing); + GPR_ASSERT(t->accepting_stream == NULL); + t->accepting_stream = &accepting; + t->channel_callback.accept_stream(exec_ctx, + t->channel_callback.accept_stream_user_data, + &t->base, (void *)(uintptr_t)id); + t->accepting_stream = NULL; + return &accepting->parsing; +} + +/******************************************************************************* + * LOCK MANAGEMENT + */ + +/* We take a grpc_chttp2_transport-global lock in response to calls coming in + from above, + and in response to data being received from below. New data to be written + is always queued, as are callbacks to process data. During unlock() we + check our todo lists and initiate callbacks and flush writes. */ + +static void lock(grpc_chttp2_transport *t) { gpr_mu_lock(&t->mu); } + +static void unlock(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) { + GPR_TIMER_BEGIN("unlock", 0); + if (!t->writing_active && !t->closed && + grpc_chttp2_unlocking_check_writes(exec_ctx, &t->global, &t->writing, + t->parsing_active)) { + t->writing_active = 1; + REF_TRANSPORT(t, "writing"); + grpc_exec_ctx_enqueue(exec_ctx, &t->writing_action, true, NULL); + prevent_endpoint_shutdown(t); + } + check_read_ops(exec_ctx, &t->global); + + gpr_mu_unlock(&t->mu); + GPR_TIMER_END("unlock", 0); +} + +/******************************************************************************* + * OUTPUT PROCESSING + */ + +void grpc_chttp2_become_writable(grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global *stream_global) { + if (!TRANSPORT_FROM_GLOBAL(transport_global)->closed && + grpc_chttp2_list_add_writable_stream(transport_global, stream_global)) { + GRPC_CHTTP2_STREAM_REF(stream_global, "chttp2_writing"); + } +} + +static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id, + uint32_t value) { + const grpc_chttp2_setting_parameters *sp = + &grpc_chttp2_settings_parameters[id]; + uint32_t use_value = GPR_CLAMP(value, sp->min_value, sp->max_value); + if (use_value != value) { + gpr_log(GPR_INFO, "Requested parameter %s clamped from %d to %d", sp->name, + value, use_value); + } + if (use_value != t->global.settings[GRPC_LOCAL_SETTINGS][id]) { + t->global.settings[GRPC_LOCAL_SETTINGS][id] = use_value; + t->global.dirtied_local_settings = 1; + } +} + +void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx, + void *transport_writing_ptr, bool success) { + grpc_chttp2_transport_writing *transport_writing = transport_writing_ptr; + grpc_chttp2_transport *t = TRANSPORT_FROM_WRITING(transport_writing); + grpc_chttp2_stream_global *stream_global; + + GPR_TIMER_BEGIN("grpc_chttp2_terminate_writing", 0); + + lock(t); + + allow_endpoint_shutdown_locked(exec_ctx, t); + + if (!success) { + drop_connection(exec_ctx, t); + } + + grpc_chttp2_cleanup_writing(exec_ctx, &t->global, &t->writing); + + while (grpc_chttp2_list_pop_closed_waiting_for_writing(&t->global, + &stream_global)) { + fail_pending_writes(exec_ctx, stream_global); + GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "finish_writes"); + } + + /* leave the writing flag up on shutdown to prevent further writes in unlock() + from starting */ + t->writing_active = 0; + if (t->ep && !t->endpoint_reading) { + destroy_endpoint(exec_ctx, t); + } + + unlock(exec_ctx, t); + + UNREF_TRANSPORT(exec_ctx, t, "writing"); + + GPR_TIMER_END("grpc_chttp2_terminate_writing", 0); +} + +static void writing_action(grpc_exec_ctx *exec_ctx, void *gt, + bool iomgr_success_ignored) { + grpc_chttp2_transport *t = gt; + GPR_TIMER_BEGIN("writing_action", 0); + grpc_chttp2_perform_writes(exec_ctx, &t->writing, t->ep); + GPR_TIMER_END("writing_action", 0); +} + +void grpc_chttp2_add_incoming_goaway( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, + uint32_t goaway_error, gpr_slice goaway_text) { + char *msg = gpr_dump_slice(goaway_text, GPR_DUMP_HEX | GPR_DUMP_ASCII); + gpr_log(GPR_DEBUG, "got goaway [%d]: %s", goaway_error, msg); + gpr_free(msg); + gpr_slice_unref(goaway_text); + transport_global->seen_goaway = 1; + connectivity_state_set(exec_ctx, transport_global, GRPC_CHANNEL_FATAL_FAILURE, + "got_goaway"); +} + +static void maybe_start_some_streams( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global) { + grpc_chttp2_stream_global *stream_global; + uint32_t stream_incoming_window; + /* start streams where we have free grpc_chttp2_stream ids and free + * concurrency */ + while (transport_global->next_stream_id <= MAX_CLIENT_STREAM_ID && + transport_global->concurrent_stream_count < + transport_global + ->settings[GRPC_PEER_SETTINGS] + [GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS] && + grpc_chttp2_list_pop_waiting_for_concurrency(transport_global, + &stream_global)) { + /* safe since we can't (legally) be parsing this stream yet */ + grpc_chttp2_stream_parsing *stream_parsing = + &STREAM_FROM_GLOBAL(stream_global)->parsing; + GRPC_CHTTP2_IF_TRACING(gpr_log( + GPR_DEBUG, "HTTP:%s: Allocating new grpc_chttp2_stream %p to id %d", + transport_global->is_client ? "CLI" : "SVR", stream_global, + transport_global->next_stream_id)); + + GPR_ASSERT(stream_global->id == 0); + stream_global->id = stream_parsing->id = transport_global->next_stream_id; + transport_global->next_stream_id += 2; + + if (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID) { + connectivity_state_set(exec_ctx, transport_global, + GRPC_CHANNEL_TRANSIENT_FAILURE, + "no_more_stream_ids"); + } + + stream_global->outgoing_window = + transport_global->settings[GRPC_PEER_SETTINGS] + [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; + stream_parsing->incoming_window = stream_incoming_window = + transport_global->settings[GRPC_SENT_SETTINGS] + [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; + stream_global->max_recv_bytes = + GPR_MAX(stream_incoming_window, stream_global->max_recv_bytes); + grpc_chttp2_stream_map_add( + &TRANSPORT_FROM_GLOBAL(transport_global)->new_stream_map, + stream_global->id, STREAM_FROM_GLOBAL(stream_global)); + stream_global->in_stream_map = 1; + transport_global->concurrent_stream_count++; + grpc_chttp2_become_writable(transport_global, stream_global); + } + /* cancel out streams that will never be started */ + while (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID && + grpc_chttp2_list_pop_waiting_for_concurrency(transport_global, + &stream_global)) { + cancel_from_api(exec_ctx, transport_global, stream_global, + GRPC_STATUS_UNAVAILABLE); + } +} + +static grpc_closure *add_closure_barrier(grpc_closure *closure) { + closure->final_data += 2; + return closure; +} + +void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx, + grpc_closure **pclosure, int success) { + grpc_closure *closure = *pclosure; + if (closure == NULL) { + return; + } + closure->final_data -= 2; + if (!success) { + closure->final_data |= 1; + } + if (closure->final_data < 2) { + grpc_exec_ctx_enqueue(exec_ctx, closure, closure->final_data == 0, NULL); + } + *pclosure = NULL; +} + +static int contains_non_ok_status( + grpc_chttp2_transport_global *transport_global, + grpc_metadata_batch *batch) { + grpc_linked_mdelem *l; + for (l = batch->list.head; l; l = l->next) { + if (l->md->key == GRPC_MDSTR_GRPC_STATUS && + l->md != GRPC_MDELEM_GRPC_STATUS_0) { + return 1; + } + } + return 0; +} + +static void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, bool success) {} + +static void perform_stream_op_locked( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global *stream_global, grpc_transport_stream_op *op) { + grpc_closure *on_complete; + + GPR_TIMER_BEGIN("perform_stream_op_locked", 0); + + on_complete = op->on_complete; + if (on_complete == NULL) { + on_complete = grpc_closure_create(do_nothing, NULL); + } + /* use final_data as a barrier until enqueue time; the inital counter is + dropped at the end of this function */ + on_complete->final_data = 2; + + if (op->cancel_with_status != GRPC_STATUS_OK) { + cancel_from_api(exec_ctx, transport_global, stream_global, + op->cancel_with_status); + } + + if (op->close_with_status != GRPC_STATUS_OK) { + close_from_api(exec_ctx, transport_global, stream_global, + op->close_with_status, op->optional_close_message); + } + + if (op->send_initial_metadata != NULL) { + GPR_ASSERT(stream_global->send_initial_metadata_finished == NULL); + stream_global->send_initial_metadata_finished = + add_closure_barrier(on_complete); + stream_global->send_initial_metadata = op->send_initial_metadata; + if (contains_non_ok_status(transport_global, op->send_initial_metadata)) { + stream_global->seen_error = 1; + grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); + } + if (!stream_global->write_closed) { + if (transport_global->is_client) { + GPR_ASSERT(stream_global->id == 0); + grpc_chttp2_list_add_waiting_for_concurrency(transport_global, + stream_global); + maybe_start_some_streams(exec_ctx, transport_global); + } else { + GPR_ASSERT(stream_global->id != 0); + grpc_chttp2_become_writable(transport_global, stream_global); + } + } else { + grpc_chttp2_complete_closure_step( + exec_ctx, &stream_global->send_initial_metadata_finished, 0); + } + } + + if (op->send_message != NULL) { + GPR_ASSERT(stream_global->send_message_finished == NULL); + GPR_ASSERT(stream_global->send_message == NULL); + stream_global->send_message_finished = add_closure_barrier(on_complete); + if (stream_global->write_closed) { + grpc_chttp2_complete_closure_step( + exec_ctx, &stream_global->send_message_finished, 0); + } else { + stream_global->send_message = op->send_message; + if (stream_global->id != 0) { + grpc_chttp2_become_writable(transport_global, stream_global); + } + } + } + + if (op->send_trailing_metadata != NULL) { + GPR_ASSERT(stream_global->send_trailing_metadata_finished == NULL); + stream_global->send_trailing_metadata_finished = + add_closure_barrier(on_complete); + stream_global->send_trailing_metadata = op->send_trailing_metadata; + if (contains_non_ok_status(transport_global, op->send_trailing_metadata)) { + stream_global->seen_error = 1; + grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); + } + if (stream_global->write_closed) { + grpc_chttp2_complete_closure_step( + exec_ctx, &stream_global->send_trailing_metadata_finished, + grpc_metadata_batch_is_empty(op->send_trailing_metadata)); + } else if (stream_global->id != 0) { + /* TODO(ctiller): check if there's flow control for any outstanding + bytes before going writable */ + grpc_chttp2_become_writable(transport_global, stream_global); + } + } + + if (op->recv_initial_metadata != NULL) { + GPR_ASSERT(stream_global->recv_initial_metadata_ready == NULL); + stream_global->recv_initial_metadata_ready = + op->recv_initial_metadata_ready; + stream_global->recv_initial_metadata = op->recv_initial_metadata; + grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); + } + + if (op->recv_message != NULL) { + GPR_ASSERT(stream_global->recv_message_ready == NULL); + stream_global->recv_message_ready = op->recv_message_ready; + stream_global->recv_message = op->recv_message; + if (stream_global->id != 0 && + (stream_global->incoming_frames.head == NULL || + stream_global->incoming_frames.head->is_tail)) { + incoming_byte_stream_update_flow_control( + transport_global, stream_global, transport_global->stream_lookahead, + 0); + } + grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); + } + + if (op->recv_trailing_metadata != NULL) { + GPR_ASSERT(stream_global->recv_trailing_metadata_finished == NULL); + stream_global->recv_trailing_metadata_finished = + add_closure_barrier(on_complete); + stream_global->recv_trailing_metadata = op->recv_trailing_metadata; + grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); + } + + grpc_chttp2_complete_closure_step(exec_ctx, &on_complete, 1); + + GPR_TIMER_END("perform_stream_op_locked", 0); +} + +static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt, + grpc_stream *gs, grpc_transport_stream_op *op) { + grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; + grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs; + + lock(t); + perform_stream_op_locked(exec_ctx, &t->global, &s->global, op); + unlock(exec_ctx, t); +} + +static void send_ping_locked(grpc_chttp2_transport *t, grpc_closure *on_recv) { + grpc_chttp2_outstanding_ping *p = gpr_malloc(sizeof(*p)); + p->next = &t->global.pings; + p->prev = p->next->prev; + p->prev->next = p->next->prev = p; + p->id[0] = (uint8_t)((t->global.ping_counter >> 56) & 0xff); + p->id[1] = (uint8_t)((t->global.ping_counter >> 48) & 0xff); + p->id[2] = (uint8_t)((t->global.ping_counter >> 40) & 0xff); + p->id[3] = (uint8_t)((t->global.ping_counter >> 32) & 0xff); + p->id[4] = (uint8_t)((t->global.ping_counter >> 24) & 0xff); + p->id[5] = (uint8_t)((t->global.ping_counter >> 16) & 0xff); + p->id[6] = (uint8_t)((t->global.ping_counter >> 8) & 0xff); + p->id[7] = (uint8_t)(t->global.ping_counter & 0xff); + p->on_recv = on_recv; + gpr_slice_buffer_add(&t->global.qbuf, grpc_chttp2_ping_create(0, p->id)); +} + +void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport_parsing *transport_parsing, + const uint8_t *opaque_8bytes) { + grpc_chttp2_outstanding_ping *ping; + grpc_chttp2_transport *t = TRANSPORT_FROM_PARSING(transport_parsing); + grpc_chttp2_transport_global *transport_global = &t->global; + lock(t); + for (ping = transport_global->pings.next; ping != &transport_global->pings; + ping = ping->next) { + if (0 == memcmp(opaque_8bytes, ping->id, 8)) { + grpc_exec_ctx_enqueue(exec_ctx, ping->on_recv, true, NULL); + ping->next->prev = ping->prev; + ping->prev->next = ping->next; + gpr_free(ping); + break; + } + } + unlock(exec_ctx, t); +} + +static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + grpc_transport_op *op) { + bool close_transport = false; + + grpc_exec_ctx_enqueue(exec_ctx, op->on_consumed, true, NULL); + + if (op->on_connectivity_state_change != NULL) { + grpc_connectivity_state_notify_on_state_change( + exec_ctx, &t->channel_callback.state_tracker, op->connectivity_state, + op->on_connectivity_state_change); + } + + if (op->send_goaway) { + t->global.sent_goaway = 1; + grpc_chttp2_goaway_append( + t->global.last_incoming_stream_id, + (uint32_t)grpc_chttp2_grpc_status_to_http2_error(op->goaway_status), + gpr_slice_ref(*op->goaway_message), &t->global.qbuf); + close_transport = !grpc_chttp2_has_streams(t); + } + + if (op->set_accept_stream) { + t->channel_callback.accept_stream = op->set_accept_stream_fn; + t->channel_callback.accept_stream_user_data = + op->set_accept_stream_user_data; + } + + if (op->bind_pollset) { + add_to_pollset_locked(exec_ctx, t, op->bind_pollset); + } + + if (op->bind_pollset_set) { + add_to_pollset_set_locked(exec_ctx, t, op->bind_pollset_set); + } + + if (op->send_ping) { + send_ping_locked(t, op->send_ping); + } + + if (op->disconnect) { + close_transport_locked(exec_ctx, t); + } + + if (close_transport) { + close_transport_locked(exec_ctx, t); + } +} + +static void perform_transport_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt, + grpc_transport_op *op) { + grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; + + lock(t); + + /* If there's a set_accept_stream ensure that we're not parsing + to avoid changing things out from underneath */ + if (t->parsing_active && op->set_accept_stream) { + GPR_ASSERT(t->post_parsing_op == NULL); + t->post_parsing_op = gpr_malloc(sizeof(*op)); + memcpy(t->post_parsing_op, op, sizeof(*op)); + } else { + perform_transport_op_locked(exec_ctx, t, op); + } + + unlock(exec_ctx, t); +} + +/******************************************************************************* + * INPUT PROCESSING + */ + +static void check_read_ops(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport_global *transport_global) { + grpc_chttp2_stream_global *stream_global; + grpc_byte_stream *bs; + while ( + grpc_chttp2_list_pop_check_read_ops(transport_global, &stream_global)) { + if (stream_global->recv_initial_metadata_ready != NULL && + stream_global->published_initial_metadata) { + grpc_chttp2_incoming_metadata_buffer_publish( + &stream_global->received_initial_metadata, + stream_global->recv_initial_metadata); + grpc_exec_ctx_enqueue( + exec_ctx, stream_global->recv_initial_metadata_ready, true, NULL); + stream_global->recv_initial_metadata_ready = NULL; + } + if (stream_global->recv_message_ready != NULL) { + while (stream_global->seen_error && + (bs = grpc_chttp2_incoming_frame_queue_pop( + &stream_global->incoming_frames)) != NULL) { + grpc_byte_stream_destroy(exec_ctx, bs); + } + if (stream_global->incoming_frames.head != NULL) { + *stream_global->recv_message = grpc_chttp2_incoming_frame_queue_pop( + &stream_global->incoming_frames); + GPR_ASSERT(*stream_global->recv_message != NULL); + grpc_exec_ctx_enqueue(exec_ctx, stream_global->recv_message_ready, true, + NULL); + stream_global->recv_message_ready = NULL; + } else if (stream_global->published_trailing_metadata) { + *stream_global->recv_message = NULL; + grpc_exec_ctx_enqueue(exec_ctx, stream_global->recv_message_ready, true, + NULL); + stream_global->recv_message_ready = NULL; + } + } + if (stream_global->recv_trailing_metadata_finished != NULL && + stream_global->read_closed && stream_global->write_closed) { + while (stream_global->seen_error && + (bs = grpc_chttp2_incoming_frame_queue_pop( + &stream_global->incoming_frames)) != NULL) { + grpc_byte_stream_destroy(exec_ctx, bs); + } + if (stream_global->incoming_frames.head == NULL) { + grpc_chttp2_incoming_metadata_buffer_publish( + &stream_global->received_trailing_metadata, + stream_global->recv_trailing_metadata); + grpc_chttp2_complete_closure_step( + exec_ctx, &stream_global->recv_trailing_metadata_finished, 1); + } + } + } +} + +static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, + uint32_t id) { + size_t new_stream_count; + grpc_chttp2_stream *s = + grpc_chttp2_stream_map_delete(&t->parsing_stream_map, id); + if (!s) { + s = grpc_chttp2_stream_map_delete(&t->new_stream_map, id); + } + GPR_ASSERT(s); + s->global.in_stream_map = 0; + if (t->parsing.incoming_stream == &s->parsing) { + t->parsing.incoming_stream = NULL; + grpc_chttp2_parsing_become_skip_parser(exec_ctx, &t->parsing); + } + if (s->parsing.data_parser.parsing_frame != NULL) { + grpc_chttp2_incoming_byte_stream_finished( + exec_ctx, s->parsing.data_parser.parsing_frame, 0, 0); + s->parsing.data_parser.parsing_frame = NULL; + } + + if (grpc_chttp2_unregister_stream(t, s) && t->global.sent_goaway) { + close_transport_locked(exec_ctx, t); + } + if (grpc_chttp2_list_remove_writable_stream(&t->global, &s->global)) { + GRPC_CHTTP2_STREAM_UNREF(exec_ctx, &s->global, "chttp2_writing"); + } + + new_stream_count = grpc_chttp2_stream_map_size(&t->parsing_stream_map) + + grpc_chttp2_stream_map_size(&t->new_stream_map); + GPR_ASSERT(new_stream_count <= UINT32_MAX); + if (new_stream_count != t->global.concurrent_stream_count) { + t->global.concurrent_stream_count = (uint32_t)new_stream_count; + maybe_start_some_streams(exec_ctx, &t->global); + } +} + +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) { + if (stream_global->id != 0) { + gpr_slice_buffer_add( + &transport_global->qbuf, + grpc_chttp2_rst_stream_create( + stream_global->id, + (uint32_t)grpc_chttp2_grpc_status_to_http2_error(status))); + } + grpc_chttp2_fake_status(exec_ctx, transport_global, stream_global, status, + NULL); + grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, 1, + 1); +} + +void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global *stream_global, + grpc_status_code status, gpr_slice *slice) { + if (status != GRPC_STATUS_OK) { + stream_global->seen_error = 1; + grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); + } + /* stream_global->recv_trailing_metadata_finished gives us a + last chance replacement: we've received trailing metadata, + but something more important has become available to signal + to the upper layers - drop what we've got, and then publish + what we want - which is safe because we haven't told anyone + about the metadata yet */ + if (!stream_global->published_trailing_metadata || + stream_global->recv_trailing_metadata_finished != NULL) { + char status_string[GPR_LTOA_MIN_BUFSIZE]; + gpr_ltoa(status, status_string); + grpc_chttp2_incoming_metadata_buffer_add( + &stream_global->received_trailing_metadata, + grpc_mdelem_from_metadata_strings( + GRPC_MDSTR_GRPC_STATUS, grpc_mdstr_from_string(status_string))); + if (slice) { + grpc_chttp2_incoming_metadata_buffer_add( + &stream_global->received_trailing_metadata, + grpc_mdelem_from_metadata_strings( + GRPC_MDSTR_GRPC_MESSAGE, + grpc_mdstr_from_slice(gpr_slice_ref(*slice)))); + } + stream_global->published_trailing_metadata = 1; + grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); + } + if (slice) { + gpr_slice_unref(*slice); + } +} + +static void fail_pending_writes(grpc_exec_ctx *exec_ctx, + grpc_chttp2_stream_global *stream_global) { + grpc_chttp2_complete_closure_step( + exec_ctx, &stream_global->send_initial_metadata_finished, 0); + grpc_chttp2_complete_closure_step( + exec_ctx, &stream_global->send_trailing_metadata_finished, 0); + grpc_chttp2_complete_closure_step(exec_ctx, + &stream_global->send_message_finished, 0); +} + +void grpc_chttp2_mark_stream_closed( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global *stream_global, int close_reads, + int close_writes) { + if (stream_global->read_closed && stream_global->write_closed) { + /* already closed */ + return; + } + grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); + if (close_reads && !stream_global->read_closed) { + stream_global->read_closed = 1; + stream_global->published_initial_metadata = 1; + stream_global->published_trailing_metadata = 1; + } + if (close_writes && !stream_global->write_closed) { + stream_global->write_closed = 1; + if (TRANSPORT_FROM_GLOBAL(transport_global)->writing_active) { + GRPC_CHTTP2_STREAM_REF(stream_global, "finish_writes"); + grpc_chttp2_list_add_closed_waiting_for_writing(transport_global, + stream_global); + } else { + fail_pending_writes(exec_ctx, stream_global); + } + } + if (stream_global->read_closed && stream_global->write_closed) { + if (stream_global->id != 0 && + TRANSPORT_FROM_GLOBAL(transport_global)->parsing_active) { + grpc_chttp2_list_add_closed_waiting_for_parsing(transport_global, + stream_global); + } else { + if (stream_global->id != 0) { + remove_stream(exec_ctx, TRANSPORT_FROM_GLOBAL(transport_global), + stream_global->id); + } + GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2"); + } + } +} + +static void close_from_api(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global *stream_global, + grpc_status_code status, + gpr_slice *optional_message) { + gpr_slice hdr; + gpr_slice status_hdr; + gpr_slice message_pfx; + uint8_t *p; + uint32_t len = 0; + + GPR_ASSERT(status >= 0 && (int)status < 100); + + GPR_ASSERT(stream_global->id != 0); + + /* Hand roll a header block. + This is unnecessarily ugly - at some point we should find a more elegant + solution. + It's complicated by the fact that our send machinery would be dead by the + time we got around to sending this, so instead we ignore HPACK compression + and just write the uncompressed bytes onto the wire. */ + status_hdr = gpr_slice_malloc(15 + (status >= 10)); + p = GPR_SLICE_START_PTR(status_hdr); + *p++ = 0x40; /* literal header */ + *p++ = 11; /* len(grpc-status) */ + *p++ = 'g'; + *p++ = 'r'; + *p++ = 'p'; + *p++ = 'c'; + *p++ = '-'; + *p++ = 's'; + *p++ = 't'; + *p++ = 'a'; + *p++ = 't'; + *p++ = 'u'; + *p++ = 's'; + if (status < 10) { + *p++ = 1; + *p++ = (uint8_t)('0' + status); + } else { + *p++ = 2; + *p++ = (uint8_t)('0' + (status / 10)); + *p++ = (uint8_t)('0' + (status % 10)); + } + GPR_ASSERT(p == GPR_SLICE_END_PTR(status_hdr)); + len += (uint32_t)GPR_SLICE_LENGTH(status_hdr); + + if (optional_message) { + GPR_ASSERT(GPR_SLICE_LENGTH(*optional_message) < 127); + message_pfx = gpr_slice_malloc(15); + p = GPR_SLICE_START_PTR(message_pfx); + *p++ = 0x40; + *p++ = 12; /* len(grpc-message) */ + *p++ = 'g'; + *p++ = 'r'; + *p++ = 'p'; + *p++ = 'c'; + *p++ = '-'; + *p++ = 'm'; + *p++ = 'e'; + *p++ = 's'; + *p++ = 's'; + *p++ = 'a'; + *p++ = 'g'; + *p++ = 'e'; + *p++ = (uint8_t)GPR_SLICE_LENGTH(*optional_message); + GPR_ASSERT(p == GPR_SLICE_END_PTR(message_pfx)); + len += (uint32_t)GPR_SLICE_LENGTH(message_pfx); + len += (uint32_t)GPR_SLICE_LENGTH(*optional_message); + } + + hdr = gpr_slice_malloc(9); + p = GPR_SLICE_START_PTR(hdr); + *p++ = (uint8_t)(len >> 16); + *p++ = (uint8_t)(len >> 8); + *p++ = (uint8_t)(len); + *p++ = GRPC_CHTTP2_FRAME_HEADER; + *p++ = GRPC_CHTTP2_DATA_FLAG_END_STREAM | GRPC_CHTTP2_DATA_FLAG_END_HEADERS; + *p++ = (uint8_t)(stream_global->id >> 24); + *p++ = (uint8_t)(stream_global->id >> 16); + *p++ = (uint8_t)(stream_global->id >> 8); + *p++ = (uint8_t)(stream_global->id); + GPR_ASSERT(p == GPR_SLICE_END_PTR(hdr)); + + gpr_slice_buffer_add(&transport_global->qbuf, hdr); + gpr_slice_buffer_add(&transport_global->qbuf, status_hdr); + if (optional_message) { + gpr_slice_buffer_add(&transport_global->qbuf, message_pfx); + gpr_slice_buffer_add(&transport_global->qbuf, + gpr_slice_ref(*optional_message)); + } + + gpr_slice_buffer_add( + &transport_global->qbuf, + grpc_chttp2_rst_stream_create(stream_global->id, GRPC_CHTTP2_NO_ERROR)); + + if (optional_message) { + gpr_slice_ref(*optional_message); + } + grpc_chttp2_fake_status(exec_ctx, transport_global, stream_global, status, + optional_message); + grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, 1, + 1); +} + +static void cancel_stream_cb(grpc_chttp2_transport_global *transport_global, + void *user_data, + grpc_chttp2_stream_global *stream_global) { + cancel_from_api(user_data, transport_global, stream_global, + GRPC_STATUS_UNAVAILABLE); +} + +static void end_all_the_calls(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t) { + grpc_chttp2_for_all_streams(&t->global, exec_ctx, cancel_stream_cb); +} + +static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) { + close_transport_locked(exec_ctx, t); + end_all_the_calls(exec_ctx, t); +} + +/** update window from a settings change */ +static void update_global_window(void *args, uint32_t id, void *stream) { + grpc_chttp2_transport *t = args; + grpc_chttp2_stream *s = stream; + grpc_chttp2_transport_global *transport_global = &t->global; + grpc_chttp2_stream_global *stream_global = &s->global; + int was_zero; + int is_zero; + int64_t initial_window_update = t->parsing.initial_window_update; + + was_zero = stream_global->outgoing_window <= 0; + GRPC_CHTTP2_FLOW_CREDIT_STREAM("settings", transport_global, stream_global, + outgoing_window, initial_window_update); + is_zero = stream_global->outgoing_window <= 0; + + if (was_zero && !is_zero) { + grpc_chttp2_become_writable(transport_global, stream_global); + } +} + +static void read_error_locked(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t) { + t->endpoint_reading = 0; + if (!t->writing_active && t->ep) { + destroy_endpoint(exec_ctx, t); + } +} + +/* tcp read callback */ +static void recv_data(grpc_exec_ctx *exec_ctx, void *tp, bool success) { + size_t i; + int keep_reading = 0; + grpc_chttp2_transport *t = tp; + grpc_chttp2_transport_global *transport_global = &t->global; + grpc_chttp2_transport_parsing *transport_parsing = &t->parsing; + grpc_chttp2_stream_global *stream_global; + + GPR_TIMER_BEGIN("recv_data", 0); + + lock(t); + i = 0; + GPR_ASSERT(!t->parsing_active); + if (!t->closed) { + t->parsing_active = 1; + /* merge stream lists */ + grpc_chttp2_stream_map_move_into(&t->new_stream_map, + &t->parsing_stream_map); + grpc_chttp2_prepare_to_read(transport_global, transport_parsing); + gpr_mu_unlock(&t->mu); + GPR_TIMER_BEGIN("recv_data.parse", 0); + for (; i < t->read_buffer.count && + grpc_chttp2_perform_read(exec_ctx, transport_parsing, + t->read_buffer.slices[i]); + i++) + ; + GPR_TIMER_END("recv_data.parse", 0); + gpr_mu_lock(&t->mu); + /* copy parsing qbuf to global qbuf */ + gpr_slice_buffer_move_into(&t->parsing.qbuf, &t->global.qbuf); + if (i != t->read_buffer.count) { + unlock(exec_ctx, t); + lock(t); + drop_connection(exec_ctx, t); + } + /* merge stream lists */ + grpc_chttp2_stream_map_move_into(&t->new_stream_map, + &t->parsing_stream_map); + transport_global->concurrent_stream_count = + (uint32_t)grpc_chttp2_stream_map_size(&t->parsing_stream_map); + if (transport_parsing->initial_window_update != 0) { + grpc_chttp2_stream_map_for_each(&t->parsing_stream_map, + update_global_window, t); + transport_parsing->initial_window_update = 0; + } + /* handle higher level things */ + grpc_chttp2_publish_reads(exec_ctx, transport_global, transport_parsing); + t->parsing_active = 0; + /* handle delayed transport ops (if there is one) */ + if (t->post_parsing_op) { + grpc_transport_op *op = t->post_parsing_op; + t->post_parsing_op = NULL; + perform_transport_op_locked(exec_ctx, t, op); + gpr_free(op); + } + /* if a stream is in the stream map, and gets cancelled, we need to ensure + * we are not parsing before continuing the cancellation to keep things in + * a sane state */ + while (grpc_chttp2_list_pop_closed_waiting_for_parsing(transport_global, + &stream_global)) { + GPR_ASSERT(stream_global->in_stream_map); + GPR_ASSERT(stream_global->write_closed); + GPR_ASSERT(stream_global->read_closed); + remove_stream(exec_ctx, t, stream_global->id); + GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2"); + } + } + if (!success || i != t->read_buffer.count || t->closed) { + drop_connection(exec_ctx, t); + read_error_locked(exec_ctx, t); + } else if (!t->closed) { + keep_reading = 1; + REF_TRANSPORT(t, "keep_reading"); + prevent_endpoint_shutdown(t); + } + gpr_slice_buffer_reset_and_unref(&t->read_buffer); + unlock(exec_ctx, t); + + if (keep_reading) { + grpc_endpoint_read(exec_ctx, t->ep, &t->read_buffer, &t->recv_data); + allow_endpoint_shutdown_unlocked(exec_ctx, t); + UNREF_TRANSPORT(exec_ctx, t, "keep_reading"); + } else { + UNREF_TRANSPORT(exec_ctx, t, "recv_data"); + } + + GPR_TIMER_END("recv_data", 0); +} + +/******************************************************************************* + * CALLBACK LOOP + */ + +static void connectivity_state_set( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, + grpc_connectivity_state state, const char *reason) { + GRPC_CHTTP2_IF_TRACING( + gpr_log(GPR_DEBUG, "set connectivity_state=%d", state)); + grpc_connectivity_state_set( + exec_ctx, + &TRANSPORT_FROM_GLOBAL(transport_global)->channel_callback.state_tracker, + state, reason); +} + +/******************************************************************************* + * POLLSET STUFF + */ + +static void add_to_pollset_locked(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + grpc_pollset *pollset) { + if (t->ep) { + grpc_endpoint_add_to_pollset(exec_ctx, t->ep, pollset); + } +} + +static void add_to_pollset_set_locked(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + grpc_pollset_set *pollset_set) { + if (t->ep) { + grpc_endpoint_add_to_pollset_set(exec_ctx, t->ep, pollset_set); + } +} + +static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_transport *gt, + grpc_stream *gs, grpc_pollset *pollset) { + grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; + lock(t); + add_to_pollset_locked(exec_ctx, t, pollset); + unlock(exec_ctx, t); +} + +/******************************************************************************* + * BYTE STREAM + */ + +static void incoming_byte_stream_update_flow_control( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global *stream_global, size_t max_size_hint, + size_t have_already) { + uint32_t max_recv_bytes; + + /* clamp max recv hint to an allowable size */ + if (max_size_hint >= UINT32_MAX - transport_global->stream_lookahead) { + max_recv_bytes = UINT32_MAX - transport_global->stream_lookahead; + } else { + max_recv_bytes = (uint32_t)max_size_hint; + } + + /* account for bytes already received but unknown to higher layers */ + if (max_recv_bytes >= have_already) { + max_recv_bytes -= (uint32_t)have_already; + } else { + max_recv_bytes = 0; + } + + /* add some small lookahead to keep pipelines flowing */ + GPR_ASSERT(max_recv_bytes <= UINT32_MAX - transport_global->stream_lookahead); + max_recv_bytes += transport_global->stream_lookahead; + if (stream_global->max_recv_bytes < max_recv_bytes) { + uint32_t add_max_recv_bytes = + max_recv_bytes - stream_global->max_recv_bytes; + GRPC_CHTTP2_FLOW_CREDIT_STREAM("op", transport_global, stream_global, + max_recv_bytes, add_max_recv_bytes); + GRPC_CHTTP2_FLOW_CREDIT_STREAM("op", transport_global, stream_global, + unannounced_incoming_window_for_parse, + add_max_recv_bytes); + GRPC_CHTTP2_FLOW_CREDIT_STREAM("op", transport_global, stream_global, + unannounced_incoming_window_for_writing, + add_max_recv_bytes); + grpc_chttp2_list_add_unannounced_incoming_window_available(transport_global, + stream_global); + grpc_chttp2_become_writable(transport_global, stream_global); + } +} + +static int incoming_byte_stream_next(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *byte_stream, + gpr_slice *slice, size_t max_size_hint, + grpc_closure *on_complete) { + grpc_chttp2_incoming_byte_stream *bs = + (grpc_chttp2_incoming_byte_stream *)byte_stream; + grpc_chttp2_transport_global *transport_global = &bs->transport->global; + grpc_chttp2_stream_global *stream_global = &bs->stream->global; + + lock(bs->transport); + if (bs->is_tail) { + incoming_byte_stream_update_flow_control(transport_global, stream_global, + max_size_hint, bs->slices.length); + } + if (bs->slices.count > 0) { + *slice = gpr_slice_buffer_take_first(&bs->slices); + unlock(exec_ctx, bs->transport); + return 1; + } else if (bs->failed) { + grpc_exec_ctx_enqueue(exec_ctx, on_complete, false, NULL); + unlock(exec_ctx, bs->transport); + return 0; + } else { + bs->on_next = on_complete; + bs->next = slice; + unlock(exec_ctx, bs->transport); + return 0; + } +} + +static void incoming_byte_stream_unref(grpc_chttp2_incoming_byte_stream *bs) { + if (gpr_unref(&bs->refs)) { + gpr_slice_buffer_destroy(&bs->slices); + gpr_free(bs); + } +} + +static void incoming_byte_stream_destroy(grpc_exec_ctx *exec_ctx, + grpc_byte_stream *byte_stream) { + incoming_byte_stream_unref((grpc_chttp2_incoming_byte_stream *)byte_stream); +} + +void grpc_chttp2_incoming_byte_stream_push(grpc_exec_ctx *exec_ctx, + grpc_chttp2_incoming_byte_stream *bs, + gpr_slice slice) { + gpr_mu_lock(&bs->transport->mu); + if (bs->on_next != NULL) { + *bs->next = slice; + grpc_exec_ctx_enqueue(exec_ctx, bs->on_next, true, NULL); + bs->on_next = NULL; + } else { + gpr_slice_buffer_add(&bs->slices, slice); + } + gpr_mu_unlock(&bs->transport->mu); +} + +void grpc_chttp2_incoming_byte_stream_finished( + grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs, int success, + int from_parsing_thread) { + if (!success) { + if (from_parsing_thread) { + gpr_mu_lock(&bs->transport->mu); + } + grpc_exec_ctx_enqueue(exec_ctx, bs->on_next, false, NULL); + bs->on_next = NULL; + bs->failed = 1; + if (from_parsing_thread) { + gpr_mu_unlock(&bs->transport->mu); + } + } else { +#ifndef NDEBUG + if (from_parsing_thread) { + gpr_mu_lock(&bs->transport->mu); + } + GPR_ASSERT(bs->on_next == NULL); + if (from_parsing_thread) { + gpr_mu_unlock(&bs->transport->mu); + } +#endif + } + incoming_byte_stream_unref(bs); +} + +grpc_chttp2_incoming_byte_stream *grpc_chttp2_incoming_byte_stream_create( + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, + grpc_chttp2_stream_parsing *stream_parsing, uint32_t frame_size, + uint32_t flags, grpc_chttp2_incoming_frame_queue *add_to_queue) { + grpc_chttp2_incoming_byte_stream *incoming_byte_stream = + gpr_malloc(sizeof(*incoming_byte_stream)); + incoming_byte_stream->base.length = frame_size; + incoming_byte_stream->base.flags = flags; + incoming_byte_stream->base.next = incoming_byte_stream_next; + incoming_byte_stream->base.destroy = incoming_byte_stream_destroy; + gpr_ref_init(&incoming_byte_stream->refs, 2); + incoming_byte_stream->next_message = NULL; + incoming_byte_stream->transport = TRANSPORT_FROM_PARSING(transport_parsing); + incoming_byte_stream->stream = STREAM_FROM_PARSING(stream_parsing); + gpr_slice_buffer_init(&incoming_byte_stream->slices); + incoming_byte_stream->on_next = NULL; + incoming_byte_stream->is_tail = 1; + incoming_byte_stream->failed = 0; + if (add_to_queue->head == NULL) { + add_to_queue->head = incoming_byte_stream; + } else { + add_to_queue->tail->is_tail = 0; + add_to_queue->tail->next_message = incoming_byte_stream; + } + add_to_queue->tail = incoming_byte_stream; + return incoming_byte_stream; +} + +/******************************************************************************* + * TRACING + */ + +static char *format_flowctl_context_var(const char *context, const char *var, + int64_t val, uint32_t id, + char **scope) { + char *underscore_pos; + char *result; + if (context == NULL) { + *scope = NULL; + gpr_asprintf(&result, "%s(%lld)", var, val); + return result; + } + underscore_pos = strchr(context, '_'); + *scope = gpr_strdup(context); + (*scope)[underscore_pos - context] = 0; + if (id != 0) { + char *tmp = *scope; + gpr_asprintf(scope, "%s[%d]", tmp, id); + gpr_free(tmp); + } + gpr_asprintf(&result, "%s.%s(%lld)", underscore_pos + 1, var, val); + return result; +} + +static int samestr(char *a, char *b) { + if (a == NULL) { + return b == NULL; + } + if (b == NULL) { + return 0; + } + return 0 == strcmp(a, b); +} + +void grpc_chttp2_flowctl_trace(const char *file, int line, const char *phase, + grpc_chttp2_flowctl_op op, const char *context1, + const char *var1, const char *context2, + const char *var2, int is_client, + uint32_t stream_id, int64_t val1, int64_t val2) { + char *scope1; + char *scope2; + char *label1 = + format_flowctl_context_var(context1, var1, val1, stream_id, &scope1); + char *label2 = + format_flowctl_context_var(context2, var2, val2, stream_id, &scope2); + char *clisvr = is_client ? "client" : "server"; + char *prefix; + + gpr_asprintf(&prefix, "FLOW % 8s: %s % 11s ", phase, clisvr, 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, + val1 + val2); + } + break; + case GRPC_CHTTP2_FLOWCTL_CREDIT: + GPR_ASSERT(val2 >= 0); + if (val2 != 0) { + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, + "%sCREDIT % 40s by % 40s giving %d", prefix, label1, label2, + val1 + val2); + } + break; + case GRPC_CHTTP2_FLOWCTL_DEBIT: + GPR_ASSERT(val2 >= 0); + if (val2 != 0) { + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, + "%sDEBIT % 40s by % 40s giving %d", prefix, label1, label2, + val1 - val2); + } + break; + } + + gpr_free(scope1); + gpr_free(scope2); + gpr_free(label1); + gpr_free(label2); + gpr_free(prefix); +} + +/******************************************************************************* + * INTEGRATION GLUE + */ + +static char *chttp2_get_peer(grpc_exec_ctx *exec_ctx, grpc_transport *t) { + return gpr_strdup(((grpc_chttp2_transport *)t)->peer_string); +} + +static const grpc_transport_vtable vtable = {sizeof(grpc_chttp2_stream), + "chttp2", + init_stream, + set_pollset, + perform_stream_op, + perform_transport_op, + destroy_stream, + destroy_transport, + chttp2_get_peer}; + +grpc_transport *grpc_create_chttp2_transport( + grpc_exec_ctx *exec_ctx, const grpc_channel_args *channel_args, + grpc_endpoint *ep, int is_client) { + grpc_chttp2_transport *t = gpr_malloc(sizeof(grpc_chttp2_transport)); + init_transport(exec_ctx, t, channel_args, ep, is_client != 0); + return &t->base; +} + +void grpc_chttp2_transport_start_reading(grpc_exec_ctx *exec_ctx, + grpc_transport *transport, + gpr_slice *slices, size_t nslices) { + grpc_chttp2_transport *t = (grpc_chttp2_transport *)transport; + REF_TRANSPORT(t, "recv_data"); /* matches unref inside recv_data */ + gpr_slice_buffer_addn(&t->read_buffer, slices, nslices); + recv_data(exec_ctx, t, 1); +} diff --git a/src/core/lib/transport/chttp2_transport.h b/src/core/lib/transport/chttp2_transport.h new file mode 100644 index 0000000000..9a6cf0ed35 --- /dev/null +++ b/src/core/lib/transport/chttp2_transport.h @@ -0,0 +1,51 @@ +/* + * + * Copyright 2015-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_TRANSPORT_CHTTP2_TRANSPORT_H +#define GRPC_CORE_TRANSPORT_CHTTP2_TRANSPORT_H + +#include "src/core/iomgr/endpoint.h" +#include "src/core/transport/transport.h" + +extern int grpc_http_trace; +extern int grpc_flowctl_trace; + +grpc_transport *grpc_create_chttp2_transport( + grpc_exec_ctx *exec_ctx, const grpc_channel_args *channel_args, + grpc_endpoint *ep, int is_client); + +void grpc_chttp2_transport_start_reading(grpc_exec_ctx *exec_ctx, + grpc_transport *transport, + gpr_slice *slices, size_t nslices); + +#endif /* GRPC_CORE_TRANSPORT_CHTTP2_TRANSPORT_H */ diff --git a/src/core/lib/transport/connectivity_state.c b/src/core/lib/transport/connectivity_state.c new file mode 100644 index 0000000000..87765b9799 --- /dev/null +++ b/src/core/lib/transport/connectivity_state.c @@ -0,0 +1,164 @@ +/* + * + * Copyright 2015-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/transport/connectivity_state.h" + +#include + +#include +#include +#include + +int grpc_connectivity_state_trace = 0; + +const char *grpc_connectivity_state_name(grpc_connectivity_state state) { + switch (state) { + case GRPC_CHANNEL_IDLE: + return "IDLE"; + case GRPC_CHANNEL_CONNECTING: + return "CONNECTING"; + case GRPC_CHANNEL_READY: + return "READY"; + case GRPC_CHANNEL_TRANSIENT_FAILURE: + return "TRANSIENT_FAILURE"; + case GRPC_CHANNEL_FATAL_FAILURE: + return "FATAL_FAILURE"; + } + GPR_UNREACHABLE_CODE(return "UNKNOWN"); +} + +void grpc_connectivity_state_init(grpc_connectivity_state_tracker *tracker, + grpc_connectivity_state init_state, + const char *name) { + tracker->current_state = init_state; + tracker->watchers = NULL; + tracker->name = gpr_strdup(name); +} + +void grpc_connectivity_state_destroy(grpc_exec_ctx *exec_ctx, + grpc_connectivity_state_tracker *tracker) { + int success; + grpc_connectivity_state_watcher *w; + while ((w = tracker->watchers)) { + tracker->watchers = w->next; + + if (GRPC_CHANNEL_FATAL_FAILURE != *w->current) { + *w->current = GRPC_CHANNEL_FATAL_FAILURE; + success = 1; + } else { + success = 0; + } + grpc_exec_ctx_enqueue(exec_ctx, w->notify, success, NULL); + gpr_free(w); + } + gpr_free(tracker->name); +} + +grpc_connectivity_state grpc_connectivity_state_check( + grpc_connectivity_state_tracker *tracker) { + if (grpc_connectivity_state_trace) { + gpr_log(GPR_DEBUG, "CONWATCH: %p %s: get %s", tracker, tracker->name, + grpc_connectivity_state_name(tracker->current_state)); + } + return tracker->current_state; +} + +int grpc_connectivity_state_notify_on_state_change( + grpc_exec_ctx *exec_ctx, grpc_connectivity_state_tracker *tracker, + grpc_connectivity_state *current, grpc_closure *notify) { + if (grpc_connectivity_state_trace) { + if (current == NULL) { + gpr_log(GPR_DEBUG, "CONWATCH: %p %s: unsubscribe notify=%p", tracker, + tracker->name, notify); + } else { + gpr_log(GPR_DEBUG, "CONWATCH: %p %s: from %s [cur=%s] notify=%p", tracker, + tracker->name, grpc_connectivity_state_name(*current), + grpc_connectivity_state_name(tracker->current_state), notify); + } + } + if (current == NULL) { + grpc_connectivity_state_watcher *w = tracker->watchers; + if (w != NULL && w->notify == notify) { + grpc_exec_ctx_enqueue(exec_ctx, notify, false, NULL); + tracker->watchers = w->next; + gpr_free(w); + return 0; + } + while (w != NULL) { + grpc_connectivity_state_watcher *rm_candidate = w->next; + if (rm_candidate != NULL && rm_candidate->notify == notify) { + grpc_exec_ctx_enqueue(exec_ctx, notify, false, NULL); + w->next = w->next->next; + gpr_free(rm_candidate); + return 0; + } + w = w->next; + } + return 0; + } else { + if (tracker->current_state != *current) { + *current = tracker->current_state; + grpc_exec_ctx_enqueue(exec_ctx, notify, true, NULL); + } else { + grpc_connectivity_state_watcher *w = gpr_malloc(sizeof(*w)); + w->current = current; + w->notify = notify; + w->next = tracker->watchers; + tracker->watchers = w; + } + return tracker->current_state == GRPC_CHANNEL_IDLE; + } +} + +void grpc_connectivity_state_set(grpc_exec_ctx *exec_ctx, + grpc_connectivity_state_tracker *tracker, + grpc_connectivity_state state, + const char *reason) { + grpc_connectivity_state_watcher *w; + if (grpc_connectivity_state_trace) { + gpr_log(GPR_DEBUG, "SET: %p %s: %s --> %s [%s]", tracker, 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) != NULL) { + *w->current = tracker->current_state; + tracker->watchers = w->next; + grpc_exec_ctx_enqueue(exec_ctx, w->notify, true, NULL); + gpr_free(w); + } +} diff --git a/src/core/lib/transport/connectivity_state.h b/src/core/lib/transport/connectivity_state.h new file mode 100644 index 0000000000..b4a3ce924d --- /dev/null +++ b/src/core/lib/transport/connectivity_state.h @@ -0,0 +1,85 @@ +/* + * + * Copyright 2015-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_TRANSPORT_CONNECTIVITY_STATE_H +#define GRPC_CORE_TRANSPORT_CONNECTIVITY_STATE_H + +#include +#include "src/core/iomgr/exec_ctx.h" + +typedef struct grpc_connectivity_state_watcher { + /** we keep watchers in a linked list */ + struct grpc_connectivity_state_watcher *next; + /** closure to notify on change */ + grpc_closure *notify; + /** the current state as believed by the watcher */ + grpc_connectivity_state *current; +} grpc_connectivity_state_watcher; + +typedef struct { + /** current connectivity state */ + grpc_connectivity_state current_state; + /** all our watchers */ + grpc_connectivity_state_watcher *watchers; + /** a name to help debugging */ + char *name; +} grpc_connectivity_state_tracker; + +extern int grpc_connectivity_state_trace; + +const char *grpc_connectivity_state_name(grpc_connectivity_state state); + +void grpc_connectivity_state_init(grpc_connectivity_state_tracker *tracker, + grpc_connectivity_state init_state, + const char *name); +void grpc_connectivity_state_destroy(grpc_exec_ctx *exec_ctx, + grpc_connectivity_state_tracker *tracker); + +/** Set connectivity state; not thread safe; access must be serialized with an + * external lock */ +void grpc_connectivity_state_set(grpc_exec_ctx *exec_ctx, + grpc_connectivity_state_tracker *tracker, + grpc_connectivity_state state, + const char *reason); + +grpc_connectivity_state grpc_connectivity_state_check( + grpc_connectivity_state_tracker *tracker); + +/** Return 1 if the channel should start connecting, 0 otherwise. + If current==NULL cancel notify if it is already queued (success==0 in that + case) */ +int grpc_connectivity_state_notify_on_state_change( + grpc_exec_ctx *exec_ctx, grpc_connectivity_state_tracker *tracker, + grpc_connectivity_state *current, grpc_closure *notify); + +#endif /* GRPC_CORE_TRANSPORT_CONNECTIVITY_STATE_H */ diff --git a/src/core/lib/transport/metadata.c b/src/core/lib/transport/metadata.c new file mode 100644 index 0000000000..7ed28feca8 --- /dev/null +++ b/src/core/lib/transport/metadata.c @@ -0,0 +1,698 @@ +/* + * + * Copyright 2015-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/transport/metadata.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "src/core/iomgr/iomgr_internal.h" +#include "src/core/profiling/timers.h" +#include "src/core/support/murmur_hash.h" +#include "src/core/support/string.h" +#include "src/core/transport/chttp2/bin_encoder.h" +#include "src/core/transport/static_metadata.h" + +/* There are two kinds of mdelem and mdstr instances. + * Static instances are declared in static_metadata.{h,c} and + * are initialized by grpc_mdctx_global_init(). + * Dynamic instances are stored in hash tables on grpc_mdctx, and are backed + * by internal_string and internal_element structures. + * Internal helper functions here-in (is_mdstr_static, is_mdelem_static) are + * used to determine which kind of element a pointer refers to. + */ + +#define INITIAL_STRTAB_CAPACITY 4 +#define INITIAL_MDTAB_CAPACITY 4 + +#ifdef GRPC_METADATA_REFCOUNT_DEBUG +#define DEBUG_ARGS , const char *file, int line +#define FWD_DEBUG_ARGS , file, line +#define REF_MD_LOCKED(shard, s) ref_md_locked((shard), (s), __FILE__, __LINE__) +#else +#define DEBUG_ARGS +#define FWD_DEBUG_ARGS +#define REF_MD_LOCKED(shard, s) ref_md_locked((shard), (s)) +#endif + +#define TABLE_IDX(hash, log2_shards, capacity) \ + (((hash) >> (log2_shards)) % (capacity)) +#define SHARD_IDX(hash, log2_shards) ((hash) & ((1 << (log2_shards)) - 1)) + +typedef void (*destroy_user_data_func)(void *user_data); + +/* Shadow structure for grpc_mdstr for non-static values */ +typedef struct internal_string { + /* must be byte compatible with grpc_mdstr */ + gpr_slice slice; + uint32_t hash; + + /* private only data */ + gpr_atm refcnt; + + uint8_t has_base64_and_huffman_encoded; + gpr_slice_refcount refcount; + + gpr_slice base64_and_huffman; + + struct internal_string *bucket_next; +} internal_string; + +/* Shadow structure for grpc_mdelem for non-static elements */ +typedef struct internal_metadata { + /* must be byte compatible with grpc_mdelem */ + internal_string *key; + internal_string *value; + + /* private only data */ + gpr_atm refcnt; + + gpr_mu mu_user_data; + gpr_atm destroy_user_data; + gpr_atm user_data; + + struct internal_metadata *bucket_next; +} internal_metadata; + +typedef struct strtab_shard { + gpr_mu mu; + internal_string **strs; + size_t count; + size_t capacity; +} strtab_shard; + +typedef struct mdtab_shard { + gpr_mu mu; + internal_metadata **elems; + size_t count; + size_t capacity; + size_t free; +} mdtab_shard; + +#define LOG2_STRTAB_SHARD_COUNT 5 +#define LOG2_MDTAB_SHARD_COUNT 4 +#define STRTAB_SHARD_COUNT ((size_t)(1 << LOG2_STRTAB_SHARD_COUNT)) +#define MDTAB_SHARD_COUNT ((size_t)(1 << LOG2_MDTAB_SHARD_COUNT)) + +/* hash seed: decided at initialization time */ +static uint32_t g_hash_seed; +static int g_forced_hash_seed = 0; + +/* linearly probed hash tables for static element lookup */ +static grpc_mdstr *g_static_strtab[GRPC_STATIC_MDSTR_COUNT * 2]; +static grpc_mdelem *g_static_mdtab[GRPC_STATIC_MDELEM_COUNT * 2]; +static size_t g_static_strtab_maxprobe; +static size_t g_static_mdtab_maxprobe; + +static strtab_shard g_strtab_shard[STRTAB_SHARD_COUNT]; +static mdtab_shard g_mdtab_shard[MDTAB_SHARD_COUNT]; + +static void gc_mdtab(mdtab_shard *shard); + +void grpc_test_only_set_metadata_hash_seed(uint32_t seed) { + g_hash_seed = seed; + g_forced_hash_seed = 1; +} + +void grpc_mdctx_global_init(void) { + size_t i, j; + if (!g_forced_hash_seed) { + g_hash_seed = (uint32_t)gpr_now(GPR_CLOCK_REALTIME).tv_nsec; + } + g_static_strtab_maxprobe = 0; + g_static_mdtab_maxprobe = 0; + /* build static tables */ + memset(g_static_mdtab, 0, sizeof(g_static_mdtab)); + memset(g_static_strtab, 0, sizeof(g_static_strtab)); + for (i = 0; i < GRPC_STATIC_MDSTR_COUNT; i++) { + grpc_mdstr *elem = &grpc_static_mdstr_table[i]; + const char *str = grpc_static_metadata_strings[i]; + uint32_t hash = gpr_murmur_hash3(str, strlen(str), g_hash_seed); + *(gpr_slice *)&elem->slice = gpr_slice_from_static_string(str); + *(uint32_t *)&elem->hash = hash; + for (j = 0;; j++) { + size_t idx = (hash + j) % GPR_ARRAY_SIZE(g_static_strtab); + if (g_static_strtab[idx] == NULL) { + g_static_strtab[idx] = &grpc_static_mdstr_table[i]; + break; + } + } + if (j > g_static_strtab_maxprobe) { + g_static_strtab_maxprobe = j; + } + } + for (i = 0; i < GRPC_STATIC_MDELEM_COUNT; i++) { + grpc_mdelem *elem = &grpc_static_mdelem_table[i]; + grpc_mdstr *key = + &grpc_static_mdstr_table[grpc_static_metadata_elem_indices[2 * i + 0]]; + grpc_mdstr *value = + &grpc_static_mdstr_table[grpc_static_metadata_elem_indices[2 * i + 1]]; + uint32_t hash = GRPC_MDSTR_KV_HASH(key->hash, value->hash); + *(grpc_mdstr **)&elem->key = key; + *(grpc_mdstr **)&elem->value = value; + for (j = 0;; j++) { + size_t idx = (hash + j) % GPR_ARRAY_SIZE(g_static_mdtab); + if (g_static_mdtab[idx] == NULL) { + g_static_mdtab[idx] = elem; + break; + } + } + if (j > g_static_mdtab_maxprobe) { + g_static_mdtab_maxprobe = j; + } + } + /* initialize shards */ + for (i = 0; i < STRTAB_SHARD_COUNT; i++) { + strtab_shard *shard = &g_strtab_shard[i]; + gpr_mu_init(&shard->mu); + shard->count = 0; + shard->capacity = INITIAL_STRTAB_CAPACITY; + shard->strs = gpr_malloc(sizeof(*shard->strs) * shard->capacity); + memset(shard->strs, 0, sizeof(*shard->strs) * shard->capacity); + } + for (i = 0; i < MDTAB_SHARD_COUNT; i++) { + mdtab_shard *shard = &g_mdtab_shard[i]; + gpr_mu_init(&shard->mu); + shard->count = 0; + shard->free = 0; + shard->capacity = INITIAL_MDTAB_CAPACITY; + shard->elems = gpr_malloc(sizeof(*shard->elems) * shard->capacity); + memset(shard->elems, 0, sizeof(*shard->elems) * shard->capacity); + } +} + +void grpc_mdctx_global_shutdown(void) { + size_t i; + for (i = 0; i < MDTAB_SHARD_COUNT; i++) { + mdtab_shard *shard = &g_mdtab_shard[i]; + gpr_mu_destroy(&shard->mu); + gc_mdtab(shard); + /* TODO(ctiller): GPR_ASSERT(shard->count == 0); */ + if (shard->count != 0) { + gpr_log(GPR_DEBUG, "WARNING: %d metadata elements were leaked", + shard->count); + if (grpc_iomgr_abort_on_leaks()) { + abort(); + } + } + gpr_free(shard->elems); + } + for (i = 0; i < STRTAB_SHARD_COUNT; i++) { + strtab_shard *shard = &g_strtab_shard[i]; + 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", + shard->count); + if (grpc_iomgr_abort_on_leaks()) { + abort(); + } + } + gpr_free(shard->strs); + } +} + +static int is_mdstr_static(grpc_mdstr *s) { + return s >= &grpc_static_mdstr_table[0] && + s < &grpc_static_mdstr_table[GRPC_STATIC_MDSTR_COUNT]; +} + +static int is_mdelem_static(grpc_mdelem *e) { + return e >= &grpc_static_mdelem_table[0] && + e < &grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT]; +} + +static void ref_md_locked(mdtab_shard *shard, + internal_metadata *md DEBUG_ARGS) { +#ifdef GRPC_METADATA_REFCOUNT_DEBUG + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, + "ELM REF:%p:%d->%d: '%s' = '%s'", md, + gpr_atm_no_barrier_load(&md->refcnt), + gpr_atm_no_barrier_load(&md->refcnt) + 1, + grpc_mdstr_as_c_string((grpc_mdstr *)md->key), + grpc_mdstr_as_c_string((grpc_mdstr *)md->value)); +#endif + if (0 == gpr_atm_no_barrier_fetch_add(&md->refcnt, 2)) { + shard->free--; + } else { + GPR_ASSERT(1 != gpr_atm_no_barrier_fetch_add(&md->refcnt, -1)); + } +} + +static void grow_strtab(strtab_shard *shard) { + size_t capacity = shard->capacity * 2; + size_t i; + internal_string **strtab; + internal_string *s, *next; + + GPR_TIMER_BEGIN("grow_strtab", 0); + + strtab = gpr_malloc(sizeof(internal_string *) * capacity); + memset(strtab, 0, sizeof(internal_string *) * capacity); + + for (i = 0; i < shard->capacity; i++) { + for (s = shard->strs[i]; s; s = next) { + size_t idx = TABLE_IDX(s->hash, LOG2_STRTAB_SHARD_COUNT, capacity); + next = s->bucket_next; + s->bucket_next = strtab[idx]; + strtab[idx] = s; + } + } + + gpr_free(shard->strs); + shard->strs = strtab; + shard->capacity = capacity; + + GPR_TIMER_END("grow_strtab", 0); +} + +static void internal_destroy_string(strtab_shard *shard, internal_string *is) { + internal_string **prev_next; + internal_string *cur; + GPR_TIMER_BEGIN("internal_destroy_string", 0); + if (is->has_base64_and_huffman_encoded) { + gpr_slice_unref(is->base64_and_huffman); + } + for (prev_next = &shard->strs[TABLE_IDX(is->hash, LOG2_STRTAB_SHARD_COUNT, + shard->capacity)], + cur = *prev_next; + cur != is; prev_next = &cur->bucket_next, cur = cur->bucket_next) + ; + *prev_next = cur->bucket_next; + shard->count--; + gpr_free(is); + GPR_TIMER_END("internal_destroy_string", 0); +} + +static void slice_ref(void *p) { + internal_string *is = + (internal_string *)((char *)p - offsetof(internal_string, refcount)); + GRPC_MDSTR_REF((grpc_mdstr *)(is)); +} + +static void slice_unref(void *p) { + internal_string *is = + (internal_string *)((char *)p - offsetof(internal_string, refcount)); + GRPC_MDSTR_UNREF((grpc_mdstr *)(is)); +} + +grpc_mdstr *grpc_mdstr_from_string(const char *str) { + return grpc_mdstr_from_buffer((const uint8_t *)str, strlen(str)); +} + +grpc_mdstr *grpc_mdstr_from_slice(gpr_slice slice) { + grpc_mdstr *result = grpc_mdstr_from_buffer(GPR_SLICE_START_PTR(slice), + GPR_SLICE_LENGTH(slice)); + gpr_slice_unref(slice); + return result; +} + +grpc_mdstr *grpc_mdstr_from_buffer(const uint8_t *buf, size_t length) { + uint32_t hash = gpr_murmur_hash3(buf, length, g_hash_seed); + internal_string *s; + strtab_shard *shard = + &g_strtab_shard[SHARD_IDX(hash, LOG2_STRTAB_SHARD_COUNT)]; + size_t i; + size_t idx; + + GPR_TIMER_BEGIN("grpc_mdstr_from_buffer", 0); + + /* search for a static string */ + for (i = 0; i <= g_static_strtab_maxprobe; i++) { + grpc_mdstr *ss; + idx = (hash + i) % GPR_ARRAY_SIZE(g_static_strtab); + ss = g_static_strtab[idx]; + if (ss == NULL) break; + if (ss->hash == hash && GPR_SLICE_LENGTH(ss->slice) == length && + 0 == memcmp(buf, GPR_SLICE_START_PTR(ss->slice), length)) { + GPR_TIMER_END("grpc_mdstr_from_buffer", 0); + return ss; + } + } + + gpr_mu_lock(&shard->mu); + + /* search for an existing string */ + idx = TABLE_IDX(hash, LOG2_STRTAB_SHARD_COUNT, shard->capacity); + for (s = shard->strs[idx]; s; s = s->bucket_next) { + if (s->hash == hash && GPR_SLICE_LENGTH(s->slice) == length && + 0 == memcmp(buf, GPR_SLICE_START_PTR(s->slice), length)) { + GRPC_MDSTR_REF((grpc_mdstr *)s); + gpr_mu_unlock(&shard->mu); + GPR_TIMER_END("grpc_mdstr_from_buffer", 0); + return (grpc_mdstr *)s; + } + } + + /* not found: create a new string */ + if (length + 1 < GPR_SLICE_INLINED_SIZE) { + /* string data goes directly into the slice */ + s = gpr_malloc(sizeof(internal_string)); + gpr_atm_rel_store(&s->refcnt, 2); + s->slice.refcount = NULL; + memcpy(s->slice.data.inlined.bytes, buf, length); + s->slice.data.inlined.bytes[length] = 0; + s->slice.data.inlined.length = (uint8_t)length; + } else { + /* string data goes after the internal_string header, and we +1 for null + terminator */ + s = gpr_malloc(sizeof(internal_string) + length + 1); + gpr_atm_rel_store(&s->refcnt, 2); + s->refcount.ref = slice_ref; + s->refcount.unref = slice_unref; + s->slice.refcount = &s->refcount; + s->slice.data.refcounted.bytes = (uint8_t *)(s + 1); + s->slice.data.refcounted.length = length; + memcpy(s->slice.data.refcounted.bytes, buf, length); + /* add a null terminator for cheap c string conversion when desired */ + s->slice.data.refcounted.bytes[length] = 0; + } + s->has_base64_and_huffman_encoded = 0; + s->hash = hash; + s->bucket_next = shard->strs[idx]; + shard->strs[idx] = s; + + shard->count++; + + if (shard->count > shard->capacity * 2) { + grow_strtab(shard); + } + + gpr_mu_unlock(&shard->mu); + GPR_TIMER_END("grpc_mdstr_from_buffer", 0); + + return (grpc_mdstr *)s; +} + +static void gc_mdtab(mdtab_shard *shard) { + size_t i; + internal_metadata **prev_next; + internal_metadata *md, *next; + + GPR_TIMER_BEGIN("gc_mdtab", 0); + for (i = 0; i < shard->capacity; i++) { + prev_next = &shard->elems[i]; + for (md = shard->elems[i]; md; md = next) { + void *user_data = (void *)gpr_atm_no_barrier_load(&md->user_data); + next = md->bucket_next; + if (gpr_atm_acq_load(&md->refcnt) == 0) { + GRPC_MDSTR_UNREF((grpc_mdstr *)md->key); + GRPC_MDSTR_UNREF((grpc_mdstr *)md->value); + if (md->user_data) { + ((destroy_user_data_func)gpr_atm_no_barrier_load( + &md->destroy_user_data))(user_data); + } + gpr_free(md); + *prev_next = next; + shard->free--; + shard->count--; + } else { + prev_next = &md->bucket_next; + } + } + } + GPR_TIMER_END("gc_mdtab", 0); +} + +static void grow_mdtab(mdtab_shard *shard) { + size_t capacity = shard->capacity * 2; + size_t i; + internal_metadata **mdtab; + internal_metadata *md, *next; + uint32_t hash; + + GPR_TIMER_BEGIN("grow_mdtab", 0); + + mdtab = gpr_malloc(sizeof(internal_metadata *) * capacity); + memset(mdtab, 0, sizeof(internal_metadata *) * capacity); + + for (i = 0; i < shard->capacity; i++) { + for (md = shard->elems[i]; md; md = next) { + size_t idx; + hash = GRPC_MDSTR_KV_HASH(md->key->hash, md->value->hash); + next = md->bucket_next; + idx = TABLE_IDX(hash, LOG2_MDTAB_SHARD_COUNT, capacity); + md->bucket_next = mdtab[idx]; + mdtab[idx] = md; + } + } + + gpr_free(shard->elems); + shard->elems = mdtab; + shard->capacity = capacity; + + GPR_TIMER_END("grow_mdtab", 0); +} + +static void rehash_mdtab(mdtab_shard *shard) { + if (shard->free > shard->capacity / 4) { + gc_mdtab(shard); + } else { + grow_mdtab(shard); + } +} + +grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdstr *mkey, + grpc_mdstr *mvalue) { + internal_string *key = (internal_string *)mkey; + internal_string *value = (internal_string *)mvalue; + uint32_t hash = GRPC_MDSTR_KV_HASH(mkey->hash, mvalue->hash); + internal_metadata *md; + mdtab_shard *shard = &g_mdtab_shard[SHARD_IDX(hash, LOG2_MDTAB_SHARD_COUNT)]; + size_t i; + size_t idx; + + GPR_TIMER_BEGIN("grpc_mdelem_from_metadata_strings", 0); + + if (is_mdstr_static(mkey) && is_mdstr_static(mvalue)) { + for (i = 0; i <= g_static_mdtab_maxprobe; i++) { + grpc_mdelem *smd; + idx = (hash + i) % GPR_ARRAY_SIZE(g_static_mdtab); + smd = g_static_mdtab[idx]; + if (smd == NULL) break; + if (smd->key == mkey && smd->value == mvalue) { + GPR_TIMER_END("grpc_mdelem_from_metadata_strings", 0); + return smd; + } + } + } + + gpr_mu_lock(&shard->mu); + + idx = TABLE_IDX(hash, LOG2_MDTAB_SHARD_COUNT, shard->capacity); + /* search for an existing pair */ + for (md = shard->elems[idx]; md; md = md->bucket_next) { + if (md->key == key && md->value == value) { + REF_MD_LOCKED(shard, md); + GRPC_MDSTR_UNREF((grpc_mdstr *)key); + GRPC_MDSTR_UNREF((grpc_mdstr *)value); + gpr_mu_unlock(&shard->mu); + GPR_TIMER_END("grpc_mdelem_from_metadata_strings", 0); + return (grpc_mdelem *)md; + } + } + + /* not found: create a new pair */ + md = gpr_malloc(sizeof(internal_metadata)); + gpr_atm_rel_store(&md->refcnt, 2); + md->key = key; + md->value = value; + md->user_data = 0; + md->destroy_user_data = 0; + md->bucket_next = shard->elems[idx]; + shard->elems[idx] = md; + gpr_mu_init(&md->mu_user_data); +#ifdef GRPC_METADATA_REFCOUNT_DEBUG + gpr_log(GPR_DEBUG, "ELM NEW:%p:%d: '%s' = '%s'", md, + gpr_atm_no_barrier_load(&md->refcnt), + grpc_mdstr_as_c_string((grpc_mdstr *)md->key), + grpc_mdstr_as_c_string((grpc_mdstr *)md->value)); +#endif + shard->count++; + + if (shard->count > shard->capacity * 2) { + rehash_mdtab(shard); + } + + gpr_mu_unlock(&shard->mu); + + GPR_TIMER_END("grpc_mdelem_from_metadata_strings", 0); + + return (grpc_mdelem *)md; +} + +grpc_mdelem *grpc_mdelem_from_strings(const char *key, const char *value) { + return grpc_mdelem_from_metadata_strings(grpc_mdstr_from_string(key), + grpc_mdstr_from_string(value)); +} + +grpc_mdelem *grpc_mdelem_from_slices(gpr_slice key, gpr_slice value) { + return grpc_mdelem_from_metadata_strings(grpc_mdstr_from_slice(key), + grpc_mdstr_from_slice(value)); +} + +grpc_mdelem *grpc_mdelem_from_string_and_buffer(const char *key, + const uint8_t *value, + size_t value_length) { + return grpc_mdelem_from_metadata_strings( + grpc_mdstr_from_string(key), grpc_mdstr_from_buffer(value, value_length)); +} + +grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *gmd DEBUG_ARGS) { + internal_metadata *md = (internal_metadata *)gmd; + if (is_mdelem_static(gmd)) return gmd; +#ifdef GRPC_METADATA_REFCOUNT_DEBUG + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, + "ELM REF:%p:%d->%d: '%s' = '%s'", md, + gpr_atm_no_barrier_load(&md->refcnt), + gpr_atm_no_barrier_load(&md->refcnt) + 1, + grpc_mdstr_as_c_string((grpc_mdstr *)md->key), + grpc_mdstr_as_c_string((grpc_mdstr *)md->value)); +#endif + /* we can assume the ref count is >= 1 as the application is calling + this function - meaning that no adjustment to mdtab_free is necessary, + simplifying the logic here to be just an atomic increment */ + /* use C assert to have this removed in opt builds */ + assert(gpr_atm_no_barrier_load(&md->refcnt) >= 2); + gpr_atm_no_barrier_fetch_add(&md->refcnt, 1); + return gmd; +} + +void grpc_mdelem_unref(grpc_mdelem *gmd DEBUG_ARGS) { + internal_metadata *md = (internal_metadata *)gmd; + if (!md) return; + if (is_mdelem_static(gmd)) return; +#ifdef GRPC_METADATA_REFCOUNT_DEBUG + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, + "ELM UNREF:%p:%d->%d: '%s' = '%s'", md, + gpr_atm_no_barrier_load(&md->refcnt), + gpr_atm_no_barrier_load(&md->refcnt) - 1, + grpc_mdstr_as_c_string((grpc_mdstr *)md->key), + grpc_mdstr_as_c_string((grpc_mdstr *)md->value)); +#endif + if (2 == gpr_atm_full_fetch_add(&md->refcnt, -1)) { + uint32_t hash = GRPC_MDSTR_KV_HASH(md->key->hash, md->value->hash); + mdtab_shard *shard = + &g_mdtab_shard[SHARD_IDX(hash, LOG2_MDTAB_SHARD_COUNT)]; + GPR_TIMER_BEGIN("grpc_mdelem_unref.to_zero", 0); + gpr_mu_lock(&shard->mu); + if (1 == gpr_atm_no_barrier_load(&md->refcnt)) { + shard->free++; + gpr_atm_no_barrier_store(&md->refcnt, 0); + } + gpr_mu_unlock(&shard->mu); + GPR_TIMER_END("grpc_mdelem_unref.to_zero", 0); + } +} + +const char *grpc_mdstr_as_c_string(grpc_mdstr *s) { + return (const char *)GPR_SLICE_START_PTR(s->slice); +} + +grpc_mdstr *grpc_mdstr_ref(grpc_mdstr *gs DEBUG_ARGS) { + internal_string *s = (internal_string *)gs; + if (is_mdstr_static(gs)) return gs; + GPR_ASSERT(gpr_atm_full_fetch_add(&s->refcnt, 1) != 0); + return gs; +} + +void grpc_mdstr_unref(grpc_mdstr *gs DEBUG_ARGS) { + internal_string *s = (internal_string *)gs; + if (is_mdstr_static(gs)) return; + if (2 == gpr_atm_full_fetch_add(&s->refcnt, -1)) { + strtab_shard *shard = + &g_strtab_shard[SHARD_IDX(s->hash, LOG2_STRTAB_SHARD_COUNT)]; + gpr_mu_lock(&shard->mu); + if (1 == gpr_atm_no_barrier_load(&s->refcnt)) { + internal_destroy_string(shard, s); + } + gpr_mu_unlock(&shard->mu); + } +} + +void *grpc_mdelem_get_user_data(grpc_mdelem *md, void (*destroy_func)(void *)) { + internal_metadata *im = (internal_metadata *)md; + void *result; + if (is_mdelem_static(md)) { + return (void *)grpc_static_mdelem_user_data[md - grpc_static_mdelem_table]; + } + if (gpr_atm_acq_load(&im->destroy_user_data) == (gpr_atm)destroy_func) { + return (void *)gpr_atm_no_barrier_load(&im->user_data); + } else { + return NULL; + } + return result; +} + +void grpc_mdelem_set_user_data(grpc_mdelem *md, void (*destroy_func)(void *), + void *user_data) { + internal_metadata *im = (internal_metadata *)md; + GPR_ASSERT(!is_mdelem_static(md)); + GPR_ASSERT((user_data == NULL) == (destroy_func == NULL)); + gpr_mu_lock(&im->mu_user_data); + if (gpr_atm_no_barrier_load(&im->destroy_user_data)) { + /* user data can only be set once */ + gpr_mu_unlock(&im->mu_user_data); + if (destroy_func != NULL) { + destroy_func(user_data); + } + return; + } + gpr_atm_no_barrier_store(&im->user_data, (gpr_atm)user_data); + gpr_atm_rel_store(&im->destroy_user_data, (gpr_atm)destroy_func); + gpr_mu_unlock(&im->mu_user_data); +} + +gpr_slice grpc_mdstr_as_base64_encoded_and_huffman_compressed(grpc_mdstr *gs) { + internal_string *s = (internal_string *)gs; + gpr_slice slice; + strtab_shard *shard = + &g_strtab_shard[SHARD_IDX(s->hash, LOG2_STRTAB_SHARD_COUNT)]; + gpr_mu_lock(&shard->mu); + if (!s->has_base64_and_huffman_encoded) { + s->base64_and_huffman = + grpc_chttp2_base64_encode_and_huffman_compress(s->slice); + s->has_base64_and_huffman_encoded = 1; + } + slice = s->base64_and_huffman; + gpr_mu_unlock(&shard->mu); + return slice; +} diff --git a/src/core/lib/transport/metadata.h b/src/core/lib/transport/metadata.h new file mode 100644 index 0000000000..5ab397848c --- /dev/null +++ b/src/core/lib/transport/metadata.h @@ -0,0 +1,156 @@ +/* + * + * Copyright 2015-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_TRANSPORT_METADATA_H +#define GRPC_CORE_TRANSPORT_METADATA_H + +#include +#include + +/* This file provides a mechanism for tracking metadata through the grpc stack. + It's not intended for consumption outside of the library. + + Metadata is tracked in the context of a grpc_mdctx. For the time being there + is one of these per-channel, avoiding cross channel interference with memory + use and lock contention. + + The context tracks unique strings (grpc_mdstr) and pairs of strings + (grpc_mdelem). Any of these objects can be checked for equality by comparing + their pointers. These objects are reference counted. + + grpc_mdelem can additionally store a (non-NULL) user data pointer. This + pointer is intended to be used to cache semantic meaning of a metadata + element. For example, an OAuth token may cache the credentials it represents + and the time at which it expires in the mdelem user data. + + Combining this metadata cache and the hpack compression table allows us to + simply lookup complete preparsed objects quickly, incurring a few atomic + ops per metadata element on the fast path. + + grpc_mdelem instances MAY live longer than their refcount implies, and are + garbage collected periodically, meaning cached data can easily outlive a + single request. + + STATIC METADATA: in static_metadata.h we declare a set of static metadata. + These mdelems and mdstrs are available via pre-declared code generated macros + and are available to code anywhere between grpc_init() and grpc_shutdown(). + They are not refcounted, but can be passed to _ref and _unref functions + declared here - in which case those functions are effectively no-ops. */ + +/* Forward declarations */ +typedef struct grpc_mdstr grpc_mdstr; +typedef struct grpc_mdelem grpc_mdelem; + +/* if changing this, make identical changes in internal_string in metadata.c */ +struct grpc_mdstr { + const gpr_slice slice; + const uint32_t hash; + /* there is a private part to this in metadata.c */ +}; + +/* if changing this, make identical changes in internal_metadata in + metadata.c */ +struct grpc_mdelem { + grpc_mdstr *const key; + grpc_mdstr *const value; + /* there is a private part to this in metadata.c */ +}; + +void grpc_test_only_set_metadata_hash_seed(uint32_t seed); + +/* Constructors for grpc_mdstr instances; take a variety of data types that + clients may have handy */ +grpc_mdstr *grpc_mdstr_from_string(const char *str); +/* Unrefs the slice. */ +grpc_mdstr *grpc_mdstr_from_slice(gpr_slice slice); +grpc_mdstr *grpc_mdstr_from_buffer(const uint8_t *str, size_t length); + +/* Returns a borrowed slice from the mdstr with its contents base64 encoded + and huffman compressed */ +gpr_slice grpc_mdstr_as_base64_encoded_and_huffman_compressed(grpc_mdstr *str); + +/* Constructors for grpc_mdelem instances; take a variety of data types that + clients may have handy */ +grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdstr *key, + grpc_mdstr *value); +grpc_mdelem *grpc_mdelem_from_strings(const char *key, const char *value); +/* Unrefs the slices. */ +grpc_mdelem *grpc_mdelem_from_slices(gpr_slice key, gpr_slice value); +grpc_mdelem *grpc_mdelem_from_string_and_buffer(const char *key, + const uint8_t *value, + size_t value_length); + +/* Mutator and accessor for grpc_mdelem user data. The destructor function + is used as a type tag and is checked during user_data fetch. */ +void *grpc_mdelem_get_user_data(grpc_mdelem *md, + void (*if_destroy_func)(void *)); +void grpc_mdelem_set_user_data(grpc_mdelem *md, void (*destroy_func)(void *), + void *user_data); + +/* Reference counting */ +#ifdef GRPC_METADATA_REFCOUNT_DEBUG +#define GRPC_MDSTR_REF(s) grpc_mdstr_ref((s), __FILE__, __LINE__) +#define GRPC_MDSTR_UNREF(s) grpc_mdstr_unref((s), __FILE__, __LINE__) +#define GRPC_MDELEM_REF(s) grpc_mdelem_ref((s), __FILE__, __LINE__) +#define GRPC_MDELEM_UNREF(s) grpc_mdelem_unref((s), __FILE__, __LINE__) +grpc_mdstr *grpc_mdstr_ref(grpc_mdstr *s, const char *file, int line); +void grpc_mdstr_unref(grpc_mdstr *s, const char *file, int line); +grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *md, const char *file, int line); +void grpc_mdelem_unref(grpc_mdelem *md, const char *file, int line); +#else +#define GRPC_MDSTR_REF(s) grpc_mdstr_ref((s)) +#define GRPC_MDSTR_UNREF(s) grpc_mdstr_unref((s)) +#define GRPC_MDELEM_REF(s) grpc_mdelem_ref((s)) +#define GRPC_MDELEM_UNREF(s) grpc_mdelem_unref((s)) +grpc_mdstr *grpc_mdstr_ref(grpc_mdstr *s); +void grpc_mdstr_unref(grpc_mdstr *s); +grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *md); +void grpc_mdelem_unref(grpc_mdelem *md); +#endif + +/* Recover a char* from a grpc_mdstr. The returned string is null terminated. + Does not promise that the returned string has no embedded nulls however. */ +const char *grpc_mdstr_as_c_string(grpc_mdstr *s); + +#define GRPC_MDSTR_LENGTH(s) (GPR_SLICE_LENGTH(s->slice)) + +int grpc_mdstr_is_legal_header(grpc_mdstr *s); +int grpc_mdstr_is_legal_nonbin_header(grpc_mdstr *s); +int grpc_mdstr_is_bin_suffixed(grpc_mdstr *s); + +#define GRPC_MDSTR_KV_HASH(k_hash, v_hash) (GPR_ROTL((k_hash), 2) ^ (v_hash)) + +void grpc_mdctx_global_init(void); +void grpc_mdctx_global_shutdown(void); + +#endif /* GRPC_CORE_TRANSPORT_METADATA_H */ diff --git a/src/core/lib/transport/metadata_batch.c b/src/core/lib/transport/metadata_batch.c new file mode 100644 index 0000000000..1266862f82 --- /dev/null +++ b/src/core/lib/transport/metadata_batch.c @@ -0,0 +1,194 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/transport/metadata_batch.h" + +#include + +#include +#include + +#include "src/core/profiling/timers.h" + +static void assert_valid_list(grpc_mdelem_list *list) { +#ifndef NDEBUG + grpc_linked_mdelem *l; + + GPR_ASSERT((list->head == NULL) == (list->tail == NULL)); + if (!list->head) return; + GPR_ASSERT(list->head->prev == NULL); + GPR_ASSERT(list->tail->next == NULL); + GPR_ASSERT((list->head == list->tail) == (list->head->next == NULL)); + + for (l = list->head; l; l = l->next) { + GPR_ASSERT(l->md); + GPR_ASSERT((l->prev == NULL) == (l == list->head)); + GPR_ASSERT((l->next == NULL) == (l == list->tail)); + if (l->next) GPR_ASSERT(l->next->prev == l); + if (l->prev) GPR_ASSERT(l->prev->next == l); + } +#endif /* NDEBUG */ +} + +#ifndef NDEBUG +void grpc_metadata_batch_assert_ok(grpc_metadata_batch *batch) { + assert_valid_list(&batch->list); +} +#endif /* NDEBUG */ + +void grpc_metadata_batch_init(grpc_metadata_batch *batch) { + batch->list.head = batch->list.tail = NULL; + batch->deadline = gpr_inf_future(GPR_CLOCK_REALTIME); +} + +void grpc_metadata_batch_destroy(grpc_metadata_batch *batch) { + grpc_linked_mdelem *l; + for (l = batch->list.head; l; l = l->next) { + GRPC_MDELEM_UNREF(l->md); + } +} + +void grpc_metadata_batch_add_head(grpc_metadata_batch *batch, + grpc_linked_mdelem *storage, + grpc_mdelem *elem_to_add) { + GPR_ASSERT(elem_to_add); + storage->md = elem_to_add; + grpc_metadata_batch_link_head(batch, storage); +} + +static void link_head(grpc_mdelem_list *list, grpc_linked_mdelem *storage) { + assert_valid_list(list); + GPR_ASSERT(storage->md); + storage->prev = NULL; + storage->next = list->head; + if (list->head != NULL) { + list->head->prev = storage; + } else { + list->tail = storage; + } + list->head = storage; + assert_valid_list(list); +} + +void grpc_metadata_batch_link_head(grpc_metadata_batch *batch, + grpc_linked_mdelem *storage) { + link_head(&batch->list, storage); +} + +void grpc_metadata_batch_add_tail(grpc_metadata_batch *batch, + grpc_linked_mdelem *storage, + grpc_mdelem *elem_to_add) { + GPR_ASSERT(elem_to_add); + storage->md = elem_to_add; + grpc_metadata_batch_link_tail(batch, storage); +} + +static void link_tail(grpc_mdelem_list *list, grpc_linked_mdelem *storage) { + assert_valid_list(list); + GPR_ASSERT(storage->md); + storage->prev = list->tail; + storage->next = NULL; + storage->reserved = NULL; + if (list->tail != NULL) { + list->tail->next = storage; + } else { + list->head = storage; + } + list->tail = storage; + assert_valid_list(list); +} + +void grpc_metadata_batch_link_tail(grpc_metadata_batch *batch, + grpc_linked_mdelem *storage) { + link_tail(&batch->list, storage); +} + +void grpc_metadata_batch_move(grpc_metadata_batch *dst, + grpc_metadata_batch *src) { + *dst = *src; + memset(src, 0, sizeof(grpc_metadata_batch)); +} + +void grpc_metadata_batch_filter(grpc_metadata_batch *batch, + grpc_mdelem *(*filter)(void *user_data, + grpc_mdelem *elem), + void *user_data) { + grpc_linked_mdelem *l; + grpc_linked_mdelem *next; + + GPR_TIMER_BEGIN("grpc_metadata_batch_filter", 0); + + assert_valid_list(&batch->list); + for (l = batch->list.head; l; l = next) { + grpc_mdelem *orig = l->md; + grpc_mdelem *filt = filter(user_data, orig); + next = l->next; + if (filt == NULL) { + if (l->prev) { + l->prev->next = l->next; + } + if (l->next) { + l->next->prev = l->prev; + } + if (batch->list.head == l) { + batch->list.head = l->next; + } + if (batch->list.tail == l) { + batch->list.tail = l->prev; + } + assert_valid_list(&batch->list); + GRPC_MDELEM_UNREF(l->md); + } else if (filt != orig) { + GRPC_MDELEM_UNREF(orig); + l->md = filt; + } + } + assert_valid_list(&batch->list); + + GPR_TIMER_END("grpc_metadata_batch_filter", 0); +} + +static grpc_mdelem *no_metadata_for_you(void *user_data, grpc_mdelem *elem) { + return NULL; +} + +void grpc_metadata_batch_clear(grpc_metadata_batch *batch) { + batch->deadline = gpr_inf_future(GPR_CLOCK_REALTIME); + grpc_metadata_batch_filter(batch, no_metadata_for_you, NULL); +} + +int grpc_metadata_batch_is_empty(grpc_metadata_batch *batch) { + return batch->list.head == NULL && + gpr_time_cmp(gpr_inf_future(batch->deadline.clock_type), + batch->deadline) == 0; +} diff --git a/src/core/lib/transport/metadata_batch.h b/src/core/lib/transport/metadata_batch.h new file mode 100644 index 0000000000..9337b28328 --- /dev/null +++ b/src/core/lib/transport/metadata_batch.h @@ -0,0 +1,125 @@ +/* + * + * Copyright 2015-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_TRANSPORT_METADATA_BATCH_H +#define GRPC_CORE_TRANSPORT_METADATA_BATCH_H + +#include +#include +#include +#include +#include "src/core/transport/metadata.h" + +typedef struct grpc_linked_mdelem { + grpc_mdelem *md; + struct grpc_linked_mdelem *next; + struct grpc_linked_mdelem *prev; + void *reserved; +} grpc_linked_mdelem; + +typedef struct grpc_mdelem_list { + grpc_linked_mdelem *head; + grpc_linked_mdelem *tail; +} grpc_mdelem_list; + +typedef struct grpc_metadata_batch { + /** Metadata elements in this batch */ + grpc_mdelem_list list; + /** Used to calculate grpc-timeout at the point of sending, + or gpr_inf_future if this batch does not need to send a + grpc-timeout */ + gpr_timespec deadline; +} grpc_metadata_batch; + +void grpc_metadata_batch_init(grpc_metadata_batch *batch); +void grpc_metadata_batch_destroy(grpc_metadata_batch *batch); +void grpc_metadata_batch_clear(grpc_metadata_batch *batch); +int grpc_metadata_batch_is_empty(grpc_metadata_batch *batch); + +/** Moves the metadata information from \a src to \a dst. Upon return, \a src is + * zeroed. */ +void grpc_metadata_batch_move(grpc_metadata_batch *dst, + grpc_metadata_batch *src); + +/** Add \a storage to the beginning of \a batch. storage->md is + assumed to be valid. + \a storage is owned by the caller and must survive for the + lifetime of batch. This usually means it should be around + for the lifetime of the call. */ +void grpc_metadata_batch_link_head(grpc_metadata_batch *batch, + grpc_linked_mdelem *storage); +/** Add \a storage to the end of \a batch. storage->md is + assumed to be valid. + \a storage is owned by the caller and must survive for the + lifetime of batch. This usually means it should be around + for the lifetime of the call. */ +void grpc_metadata_batch_link_tail(grpc_metadata_batch *batch, + grpc_linked_mdelem *storage); + +/** Add \a elem_to_add as the first element in \a batch, using + \a storage as backing storage for the linked list element. + \a storage is owned by the caller and must survive for the + lifetime of batch. This usually means it should be around + for the lifetime of the call. + Takes ownership of \a elem_to_add */ +void grpc_metadata_batch_add_head(grpc_metadata_batch *batch, + grpc_linked_mdelem *storage, + grpc_mdelem *elem_to_add); +/** Add \a elem_to_add as the last element in \a batch, using + \a storage as backing storage for the linked list element. + \a storage is owned by the caller and must survive for the + lifetime of batch. This usually means it should be around + for the lifetime of the call. + Takes ownership of \a elem_to_add */ +void grpc_metadata_batch_add_tail(grpc_metadata_batch *batch, + grpc_linked_mdelem *storage, + grpc_mdelem *elem_to_add); + +/** For each element in \a batch, execute \a filter. + The return value from \a filter will be substituted for the + grpc_mdelem passed to \a filter. If \a filter returns NULL, + the element will be moved to the garbage list. */ +void grpc_metadata_batch_filter(grpc_metadata_batch *batch, + grpc_mdelem *(*filter)(void *user_data, + grpc_mdelem *elem), + void *user_data); + +#ifndef NDEBUG +void grpc_metadata_batch_assert_ok(grpc_metadata_batch *comd); +#else +#define grpc_metadata_batch_assert_ok(comd) \ + do { \ + } while (0) +#endif + +#endif /* GRPC_CORE_TRANSPORT_METADATA_BATCH_H */ diff --git a/src/core/lib/transport/static_metadata.c b/src/core/lib/transport/static_metadata.c new file mode 100644 index 0000000000..30bbb89880 --- /dev/null +++ b/src/core/lib/transport/static_metadata.c @@ -0,0 +1,160 @@ +/* + * + * Copyright 2015-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. + * + */ + +/* + * WARNING: Auto-generated code. + * + * To make changes to this file, change + * tools/codegen/core/gen_static_metadata.py, + * and then re-run it. + * + * See metadata.h for an explanation of the interface here, and metadata.c for + * an + * explanation of what's going on. + */ + +#include "src/core/transport/static_metadata.h" + +grpc_mdstr grpc_static_mdstr_table[GRPC_STATIC_MDSTR_COUNT]; + +grpc_mdelem grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT]; +uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 4, 8, 6, 2, 4, 8, 6, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +const uint8_t grpc_static_metadata_elem_indices[GRPC_STATIC_MDELEM_COUNT * 2] = + {11, 35, 10, 35, 12, 35, 12, 49, 13, 35, 14, 35, 15, 35, 16, 35, 17, 35, + 19, 35, 20, 35, 21, 35, 24, 35, 25, 35, 26, 35, 27, 35, 28, 35, 29, 35, + 30, 18, 30, 35, 31, 35, 32, 35, 36, 35, 37, 35, 38, 35, 39, 35, 42, 33, + 42, 34, 42, 48, 42, 53, 42, 54, 42, 55, 42, 56, 43, 33, 43, 48, 43, 53, + 46, 0, 46, 1, 46, 2, 50, 35, 57, 35, 58, 35, 59, 35, 60, 35, 61, 35, + 62, 35, 63, 35, 64, 35, 65, 35, 66, 40, 66, 68, 67, 78, 67, 79, 69, 35, + 70, 35, 71, 35, 72, 35, 73, 35, 74, 35, 75, 41, 75, 51, 75, 52, 76, 35, + 77, 35, 80, 3, 80, 4, 80, 5, 80, 6, 80, 7, 80, 8, 80, 9, 81, 35, + 82, 83, 84, 35, 85, 35, 86, 35, 87, 35, 88, 35}; + +const char *const grpc_static_metadata_strings[GRPC_STATIC_MDSTR_COUNT] = { + "0", + "1", + "2", + "200", + "204", + "206", + "304", + "400", + "404", + "500", + "accept", + "accept-charset", + "accept-encoding", + "accept-language", + "accept-ranges", + "access-control-allow-origin", + "age", + "allow", + "application/grpc", + ":authority", + "authorization", + "cache-control", + "census-bin", + "census-binary-bin", + "content-disposition", + "content-encoding", + "content-language", + "content-length", + "content-location", + "content-range", + "content-type", + "cookie", + "date", + "deflate", + "deflate,gzip", + "", + "etag", + "expect", + "expires", + "from", + "GET", + "grpc", + "grpc-accept-encoding", + "grpc-encoding", + "grpc-internal-encoding-request", + "grpc-message", + "grpc-status", + "grpc-timeout", + "gzip", + "gzip, deflate", + "host", + "http", + "https", + "identity", + "identity,deflate", + "identity,deflate,gzip", + "identity,gzip", + "if-match", + "if-modified-since", + "if-none-match", + "if-range", + "if-unmodified-since", + "last-modified", + "link", + "location", + "max-forwards", + ":method", + ":path", + "POST", + "proxy-authenticate", + "proxy-authorization", + "range", + "referer", + "refresh", + "retry-after", + ":scheme", + "server", + "set-cookie", + "/", + "/index.html", + ":status", + "strict-transport-security", + "te", + "trailers", + "transfer-encoding", + "user-agent", + "vary", + "via", + "www-authenticate"}; + +const uint8_t grpc_static_accept_encoding_metadata[8] = {0, 29, 26, 30, + 28, 32, 27, 31}; diff --git a/src/core/lib/transport/static_metadata.h b/src/core/lib/transport/static_metadata.h new file mode 100644 index 0000000000..85442f8107 --- /dev/null +++ b/src/core/lib/transport/static_metadata.h @@ -0,0 +1,408 @@ +/* + * + * Copyright 2015-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. + * + */ + +/* + * WARNING: Auto-generated code. + * + * To make changes to this file, change + * tools/codegen/core/gen_static_metadata.py, + * and then re-run it. + * + * See metadata.h for an explanation of the interface here, and metadata.c for + * an + * explanation of what's going on. + */ + +#ifndef GRPC_CORE_TRANSPORT_STATIC_METADATA_H +#define GRPC_CORE_TRANSPORT_STATIC_METADATA_H + +#include "src/core/transport/metadata.h" + +#define GRPC_STATIC_MDSTR_COUNT 89 +extern grpc_mdstr grpc_static_mdstr_table[GRPC_STATIC_MDSTR_COUNT]; +/* "0" */ +#define GRPC_MDSTR_0 (&grpc_static_mdstr_table[0]) +/* "1" */ +#define GRPC_MDSTR_1 (&grpc_static_mdstr_table[1]) +/* "2" */ +#define GRPC_MDSTR_2 (&grpc_static_mdstr_table[2]) +/* "200" */ +#define GRPC_MDSTR_200 (&grpc_static_mdstr_table[3]) +/* "204" */ +#define GRPC_MDSTR_204 (&grpc_static_mdstr_table[4]) +/* "206" */ +#define GRPC_MDSTR_206 (&grpc_static_mdstr_table[5]) +/* "304" */ +#define GRPC_MDSTR_304 (&grpc_static_mdstr_table[6]) +/* "400" */ +#define GRPC_MDSTR_400 (&grpc_static_mdstr_table[7]) +/* "404" */ +#define GRPC_MDSTR_404 (&grpc_static_mdstr_table[8]) +/* "500" */ +#define GRPC_MDSTR_500 (&grpc_static_mdstr_table[9]) +/* "accept" */ +#define GRPC_MDSTR_ACCEPT (&grpc_static_mdstr_table[10]) +/* "accept-charset" */ +#define GRPC_MDSTR_ACCEPT_CHARSET (&grpc_static_mdstr_table[11]) +/* "accept-encoding" */ +#define GRPC_MDSTR_ACCEPT_ENCODING (&grpc_static_mdstr_table[12]) +/* "accept-language" */ +#define GRPC_MDSTR_ACCEPT_LANGUAGE (&grpc_static_mdstr_table[13]) +/* "accept-ranges" */ +#define GRPC_MDSTR_ACCEPT_RANGES (&grpc_static_mdstr_table[14]) +/* "access-control-allow-origin" */ +#define GRPC_MDSTR_ACCESS_CONTROL_ALLOW_ORIGIN (&grpc_static_mdstr_table[15]) +/* "age" */ +#define GRPC_MDSTR_AGE (&grpc_static_mdstr_table[16]) +/* "allow" */ +#define GRPC_MDSTR_ALLOW (&grpc_static_mdstr_table[17]) +/* "application/grpc" */ +#define GRPC_MDSTR_APPLICATION_SLASH_GRPC (&grpc_static_mdstr_table[18]) +/* ":authority" */ +#define GRPC_MDSTR_AUTHORITY (&grpc_static_mdstr_table[19]) +/* "authorization" */ +#define GRPC_MDSTR_AUTHORIZATION (&grpc_static_mdstr_table[20]) +/* "cache-control" */ +#define GRPC_MDSTR_CACHE_CONTROL (&grpc_static_mdstr_table[21]) +/* "census-bin" */ +#define GRPC_MDSTR_CENSUS_BIN (&grpc_static_mdstr_table[22]) +/* "census-binary-bin" */ +#define GRPC_MDSTR_CENSUS_BINARY_BIN (&grpc_static_mdstr_table[23]) +/* "content-disposition" */ +#define GRPC_MDSTR_CONTENT_DISPOSITION (&grpc_static_mdstr_table[24]) +/* "content-encoding" */ +#define GRPC_MDSTR_CONTENT_ENCODING (&grpc_static_mdstr_table[25]) +/* "content-language" */ +#define GRPC_MDSTR_CONTENT_LANGUAGE (&grpc_static_mdstr_table[26]) +/* "content-length" */ +#define GRPC_MDSTR_CONTENT_LENGTH (&grpc_static_mdstr_table[27]) +/* "content-location" */ +#define GRPC_MDSTR_CONTENT_LOCATION (&grpc_static_mdstr_table[28]) +/* "content-range" */ +#define GRPC_MDSTR_CONTENT_RANGE (&grpc_static_mdstr_table[29]) +/* "content-type" */ +#define GRPC_MDSTR_CONTENT_TYPE (&grpc_static_mdstr_table[30]) +/* "cookie" */ +#define GRPC_MDSTR_COOKIE (&grpc_static_mdstr_table[31]) +/* "date" */ +#define GRPC_MDSTR_DATE (&grpc_static_mdstr_table[32]) +/* "deflate" */ +#define GRPC_MDSTR_DEFLATE (&grpc_static_mdstr_table[33]) +/* "deflate,gzip" */ +#define GRPC_MDSTR_DEFLATE_COMMA_GZIP (&grpc_static_mdstr_table[34]) +/* "" */ +#define GRPC_MDSTR_EMPTY (&grpc_static_mdstr_table[35]) +/* "etag" */ +#define GRPC_MDSTR_ETAG (&grpc_static_mdstr_table[36]) +/* "expect" */ +#define GRPC_MDSTR_EXPECT (&grpc_static_mdstr_table[37]) +/* "expires" */ +#define GRPC_MDSTR_EXPIRES (&grpc_static_mdstr_table[38]) +/* "from" */ +#define GRPC_MDSTR_FROM (&grpc_static_mdstr_table[39]) +/* "GET" */ +#define GRPC_MDSTR_GET (&grpc_static_mdstr_table[40]) +/* "grpc" */ +#define GRPC_MDSTR_GRPC (&grpc_static_mdstr_table[41]) +/* "grpc-accept-encoding" */ +#define GRPC_MDSTR_GRPC_ACCEPT_ENCODING (&grpc_static_mdstr_table[42]) +/* "grpc-encoding" */ +#define GRPC_MDSTR_GRPC_ENCODING (&grpc_static_mdstr_table[43]) +/* "grpc-internal-encoding-request" */ +#define GRPC_MDSTR_GRPC_INTERNAL_ENCODING_REQUEST (&grpc_static_mdstr_table[44]) +/* "grpc-message" */ +#define GRPC_MDSTR_GRPC_MESSAGE (&grpc_static_mdstr_table[45]) +/* "grpc-status" */ +#define GRPC_MDSTR_GRPC_STATUS (&grpc_static_mdstr_table[46]) +/* "grpc-timeout" */ +#define GRPC_MDSTR_GRPC_TIMEOUT (&grpc_static_mdstr_table[47]) +/* "gzip" */ +#define GRPC_MDSTR_GZIP (&grpc_static_mdstr_table[48]) +/* "gzip, deflate" */ +#define GRPC_MDSTR_GZIP_COMMA_DEFLATE (&grpc_static_mdstr_table[49]) +/* "host" */ +#define GRPC_MDSTR_HOST (&grpc_static_mdstr_table[50]) +/* "http" */ +#define GRPC_MDSTR_HTTP (&grpc_static_mdstr_table[51]) +/* "https" */ +#define GRPC_MDSTR_HTTPS (&grpc_static_mdstr_table[52]) +/* "identity" */ +#define GRPC_MDSTR_IDENTITY (&grpc_static_mdstr_table[53]) +/* "identity,deflate" */ +#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE (&grpc_static_mdstr_table[54]) +/* "identity,deflate,gzip" */ +#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE_COMMA_GZIP \ + (&grpc_static_mdstr_table[55]) +/* "identity,gzip" */ +#define GRPC_MDSTR_IDENTITY_COMMA_GZIP (&grpc_static_mdstr_table[56]) +/* "if-match" */ +#define GRPC_MDSTR_IF_MATCH (&grpc_static_mdstr_table[57]) +/* "if-modified-since" */ +#define GRPC_MDSTR_IF_MODIFIED_SINCE (&grpc_static_mdstr_table[58]) +/* "if-none-match" */ +#define GRPC_MDSTR_IF_NONE_MATCH (&grpc_static_mdstr_table[59]) +/* "if-range" */ +#define GRPC_MDSTR_IF_RANGE (&grpc_static_mdstr_table[60]) +/* "if-unmodified-since" */ +#define GRPC_MDSTR_IF_UNMODIFIED_SINCE (&grpc_static_mdstr_table[61]) +/* "last-modified" */ +#define GRPC_MDSTR_LAST_MODIFIED (&grpc_static_mdstr_table[62]) +/* "link" */ +#define GRPC_MDSTR_LINK (&grpc_static_mdstr_table[63]) +/* "location" */ +#define GRPC_MDSTR_LOCATION (&grpc_static_mdstr_table[64]) +/* "max-forwards" */ +#define GRPC_MDSTR_MAX_FORWARDS (&grpc_static_mdstr_table[65]) +/* ":method" */ +#define GRPC_MDSTR_METHOD (&grpc_static_mdstr_table[66]) +/* ":path" */ +#define GRPC_MDSTR_PATH (&grpc_static_mdstr_table[67]) +/* "POST" */ +#define GRPC_MDSTR_POST (&grpc_static_mdstr_table[68]) +/* "proxy-authenticate" */ +#define GRPC_MDSTR_PROXY_AUTHENTICATE (&grpc_static_mdstr_table[69]) +/* "proxy-authorization" */ +#define GRPC_MDSTR_PROXY_AUTHORIZATION (&grpc_static_mdstr_table[70]) +/* "range" */ +#define GRPC_MDSTR_RANGE (&grpc_static_mdstr_table[71]) +/* "referer" */ +#define GRPC_MDSTR_REFERER (&grpc_static_mdstr_table[72]) +/* "refresh" */ +#define GRPC_MDSTR_REFRESH (&grpc_static_mdstr_table[73]) +/* "retry-after" */ +#define GRPC_MDSTR_RETRY_AFTER (&grpc_static_mdstr_table[74]) +/* ":scheme" */ +#define GRPC_MDSTR_SCHEME (&grpc_static_mdstr_table[75]) +/* "server" */ +#define GRPC_MDSTR_SERVER (&grpc_static_mdstr_table[76]) +/* "set-cookie" */ +#define GRPC_MDSTR_SET_COOKIE (&grpc_static_mdstr_table[77]) +/* "/" */ +#define GRPC_MDSTR_SLASH (&grpc_static_mdstr_table[78]) +/* "/index.html" */ +#define GRPC_MDSTR_SLASH_INDEX_DOT_HTML (&grpc_static_mdstr_table[79]) +/* ":status" */ +#define GRPC_MDSTR_STATUS (&grpc_static_mdstr_table[80]) +/* "strict-transport-security" */ +#define GRPC_MDSTR_STRICT_TRANSPORT_SECURITY (&grpc_static_mdstr_table[81]) +/* "te" */ +#define GRPC_MDSTR_TE (&grpc_static_mdstr_table[82]) +/* "trailers" */ +#define GRPC_MDSTR_TRAILERS (&grpc_static_mdstr_table[83]) +/* "transfer-encoding" */ +#define GRPC_MDSTR_TRANSFER_ENCODING (&grpc_static_mdstr_table[84]) +/* "user-agent" */ +#define GRPC_MDSTR_USER_AGENT (&grpc_static_mdstr_table[85]) +/* "vary" */ +#define GRPC_MDSTR_VARY (&grpc_static_mdstr_table[86]) +/* "via" */ +#define GRPC_MDSTR_VIA (&grpc_static_mdstr_table[87]) +/* "www-authenticate" */ +#define GRPC_MDSTR_WWW_AUTHENTICATE (&grpc_static_mdstr_table[88]) + +#define GRPC_STATIC_MDELEM_COUNT 78 +extern grpc_mdelem grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT]; +extern uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT]; +/* "accept-charset": "" */ +#define GRPC_MDELEM_ACCEPT_CHARSET_EMPTY (&grpc_static_mdelem_table[0]) +/* "accept": "" */ +#define GRPC_MDELEM_ACCEPT_EMPTY (&grpc_static_mdelem_table[1]) +/* "accept-encoding": "" */ +#define GRPC_MDELEM_ACCEPT_ENCODING_EMPTY (&grpc_static_mdelem_table[2]) +/* "accept-encoding": "gzip, deflate" */ +#define GRPC_MDELEM_ACCEPT_ENCODING_GZIP_COMMA_DEFLATE \ + (&grpc_static_mdelem_table[3]) +/* "accept-language": "" */ +#define GRPC_MDELEM_ACCEPT_LANGUAGE_EMPTY (&grpc_static_mdelem_table[4]) +/* "accept-ranges": "" */ +#define GRPC_MDELEM_ACCEPT_RANGES_EMPTY (&grpc_static_mdelem_table[5]) +/* "access-control-allow-origin": "" */ +#define GRPC_MDELEM_ACCESS_CONTROL_ALLOW_ORIGIN_EMPTY \ + (&grpc_static_mdelem_table[6]) +/* "age": "" */ +#define GRPC_MDELEM_AGE_EMPTY (&grpc_static_mdelem_table[7]) +/* "allow": "" */ +#define GRPC_MDELEM_ALLOW_EMPTY (&grpc_static_mdelem_table[8]) +/* ":authority": "" */ +#define GRPC_MDELEM_AUTHORITY_EMPTY (&grpc_static_mdelem_table[9]) +/* "authorization": "" */ +#define GRPC_MDELEM_AUTHORIZATION_EMPTY (&grpc_static_mdelem_table[10]) +/* "cache-control": "" */ +#define GRPC_MDELEM_CACHE_CONTROL_EMPTY (&grpc_static_mdelem_table[11]) +/* "content-disposition": "" */ +#define GRPC_MDELEM_CONTENT_DISPOSITION_EMPTY (&grpc_static_mdelem_table[12]) +/* "content-encoding": "" */ +#define GRPC_MDELEM_CONTENT_ENCODING_EMPTY (&grpc_static_mdelem_table[13]) +/* "content-language": "" */ +#define GRPC_MDELEM_CONTENT_LANGUAGE_EMPTY (&grpc_static_mdelem_table[14]) +/* "content-length": "" */ +#define GRPC_MDELEM_CONTENT_LENGTH_EMPTY (&grpc_static_mdelem_table[15]) +/* "content-location": "" */ +#define GRPC_MDELEM_CONTENT_LOCATION_EMPTY (&grpc_static_mdelem_table[16]) +/* "content-range": "" */ +#define GRPC_MDELEM_CONTENT_RANGE_EMPTY (&grpc_static_mdelem_table[17]) +/* "content-type": "application/grpc" */ +#define GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC \ + (&grpc_static_mdelem_table[18]) +/* "content-type": "" */ +#define GRPC_MDELEM_CONTENT_TYPE_EMPTY (&grpc_static_mdelem_table[19]) +/* "cookie": "" */ +#define GRPC_MDELEM_COOKIE_EMPTY (&grpc_static_mdelem_table[20]) +/* "date": "" */ +#define GRPC_MDELEM_DATE_EMPTY (&grpc_static_mdelem_table[21]) +/* "etag": "" */ +#define GRPC_MDELEM_ETAG_EMPTY (&grpc_static_mdelem_table[22]) +/* "expect": "" */ +#define GRPC_MDELEM_EXPECT_EMPTY (&grpc_static_mdelem_table[23]) +/* "expires": "" */ +#define GRPC_MDELEM_EXPIRES_EMPTY (&grpc_static_mdelem_table[24]) +/* "from": "" */ +#define GRPC_MDELEM_FROM_EMPTY (&grpc_static_mdelem_table[25]) +/* "grpc-accept-encoding": "deflate" */ +#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_DEFLATE (&grpc_static_mdelem_table[26]) +/* "grpc-accept-encoding": "deflate,gzip" */ +#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_DEFLATE_COMMA_GZIP \ + (&grpc_static_mdelem_table[27]) +/* "grpc-accept-encoding": "gzip" */ +#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_GZIP (&grpc_static_mdelem_table[28]) +/* "grpc-accept-encoding": "identity" */ +#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY \ + (&grpc_static_mdelem_table[29]) +/* "grpc-accept-encoding": "identity,deflate" */ +#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE \ + (&grpc_static_mdelem_table[30]) +/* "grpc-accept-encoding": "identity,deflate,gzip" */ +#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE_COMMA_GZIP \ + (&grpc_static_mdelem_table[31]) +/* "grpc-accept-encoding": "identity,gzip" */ +#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_GZIP \ + (&grpc_static_mdelem_table[32]) +/* "grpc-encoding": "deflate" */ +#define GRPC_MDELEM_GRPC_ENCODING_DEFLATE (&grpc_static_mdelem_table[33]) +/* "grpc-encoding": "gzip" */ +#define GRPC_MDELEM_GRPC_ENCODING_GZIP (&grpc_static_mdelem_table[34]) +/* "grpc-encoding": "identity" */ +#define GRPC_MDELEM_GRPC_ENCODING_IDENTITY (&grpc_static_mdelem_table[35]) +/* "grpc-status": "0" */ +#define GRPC_MDELEM_GRPC_STATUS_0 (&grpc_static_mdelem_table[36]) +/* "grpc-status": "1" */ +#define GRPC_MDELEM_GRPC_STATUS_1 (&grpc_static_mdelem_table[37]) +/* "grpc-status": "2" */ +#define GRPC_MDELEM_GRPC_STATUS_2 (&grpc_static_mdelem_table[38]) +/* "host": "" */ +#define GRPC_MDELEM_HOST_EMPTY (&grpc_static_mdelem_table[39]) +/* "if-match": "" */ +#define GRPC_MDELEM_IF_MATCH_EMPTY (&grpc_static_mdelem_table[40]) +/* "if-modified-since": "" */ +#define GRPC_MDELEM_IF_MODIFIED_SINCE_EMPTY (&grpc_static_mdelem_table[41]) +/* "if-none-match": "" */ +#define GRPC_MDELEM_IF_NONE_MATCH_EMPTY (&grpc_static_mdelem_table[42]) +/* "if-range": "" */ +#define GRPC_MDELEM_IF_RANGE_EMPTY (&grpc_static_mdelem_table[43]) +/* "if-unmodified-since": "" */ +#define GRPC_MDELEM_IF_UNMODIFIED_SINCE_EMPTY (&grpc_static_mdelem_table[44]) +/* "last-modified": "" */ +#define GRPC_MDELEM_LAST_MODIFIED_EMPTY (&grpc_static_mdelem_table[45]) +/* "link": "" */ +#define GRPC_MDELEM_LINK_EMPTY (&grpc_static_mdelem_table[46]) +/* "location": "" */ +#define GRPC_MDELEM_LOCATION_EMPTY (&grpc_static_mdelem_table[47]) +/* "max-forwards": "" */ +#define GRPC_MDELEM_MAX_FORWARDS_EMPTY (&grpc_static_mdelem_table[48]) +/* ":method": "GET" */ +#define GRPC_MDELEM_METHOD_GET (&grpc_static_mdelem_table[49]) +/* ":method": "POST" */ +#define GRPC_MDELEM_METHOD_POST (&grpc_static_mdelem_table[50]) +/* ":path": "/" */ +#define GRPC_MDELEM_PATH_SLASH (&grpc_static_mdelem_table[51]) +/* ":path": "/index.html" */ +#define GRPC_MDELEM_PATH_SLASH_INDEX_DOT_HTML (&grpc_static_mdelem_table[52]) +/* "proxy-authenticate": "" */ +#define GRPC_MDELEM_PROXY_AUTHENTICATE_EMPTY (&grpc_static_mdelem_table[53]) +/* "proxy-authorization": "" */ +#define GRPC_MDELEM_PROXY_AUTHORIZATION_EMPTY (&grpc_static_mdelem_table[54]) +/* "range": "" */ +#define GRPC_MDELEM_RANGE_EMPTY (&grpc_static_mdelem_table[55]) +/* "referer": "" */ +#define GRPC_MDELEM_REFERER_EMPTY (&grpc_static_mdelem_table[56]) +/* "refresh": "" */ +#define GRPC_MDELEM_REFRESH_EMPTY (&grpc_static_mdelem_table[57]) +/* "retry-after": "" */ +#define GRPC_MDELEM_RETRY_AFTER_EMPTY (&grpc_static_mdelem_table[58]) +/* ":scheme": "grpc" */ +#define GRPC_MDELEM_SCHEME_GRPC (&grpc_static_mdelem_table[59]) +/* ":scheme": "http" */ +#define GRPC_MDELEM_SCHEME_HTTP (&grpc_static_mdelem_table[60]) +/* ":scheme": "https" */ +#define GRPC_MDELEM_SCHEME_HTTPS (&grpc_static_mdelem_table[61]) +/* "server": "" */ +#define GRPC_MDELEM_SERVER_EMPTY (&grpc_static_mdelem_table[62]) +/* "set-cookie": "" */ +#define GRPC_MDELEM_SET_COOKIE_EMPTY (&grpc_static_mdelem_table[63]) +/* ":status": "200" */ +#define GRPC_MDELEM_STATUS_200 (&grpc_static_mdelem_table[64]) +/* ":status": "204" */ +#define GRPC_MDELEM_STATUS_204 (&grpc_static_mdelem_table[65]) +/* ":status": "206" */ +#define GRPC_MDELEM_STATUS_206 (&grpc_static_mdelem_table[66]) +/* ":status": "304" */ +#define GRPC_MDELEM_STATUS_304 (&grpc_static_mdelem_table[67]) +/* ":status": "400" */ +#define GRPC_MDELEM_STATUS_400 (&grpc_static_mdelem_table[68]) +/* ":status": "404" */ +#define GRPC_MDELEM_STATUS_404 (&grpc_static_mdelem_table[69]) +/* ":status": "500" */ +#define GRPC_MDELEM_STATUS_500 (&grpc_static_mdelem_table[70]) +/* "strict-transport-security": "" */ +#define GRPC_MDELEM_STRICT_TRANSPORT_SECURITY_EMPTY \ + (&grpc_static_mdelem_table[71]) +/* "te": "trailers" */ +#define GRPC_MDELEM_TE_TRAILERS (&grpc_static_mdelem_table[72]) +/* "transfer-encoding": "" */ +#define GRPC_MDELEM_TRANSFER_ENCODING_EMPTY (&grpc_static_mdelem_table[73]) +/* "user-agent": "" */ +#define GRPC_MDELEM_USER_AGENT_EMPTY (&grpc_static_mdelem_table[74]) +/* "vary": "" */ +#define GRPC_MDELEM_VARY_EMPTY (&grpc_static_mdelem_table[75]) +/* "via": "" */ +#define GRPC_MDELEM_VIA_EMPTY (&grpc_static_mdelem_table[76]) +/* "www-authenticate": "" */ +#define GRPC_MDELEM_WWW_AUTHENTICATE_EMPTY (&grpc_static_mdelem_table[77]) + +extern const uint8_t + grpc_static_metadata_elem_indices[GRPC_STATIC_MDELEM_COUNT * 2]; +extern const char *const grpc_static_metadata_strings[GRPC_STATIC_MDSTR_COUNT]; +extern const uint8_t grpc_static_accept_encoding_metadata[8]; +#define GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS(algs) \ + (&grpc_static_mdelem_table[grpc_static_accept_encoding_metadata[(algs)]]) +#endif /* GRPC_CORE_TRANSPORT_STATIC_METADATA_H */ diff --git a/src/core/lib/transport/transport.c b/src/core/lib/transport/transport.c new file mode 100644 index 0000000000..3b555fa933 --- /dev/null +++ b/src/core/lib/transport/transport.c @@ -0,0 +1,184 @@ +/* + * + * Copyright 2015-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/transport/transport.h" +#include +#include +#include +#include "src/core/transport/transport_impl.h" + +#ifdef GRPC_STREAM_REFCOUNT_DEBUG +void grpc_stream_ref(grpc_stream_refcount *refcount, const char *reason) { + gpr_atm val = gpr_atm_no_barrier_load(&refcount->refs.count); + gpr_log(GPR_DEBUG, "%s %p:%p REF %d->%d %s", refcount->object_type, + refcount, refcount->destroy.cb_arg, val, val + 1, reason); +#else +void grpc_stream_ref(grpc_stream_refcount *refcount) { +#endif + gpr_ref_non_zero(&refcount->refs); +} + +#ifdef GRPC_STREAM_REFCOUNT_DEBUG +void grpc_stream_unref(grpc_exec_ctx *exec_ctx, grpc_stream_refcount *refcount, + const char *reason) { + gpr_atm val = gpr_atm_no_barrier_load(&refcount->refs.count); + gpr_log(GPR_DEBUG, "%s %p:%p UNREF %d->%d %s", refcount->object_type, + refcount, refcount->destroy.cb_arg, val, val - 1, reason); +#else +void grpc_stream_unref(grpc_exec_ctx *exec_ctx, + grpc_stream_refcount *refcount) { +#endif + if (gpr_unref(&refcount->refs)) { + grpc_exec_ctx_enqueue(exec_ctx, &refcount->destroy, true, NULL); + } +} + +#ifdef GRPC_STREAM_REFCOUNT_DEBUG +void grpc_stream_ref_init(grpc_stream_refcount *refcount, int initial_refs, + grpc_iomgr_cb_func cb, void *cb_arg, + const char *object_type) { + refcount->object_type = object_type; +#else +void grpc_stream_ref_init(grpc_stream_refcount *refcount, int initial_refs, + grpc_iomgr_cb_func cb, void *cb_arg) { +#endif + gpr_ref_init(&refcount->refs, initial_refs); + grpc_closure_init(&refcount->destroy, cb, cb_arg); +} + +size_t grpc_transport_stream_size(grpc_transport *transport) { + return transport->vtable->sizeof_stream; +} + +void grpc_transport_destroy(grpc_exec_ctx *exec_ctx, + grpc_transport *transport) { + transport->vtable->destroy(exec_ctx, transport); +} + +int grpc_transport_init_stream(grpc_exec_ctx *exec_ctx, + grpc_transport *transport, grpc_stream *stream, + grpc_stream_refcount *refcount, + const void *server_data) { + return transport->vtable->init_stream(exec_ctx, transport, stream, refcount, + server_data); +} + +void grpc_transport_perform_stream_op(grpc_exec_ctx *exec_ctx, + grpc_transport *transport, + grpc_stream *stream, + grpc_transport_stream_op *op) { + transport->vtable->perform_stream_op(exec_ctx, transport, stream, op); +} + +void grpc_transport_perform_op(grpc_exec_ctx *exec_ctx, + grpc_transport *transport, + grpc_transport_op *op) { + transport->vtable->perform_op(exec_ctx, transport, op); +} + +void grpc_transport_set_pollset(grpc_exec_ctx *exec_ctx, + grpc_transport *transport, grpc_stream *stream, + grpc_pollset *pollset) { + transport->vtable->set_pollset(exec_ctx, transport, stream, pollset); +} + +void grpc_transport_destroy_stream(grpc_exec_ctx *exec_ctx, + grpc_transport *transport, + grpc_stream *stream) { + transport->vtable->destroy_stream(exec_ctx, transport, stream); +} + +char *grpc_transport_get_peer(grpc_exec_ctx *exec_ctx, + grpc_transport *transport) { + return transport->vtable->get_peer(exec_ctx, transport); +} + +void grpc_transport_stream_op_finish_with_failure( + grpc_exec_ctx *exec_ctx, grpc_transport_stream_op *op) { + grpc_exec_ctx_enqueue(exec_ctx, op->recv_message_ready, false, NULL); + grpc_exec_ctx_enqueue(exec_ctx, op->recv_initial_metadata_ready, false, NULL); + grpc_exec_ctx_enqueue(exec_ctx, op->on_complete, false, NULL); +} + +void grpc_transport_stream_op_add_cancellation(grpc_transport_stream_op *op, + grpc_status_code status) { + GPR_ASSERT(status != GRPC_STATUS_OK); + if (op->cancel_with_status == GRPC_STATUS_OK) { + op->cancel_with_status = status; + } + if (op->close_with_status != GRPC_STATUS_OK) { + op->close_with_status = GRPC_STATUS_OK; + if (op->optional_close_message != NULL) { + gpr_slice_unref(*op->optional_close_message); + op->optional_close_message = NULL; + } + } +} + +typedef struct { + gpr_slice message; + grpc_closure *then_call; + grpc_closure closure; +} close_message_data; + +static void free_message(grpc_exec_ctx *exec_ctx, void *p, bool iomgr_success) { + close_message_data *cmd = p; + gpr_slice_unref(cmd->message); + if (cmd->then_call != NULL) { + cmd->then_call->cb(exec_ctx, cmd->then_call->cb_arg, iomgr_success); + } + gpr_free(cmd); +} + +void grpc_transport_stream_op_add_close(grpc_transport_stream_op *op, + grpc_status_code status, + gpr_slice *optional_message) { + close_message_data *cmd; + GPR_ASSERT(status != GRPC_STATUS_OK); + if (op->cancel_with_status != GRPC_STATUS_OK || + op->close_with_status != GRPC_STATUS_OK) { + if (optional_message) { + gpr_slice_unref(*optional_message); + } + return; + } + if (optional_message) { + cmd = gpr_malloc(sizeof(*cmd)); + cmd->message = *optional_message; + cmd->then_call = op->on_complete; + grpc_closure_init(&cmd->closure, free_message, cmd); + op->on_complete = &cmd->closure; + op->optional_close_message = &cmd->message; + } + op->close_with_status = status; +} diff --git a/src/core/lib/transport/transport.h b/src/core/lib/transport/transport.h new file mode 100644 index 0000000000..f43e56f23c --- /dev/null +++ b/src/core/lib/transport/transport.h @@ -0,0 +1,242 @@ +/* + * + * Copyright 2015-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_TRANSPORT_TRANSPORT_H +#define GRPC_CORE_TRANSPORT_TRANSPORT_H + +#include + +#include "src/core/channel/context.h" +#include "src/core/iomgr/pollset.h" +#include "src/core/iomgr/pollset_set.h" +#include "src/core/transport/byte_stream.h" +#include "src/core/transport/metadata_batch.h" + +/* forward declarations */ +typedef struct grpc_transport grpc_transport; + +/* grpc_stream doesn't actually exist. It's used as a typesafe + opaque pointer for whatever data the transport wants to track + for a stream. */ +typedef struct grpc_stream grpc_stream; + +/*#define GRPC_STREAM_REFCOUNT_DEBUG*/ + +typedef struct grpc_stream_refcount { + gpr_refcount refs; + grpc_closure destroy; +#ifdef GRPC_STREAM_REFCOUNT_DEBUG + const char *object_type; +#endif +} grpc_stream_refcount; + +#ifdef GRPC_STREAM_REFCOUNT_DEBUG +void grpc_stream_ref_init(grpc_stream_refcount *refcount, int initial_refs, + grpc_iomgr_cb_func cb, void *cb_arg, + const char *object_type); +void grpc_stream_ref(grpc_stream_refcount *refcount, const char *reason); +void grpc_stream_unref(grpc_exec_ctx *exec_ctx, grpc_stream_refcount *refcount, + const char *reason); +#define GRPC_STREAM_REF_INIT(rc, ir, cb, cb_arg, objtype) \ + grpc_stream_ref_init(rc, ir, cb, cb_arg, objtype) +#else +void grpc_stream_ref_init(grpc_stream_refcount *refcount, int initial_refs, + grpc_iomgr_cb_func cb, void *cb_arg); +void grpc_stream_ref(grpc_stream_refcount *refcount); +void grpc_stream_unref(grpc_exec_ctx *exec_ctx, grpc_stream_refcount *refcount); +#define GRPC_STREAM_REF_INIT(rc, ir, cb, cb_arg, objtype) \ + grpc_stream_ref_init(rc, ir, cb, cb_arg) +#endif + +/* Transport stream op: a set of operations to perform on a transport + against a single stream */ +typedef struct grpc_transport_stream_op { + /** Send initial metadata to the peer, from the provided metadata batch. */ + grpc_metadata_batch *send_initial_metadata; + + /** Send trailing metadata to the peer, from the provided metadata batch. */ + grpc_metadata_batch *send_trailing_metadata; + + /** Send message data to the peer, from the provided byte stream. */ + grpc_byte_stream *send_message; + + /** Receive initial metadata from the stream, into provided metadata batch. */ + grpc_metadata_batch *recv_initial_metadata; + /** Should be enqueued when initial metadata is ready to be processed. */ + grpc_closure *recv_initial_metadata_ready; + + /** Receive message data from the stream, into provided byte stream. */ + grpc_byte_stream **recv_message; + /** Should be enqueued when one message is ready to be processed. */ + grpc_closure *recv_message_ready; + + /** Receive trailing metadata from the stream, into provided metadata batch. + */ + grpc_metadata_batch *recv_trailing_metadata; + + /** Should be enqueued when all requested operations (excluding recv_message + and recv_initial_metadata which have their own closures) in a given batch + have been completed. */ + grpc_closure *on_complete; + + /** If != GRPC_STATUS_OK, cancel this stream */ + grpc_status_code cancel_with_status; + + /** If != GRPC_STATUS_OK, send grpc-status, grpc-message, and close this + stream for both reading and writing */ + grpc_status_code close_with_status; + gpr_slice *optional_close_message; + + /* Indexes correspond to grpc_context_index enum values */ + grpc_call_context_element *context; +} grpc_transport_stream_op; + +/** Transport op: a set of operations to perform on a transport as a whole */ +typedef struct grpc_transport_op { + /** Called when processing of this op is done. */ + grpc_closure *on_consumed; + /** connectivity monitoring - set connectivity_state to NULL to unsubscribe */ + grpc_closure *on_connectivity_state_change; + grpc_connectivity_state *connectivity_state; + /** should the transport be disconnected */ + int disconnect; + /** should we send a goaway? + after a goaway is sent, once there are no more active calls on + the transport, the transport should disconnect */ + int send_goaway; + /** what should the goaway contain? */ + grpc_status_code goaway_status; + gpr_slice *goaway_message; + /** set the callback for accepting new streams; + this is a permanent callback, unlike the other one-shot closures. + If true, the callback is set to set_accept_stream_fn, with its + user_data argument set to set_accept_stream_user_data */ + bool set_accept_stream; + void (*set_accept_stream_fn)(grpc_exec_ctx *exec_ctx, void *user_data, + grpc_transport *transport, + const void *server_data); + void *set_accept_stream_user_data; + /** add this transport to a pollset */ + grpc_pollset *bind_pollset; + /** add this transport to a pollset_set */ + grpc_pollset_set *bind_pollset_set; + /** send a ping, call this back if not NULL */ + grpc_closure *send_ping; +} grpc_transport_op; + +/* Returns the amount of memory required to store a grpc_stream for this + transport */ +size_t grpc_transport_stream_size(grpc_transport *transport); + +/* Initialize transport data for a stream. + + Returns 0 on success, any other (transport-defined) value for failure. + + Arguments: + transport - the transport on which to create this stream + stream - a pointer to uninitialized memory to initialize + server_data - either NULL for a client initiated stream, or a pointer + supplied from the accept_stream callback function */ +int grpc_transport_init_stream(grpc_exec_ctx *exec_ctx, + grpc_transport *transport, grpc_stream *stream, + grpc_stream_refcount *refcount, + const void *server_data); + +void grpc_transport_set_pollset(grpc_exec_ctx *exec_ctx, + grpc_transport *transport, grpc_stream *stream, + grpc_pollset *pollset); + +/* Destroy transport data for a stream. + + Requires: a recv_batch with final_state == GRPC_STREAM_CLOSED has been + received by the up-layer. Must not be called in the same call stack as + recv_frame. + + Arguments: + transport - the transport on which to create this stream + stream - the grpc_stream to destroy (memory is still owned by the + caller, but any child memory must be cleaned up) */ +void grpc_transport_destroy_stream(grpc_exec_ctx *exec_ctx, + grpc_transport *transport, + grpc_stream *stream); + +void grpc_transport_stream_op_finish_with_failure(grpc_exec_ctx *exec_ctx, + grpc_transport_stream_op *op); + +void grpc_transport_stream_op_add_cancellation(grpc_transport_stream_op *op, + grpc_status_code status); + +void grpc_transport_stream_op_add_close(grpc_transport_stream_op *op, + grpc_status_code status, + gpr_slice *optional_message); + +char *grpc_transport_stream_op_string(grpc_transport_stream_op *op); + +/* Send a batch of operations on a transport + + Takes ownership of any objects contained in ops. + + Arguments: + transport - the transport on which to initiate the stream + stream - the stream on which to send the operations. This must be + non-NULL and previously initialized by the same transport. + op - a grpc_transport_stream_op specifying the op to perform */ +void grpc_transport_perform_stream_op(grpc_exec_ctx *exec_ctx, + grpc_transport *transport, + grpc_stream *stream, + grpc_transport_stream_op *op); + +void grpc_transport_perform_op(grpc_exec_ctx *exec_ctx, + grpc_transport *transport, + grpc_transport_op *op); + +/* Send a ping on a transport + + Calls cb with user data when a response is received. */ +void grpc_transport_ping(grpc_transport *transport, grpc_closure *cb); + +/* Advise peer of pending connection termination. */ +void grpc_transport_goaway(grpc_transport *transport, grpc_status_code status, + gpr_slice debug_data); + +/* Close a transport. Aborts all open streams. */ +void grpc_transport_close(grpc_transport *transport); + +/* Destroy the transport */ +void grpc_transport_destroy(grpc_exec_ctx *exec_ctx, grpc_transport *transport); + +/* Get the transports peer */ +char *grpc_transport_get_peer(grpc_exec_ctx *exec_ctx, + grpc_transport *transport); + +#endif /* GRPC_CORE_TRANSPORT_TRANSPORT_H */ diff --git a/src/core/lib/transport/transport_impl.h b/src/core/lib/transport/transport_impl.h new file mode 100644 index 0000000000..d9ecc4d2ba --- /dev/null +++ b/src/core/lib/transport/transport_impl.h @@ -0,0 +1,81 @@ +/* + * + * Copyright 2015-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_TRANSPORT_TRANSPORT_IMPL_H +#define GRPC_CORE_TRANSPORT_TRANSPORT_IMPL_H + +#include "src/core/transport/transport.h" + +typedef struct grpc_transport_vtable { + /* Memory required for a single stream element - this is allocated by upper + layers and initialized by the transport */ + size_t sizeof_stream; /* = sizeof(transport stream) */ + + /* name of this transport implementation */ + const char *name; + + /* implementation of grpc_transport_init_stream */ + int (*init_stream)(grpc_exec_ctx *exec_ctx, grpc_transport *self, + grpc_stream *stream, grpc_stream_refcount *refcount, + const void *server_data); + + /* implementation of grpc_transport_set_pollset */ + void (*set_pollset)(grpc_exec_ctx *exec_ctx, grpc_transport *self, + grpc_stream *stream, grpc_pollset *pollset); + + /* implementation of grpc_transport_perform_stream_op */ + void (*perform_stream_op)(grpc_exec_ctx *exec_ctx, grpc_transport *self, + grpc_stream *stream, grpc_transport_stream_op *op); + + /* implementation of grpc_transport_perform_op */ + void (*perform_op)(grpc_exec_ctx *exec_ctx, grpc_transport *self, + grpc_transport_op *op); + + /* implementation of grpc_transport_destroy_stream */ + void (*destroy_stream)(grpc_exec_ctx *exec_ctx, grpc_transport *self, + grpc_stream *stream); + + /* implementation of grpc_transport_destroy */ + void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_transport *self); + + /* implementation of grpc_transport_get_peer */ + char *(*get_peer)(grpc_exec_ctx *exec_ctx, grpc_transport *self); +} grpc_transport_vtable; + +/* an instance of a grpc transport */ +struct grpc_transport { + /* pointer to a vtable defining operations on this transport */ + const grpc_transport_vtable *vtable; +}; + +#endif /* GRPC_CORE_TRANSPORT_TRANSPORT_IMPL_H */ diff --git a/src/core/lib/transport/transport_op_string.c b/src/core/lib/transport/transport_op_string.c new file mode 100644 index 0000000000..8453412480 --- /dev/null +++ b/src/core/lib/transport/transport_op_string.c @@ -0,0 +1,140 @@ +/* + * + * Copyright 2015-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/channel/channel_stack.h" + +#include +#include +#include + +#include +#include +#include +#include "src/core/support/string.h" + +/* These routines are here to facilitate debugging - they produce string + representations of various transport data structures */ + +static void put_metadata(gpr_strvec *b, grpc_mdelem *md) { + gpr_strvec_add(b, gpr_strdup("key=")); + gpr_strvec_add(b, + gpr_dump_slice(md->key->slice, GPR_DUMP_HEX | GPR_DUMP_ASCII)); + + gpr_strvec_add(b, gpr_strdup(" value=")); + gpr_strvec_add( + b, gpr_dump_slice(md->value->slice, GPR_DUMP_HEX | GPR_DUMP_ASCII)); +} + +static void put_metadata_list(gpr_strvec *b, grpc_metadata_batch md) { + grpc_linked_mdelem *m; + for (m = md.list.head; m != NULL; m = m->next) { + if (m != md.list.head) gpr_strvec_add(b, gpr_strdup(", ")); + put_metadata(b, m->md); + } + if (gpr_time_cmp(md.deadline, gpr_inf_future(md.deadline.clock_type)) != 0) { + char *tmp; + gpr_asprintf(&tmp, " deadline=%lld.%09d", (long long)md.deadline.tv_sec, + (int)md.deadline.tv_nsec); + gpr_strvec_add(b, tmp); + } +} + +char *grpc_transport_stream_op_string(grpc_transport_stream_op *op) { + char *tmp; + char *out; + int first = 1; + + gpr_strvec b; + gpr_strvec_init(&b); + + if (op->send_initial_metadata != NULL) { + if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); + first = 0; + gpr_strvec_add(&b, gpr_strdup("SEND_INITIAL_METADATA{")); + put_metadata_list(&b, *op->send_initial_metadata); + gpr_strvec_add(&b, gpr_strdup("}")); + } + + if (op->send_message != NULL) { + if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); + first = 0; + gpr_asprintf(&tmp, "SEND_MESSAGE:flags=0x%08x:len=%d", + op->send_message->flags, op->send_message->length); + gpr_strvec_add(&b, tmp); + } + + if (op->send_trailing_metadata != NULL) { + if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); + first = 0; + gpr_strvec_add(&b, gpr_strdup("SEND_TRAILING_METADATA{")); + put_metadata_list(&b, *op->send_trailing_metadata); + gpr_strvec_add(&b, gpr_strdup("}")); + } + + if (op->recv_initial_metadata != NULL) { + if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); + first = 0; + gpr_strvec_add(&b, gpr_strdup("RECV_INITIAL_METADATA")); + } + + if (op->recv_message != NULL) { + if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); + first = 0; + gpr_strvec_add(&b, gpr_strdup("RECV_MESSAGE")); + } + + if (op->recv_trailing_metadata != NULL) { + if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); + first = 0; + gpr_strvec_add(&b, gpr_strdup("RECV_TRAILING_METADATA")); + } + + if (op->cancel_with_status != GRPC_STATUS_OK) { + if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); + first = 0; + gpr_asprintf(&tmp, "CANCEL:%d", op->cancel_with_status); + gpr_strvec_add(&b, tmp); + } + + out = gpr_strvec_flatten(&b, NULL); + gpr_strvec_destroy(&b); + + return out; +} + +void grpc_call_log_op(char *file, int line, gpr_log_severity severity, + grpc_call_element *elem, grpc_transport_stream_op *op) { + char *str = grpc_transport_stream_op_string(op); + gpr_log(file, line, severity, "OP[%s:%p]: %s", elem->filter->name, elem, str); + gpr_free(str); +} diff --git a/src/core/lib/tsi/fake_transport_security.c b/src/core/lib/tsi/fake_transport_security.c new file mode 100644 index 0000000000..c0106f7a33 --- /dev/null +++ b/src/core/lib/tsi/fake_transport_security.c @@ -0,0 +1,527 @@ +/* + * + * Copyright 2015-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/tsi/fake_transport_security.h" + +#include +#include + +#include +#include +#include +#include "src/core/tsi/transport_security.h" + +/* --- Constants. ---*/ +#define TSI_FAKE_FRAME_HEADER_SIZE 4 +#define TSI_FAKE_FRAME_INITIAL_ALLOCATED_SIZE 64 +#define TSI_FAKE_DEFAULT_FRAME_SIZE 16384 + +/* --- Structure definitions. ---*/ + +/* a frame is encoded like this: + | size | data | + where the size field value is the size of the size field plus the size of + the data encoded in little endian on 4 bytes. */ +typedef struct { + unsigned char *data; + size_t size; + size_t allocated_size; + size_t offset; + int needs_draining; +} tsi_fake_frame; + +typedef enum { + TSI_FAKE_CLIENT_INIT = 0, + TSI_FAKE_SERVER_INIT = 1, + TSI_FAKE_CLIENT_FINISHED = 2, + TSI_FAKE_SERVER_FINISHED = 3, + TSI_FAKE_HANDSHAKE_MESSAGE_MAX = 4 +} tsi_fake_handshake_message; + +typedef struct { + tsi_handshaker base; + int is_client; + tsi_fake_handshake_message next_message_to_send; + int needs_incoming_message; + tsi_fake_frame incoming; + tsi_fake_frame outgoing; + tsi_result result; +} tsi_fake_handshaker; + +typedef struct { + tsi_frame_protector base; + tsi_fake_frame protect_frame; + tsi_fake_frame unprotect_frame; + size_t max_frame_size; +} tsi_fake_frame_protector; + +/* --- Utils. ---*/ + +static const char *tsi_fake_handshake_message_strings[] = { + "CLIENT_INIT", "SERVER_INIT", "CLIENT_FINISHED", "SERVER_FINISHED"}; + +static const char *tsi_fake_handshake_message_to_string(int msg) { + if (msg < 0 || msg >= TSI_FAKE_HANDSHAKE_MESSAGE_MAX) { + gpr_log(GPR_ERROR, "Invalid message %d", msg); + return "UNKNOWN"; + } + return tsi_fake_handshake_message_strings[msg]; +} + +static tsi_result tsi_fake_handshake_message_from_string( + const char *msg_string, tsi_fake_handshake_message *msg) { + tsi_fake_handshake_message i; + for (i = 0; i < TSI_FAKE_HANDSHAKE_MESSAGE_MAX; i++) { + if (strncmp(msg_string, tsi_fake_handshake_message_strings[i], + strlen(tsi_fake_handshake_message_strings[i])) == 0) { + *msg = i; + return TSI_OK; + } + } + gpr_log(GPR_ERROR, "Invalid handshake message."); + return TSI_DATA_CORRUPTED; +} + +static uint32_t load32_little_endian(const unsigned char *buf) { + return ((uint32_t)(buf[0]) | (uint32_t)(buf[1] << 8) | + (uint32_t)(buf[2] << 16) | (uint32_t)(buf[3] << 24)); +} + +static void store32_little_endian(uint32_t value, unsigned char *buf) { + buf[3] = (unsigned char)((value >> 24) & 0xFF); + buf[2] = (unsigned char)((value >> 16) & 0xFF); + buf[1] = (unsigned char)((value >> 8) & 0xFF); + buf[0] = (unsigned char)((value)&0xFF); +} + +static void tsi_fake_frame_reset(tsi_fake_frame *frame, int needs_draining) { + frame->offset = 0; + frame->needs_draining = needs_draining; + if (!needs_draining) frame->size = 0; +} + +/* Returns 1 if successful, 0 otherwise. */ +static int tsi_fake_frame_ensure_size(tsi_fake_frame *frame) { + if (frame->data == NULL) { + frame->allocated_size = frame->size; + frame->data = malloc(frame->allocated_size); + if (frame->data == NULL) return 0; + } else if (frame->size > frame->allocated_size) { + unsigned char *new_data = realloc(frame->data, frame->size); + if (new_data == NULL) { + free(frame->data); + frame->data = NULL; + return 0; + } + frame->data = new_data; + frame->allocated_size = frame->size; + } + return 1; +} + +/* This method should not be called if frame->needs_framing is not 0. */ +static tsi_result fill_frame_from_bytes(const unsigned char *incoming_bytes, + size_t *incoming_bytes_size, + tsi_fake_frame *frame) { + size_t available_size = *incoming_bytes_size; + size_t to_read_size = 0; + const unsigned char *bytes_cursor = incoming_bytes; + + if (frame->needs_draining) return TSI_INTERNAL_ERROR; + if (frame->data == NULL) { + frame->allocated_size = TSI_FAKE_FRAME_INITIAL_ALLOCATED_SIZE; + frame->data = malloc(frame->allocated_size); + if (frame->data == NULL) return TSI_OUT_OF_RESOURCES; + } + + if (frame->offset < TSI_FAKE_FRAME_HEADER_SIZE) { + to_read_size = TSI_FAKE_FRAME_HEADER_SIZE - frame->offset; + if (to_read_size > available_size) { + /* Just fill what we can and exit. */ + memcpy(frame->data + frame->offset, bytes_cursor, available_size); + bytes_cursor += available_size; + frame->offset += available_size; + *incoming_bytes_size = (size_t)(bytes_cursor - incoming_bytes); + return TSI_INCOMPLETE_DATA; + } + memcpy(frame->data + frame->offset, bytes_cursor, to_read_size); + bytes_cursor += to_read_size; + frame->offset += to_read_size; + available_size -= to_read_size; + frame->size = load32_little_endian(frame->data); + if (!tsi_fake_frame_ensure_size(frame)) return TSI_OUT_OF_RESOURCES; + } + + to_read_size = frame->size - frame->offset; + if (to_read_size > available_size) { + memcpy(frame->data + frame->offset, bytes_cursor, available_size); + frame->offset += available_size; + bytes_cursor += available_size; + *incoming_bytes_size = (size_t)(bytes_cursor - incoming_bytes); + return TSI_INCOMPLETE_DATA; + } + memcpy(frame->data + frame->offset, bytes_cursor, to_read_size); + bytes_cursor += to_read_size; + *incoming_bytes_size = (size_t)(bytes_cursor - incoming_bytes); + tsi_fake_frame_reset(frame, 1 /* needs_draining */); + return TSI_OK; +} + +/* This method should not be called if frame->needs_framing is 0. */ +static tsi_result drain_frame_to_bytes(unsigned char *outgoing_bytes, + size_t *outgoing_bytes_size, + tsi_fake_frame *frame) { + size_t to_write_size = frame->size - frame->offset; + if (!frame->needs_draining) return TSI_INTERNAL_ERROR; + if (*outgoing_bytes_size < to_write_size) { + memcpy(outgoing_bytes, frame->data + frame->offset, *outgoing_bytes_size); + frame->offset += *outgoing_bytes_size; + return TSI_INCOMPLETE_DATA; + } + memcpy(outgoing_bytes, frame->data + frame->offset, to_write_size); + *outgoing_bytes_size = to_write_size; + tsi_fake_frame_reset(frame, 0 /* needs_draining */); + return TSI_OK; +} + +static tsi_result bytes_to_frame(unsigned char *bytes, size_t bytes_size, + tsi_fake_frame *frame) { + frame->offset = 0; + frame->size = bytes_size + TSI_FAKE_FRAME_HEADER_SIZE; + if (!tsi_fake_frame_ensure_size(frame)) return TSI_OUT_OF_RESOURCES; + store32_little_endian((uint32_t)frame->size, frame->data); + memcpy(frame->data + TSI_FAKE_FRAME_HEADER_SIZE, bytes, bytes_size); + tsi_fake_frame_reset(frame, 1 /* needs draining */); + return TSI_OK; +} + +static void tsi_fake_frame_destruct(tsi_fake_frame *frame) { + if (frame->data != NULL) free(frame->data); +} + +/* --- tsi_frame_protector methods implementation. ---*/ + +static tsi_result fake_protector_protect(tsi_frame_protector *self, + const unsigned char *unprotected_bytes, + size_t *unprotected_bytes_size, + unsigned char *protected_output_frames, + size_t *protected_output_frames_size) { + tsi_result result = TSI_OK; + tsi_fake_frame_protector *impl = (tsi_fake_frame_protector *)self; + unsigned char frame_header[TSI_FAKE_FRAME_HEADER_SIZE]; + tsi_fake_frame *frame = &impl->protect_frame; + size_t saved_output_size = *protected_output_frames_size; + size_t drained_size = 0; + size_t *num_bytes_written = protected_output_frames_size; + *num_bytes_written = 0; + + /* Try to drain first. */ + if (frame->needs_draining) { + drained_size = saved_output_size - *num_bytes_written; + result = + drain_frame_to_bytes(protected_output_frames, &drained_size, frame); + *num_bytes_written += drained_size; + protected_output_frames += drained_size; + if (result != TSI_OK) { + if (result == TSI_INCOMPLETE_DATA) { + *unprotected_bytes_size = 0; + result = TSI_OK; + } + return result; + } + } + + /* Now process the unprotected_bytes. */ + if (frame->needs_draining) return TSI_INTERNAL_ERROR; + if (frame->size == 0) { + /* New frame, create a header. */ + size_t written_in_frame_size = 0; + store32_little_endian((uint32_t)impl->max_frame_size, frame_header); + written_in_frame_size = TSI_FAKE_FRAME_HEADER_SIZE; + result = fill_frame_from_bytes(frame_header, &written_in_frame_size, frame); + if (result != TSI_INCOMPLETE_DATA) { + gpr_log(GPR_ERROR, "fill_frame_from_bytes returned %s", + tsi_result_to_string(result)); + return result; + } + } + result = + fill_frame_from_bytes(unprotected_bytes, unprotected_bytes_size, frame); + if (result != TSI_OK) { + if (result == TSI_INCOMPLETE_DATA) result = TSI_OK; + return result; + } + + /* Try to drain again. */ + if (!frame->needs_draining) return TSI_INTERNAL_ERROR; + if (frame->offset != 0) return TSI_INTERNAL_ERROR; + drained_size = saved_output_size - *num_bytes_written; + result = drain_frame_to_bytes(protected_output_frames, &drained_size, frame); + *num_bytes_written += drained_size; + if (result == TSI_INCOMPLETE_DATA) result = TSI_OK; + return result; +} + +static tsi_result fake_protector_protect_flush( + tsi_frame_protector *self, unsigned char *protected_output_frames, + size_t *protected_output_frames_size, size_t *still_pending_size) { + tsi_result result = TSI_OK; + tsi_fake_frame_protector *impl = (tsi_fake_frame_protector *)self; + tsi_fake_frame *frame = &impl->protect_frame; + if (!frame->needs_draining) { + /* Create a short frame. */ + frame->size = frame->offset; + frame->offset = 0; + frame->needs_draining = 1; + store32_little_endian((uint32_t)frame->size, + frame->data); /* Overwrite header. */ + } + result = drain_frame_to_bytes(protected_output_frames, + protected_output_frames_size, frame); + if (result == TSI_INCOMPLETE_DATA) result = TSI_OK; + *still_pending_size = frame->size - frame->offset; + return result; +} + +static tsi_result fake_protector_unprotect( + tsi_frame_protector *self, const unsigned char *protected_frames_bytes, + size_t *protected_frames_bytes_size, unsigned char *unprotected_bytes, + size_t *unprotected_bytes_size) { + tsi_result result = TSI_OK; + tsi_fake_frame_protector *impl = (tsi_fake_frame_protector *)self; + tsi_fake_frame *frame = &impl->unprotect_frame; + size_t saved_output_size = *unprotected_bytes_size; + size_t drained_size = 0; + size_t *num_bytes_written = unprotected_bytes_size; + *num_bytes_written = 0; + + /* Try to drain first. */ + if (frame->needs_draining) { + /* Go past the header if needed. */ + if (frame->offset == 0) frame->offset = TSI_FAKE_FRAME_HEADER_SIZE; + drained_size = saved_output_size - *num_bytes_written; + result = drain_frame_to_bytes(unprotected_bytes, &drained_size, frame); + unprotected_bytes += drained_size; + *num_bytes_written += drained_size; + if (result != TSI_OK) { + if (result == TSI_INCOMPLETE_DATA) { + *protected_frames_bytes_size = 0; + result = TSI_OK; + } + return result; + } + } + + /* Now process the protected_bytes. */ + if (frame->needs_draining) return TSI_INTERNAL_ERROR; + result = fill_frame_from_bytes(protected_frames_bytes, + protected_frames_bytes_size, frame); + if (result != TSI_OK) { + if (result == TSI_INCOMPLETE_DATA) result = TSI_OK; + return result; + } + + /* Try to drain again. */ + if (!frame->needs_draining) return TSI_INTERNAL_ERROR; + if (frame->offset != 0) return TSI_INTERNAL_ERROR; + frame->offset = TSI_FAKE_FRAME_HEADER_SIZE; /* Go past the header. */ + drained_size = saved_output_size - *num_bytes_written; + result = drain_frame_to_bytes(unprotected_bytes, &drained_size, frame); + *num_bytes_written += drained_size; + if (result == TSI_INCOMPLETE_DATA) result = TSI_OK; + return result; +} + +static void fake_protector_destroy(tsi_frame_protector *self) { + tsi_fake_frame_protector *impl = (tsi_fake_frame_protector *)self; + tsi_fake_frame_destruct(&impl->protect_frame); + tsi_fake_frame_destruct(&impl->unprotect_frame); + free(self); +} + +static const tsi_frame_protector_vtable frame_protector_vtable = { + fake_protector_protect, fake_protector_protect_flush, + fake_protector_unprotect, fake_protector_destroy, +}; + +/* --- tsi_handshaker methods implementation. ---*/ + +static tsi_result fake_handshaker_get_bytes_to_send_to_peer( + tsi_handshaker *self, unsigned char *bytes, size_t *bytes_size) { + tsi_fake_handshaker *impl = (tsi_fake_handshaker *)self; + tsi_result result = TSI_OK; + if (impl->needs_incoming_message || impl->result == TSI_OK) { + *bytes_size = 0; + return TSI_OK; + } + if (!impl->outgoing.needs_draining) { + tsi_fake_handshake_message next_message_to_send = + impl->next_message_to_send + 2; + const char *msg_string = + tsi_fake_handshake_message_to_string(impl->next_message_to_send); + result = bytes_to_frame((unsigned char *)msg_string, strlen(msg_string), + &impl->outgoing); + if (result != TSI_OK) return result; + if (next_message_to_send > TSI_FAKE_HANDSHAKE_MESSAGE_MAX) { + next_message_to_send = TSI_FAKE_HANDSHAKE_MESSAGE_MAX; + } + if (tsi_tracing_enabled) { + gpr_log(GPR_INFO, "%s prepared %s.", + impl->is_client ? "Client" : "Server", + tsi_fake_handshake_message_to_string(impl->next_message_to_send)); + } + impl->next_message_to_send = next_message_to_send; + } + result = drain_frame_to_bytes(bytes, bytes_size, &impl->outgoing); + if (result != TSI_OK) return result; + if (!impl->is_client && + impl->next_message_to_send == TSI_FAKE_HANDSHAKE_MESSAGE_MAX) { + /* We're done. */ + if (tsi_tracing_enabled) { + gpr_log(GPR_INFO, "Server is done."); + } + impl->result = TSI_OK; + } else { + impl->needs_incoming_message = 1; + } + return TSI_OK; +} + +static tsi_result fake_handshaker_process_bytes_from_peer( + tsi_handshaker *self, const unsigned char *bytes, size_t *bytes_size) { + tsi_result result = TSI_OK; + tsi_fake_handshaker *impl = (tsi_fake_handshaker *)self; + tsi_fake_handshake_message expected_msg = impl->next_message_to_send - 1; + tsi_fake_handshake_message received_msg; + + if (!impl->needs_incoming_message || impl->result == TSI_OK) { + *bytes_size = 0; + return TSI_OK; + } + result = fill_frame_from_bytes(bytes, bytes_size, &impl->incoming); + if (result != TSI_OK) return result; + + /* We now have a complete frame. */ + result = tsi_fake_handshake_message_from_string( + (const char *)impl->incoming.data + TSI_FAKE_FRAME_HEADER_SIZE, + &received_msg); + if (result != TSI_OK) { + impl->result = result; + return result; + } + if (received_msg != expected_msg) { + gpr_log(GPR_ERROR, "Invalid received message (%s instead of %s)", + tsi_fake_handshake_message_to_string(received_msg), + tsi_fake_handshake_message_to_string(expected_msg)); + } + if (tsi_tracing_enabled) { + gpr_log(GPR_INFO, "%s received %s.", impl->is_client ? "Client" : "Server", + tsi_fake_handshake_message_to_string(received_msg)); + } + tsi_fake_frame_reset(&impl->incoming, 0 /* needs_draining */); + impl->needs_incoming_message = 0; + if (impl->next_message_to_send == TSI_FAKE_HANDSHAKE_MESSAGE_MAX) { + /* We're done. */ + if (tsi_tracing_enabled) { + gpr_log(GPR_INFO, "%s is done.", impl->is_client ? "Client" : "Server"); + } + impl->result = TSI_OK; + } + return TSI_OK; +} + +static tsi_result fake_handshaker_get_result(tsi_handshaker *self) { + tsi_fake_handshaker *impl = (tsi_fake_handshaker *)self; + return impl->result; +} + +static tsi_result fake_handshaker_extract_peer(tsi_handshaker *self, + tsi_peer *peer) { + tsi_result result = tsi_construct_peer(1, peer); + if (result != TSI_OK) return result; + result = tsi_construct_string_peer_property_from_cstring( + TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_FAKE_CERTIFICATE_TYPE, + &peer->properties[0]); + if (result != TSI_OK) tsi_peer_destruct(peer); + return result; +} + +static tsi_result fake_handshaker_create_frame_protector( + tsi_handshaker *self, size_t *max_protected_frame_size, + tsi_frame_protector **protector) { + *protector = tsi_create_fake_protector(max_protected_frame_size); + if (*protector == NULL) return TSI_OUT_OF_RESOURCES; + return TSI_OK; +} + +static void fake_handshaker_destroy(tsi_handshaker *self) { + tsi_fake_handshaker *impl = (tsi_fake_handshaker *)self; + tsi_fake_frame_destruct(&impl->incoming); + tsi_fake_frame_destruct(&impl->outgoing); + free(self); +} + +static const tsi_handshaker_vtable handshaker_vtable = { + fake_handshaker_get_bytes_to_send_to_peer, + fake_handshaker_process_bytes_from_peer, + fake_handshaker_get_result, + fake_handshaker_extract_peer, + fake_handshaker_create_frame_protector, + fake_handshaker_destroy, +}; + +tsi_handshaker *tsi_create_fake_handshaker(int is_client) { + tsi_fake_handshaker *impl = calloc(1, sizeof(tsi_fake_handshaker)); + impl->base.vtable = &handshaker_vtable; + impl->is_client = is_client; + impl->result = TSI_HANDSHAKE_IN_PROGRESS; + if (is_client) { + impl->needs_incoming_message = 0; + impl->next_message_to_send = TSI_FAKE_CLIENT_INIT; + } else { + impl->needs_incoming_message = 1; + impl->next_message_to_send = TSI_FAKE_SERVER_INIT; + } + return &impl->base; +} + +tsi_frame_protector *tsi_create_fake_protector( + size_t *max_protected_frame_size) { + tsi_fake_frame_protector *impl = calloc(1, sizeof(tsi_fake_frame_protector)); + if (impl == NULL) return NULL; + impl->max_frame_size = (max_protected_frame_size == NULL) + ? TSI_FAKE_DEFAULT_FRAME_SIZE + : *max_protected_frame_size; + impl->base.vtable = &frame_protector_vtable; + return &impl->base; +} diff --git a/src/core/lib/tsi/fake_transport_security.h b/src/core/lib/tsi/fake_transport_security.h new file mode 100644 index 0000000000..6b8e596290 --- /dev/null +++ b/src/core/lib/tsi/fake_transport_security.h @@ -0,0 +1,61 @@ +/* + * + * Copyright 2015-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_TSI_FAKE_TRANSPORT_SECURITY_H +#define GRPC_CORE_TSI_FAKE_TRANSPORT_SECURITY_H + +#include "src/core/tsi/transport_security_interface.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Value for the TSI_CERTIFICATE_TYPE_PEER_PROPERTY property for FAKE certs. */ +#define TSI_FAKE_CERTIFICATE_TYPE "FAKE" + +/* Creates a fake handshaker that will create a fake frame protector. + + No cryptography is performed in these objects. They just simulate handshake + messages going back and forth for the handshaker and do some framing on + cleartext data for the protector. */ +tsi_handshaker *tsi_create_fake_handshaker(int is_client); + +/* Creates a protector directly without going through the handshake phase. */ +tsi_frame_protector *tsi_create_fake_protector( + size_t *max_protected_frame_size); + +#ifdef __cplusplus +} +#endif + +#endif /* GRPC_CORE_TSI_FAKE_TRANSPORT_SECURITY_H */ diff --git a/src/core/lib/tsi/ssl_transport_security.c b/src/core/lib/tsi/ssl_transport_security.c new file mode 100644 index 0000000000..8df582609b --- /dev/null +++ b/src/core/lib/tsi/ssl_transport_security.c @@ -0,0 +1,1536 @@ +/* + * + * Copyright 2015-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/tsi/ssl_transport_security.h" + +#include + +#include +#include + +/* TODO(jboeuf): refactor inet_ntop into a portability header. */ +#ifdef GPR_WINSOCK_SOCKET +#include +#else +#include +#endif + +#include +#include +#include +#include + +#include +#include /* For OPENSSL_free */ +#include +#include +#include +#include + +#include "src/core/tsi/ssl_types.h" +#include "src/core/tsi/transport_security.h" + +/* --- Constants. ---*/ + +#define TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND 16384 +#define TSI_SSL_MAX_PROTECTED_FRAME_SIZE_LOWER_BOUND 1024 + +/* Putting a macro like this and littering the source file with #if is really + bad practice. + TODO(jboeuf): refactor all the #if / #endif in a separate module. */ +#ifndef TSI_OPENSSL_ALPN_SUPPORT +#define TSI_OPENSSL_ALPN_SUPPORT 1 +#endif + +/* TODO(jboeuf): I have not found a way to get this number dynamically from the + SSL structure. This is what we would ultimately want though... */ +#define TSI_SSL_MAX_PROTECTION_OVERHEAD 100 + +/* --- Structure definitions. ---*/ + +struct tsi_ssl_handshaker_factory { + tsi_result (*create_handshaker)(tsi_ssl_handshaker_factory *self, + const char *server_name_indication, + tsi_handshaker **handshaker); + void (*destroy)(tsi_ssl_handshaker_factory *self); +}; + +typedef struct { + tsi_ssl_handshaker_factory base; + SSL_CTX *ssl_context; + unsigned char *alpn_protocol_list; + size_t alpn_protocol_list_length; +} tsi_ssl_client_handshaker_factory; + +typedef struct { + tsi_ssl_handshaker_factory base; + + /* Several contexts to support SNI. + The tsi_peer array contains the subject names of the server certificates + associated with the contexts at the same index. */ + SSL_CTX **ssl_contexts; + tsi_peer *ssl_context_x509_subject_names; + size_t ssl_context_count; + unsigned char *alpn_protocol_list; + size_t alpn_protocol_list_length; +} tsi_ssl_server_handshaker_factory; + +typedef struct { + tsi_handshaker base; + SSL *ssl; + BIO *into_ssl; + BIO *from_ssl; + tsi_result result; +} tsi_ssl_handshaker; + +typedef struct { + tsi_frame_protector base; + SSL *ssl; + BIO *into_ssl; + BIO *from_ssl; + unsigned char *buffer; + size_t buffer_size; + size_t buffer_offset; +} tsi_ssl_frame_protector; + +/* --- Library Initialization. ---*/ + +static gpr_once init_openssl_once = GPR_ONCE_INIT; +static gpr_mu *openssl_mutexes = NULL; + +static void openssl_locking_cb(int mode, int type, const char *file, int line) { + if (mode & CRYPTO_LOCK) { + gpr_mu_lock(&openssl_mutexes[type]); + } else { + gpr_mu_unlock(&openssl_mutexes[type]); + } +} + +static unsigned long openssl_thread_id_cb(void) { + return (unsigned long)gpr_thd_currentid(); +} + +static void init_openssl(void) { + int i; + int num_locks; + SSL_library_init(); + SSL_load_error_strings(); + OpenSSL_add_all_algorithms(); + num_locks = CRYPTO_num_locks(); + GPR_ASSERT(num_locks > 0); + openssl_mutexes = malloc((size_t)num_locks * sizeof(gpr_mu)); + GPR_ASSERT(openssl_mutexes != NULL); + for (i = 0; i < CRYPTO_num_locks(); i++) { + gpr_mu_init(&openssl_mutexes[i]); + } + CRYPTO_set_locking_callback(openssl_locking_cb); + CRYPTO_set_id_callback(openssl_thread_id_cb); +} + +/* --- Ssl utils. ---*/ + +static const char *ssl_error_string(int error) { + switch (error) { + case SSL_ERROR_NONE: + return "SSL_ERROR_NONE"; + case SSL_ERROR_ZERO_RETURN: + return "SSL_ERROR_ZERO_RETURN"; + case SSL_ERROR_WANT_READ: + return "SSL_ERROR_WANT_READ"; + case SSL_ERROR_WANT_WRITE: + return "SSL_ERROR_WANT_WRITE"; + case SSL_ERROR_WANT_CONNECT: + return "SSL_ERROR_WANT_CONNECT"; + case SSL_ERROR_WANT_ACCEPT: + return "SSL_ERROR_WANT_ACCEPT"; + case SSL_ERROR_WANT_X509_LOOKUP: + return "SSL_ERROR_WANT_X509_LOOKUP"; + case SSL_ERROR_SYSCALL: + return "SSL_ERROR_SYSCALL"; + case SSL_ERROR_SSL: + return "SSL_ERROR_SSL"; + default: + return "Unknown error"; + } +} + +/* TODO(jboeuf): Remove when we are past the debugging phase with this code. */ +static void ssl_log_where_info(const SSL *ssl, int where, int flag, + const char *msg) { + if ((where & flag) && tsi_tracing_enabled) { + gpr_log(GPR_INFO, "%20.20s - %30.30s - %5.10s", msg, + SSL_state_string_long(ssl), SSL_state_string(ssl)); + } +} + +/* Used for debugging. TODO(jboeuf): Remove when code is mature enough. */ +static void ssl_info_callback(const SSL *ssl, int where, int ret) { + if (ret == 0) { + gpr_log(GPR_ERROR, "ssl_info_callback: error occured.\n"); + return; + } + + ssl_log_where_info(ssl, where, SSL_CB_LOOP, "LOOP"); + ssl_log_where_info(ssl, where, SSL_CB_HANDSHAKE_START, "HANDSHAKE START"); + ssl_log_where_info(ssl, where, SSL_CB_HANDSHAKE_DONE, "HANDSHAKE DONE"); +} + +/* Returns 1 if name looks like an IP address, 0 otherwise. + This is a very rough heuristic, and only handles IPv6 in hexadecimal form. */ +static int looks_like_ip_address(const char *name) { + size_t i; + size_t dot_count = 0; + size_t num_size = 0; + for (i = 0; i < strlen(name); i++) { + if (name[i] == ':') { + /* IPv6 Address in hexadecimal form, : is not allowed in DNS names. */ + return 1; + } + if (name[i] >= '0' && name[i] <= '9') { + if (num_size > 3) return 0; + num_size++; + } else if (name[i] == '.') { + if (dot_count > 3 || num_size == 0) return 0; + dot_count++; + num_size = 0; + } else { + return 0; + } + } + if (dot_count < 3 || num_size == 0) return 0; + return 1; +} + +/* Gets the subject CN from an X509 cert. */ +static tsi_result ssl_get_x509_common_name(X509 *cert, unsigned char **utf8, + size_t *utf8_size) { + int common_name_index = -1; + X509_NAME_ENTRY *common_name_entry = NULL; + ASN1_STRING *common_name_asn1 = NULL; + X509_NAME *subject_name = X509_get_subject_name(cert); + int utf8_returned_size = 0; + if (subject_name == NULL) { + gpr_log(GPR_ERROR, "Could not get subject name from certificate."); + return TSI_NOT_FOUND; + } + common_name_index = + X509_NAME_get_index_by_NID(subject_name, NID_commonName, -1); + if (common_name_index == -1) { + gpr_log(GPR_ERROR, + "Could not get common name of subject from certificate."); + return TSI_NOT_FOUND; + } + common_name_entry = X509_NAME_get_entry(subject_name, common_name_index); + if (common_name_entry == NULL) { + gpr_log(GPR_ERROR, "Could not get common name entry from certificate."); + return TSI_INTERNAL_ERROR; + } + common_name_asn1 = X509_NAME_ENTRY_get_data(common_name_entry); + if (common_name_asn1 == NULL) { + gpr_log(GPR_ERROR, + "Could not get common name entry asn1 from certificate."); + return TSI_INTERNAL_ERROR; + } + utf8_returned_size = ASN1_STRING_to_UTF8(utf8, common_name_asn1); + if (utf8_returned_size < 0) { + gpr_log(GPR_ERROR, "Could not extract utf8 from asn1 string."); + return TSI_OUT_OF_RESOURCES; + } + *utf8_size = (size_t)utf8_returned_size; + return TSI_OK; +} + +/* Gets the subject CN of an X509 cert as a tsi_peer_property. */ +static tsi_result peer_property_from_x509_common_name( + X509 *cert, tsi_peer_property *property) { + unsigned char *common_name; + size_t common_name_size; + tsi_result result = + ssl_get_x509_common_name(cert, &common_name, &common_name_size); + if (result != TSI_OK) { + if (result == TSI_NOT_FOUND) { + common_name = NULL; + common_name_size = 0; + } else { + return result; + } + } + result = tsi_construct_string_peer_property( + TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY, + common_name == NULL ? "" : (const char *)common_name, common_name_size, + property); + OPENSSL_free(common_name); + return result; +} + +/* Gets the X509 cert in PEM format as a tsi_peer_property. */ +static tsi_result add_pem_certificate(X509 *cert, tsi_peer_property *property) { + BIO *bio = BIO_new(BIO_s_mem()); + if (!PEM_write_bio_X509(bio, cert)) { + BIO_free(bio); + return TSI_INTERNAL_ERROR; + } + char *contents; + long len = BIO_get_mem_data(bio, &contents); + if (len <= 0) { + BIO_free(bio); + return TSI_INTERNAL_ERROR; + } + tsi_result result = tsi_construct_string_peer_property( + TSI_X509_PEM_CERT_PROPERTY, (const char *)contents, (size_t)len, + property); + BIO_free(bio); + return result; +} + +/* Gets the subject SANs from an X509 cert as a tsi_peer_property. */ +static tsi_result add_subject_alt_names_properties_to_peer( + tsi_peer *peer, GENERAL_NAMES *subject_alt_names, + size_t subject_alt_name_count) { + size_t i; + tsi_result result = TSI_OK; + + /* Reset for DNS entries filtering. */ + peer->property_count -= subject_alt_name_count; + + for (i = 0; i < subject_alt_name_count; i++) { + GENERAL_NAME *subject_alt_name = + sk_GENERAL_NAME_value(subject_alt_names, TSI_SIZE_AS_SIZE(i)); + /* Filter out the non-dns entries names. */ + if (subject_alt_name->type == GEN_DNS) { + unsigned char *name = NULL; + int name_size; + name_size = ASN1_STRING_to_UTF8(&name, subject_alt_name->d.dNSName); + if (name_size < 0) { + gpr_log(GPR_ERROR, "Could not get utf8 from asn1 string."); + result = TSI_INTERNAL_ERROR; + break; + } + result = tsi_construct_string_peer_property( + TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, (const char *)name, + (size_t)name_size, &peer->properties[peer->property_count++]); + OPENSSL_free(name); + } else if (subject_alt_name->type == GEN_IPADD) { + char ntop_buf[INET6_ADDRSTRLEN]; + int af; + + if (subject_alt_name->d.iPAddress->length == 4) { + af = AF_INET; + } else if (subject_alt_name->d.iPAddress->length == 16) { + af = AF_INET6; + } else { + gpr_log(GPR_ERROR, "SAN IP Address contained invalid IP"); + result = TSI_INTERNAL_ERROR; + break; + } + const char *name = inet_ntop(af, subject_alt_name->d.iPAddress->data, + ntop_buf, INET6_ADDRSTRLEN); + if (name == NULL) { + gpr_log(GPR_ERROR, "Could not get IP string from asn1 octet."); + result = TSI_INTERNAL_ERROR; + break; + } + + result = tsi_construct_string_peer_property_from_cstring( + TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, name, + &peer->properties[peer->property_count++]); + } + if (result != TSI_OK) break; + } + return result; +} + +/* Gets information about the peer's X509 cert as a tsi_peer object. */ +static tsi_result peer_from_x509(X509 *cert, int include_certificate_type, + tsi_peer *peer) { + /* TODO(jboeuf): Maybe add more properties. */ + GENERAL_NAMES *subject_alt_names = + X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0); + int subject_alt_name_count = (subject_alt_names != NULL) + ? (int)sk_GENERAL_NAME_num(subject_alt_names) + : 0; + size_t property_count; + tsi_result result; + GPR_ASSERT(subject_alt_name_count >= 0); + property_count = (include_certificate_type ? (size_t)1 : 0) + + 2 /* common name, certificate */ + + (size_t)subject_alt_name_count; + result = tsi_construct_peer(property_count, peer); + if (result != TSI_OK) return result; + do { + if (include_certificate_type) { + result = tsi_construct_string_peer_property_from_cstring( + TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE, + &peer->properties[0]); + if (result != TSI_OK) break; + } + result = peer_property_from_x509_common_name( + cert, &peer->properties[include_certificate_type ? 1 : 0]); + if (result != TSI_OK) break; + + result = add_pem_certificate( + cert, &peer->properties[include_certificate_type ? 2 : 1]); + if (result != TSI_OK) break; + + if (subject_alt_name_count != 0) { + result = add_subject_alt_names_properties_to_peer( + peer, subject_alt_names, (size_t)subject_alt_name_count); + if (result != TSI_OK) break; + } + } while (0); + + if (subject_alt_names != NULL) { + sk_GENERAL_NAME_pop_free(subject_alt_names, GENERAL_NAME_free); + } + if (result != TSI_OK) tsi_peer_destruct(peer); + return result; +} + +/* Logs the SSL error stack. */ +static void log_ssl_error_stack(void) { + unsigned long err; + while ((err = ERR_get_error()) != 0) { + char details[256]; + ERR_error_string_n((uint32_t)err, details, sizeof(details)); + gpr_log(GPR_ERROR, "%s", details); + } +} + +/* Performs an SSL_read and handle errors. */ +static tsi_result do_ssl_read(SSL *ssl, unsigned char *unprotected_bytes, + size_t *unprotected_bytes_size) { + int read_from_ssl; + GPR_ASSERT(*unprotected_bytes_size <= INT_MAX); + read_from_ssl = + SSL_read(ssl, unprotected_bytes, (int)*unprotected_bytes_size); + if (read_from_ssl == 0) { + gpr_log(GPR_ERROR, "SSL_read returned 0 unexpectedly."); + return TSI_INTERNAL_ERROR; + } + if (read_from_ssl < 0) { + read_from_ssl = SSL_get_error(ssl, read_from_ssl); + switch (read_from_ssl) { + case SSL_ERROR_WANT_READ: + /* We need more data to finish the frame. */ + *unprotected_bytes_size = 0; + return TSI_OK; + case SSL_ERROR_WANT_WRITE: + gpr_log( + GPR_ERROR, + "Peer tried to renegotiate SSL connection. This is unsupported."); + return TSI_UNIMPLEMENTED; + case SSL_ERROR_SSL: + gpr_log(GPR_ERROR, "Corruption detected."); + log_ssl_error_stack(); + return TSI_DATA_CORRUPTED; + default: + gpr_log(GPR_ERROR, "SSL_read failed with error %s.", + ssl_error_string(read_from_ssl)); + return TSI_PROTOCOL_FAILURE; + } + } + *unprotected_bytes_size = (size_t)read_from_ssl; + return TSI_OK; +} + +/* Performs an SSL_write and handle errors. */ +static tsi_result do_ssl_write(SSL *ssl, unsigned char *unprotected_bytes, + size_t unprotected_bytes_size) { + int ssl_write_result; + GPR_ASSERT(unprotected_bytes_size <= INT_MAX); + ssl_write_result = + SSL_write(ssl, unprotected_bytes, (int)unprotected_bytes_size); + if (ssl_write_result < 0) { + ssl_write_result = SSL_get_error(ssl, ssl_write_result); + if (ssl_write_result == SSL_ERROR_WANT_READ) { + gpr_log(GPR_ERROR, + "Peer tried to renegotiate SSL connection. This is unsupported."); + return TSI_UNIMPLEMENTED; + } else { + gpr_log(GPR_ERROR, "SSL_write failed with error %s.", + ssl_error_string(ssl_write_result)); + return TSI_INTERNAL_ERROR; + } + } + return TSI_OK; +} + +/* Loads an in-memory PEM certificate chain into the SSL context. */ +static tsi_result ssl_ctx_use_certificate_chain( + SSL_CTX *context, const unsigned char *pem_cert_chain, + size_t pem_cert_chain_size) { + tsi_result result = TSI_OK; + X509 *certificate = NULL; + BIO *pem; + GPR_ASSERT(pem_cert_chain_size <= INT_MAX); + pem = BIO_new_mem_buf((void *)pem_cert_chain, (int)pem_cert_chain_size); + if (pem == NULL) return TSI_OUT_OF_RESOURCES; + + do { + certificate = PEM_read_bio_X509_AUX(pem, NULL, NULL, ""); + if (certificate == NULL) { + result = TSI_INVALID_ARGUMENT; + break; + } + if (!SSL_CTX_use_certificate(context, certificate)) { + result = TSI_INVALID_ARGUMENT; + break; + } + while (1) { + X509 *certificate_authority = PEM_read_bio_X509(pem, NULL, NULL, ""); + if (certificate_authority == NULL) { + ERR_clear_error(); + break; /* Done reading. */ + } + if (!SSL_CTX_add_extra_chain_cert(context, certificate_authority)) { + X509_free(certificate_authority); + result = TSI_INVALID_ARGUMENT; + break; + } + /* We don't need to free certificate_authority as its ownership has been + transfered to the context. That is not the case for certificate though. + */ + } + } while (0); + + if (certificate != NULL) X509_free(certificate); + BIO_free(pem); + return result; +} + +/* Loads an in-memory PEM private key into the SSL context. */ +static tsi_result ssl_ctx_use_private_key(SSL_CTX *context, + const unsigned char *pem_key, + size_t pem_key_size) { + tsi_result result = TSI_OK; + EVP_PKEY *private_key = NULL; + BIO *pem; + GPR_ASSERT(pem_key_size <= INT_MAX); + pem = BIO_new_mem_buf((void *)pem_key, (int)pem_key_size); + if (pem == NULL) return TSI_OUT_OF_RESOURCES; + do { + private_key = PEM_read_bio_PrivateKey(pem, NULL, NULL, ""); + if (private_key == NULL) { + result = TSI_INVALID_ARGUMENT; + break; + } + if (!SSL_CTX_use_PrivateKey(context, private_key)) { + result = TSI_INVALID_ARGUMENT; + break; + } + } while (0); + if (private_key != NULL) EVP_PKEY_free(private_key); + BIO_free(pem); + return result; +} + +/* Loads in-memory PEM verification certs into the SSL context and optionally + returns the verification cert names (root_names can be NULL). */ +static tsi_result ssl_ctx_load_verification_certs( + SSL_CTX *context, const unsigned char *pem_roots, size_t pem_roots_size, + STACK_OF(X509_NAME) * *root_names) { + tsi_result result = TSI_OK; + size_t num_roots = 0; + X509 *root = NULL; + X509_NAME *root_name = NULL; + BIO *pem; + X509_STORE *root_store; + GPR_ASSERT(pem_roots_size <= INT_MAX); + pem = BIO_new_mem_buf((void *)pem_roots, (int)pem_roots_size); + root_store = SSL_CTX_get_cert_store(context); + if (root_store == NULL) return TSI_INVALID_ARGUMENT; + if (pem == NULL) return TSI_OUT_OF_RESOURCES; + if (root_names != NULL) { + *root_names = sk_X509_NAME_new_null(); + if (*root_names == NULL) return TSI_OUT_OF_RESOURCES; + } + + while (1) { + root = PEM_read_bio_X509_AUX(pem, NULL, NULL, ""); + if (root == NULL) { + ERR_clear_error(); + break; /* We're at the end of stream. */ + } + if (root_names != NULL) { + root_name = X509_get_subject_name(root); + if (root_name == NULL) { + gpr_log(GPR_ERROR, "Could not get name from root certificate."); + result = TSI_INVALID_ARGUMENT; + break; + } + root_name = X509_NAME_dup(root_name); + if (root_name == NULL) { + result = TSI_OUT_OF_RESOURCES; + break; + } + sk_X509_NAME_push(*root_names, root_name); + root_name = NULL; + } + if (!X509_STORE_add_cert(root_store, root)) { + gpr_log(GPR_ERROR, "Could not add root certificate to ssl context."); + result = TSI_INTERNAL_ERROR; + break; + } + X509_free(root); + num_roots++; + } + + if (num_roots == 0) { + gpr_log(GPR_ERROR, "Could not load any root certificate."); + result = TSI_INVALID_ARGUMENT; + } + + if (result != TSI_OK) { + if (root != NULL) X509_free(root); + if (root_names != NULL) { + sk_X509_NAME_pop_free(*root_names, X509_NAME_free); + *root_names = NULL; + if (root_name != NULL) X509_NAME_free(root_name); + } + } + BIO_free(pem); + return result; +} + +/* Populates the SSL context with a private key and a cert chain, and sets the + cipher list and the ephemeral ECDH key. */ +static tsi_result populate_ssl_context( + SSL_CTX *context, const unsigned char *pem_private_key, + size_t pem_private_key_size, const unsigned char *pem_certificate_chain, + size_t pem_certificate_chain_size, const char *cipher_list) { + tsi_result result = TSI_OK; + if (pem_certificate_chain != NULL) { + result = ssl_ctx_use_certificate_chain(context, pem_certificate_chain, + pem_certificate_chain_size); + if (result != TSI_OK) { + gpr_log(GPR_ERROR, "Invalid cert chain file."); + return result; + } + } + if (pem_private_key != NULL) { + result = + ssl_ctx_use_private_key(context, pem_private_key, pem_private_key_size); + if (result != TSI_OK || !SSL_CTX_check_private_key(context)) { + gpr_log(GPR_ERROR, "Invalid private key."); + return result != TSI_OK ? result : TSI_INVALID_ARGUMENT; + } + } + if ((cipher_list != NULL) && !SSL_CTX_set_cipher_list(context, cipher_list)) { + gpr_log(GPR_ERROR, "Invalid cipher list: %s.", cipher_list); + return TSI_INVALID_ARGUMENT; + } + { + EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); + if (!SSL_CTX_set_tmp_ecdh(context, ecdh)) { + gpr_log(GPR_ERROR, "Could not set ephemeral ECDH key."); + EC_KEY_free(ecdh); + return TSI_INTERNAL_ERROR; + } + SSL_CTX_set_options(context, SSL_OP_SINGLE_ECDH_USE); + EC_KEY_free(ecdh); + } + return TSI_OK; +} + +/* Extracts the CN and the SANs from an X509 cert as a peer object. */ +static tsi_result extract_x509_subject_names_from_pem_cert( + const unsigned char *pem_cert, size_t pem_cert_size, tsi_peer *peer) { + tsi_result result = TSI_OK; + X509 *cert = NULL; + BIO *pem; + GPR_ASSERT(pem_cert_size <= INT_MAX); + pem = BIO_new_mem_buf((void *)pem_cert, (int)pem_cert_size); + if (pem == NULL) return TSI_OUT_OF_RESOURCES; + + cert = PEM_read_bio_X509(pem, NULL, NULL, ""); + if (cert == NULL) { + gpr_log(GPR_ERROR, "Invalid certificate"); + result = TSI_INVALID_ARGUMENT; + } else { + result = peer_from_x509(cert, 0, peer); + } + if (cert != NULL) X509_free(cert); + BIO_free(pem); + return result; +} + +/* Builds the alpn protocol name list according to rfc 7301. */ +static tsi_result build_alpn_protocol_name_list( + const unsigned char **alpn_protocols, + const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols, + unsigned char **protocol_name_list, size_t *protocol_name_list_length) { + uint16_t i; + unsigned char *current; + *protocol_name_list = NULL; + *protocol_name_list_length = 0; + if (num_alpn_protocols == 0) return TSI_INVALID_ARGUMENT; + for (i = 0; i < num_alpn_protocols; i++) { + if (alpn_protocols_lengths[i] == 0) { + gpr_log(GPR_ERROR, "Invalid 0-length protocol name."); + return TSI_INVALID_ARGUMENT; + } + *protocol_name_list_length += (size_t)alpn_protocols_lengths[i] + 1; + } + *protocol_name_list = malloc(*protocol_name_list_length); + if (*protocol_name_list == NULL) return TSI_OUT_OF_RESOURCES; + current = *protocol_name_list; + for (i = 0; i < num_alpn_protocols; i++) { + *(current++) = alpn_protocols_lengths[i]; + memcpy(current, alpn_protocols[i], alpn_protocols_lengths[i]); + current += alpn_protocols_lengths[i]; + } + /* Safety check. */ + if ((current < *protocol_name_list) || + ((uintptr_t)(current - *protocol_name_list) != + *protocol_name_list_length)) { + return TSI_INTERNAL_ERROR; + } + return TSI_OK; +} + +/* --- tsi_frame_protector methods implementation. ---*/ + +static tsi_result ssl_protector_protect(tsi_frame_protector *self, + const unsigned char *unprotected_bytes, + size_t *unprotected_bytes_size, + unsigned char *protected_output_frames, + size_t *protected_output_frames_size) { + tsi_ssl_frame_protector *impl = (tsi_ssl_frame_protector *)self; + int read_from_ssl; + size_t available; + tsi_result result = TSI_OK; + + /* First see if we have some pending data in the SSL BIO. */ + int pending_in_ssl = (int)BIO_pending(impl->from_ssl); + if (pending_in_ssl > 0) { + *unprotected_bytes_size = 0; + GPR_ASSERT(*protected_output_frames_size <= INT_MAX); + read_from_ssl = BIO_read(impl->from_ssl, protected_output_frames, + (int)*protected_output_frames_size); + if (read_from_ssl < 0) { + gpr_log(GPR_ERROR, + "Could not read from BIO even though some data is pending"); + return TSI_INTERNAL_ERROR; + } + *protected_output_frames_size = (size_t)read_from_ssl; + return TSI_OK; + } + + /* Now see if we can send a complete frame. */ + available = impl->buffer_size - impl->buffer_offset; + if (available > *unprotected_bytes_size) { + /* If we cannot, just copy the data in our internal buffer. */ + memcpy(impl->buffer + impl->buffer_offset, unprotected_bytes, + *unprotected_bytes_size); + impl->buffer_offset += *unprotected_bytes_size; + *protected_output_frames_size = 0; + return TSI_OK; + } + + /* If we can, prepare the buffer, send it to SSL_write and read. */ + memcpy(impl->buffer + impl->buffer_offset, unprotected_bytes, available); + result = do_ssl_write(impl->ssl, impl->buffer, impl->buffer_size); + if (result != TSI_OK) return result; + + GPR_ASSERT(*protected_output_frames_size <= INT_MAX); + read_from_ssl = BIO_read(impl->from_ssl, protected_output_frames, + (int)*protected_output_frames_size); + if (read_from_ssl < 0) { + gpr_log(GPR_ERROR, "Could not read from BIO after SSL_write."); + return TSI_INTERNAL_ERROR; + } + *protected_output_frames_size = (size_t)read_from_ssl; + *unprotected_bytes_size = available; + impl->buffer_offset = 0; + return TSI_OK; +} + +static tsi_result ssl_protector_protect_flush( + tsi_frame_protector *self, unsigned char *protected_output_frames, + size_t *protected_output_frames_size, size_t *still_pending_size) { + tsi_result result = TSI_OK; + tsi_ssl_frame_protector *impl = (tsi_ssl_frame_protector *)self; + int read_from_ssl = 0; + int pending; + + if (impl->buffer_offset != 0) { + result = do_ssl_write(impl->ssl, impl->buffer, impl->buffer_offset); + if (result != TSI_OK) return result; + impl->buffer_offset = 0; + } + + pending = (int)BIO_pending(impl->from_ssl); + GPR_ASSERT(pending >= 0); + *still_pending_size = (size_t)pending; + if (*still_pending_size == 0) return TSI_OK; + + GPR_ASSERT(*protected_output_frames_size <= INT_MAX); + read_from_ssl = BIO_read(impl->from_ssl, protected_output_frames, + (int)*protected_output_frames_size); + if (read_from_ssl <= 0) { + gpr_log(GPR_ERROR, "Could not read from BIO after SSL_write."); + return TSI_INTERNAL_ERROR; + } + *protected_output_frames_size = (size_t)read_from_ssl; + pending = (int)BIO_pending(impl->from_ssl); + GPR_ASSERT(pending >= 0); + *still_pending_size = (size_t)pending; + return TSI_OK; +} + +static tsi_result ssl_protector_unprotect( + tsi_frame_protector *self, const unsigned char *protected_frames_bytes, + size_t *protected_frames_bytes_size, unsigned char *unprotected_bytes, + size_t *unprotected_bytes_size) { + tsi_result result = TSI_OK; + int written_into_ssl = 0; + size_t output_bytes_size = *unprotected_bytes_size; + size_t output_bytes_offset = 0; + tsi_ssl_frame_protector *impl = (tsi_ssl_frame_protector *)self; + + /* First, try to read remaining data from ssl. */ + result = do_ssl_read(impl->ssl, unprotected_bytes, unprotected_bytes_size); + if (result != TSI_OK) return result; + if (*unprotected_bytes_size == output_bytes_size) { + /* We have read everything we could and cannot process any more input. */ + *protected_frames_bytes_size = 0; + return TSI_OK; + } + output_bytes_offset = *unprotected_bytes_size; + unprotected_bytes += output_bytes_offset; + *unprotected_bytes_size = output_bytes_size - output_bytes_offset; + + /* Then, try to write some data to ssl. */ + GPR_ASSERT(*protected_frames_bytes_size <= INT_MAX); + written_into_ssl = BIO_write(impl->into_ssl, protected_frames_bytes, + (int)*protected_frames_bytes_size); + if (written_into_ssl < 0) { + gpr_log(GPR_ERROR, "Sending protected frame to ssl failed with %d", + written_into_ssl); + return TSI_INTERNAL_ERROR; + } + *protected_frames_bytes_size = (size_t)written_into_ssl; + + /* Now try to read some data again. */ + result = do_ssl_read(impl->ssl, unprotected_bytes, unprotected_bytes_size); + if (result == TSI_OK) { + /* Don't forget to output the total number of bytes read. */ + *unprotected_bytes_size += output_bytes_offset; + } + return result; +} + +static void ssl_protector_destroy(tsi_frame_protector *self) { + tsi_ssl_frame_protector *impl = (tsi_ssl_frame_protector *)self; + if (impl->buffer != NULL) free(impl->buffer); + if (impl->ssl != NULL) SSL_free(impl->ssl); + free(self); +} + +static const tsi_frame_protector_vtable frame_protector_vtable = { + ssl_protector_protect, ssl_protector_protect_flush, ssl_protector_unprotect, + ssl_protector_destroy, +}; + +/* --- tsi_handshaker methods implementation. ---*/ + +static tsi_result ssl_handshaker_get_bytes_to_send_to_peer(tsi_handshaker *self, + unsigned char *bytes, + size_t *bytes_size) { + tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self; + int bytes_read_from_ssl = 0; + if (bytes == NULL || bytes_size == NULL || *bytes_size == 0 || + *bytes_size > INT_MAX) { + return TSI_INVALID_ARGUMENT; + } + GPR_ASSERT(*bytes_size <= INT_MAX); + bytes_read_from_ssl = BIO_read(impl->from_ssl, bytes, (int)*bytes_size); + if (bytes_read_from_ssl < 0) { + *bytes_size = 0; + if (!BIO_should_retry(impl->from_ssl)) { + impl->result = TSI_INTERNAL_ERROR; + return impl->result; + } else { + return TSI_OK; + } + } + *bytes_size = (size_t)bytes_read_from_ssl; + return BIO_pending(impl->from_ssl) == 0 ? TSI_OK : TSI_INCOMPLETE_DATA; +} + +static tsi_result ssl_handshaker_get_result(tsi_handshaker *self) { + tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self; + if ((impl->result == TSI_HANDSHAKE_IN_PROGRESS) && + SSL_is_init_finished(impl->ssl)) { + impl->result = TSI_OK; + } + return impl->result; +} + +static tsi_result ssl_handshaker_process_bytes_from_peer( + tsi_handshaker *self, const unsigned char *bytes, size_t *bytes_size) { + tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self; + int bytes_written_into_ssl_size = 0; + if (bytes == NULL || bytes_size == 0 || *bytes_size > INT_MAX) { + return TSI_INVALID_ARGUMENT; + } + GPR_ASSERT(*bytes_size <= INT_MAX); + bytes_written_into_ssl_size = + BIO_write(impl->into_ssl, bytes, (int)*bytes_size); + if (bytes_written_into_ssl_size < 0) { + gpr_log(GPR_ERROR, "Could not write to memory BIO."); + impl->result = TSI_INTERNAL_ERROR; + return impl->result; + } + *bytes_size = (size_t)bytes_written_into_ssl_size; + + if (!tsi_handshaker_is_in_progress(self)) { + impl->result = TSI_OK; + return impl->result; + } else { + /* Get ready to get some bytes from SSL. */ + int ssl_result = SSL_do_handshake(impl->ssl); + ssl_result = SSL_get_error(impl->ssl, ssl_result); + switch (ssl_result) { + case SSL_ERROR_WANT_READ: + if (BIO_pending(impl->from_ssl) == 0) { + /* We need more data. */ + return TSI_INCOMPLETE_DATA; + } else { + return TSI_OK; + } + case SSL_ERROR_NONE: + return TSI_OK; + default: { + char err_str[256]; + ERR_error_string_n(ERR_get_error(), err_str, sizeof(err_str)); + gpr_log(GPR_ERROR, "Handshake failed with fatal error %s: %s.", + ssl_error_string(ssl_result), err_str); + impl->result = TSI_PROTOCOL_FAILURE; + return impl->result; + } + } + } +} + +static tsi_result ssl_handshaker_extract_peer(tsi_handshaker *self, + tsi_peer *peer) { + tsi_result result = TSI_OK; + const unsigned char *alpn_selected = NULL; + unsigned int alpn_selected_len; + tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self; + X509 *peer_cert = SSL_get_peer_certificate(impl->ssl); + if (peer_cert != NULL) { + result = peer_from_x509(peer_cert, 1, peer); + X509_free(peer_cert); + if (result != TSI_OK) return result; + } +#if TSI_OPENSSL_ALPN_SUPPORT + SSL_get0_alpn_selected(impl->ssl, &alpn_selected, &alpn_selected_len); +#endif /* TSI_OPENSSL_ALPN_SUPPORT */ + if (alpn_selected == NULL) { + /* Try npn. */ + SSL_get0_next_proto_negotiated(impl->ssl, &alpn_selected, + &alpn_selected_len); + } + if (alpn_selected != NULL) { + size_t i; + tsi_peer_property *new_properties = + calloc(1, sizeof(tsi_peer_property) * (peer->property_count + 1)); + if (new_properties == NULL) return TSI_OUT_OF_RESOURCES; + for (i = 0; i < peer->property_count; i++) { + new_properties[i] = peer->properties[i]; + } + result = tsi_construct_string_peer_property( + TSI_SSL_ALPN_SELECTED_PROTOCOL, (const char *)alpn_selected, + alpn_selected_len, &new_properties[peer->property_count]); + if (result != TSI_OK) { + free(new_properties); + return result; + } + if (peer->properties != NULL) free(peer->properties); + peer->property_count++; + peer->properties = new_properties; + } + return result; +} + +static tsi_result ssl_handshaker_create_frame_protector( + tsi_handshaker *self, size_t *max_output_protected_frame_size, + tsi_frame_protector **protector) { + size_t actual_max_output_protected_frame_size = + TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND; + tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self; + tsi_ssl_frame_protector *protector_impl = + calloc(1, sizeof(tsi_ssl_frame_protector)); + if (protector_impl == NULL) { + return TSI_OUT_OF_RESOURCES; + } + + if (max_output_protected_frame_size != NULL) { + if (*max_output_protected_frame_size > + TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND) { + *max_output_protected_frame_size = + TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND; + } else if (*max_output_protected_frame_size < + TSI_SSL_MAX_PROTECTED_FRAME_SIZE_LOWER_BOUND) { + *max_output_protected_frame_size = + TSI_SSL_MAX_PROTECTED_FRAME_SIZE_LOWER_BOUND; + } + actual_max_output_protected_frame_size = *max_output_protected_frame_size; + } + protector_impl->buffer_size = + actual_max_output_protected_frame_size - TSI_SSL_MAX_PROTECTION_OVERHEAD; + protector_impl->buffer = malloc(protector_impl->buffer_size); + if (protector_impl->buffer == NULL) { + gpr_log(GPR_ERROR, + "Could not allocated buffer for tsi_ssl_frame_protector."); + free(protector_impl); + return TSI_INTERNAL_ERROR; + } + + /* Transfer ownership of ssl to the frame protector. It is OK as the caller + * cannot call anything else but destroy on the handshaker after this call. */ + protector_impl->ssl = impl->ssl; + impl->ssl = NULL; + protector_impl->into_ssl = impl->into_ssl; + protector_impl->from_ssl = impl->from_ssl; + + protector_impl->base.vtable = &frame_protector_vtable; + *protector = &protector_impl->base; + return TSI_OK; +} + +static void ssl_handshaker_destroy(tsi_handshaker *self) { + tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self; + SSL_free(impl->ssl); /* The BIO objects are owned by ssl */ + free(impl); +} + +static const tsi_handshaker_vtable handshaker_vtable = { + ssl_handshaker_get_bytes_to_send_to_peer, + ssl_handshaker_process_bytes_from_peer, + ssl_handshaker_get_result, + ssl_handshaker_extract_peer, + ssl_handshaker_create_frame_protector, + ssl_handshaker_destroy, +}; + +/* --- tsi_ssl_handshaker_factory common methods. --- */ + +tsi_result tsi_ssl_handshaker_factory_create_handshaker( + tsi_ssl_handshaker_factory *self, const char *server_name_indication, + tsi_handshaker **handshaker) { + if (self == NULL || handshaker == NULL) return TSI_INVALID_ARGUMENT; + return self->create_handshaker(self, server_name_indication, handshaker); +} + +void tsi_ssl_handshaker_factory_destroy(tsi_ssl_handshaker_factory *self) { + if (self == NULL) return; + self->destroy(self); +} + +static tsi_result create_tsi_ssl_handshaker(SSL_CTX *ctx, int is_client, + const char *server_name_indication, + tsi_handshaker **handshaker) { + SSL *ssl = SSL_new(ctx); + BIO *into_ssl = NULL; + BIO *from_ssl = NULL; + tsi_ssl_handshaker *impl = NULL; + *handshaker = NULL; + if (ctx == NULL) { + gpr_log(GPR_ERROR, "SSL Context is null. Should never happen."); + return TSI_INTERNAL_ERROR; + } + if (ssl == NULL) { + return TSI_OUT_OF_RESOURCES; + } + SSL_set_info_callback(ssl, ssl_info_callback); + + into_ssl = BIO_new(BIO_s_mem()); + from_ssl = BIO_new(BIO_s_mem()); + if (into_ssl == NULL || from_ssl == NULL) { + gpr_log(GPR_ERROR, "BIO_new failed."); + SSL_free(ssl); + if (into_ssl != NULL) BIO_free(into_ssl); + if (from_ssl != NULL) BIO_free(into_ssl); + return TSI_OUT_OF_RESOURCES; + } + SSL_set_bio(ssl, into_ssl, from_ssl); + if (is_client) { + int ssl_result; + SSL_set_connect_state(ssl); + if (server_name_indication != NULL) { + if (!SSL_set_tlsext_host_name(ssl, server_name_indication)) { + gpr_log(GPR_ERROR, "Invalid server name indication %s.", + server_name_indication); + SSL_free(ssl); + return TSI_INTERNAL_ERROR; + } + } + ssl_result = SSL_do_handshake(ssl); + ssl_result = SSL_get_error(ssl, ssl_result); + if (ssl_result != SSL_ERROR_WANT_READ) { + gpr_log(GPR_ERROR, + "Unexpected error received from first SSL_do_handshake call: %s", + ssl_error_string(ssl_result)); + SSL_free(ssl); + return TSI_INTERNAL_ERROR; + } + } else { + SSL_set_accept_state(ssl); + } + + impl = calloc(1, sizeof(tsi_ssl_handshaker)); + if (impl == NULL) { + SSL_free(ssl); + return TSI_OUT_OF_RESOURCES; + } + impl->ssl = ssl; + impl->into_ssl = into_ssl; + impl->from_ssl = from_ssl; + impl->result = TSI_HANDSHAKE_IN_PROGRESS; + impl->base.vtable = &handshaker_vtable; + *handshaker = &impl->base; + return TSI_OK; +} + +static int select_protocol_list(const unsigned char **out, + unsigned char *outlen, + const unsigned char *client_list, + size_t client_list_len, + const unsigned char *server_list, + size_t server_list_len) { + const unsigned char *client_current = client_list; + while ((unsigned int)(client_current - client_list) < client_list_len) { + unsigned char client_current_len = *(client_current++); + const unsigned char *server_current = server_list; + while ((server_current >= server_list) && + (uintptr_t)(server_current - server_list) < server_list_len) { + unsigned char server_current_len = *(server_current++); + if ((client_current_len == server_current_len) && + !memcmp(client_current, server_current, server_current_len)) { + *out = server_current; + *outlen = server_current_len; + return SSL_TLSEXT_ERR_OK; + } + server_current += server_current_len; + } + client_current += client_current_len; + } + return SSL_TLSEXT_ERR_NOACK; +} + +/* --- tsi_ssl__client_handshaker_factory methods implementation. --- */ + +static tsi_result ssl_client_handshaker_factory_create_handshaker( + tsi_ssl_handshaker_factory *self, const char *server_name_indication, + tsi_handshaker **handshaker) { + tsi_ssl_client_handshaker_factory *impl = + (tsi_ssl_client_handshaker_factory *)self; + return create_tsi_ssl_handshaker(impl->ssl_context, 1, server_name_indication, + handshaker); +} + +static void ssl_client_handshaker_factory_destroy( + tsi_ssl_handshaker_factory *self) { + tsi_ssl_client_handshaker_factory *impl = + (tsi_ssl_client_handshaker_factory *)self; + if (impl->ssl_context != NULL) SSL_CTX_free(impl->ssl_context); + if (impl->alpn_protocol_list != NULL) free(impl->alpn_protocol_list); + free(impl); +} + +static int client_handshaker_factory_npn_callback(SSL *ssl, unsigned char **out, + unsigned char *outlen, + const unsigned char *in, + unsigned int inlen, + void *arg) { + tsi_ssl_client_handshaker_factory *factory = + (tsi_ssl_client_handshaker_factory *)arg; + return select_protocol_list((const unsigned char **)out, outlen, + factory->alpn_protocol_list, + factory->alpn_protocol_list_length, in, inlen); +} + +/* --- tsi_ssl_server_handshaker_factory methods implementation. --- */ + +static tsi_result ssl_server_handshaker_factory_create_handshaker( + tsi_ssl_handshaker_factory *self, const char *server_name_indication, + tsi_handshaker **handshaker) { + tsi_ssl_server_handshaker_factory *impl = + (tsi_ssl_server_handshaker_factory *)self; + if (impl->ssl_context_count == 0 || server_name_indication != NULL) { + return TSI_INVALID_ARGUMENT; + } + /* Create the handshaker with the first context. We will switch if needed + because of SNI in ssl_server_handshaker_factory_servername_callback. */ + return create_tsi_ssl_handshaker(impl->ssl_contexts[0], 0, NULL, handshaker); +} + +static void ssl_server_handshaker_factory_destroy( + tsi_ssl_handshaker_factory *self) { + tsi_ssl_server_handshaker_factory *impl = + (tsi_ssl_server_handshaker_factory *)self; + size_t i; + for (i = 0; i < impl->ssl_context_count; i++) { + if (impl->ssl_contexts[i] != NULL) { + SSL_CTX_free(impl->ssl_contexts[i]); + tsi_peer_destruct(&impl->ssl_context_x509_subject_names[i]); + } + } + if (impl->ssl_contexts != NULL) free(impl->ssl_contexts); + if (impl->ssl_context_x509_subject_names != NULL) { + free(impl->ssl_context_x509_subject_names); + } + if (impl->alpn_protocol_list != NULL) free(impl->alpn_protocol_list); + free(impl); +} + +static int does_entry_match_name(const char *entry, size_t entry_length, + const char *name) { + const char *dot; + const char *name_subdomain = NULL; + size_t name_length = strlen(name); + size_t name_subdomain_length; + if (entry_length == 0) return 0; + + /* Take care of '.' terminations. */ + if (name[name_length - 1] == '.') { + name_length--; + } + if (entry[entry_length - 1] == '.') { + entry_length--; + if (entry_length == 0) return 0; + } + + if ((name_length == entry_length) && + strncmp(name, entry, entry_length) == 0) { + return 1; /* Perfect match. */ + } + if (entry[0] != '*') return 0; + + /* Wildchar subdomain matching. */ + if (entry_length < 3 || entry[1] != '.') { /* At least *.x */ + gpr_log(GPR_ERROR, "Invalid wildchar entry."); + return 0; + } + name_subdomain = strchr(name, '.'); + if (name_subdomain == NULL) return 0; + name_subdomain_length = strlen(name_subdomain); + if (name_subdomain_length < 2) return 0; + name_subdomain++; /* Starts after the dot. */ + name_subdomain_length--; + entry += 2; /* Remove *. */ + entry_length -= 2; + dot = strchr(name_subdomain, '.'); + if ((dot == NULL) || (dot == &name_subdomain[name_subdomain_length - 1])) { + gpr_log(GPR_ERROR, "Invalid toplevel subdomain: %s", name_subdomain); + return 0; + } + if (name_subdomain[name_subdomain_length - 1] == '.') { + name_subdomain_length--; + } + return ((entry_length > 0) && (name_subdomain_length == entry_length) && + strncmp(entry, name_subdomain, entry_length) == 0); +} + +static int ssl_server_handshaker_factory_servername_callback(SSL *ssl, int *ap, + void *arg) { + tsi_ssl_server_handshaker_factory *impl = + (tsi_ssl_server_handshaker_factory *)arg; + size_t i = 0; + const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); + if (servername == NULL || strlen(servername) == 0) { + return SSL_TLSEXT_ERR_NOACK; + } + + for (i = 0; i < impl->ssl_context_count; i++) { + if (tsi_ssl_peer_matches_name(&impl->ssl_context_x509_subject_names[i], + servername)) { + SSL_set_SSL_CTX(ssl, impl->ssl_contexts[i]); + return SSL_TLSEXT_ERR_OK; + } + } + gpr_log(GPR_ERROR, "No match found for server name: %s.", servername); + return SSL_TLSEXT_ERR_ALERT_WARNING; +} + +#if TSI_OPENSSL_ALPN_SUPPORT +static int server_handshaker_factory_alpn_callback( + SSL *ssl, const unsigned char **out, unsigned char *outlen, + const unsigned char *in, unsigned int inlen, void *arg) { + tsi_ssl_server_handshaker_factory *factory = + (tsi_ssl_server_handshaker_factory *)arg; + return select_protocol_list(out, outlen, in, inlen, + factory->alpn_protocol_list, + factory->alpn_protocol_list_length); +} +#endif /* TSI_OPENSSL_ALPN_SUPPORT */ + +static int server_handshaker_factory_npn_advertised_callback( + SSL *ssl, const unsigned char **out, unsigned int *outlen, void *arg) { + tsi_ssl_server_handshaker_factory *factory = + (tsi_ssl_server_handshaker_factory *)arg; + *out = factory->alpn_protocol_list; + GPR_ASSERT(factory->alpn_protocol_list_length <= UINT_MAX); + *outlen = (unsigned int)factory->alpn_protocol_list_length; + return SSL_TLSEXT_ERR_OK; +} + +/* --- tsi_ssl_handshaker_factory constructors. --- */ + +tsi_result tsi_create_ssl_client_handshaker_factory( + const unsigned char *pem_private_key, size_t pem_private_key_size, + const unsigned char *pem_cert_chain, size_t pem_cert_chain_size, + const unsigned char *pem_root_certs, size_t pem_root_certs_size, + const char *cipher_list, const unsigned char **alpn_protocols, + const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols, + tsi_ssl_handshaker_factory **factory) { + SSL_CTX *ssl_context = NULL; + tsi_ssl_client_handshaker_factory *impl = NULL; + tsi_result result = TSI_OK; + + gpr_once_init(&init_openssl_once, init_openssl); + + if (factory == NULL) return TSI_INVALID_ARGUMENT; + *factory = NULL; + if (pem_root_certs == NULL) return TSI_INVALID_ARGUMENT; + + ssl_context = SSL_CTX_new(TLSv1_2_method()); + if (ssl_context == NULL) { + gpr_log(GPR_ERROR, "Could not create ssl context."); + return TSI_INVALID_ARGUMENT; + } + + impl = calloc(1, sizeof(tsi_ssl_client_handshaker_factory)); + if (impl == NULL) { + SSL_CTX_free(ssl_context); + return TSI_OUT_OF_RESOURCES; + } + impl->ssl_context = ssl_context; + + do { + result = + populate_ssl_context(ssl_context, pem_private_key, pem_private_key_size, + pem_cert_chain, pem_cert_chain_size, cipher_list); + if (result != TSI_OK) break; + result = ssl_ctx_load_verification_certs(ssl_context, pem_root_certs, + pem_root_certs_size, NULL); + if (result != TSI_OK) { + gpr_log(GPR_ERROR, "Cannot load server root certificates."); + break; + } + + if (num_alpn_protocols != 0) { + result = build_alpn_protocol_name_list( + alpn_protocols, alpn_protocols_lengths, num_alpn_protocols, + &impl->alpn_protocol_list, &impl->alpn_protocol_list_length); + if (result != TSI_OK) { + gpr_log(GPR_ERROR, "Building alpn list failed with error %s.", + tsi_result_to_string(result)); + break; + } +#if TSI_OPENSSL_ALPN_SUPPORT + GPR_ASSERT(impl->alpn_protocol_list_length < UINT_MAX); + if (SSL_CTX_set_alpn_protos( + ssl_context, impl->alpn_protocol_list, + (unsigned int)impl->alpn_protocol_list_length)) { + gpr_log(GPR_ERROR, "Could not set alpn protocol list to context."); + result = TSI_INVALID_ARGUMENT; + break; + } +#endif /* TSI_OPENSSL_ALPN_SUPPORT */ + SSL_CTX_set_next_proto_select_cb( + ssl_context, client_handshaker_factory_npn_callback, impl); + } + } while (0); + if (result != TSI_OK) { + ssl_client_handshaker_factory_destroy(&impl->base); + return result; + } + SSL_CTX_set_verify(ssl_context, SSL_VERIFY_PEER, NULL); + /* TODO(jboeuf): Add revocation verification. */ + + impl->base.create_handshaker = + ssl_client_handshaker_factory_create_handshaker; + impl->base.destroy = ssl_client_handshaker_factory_destroy; + *factory = &impl->base; + return TSI_OK; +} + +tsi_result tsi_create_ssl_server_handshaker_factory( + const unsigned char **pem_private_keys, + const size_t *pem_private_keys_sizes, const unsigned char **pem_cert_chains, + const size_t *pem_cert_chains_sizes, size_t key_cert_pair_count, + const unsigned char *pem_client_root_certs, + size_t pem_client_root_certs_size, int force_client_auth, + const char *cipher_list, const unsigned char **alpn_protocols, + const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols, + tsi_ssl_handshaker_factory **factory) { + tsi_ssl_server_handshaker_factory *impl = NULL; + tsi_result result = TSI_OK; + size_t i = 0; + + gpr_once_init(&init_openssl_once, init_openssl); + + if (factory == NULL) return TSI_INVALID_ARGUMENT; + *factory = NULL; + if (key_cert_pair_count == 0 || pem_private_keys == NULL || + pem_cert_chains == NULL) { + return TSI_INVALID_ARGUMENT; + } + + impl = calloc(1, sizeof(tsi_ssl_server_handshaker_factory)); + if (impl == NULL) return TSI_OUT_OF_RESOURCES; + impl->base.create_handshaker = + ssl_server_handshaker_factory_create_handshaker; + impl->base.destroy = ssl_server_handshaker_factory_destroy; + impl->ssl_contexts = calloc(key_cert_pair_count, sizeof(SSL_CTX *)); + impl->ssl_context_x509_subject_names = + calloc(key_cert_pair_count, sizeof(tsi_peer)); + if (impl->ssl_contexts == NULL || + impl->ssl_context_x509_subject_names == NULL) { + tsi_ssl_handshaker_factory_destroy(&impl->base); + return TSI_OUT_OF_RESOURCES; + } + impl->ssl_context_count = key_cert_pair_count; + + if (num_alpn_protocols > 0) { + result = build_alpn_protocol_name_list( + alpn_protocols, alpn_protocols_lengths, num_alpn_protocols, + &impl->alpn_protocol_list, &impl->alpn_protocol_list_length); + if (result != TSI_OK) { + tsi_ssl_handshaker_factory_destroy(&impl->base); + return result; + } + } + + for (i = 0; i < key_cert_pair_count; i++) { + do { + impl->ssl_contexts[i] = SSL_CTX_new(TLSv1_2_method()); + if (impl->ssl_contexts[i] == NULL) { + gpr_log(GPR_ERROR, "Could not create ssl context."); + result = TSI_OUT_OF_RESOURCES; + break; + } + result = populate_ssl_context( + impl->ssl_contexts[i], pem_private_keys[i], pem_private_keys_sizes[i], + pem_cert_chains[i], pem_cert_chains_sizes[i], cipher_list); + if (result != TSI_OK) break; + + if (pem_client_root_certs != NULL) { + int flags = SSL_VERIFY_PEER; + STACK_OF(X509_NAME) *root_names = NULL; + result = ssl_ctx_load_verification_certs( + impl->ssl_contexts[i], pem_client_root_certs, + pem_client_root_certs_size, &root_names); + if (result != TSI_OK) { + gpr_log(GPR_ERROR, "Invalid verification certs."); + break; + } + SSL_CTX_set_client_CA_list(impl->ssl_contexts[i], root_names); + if (force_client_auth) flags |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; + SSL_CTX_set_verify(impl->ssl_contexts[i], flags, NULL); + /* TODO(jboeuf): Add revocation verification. */ + } + + result = extract_x509_subject_names_from_pem_cert( + pem_cert_chains[i], pem_cert_chains_sizes[i], + &impl->ssl_context_x509_subject_names[i]); + if (result != TSI_OK) break; + + SSL_CTX_set_tlsext_servername_callback( + impl->ssl_contexts[i], + ssl_server_handshaker_factory_servername_callback); + SSL_CTX_set_tlsext_servername_arg(impl->ssl_contexts[i], impl); +#if TSI_OPENSSL_ALPN_SUPPORT + SSL_CTX_set_alpn_select_cb(impl->ssl_contexts[i], + server_handshaker_factory_alpn_callback, impl); +#endif /* TSI_OPENSSL_ALPN_SUPPORT */ + SSL_CTX_set_next_protos_advertised_cb( + impl->ssl_contexts[i], + server_handshaker_factory_npn_advertised_callback, impl); + } while (0); + + if (result != TSI_OK) { + tsi_ssl_handshaker_factory_destroy(&impl->base); + return result; + } + } + *factory = &impl->base; + return TSI_OK; +} + +/* --- tsi_ssl utils. --- */ + +int tsi_ssl_peer_matches_name(const tsi_peer *peer, const char *name) { + size_t i = 0; + size_t san_count = 0; + const tsi_peer_property *cn_property = NULL; + int like_ip = looks_like_ip_address(name); + + /* Check the SAN first. */ + for (i = 0; i < peer->property_count; i++) { + const tsi_peer_property *property = &peer->properties[i]; + if (property->name == NULL) continue; + if (strcmp(property->name, + TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) { + san_count++; + + if (!like_ip && does_entry_match_name(property->value.data, + property->value.length, name)) { + return 1; + } else if (like_ip && + strncmp(name, property->value.data, property->value.length) == + 0 && + strlen(name) == property->value.length) { + /* IP Addresses are exact matches only. */ + return 1; + } + } else if (strcmp(property->name, + TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY) == 0) { + cn_property = property; + } + } + + /* If there's no SAN, try the CN, but only if its not like an IP Address */ + if (san_count == 0 && cn_property != NULL && !like_ip) { + if (does_entry_match_name(cn_property->value.data, + cn_property->value.length, name)) { + return 1; + } + } + + return 0; /* Not found. */ +} diff --git a/src/core/lib/tsi/ssl_transport_security.h b/src/core/lib/tsi/ssl_transport_security.h new file mode 100644 index 0000000000..612f5c64cc --- /dev/null +++ b/src/core/lib/tsi/ssl_transport_security.h @@ -0,0 +1,174 @@ +/* + * + * Copyright 2015-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_TSI_SSL_TRANSPORT_SECURITY_H +#define GRPC_CORE_TSI_SSL_TRANSPORT_SECURITY_H + +#include "src/core/tsi/transport_security_interface.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Value for the TSI_CERTIFICATE_TYPE_PEER_PROPERTY property for X509 certs. */ +#define TSI_X509_CERTIFICATE_TYPE "X509" + +/* This property is of type TSI_PEER_PROPERTY_STRING. */ +#define TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY "x509_subject_common_name" +#define TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY \ + "x509_subject_alternative_name" + +#define TSI_X509_PEM_CERT_PROPERTY "x509_pem_cert" + +#define TSI_SSL_ALPN_SELECTED_PROTOCOL "ssl_alpn_selected_protocol" + +/* --- tsi_ssl_handshaker_factory object --- + + This object creates tsi_handshaker objects implemented in terms of the + TLS 1.2 specificiation. */ + +typedef struct tsi_ssl_handshaker_factory tsi_ssl_handshaker_factory; + +/* Creates a client handshaker factory. + - pem_private_key is the buffer containing the PEM encoding of the client's + private key. This parameter can be NULL if the client does not have a + private key. + - pem_private_key_size is the size of the associated buffer. + - pem_cert_chain is the buffer containing the PEM encoding of the client's + certificate chain. This parameter can be NULL if the client does not have + a certificate chain. + - pem_cert_chain_size is the size of the associated buffer. + - pem_roots_cert is the buffer containing the PEM encoding of the server + root certificates. This parameter cannot be NULL. + - pem_roots_cert_size is the size of the associated buffer. + - cipher_suites contains an optional list of the ciphers that the client + supports. The format of this string is described in: + https://www.openssl.org/docs/apps/ciphers.html. + This parameter can be set to NULL to use the default set of ciphers. + TODO(jboeuf): Revisit the format of this parameter. + - alpn_protocols is an array containing the protocol names that the + handshakers created with this factory support. This parameter can be NULL. + - alpn_protocols_lengths is an array containing the lengths of the alpn + protocols specified in alpn_protocols. This parameter can be NULL. + - num_alpn_protocols is the number of alpn protocols and associated lengths + specified. If this parameter is 0, the other alpn parameters must be NULL. + - factory is the address of the factory pointer to be created. + + - This method returns TSI_OK on success or TSI_INVALID_PARAMETER in the case + where a parameter is invalid. */ +tsi_result tsi_create_ssl_client_handshaker_factory( + const unsigned char *pem_private_key, size_t pem_private_key_size, + const unsigned char *pem_cert_chain, size_t pem_cert_chain_size, + const unsigned char *pem_root_certs, size_t pem_root_certs_size, + const char *cipher_suites, const unsigned char **alpn_protocols, + const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols, + tsi_ssl_handshaker_factory **factory); + +/* Creates a server handshaker factory. + - version indicates which version of the specification to use. + - pem_private_keys is an array containing the PEM encoding of the server's + private keys. This parameter cannot be NULL. The size of the array is + given by the key_cert_pair_count parameter. + - pem_private_keys_sizes is the array containing the sizes of the associated + buffers. + - pem_cert_chains is an array containing the PEM encoding of the server's + cert chains. This parameter cannot be NULL. The size of the array is + given by the key_cert_pair_count parameter. + - pem_cert_chains_sizes is the array containing the sizes of the associated + buffers. + - key_cert_pair_count indicates the number of items in the private_key_files + and cert_chain_files parameters. + - pem_client_roots is the buffer containing the PEM encoding of the client + root certificates. This parameter may be NULL in which case the server will + not authenticate the client. If not NULL, the force_client_auth parameter + specifies if the server will accept only authenticated clients or both + authenticated and non-authenticated clients. + - pem_client_root_certs_size is the size of the associated buffer. + - force_client_auth, if set to non-zero will force the client to authenticate + with an SSL cert. Note that this option is ignored if pem_client_root_certs + is NULL or pem_client_roots_certs_size is 0 + - cipher_suites contains an optional list of the ciphers that the server + supports. The format of this string is described in: + https://www.openssl.org/docs/apps/ciphers.html. + This parameter can be set to NULL to use the default set of ciphers. + TODO(jboeuf): Revisit the format of this parameter. + - alpn_protocols is an array containing the protocol names that the + handshakers created with this factory support. This parameter can be NULL. + - alpn_protocols_lengths is an array containing the lengths of the alpn + protocols specified in alpn_protocols. This parameter can be NULL. + - num_alpn_protocols is the number of alpn protocols and associated lengths + specified. If this parameter is 0, the other alpn parameters must be NULL. + - factory is the address of the factory pointer to be created. + + - This method returns TSI_OK on success or TSI_INVALID_PARAMETER in the case + where a parameter is invalid. */ +tsi_result tsi_create_ssl_server_handshaker_factory( + const unsigned char **pem_private_keys, + const size_t *pem_private_keys_sizes, const unsigned char **pem_cert_chains, + const size_t *pem_cert_chains_sizes, size_t key_cert_pair_count, + const unsigned char *pem_client_root_certs, + size_t pem_client_root_certs_size, int force_client_auth, + const char *cipher_suites, const unsigned char **alpn_protocols, + const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols, + tsi_ssl_handshaker_factory **factory); + +/* Creates a handshaker. + - self is the factory from which the handshaker will be created. + - server_name_indication indicates the name of the server the client is + trying to connect to which will be relayed to the server using the SNI + extension. + This parameter must be NULL for a server handshaker factory. + - handhshaker is the address of the handshaker pointer to be created. + + - This method returns TSI_OK on success or TSI_INVALID_PARAMETER in the case + where a parameter is invalid. */ +tsi_result tsi_ssl_handshaker_factory_create_handshaker( + tsi_ssl_handshaker_factory *self, const char *server_name_indication, + tsi_handshaker **handshaker); + +/* Destroys the handshaker factory. WARNING: it is unsafe to destroy a factory + while handshakers created with this factory are still in use. */ +void tsi_ssl_handshaker_factory_destroy(tsi_ssl_handshaker_factory *self); + +/* Util that checks that an ssl peer matches a specific name. + Still TODO(jboeuf): + - handle mixed case. + - handle %encoded chars. + - handle public suffix wildchar more strictly (e.g. *.co.uk) */ +int tsi_ssl_peer_matches_name(const tsi_peer *peer, const char *name); + +#ifdef __cplusplus +} +#endif + +#endif /* GRPC_CORE_TSI_SSL_TRANSPORT_SECURITY_H */ diff --git a/src/core/lib/tsi/ssl_types.h b/src/core/lib/tsi/ssl_types.h new file mode 100644 index 0000000000..6ea85fe6d4 --- /dev/null +++ b/src/core/lib/tsi/ssl_types.h @@ -0,0 +1,55 @@ +/* + * + * Copyright 2015-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_TSI_SSL_TYPES_H +#define GRPC_CORE_TSI_SSL_TYPES_H + +/* A collection of macros to cast between various integer types that are + * used differently between BoringSSL and OpenSSL: + * TSI_INT_AS_SIZE(x): convert 'int x' to a length parameter for an OpenSSL + * function + * TSI_SIZE_AS_SIZE(x): convert 'size_t x' to a length parameter for an OpenSSL + * function + */ + +#include + +#ifdef OPENSSL_IS_BORINGSSL +#define TSI_INT_AS_SIZE(x) ((size_t)(x)) +#define TSI_SIZE_AS_SIZE(x) (x) +#else +#define TSI_INT_AS_SIZE(x) (x) +#define TSI_SIZE_AS_SIZE(x) ((int)(x)) +#endif + +#endif /* GRPC_CORE_TSI_SSL_TYPES_H */ diff --git a/src/core/lib/tsi/test_creds/README b/src/core/lib/tsi/test_creds/README new file mode 100644 index 0000000000..eb8482d648 --- /dev/null +++ b/src/core/lib/tsi/test_creds/README @@ -0,0 +1,62 @@ +The test credentials (CONFIRMEDTESTKEY) have been generated with the following +commands: + +Bad credentials (badclient.* / badserver.*): +============================================ + +These are self-signed certificates: + +$ openssl req -x509 -newkey rsa:1024 -keyout badserver.key -out badserver.pem \ + -days 3650 -nodes + +When prompted for certificate information, everything is default except the +common name which is set to badserver.test.google.com. + + +Valid test credentials: +======================= + +The ca is self-signed: +---------------------- + +$ openssl req -x509 -new -newkey rsa:1024 -nodes -out ca.pem -config ca-openssl.cnf -days 3650 -extensions v3_req +When prompted for certificate information, everything is default. + +client is issued by CA: +----------------------- + +$ openssl genrsa -out client.key.rsa 1024 +$ openssl pkcs8 -topk8 -in client.key.rsa -out client.key -nocrypt +$ rm client.key.rsa +$ openssl req -new -key client.key -out client.csr + +When prompted for certificate information, everything is default except the +common name which is set to testclient. + +$ openssl ca -in client.csr -out client.pem + +server0 is issued by CA: +------------------------ + +$ openssl genrsa -out server0.key.rsa 1024 +$ openssl pkcs8 -topk8 -in server0.key.rsa -out server0.key -nocrypt +$ rm server0.key.rsa +$ openssl req -new -key server0.key -out server0.csr + +When prompted for certificate information, everything is default except the +common name which is set to *.test.google.com.au. + +$ openssl ca -in server0.csr -out server0.pem + +server1 is issued by CA with a special config for subject alternative names: +---------------------------------------------------------------------------- + +$ openssl genrsa -out server1.key.rsa 1024 +$ openssl pkcs8 -topk8 -in server1.key.rsa -out server1.key -nocrypt +$ rm server1.key.rsa +$ openssl req -new -key server1.key -out server1.csr -config server1-openssl.cnf + +When prompted for certificate information, everything is default except the +common name which is set to *.test.google.com. + +$ openssl ca -in server1.csr -out server1.pem diff --git a/src/core/lib/tsi/test_creds/badclient.key b/src/core/lib/tsi/test_creds/badclient.key new file mode 100644 index 0000000000..5832685122 --- /dev/null +++ b/src/core/lib/tsi/test_creds/badclient.key @@ -0,0 +1,16 @@ +-----BEGIN PRIVATE KEY----- +MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALJfYnFn4nkj52WF +E5W2qUxCfjsEFyuXYYKS/07UPWsv3gpZhtjXgdeGL+dpwEBC0IRDBfGnkMp6YY5S +O7rnEz0X3r/fvgYy+dEl2jnaA6zgc7RzMGl9U11d56gP9FiDC2190mvP/hpq2xLZ +CTbIximpmaoQyxuuH1bbYunesIG/AgMBAAECgYAdqJCEzMIyZE7oaW0tOpcB0BiP +FYoIvH4BKRH8eHvR476mt+YdDhBP1scGUmYeCT4Ej+RgHv2LPTgVYwT9eciP2+E/ +CBCNRel0Sw9JepwW0r+jWJtDY1pp6YXAgNRGX2UflvUsT+o9lZvagf9moLTMyGvU +uLFnsyfLim1B4vXvWQJBANouZllXGZoSrZLtR3VgV4tzRQvJxu84kLeIk64Ov47X +pHVBMTRBfzPEhbBodjr1m5OLaVLqkFcXftzRCrbWoKsCQQDRSoLLXOiLrtJ3DLJC +rX7Y8wrHZrqk5bMdZLGa/UX8RanhVw3+Xp+urd1711umeNJfzu/MCk4a1KkG/CU0 +rqs9AkA4cSx1DD1JSG+yxMNpsAS1xJomFIrsM9vsPt7FdndDwrF+y+CovhDkGYDk +RAHh+svGfZg/pQK2JRPimAmHhzqFAkEAu6Ya70s2FUeB3Mu9aJs2CD6hg3dQEVkB +53DI7TX48d9kGW58VX1xnqS02LyWqAPcW5qm1kLHFLdndaPNmBaj4QJBAJugl367 +9d9t/QLTSuULLaoYv2vJT3s1y9HN89EoaDDEkPVfQu6GVEXgIBtim1sI/VPSzI8H +aXvaTUwblFWSM70= +-----END PRIVATE KEY----- diff --git a/src/core/lib/tsi/test_creds/badclient.pem b/src/core/lib/tsi/test_creds/badclient.pem new file mode 100644 index 0000000000..1785970221 --- /dev/null +++ b/src/core/lib/tsi/test_creds/badclient.pem @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICoDCCAgmgAwIBAgIJANIz2/zoRiapMA0GCSqGSIb3DQEBBQUAMGkxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQxIjAgBgNVBAMMGWJhZGNsaWVudC50ZXN0Lmdvb2dsZS5j +b20wHhcNMTQwNzI4MjAwODI1WhcNMjQwNzI1MjAwODI1WjBpMQswCQYDVQQGEwJB +VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMSIwIAYDVQQDDBliYWRjbGllbnQudGVzdC5nb29nbGUuY29tMIGf +MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyX2JxZ+J5I+dlhROVtqlMQn47BBcr +l2GCkv9O1D1rL94KWYbY14HXhi/nacBAQtCEQwXxp5DKemGOUju65xM9F96/374G +MvnRJdo52gOs4HO0czBpfVNdXeeoD/RYgwttfdJrz/4aatsS2Qk2yMYpqZmqEMsb +rh9W22Lp3rCBvwIDAQABo1AwTjAdBgNVHQ4EFgQU523AJMR8Ds9V8fhf7gu1i0MM +UqAwHwYDVR0jBBgwFoAU523AJMR8Ds9V8fhf7gu1i0MMUqAwDAYDVR0TBAUwAwEB +/zANBgkqhkiG9w0BAQUFAAOBgQCI/tvSBYH1iyfLaCTBKwpdj36+MkR9EeJJmImx +X+bjhKWXwsBX4PDMWvdusr++QGUYtyoya+hfYMXRhXua39mD54xgloQNuu9REDwX +Ffto+aOw3BcYducz6ofxicFK/Y2VeXDurSMpRv5TfGf2Qr6eOOdaRhj6ed7BibHk +X1VGZA== +-----END CERTIFICATE----- diff --git a/src/core/lib/tsi/test_creds/badserver.key b/src/core/lib/tsi/test_creds/badserver.key new file mode 100644 index 0000000000..abfbde10ff --- /dev/null +++ b/src/core/lib/tsi/test_creds/badserver.key @@ -0,0 +1,16 @@ +-----BEGIN PRIVATE KEY----- +MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKeZ1e1y29cmBKaW +oIUwJ5neOJUjx+eD/3nRPe+dvLXEd9+db0fG5RYRR0S3mF1Ywuj4PIxlTW2YprUS +oGSw+tcqWNIzxv94HjwYFkkvER3AblXcDBh0P2zAkzg+nf9AcAsMh0QpDTyrXtMl +gqryjq1/vkhFofKMMbY+aXJdG6OBAgMBAAECgYAAgaB51S0A22aMMkxN2rVj6530 +JWWHN4jgD1fGj41wZyWNkWYyq1Ep3ed/N6bIMWp1VbqpGe0/9YQba/D8HOTFHGRt +72YXnP1e/ds8cxU4x4j1vvqSPtXpMmkiXfXijOvCl9mrMH2xjghFAt6/1Nb9xo1m +VdcOB8OdSuOIw6CI+QJBAN5FZUbS+bRXDWII/FaAih1DBpwCxhYEN+TXPJBxSen6 +kOzGt5g+mB6YqRMZ/qshshwPq7bsgFGfJ2lIdS2t3GsCQQDBCKifV5AAkOdOUrkK +HvoX3qnVmyIA8CyvWLcIWpfZ76QAYh0q0StedKdOMXaB1jTeSJ2KU1nlss7UD1Yw +VbrDAkAwjMHpbW3jiVw//Kx5jIwehiRscWKpLnSzBJyTBFvbwsJjJai2lX2OuVO8 ++2GYKb0Iyhd81j3VFkl6grwtpRtPAkB7+n+yt555fpfRKjhGU9b09cHGu7h/OcK5 +bBVCfE0DYHLI/DsXgPiF1g6Onh4rDdUu3xyv9xDKAqnscV099hHZAkEAvcFBfXZs +tk18N+bUcvXTdZjzZbfLCHlJmwPIspZ8G/6Pn63deg4GVYoCvTwGruah+8y734Ph +7PskfPgUQlB7Ag== +-----END PRIVATE KEY----- diff --git a/src/core/lib/tsi/test_creds/badserver.pem b/src/core/lib/tsi/test_creds/badserver.pem new file mode 100644 index 0000000000..983c979f31 --- /dev/null +++ b/src/core/lib/tsi/test_creds/badserver.pem @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICoDCCAgmgAwIBAgIJAPdqwqsKNy81MA0GCSqGSIb3DQEBBQUAMGkxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQxIjAgBgNVBAMMGWJhZHNlcnZlci50ZXN0Lmdvb2dsZS5j +b20wHhcNMTQwNzI4MjAwODU0WhcNMjQwNzI1MjAwODU0WjBpMQswCQYDVQQGEwJB +VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMSIwIAYDVQQDDBliYWRzZXJ2ZXIudGVzdC5nb29nbGUuY29tMIGf +MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCnmdXtctvXJgSmlqCFMCeZ3jiVI8fn +g/950T3vnby1xHffnW9HxuUWEUdEt5hdWMLo+DyMZU1tmKa1EqBksPrXKljSM8b/ +eB48GBZJLxEdwG5V3AwYdD9swJM4Pp3/QHALDIdEKQ08q17TJYKq8o6tf75IRaHy +jDG2PmlyXRujgQIDAQABo1AwTjAdBgNVHQ4EFgQU3u/qvHr9knMBeZyAD7mAA/ec +8cUwHwYDVR0jBBgwFoAU3u/qvHr9knMBeZyAD7mAA/ec8cUwDAYDVR0TBAUwAwEB +/zANBgkqhkiG9w0BAQUFAAOBgQA/FmR1SGLguxCCfhp4CYCbrAePSyPWDi48gTwj +vVZf/OMxdVu/H8sBYFf27BjbrEugAw16DElFtgTZ83pLb2BvkUgb6vBUK5sEkgmh +z88zBsgDp8aCf4STDOLFZMBh/E9ZKkm1zogbEmlTjFp/ceSpa2gNv7OuN4WiorOh +Wvw40g== +-----END CERTIFICATE----- diff --git a/src/core/lib/tsi/test_creds/ca-openssl.cnf b/src/core/lib/tsi/test_creds/ca-openssl.cnf new file mode 100644 index 0000000000..e97b945e4b --- /dev/null +++ b/src/core/lib/tsi/test_creds/ca-openssl.cnf @@ -0,0 +1,17 @@ +[req] +distinguished_name = req_distinguished_name +req_extensions = v3_req + +[req_distinguished_name] +countryName = Country Name (2 letter code) +countryName_default = AU +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = Some-State +organizationName = Organization Name (eg, company) +organizationName_default = Internet Widgits Pty Ltd +commonName = Common Name (eg, YOUR name) +commonName_default = testca + +[v3_req] +basicConstraints = CA:true +keyUsage = critical, keyCertSign diff --git a/src/core/lib/tsi/test_creds/ca.key b/src/core/lib/tsi/test_creds/ca.key new file mode 100644 index 0000000000..03c4f950e3 --- /dev/null +++ b/src/core/lib/tsi/test_creds/ca.key @@ -0,0 +1,16 @@ +-----BEGIN PRIVATE KEY----- +MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAMBA3wVeTGHZR1Ry +e/i+J8a2cu5gXwFV6TnObzGM7bLFCO5i9v4mLo4iFzPsHmWDUxKS3Y8iXbu0eYBl +LoNY0lSvxDx33O+DuwMmVN+DzSD+Eod9zfvwOWHsazYCZT2PhNxnVWIuJXViY4JA +HUGodjx+QAi6yCAurUZGvYXGgZSBAgMBAAECgYAxRi8i9BlFlufGSBVoGmydbJOm +bwLKl9dP3o33ODSP9hok5y6A0w5plWk3AJSF1hPLleK9VcSKYGYnt0clmPVHF35g +bx2rVK8dOT0mn7rz9Zr70jcSz1ETA2QonHZ+Y+niLmcic9At6hRtWiewblUmyFQm +GwggIzi7LOyEUHrEcQJBAOXxyQvnLvtKzXiqcsW/K6rExqVJVk+KF0fzzVyMzTJx +HRBxUVgvGdEJT7j+7P2kcTyafve0BBzDSPIaDyiJ+Y0CQQDWCb7jASFSbu5M3Zcd +Gkr4ZKN1XO3VLQX10b22bQYdF45hrTN2tnzRvVUR4q86VVnXmiGiTqmLkXcA2WWf +pHfFAkAhv9olUBo6MeF0i3frBEMRfm41hk0PwZHnMqZ6pgPcGnQMnMU2rzsXzkkQ +OwJnvAIOxhJKovZTjmofdqmw5odlAkBYVUdRWjsNUTjJwj3GRf6gyq/nFMYWz3EB +RWFdM1ttkDYzu45ctO2IhfHg4sPceDMO1s6AtKQmNI9/azkUjITdAkApNa9yFRzc +TBaDNPd5KVd58LVIzoPQ6i7uMHteLXJUWqSroji6S3s4gKMFJ/dO+ZXIlgQgfJJJ +ZDL4cdrdkeoM +-----END PRIVATE KEY----- diff --git a/src/core/lib/tsi/test_creds/ca.pem b/src/core/lib/tsi/test_creds/ca.pem new file mode 100644 index 0000000000..6c8511a73c --- /dev/null +++ b/src/core/lib/tsi/test_creds/ca.pem @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE----- +MIICSjCCAbOgAwIBAgIJAJHGGR4dGioHMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQxDzANBgNVBAMTBnRlc3RjYTAeFw0xNDExMTEyMjMxMjla +Fw0yNDExMDgyMjMxMjlaMFYxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0 +YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDzANBgNVBAMT +BnRlc3RjYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwEDfBV5MYdlHVHJ7 ++L4nxrZy7mBfAVXpOc5vMYztssUI7mL2/iYujiIXM+weZYNTEpLdjyJdu7R5gGUu +g1jSVK/EPHfc74O7AyZU34PNIP4Sh33N+/A5YexrNgJlPY+E3GdVYi4ldWJjgkAd +Qah2PH5ACLrIIC6tRka9hcaBlIECAwEAAaMgMB4wDAYDVR0TBAUwAwEB/zAOBgNV +HQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADgYEAHzC7jdYlzAVmddi/gdAeKPau +sPBG/C2HCWqHzpCUHcKuvMzDVkY/MP2o6JIW2DBbY64bO/FceExhjcykgaYtCH/m +oIU63+CFOTtR7otyQAWHqXa7q4SbCDlG7DyRFxqG0txPtGvy12lgldA2+RgcigQG +Dfcog5wrJytaQ6UA0wE= +-----END CERTIFICATE----- diff --git a/src/core/lib/tsi/test_creds/client.key b/src/core/lib/tsi/test_creds/client.key new file mode 100644 index 0000000000..f48d0735d9 --- /dev/null +++ b/src/core/lib/tsi/test_creds/client.key @@ -0,0 +1,16 @@ +-----BEGIN PRIVATE KEY----- +MIICeQIBADANBgkqhkiG9w0BAQEFAASCAmMwggJfAgEAAoGBAOxUR9uhvhbeVUIM +s5WbH0px0mehl2+6sZpNjzvE2KimZpHzMJHukVH0Ffkvhs0b8+S5Ut9VNUAqd3IM +JCCAEGtRNoQhM1t9Yr2zAckSvbRacp+FL/Cj9eDmyo00KsVGaeefA4Dh4OW+ZhkT +NKcldXqkSuj1sEf244JZYuqZp6/tAgMBAAECgYEAi2NSVqpZMafE5YYUTcMGe6QS +k2jtpsqYgggI2RnLJ/2tNZwYI5pwP8QVSbnMaiF4gokD5hGdrNDfTnb2v+yIwYEH +0w8+oG7Z81KodsiZSIDJfTGsAZhVNwOz9y0VD8BBZZ1/274Zh52AUKLjZS/ZwIbS +W2ywya855dPnH/wj+0ECQQD9X8D920kByTNHhBG18biAEZ4pxs9f0OAG8333eVcI +w2lJDLsYDZrCB2ocgA3lUdozlzPC7YDYw8reg0tkiRY5AkEA7sdNzOeQsQRn7++5 +0bP9DtT/iON1gbfxRzCfCfXdoOtfQWIzTePWtURt9X/5D9NofI0Rg5W2oGy/MLe5 +/sXHVQJBAIup5XrJDkQywNZyAUU2ecn2bCWBFjwtqd+LBmuMciI9fOKsZtEKZrz/ +U0lkeMRoSwvXE8wmGLjjrAbdfohrXFkCQQDZEx/LtIl6JINJQiswVe0tWr6k+ASP +1WXoTm+HYpoF/XUvv9LccNF1IazFj34hwRQwhx7w/V52Ieb+p0jUMYGxAkEAjDhd +9pBO1fKXWiXzi9ZKfoyTNcUq3eBSVKwPG2nItg5ycXengjT5sgcWDnciIzW7BIVI +JiqOszq9GWESErAatg== +-----END PRIVATE KEY----- diff --git a/src/core/lib/tsi/test_creds/client.pem b/src/core/lib/tsi/test_creds/client.pem new file mode 100644 index 0000000000..e332091019 --- /dev/null +++ b/src/core/lib/tsi/test_creds/client.pem @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICHzCCAYgCAQEwDQYJKoZIhvcNAQEFBQAwVjELMAkGA1UEBhMCQVUxEzARBgNV +BAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0 +ZDEPMA0GA1UEAwwGdGVzdGNhMB4XDTE0MDcxNzIzNTYwMloXDTI0MDcxNDIzNTYw +MlowWjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDETMBEGA1UEAwwKdGVzdGNsaWVudDCB +nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA7FRH26G+Ft5VQgyzlZsfSnHSZ6GX +b7qxmk2PO8TYqKZmkfMwke6RUfQV+S+GzRvz5LlS31U1QCp3cgwkIIAQa1E2hCEz +W31ivbMByRK9tFpyn4Uv8KP14ObKjTQqxUZp558DgOHg5b5mGRM0pyV1eqRK6PWw +R/bjglli6pmnr+0CAwEAATANBgkqhkiG9w0BAQUFAAOBgQAStSm5PM7ubROiKK6/ +T2FkKlhiTOx+Ryenm3Eio59emq+jXl+1nhPySX5G2PQzSR5vd1dIhwgZSR4Gyttk +tRZ57k/NI1brUW8joiEOMJA/Mr7H7asx7wIRYDE91Fs8GkKWd5LhoPAQj+qdG35C +OO+svdkmqH0KZo320ZUqdl2ooQ== +-----END CERTIFICATE----- diff --git a/src/core/lib/tsi/test_creds/server0.key b/src/core/lib/tsi/test_creds/server0.key new file mode 100644 index 0000000000..add153c9ae --- /dev/null +++ b/src/core/lib/tsi/test_creds/server0.key @@ -0,0 +1,16 @@ +-----BEGIN PRIVATE KEY----- +MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANOmffupIGC8YDau +rOF4eKnHwPszgpkkhWzKsVxhNDBxCVYx4TEjG0XWIO0iyRXupZbUC+7N/8HnEVNa +8F1jYhng14Iiq99cNQbbnuHHhIztmpocrJTxmnhGzoAnRa1Tb+GnAuRoIHRA/V2c +VUE9tbikQugFx/SPgXAw6tfWB+YvAgMBAAECgYEAoEq9qzUBgoHoVEGiSPiWWe8g +5p6yUA1qx2QTQyWTAwT4z0DjjfVKmG99bFsl8+hTnJFnoCp/gnjflEOROwkjp5kG +m0drqOPx1jeipJjpXYTBu49h+WpZ1PF+KhVtxsIm3OOCvh67iWaKyyOVb5Og8aiR +jl6dn/TdG/dlGD8AfUECQQDuNMle6p0oU8amC6O9wIMBroxx2nFstzE6O35PLEzG +/tj0kxxn9Jp2TS9mGaLCzSuXmpjlF4+NOWiBPkrLC2TfAkEA43Xg7uEUkaJAz2/W +m1lIBTLt+4rIQY/2emh33bDcA+rv8rwwrMMIv17/xPx7bs49YqGG5xufD+Rwl6TL +qFXYsQJAPrOwagax1aKvwJeBw3oAQhoTKAkLIEXcdGqipe6QSzVcIIz0xjxxyEAr +AOIwoLxnBCISqwMXq2H4K0UdZPMb2wJAdhdYLY1L6YRMk6XjzImg25oidisKZweA +FvMv8DgHMj2CUAqmVrt3SivfLH1M9C09L3zfFhOAFHcsgX58gav4MQJBANSBnrHj +tIq4l8z79CPUIuu3QyeEh+XwY8s5qE5CNTck0U59lzp9NvENHbkx3KO896TTerko ++8bXHMLkJkHPXms= +-----END PRIVATE KEY----- diff --git a/src/core/lib/tsi/test_creds/server0.pem b/src/core/lib/tsi/test_creds/server0.pem new file mode 100644 index 0000000000..ade75d8563 --- /dev/null +++ b/src/core/lib/tsi/test_creds/server0.pem @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICHDCCAYUCAQQwDQYJKoZIhvcNAQEFBQAwVjELMAkGA1UEBhMCQVUxEzARBgNV +BAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0 +ZDEPMA0GA1UEAwwGdGVzdGNhMB4XDTE0MDcyMjE3NTk0OVoXDTI0MDcxOTE3NTk0 +OVowVzELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxFDASBgNVBAoM +C0dvb2dsZSBJbmMuMR0wGwYDVQQDDBQqLnRlc3QuZ29vZ2xlLmNvbS5hdTCBnzAN +BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA06Z9+6kgYLxgNq6s4Xh4qcfA+zOCmSSF +bMqxXGE0MHEJVjHhMSMbRdYg7SLJFe6lltQL7s3/wecRU1rwXWNiGeDXgiKr31w1 +Btue4ceEjO2amhyslPGaeEbOgCdFrVNv4acC5GggdED9XZxVQT21uKRC6AXH9I+B +cDDq19YH5i8CAwEAATANBgkqhkiG9w0BAQUFAAOBgQBtfR5qXG9TTI8YcYh7sA4V +GeNoplp0x6p7OG0NLvbJqAkUnkvjIkk1m1R2AUHhbkxzx6G75JIOoNJcWrCzywBA +BIsaTdmnNysf/s1hQJuD3IHiVb+7Ji0jhttnJlYcMid4o0tJO/a2E9YUxR+9cg0i +obb+Ql3qsvKdWBC1dDLDLw== +-----END CERTIFICATE----- diff --git a/src/core/lib/tsi/test_creds/server1-openssl.cnf b/src/core/lib/tsi/test_creds/server1-openssl.cnf new file mode 100644 index 0000000000..8a02108289 --- /dev/null +++ b/src/core/lib/tsi/test_creds/server1-openssl.cnf @@ -0,0 +1,26 @@ +[req] +distinguished_name = req_distinguished_name +req_extensions = v3_req + +[req_distinguished_name] +countryName = Country Name (2 letter code) +countryName_default = US +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = Illinois +localityName = Locality Name (eg, city) +localityName_default = Chicago +organizationName = Organization Name (eg, company) +organizationName_default = Example, Co. +commonName = Common Name (eg, YOUR name) +commonName_max = 64 + +[v3_req] +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment +subjectAltName = @alt_names + +[alt_names] +DNS.1 = *.test.google.fr +DNS.2 = waterzooi.test.google.be +DNS.3 = *.test.youtube.com +IP.1 = "192.168.1.3" diff --git a/src/core/lib/tsi/test_creds/server1.key b/src/core/lib/tsi/test_creds/server1.key new file mode 100644 index 0000000000..143a5b8765 --- /dev/null +++ b/src/core/lib/tsi/test_creds/server1.key @@ -0,0 +1,16 @@ +-----BEGIN PRIVATE KEY----- +MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAOHDFScoLCVJpYDD +M4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1BgzkWF+slf +3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd9N8YwbBY +AckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAECgYAn7qGnM2vbjJNBm0VZCkOkTIWm +V10okw7EPJrdL2mkre9NasghNXbE1y5zDshx5Nt3KsazKOxTT8d0Jwh/3KbaN+YY +tTCbKGW0pXDRBhwUHRcuRzScjli8Rih5UOCiZkhefUTcRb6xIhZJuQy71tjaSy0p +dHZRmYyBYO2YEQ8xoQJBAPrJPhMBkzmEYFtyIEqAxQ/o/A6E+E4w8i+KM7nQCK7q +K4JXzyXVAjLfyBZWHGM2uro/fjqPggGD6QH1qXCkI4MCQQDmdKeb2TrKRh5BY1LR +81aJGKcJ2XbcDu6wMZK4oqWbTX2KiYn9GB0woM6nSr/Y6iy1u145YzYxEV/iMwff +DJULAkB8B2MnyzOg0pNFJqBJuH29bKCcHa8gHJzqXhNO5lAlEbMK95p/P2Wi+4Hd +aiEIAF1BF326QJcvYKmwSmrORp85AkAlSNxRJ50OWrfMZnBgzVjDx3xG6KsFQVk2 +ol6VhqL6dFgKUORFUWBvnKSyhjJxurlPEahV6oo6+A+mPhFY8eUvAkAZQyTdupP3 +XEFQKctGz+9+gKkemDp7LBBMEMBXrGTLPhpEfcjv/7KPdnFHYmhYeBTBnuVmTVWe +F98XJ7tIFfJq +-----END PRIVATE KEY----- diff --git a/src/core/lib/tsi/test_creds/server1.pem b/src/core/lib/tsi/test_creds/server1.pem new file mode 100644 index 0000000000..f3d43fcc5b --- /dev/null +++ b/src/core/lib/tsi/test_creds/server1.pem @@ -0,0 +1,16 @@ +-----BEGIN CERTIFICATE----- +MIICnDCCAgWgAwIBAgIBBzANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJBVTET +MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ +dHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2EwHhcNMTUxMTA0MDIyMDI0WhcNMjUxMTAx +MDIyMDI0WjBlMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV +BAcTB0NoaWNhZ28xFTATBgNVBAoTDEV4YW1wbGUsIENvLjEaMBgGA1UEAxQRKi50 +ZXN0Lmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOHDFSco +LCVJpYDDM4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1Bg +zkWF+slf3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd +9N8YwbBYAckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAGjazBpMAkGA1UdEwQCMAAw +CwYDVR0PBAQDAgXgME8GA1UdEQRIMEaCECoudGVzdC5nb29nbGUuZnKCGHdhdGVy +em9vaS50ZXN0Lmdvb2dsZS5iZYISKi50ZXN0LnlvdXR1YmUuY29thwTAqAEDMA0G +CSqGSIb3DQEBCwUAA4GBAJFXVifQNub1LUP4JlnX5lXNlo8FxZ2a12AFQs+bzoJ6 +hM044EDjqyxUqSbVePK0ni3w1fHQB5rY9yYC5f8G7aqqTY1QOhoUk8ZTSTRpnkTh +y4jjdvTZeLDVBlueZUTDRmy2feY5aZIU18vFDK08dTG0A87pppuv1LNIR3loveU8 +-----END CERTIFICATE----- diff --git a/src/core/lib/tsi/transport_security.c b/src/core/lib/tsi/transport_security.c new file mode 100644 index 0000000000..db219a50a6 --- /dev/null +++ b/src/core/lib/tsi/transport_security.c @@ -0,0 +1,284 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/tsi/transport_security.h" + +#include +#include + +/* --- Tracing. --- */ + +int tsi_tracing_enabled = 0; + +/* --- Utils. --- */ + +char *tsi_strdup(const char *src) { + char *dst; + size_t len; + if (!src) return NULL; + len = strlen(src) + 1; + dst = malloc(len); + if (!dst) return NULL; + memcpy(dst, src, len); + return dst; +} + +/* --- tsi_result common implementation. --- */ + +const char *tsi_result_to_string(tsi_result result) { + switch (result) { + case TSI_OK: + return "TSI_OK"; + case TSI_UNKNOWN_ERROR: + return "TSI_UNKNOWN_ERROR"; + case TSI_INVALID_ARGUMENT: + return "TSI_INVALID_ARGUMENT"; + case TSI_PERMISSION_DENIED: + return "TSI_PERMISSION_DENIED"; + case TSI_INCOMPLETE_DATA: + return "TSI_INCOMPLETE_DATA"; + case TSI_FAILED_PRECONDITION: + return "TSI_FAILED_PRECONDITION"; + case TSI_UNIMPLEMENTED: + return "TSI_UNIMPLEMENTED"; + case TSI_INTERNAL_ERROR: + return "TSI_INTERNAL_ERROR"; + case TSI_DATA_CORRUPTED: + return "TSI_DATA_CORRUPTED"; + case TSI_NOT_FOUND: + return "TSI_NOT_FOUND"; + case TSI_PROTOCOL_FAILURE: + return "TSI_PROTOCOL_FAILURE"; + case TSI_HANDSHAKE_IN_PROGRESS: + return "TSI_HANDSHAKE_IN_PROGRESS"; + case TSI_OUT_OF_RESOURCES: + return "TSI_OUT_OF_RESOURCES"; + default: + return "UNKNOWN"; + } +} + +/* --- tsi_frame_protector common implementation. --- + + Calls specific implementation after state/input validation. */ + +tsi_result tsi_frame_protector_protect(tsi_frame_protector *self, + const unsigned char *unprotected_bytes, + size_t *unprotected_bytes_size, + unsigned char *protected_output_frames, + size_t *protected_output_frames_size) { + if (self == NULL || unprotected_bytes == NULL || + unprotected_bytes_size == NULL || protected_output_frames == NULL || + protected_output_frames_size == NULL) { + return TSI_INVALID_ARGUMENT; + } + return self->vtable->protect(self, unprotected_bytes, unprotected_bytes_size, + protected_output_frames, + protected_output_frames_size); +} + +tsi_result tsi_frame_protector_protect_flush( + tsi_frame_protector *self, unsigned char *protected_output_frames, + size_t *protected_output_frames_size, size_t *still_pending_size) { + if (self == NULL || protected_output_frames == NULL || + protected_output_frames == NULL || still_pending_size == NULL) { + return TSI_INVALID_ARGUMENT; + } + return self->vtable->protect_flush(self, protected_output_frames, + protected_output_frames_size, + still_pending_size); +} + +tsi_result tsi_frame_protector_unprotect( + tsi_frame_protector *self, const unsigned char *protected_frames_bytes, + size_t *protected_frames_bytes_size, unsigned char *unprotected_bytes, + size_t *unprotected_bytes_size) { + if (self == NULL || protected_frames_bytes == NULL || + protected_frames_bytes_size == NULL || unprotected_bytes == NULL || + unprotected_bytes_size == NULL) { + return TSI_INVALID_ARGUMENT; + } + return self->vtable->unprotect(self, protected_frames_bytes, + protected_frames_bytes_size, unprotected_bytes, + unprotected_bytes_size); +} + +void tsi_frame_protector_destroy(tsi_frame_protector *self) { + if (self == NULL) return; + self->vtable->destroy(self); +} + +/* --- tsi_handshaker common implementation. --- + + Calls specific implementation after state/input validation. */ + +tsi_result tsi_handshaker_get_bytes_to_send_to_peer(tsi_handshaker *self, + unsigned char *bytes, + size_t *bytes_size) { + if (self == NULL || bytes == NULL || bytes_size == NULL) { + return TSI_INVALID_ARGUMENT; + } + if (self->frame_protector_created) return TSI_FAILED_PRECONDITION; + return self->vtable->get_bytes_to_send_to_peer(self, bytes, bytes_size); +} + +tsi_result tsi_handshaker_process_bytes_from_peer(tsi_handshaker *self, + const unsigned char *bytes, + size_t *bytes_size) { + if (self == NULL || bytes == NULL || bytes_size == NULL) { + return TSI_INVALID_ARGUMENT; + } + if (self->frame_protector_created) return TSI_FAILED_PRECONDITION; + return self->vtable->process_bytes_from_peer(self, bytes, bytes_size); +} + +tsi_result tsi_handshaker_get_result(tsi_handshaker *self) { + if (self == NULL) return TSI_INVALID_ARGUMENT; + if (self->frame_protector_created) return TSI_FAILED_PRECONDITION; + return self->vtable->get_result(self); +} + +tsi_result tsi_handshaker_extract_peer(tsi_handshaker *self, tsi_peer *peer) { + if (self == NULL || peer == NULL) return TSI_INVALID_ARGUMENT; + memset(peer, 0, sizeof(tsi_peer)); + if (self->frame_protector_created) return TSI_FAILED_PRECONDITION; + if (tsi_handshaker_get_result(self) != TSI_OK) { + return TSI_FAILED_PRECONDITION; + } + return self->vtable->extract_peer(self, peer); +} + +tsi_result tsi_handshaker_create_frame_protector( + tsi_handshaker *self, size_t *max_protected_frame_size, + tsi_frame_protector **protector) { + tsi_result result; + if (self == NULL || protector == NULL) return TSI_INVALID_ARGUMENT; + if (self->frame_protector_created) return TSI_FAILED_PRECONDITION; + if (tsi_handshaker_get_result(self) != TSI_OK) { + return TSI_FAILED_PRECONDITION; + } + result = self->vtable->create_frame_protector(self, max_protected_frame_size, + protector); + if (result == TSI_OK) { + self->frame_protector_created = 1; + } + return result; +} + +void tsi_handshaker_destroy(tsi_handshaker *self) { + if (self == NULL) return; + self->vtable->destroy(self); +} + +/* --- tsi_peer implementation. --- */ + +tsi_peer_property tsi_init_peer_property(void) { + tsi_peer_property property; + memset(&property, 0, sizeof(tsi_peer_property)); + return property; +} + +static void tsi_peer_destroy_list_property(tsi_peer_property *children, + size_t child_count) { + size_t i; + for (i = 0; i < child_count; i++) { + tsi_peer_property_destruct(&children[i]); + } + free(children); +} + +void tsi_peer_property_destruct(tsi_peer_property *property) { + if (property->name != NULL) { + free(property->name); + } + if (property->value.data != NULL) { + free(property->value.data); + } + *property = tsi_init_peer_property(); /* Reset everything to 0. */ +} + +void tsi_peer_destruct(tsi_peer *self) { + if (self == NULL) return; + if (self->properties != NULL) { + tsi_peer_destroy_list_property(self->properties, self->property_count); + self->properties = NULL; + } + self->property_count = 0; +} + +tsi_result tsi_construct_allocated_string_peer_property( + const char *name, size_t value_length, tsi_peer_property *property) { + *property = tsi_init_peer_property(); + if (name != NULL) { + property->name = tsi_strdup(name); + if (property->name == NULL) return TSI_OUT_OF_RESOURCES; + } + if (value_length > 0) { + property->value.data = calloc(1, value_length); + if (property->value.data == NULL) { + tsi_peer_property_destruct(property); + return TSI_OUT_OF_RESOURCES; + } + property->value.length = value_length; + } + return TSI_OK; +} + +tsi_result tsi_construct_string_peer_property_from_cstring( + const char *name, const char *value, tsi_peer_property *property) { + return tsi_construct_string_peer_property(name, value, strlen(value), + property); +} + +tsi_result tsi_construct_string_peer_property(const char *name, + const char *value, + size_t value_length, + tsi_peer_property *property) { + tsi_result result = tsi_construct_allocated_string_peer_property( + name, value_length, property); + if (result != TSI_OK) return result; + if (value_length > 0) { + memcpy(property->value.data, value, value_length); + } + return TSI_OK; +} + +tsi_result tsi_construct_peer(size_t property_count, tsi_peer *peer) { + memset(peer, 0, sizeof(tsi_peer)); + if (property_count > 0) { + peer->properties = calloc(property_count, sizeof(tsi_peer_property)); + if (peer->properties == NULL) return TSI_OUT_OF_RESOURCES; + peer->property_count = property_count; + } + return TSI_OK; +} diff --git a/src/core/lib/tsi/transport_security.h b/src/core/lib/tsi/transport_security.h new file mode 100644 index 0000000000..ecc037193b --- /dev/null +++ b/src/core/lib/tsi/transport_security.h @@ -0,0 +1,111 @@ +/* + * + * Copyright 2015-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_TSI_TRANSPORT_SECURITY_H +#define GRPC_CORE_TSI_TRANSPORT_SECURITY_H + +#include "src/core/tsi/transport_security_interface.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern int tsi_tracing_enabled; + +/* Base for tsi_frame_protector implementations. + See transport_security_interface.h for documentation. */ +typedef struct { + tsi_result (*protect)(tsi_frame_protector *self, + const unsigned char *unprotected_bytes, + size_t *unprotected_bytes_size, + unsigned char *protected_output_frames, + size_t *protected_output_frames_size); + tsi_result (*protect_flush)(tsi_frame_protector *self, + unsigned char *protected_output_frames, + size_t *protected_output_frames_size, + size_t *still_pending_size); + tsi_result (*unprotect)(tsi_frame_protector *self, + const unsigned char *protected_frames_bytes, + size_t *protected_frames_bytes_size, + unsigned char *unprotected_bytes, + size_t *unprotected_bytes_size); + void (*destroy)(tsi_frame_protector *self); +} tsi_frame_protector_vtable; + +struct tsi_frame_protector { + const tsi_frame_protector_vtable *vtable; +}; + +/* Base for tsi_handshaker implementations. + See transport_security_interface.h for documentation. */ +typedef struct { + tsi_result (*get_bytes_to_send_to_peer)(tsi_handshaker *self, + unsigned char *bytes, + size_t *bytes_size); + tsi_result (*process_bytes_from_peer)(tsi_handshaker *self, + const unsigned char *bytes, + size_t *bytes_size); + tsi_result (*get_result)(tsi_handshaker *self); + tsi_result (*extract_peer)(tsi_handshaker *self, tsi_peer *peer); + tsi_result (*create_frame_protector)(tsi_handshaker *self, + size_t *max_protected_frame_size, + tsi_frame_protector **protector); + void (*destroy)(tsi_handshaker *self); +} tsi_handshaker_vtable; + +struct tsi_handshaker { + const tsi_handshaker_vtable *vtable; + int frame_protector_created; +}; + +/* Peer and property construction/destruction functions. */ +tsi_result tsi_construct_peer(size_t property_count, tsi_peer *peer); +tsi_peer_property tsi_init_peer_property(void); +void tsi_peer_property_destruct(tsi_peer_property *property); +tsi_result tsi_construct_string_peer_property(const char *name, + const char *value, + size_t value_length, + tsi_peer_property *property); +tsi_result tsi_construct_allocated_string_peer_property( + const char *name, size_t value_length, tsi_peer_property *property); +tsi_result tsi_construct_string_peer_property_from_cstring( + const char *name, const char *value, tsi_peer_property *property); + +/* Utils. */ +char *tsi_strdup(const char *src); /* Sadly, no strdup in C89. */ + +#ifdef __cplusplus +} +#endif + +#endif /* GRPC_CORE_TSI_TRANSPORT_SECURITY_H */ diff --git a/src/core/lib/tsi/transport_security_interface.h b/src/core/lib/tsi/transport_security_interface.h new file mode 100644 index 0000000000..08501802f5 --- /dev/null +++ b/src/core/lib/tsi/transport_security_interface.h @@ -0,0 +1,344 @@ +/* + * + * Copyright 2015-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_TSI_TRANSPORT_SECURITY_INTERFACE_H +#define GRPC_CORE_TSI_TRANSPORT_SECURITY_INTERFACE_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* --- tsi result --- */ + +typedef enum { + TSI_OK = 0, + TSI_UNKNOWN_ERROR = 1, + TSI_INVALID_ARGUMENT = 2, + TSI_PERMISSION_DENIED = 3, + TSI_INCOMPLETE_DATA = 4, + TSI_FAILED_PRECONDITION = 5, + TSI_UNIMPLEMENTED = 6, + TSI_INTERNAL_ERROR = 7, + TSI_DATA_CORRUPTED = 8, + TSI_NOT_FOUND = 9, + TSI_PROTOCOL_FAILURE = 10, + TSI_HANDSHAKE_IN_PROGRESS = 11, + TSI_OUT_OF_RESOURCES = 12 +} tsi_result; + +const char *tsi_result_to_string(tsi_result result); + +/* --- tsi tracing --- */ + +/* Set this early to avoid races */ +extern int tsi_tracing_enabled; + +/* --- tsi_frame_protector object --- + + This object protects and unprotects buffers once the handshake is done. + Implementations of this object must be thread compatible. */ + +typedef struct tsi_frame_protector tsi_frame_protector; + +/* Outputs protected frames. + - unprotected_bytes is an input only parameter and points to the data + to be protected. + - unprotected_bytes_size is an input/output parameter used by the caller to + specify how many bytes are available in unprotected_bytes. The output + value is the number of bytes consumed during the call. + - protected_output_frames points to a buffer allocated by the caller that + will be written. + - protected_output_frames_size is an input/output parameter used by the + caller to specify how many bytes are available in protected_output_frames. + As an output, this value indicates the number of bytes written. + - This method returns TSI_OK in case of success or a specific error code in + case of failure. Note that even if all the input unprotected bytes are + consumed, they may not have been processed into the returned protected + output frames. The caller should call the protect_flush method + to make sure that there are no more protected bytes buffered in the + protector. + + A typical way to call this method would be: + + ------------------------------------------------------------------------ + unsigned char protected_buffer[4096]; + size_t protected_buffer_size = sizeof(protected_buffer); + tsi_result result = TSI_OK; + while (message_size > 0) { + size_t protected_buffer_size_to_send = protected_buffer_size; + size_t processed_message_size = message_size; + result = tsi_frame_protector_protect(protector, + message_bytes, + &processed_message_size, + protected_buffer, + &protected_buffer_size_to_send); + if (result != TSI_OK) break; + send_bytes_to_peer(protected_buffer, protected_buffer_size_to_send); + message_bytes += processed_message_size; + message_size -= processed_message_size; + + // Don't forget to flush. + if (message_size == 0) { + size_t still_pending_size; + do { + protected_buffer_size_to_send = protected_buffer_size; + result = tsi_frame_protector_protect_flush( + protector, protected_buffer, + &protected_buffer_size_to_send, &still_pending_size); + if (result != TSI_OK) break; + send_bytes_to_peer(protected_buffer, protected_buffer_size_to_send); + } while (still_pending_size > 0); + } + } + + if (result != TSI_OK) HandleError(result); + ------------------------------------------------------------------------ */ +tsi_result tsi_frame_protector_protect(tsi_frame_protector *self, + const unsigned char *unprotected_bytes, + size_t *unprotected_bytes_size, + unsigned char *protected_output_frames, + size_t *protected_output_frames_size); + +/* Indicates that we need to flush the bytes buffered in the protector and get + the resulting frame. + - protected_output_frames points to a buffer allocated by the caller that + will be written. + - protected_output_frames_size is an input/output parameter used by the + caller to specify how many bytes are available in protected_output_frames. + - still_pending_bytes is an output parameter indicating the number of bytes + that still need to be flushed from the protector.*/ +tsi_result tsi_frame_protector_protect_flush( + tsi_frame_protector *self, unsigned char *protected_output_frames, + size_t *protected_output_frames_size, size_t *still_pending_size); + +/* Outputs unprotected bytes. + - protected_frames_bytes is an input only parameter and points to the + protected frames to be unprotected. + - protected_frames_bytes_size is an input/output only parameter used by the + caller to specify how many bytes are available in protected_bytes. The + output value is the number of bytes consumed during the call. + Implementations will buffer up to a frame of protected data. + - unprotected_bytes points to a buffer allocated by the caller that will be + written. + - unprotected_bytes_size is an input/output parameter used by the caller to + specify how many bytes are available in unprotected_bytes. This + value is expected to be at most max_protected_frame_size minus overhead + which means that max_protected_frame_size is a safe bet. The output value + is the number of bytes actually written. + If *unprotected_bytes_size is unchanged, there may be more data remaining + to unprotect, and the caller should call this function again. + + - This method returns TSI_OK in case of success. Success includes cases where + there is not enough data to output a frame in which case + unprotected_bytes_size will be set to 0 and cases where the internal buffer + needs to be read before new protected data can be processed in which case + protected_frames_size will be set to 0. */ +tsi_result tsi_frame_protector_unprotect( + tsi_frame_protector *self, const unsigned char *protected_frames_bytes, + size_t *protected_frames_bytes_size, unsigned char *unprotected_bytes, + size_t *unprotected_bytes_size); + +/* Destroys the tsi_frame_protector object. */ +void tsi_frame_protector_destroy(tsi_frame_protector *self); + +/* --- tsi_peer objects --- + + tsi_peer objects are a set of properties. The peer owns the properties. */ + +/* This property is of type TSI_PEER_PROPERTY_STRING. */ +#define TSI_CERTIFICATE_TYPE_PEER_PROPERTY "certificate_type" + +/* Property values may contain NULL characters just like C++ strings. + The length field gives the length of the string. */ +typedef struct tsi_peer_property { + char *name; + struct { + char *data; + size_t length; + } value; +} tsi_peer_property; + +typedef struct { + tsi_peer_property *properties; + size_t property_count; +} tsi_peer; + +/* Destructs the tsi_peer object. */ +void tsi_peer_destruct(tsi_peer *self); + +/* --- tsi_handshaker objects ---- + + Implementations of this object must be thread compatible. + + A typical usage of this object would be: + + ------------------------------------------------------------------------ + tsi_result result = TSI_OK; + unsigned char buf[4096]; + size_t buf_offset; + size_t buf_size; + while (1) { + // See if we need to send some bytes to the peer. + do { + size_t buf_size_to_send = sizeof(buf); + result = tsi_handshaker_get_bytes_to_send_to_peer(handshaker, buf, + &buf_size_to_send); + if (buf_size_to_send > 0) send_bytes_to_peer(buf, buf_size_to_send); + } while (result == TSI_INCOMPLETE_DATA); + if (result != TSI_OK) return result; + if (!tsi_handshaker_is_in_progress(handshaker)) break; + + do { + // Read bytes from the peer. + buf_size = sizeof(buf); + buf_offset = 0; + read_bytes_from_peer(buf, &buf_size); + if (buf_size == 0) break; + + // Process the bytes from the peer. We have to be careful as these bytes + // may contain non-handshake data (protected data). If this is the case, + // we will exit from the loop with buf_size > 0. + size_t consumed_by_handshaker = buf_size; + result = tsi_handshaker_process_bytes_from_peer( + handshaker, buf, &consumed_by_handshaker); + buf_size -= consumed_by_handshaker; + buf_offset += consumed_by_handshaker; + } while (result == TSI_INCOMPLETE_DATA); + + if (result != TSI_OK) return result; + if (!tsi_handshaker_is_in_progress(handshaker)) break; + } + + // Check the Peer. + tsi_peer peer; + do { + result = tsi_handshaker_extract_peer(handshaker, &peer); + if (result != TSI_OK) break; + result = check_peer(&peer); + } while (0); + tsi_peer_destruct(&peer); + if (result != TSI_OK) return result; + + // Create the protector. + tsi_frame_protector* protector = NULL; + result = tsi_handshaker_create_frame_protector(handshaker, NULL, + &protector); + if (result != TSI_OK) return result; + + // Do not forget to unprotect outstanding data if any. + if (buf_size > 0) { + result = tsi_frame_protector_unprotect(protector, buf + buf_offset, + buf_size, ..., ...); + .... + } + ... + ------------------------------------------------------------------------ */ +typedef struct tsi_handshaker tsi_handshaker; + +/* Gets bytes that need to be sent to the peer. + - bytes is the buffer that will be written with the data to be sent to the + peer. + - bytes_size is an input/output parameter specifying the capacity of the + bytes parameter as input and the number of bytes written as output. + Returns TSI_OK if all the data to send to the peer has been written or if + nothing has to be sent to the peer (in which base bytes_size outputs to 0), + otherwise returns TSI_INCOMPLETE_DATA which indicates that this method + needs to be called again to get all the bytes to send to the peer (there + was more data to write than the specified bytes_size). In case of a fatal + error in the handshake, another specific error code is returned. */ +tsi_result tsi_handshaker_get_bytes_to_send_to_peer(tsi_handshaker *self, + unsigned char *bytes, + size_t *bytes_size); + +/* Processes bytes received from the peer. + - bytes is the buffer containing the data. + - bytes_size is an input/output parameter specifying the size of the data as + input and the number of bytes consumed as output. + Return TSI_OK if the handshake has all the data it needs to process, + otherwise return TSI_INCOMPLETE_DATA which indicates that this method + needs to be called again to complete the data needed for processing. In + case of a fatal error in the handshake, another specific error code is + returned. */ +tsi_result tsi_handshaker_process_bytes_from_peer(tsi_handshaker *self, + const unsigned char *bytes, + size_t *bytes_size); + +/* Gets the result of the handshaker. + Returns TSI_OK if the hanshake completed successfully and there has been no + errors. Returns TSI_HANDSHAKE_IN_PROGRESS if the handshaker is not done yet + but no error has been encountered so far. Otherwise the handshaker failed + with the returned error. */ +tsi_result tsi_handshaker_get_result(tsi_handshaker *self); + +/* Returns 1 if the handshake is in progress, 0 otherwise. */ +#define tsi_handshaker_is_in_progress(h) \ + (tsi_handshaker_get_result((h)) == TSI_HANDSHAKE_IN_PROGRESS) + +/* This method may return TSI_FAILED_PRECONDITION if + tsi_handshaker_is_in_progress returns 1, it returns TSI_OK otherwise + assuming the handshaker is not in a fatal error state. + The caller is responsible for destructing the peer. */ +tsi_result tsi_handshaker_extract_peer(tsi_handshaker *self, tsi_peer *peer); + +/* This method creates a tsi_frame_protector object after the handshake phase + is done. After this method has been called successfully, the only method + that can be called on this object is Destroy. + - max_output_protected_frame_size is an input/output parameter specifying the + desired max output protected frame size as input and outputing the actual + max output frame size as the output. Passing NULL is OK and will result in + the implementation choosing the default maximum protected frame size. Note + that this size only applies to outgoing frames (generated with + tsi_frame_protector_protect) and not incoming frames (input of + tsi_frame_protector_unprotect). + - protector is an output parameter pointing to the newly created + tsi_frame_protector object. + This method may return TSI_FAILED_PRECONDITION if + tsi_handshaker_is_in_progress returns 1, it returns TSI_OK otherwise assuming + the handshaker is not in a fatal error state. + The caller is responsible for destroying the protector. */ +tsi_result tsi_handshaker_create_frame_protector( + tsi_handshaker *self, size_t *max_output_protected_frame_size, + tsi_frame_protector **protector); + +/* This method releases the tsi_handshaker object. After this method is called, + no other method can be called on the object. */ +void tsi_handshaker_destroy(tsi_handshaker *self); + +#ifdef __cplusplus +} +#endif + +#endif /* GRPC_CORE_TSI_TRANSPORT_SECURITY_INTERFACE_H */ diff --git a/src/core/profiling/basic_timers.c b/src/core/profiling/basic_timers.c deleted file mode 100644 index 3067f52c21..0000000000 --- a/src/core/profiling/basic_timers.c +++ /dev/null @@ -1,274 +0,0 @@ -/* - * - * Copyright 2015-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 - -#ifdef GRPC_BASIC_PROFILER - -#include "src/core/profiling/timers.h" - -#include -#include -#include -#include -#include -#include - -typedef enum { BEGIN = '{', END = '}', MARK = '.' } marker_type; - -typedef struct gpr_timer_entry { - gpr_timespec tm; - const char *tagstr; - const char *file; - short line; - char type; - uint8_t important; - int thd; -} gpr_timer_entry; - -#define MAX_COUNT 1000000 - -typedef struct gpr_timer_log { - size_t num_entries; - struct gpr_timer_log *next; - struct gpr_timer_log *prev; - gpr_timer_entry log[MAX_COUNT]; -} gpr_timer_log; - -typedef struct gpr_timer_log_list { - gpr_timer_log *head; - /* valid iff head!=NULL */ - gpr_timer_log *tail; -} gpr_timer_log_list; - -static __thread gpr_timer_log *g_thread_log; -static gpr_once g_once_init = GPR_ONCE_INIT; -static FILE *output_file; -static const char *output_filename = "latency_trace.txt"; -static pthread_mutex_t g_mu; -static pthread_cond_t g_cv; -static gpr_timer_log_list g_in_progress_logs; -static gpr_timer_log_list g_done_logs; -static int g_shutdown; -static gpr_thd_id g_writing_thread; -static __thread int g_thread_id; -static int g_next_thread_id; - -static int timer_log_push_back(gpr_timer_log_list *list, gpr_timer_log *log) { - if (list->head == NULL) { - list->head = list->tail = log; - log->next = log->prev = NULL; - return 1; - } else { - log->prev = list->tail; - log->next = NULL; - list->tail->next = log; - list->tail = log; - return 0; - } -} - -static gpr_timer_log *timer_log_pop_front(gpr_timer_log_list *list) { - gpr_timer_log *out = list->head; - if (out != NULL) { - list->head = out->next; - if (list->head != NULL) { - list->head->prev = NULL; - } else { - list->tail = NULL; - } - } - return out; -} - -static void timer_log_remove(gpr_timer_log_list *list, gpr_timer_log *log) { - if (log->prev == NULL) { - list->head = log->next; - if (list->head != NULL) { - list->head->prev = NULL; - } - } else { - log->prev->next = log->next; - } - if (log->next == NULL) { - list->tail = log->prev; - if (list->tail != NULL) { - list->tail->next = NULL; - } - } else { - log->next->prev = log->prev; - } -} - -static void write_log(gpr_timer_log *log) { - size_t i; - if (output_file == NULL) { - output_file = fopen(output_filename, "w"); - } - for (i = 0; i < log->num_entries; i++) { - gpr_timer_entry *entry = &(log->log[i]); - if (gpr_time_cmp(entry->tm, gpr_time_0(entry->tm.clock_type)) < 0) { - entry->tm = gpr_time_0(entry->tm.clock_type); - } - fprintf(output_file, - "{\"t\": %lld.%09d, \"thd\": \"%d\", \"type\": \"%c\", \"tag\": " - "\"%s\", \"file\": \"%s\", \"line\": %d, \"imp\": %d}\n", - (long long)entry->tm.tv_sec, (int)entry->tm.tv_nsec, entry->thd, - entry->type, entry->tagstr, entry->file, entry->line, - entry->important); - } -} - -static void writing_thread(void *unused) { - gpr_timer_log *log; - pthread_mutex_lock(&g_mu); - for (;;) { - while ((log = timer_log_pop_front(&g_done_logs)) == NULL && !g_shutdown) { - pthread_cond_wait(&g_cv, &g_mu); - } - if (log != NULL) { - pthread_mutex_unlock(&g_mu); - write_log(log); - free(log); - pthread_mutex_lock(&g_mu); - } - if (g_shutdown) { - pthread_mutex_unlock(&g_mu); - return; - } - } -} - -static void flush_logs(gpr_timer_log_list *list) { - gpr_timer_log *log; - while ((log = timer_log_pop_front(list)) != NULL) { - write_log(log); - free(log); - } -} - -static void finish_writing() { - pthread_mutex_lock(&g_mu); - g_shutdown = 1; - pthread_cond_signal(&g_cv); - pthread_mutex_unlock(&g_mu); - gpr_thd_join(g_writing_thread); - - gpr_log(GPR_INFO, "flushing logs"); - - pthread_mutex_lock(&g_mu); - flush_logs(&g_done_logs); - flush_logs(&g_in_progress_logs); - pthread_mutex_unlock(&g_mu); - - if (output_file) { - fclose(output_file); - } -} - -void gpr_timers_set_log_filename(const char *filename) { - output_filename = filename; -} - -static void init_output() { - gpr_thd_options options = gpr_thd_options_default(); - gpr_thd_options_set_joinable(&options); - gpr_thd_new(&g_writing_thread, writing_thread, NULL, &options); - atexit(finish_writing); -} - -static void rotate_log() { - gpr_timer_log *new = malloc(sizeof(*new)); - gpr_once_init(&g_once_init, init_output); - new->num_entries = 0; - pthread_mutex_lock(&g_mu); - if (g_thread_log != NULL) { - timer_log_remove(&g_in_progress_logs, g_thread_log); - if (timer_log_push_back(&g_done_logs, g_thread_log)) { - pthread_cond_signal(&g_cv); - } - } else { - g_thread_id = g_next_thread_id++; - } - timer_log_push_back(&g_in_progress_logs, new); - pthread_mutex_unlock(&g_mu); - g_thread_log = new; -} - -static void gpr_timers_log_add(const char *tagstr, marker_type type, - int important, const char *file, int line) { - gpr_timer_entry *entry; - - if (g_thread_log == NULL || g_thread_log->num_entries == MAX_COUNT) { - rotate_log(); - } - - entry = &g_thread_log->log[g_thread_log->num_entries++]; - - entry->tm = gpr_now(GPR_CLOCK_PRECISE); - entry->tagstr = tagstr; - entry->type = type; - entry->file = file; - entry->line = (short)line; - entry->important = important != 0; - entry->thd = g_thread_id; -} - -/* Latency profiler API implementation. */ -void gpr_timer_add_mark(const char *tagstr, int important, const char *file, - int line) { - gpr_timers_log_add(tagstr, MARK, important, file, line); -} - -void gpr_timer_begin(const char *tagstr, int important, const char *file, - int line) { - gpr_timers_log_add(tagstr, BEGIN, important, file, line); -} - -void gpr_timer_end(const char *tagstr, int important, const char *file, - int line) { - gpr_timers_log_add(tagstr, END, important, file, line); -} - -/* Basic profiler specific API functions. */ -void gpr_timers_global_init(void) {} - -void gpr_timers_global_destroy(void) {} - -#else /* !GRPC_BASIC_PROFILER */ -void gpr_timers_global_init(void) {} - -void gpr_timers_global_destroy(void) {} - -void gpr_timers_set_log_filename(const char *filename) {} -#endif /* GRPC_BASIC_PROFILER */ diff --git a/src/core/profiling/stap_probes.d b/src/core/profiling/stap_probes.d deleted file mode 100644 index 153de91752..0000000000 --- a/src/core/profiling/stap_probes.d +++ /dev/null @@ -1,7 +0,0 @@ -provider _stap { - probe add_mark(int tag); - probe add_important_mark(int tag); - probe timing_ns_begin(int tag); - probe timing_ns_end(int tag); -}; - diff --git a/src/core/profiling/stap_timers.c b/src/core/profiling/stap_timers.c deleted file mode 100644 index efcd1af4a1..0000000000 --- a/src/core/profiling/stap_timers.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include - -#ifdef GRPC_STAP_PROFILER - -#include "src/core/profiling/timers.h" - -#include -/* Generated from src/core/profiling/stap_probes.d */ -#include "src/core/profiling/stap_probes.h" - -/* Latency profiler API implementation. */ -void gpr_timer_add_mark(int tag, const char *tagstr, void *id, const char *file, - int line) { - _STAP_ADD_MARK(tag); -} - -void gpr_timer_add_important_mark(int tag, const char *tagstr, void *id, - const char *file, int line) { - _STAP_ADD_IMPORTANT_MARK(tag); -} - -void gpr_timer_begin(int tag, const char *tagstr, void *id, const char *file, - int line) { - _STAP_TIMING_NS_BEGIN(tag); -} - -void gpr_timer_end(int tag, const char *tagstr, void *id, const char *file, - int line) { - _STAP_TIMING_NS_END(tag); -} - -#endif /* GRPC_STAP_PROFILER */ diff --git a/src/core/profiling/timers.h b/src/core/profiling/timers.h deleted file mode 100644 index 6a188dc566..0000000000 --- a/src/core/profiling/timers.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef GRPC_CORE_PROFILING_TIMERS_H -#define GRPC_CORE_PROFILING_TIMERS_H - -#ifdef __cplusplus -extern "C" { -#endif - -void gpr_timers_global_init(void); -void gpr_timers_global_destroy(void); - -void gpr_timer_add_mark(const char *tagstr, int important, const char *file, - int line); -void gpr_timer_begin(const char *tagstr, int important, const char *file, - int line); -void gpr_timer_end(const char *tagstr, int important, const char *file, - int line); - -void gpr_timers_set_log_filename(const char *filename); - -#if !(defined(GRPC_STAP_PROFILER) + defined(GRPC_BASIC_PROFILER)) -/* No profiling. No-op all the things. */ -#define GPR_TIMER_MARK(tag, important) \ - do { \ - } while (0) - -#define GPR_TIMER_BEGIN(tag, important) \ - do { \ - } while (0) - -#define GPR_TIMER_END(tag, important) \ - do { \ - } while (0) - -#else /* at least one profiler requested... */ -/* ... hopefully only one. */ -#if defined(GRPC_STAP_PROFILER) && defined(GRPC_BASIC_PROFILER) -#error "GRPC_STAP_PROFILER and GRPC_BASIC_PROFILER are mutually exclusive." -#endif - -/* Generic profiling interface. */ -#define GPR_TIMER_MARK(tag, important) \ - gpr_timer_add_mark(tag, important, __FILE__, __LINE__); - -#define GPR_TIMER_BEGIN(tag, important) \ - gpr_timer_begin(tag, important, __FILE__, __LINE__); - -#define GPR_TIMER_END(tag, important) \ - gpr_timer_end(tag, important, __FILE__, __LINE__); - -#ifdef GRPC_STAP_PROFILER -/* Empty placeholder for now. */ -#endif /* GRPC_STAP_PROFILER */ - -#ifdef GRPC_BASIC_PROFILER -/* Empty placeholder for now. */ -#endif /* GRPC_BASIC_PROFILER */ - -#endif /* at least one profiler requested. */ - -#ifdef __cplusplus -} - -#if (defined(GRPC_STAP_PROFILER) + defined(GRPC_BASIC_PROFILER)) -namespace grpc { -class ProfileScope { - public: - ProfileScope(const char *desc, bool important) : desc_(desc) { - GPR_TIMER_BEGIN(desc_, important ? 1 : 0); - } - ~ProfileScope() { GPR_TIMER_END(desc_, 0); } - - private: - const char *const desc_; -}; -} - -#define GPR_TIMER_SCOPE(tag, important) \ - ::grpc::ProfileScope _profile_scope_##__LINE__((tag), (important)) -#else -#define GPR_TIMER_SCOPE(tag, important) \ - do { \ - } while (false) -#endif -#endif - -#endif /* GRPC_CORE_PROFILING_TIMERS_H */ diff --git a/src/core/proto/grpc/lb/v0/load_balancer.pb.c b/src/core/proto/grpc/lb/v0/load_balancer.pb.c deleted file mode 100644 index 59aae30cff..0000000000 --- a/src/core/proto/grpc/lb/v0/load_balancer.pb.c +++ /dev/null @@ -1,119 +0,0 @@ -/* - * - * 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. - * - */ -/* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.3.5-dev */ - -#include "src/core/proto/grpc/lb/v0/load_balancer.pb.h" - -#if PB_PROTO_HEADER_VERSION != 30 -#error Regenerate this file with the current version of nanopb generator. -#endif - - - -const pb_field_t grpc_lb_v0_Duration_fields[3] = { - PB_FIELD( 1, INT64 , OPTIONAL, STATIC , FIRST, grpc_lb_v0_Duration, seconds, seconds, 0), - PB_FIELD( 2, INT32 , OPTIONAL, STATIC , OTHER, grpc_lb_v0_Duration, nanos, seconds, 0), - PB_LAST_FIELD -}; - -const pb_field_t grpc_lb_v0_LoadBalanceRequest_fields[3] = { - PB_FIELD( 1, MESSAGE , OPTIONAL, STATIC , FIRST, grpc_lb_v0_LoadBalanceRequest, initial_request, initial_request, &grpc_lb_v0_InitialLoadBalanceRequest_fields), - PB_FIELD( 2, MESSAGE , OPTIONAL, STATIC , OTHER, grpc_lb_v0_LoadBalanceRequest, client_stats, initial_request, &grpc_lb_v0_ClientStats_fields), - PB_LAST_FIELD -}; - -const pb_field_t grpc_lb_v0_InitialLoadBalanceRequest_fields[2] = { - PB_FIELD( 1, STRING , OPTIONAL, STATIC , FIRST, grpc_lb_v0_InitialLoadBalanceRequest, name, name, 0), - PB_LAST_FIELD -}; - -const pb_field_t grpc_lb_v0_ClientStats_fields[4] = { - PB_FIELD( 1, INT64 , OPTIONAL, STATIC , FIRST, grpc_lb_v0_ClientStats, total_requests, total_requests, 0), - PB_FIELD( 2, INT64 , OPTIONAL, STATIC , OTHER, grpc_lb_v0_ClientStats, client_rpc_errors, total_requests, 0), - PB_FIELD( 3, INT64 , OPTIONAL, STATIC , OTHER, grpc_lb_v0_ClientStats, dropped_requests, client_rpc_errors, 0), - PB_LAST_FIELD -}; - -const pb_field_t grpc_lb_v0_LoadBalanceResponse_fields[3] = { - PB_FIELD( 1, MESSAGE , OPTIONAL, STATIC , FIRST, grpc_lb_v0_LoadBalanceResponse, initial_response, initial_response, &grpc_lb_v0_InitialLoadBalanceResponse_fields), - PB_FIELD( 2, MESSAGE , OPTIONAL, STATIC , OTHER, grpc_lb_v0_LoadBalanceResponse, server_list, initial_response, &grpc_lb_v0_ServerList_fields), - PB_LAST_FIELD -}; - -const pb_field_t grpc_lb_v0_InitialLoadBalanceResponse_fields[4] = { - PB_FIELD( 1, STRING , OPTIONAL, STATIC , FIRST, grpc_lb_v0_InitialLoadBalanceResponse, client_config, client_config, 0), - PB_FIELD( 2, STRING , OPTIONAL, STATIC , OTHER, grpc_lb_v0_InitialLoadBalanceResponse, load_balancer_delegate, client_config, 0), - PB_FIELD( 3, MESSAGE , OPTIONAL, STATIC , OTHER, grpc_lb_v0_InitialLoadBalanceResponse, client_stats_report_interval, load_balancer_delegate, &grpc_lb_v0_Duration_fields), - PB_LAST_FIELD -}; - -const pb_field_t grpc_lb_v0_ServerList_fields[3] = { - PB_FIELD( 1, MESSAGE , REPEATED, CALLBACK, FIRST, grpc_lb_v0_ServerList, servers, servers, &grpc_lb_v0_Server_fields), - PB_FIELD( 3, MESSAGE , OPTIONAL, STATIC , OTHER, grpc_lb_v0_ServerList, expiration_interval, servers, &grpc_lb_v0_Duration_fields), - PB_LAST_FIELD -}; - -const pb_field_t grpc_lb_v0_Server_fields[5] = { - PB_FIELD( 1, STRING , OPTIONAL, STATIC , FIRST, grpc_lb_v0_Server, ip_address, ip_address, 0), - PB_FIELD( 2, INT32 , OPTIONAL, STATIC , OTHER, grpc_lb_v0_Server, port, ip_address, 0), - PB_FIELD( 3, BYTES , OPTIONAL, STATIC , OTHER, grpc_lb_v0_Server, load_balance_token, port, 0), - PB_FIELD( 4, BOOL , OPTIONAL, STATIC , OTHER, grpc_lb_v0_Server, drop_request, load_balance_token, 0), - PB_LAST_FIELD -}; - - -/* Check that field information fits in pb_field_t */ -#if !defined(PB_FIELD_32BIT) -/* If you get an error here, it means that you need to define PB_FIELD_32BIT - * compile-time option. You can do that in pb.h or on compiler command line. - * - * The reason you need to do this is that some of your messages contain tag - * numbers or field sizes that are larger than what can fit in 8 or 16 bit - * field descriptors. - */ -PB_STATIC_ASSERT((pb_membersize(grpc_lb_v0_LoadBalanceRequest, initial_request) < 65536 && pb_membersize(grpc_lb_v0_LoadBalanceRequest, client_stats) < 65536 && pb_membersize(grpc_lb_v0_LoadBalanceResponse, initial_response) < 65536 && pb_membersize(grpc_lb_v0_LoadBalanceResponse, server_list) < 65536 && pb_membersize(grpc_lb_v0_InitialLoadBalanceResponse, client_stats_report_interval) < 65536 && pb_membersize(grpc_lb_v0_ServerList, servers) < 65536 && pb_membersize(grpc_lb_v0_ServerList, expiration_interval) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_grpc_lb_v0_Duration_grpc_lb_v0_LoadBalanceRequest_grpc_lb_v0_InitialLoadBalanceRequest_grpc_lb_v0_ClientStats_grpc_lb_v0_LoadBalanceResponse_grpc_lb_v0_InitialLoadBalanceResponse_grpc_lb_v0_ServerList_grpc_lb_v0_Server) -#endif - -#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) -/* If you get an error here, it means that you need to define PB_FIELD_16BIT - * compile-time option. You can do that in pb.h or on compiler command line. - * - * The reason you need to do this is that some of your messages contain tag - * numbers or field sizes that are larger than what can fit in the default - * 8 bit descriptors. - */ -PB_STATIC_ASSERT((pb_membersize(grpc_lb_v0_LoadBalanceRequest, initial_request) < 256 && pb_membersize(grpc_lb_v0_LoadBalanceRequest, client_stats) < 256 && pb_membersize(grpc_lb_v0_LoadBalanceResponse, initial_response) < 256 && pb_membersize(grpc_lb_v0_LoadBalanceResponse, server_list) < 256 && pb_membersize(grpc_lb_v0_InitialLoadBalanceResponse, client_stats_report_interval) < 256 && pb_membersize(grpc_lb_v0_ServerList, servers) < 256 && pb_membersize(grpc_lb_v0_ServerList, expiration_interval) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_grpc_lb_v0_Duration_grpc_lb_v0_LoadBalanceRequest_grpc_lb_v0_InitialLoadBalanceRequest_grpc_lb_v0_ClientStats_grpc_lb_v0_LoadBalanceResponse_grpc_lb_v0_InitialLoadBalanceResponse_grpc_lb_v0_ServerList_grpc_lb_v0_Server) -#endif - - diff --git a/src/core/proto/grpc/lb/v0/load_balancer.pb.h b/src/core/proto/grpc/lb/v0/load_balancer.pb.h deleted file mode 100644 index 3599f881bb..0000000000 --- a/src/core/proto/grpc/lb/v0/load_balancer.pb.h +++ /dev/null @@ -1,182 +0,0 @@ -/* - * - * 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. - * - */ -/* Automatically generated nanopb header */ -/* Generated by nanopb-0.3.5-dev */ - -#ifndef PB_LOAD_BALANCER_PB_H_INCLUDED -#define PB_LOAD_BALANCER_PB_H_INCLUDED -#include "third_party/nanopb/pb.h" -#if PB_PROTO_HEADER_VERSION != 30 -#error Regenerate this file with the current version of nanopb generator. -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* Struct definitions */ -typedef struct _grpc_lb_v0_ClientStats { - bool has_total_requests; - int64_t total_requests; - bool has_client_rpc_errors; - int64_t client_rpc_errors; - bool has_dropped_requests; - int64_t dropped_requests; -} grpc_lb_v0_ClientStats; - -typedef struct _grpc_lb_v0_Duration { - bool has_seconds; - int64_t seconds; - bool has_nanos; - int32_t nanos; -} grpc_lb_v0_Duration; - -typedef struct _grpc_lb_v0_InitialLoadBalanceRequest { - bool has_name; - char name[128]; -} grpc_lb_v0_InitialLoadBalanceRequest; - -typedef PB_BYTES_ARRAY_T(64) grpc_lb_v0_Server_load_balance_token_t; -typedef struct _grpc_lb_v0_Server { - bool has_ip_address; - char ip_address[46]; - bool has_port; - int32_t port; - bool has_load_balance_token; - grpc_lb_v0_Server_load_balance_token_t load_balance_token; - bool has_drop_request; - bool drop_request; -} grpc_lb_v0_Server; - -typedef struct _grpc_lb_v0_InitialLoadBalanceResponse { - bool has_client_config; - char client_config[64]; - bool has_load_balancer_delegate; - char load_balancer_delegate[64]; - bool has_client_stats_report_interval; - grpc_lb_v0_Duration client_stats_report_interval; -} grpc_lb_v0_InitialLoadBalanceResponse; - -typedef struct _grpc_lb_v0_LoadBalanceRequest { - bool has_initial_request; - grpc_lb_v0_InitialLoadBalanceRequest initial_request; - bool has_client_stats; - grpc_lb_v0_ClientStats client_stats; -} grpc_lb_v0_LoadBalanceRequest; - -typedef struct _grpc_lb_v0_ServerList { - pb_callback_t servers; - bool has_expiration_interval; - grpc_lb_v0_Duration expiration_interval; -} grpc_lb_v0_ServerList; - -typedef struct _grpc_lb_v0_LoadBalanceResponse { - bool has_initial_response; - grpc_lb_v0_InitialLoadBalanceResponse initial_response; - bool has_server_list; - grpc_lb_v0_ServerList server_list; -} grpc_lb_v0_LoadBalanceResponse; - -/* Default values for struct fields */ - -/* Initializer values for message structs */ -#define grpc_lb_v0_Duration_init_default {false, 0, false, 0} -#define grpc_lb_v0_LoadBalanceRequest_init_default {false, grpc_lb_v0_InitialLoadBalanceRequest_init_default, false, grpc_lb_v0_ClientStats_init_default} -#define grpc_lb_v0_InitialLoadBalanceRequest_init_default {false, ""} -#define grpc_lb_v0_ClientStats_init_default {false, 0, false, 0, false, 0} -#define grpc_lb_v0_LoadBalanceResponse_init_default {false, grpc_lb_v0_InitialLoadBalanceResponse_init_default, false, grpc_lb_v0_ServerList_init_default} -#define grpc_lb_v0_InitialLoadBalanceResponse_init_default {false, "", false, "", false, grpc_lb_v0_Duration_init_default} -#define grpc_lb_v0_ServerList_init_default {{{NULL}, NULL}, false, grpc_lb_v0_Duration_init_default} -#define grpc_lb_v0_Server_init_default {false, "", false, 0, false, {0, {0}}, false, 0} -#define grpc_lb_v0_Duration_init_zero {false, 0, false, 0} -#define grpc_lb_v0_LoadBalanceRequest_init_zero {false, grpc_lb_v0_InitialLoadBalanceRequest_init_zero, false, grpc_lb_v0_ClientStats_init_zero} -#define grpc_lb_v0_InitialLoadBalanceRequest_init_zero {false, ""} -#define grpc_lb_v0_ClientStats_init_zero {false, 0, false, 0, false, 0} -#define grpc_lb_v0_LoadBalanceResponse_init_zero {false, grpc_lb_v0_InitialLoadBalanceResponse_init_zero, false, grpc_lb_v0_ServerList_init_zero} -#define grpc_lb_v0_InitialLoadBalanceResponse_init_zero {false, "", false, "", false, grpc_lb_v0_Duration_init_zero} -#define grpc_lb_v0_ServerList_init_zero {{{NULL}, NULL}, false, grpc_lb_v0_Duration_init_zero} -#define grpc_lb_v0_Server_init_zero {false, "", false, 0, false, {0, {0}}, false, 0} - -/* Field tags (for use in manual encoding/decoding) */ -#define grpc_lb_v0_ClientStats_total_requests_tag 1 -#define grpc_lb_v0_ClientStats_client_rpc_errors_tag 2 -#define grpc_lb_v0_ClientStats_dropped_requests_tag 3 -#define grpc_lb_v0_Duration_seconds_tag 1 -#define grpc_lb_v0_Duration_nanos_tag 2 -#define grpc_lb_v0_InitialLoadBalanceRequest_name_tag 1 -#define grpc_lb_v0_Server_ip_address_tag 1 -#define grpc_lb_v0_Server_port_tag 2 -#define grpc_lb_v0_Server_load_balance_token_tag 3 -#define grpc_lb_v0_Server_drop_request_tag 4 -#define grpc_lb_v0_InitialLoadBalanceResponse_client_config_tag 1 -#define grpc_lb_v0_InitialLoadBalanceResponse_load_balancer_delegate_tag 2 -#define grpc_lb_v0_InitialLoadBalanceResponse_client_stats_report_interval_tag 3 -#define grpc_lb_v0_LoadBalanceRequest_initial_request_tag 1 -#define grpc_lb_v0_LoadBalanceRequest_client_stats_tag 2 -#define grpc_lb_v0_ServerList_servers_tag 1 -#define grpc_lb_v0_ServerList_expiration_interval_tag 3 -#define grpc_lb_v0_LoadBalanceResponse_initial_response_tag 1 -#define grpc_lb_v0_LoadBalanceResponse_server_list_tag 2 - -/* Struct field encoding specification for nanopb */ -extern const pb_field_t grpc_lb_v0_Duration_fields[3]; -extern const pb_field_t grpc_lb_v0_LoadBalanceRequest_fields[3]; -extern const pb_field_t grpc_lb_v0_InitialLoadBalanceRequest_fields[2]; -extern const pb_field_t grpc_lb_v0_ClientStats_fields[4]; -extern const pb_field_t grpc_lb_v0_LoadBalanceResponse_fields[3]; -extern const pb_field_t grpc_lb_v0_InitialLoadBalanceResponse_fields[4]; -extern const pb_field_t grpc_lb_v0_ServerList_fields[3]; -extern const pb_field_t grpc_lb_v0_Server_fields[5]; - -/* Maximum encoded size of messages (where known) */ -#define grpc_lb_v0_Duration_size 22 -#define grpc_lb_v0_LoadBalanceRequest_size 169 -#define grpc_lb_v0_InitialLoadBalanceRequest_size 131 -#define grpc_lb_v0_ClientStats_size 33 -#define grpc_lb_v0_LoadBalanceResponse_size (165 + grpc_lb_v0_ServerList_size) -#define grpc_lb_v0_InitialLoadBalanceResponse_size 156 -#define grpc_lb_v0_Server_size 127 - -/* Message IDs (where set with "msgid" option) */ -#ifdef PB_MSGID - -#define LOAD_BALANCER_MESSAGES \ - - -#endif - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif diff --git a/src/core/security/auth_filters.h b/src/core/security/auth_filters.h deleted file mode 100644 index 1154a1d914..0000000000 --- a/src/core/security/auth_filters.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * - * Copyright 2015-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_SECURITY_AUTH_FILTERS_H -#define GRPC_CORE_SECURITY_AUTH_FILTERS_H - -#include "src/core/channel/channel_stack.h" - -extern const grpc_channel_filter grpc_client_auth_filter; -extern const grpc_channel_filter grpc_server_auth_filter; - -#endif /* GRPC_CORE_SECURITY_AUTH_FILTERS_H */ diff --git a/src/core/security/b64.c b/src/core/security/b64.c deleted file mode 100644 index c40b528e2f..0000000000 --- a/src/core/security/b64.c +++ /dev/null @@ -1,233 +0,0 @@ -/* - * - * Copyright 2015-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/security/b64.h" - -#include -#include - -#include -#include -#include - -/* --- Constants. --- */ - -static const int8_t base64_bytes[] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 0x3E, -1, -1, -1, 0x3F, - 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, -1, -1, - -1, 0x7F, -1, -1, -1, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, - 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, - 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, -1, -1, -1, -1, -1, - -1, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, - 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, - 0x31, 0x32, 0x33, -1, -1, -1, -1, -1}; - -static const char base64_url_unsafe_chars[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -static const char base64_url_safe_chars[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; - -#define GRPC_BASE64_PAD_CHAR '=' -#define GRPC_BASE64_PAD_BYTE 0x7F -#define GRPC_BASE64_MULTILINE_LINE_LEN 76 -#define GRPC_BASE64_MULTILINE_NUM_BLOCKS (GRPC_BASE64_MULTILINE_LINE_LEN / 4) - -/* --- base64 functions. --- */ - -char *grpc_base64_encode(const void *vdata, size_t data_size, int url_safe, - int multiline) { - const unsigned char *data = vdata; - const char *base64_chars = - url_safe ? base64_url_safe_chars : base64_url_unsafe_chars; - size_t result_projected_size = - 4 * ((data_size + 3) / 3) + - 2 * (multiline ? (data_size / (3 * GRPC_BASE64_MULTILINE_NUM_BLOCKS)) - : 0) + - 1; - char *result = gpr_malloc(result_projected_size); - char *current = result; - size_t num_blocks = 0; - size_t i = 0; - - /* Encode each block. */ - while (data_size >= 3) { - *current++ = base64_chars[(data[i] >> 2) & 0x3F]; - *current++ = - base64_chars[((data[i] & 0x03) << 4) | ((data[i + 1] >> 4) & 0x0F)]; - *current++ = - base64_chars[((data[i + 1] & 0x0F) << 2) | ((data[i + 2] >> 6) & 0x03)]; - *current++ = base64_chars[data[i + 2] & 0x3F]; - - data_size -= 3; - i += 3; - if (multiline && (++num_blocks == GRPC_BASE64_MULTILINE_NUM_BLOCKS)) { - *current++ = '\r'; - *current++ = '\n'; - num_blocks = 0; - } - } - - /* Take care of the tail. */ - if (data_size == 2) { - *current++ = base64_chars[(data[i] >> 2) & 0x3F]; - *current++ = - base64_chars[((data[i] & 0x03) << 4) | ((data[i + 1] >> 4) & 0x0F)]; - *current++ = base64_chars[(data[i + 1] & 0x0F) << 2]; - *current++ = GRPC_BASE64_PAD_CHAR; - } else if (data_size == 1) { - *current++ = base64_chars[(data[i] >> 2) & 0x3F]; - *current++ = base64_chars[(data[i] & 0x03) << 4]; - *current++ = GRPC_BASE64_PAD_CHAR; - *current++ = GRPC_BASE64_PAD_CHAR; - } - - GPR_ASSERT(current >= result); - GPR_ASSERT((uintptr_t)(current - result) < result_projected_size); - result[current - result] = '\0'; - return result; -} - -gpr_slice grpc_base64_decode(const char *b64, int url_safe) { - return grpc_base64_decode_with_len(b64, strlen(b64), url_safe); -} - -static void decode_one_char(const unsigned char *codes, unsigned char *result, - size_t *result_offset) { - uint32_t packed = ((uint32_t)codes[0] << 2) | ((uint32_t)codes[1] >> 4); - result[(*result_offset)++] = (unsigned char)packed; -} - -static void decode_two_chars(const unsigned char *codes, unsigned char *result, - size_t *result_offset) { - uint32_t packed = ((uint32_t)codes[0] << 10) | ((uint32_t)codes[1] << 4) | - ((uint32_t)codes[2] >> 2); - result[(*result_offset)++] = (unsigned char)(packed >> 8); - result[(*result_offset)++] = (unsigned char)(packed); -} - -static int decode_group(const unsigned char *codes, size_t num_codes, - unsigned char *result, size_t *result_offset) { - GPR_ASSERT(num_codes <= 4); - - /* Short end groups that may not have padding. */ - if (num_codes == 1) { - gpr_log(GPR_ERROR, "Invalid group. Must be at least 2 bytes."); - return 0; - } - if (num_codes == 2) { - decode_one_char(codes, result, result_offset); - return 1; - } - if (num_codes == 3) { - decode_two_chars(codes, result, result_offset); - return 1; - } - - /* Regular 4 byte groups with padding or not. */ - GPR_ASSERT(num_codes == 4); - if (codes[0] == GRPC_BASE64_PAD_BYTE || codes[1] == GRPC_BASE64_PAD_BYTE) { - gpr_log(GPR_ERROR, "Invalid padding detected."); - return 0; - } - if (codes[2] == GRPC_BASE64_PAD_BYTE) { - if (codes[3] == GRPC_BASE64_PAD_BYTE) { - decode_one_char(codes, result, result_offset); - } else { - gpr_log(GPR_ERROR, "Invalid padding detected."); - return 0; - } - } else if (codes[3] == GRPC_BASE64_PAD_BYTE) { - decode_two_chars(codes, result, result_offset); - } else { - /* No padding. */ - uint32_t packed = ((uint32_t)codes[0] << 18) | ((uint32_t)codes[1] << 12) | - ((uint32_t)codes[2] << 6) | codes[3]; - result[(*result_offset)++] = (unsigned char)(packed >> 16); - result[(*result_offset)++] = (unsigned char)(packed >> 8); - result[(*result_offset)++] = (unsigned char)(packed); - } - return 1; -} - -gpr_slice grpc_base64_decode_with_len(const char *b64, size_t b64_len, - int url_safe) { - gpr_slice result = gpr_slice_malloc(b64_len); - unsigned char *current = GPR_SLICE_START_PTR(result); - size_t result_size = 0; - unsigned char codes[4]; - size_t num_codes = 0; - - while (b64_len--) { - unsigned char c = (unsigned char)(*b64++); - signed char code; - if (c >= GPR_ARRAY_SIZE(base64_bytes)) continue; - if (url_safe) { - if (c == '+' || c == '/') { - gpr_log(GPR_ERROR, "Invalid character for url safe base64 %c", c); - goto fail; - } - if (c == '-') { - c = '+'; - } else if (c == '_') { - c = '/'; - } - } - code = base64_bytes[c]; - if (code == -1) { - if (c != '\r' && c != '\n') { - gpr_log(GPR_ERROR, "Invalid character %c", c); - goto fail; - } - } else { - codes[num_codes++] = (unsigned char)code; - if (num_codes == 4) { - if (!decode_group(codes, num_codes, current, &result_size)) goto fail; - num_codes = 0; - } - } - } - - if (num_codes != 0 && - !decode_group(codes, num_codes, current, &result_size)) { - goto fail; - } - GPR_SLICE_SET_LENGTH(result, result_size); - return result; - -fail: - gpr_slice_unref(result); - return gpr_empty_slice(); -} diff --git a/src/core/security/b64.h b/src/core/security/b64.h deleted file mode 100644 index d18f69563d..0000000000 --- a/src/core/security/b64.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * - * Copyright 2015-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_SECURITY_B64_H -#define GRPC_CORE_SECURITY_B64_H - -#include - -/* Encodes data using base64. It is the caller's responsability to free - the returned char * using gpr_free. Returns NULL on NULL input. */ -char *grpc_base64_encode(const void *data, size_t data_size, int url_safe, - int multiline); - -/* Decodes data according to the base64 specification. Returns an empty - slice in case of failure. */ -gpr_slice grpc_base64_decode(const char *b64, int url_safe); - -/* Same as above except that the length is provided by the caller. */ -gpr_slice grpc_base64_decode_with_len(const char *b64, size_t b64_len, - int url_safe); - -#endif /* GRPC_CORE_SECURITY_B64_H */ diff --git a/src/core/security/client_auth_filter.c b/src/core/security/client_auth_filter.c deleted file mode 100644 index e2c23ef98d..0000000000 --- a/src/core/security/client_auth_filter.c +++ /dev/null @@ -1,336 +0,0 @@ -/* - * - * Copyright 2015-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/security/auth_filters.h" - -#include - -#include -#include -#include - -#include "src/core/channel/channel_stack.h" -#include "src/core/security/credentials.h" -#include "src/core/security/security_connector.h" -#include "src/core/security/security_context.h" -#include "src/core/support/string.h" -#include "src/core/surface/call.h" -#include "src/core/transport/static_metadata.h" - -#define MAX_CREDENTIALS_METADATA_COUNT 4 - -/* We can have a per-call credentials. */ -typedef struct { - grpc_call_credentials *creds; - grpc_mdstr *host; - grpc_mdstr *method; - /* pollset bound to this call; if we need to make external - network requests, they should be done under this pollset - so that work can progress when this call wants work to - progress */ - grpc_pollset *pollset; - grpc_transport_stream_op op; - uint8_t security_context_set; - grpc_linked_mdelem md_links[MAX_CREDENTIALS_METADATA_COUNT]; - grpc_auth_metadata_context auth_md_context; -} call_data; - -/* We can have a per-channel credentials. */ -typedef struct { - grpc_channel_security_connector *security_connector; - grpc_auth_context *auth_context; -} channel_data; - -static void reset_auth_metadata_context( - grpc_auth_metadata_context *auth_md_context) { - if (auth_md_context->service_url != NULL) { - gpr_free((char *)auth_md_context->service_url); - auth_md_context->service_url = NULL; - } - if (auth_md_context->method_name != NULL) { - gpr_free((char *)auth_md_context->method_name); - auth_md_context->method_name = NULL; - } - GRPC_AUTH_CONTEXT_UNREF( - (grpc_auth_context *)auth_md_context->channel_auth_context, - "grpc_auth_metadata_context"); - auth_md_context->channel_auth_context = NULL; -} - -static void bubble_up_error(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_status_code status, const char *error_msg) { - call_data *calld = elem->call_data; - gpr_log(GPR_ERROR, "Client side authentication failure: %s", error_msg); - grpc_transport_stream_op_add_cancellation(&calld->op, status); - grpc_call_next_op(exec_ctx, elem, &calld->op); -} - -static void on_credentials_metadata(grpc_exec_ctx *exec_ctx, void *user_data, - grpc_credentials_md *md_elems, - size_t num_md, - grpc_credentials_status status) { - grpc_call_element *elem = (grpc_call_element *)user_data; - call_data *calld = elem->call_data; - grpc_transport_stream_op *op = &calld->op; - grpc_metadata_batch *mdb; - size_t i; - reset_auth_metadata_context(&calld->auth_md_context); - if (status != GRPC_CREDENTIALS_OK) { - bubble_up_error(exec_ctx, elem, GRPC_STATUS_UNAUTHENTICATED, - "Credentials failed to get metadata."); - return; - } - GPR_ASSERT(num_md <= MAX_CREDENTIALS_METADATA_COUNT); - GPR_ASSERT(op->send_initial_metadata != NULL); - mdb = op->send_initial_metadata; - for (i = 0; i < num_md; i++) { - grpc_metadata_batch_add_tail( - mdb, &calld->md_links[i], - grpc_mdelem_from_slices(gpr_slice_ref(md_elems[i].key), - gpr_slice_ref(md_elems[i].value))); - } - grpc_call_next_op(exec_ctx, elem, op); -} - -void build_auth_metadata_context(grpc_security_connector *sc, - grpc_auth_context *auth_context, - call_data *calld) { - char *service = gpr_strdup(grpc_mdstr_as_c_string(calld->method)); - char *last_slash = strrchr(service, '/'); - char *method_name = NULL; - char *service_url = NULL; - reset_auth_metadata_context(&calld->auth_md_context); - if (last_slash == NULL) { - gpr_log(GPR_ERROR, "No '/' found in fully qualified method name"); - service[0] = '\0'; - } else if (last_slash == service) { - /* No service part in fully qualified method name: will just be "/". */ - service[1] = '\0'; - } else { - *last_slash = '\0'; - method_name = gpr_strdup(last_slash + 1); - } - if (method_name == NULL) method_name = gpr_strdup(""); - gpr_asprintf(&service_url, "%s://%s%s", - sc->url_scheme == NULL ? "" : sc->url_scheme, - grpc_mdstr_as_c_string(calld->host), service); - calld->auth_md_context.service_url = service_url; - calld->auth_md_context.method_name = method_name; - calld->auth_md_context.channel_auth_context = - GRPC_AUTH_CONTEXT_REF(auth_context, "grpc_auth_metadata_context"); - gpr_free(service); -} - -static void send_security_metadata(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_transport_stream_op *op) { - call_data *calld = elem->call_data; - channel_data *chand = elem->channel_data; - grpc_client_security_context *ctx = - (grpc_client_security_context *)op->context[GRPC_CONTEXT_SECURITY].value; - grpc_call_credentials *channel_call_creds = - chand->security_connector->request_metadata_creds; - int call_creds_has_md = (ctx != NULL) && (ctx->creds != NULL); - - if (channel_call_creds == NULL && !call_creds_has_md) { - /* Skip sending metadata altogether. */ - grpc_call_next_op(exec_ctx, elem, op); - return; - } - - if (channel_call_creds != NULL && call_creds_has_md) { - calld->creds = grpc_composite_call_credentials_create(channel_call_creds, - ctx->creds, NULL); - if (calld->creds == NULL) { - bubble_up_error(exec_ctx, elem, GRPC_STATUS_INVALID_ARGUMENT, - "Incompatible credentials set on channel and call."); - return; - } - } else { - calld->creds = grpc_call_credentials_ref( - call_creds_has_md ? ctx->creds : channel_call_creds); - } - - build_auth_metadata_context(&chand->security_connector->base, - chand->auth_context, calld); - calld->op = *op; /* Copy op (originates from the caller's stack). */ - GPR_ASSERT(calld->pollset); - grpc_call_credentials_get_request_metadata( - exec_ctx, calld->creds, calld->pollset, calld->auth_md_context, - on_credentials_metadata, elem); -} - -static void on_host_checked(grpc_exec_ctx *exec_ctx, void *user_data, - grpc_security_status status) { - grpc_call_element *elem = (grpc_call_element *)user_data; - call_data *calld = elem->call_data; - - if (status == GRPC_SECURITY_OK) { - send_security_metadata(exec_ctx, elem, &calld->op); - } else { - char *error_msg; - gpr_asprintf(&error_msg, "Invalid host %s set in :authority metadata.", - grpc_mdstr_as_c_string(calld->host)); - bubble_up_error(exec_ctx, elem, GRPC_STATUS_INVALID_ARGUMENT, error_msg); - gpr_free(error_msg); - } -} - -/* Called either: - - in response to an API call (or similar) from above, to send something - - a network event (or similar) from below, to receive something - op contains type and call direction information, in addition to the data - that is being sent or received. */ -static void auth_start_transport_op(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_transport_stream_op *op) { - /* grab pointers to our data from the call element */ - call_data *calld = elem->call_data; - channel_data *chand = elem->channel_data; - grpc_linked_mdelem *l; - grpc_client_security_context *sec_ctx = NULL; - - if (calld->security_context_set == 0 && - op->cancel_with_status == GRPC_STATUS_OK) { - calld->security_context_set = 1; - GPR_ASSERT(op->context); - if (op->context[GRPC_CONTEXT_SECURITY].value == NULL) { - op->context[GRPC_CONTEXT_SECURITY].value = - grpc_client_security_context_create(); - op->context[GRPC_CONTEXT_SECURITY].destroy = - grpc_client_security_context_destroy; - } - sec_ctx = op->context[GRPC_CONTEXT_SECURITY].value; - GRPC_AUTH_CONTEXT_UNREF(sec_ctx->auth_context, "client auth filter"); - sec_ctx->auth_context = - GRPC_AUTH_CONTEXT_REF(chand->auth_context, "client_auth_filter"); - } - - if (op->send_initial_metadata != NULL) { - for (l = op->send_initial_metadata->list.head; l != NULL; l = l->next) { - grpc_mdelem *md = l->md; - /* Pointer comparison is OK for md_elems created from the same context. - */ - if (md->key == GRPC_MDSTR_AUTHORITY) { - if (calld->host != NULL) GRPC_MDSTR_UNREF(calld->host); - calld->host = GRPC_MDSTR_REF(md->value); - } else if (md->key == GRPC_MDSTR_PATH) { - if (calld->method != NULL) GRPC_MDSTR_UNREF(calld->method); - calld->method = GRPC_MDSTR_REF(md->value); - } - } - if (calld->host != NULL) { - const char *call_host = grpc_mdstr_as_c_string(calld->host); - calld->op = *op; /* Copy op (originates from the caller's stack). */ - grpc_channel_security_connector_check_call_host( - exec_ctx, chand->security_connector, call_host, chand->auth_context, - on_host_checked, elem); - return; /* early exit */ - } - } - - /* pass control down the stack */ - grpc_call_next_op(exec_ctx, elem, op); -} - -/* Constructor for call_data */ -static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_call_element_args *args) { - call_data *calld = elem->call_data; - memset(calld, 0, sizeof(*calld)); -} - -static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_pollset *pollset) { - call_data *calld = elem->call_data; - calld->pollset = pollset; -} - -/* Destructor for call_data */ -static void destroy_call_elem(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem) { - call_data *calld = elem->call_data; - grpc_call_credentials_unref(calld->creds); - if (calld->host != NULL) { - GRPC_MDSTR_UNREF(calld->host); - } - if (calld->method != NULL) { - GRPC_MDSTR_UNREF(calld->method); - } - reset_auth_metadata_context(&calld->auth_md_context); -} - -/* Constructor for channel_data */ -static void init_channel_elem(grpc_exec_ctx *exec_ctx, - grpc_channel_element *elem, - grpc_channel_element_args *args) { - grpc_security_connector *sc = - grpc_find_security_connector_in_args(args->channel_args); - grpc_auth_context *auth_context = - grpc_find_auth_context_in_args(args->channel_args); - - /* grab pointers to our data from the channel element */ - channel_data *chand = elem->channel_data; - - /* The first and the last filters tend to be implemented differently to - handle the case that there's no 'next' filter to call on the up or down - path */ - GPR_ASSERT(!args->is_last); - GPR_ASSERT(sc != NULL); - GPR_ASSERT(auth_context != NULL); - - /* initialize members */ - chand->security_connector = - (grpc_channel_security_connector *)GRPC_SECURITY_CONNECTOR_REF( - sc, "client_auth_filter"); - chand->auth_context = - GRPC_AUTH_CONTEXT_REF(auth_context, "client_auth_filter"); -} - -/* Destructor for channel data */ -static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, - grpc_channel_element *elem) { - /* grab pointers to our data from the channel element */ - channel_data *chand = elem->channel_data; - grpc_channel_security_connector *sc = chand->security_connector; - if (sc != NULL) { - GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "client_auth_filter"); - } - GRPC_AUTH_CONTEXT_UNREF(chand->auth_context, "client_auth_filter"); -} - -const grpc_channel_filter grpc_client_auth_filter = { - auth_start_transport_op, grpc_channel_next_op, sizeof(call_data), - init_call_elem, set_pollset, destroy_call_elem, - sizeof(channel_data), init_channel_elem, destroy_channel_elem, - grpc_call_next_get_peer, "client-auth"}; diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c deleted file mode 100644 index c8348bc12c..0000000000 --- a/src/core/security/credentials.c +++ /dev/null @@ -1,1281 +0,0 @@ -/* - * - * Copyright 2015-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/security/credentials.h" - -#include -#include - -#include "src/core/channel/channel_args.h" -#include "src/core/channel/http_client_filter.h" -#include "src/core/http/httpcli.h" -#include "src/core/http/parser.h" -#include "src/core/iomgr/executor.h" -#include "src/core/json/json.h" -#include "src/core/support/string.h" -#include "src/core/surface/api_trace.h" - -#include -#include -#include -#include -#include - -/* -- Common. -- */ - -struct grpc_credentials_metadata_request { - grpc_call_credentials *creds; - grpc_credentials_metadata_cb cb; - void *user_data; -}; - -static grpc_credentials_metadata_request * -grpc_credentials_metadata_request_create(grpc_call_credentials *creds, - grpc_credentials_metadata_cb cb, - void *user_data) { - grpc_credentials_metadata_request *r = - gpr_malloc(sizeof(grpc_credentials_metadata_request)); - r->creds = grpc_call_credentials_ref(creds); - r->cb = cb; - r->user_data = user_data; - return r; -} - -static void grpc_credentials_metadata_request_destroy( - grpc_credentials_metadata_request *r) { - grpc_call_credentials_unref(r->creds); - gpr_free(r); -} - -grpc_channel_credentials *grpc_channel_credentials_ref( - grpc_channel_credentials *creds) { - if (creds == NULL) return NULL; - gpr_ref(&creds->refcount); - return creds; -} - -void grpc_channel_credentials_unref(grpc_channel_credentials *creds) { - if (creds == NULL) return; - if (gpr_unref(&creds->refcount)) { - if (creds->vtable->destruct != NULL) creds->vtable->destruct(creds); - gpr_free(creds); - } -} - -void grpc_channel_credentials_release(grpc_channel_credentials *creds) { - GRPC_API_TRACE("grpc_channel_credentials_release(creds=%p)", 1, (creds)); - grpc_channel_credentials_unref(creds); -} - -grpc_call_credentials *grpc_call_credentials_ref(grpc_call_credentials *creds) { - if (creds == NULL) return NULL; - gpr_ref(&creds->refcount); - return creds; -} - -void grpc_call_credentials_unref(grpc_call_credentials *creds) { - if (creds == NULL) return; - if (gpr_unref(&creds->refcount)) { - if (creds->vtable->destruct != NULL) creds->vtable->destruct(creds); - gpr_free(creds); - } -} - -void grpc_call_credentials_release(grpc_call_credentials *creds) { - GRPC_API_TRACE("grpc_call_credentials_release(creds=%p)", 1, (creds)); - grpc_call_credentials_unref(creds); -} - -void grpc_call_credentials_get_request_metadata( - grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, - grpc_pollset *pollset, grpc_auth_metadata_context context, - grpc_credentials_metadata_cb cb, void *user_data) { - if (creds == NULL || creds->vtable->get_request_metadata == NULL) { - if (cb != NULL) { - cb(exec_ctx, user_data, NULL, 0, GRPC_CREDENTIALS_OK); - } - return; - } - creds->vtable->get_request_metadata(exec_ctx, creds, pollset, context, cb, - user_data); -} - -grpc_security_status grpc_channel_credentials_create_security_connector( - grpc_channel_credentials *channel_creds, const char *target, - const grpc_channel_args *args, grpc_channel_security_connector **sc, - grpc_channel_args **new_args) { - *new_args = NULL; - if (channel_creds == NULL) { - return GRPC_SECURITY_ERROR; - } - GPR_ASSERT(channel_creds->vtable->create_security_connector != NULL); - return channel_creds->vtable->create_security_connector( - channel_creds, NULL, target, args, sc, new_args); -} - -grpc_server_credentials *grpc_server_credentials_ref( - grpc_server_credentials *creds) { - if (creds == NULL) return NULL; - gpr_ref(&creds->refcount); - return creds; -} - -void grpc_server_credentials_unref(grpc_server_credentials *creds) { - if (creds == NULL) return; - if (gpr_unref(&creds->refcount)) { - if (creds->vtable->destruct != NULL) creds->vtable->destruct(creds); - if (creds->processor.destroy != NULL && creds->processor.state != NULL) { - creds->processor.destroy(creds->processor.state); - } - gpr_free(creds); - } -} - -void grpc_server_credentials_release(grpc_server_credentials *creds) { - GRPC_API_TRACE("grpc_server_credentials_release(creds=%p)", 1, (creds)); - grpc_server_credentials_unref(creds); -} - -grpc_security_status grpc_server_credentials_create_security_connector( - grpc_server_credentials *creds, grpc_server_security_connector **sc) { - if (creds == NULL || creds->vtable->create_security_connector == NULL) { - gpr_log(GPR_ERROR, "Server credentials cannot create security context."); - return GRPC_SECURITY_ERROR; - } - return creds->vtable->create_security_connector(creds, sc); -} - -void grpc_server_credentials_set_auth_metadata_processor( - grpc_server_credentials *creds, grpc_auth_metadata_processor processor) { - GRPC_API_TRACE( - "grpc_server_credentials_set_auth_metadata_processor(" - "creds=%p, " - "processor=grpc_auth_metadata_processor { process: %p, state: %p })", - 3, (creds, (void *)(intptr_t)processor.process, processor.state)); - if (creds == NULL) return; - if (creds->processor.destroy != NULL && creds->processor.state != NULL) { - creds->processor.destroy(creds->processor.state); - } - creds->processor = processor; -} - -static void server_credentials_pointer_arg_destroy(void *p) { - grpc_server_credentials_unref(p); -} - -static void *server_credentials_pointer_arg_copy(void *p) { - return grpc_server_credentials_ref(p); -} - -static int server_credentials_pointer_cmp(void *a, void *b) { - return GPR_ICMP(a, b); -} - -static const grpc_arg_pointer_vtable cred_ptr_vtable = { - server_credentials_pointer_arg_copy, server_credentials_pointer_arg_destroy, - server_credentials_pointer_cmp}; - -grpc_arg grpc_server_credentials_to_arg(grpc_server_credentials *p) { - grpc_arg arg; - memset(&arg, 0, sizeof(grpc_arg)); - arg.type = GRPC_ARG_POINTER; - arg.key = GRPC_SERVER_CREDENTIALS_ARG; - arg.value.pointer.p = p; - arg.value.pointer.vtable = &cred_ptr_vtable; - return arg; -} - -grpc_server_credentials *grpc_server_credentials_from_arg(const grpc_arg *arg) { - if (strcmp(arg->key, GRPC_SERVER_CREDENTIALS_ARG) != 0) return NULL; - if (arg->type != GRPC_ARG_POINTER) { - gpr_log(GPR_ERROR, "Invalid type %d for arg %s", arg->type, - GRPC_SERVER_CREDENTIALS_ARG); - return NULL; - } - return arg->value.pointer.p; -} - -grpc_server_credentials *grpc_find_server_credentials_in_args( - const grpc_channel_args *args) { - size_t i; - if (args == NULL) return NULL; - for (i = 0; i < args->num_args; i++) { - grpc_server_credentials *p = - grpc_server_credentials_from_arg(&args->args[i]); - if (p != NULL) return p; - } - return NULL; -} - -/* -- Ssl credentials. -- */ - -static void ssl_destruct(grpc_channel_credentials *creds) { - grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds; - if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs); - if (c->config.pem_private_key != NULL) gpr_free(c->config.pem_private_key); - if (c->config.pem_cert_chain != NULL) gpr_free(c->config.pem_cert_chain); -} - -static void ssl_server_destruct(grpc_server_credentials *creds) { - grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds; - size_t i; - for (i = 0; i < c->config.num_key_cert_pairs; i++) { - if (c->config.pem_private_keys[i] != NULL) { - gpr_free(c->config.pem_private_keys[i]); - } - if (c->config.pem_cert_chains[i] != NULL) { - gpr_free(c->config.pem_cert_chains[i]); - } - } - if (c->config.pem_private_keys != NULL) gpr_free(c->config.pem_private_keys); - if (c->config.pem_private_keys_sizes != NULL) { - gpr_free(c->config.pem_private_keys_sizes); - } - if (c->config.pem_cert_chains != NULL) gpr_free(c->config.pem_cert_chains); - if (c->config.pem_cert_chains_sizes != NULL) { - gpr_free(c->config.pem_cert_chains_sizes); - } - if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs); -} - -static grpc_security_status ssl_create_security_connector( - grpc_channel_credentials *creds, grpc_call_credentials *call_creds, - const char *target, const grpc_channel_args *args, - grpc_channel_security_connector **sc, grpc_channel_args **new_args) { - grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds; - grpc_security_status status = GRPC_SECURITY_OK; - size_t i = 0; - const char *overridden_target_name = NULL; - grpc_arg new_arg; - - for (i = 0; args && i < args->num_args; i++) { - grpc_arg *arg = &args->args[i]; - if (strcmp(arg->key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG) == 0 && - arg->type == GRPC_ARG_STRING) { - overridden_target_name = arg->value.string; - break; - } - } - status = grpc_ssl_channel_security_connector_create( - call_creds, &c->config, target, overridden_target_name, sc); - if (status != GRPC_SECURITY_OK) { - return status; - } - new_arg.type = GRPC_ARG_STRING; - new_arg.key = GRPC_ARG_HTTP2_SCHEME; - new_arg.value.string = "https"; - *new_args = grpc_channel_args_copy_and_add(args, &new_arg, 1); - return status; -} - -static grpc_security_status ssl_server_create_security_connector( - grpc_server_credentials *creds, grpc_server_security_connector **sc) { - grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds; - return grpc_ssl_server_security_connector_create(&c->config, sc); -} - -static grpc_channel_credentials_vtable ssl_vtable = { - ssl_destruct, ssl_create_security_connector}; - -static grpc_server_credentials_vtable ssl_server_vtable = { - ssl_server_destruct, ssl_server_create_security_connector}; - -static void ssl_copy_key_material(const char *input, unsigned char **output, - size_t *output_size) { - *output_size = strlen(input); - *output = gpr_malloc(*output_size); - memcpy(*output, input, *output_size); -} - -static void ssl_build_config(const char *pem_root_certs, - grpc_ssl_pem_key_cert_pair *pem_key_cert_pair, - grpc_ssl_config *config) { - if (pem_root_certs != NULL) { - ssl_copy_key_material(pem_root_certs, &config->pem_root_certs, - &config->pem_root_certs_size); - } - if (pem_key_cert_pair != NULL) { - GPR_ASSERT(pem_key_cert_pair->private_key != NULL); - GPR_ASSERT(pem_key_cert_pair->cert_chain != NULL); - ssl_copy_key_material(pem_key_cert_pair->private_key, - &config->pem_private_key, - &config->pem_private_key_size); - ssl_copy_key_material(pem_key_cert_pair->cert_chain, - &config->pem_cert_chain, - &config->pem_cert_chain_size); - } -} - -static void ssl_build_server_config( - const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs, - size_t num_key_cert_pairs, int force_client_auth, - grpc_ssl_server_config *config) { - size_t i; - config->force_client_auth = force_client_auth; - if (pem_root_certs != NULL) { - ssl_copy_key_material(pem_root_certs, &config->pem_root_certs, - &config->pem_root_certs_size); - } - if (num_key_cert_pairs > 0) { - GPR_ASSERT(pem_key_cert_pairs != NULL); - config->pem_private_keys = - gpr_malloc(num_key_cert_pairs * sizeof(unsigned char *)); - config->pem_cert_chains = - gpr_malloc(num_key_cert_pairs * sizeof(unsigned char *)); - config->pem_private_keys_sizes = - gpr_malloc(num_key_cert_pairs * sizeof(size_t)); - config->pem_cert_chains_sizes = - gpr_malloc(num_key_cert_pairs * sizeof(size_t)); - } - config->num_key_cert_pairs = num_key_cert_pairs; - for (i = 0; i < num_key_cert_pairs; i++) { - GPR_ASSERT(pem_key_cert_pairs[i].private_key != NULL); - GPR_ASSERT(pem_key_cert_pairs[i].cert_chain != NULL); - ssl_copy_key_material(pem_key_cert_pairs[i].private_key, - &config->pem_private_keys[i], - &config->pem_private_keys_sizes[i]); - ssl_copy_key_material(pem_key_cert_pairs[i].cert_chain, - &config->pem_cert_chains[i], - &config->pem_cert_chains_sizes[i]); - } -} - -grpc_channel_credentials *grpc_ssl_credentials_create( - const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair, - void *reserved) { - grpc_ssl_credentials *c = gpr_malloc(sizeof(grpc_ssl_credentials)); - GRPC_API_TRACE( - "grpc_ssl_credentials_create(pem_root_certs=%s, " - "pem_key_cert_pair=%p, " - "reserved=%p)", - 3, (pem_root_certs, pem_key_cert_pair, reserved)); - GPR_ASSERT(reserved == NULL); - memset(c, 0, sizeof(grpc_ssl_credentials)); - c->base.type = GRPC_CHANNEL_CREDENTIALS_TYPE_SSL; - c->base.vtable = &ssl_vtable; - gpr_ref_init(&c->base.refcount, 1); - ssl_build_config(pem_root_certs, pem_key_cert_pair, &c->config); - return &c->base; -} - -grpc_server_credentials *grpc_ssl_server_credentials_create( - const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs, - size_t num_key_cert_pairs, int force_client_auth, void *reserved) { - grpc_ssl_server_credentials *c = - gpr_malloc(sizeof(grpc_ssl_server_credentials)); - GRPC_API_TRACE( - "grpc_ssl_server_credentials_create(" - "pem_root_certs=%s, pem_key_cert_pairs=%p, num_key_cert_pairs=%lu, " - "force_client_auth=%d, reserved=%p)", - 5, (pem_root_certs, pem_key_cert_pairs, (unsigned long)num_key_cert_pairs, - force_client_auth, reserved)); - GPR_ASSERT(reserved == NULL); - memset(c, 0, sizeof(grpc_ssl_server_credentials)); - c->base.type = GRPC_CHANNEL_CREDENTIALS_TYPE_SSL; - gpr_ref_init(&c->base.refcount, 1); - c->base.vtable = &ssl_server_vtable; - ssl_build_server_config(pem_root_certs, pem_key_cert_pairs, - num_key_cert_pairs, force_client_auth, &c->config); - return &c->base; -} - -/* -- Jwt credentials -- */ - -static void jwt_reset_cache(grpc_service_account_jwt_access_credentials *c) { - if (c->cached.jwt_md != NULL) { - grpc_credentials_md_store_unref(c->cached.jwt_md); - c->cached.jwt_md = NULL; - } - if (c->cached.service_url != NULL) { - gpr_free(c->cached.service_url); - c->cached.service_url = NULL; - } - c->cached.jwt_expiration = gpr_inf_past(GPR_CLOCK_REALTIME); -} - -static void jwt_destruct(grpc_call_credentials *creds) { - grpc_service_account_jwt_access_credentials *c = - (grpc_service_account_jwt_access_credentials *)creds; - grpc_auth_json_key_destruct(&c->key); - jwt_reset_cache(c); - gpr_mu_destroy(&c->cache_mu); -} - -static void jwt_get_request_metadata(grpc_exec_ctx *exec_ctx, - grpc_call_credentials *creds, - grpc_pollset *pollset, - grpc_auth_metadata_context context, - grpc_credentials_metadata_cb cb, - void *user_data) { - grpc_service_account_jwt_access_credentials *c = - (grpc_service_account_jwt_access_credentials *)creds; - gpr_timespec refresh_threshold = gpr_time_from_seconds( - GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS, GPR_TIMESPAN); - - /* See if we can return a cached jwt. */ - grpc_credentials_md_store *jwt_md = NULL; - { - gpr_mu_lock(&c->cache_mu); - if (c->cached.service_url != NULL && - strcmp(c->cached.service_url, context.service_url) == 0 && - c->cached.jwt_md != NULL && - (gpr_time_cmp(gpr_time_sub(c->cached.jwt_expiration, - gpr_now(GPR_CLOCK_REALTIME)), - refresh_threshold) > 0)) { - jwt_md = grpc_credentials_md_store_ref(c->cached.jwt_md); - } - gpr_mu_unlock(&c->cache_mu); - } - - if (jwt_md == NULL) { - char *jwt = NULL; - /* Generate a new jwt. */ - gpr_mu_lock(&c->cache_mu); - jwt_reset_cache(c); - jwt = grpc_jwt_encode_and_sign(&c->key, context.service_url, - c->jwt_lifetime, NULL); - if (jwt != NULL) { - char *md_value; - gpr_asprintf(&md_value, "Bearer %s", jwt); - gpr_free(jwt); - c->cached.jwt_expiration = - gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), c->jwt_lifetime); - c->cached.service_url = gpr_strdup(context.service_url); - c->cached.jwt_md = grpc_credentials_md_store_create(1); - grpc_credentials_md_store_add_cstrings( - c->cached.jwt_md, GRPC_AUTHORIZATION_METADATA_KEY, md_value); - gpr_free(md_value); - jwt_md = grpc_credentials_md_store_ref(c->cached.jwt_md); - } - gpr_mu_unlock(&c->cache_mu); - } - - if (jwt_md != NULL) { - cb(exec_ctx, user_data, jwt_md->entries, jwt_md->num_entries, - GRPC_CREDENTIALS_OK); - grpc_credentials_md_store_unref(jwt_md); - } else { - cb(exec_ctx, user_data, NULL, 0, GRPC_CREDENTIALS_ERROR); - } -} - -static grpc_call_credentials_vtable jwt_vtable = {jwt_destruct, - jwt_get_request_metadata}; - -grpc_call_credentials * -grpc_service_account_jwt_access_credentials_create_from_auth_json_key( - grpc_auth_json_key key, gpr_timespec token_lifetime) { - grpc_service_account_jwt_access_credentials *c; - if (!grpc_auth_json_key_is_valid(&key)) { - gpr_log(GPR_ERROR, "Invalid input for jwt credentials creation"); - return NULL; - } - c = gpr_malloc(sizeof(grpc_service_account_jwt_access_credentials)); - memset(c, 0, sizeof(grpc_service_account_jwt_access_credentials)); - c->base.type = GRPC_CALL_CREDENTIALS_TYPE_JWT; - gpr_ref_init(&c->base.refcount, 1); - c->base.vtable = &jwt_vtable; - c->key = key; - c->jwt_lifetime = token_lifetime; - gpr_mu_init(&c->cache_mu); - jwt_reset_cache(c); - return &c->base; -} - -grpc_call_credentials *grpc_service_account_jwt_access_credentials_create( - const char *json_key, gpr_timespec token_lifetime, void *reserved) { - GRPC_API_TRACE( - "grpc_service_account_jwt_access_credentials_create(" - "json_key=%s, " - "token_lifetime=" - "gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, " - "reserved=%p)", - 5, - (json_key, (long long)token_lifetime.tv_sec, (int)token_lifetime.tv_nsec, - (int)token_lifetime.clock_type, reserved)); - GPR_ASSERT(reserved == NULL); - return grpc_service_account_jwt_access_credentials_create_from_auth_json_key( - grpc_auth_json_key_create_from_string(json_key), token_lifetime); -} - -/* -- Oauth2TokenFetcher credentials -- */ - -static void oauth2_token_fetcher_destruct(grpc_call_credentials *creds) { - grpc_oauth2_token_fetcher_credentials *c = - (grpc_oauth2_token_fetcher_credentials *)creds; - grpc_credentials_md_store_unref(c->access_token_md); - gpr_mu_destroy(&c->mu); - grpc_httpcli_context_destroy(&c->httpcli_context); -} - -grpc_credentials_status -grpc_oauth2_token_fetcher_credentials_parse_server_response( - const grpc_http_response *response, grpc_credentials_md_store **token_md, - gpr_timespec *token_lifetime) { - char *null_terminated_body = NULL; - char *new_access_token = NULL; - grpc_credentials_status status = GRPC_CREDENTIALS_OK; - grpc_json *json = NULL; - - if (response == NULL) { - gpr_log(GPR_ERROR, "Received NULL response."); - status = GRPC_CREDENTIALS_ERROR; - goto end; - } - - if (response->body_length > 0) { - null_terminated_body = gpr_malloc(response->body_length + 1); - null_terminated_body[response->body_length] = '\0'; - memcpy(null_terminated_body, response->body, response->body_length); - } - - if (response->status != 200) { - gpr_log(GPR_ERROR, "Call to http server ended with error %d [%s].", - response->status, - null_terminated_body != NULL ? null_terminated_body : ""); - status = GRPC_CREDENTIALS_ERROR; - goto end; - } else { - grpc_json *access_token = NULL; - grpc_json *token_type = NULL; - grpc_json *expires_in = NULL; - grpc_json *ptr; - json = grpc_json_parse_string(null_terminated_body); - if (json == NULL) { - gpr_log(GPR_ERROR, "Could not parse JSON from %s", null_terminated_body); - status = GRPC_CREDENTIALS_ERROR; - goto end; - } - if (json->type != GRPC_JSON_OBJECT) { - gpr_log(GPR_ERROR, "Response should be a JSON object"); - status = GRPC_CREDENTIALS_ERROR; - goto end; - } - for (ptr = json->child; ptr; ptr = ptr->next) { - if (strcmp(ptr->key, "access_token") == 0) { - access_token = ptr; - } else if (strcmp(ptr->key, "token_type") == 0) { - token_type = ptr; - } else if (strcmp(ptr->key, "expires_in") == 0) { - expires_in = ptr; - } - } - if (access_token == NULL || access_token->type != GRPC_JSON_STRING) { - gpr_log(GPR_ERROR, "Missing or invalid access_token in JSON."); - status = GRPC_CREDENTIALS_ERROR; - goto end; - } - if (token_type == NULL || token_type->type != GRPC_JSON_STRING) { - gpr_log(GPR_ERROR, "Missing or invalid token_type in JSON."); - status = GRPC_CREDENTIALS_ERROR; - goto end; - } - if (expires_in == NULL || expires_in->type != GRPC_JSON_NUMBER) { - gpr_log(GPR_ERROR, "Missing or invalid expires_in in JSON."); - status = GRPC_CREDENTIALS_ERROR; - goto end; - } - gpr_asprintf(&new_access_token, "%s %s", token_type->value, - access_token->value); - token_lifetime->tv_sec = strtol(expires_in->value, NULL, 10); - token_lifetime->tv_nsec = 0; - token_lifetime->clock_type = GPR_TIMESPAN; - if (*token_md != NULL) grpc_credentials_md_store_unref(*token_md); - *token_md = grpc_credentials_md_store_create(1); - grpc_credentials_md_store_add_cstrings( - *token_md, GRPC_AUTHORIZATION_METADATA_KEY, new_access_token); - status = GRPC_CREDENTIALS_OK; - } - -end: - if (status != GRPC_CREDENTIALS_OK && (*token_md != NULL)) { - grpc_credentials_md_store_unref(*token_md); - *token_md = NULL; - } - if (null_terminated_body != NULL) gpr_free(null_terminated_body); - if (new_access_token != NULL) gpr_free(new_access_token); - if (json != NULL) grpc_json_destroy(json); - return status; -} - -static void on_oauth2_token_fetcher_http_response( - grpc_exec_ctx *exec_ctx, void *user_data, - const grpc_http_response *response) { - grpc_credentials_metadata_request *r = - (grpc_credentials_metadata_request *)user_data; - grpc_oauth2_token_fetcher_credentials *c = - (grpc_oauth2_token_fetcher_credentials *)r->creds; - gpr_timespec token_lifetime; - grpc_credentials_status status; - - gpr_mu_lock(&c->mu); - status = grpc_oauth2_token_fetcher_credentials_parse_server_response( - response, &c->access_token_md, &token_lifetime); - if (status == GRPC_CREDENTIALS_OK) { - c->token_expiration = - gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), token_lifetime); - r->cb(exec_ctx, r->user_data, c->access_token_md->entries, - c->access_token_md->num_entries, status); - } else { - c->token_expiration = gpr_inf_past(GPR_CLOCK_REALTIME); - r->cb(exec_ctx, r->user_data, NULL, 0, status); - } - gpr_mu_unlock(&c->mu); - grpc_credentials_metadata_request_destroy(r); -} - -static void oauth2_token_fetcher_get_request_metadata( - grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, - grpc_pollset *pollset, grpc_auth_metadata_context context, - grpc_credentials_metadata_cb cb, void *user_data) { - grpc_oauth2_token_fetcher_credentials *c = - (grpc_oauth2_token_fetcher_credentials *)creds; - gpr_timespec refresh_threshold = gpr_time_from_seconds( - GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS, GPR_TIMESPAN); - grpc_credentials_md_store *cached_access_token_md = NULL; - { - gpr_mu_lock(&c->mu); - if (c->access_token_md != NULL && - (gpr_time_cmp( - gpr_time_sub(c->token_expiration, gpr_now(GPR_CLOCK_REALTIME)), - refresh_threshold) > 0)) { - cached_access_token_md = - grpc_credentials_md_store_ref(c->access_token_md); - } - gpr_mu_unlock(&c->mu); - } - if (cached_access_token_md != NULL) { - cb(exec_ctx, user_data, cached_access_token_md->entries, - cached_access_token_md->num_entries, GRPC_CREDENTIALS_OK); - grpc_credentials_md_store_unref(cached_access_token_md); - } else { - c->fetch_func( - exec_ctx, - grpc_credentials_metadata_request_create(creds, cb, user_data), - &c->httpcli_context, pollset, on_oauth2_token_fetcher_http_response, - gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), refresh_threshold)); - } -} - -static void init_oauth2_token_fetcher(grpc_oauth2_token_fetcher_credentials *c, - grpc_fetch_oauth2_func fetch_func) { - memset(c, 0, sizeof(grpc_oauth2_token_fetcher_credentials)); - c->base.type = GRPC_CALL_CREDENTIALS_TYPE_OAUTH2; - gpr_ref_init(&c->base.refcount, 1); - gpr_mu_init(&c->mu); - c->token_expiration = gpr_inf_past(GPR_CLOCK_REALTIME); - c->fetch_func = fetch_func; - grpc_httpcli_context_init(&c->httpcli_context); -} - -/* -- GoogleComputeEngine credentials. -- */ - -static grpc_call_credentials_vtable compute_engine_vtable = { - oauth2_token_fetcher_destruct, oauth2_token_fetcher_get_request_metadata}; - -static void compute_engine_fetch_oauth2( - grpc_exec_ctx *exec_ctx, grpc_credentials_metadata_request *metadata_req, - grpc_httpcli_context *httpcli_context, grpc_pollset *pollset, - grpc_httpcli_response_cb response_cb, gpr_timespec deadline) { - grpc_http_header header = {"Metadata-Flavor", "Google"}; - grpc_httpcli_request request; - memset(&request, 0, sizeof(grpc_httpcli_request)); - request.host = GRPC_COMPUTE_ENGINE_METADATA_HOST; - request.http.path = GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH; - request.http.hdr_count = 1; - request.http.hdrs = &header; - grpc_httpcli_get(exec_ctx, httpcli_context, pollset, &request, deadline, - response_cb, metadata_req); -} - -grpc_call_credentials *grpc_google_compute_engine_credentials_create( - void *reserved) { - grpc_oauth2_token_fetcher_credentials *c = - gpr_malloc(sizeof(grpc_oauth2_token_fetcher_credentials)); - GRPC_API_TRACE("grpc_compute_engine_credentials_create(reserved=%p)", 1, - (reserved)); - GPR_ASSERT(reserved == NULL); - init_oauth2_token_fetcher(c, compute_engine_fetch_oauth2); - c->base.vtable = &compute_engine_vtable; - return &c->base; -} - -/* -- GoogleRefreshToken credentials. -- */ - -static void refresh_token_destruct(grpc_call_credentials *creds) { - grpc_google_refresh_token_credentials *c = - (grpc_google_refresh_token_credentials *)creds; - grpc_auth_refresh_token_destruct(&c->refresh_token); - oauth2_token_fetcher_destruct(&c->base.base); -} - -static grpc_call_credentials_vtable refresh_token_vtable = { - refresh_token_destruct, oauth2_token_fetcher_get_request_metadata}; - -static void refresh_token_fetch_oauth2( - grpc_exec_ctx *exec_ctx, grpc_credentials_metadata_request *metadata_req, - grpc_httpcli_context *httpcli_context, grpc_pollset *pollset, - grpc_httpcli_response_cb response_cb, gpr_timespec deadline) { - grpc_google_refresh_token_credentials *c = - (grpc_google_refresh_token_credentials *)metadata_req->creds; - grpc_http_header header = {"Content-Type", - "application/x-www-form-urlencoded"}; - grpc_httpcli_request request; - char *body = NULL; - gpr_asprintf(&body, GRPC_REFRESH_TOKEN_POST_BODY_FORMAT_STRING, - c->refresh_token.client_id, c->refresh_token.client_secret, - c->refresh_token.refresh_token); - memset(&request, 0, sizeof(grpc_httpcli_request)); - request.host = GRPC_GOOGLE_OAUTH2_SERVICE_HOST; - request.http.path = GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH; - request.http.hdr_count = 1; - request.http.hdrs = &header; - request.handshaker = &grpc_httpcli_ssl; - grpc_httpcli_post(exec_ctx, httpcli_context, pollset, &request, body, - strlen(body), deadline, response_cb, metadata_req); - gpr_free(body); -} - -grpc_call_credentials * -grpc_refresh_token_credentials_create_from_auth_refresh_token( - grpc_auth_refresh_token refresh_token) { - grpc_google_refresh_token_credentials *c; - if (!grpc_auth_refresh_token_is_valid(&refresh_token)) { - gpr_log(GPR_ERROR, "Invalid input for refresh token credentials creation"); - return NULL; - } - c = gpr_malloc(sizeof(grpc_google_refresh_token_credentials)); - memset(c, 0, sizeof(grpc_google_refresh_token_credentials)); - init_oauth2_token_fetcher(&c->base, refresh_token_fetch_oauth2); - c->base.base.vtable = &refresh_token_vtable; - c->refresh_token = refresh_token; - return &c->base.base; -} - -grpc_call_credentials *grpc_google_refresh_token_credentials_create( - const char *json_refresh_token, void *reserved) { - GRPC_API_TRACE( - "grpc_refresh_token_credentials_create(json_refresh_token=%s, " - "reserved=%p)", - 2, (json_refresh_token, reserved)); - GPR_ASSERT(reserved == NULL); - return grpc_refresh_token_credentials_create_from_auth_refresh_token( - grpc_auth_refresh_token_create_from_string(json_refresh_token)); -} - -/* -- Metadata-only credentials. -- */ - -static void md_only_test_destruct(grpc_call_credentials *creds) { - grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)creds; - grpc_credentials_md_store_unref(c->md_store); -} - -static void on_simulated_token_fetch_done(grpc_exec_ctx *exec_ctx, - void *user_data, bool success) { - grpc_credentials_metadata_request *r = - (grpc_credentials_metadata_request *)user_data; - grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)r->creds; - r->cb(exec_ctx, r->user_data, c->md_store->entries, c->md_store->num_entries, - GRPC_CREDENTIALS_OK); - grpc_credentials_metadata_request_destroy(r); -} - -static void md_only_test_get_request_metadata( - grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, - grpc_pollset *pollset, grpc_auth_metadata_context context, - grpc_credentials_metadata_cb cb, void *user_data) { - grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)creds; - - if (c->is_async) { - grpc_credentials_metadata_request *cb_arg = - grpc_credentials_metadata_request_create(creds, cb, user_data); - grpc_executor_enqueue( - grpc_closure_create(on_simulated_token_fetch_done, cb_arg), true); - } else { - cb(exec_ctx, user_data, c->md_store->entries, 1, GRPC_CREDENTIALS_OK); - } -} - -static grpc_call_credentials_vtable md_only_test_vtable = { - md_only_test_destruct, md_only_test_get_request_metadata}; - -grpc_call_credentials *grpc_md_only_test_credentials_create( - const char *md_key, const char *md_value, int is_async) { - grpc_md_only_test_credentials *c = - gpr_malloc(sizeof(grpc_md_only_test_credentials)); - memset(c, 0, sizeof(grpc_md_only_test_credentials)); - c->base.type = GRPC_CALL_CREDENTIALS_TYPE_OAUTH2; - c->base.vtable = &md_only_test_vtable; - gpr_ref_init(&c->base.refcount, 1); - c->md_store = grpc_credentials_md_store_create(1); - grpc_credentials_md_store_add_cstrings(c->md_store, md_key, md_value); - c->is_async = is_async; - return &c->base; -} - -/* -- Oauth2 Access Token credentials. -- */ - -static void access_token_destruct(grpc_call_credentials *creds) { - grpc_access_token_credentials *c = (grpc_access_token_credentials *)creds; - grpc_credentials_md_store_unref(c->access_token_md); -} - -static void access_token_get_request_metadata( - grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, - grpc_pollset *pollset, grpc_auth_metadata_context context, - grpc_credentials_metadata_cb cb, void *user_data) { - grpc_access_token_credentials *c = (grpc_access_token_credentials *)creds; - cb(exec_ctx, user_data, c->access_token_md->entries, 1, GRPC_CREDENTIALS_OK); -} - -static grpc_call_credentials_vtable access_token_vtable = { - access_token_destruct, access_token_get_request_metadata}; - -grpc_call_credentials *grpc_access_token_credentials_create( - const char *access_token, void *reserved) { - grpc_access_token_credentials *c = - gpr_malloc(sizeof(grpc_access_token_credentials)); - char *token_md_value; - GRPC_API_TRACE( - "grpc_access_token_credentials_create(access_token=%s, " - "reserved=%p)", - 2, (access_token, reserved)); - GPR_ASSERT(reserved == NULL); - memset(c, 0, sizeof(grpc_access_token_credentials)); - c->base.type = GRPC_CALL_CREDENTIALS_TYPE_OAUTH2; - c->base.vtable = &access_token_vtable; - gpr_ref_init(&c->base.refcount, 1); - c->access_token_md = grpc_credentials_md_store_create(1); - gpr_asprintf(&token_md_value, "Bearer %s", access_token); - grpc_credentials_md_store_add_cstrings( - c->access_token_md, GRPC_AUTHORIZATION_METADATA_KEY, token_md_value); - gpr_free(token_md_value); - return &c->base; -} - -/* -- Fake transport security credentials. -- */ - -static grpc_security_status fake_transport_security_create_security_connector( - grpc_channel_credentials *c, grpc_call_credentials *call_creds, - const char *target, const grpc_channel_args *args, - grpc_channel_security_connector **sc, grpc_channel_args **new_args) { - *sc = grpc_fake_channel_security_connector_create(call_creds); - return GRPC_SECURITY_OK; -} - -static grpc_security_status -fake_transport_security_server_create_security_connector( - grpc_server_credentials *c, grpc_server_security_connector **sc) { - *sc = grpc_fake_server_security_connector_create(); - return GRPC_SECURITY_OK; -} - -static grpc_channel_credentials_vtable - fake_transport_security_credentials_vtable = { - NULL, fake_transport_security_create_security_connector}; - -static grpc_server_credentials_vtable - fake_transport_security_server_credentials_vtable = { - NULL, fake_transport_security_server_create_security_connector}; - -grpc_channel_credentials *grpc_fake_transport_security_credentials_create( - void) { - grpc_channel_credentials *c = gpr_malloc(sizeof(grpc_channel_credentials)); - memset(c, 0, sizeof(grpc_channel_credentials)); - c->type = GRPC_CHANNEL_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY; - c->vtable = &fake_transport_security_credentials_vtable; - gpr_ref_init(&c->refcount, 1); - return c; -} - -grpc_server_credentials *grpc_fake_transport_security_server_credentials_create( - void) { - grpc_server_credentials *c = gpr_malloc(sizeof(grpc_server_credentials)); - memset(c, 0, sizeof(grpc_server_credentials)); - c->type = GRPC_CHANNEL_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY; - gpr_ref_init(&c->refcount, 1); - c->vtable = &fake_transport_security_server_credentials_vtable; - return c; -} - -/* -- Composite call credentials. -- */ - -typedef struct { - grpc_composite_call_credentials *composite_creds; - size_t creds_index; - grpc_credentials_md_store *md_elems; - grpc_auth_metadata_context auth_md_context; - void *user_data; - grpc_pollset *pollset; - grpc_credentials_metadata_cb cb; -} grpc_composite_call_credentials_metadata_context; - -static void composite_call_destruct(grpc_call_credentials *creds) { - grpc_composite_call_credentials *c = (grpc_composite_call_credentials *)creds; - size_t i; - for (i = 0; i < c->inner.num_creds; i++) { - grpc_call_credentials_unref(c->inner.creds_array[i]); - } - gpr_free(c->inner.creds_array); -} - -static void composite_call_md_context_destroy( - grpc_composite_call_credentials_metadata_context *ctx) { - grpc_credentials_md_store_unref(ctx->md_elems); - gpr_free(ctx); -} - -static void composite_call_metadata_cb(grpc_exec_ctx *exec_ctx, void *user_data, - grpc_credentials_md *md_elems, - size_t num_md, - grpc_credentials_status status) { - grpc_composite_call_credentials_metadata_context *ctx = - (grpc_composite_call_credentials_metadata_context *)user_data; - if (status != GRPC_CREDENTIALS_OK) { - ctx->cb(exec_ctx, ctx->user_data, NULL, 0, status); - return; - } - - /* Copy the metadata in the context. */ - if (num_md > 0) { - size_t i; - for (i = 0; i < num_md; i++) { - grpc_credentials_md_store_add(ctx->md_elems, md_elems[i].key, - md_elems[i].value); - } - } - - /* See if we need to get some more metadata. */ - if (ctx->creds_index < ctx->composite_creds->inner.num_creds) { - grpc_call_credentials *inner_creds = - ctx->composite_creds->inner.creds_array[ctx->creds_index++]; - grpc_call_credentials_get_request_metadata( - exec_ctx, inner_creds, ctx->pollset, ctx->auth_md_context, - composite_call_metadata_cb, ctx); - return; - } - - /* We're done!. */ - ctx->cb(exec_ctx, ctx->user_data, ctx->md_elems->entries, - ctx->md_elems->num_entries, GRPC_CREDENTIALS_OK); - composite_call_md_context_destroy(ctx); -} - -static void composite_call_get_request_metadata( - grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, - grpc_pollset *pollset, grpc_auth_metadata_context auth_md_context, - grpc_credentials_metadata_cb cb, void *user_data) { - grpc_composite_call_credentials *c = (grpc_composite_call_credentials *)creds; - grpc_composite_call_credentials_metadata_context *ctx; - - ctx = gpr_malloc(sizeof(grpc_composite_call_credentials_metadata_context)); - memset(ctx, 0, sizeof(grpc_composite_call_credentials_metadata_context)); - ctx->auth_md_context = auth_md_context; - ctx->user_data = user_data; - ctx->cb = cb; - ctx->composite_creds = c; - ctx->pollset = pollset; - ctx->md_elems = grpc_credentials_md_store_create(c->inner.num_creds); - grpc_call_credentials_get_request_metadata( - exec_ctx, c->inner.creds_array[ctx->creds_index++], pollset, - auth_md_context, composite_call_metadata_cb, ctx); -} - -static grpc_call_credentials_vtable composite_call_credentials_vtable = { - composite_call_destruct, composite_call_get_request_metadata}; - -static grpc_call_credentials_array get_creds_array( - grpc_call_credentials **creds_addr) { - grpc_call_credentials_array result; - grpc_call_credentials *creds = *creds_addr; - result.creds_array = creds_addr; - result.num_creds = 1; - if (strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0) { - result = *grpc_composite_call_credentials_get_credentials(creds); - } - return result; -} - -grpc_call_credentials *grpc_composite_call_credentials_create( - grpc_call_credentials *creds1, grpc_call_credentials *creds2, - void *reserved) { - size_t i; - size_t creds_array_byte_size; - grpc_call_credentials_array creds1_array; - grpc_call_credentials_array creds2_array; - grpc_composite_call_credentials *c; - GRPC_API_TRACE( - "grpc_composite_call_credentials_create(creds1=%p, creds2=%p, " - "reserved=%p)", - 3, (creds1, creds2, reserved)); - GPR_ASSERT(reserved == NULL); - GPR_ASSERT(creds1 != NULL); - GPR_ASSERT(creds2 != NULL); - c = gpr_malloc(sizeof(grpc_composite_call_credentials)); - memset(c, 0, sizeof(grpc_composite_call_credentials)); - c->base.type = GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE; - c->base.vtable = &composite_call_credentials_vtable; - gpr_ref_init(&c->base.refcount, 1); - creds1_array = get_creds_array(&creds1); - creds2_array = get_creds_array(&creds2); - c->inner.num_creds = creds1_array.num_creds + creds2_array.num_creds; - creds_array_byte_size = c->inner.num_creds * sizeof(grpc_call_credentials *); - c->inner.creds_array = gpr_malloc(creds_array_byte_size); - memset(c->inner.creds_array, 0, creds_array_byte_size); - for (i = 0; i < creds1_array.num_creds; i++) { - grpc_call_credentials *cur_creds = creds1_array.creds_array[i]; - c->inner.creds_array[i] = grpc_call_credentials_ref(cur_creds); - } - for (i = 0; i < creds2_array.num_creds; i++) { - grpc_call_credentials *cur_creds = creds2_array.creds_array[i]; - c->inner.creds_array[i + creds1_array.num_creds] = - grpc_call_credentials_ref(cur_creds); - } - return &c->base; -} - -const grpc_call_credentials_array * -grpc_composite_call_credentials_get_credentials(grpc_call_credentials *creds) { - const grpc_composite_call_credentials *c = - (const grpc_composite_call_credentials *)creds; - GPR_ASSERT(strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0); - return &c->inner; -} - -grpc_call_credentials *grpc_credentials_contains_type( - grpc_call_credentials *creds, const char *type, - grpc_call_credentials **composite_creds) { - size_t i; - if (strcmp(creds->type, type) == 0) { - if (composite_creds != NULL) *composite_creds = NULL; - return creds; - } else if (strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0) { - const grpc_call_credentials_array *inner_creds_array = - grpc_composite_call_credentials_get_credentials(creds); - for (i = 0; i < inner_creds_array->num_creds; i++) { - if (strcmp(type, inner_creds_array->creds_array[i]->type) == 0) { - if (composite_creds != NULL) *composite_creds = creds; - return inner_creds_array->creds_array[i]; - } - } - } - return NULL; -} - -/* -- IAM credentials. -- */ - -static void iam_destruct(grpc_call_credentials *creds) { - grpc_google_iam_credentials *c = (grpc_google_iam_credentials *)creds; - grpc_credentials_md_store_unref(c->iam_md); -} - -static void iam_get_request_metadata(grpc_exec_ctx *exec_ctx, - grpc_call_credentials *creds, - grpc_pollset *pollset, - grpc_auth_metadata_context context, - grpc_credentials_metadata_cb cb, - void *user_data) { - grpc_google_iam_credentials *c = (grpc_google_iam_credentials *)creds; - cb(exec_ctx, user_data, c->iam_md->entries, c->iam_md->num_entries, - GRPC_CREDENTIALS_OK); -} - -static grpc_call_credentials_vtable iam_vtable = {iam_destruct, - iam_get_request_metadata}; - -grpc_call_credentials *grpc_google_iam_credentials_create( - const char *token, const char *authority_selector, void *reserved) { - grpc_google_iam_credentials *c; - GRPC_API_TRACE( - "grpc_iam_credentials_create(token=%s, authority_selector=%s, " - "reserved=%p)", - 3, (token, authority_selector, reserved)); - GPR_ASSERT(reserved == NULL); - GPR_ASSERT(token != NULL); - GPR_ASSERT(authority_selector != NULL); - c = gpr_malloc(sizeof(grpc_google_iam_credentials)); - memset(c, 0, sizeof(grpc_google_iam_credentials)); - c->base.type = GRPC_CALL_CREDENTIALS_TYPE_IAM; - c->base.vtable = &iam_vtable; - gpr_ref_init(&c->base.refcount, 1); - c->iam_md = grpc_credentials_md_store_create(2); - grpc_credentials_md_store_add_cstrings( - c->iam_md, GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY, token); - grpc_credentials_md_store_add_cstrings( - c->iam_md, GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY, authority_selector); - return &c->base; -} - -/* -- Plugin credentials. -- */ - -typedef struct { - void *user_data; - grpc_credentials_metadata_cb cb; -} grpc_metadata_plugin_request; - -static void plugin_destruct(grpc_call_credentials *creds) { - grpc_plugin_credentials *c = (grpc_plugin_credentials *)creds; - if (c->plugin.state != NULL && c->plugin.destroy != NULL) { - c->plugin.destroy(c->plugin.state); - } -} - -static void plugin_md_request_metadata_ready(void *request, - const grpc_metadata *md, - size_t num_md, - grpc_status_code status, - const char *error_details) { - /* called from application code */ - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_metadata_plugin_request *r = (grpc_metadata_plugin_request *)request; - if (status != GRPC_STATUS_OK) { - if (error_details != NULL) { - gpr_log(GPR_ERROR, "Getting metadata from plugin failed with error: %s", - error_details); - } - r->cb(&exec_ctx, r->user_data, NULL, 0, GRPC_CREDENTIALS_ERROR); - } else { - size_t i; - grpc_credentials_md *md_array = NULL; - if (num_md > 0) { - md_array = gpr_malloc(num_md * sizeof(grpc_credentials_md)); - for (i = 0; i < num_md; i++) { - md_array[i].key = gpr_slice_from_copied_string(md[i].key); - md_array[i].value = - gpr_slice_from_copied_buffer(md[i].value, md[i].value_length); - } - } - r->cb(&exec_ctx, r->user_data, md_array, num_md, GRPC_CREDENTIALS_OK); - if (md_array != NULL) { - for (i = 0; i < num_md; i++) { - gpr_slice_unref(md_array[i].key); - gpr_slice_unref(md_array[i].value); - } - gpr_free(md_array); - } - } - gpr_free(r); - grpc_exec_ctx_finish(&exec_ctx); -} - -static void plugin_get_request_metadata(grpc_exec_ctx *exec_ctx, - grpc_call_credentials *creds, - grpc_pollset *pollset, - grpc_auth_metadata_context context, - grpc_credentials_metadata_cb cb, - void *user_data) { - grpc_plugin_credentials *c = (grpc_plugin_credentials *)creds; - if (c->plugin.get_metadata != NULL) { - grpc_metadata_plugin_request *request = gpr_malloc(sizeof(*request)); - memset(request, 0, sizeof(*request)); - request->user_data = user_data; - request->cb = cb; - c->plugin.get_metadata(c->plugin.state, context, - plugin_md_request_metadata_ready, request); - } else { - cb(exec_ctx, user_data, NULL, 0, GRPC_CREDENTIALS_OK); - } -} - -static grpc_call_credentials_vtable plugin_vtable = { - plugin_destruct, plugin_get_request_metadata}; - -grpc_call_credentials *grpc_metadata_credentials_create_from_plugin( - grpc_metadata_credentials_plugin plugin, void *reserved) { - grpc_plugin_credentials *c = gpr_malloc(sizeof(*c)); - GRPC_API_TRACE("grpc_metadata_credentials_create_from_plugin(reserved=%p)", 1, - (reserved)); - GPR_ASSERT(reserved == NULL); - memset(c, 0, sizeof(*c)); - c->base.type = plugin.type; - c->base.vtable = &plugin_vtable; - gpr_ref_init(&c->base.refcount, 1); - c->plugin = plugin; - return &c->base; -} - -/* -- Composite channel credentials. -- */ - -static void composite_channel_destruct(grpc_channel_credentials *creds) { - grpc_composite_channel_credentials *c = - (grpc_composite_channel_credentials *)creds; - grpc_channel_credentials_unref(c->inner_creds); - grpc_call_credentials_unref(c->call_creds); -} - -static grpc_security_status composite_channel_create_security_connector( - grpc_channel_credentials *creds, grpc_call_credentials *call_creds, - const char *target, const grpc_channel_args *args, - grpc_channel_security_connector **sc, grpc_channel_args **new_args) { - grpc_composite_channel_credentials *c = - (grpc_composite_channel_credentials *)creds; - grpc_security_status status = GRPC_SECURITY_ERROR; - - GPR_ASSERT(c->inner_creds != NULL && c->call_creds != NULL && - c->inner_creds->vtable != NULL && - c->inner_creds->vtable->create_security_connector != NULL); - /* If we are passed a call_creds, create a call composite to pass it - downstream. */ - if (call_creds != NULL) { - grpc_call_credentials *composite_call_creds = - grpc_composite_call_credentials_create(c->call_creds, call_creds, NULL); - status = c->inner_creds->vtable->create_security_connector( - c->inner_creds, composite_call_creds, target, args, sc, new_args); - grpc_call_credentials_unref(composite_call_creds); - } else { - status = c->inner_creds->vtable->create_security_connector( - c->inner_creds, c->call_creds, target, args, sc, new_args); - } - return status; -} - -static grpc_channel_credentials_vtable composite_channel_credentials_vtable = { - composite_channel_destruct, composite_channel_create_security_connector}; - -grpc_channel_credentials *grpc_composite_channel_credentials_create( - grpc_channel_credentials *channel_creds, grpc_call_credentials *call_creds, - void *reserved) { - grpc_composite_channel_credentials *c = gpr_malloc(sizeof(*c)); - memset(c, 0, sizeof(*c)); - GPR_ASSERT(channel_creds != NULL && call_creds != NULL && reserved == NULL); - GRPC_API_TRACE( - "grpc_composite_channel_credentials_create(channel_creds=%p, " - "call_creds=%p, reserved=%p)", - 3, (channel_creds, call_creds, reserved)); - c->base.type = channel_creds->type; - c->base.vtable = &composite_channel_credentials_vtable; - gpr_ref_init(&c->base.refcount, 1); - c->inner_creds = grpc_channel_credentials_ref(channel_creds); - c->call_creds = grpc_call_credentials_ref(call_creds); - return &c->base; -} diff --git a/src/core/security/credentials.h b/src/core/security/credentials.h deleted file mode 100644 index bfa7cc71bd..0000000000 --- a/src/core/security/credentials.h +++ /dev/null @@ -1,377 +0,0 @@ -/* - * - * Copyright 2015-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_SECURITY_CREDENTIALS_H -#define GRPC_CORE_SECURITY_CREDENTIALS_H - -#include -#include -#include -#include "src/core/transport/metadata_batch.h" - -#include "src/core/http/httpcli.h" -#include "src/core/http/parser.h" -#include "src/core/security/json_token.h" -#include "src/core/security/security_connector.h" - -struct grpc_http_response; - -/* --- Constants. --- */ - -typedef enum { - GRPC_CREDENTIALS_OK = 0, - GRPC_CREDENTIALS_ERROR -} grpc_credentials_status; - -#define GRPC_FAKE_TRANSPORT_SECURITY_TYPE "fake" - -#define GRPC_CHANNEL_CREDENTIALS_TYPE_SSL "Ssl" -#define GRPC_CHANNEL_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY \ - "FakeTransportSecurity" - -#define GRPC_CALL_CREDENTIALS_TYPE_OAUTH2 "Oauth2" -#define GRPC_CALL_CREDENTIALS_TYPE_JWT "Jwt" -#define GRPC_CALL_CREDENTIALS_TYPE_IAM "Iam" -#define GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE "Composite" - -#define GRPC_AUTHORIZATION_METADATA_KEY "authorization" -#define GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY \ - "x-goog-iam-authorization-token" -#define GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY "x-goog-iam-authority-selector" - -#define GRPC_GOOGLE_CLOUD_SDK_CONFIG_DIRECTORY "gcloud" -#define GRPC_GOOGLE_WELL_KNOWN_CREDENTIALS_FILE \ - "application_default_credentials.json" - -#define GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS 60 - -#define GRPC_COMPUTE_ENGINE_METADATA_HOST "metadata" -#define GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH \ - "/computeMetadata/v1/instance/service-accounts/default/token" - -#define GRPC_GOOGLE_OAUTH2_SERVICE_HOST "www.googleapis.com" -#define GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH "/oauth2/v3/token" - -#define GRPC_SERVICE_ACCOUNT_POST_BODY_PREFIX \ - "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&" \ - "assertion=" - -#define GRPC_REFRESH_TOKEN_POST_BODY_FORMAT_STRING \ - "client_id=%s&client_secret=%s&refresh_token=%s&grant_type=refresh_token" - -/* --- Google utils --- */ - -/* It is the caller's responsibility to gpr_free the result if not NULL. */ -char *grpc_get_well_known_google_credentials_file_path(void); - -/* Implementation function for the different platforms. */ -char *grpc_get_well_known_google_credentials_file_path_impl(void); - -/* Override for testing only. Not thread-safe */ -typedef char *(*grpc_well_known_credentials_path_getter)(void); -void grpc_override_well_known_credentials_path_getter( - grpc_well_known_credentials_path_getter getter); - -/* --- grpc_channel_credentials. --- */ - -typedef struct { - void (*destruct)(grpc_channel_credentials *c); - - grpc_security_status (*create_security_connector)( - grpc_channel_credentials *c, grpc_call_credentials *call_creds, - const char *target, const grpc_channel_args *args, - grpc_channel_security_connector **sc, grpc_channel_args **new_args); -} grpc_channel_credentials_vtable; - -struct grpc_channel_credentials { - const grpc_channel_credentials_vtable *vtable; - const char *type; - gpr_refcount refcount; -}; - -grpc_channel_credentials *grpc_channel_credentials_ref( - grpc_channel_credentials *creds); -void grpc_channel_credentials_unref(grpc_channel_credentials *creds); - -/* Creates a security connector for the channel. May also create new channel - args for the channel to be used in place of the passed in const args if - returned non NULL. In that case the caller is responsible for destroying - new_args after channel creation. */ -grpc_security_status grpc_channel_credentials_create_security_connector( - grpc_channel_credentials *creds, const char *target, - const grpc_channel_args *args, grpc_channel_security_connector **sc, - grpc_channel_args **new_args); - -/* --- grpc_credentials_md. --- */ - -typedef struct { - gpr_slice key; - gpr_slice value; -} grpc_credentials_md; - -typedef struct { - grpc_credentials_md *entries; - size_t num_entries; - size_t allocated; - gpr_refcount refcount; -} grpc_credentials_md_store; - -grpc_credentials_md_store *grpc_credentials_md_store_create( - size_t initial_capacity); - -/* Will ref key and value. */ -void grpc_credentials_md_store_add(grpc_credentials_md_store *store, - gpr_slice key, gpr_slice value); -void grpc_credentials_md_store_add_cstrings(grpc_credentials_md_store *store, - const char *key, const char *value); -grpc_credentials_md_store *grpc_credentials_md_store_ref( - grpc_credentials_md_store *store); -void grpc_credentials_md_store_unref(grpc_credentials_md_store *store); - -/* --- grpc_call_credentials. --- */ - -typedef void (*grpc_credentials_metadata_cb)(grpc_exec_ctx *exec_ctx, - void *user_data, - grpc_credentials_md *md_elems, - size_t num_md, - grpc_credentials_status status); - -typedef struct { - void (*destruct)(grpc_call_credentials *c); - void (*get_request_metadata)(grpc_exec_ctx *exec_ctx, - grpc_call_credentials *c, grpc_pollset *pollset, - grpc_auth_metadata_context context, - grpc_credentials_metadata_cb cb, - void *user_data); -} grpc_call_credentials_vtable; - -struct grpc_call_credentials { - const grpc_call_credentials_vtable *vtable; - const char *type; - gpr_refcount refcount; -}; - -grpc_call_credentials *grpc_call_credentials_ref(grpc_call_credentials *creds); -void grpc_call_credentials_unref(grpc_call_credentials *creds); -void grpc_call_credentials_get_request_metadata( - grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, - grpc_pollset *pollset, grpc_auth_metadata_context context, - grpc_credentials_metadata_cb cb, void *user_data); - -typedef struct { - grpc_call_credentials **creds_array; - size_t num_creds; -} grpc_call_credentials_array; - -const grpc_call_credentials_array * -grpc_composite_call_credentials_get_credentials( - grpc_call_credentials *composite_creds); - -/* Returns creds if creds is of the specified type or the inner creds of the - specified type (if found), if the creds is of type COMPOSITE. - If composite_creds is not NULL, *composite_creds will point to creds if of - type COMPOSITE in case of success. */ -grpc_call_credentials *grpc_credentials_contains_type( - grpc_call_credentials *creds, const char *type, - grpc_call_credentials **composite_creds); - -/* Exposed for testing only. */ -grpc_credentials_status -grpc_oauth2_token_fetcher_credentials_parse_server_response( - const struct grpc_http_response *response, - grpc_credentials_md_store **token_md, gpr_timespec *token_lifetime); - -void grpc_flush_cached_google_default_credentials(void); - -/* Metadata-only credentials with the specified key and value where - asynchronicity can be simulated for testing. */ -grpc_call_credentials *grpc_md_only_test_credentials_create( - const char *md_key, const char *md_value, int is_async); - -/* Private constructor for jwt credentials from an already parsed json key. - Takes ownership of the key. */ -grpc_call_credentials * -grpc_service_account_jwt_access_credentials_create_from_auth_json_key( - grpc_auth_json_key key, gpr_timespec token_lifetime); - -/* Private constructor for refresh token credentials from an already parsed - refresh token. Takes ownership of the refresh token. */ -grpc_call_credentials * -grpc_refresh_token_credentials_create_from_auth_refresh_token( - grpc_auth_refresh_token token); - -/* --- grpc_server_credentials. --- */ - -typedef struct { - void (*destruct)(grpc_server_credentials *c); - grpc_security_status (*create_security_connector)( - grpc_server_credentials *c, grpc_server_security_connector **sc); -} grpc_server_credentials_vtable; - -struct grpc_server_credentials { - const grpc_server_credentials_vtable *vtable; - const char *type; - gpr_refcount refcount; - grpc_auth_metadata_processor processor; -}; - -grpc_security_status grpc_server_credentials_create_security_connector( - grpc_server_credentials *creds, grpc_server_security_connector **sc); - -grpc_server_credentials *grpc_server_credentials_ref( - grpc_server_credentials *creds); - -void grpc_server_credentials_unref(grpc_server_credentials *creds); - -#define GRPC_SERVER_CREDENTIALS_ARG "grpc.server_credentials" - -grpc_arg grpc_server_credentials_to_arg(grpc_server_credentials *c); -grpc_server_credentials *grpc_server_credentials_from_arg(const grpc_arg *arg); -grpc_server_credentials *grpc_find_server_credentials_in_args( - const grpc_channel_args *args); - -/* -- Fake transport security credentials. -- */ - -/* Creates a fake transport security credentials object for testing. */ -grpc_channel_credentials *grpc_fake_transport_security_credentials_create(void); -/* Creates a fake server transport security credentials object for testing. */ -grpc_server_credentials *grpc_fake_transport_security_server_credentials_create( - void); - -/* -- Ssl credentials. -- */ - -typedef struct { - grpc_channel_credentials base; - grpc_ssl_config config; -} grpc_ssl_credentials; - -typedef struct { - grpc_server_credentials base; - grpc_ssl_server_config config; -} grpc_ssl_server_credentials; - -/* -- Channel composite credentials. -- */ - -typedef struct { - grpc_channel_credentials base; - grpc_channel_credentials *inner_creds; - grpc_call_credentials *call_creds; -} grpc_composite_channel_credentials; - -/* -- Jwt credentials -- */ - -typedef struct { - grpc_call_credentials base; - - /* Have a simple cache for now with just 1 entry. We could have a map based on - the service_url for a more sophisticated one. */ - gpr_mu cache_mu; - struct { - grpc_credentials_md_store *jwt_md; - char *service_url; - gpr_timespec jwt_expiration; - } cached; - - grpc_auth_json_key key; - gpr_timespec jwt_lifetime; -} grpc_service_account_jwt_access_credentials; - -/* -- Oauth2TokenFetcher credentials -- - - This object is a base for credentials that need to acquire an oauth2 token - from an http service. */ - -typedef struct grpc_credentials_metadata_request - grpc_credentials_metadata_request; - -typedef void (*grpc_fetch_oauth2_func)(grpc_exec_ctx *exec_ctx, - grpc_credentials_metadata_request *req, - grpc_httpcli_context *http_context, - grpc_pollset *pollset, - grpc_httpcli_response_cb response_cb, - gpr_timespec deadline); - -typedef struct { - grpc_call_credentials base; - gpr_mu mu; - grpc_credentials_md_store *access_token_md; - gpr_timespec token_expiration; - grpc_httpcli_context httpcli_context; - grpc_fetch_oauth2_func fetch_func; -} grpc_oauth2_token_fetcher_credentials; - -/* -- GoogleRefreshToken credentials. -- */ - -typedef struct { - grpc_oauth2_token_fetcher_credentials base; - grpc_auth_refresh_token refresh_token; -} grpc_google_refresh_token_credentials; - -/* -- Oauth2 Access Token credentials. -- */ - -typedef struct { - grpc_call_credentials base; - grpc_credentials_md_store *access_token_md; -} grpc_access_token_credentials; - -/* -- Metadata-only Test credentials. -- */ - -typedef struct { - grpc_call_credentials base; - grpc_credentials_md_store *md_store; - int is_async; -} grpc_md_only_test_credentials; - -/* -- GoogleIAM credentials. -- */ - -typedef struct { - grpc_call_credentials base; - grpc_credentials_md_store *iam_md; -} grpc_google_iam_credentials; - -/* -- Composite credentials. -- */ - -typedef struct { - grpc_call_credentials base; - grpc_call_credentials_array inner; -} grpc_composite_call_credentials; - -/* -- Plugin credentials. -- */ - -typedef struct { - grpc_call_credentials base; - grpc_metadata_credentials_plugin plugin; - grpc_credentials_md_store *plugin_md; -} grpc_plugin_credentials; - -#endif /* GRPC_CORE_SECURITY_CREDENTIALS_H */ diff --git a/src/core/security/credentials_metadata.c b/src/core/security/credentials_metadata.c deleted file mode 100644 index b8a132f1ea..0000000000 --- a/src/core/security/credentials_metadata.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/security/credentials.h" - -#include - -#include - -static void store_ensure_capacity(grpc_credentials_md_store *store) { - if (store->num_entries == store->allocated) { - store->allocated = (store->allocated == 0) ? 1 : store->allocated * 2; - store->entries = gpr_realloc( - store->entries, store->allocated * sizeof(grpc_credentials_md)); - } -} - -grpc_credentials_md_store *grpc_credentials_md_store_create( - size_t initial_capacity) { - grpc_credentials_md_store *store = - gpr_malloc(sizeof(grpc_credentials_md_store)); - memset(store, 0, sizeof(grpc_credentials_md_store)); - if (initial_capacity > 0) { - store->entries = gpr_malloc(initial_capacity * sizeof(grpc_credentials_md)); - store->allocated = initial_capacity; - } - gpr_ref_init(&store->refcount, 1); - return store; -} - -void grpc_credentials_md_store_add(grpc_credentials_md_store *store, - gpr_slice key, gpr_slice value) { - if (store == NULL) return; - store_ensure_capacity(store); - store->entries[store->num_entries].key = gpr_slice_ref(key); - store->entries[store->num_entries].value = gpr_slice_ref(value); - store->num_entries++; -} - -void grpc_credentials_md_store_add_cstrings(grpc_credentials_md_store *store, - const char *key, - const char *value) { - if (store == NULL) return; - store_ensure_capacity(store); - store->entries[store->num_entries].key = gpr_slice_from_copied_string(key); - store->entries[store->num_entries].value = - gpr_slice_from_copied_string(value); - store->num_entries++; -} - -grpc_credentials_md_store *grpc_credentials_md_store_ref( - grpc_credentials_md_store *store) { - if (store == NULL) return NULL; - gpr_ref(&store->refcount); - return store; -} - -void grpc_credentials_md_store_unref(grpc_credentials_md_store *store) { - if (store == NULL) return; - if (gpr_unref(&store->refcount)) { - if (store->entries != NULL) { - size_t i; - for (i = 0; i < store->num_entries; i++) { - gpr_slice_unref(store->entries[i].key); - gpr_slice_unref(store->entries[i].value); - } - gpr_free(store->entries); - } - gpr_free(store); - } -} diff --git a/src/core/security/credentials_posix.c b/src/core/security/credentials_posix.c deleted file mode 100644 index 0c92bd4a96..0000000000 --- a/src/core/security/credentials_posix.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include - -#ifdef GPR_POSIX_FILE - -#include "src/core/security/credentials.h" - -#include -#include -#include - -#include "src/core/support/env.h" -#include "src/core/support/string.h" - -char *grpc_get_well_known_google_credentials_file_path_impl(void) { - char *result = NULL; - char *home = gpr_getenv("HOME"); - if (home == NULL) { - gpr_log(GPR_ERROR, "Could not get HOME environment variable."); - return NULL; - } - gpr_asprintf(&result, "%s/.config/%s/%s", home, - GRPC_GOOGLE_CLOUD_SDK_CONFIG_DIRECTORY, - GRPC_GOOGLE_WELL_KNOWN_CREDENTIALS_FILE); - gpr_free(home); - return result; -} - -#endif /* GPR_POSIX_FILE */ diff --git a/src/core/security/credentials_win32.c b/src/core/security/credentials_win32.c deleted file mode 100644 index 8ee9f706a1..0000000000 --- a/src/core/security/credentials_win32.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include - -#ifdef GPR_WIN32 - -#include "src/core/security/credentials.h" - -#include -#include -#include - -#include "src/core/support/env.h" -#include "src/core/support/string.h" - -char *grpc_get_well_known_google_credentials_file_path_impl(void) { - char *result = NULL; - char *appdata_path = gpr_getenv("APPDATA"); - if (appdata_path == NULL) { - gpr_log(GPR_ERROR, "Could not get APPDATA environment variable."); - return NULL; - } - gpr_asprintf(&result, "%s/%s/%s", appdata_path, - GRPC_GOOGLE_CLOUD_SDK_CONFIG_DIRECTORY, - GRPC_GOOGLE_WELL_KNOWN_CREDENTIALS_FILE); - gpr_free(appdata_path); - return result; -} - -#endif /* GPR_WIN32 */ diff --git a/src/core/security/google_default_credentials.c b/src/core/security/google_default_credentials.c deleted file mode 100644 index 3872e86993..0000000000 --- a/src/core/security/google_default_credentials.c +++ /dev/null @@ -1,266 +0,0 @@ -/* - * - * Copyright 2015-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/security/credentials.h" - -#include - -#include -#include -#include - -#include "src/core/http/httpcli.h" -#include "src/core/http/parser.h" -#include "src/core/support/env.h" -#include "src/core/support/load_file.h" -#include "src/core/surface/api_trace.h" - -/* -- Constants. -- */ - -#define GRPC_COMPUTE_ENGINE_DETECTION_HOST "metadata.google.internal" - -/* -- Default credentials. -- */ - -static grpc_channel_credentials *default_credentials = NULL; -static int compute_engine_detection_done = 0; -static gpr_mu g_state_mu; -static gpr_mu *g_polling_mu; -static gpr_once g_once = GPR_ONCE_INIT; - -static void init_default_credentials(void) { gpr_mu_init(&g_state_mu); } - -typedef struct { - grpc_pollset *pollset; - int is_done; - int success; -} compute_engine_detector; - -static void on_compute_engine_detection_http_response( - grpc_exec_ctx *exec_ctx, void *user_data, - const grpc_http_response *response) { - compute_engine_detector *detector = (compute_engine_detector *)user_data; - if (response != NULL && response->status == 200 && response->hdr_count > 0) { - /* Internet providers can return a generic response to all requests, so - it is necessary to check that metadata header is present also. */ - size_t i; - for (i = 0; i < response->hdr_count; i++) { - grpc_http_header *header = &response->hdrs[i]; - if (strcmp(header->key, "Metadata-Flavor") == 0 && - strcmp(header->value, "Google") == 0) { - detector->success = 1; - break; - } - } - } - gpr_mu_lock(g_polling_mu); - detector->is_done = 1; - grpc_pollset_kick(detector->pollset, NULL); - gpr_mu_unlock(g_polling_mu); -} - -static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p, bool s) { - grpc_pollset_destroy(p); -} - -static int is_stack_running_on_compute_engine(void) { - compute_engine_detector detector; - grpc_httpcli_request request; - grpc_httpcli_context context; - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_closure destroy_closure; - - /* The http call is local. If it takes more than one sec, it is for sure not - on compute engine. */ - gpr_timespec max_detection_delay = gpr_time_from_seconds(1, GPR_TIMESPAN); - - detector.pollset = gpr_malloc(grpc_pollset_size()); - grpc_pollset_init(detector.pollset, &g_polling_mu); - detector.is_done = 0; - detector.success = 0; - - memset(&request, 0, sizeof(grpc_httpcli_request)); - request.host = GRPC_COMPUTE_ENGINE_DETECTION_HOST; - request.http.path = "/"; - - grpc_httpcli_context_init(&context); - - grpc_httpcli_get( - &exec_ctx, &context, detector.pollset, &request, - gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), max_detection_delay), - on_compute_engine_detection_http_response, &detector); - - grpc_exec_ctx_finish(&exec_ctx); - - /* Block until we get the response. This is not ideal but this should only be - called once for the lifetime of the process by the default credentials. */ - gpr_mu_lock(g_polling_mu); - while (!detector.is_done) { - grpc_pollset_worker *worker = NULL; - grpc_pollset_work(&exec_ctx, detector.pollset, &worker, - gpr_now(GPR_CLOCK_MONOTONIC), - gpr_inf_future(GPR_CLOCK_MONOTONIC)); - } - gpr_mu_unlock(g_polling_mu); - - grpc_httpcli_context_destroy(&context); - grpc_closure_init(&destroy_closure, destroy_pollset, detector.pollset); - grpc_pollset_shutdown(&exec_ctx, detector.pollset, &destroy_closure); - grpc_exec_ctx_finish(&exec_ctx); - g_polling_mu = NULL; - - gpr_free(detector.pollset); - - return detector.success; -} - -/* Takes ownership of creds_path if not NULL. */ -static grpc_call_credentials *create_default_creds_from_path(char *creds_path) { - grpc_json *json = NULL; - grpc_auth_json_key key; - grpc_auth_refresh_token token; - grpc_call_credentials *result = NULL; - gpr_slice creds_data = gpr_empty_slice(); - int file_ok = 0; - if (creds_path == NULL) goto end; - creds_data = gpr_load_file(creds_path, 0, &file_ok); - if (!file_ok) goto end; - json = grpc_json_parse_string_with_len( - (char *)GPR_SLICE_START_PTR(creds_data), GPR_SLICE_LENGTH(creds_data)); - if (json == NULL) goto end; - - /* First, try an auth json key. */ - key = grpc_auth_json_key_create_from_json(json); - if (grpc_auth_json_key_is_valid(&key)) { - result = - grpc_service_account_jwt_access_credentials_create_from_auth_json_key( - key, grpc_max_auth_token_lifetime()); - goto end; - } - - /* Then try a refresh token if the auth json key was invalid. */ - token = grpc_auth_refresh_token_create_from_json(json); - if (grpc_auth_refresh_token_is_valid(&token)) { - result = - grpc_refresh_token_credentials_create_from_auth_refresh_token(token); - goto end; - } - -end: - if (creds_path != NULL) gpr_free(creds_path); - gpr_slice_unref(creds_data); - if (json != NULL) grpc_json_destroy(json); - return result; -} - -grpc_channel_credentials *grpc_google_default_credentials_create(void) { - grpc_channel_credentials *result = NULL; - grpc_call_credentials *call_creds = NULL; - - GRPC_API_TRACE("grpc_google_default_credentials_create(void)", 0, ()); - - gpr_once_init(&g_once, init_default_credentials); - - gpr_mu_lock(&g_state_mu); - - if (default_credentials != NULL) { - result = grpc_channel_credentials_ref(default_credentials); - goto end; - } - - /* First, try the environment variable. */ - call_creds = create_default_creds_from_path( - gpr_getenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR)); - if (call_creds != NULL) goto end; - - /* Then the well-known file. */ - call_creds = create_default_creds_from_path( - grpc_get_well_known_google_credentials_file_path()); - if (call_creds != NULL) goto end; - - /* At last try to see if we're on compute engine (do the detection only once - since it requires a network test). */ - if (!compute_engine_detection_done) { - int need_compute_engine_creds = is_stack_running_on_compute_engine(); - compute_engine_detection_done = 1; - if (need_compute_engine_creds) { - call_creds = grpc_google_compute_engine_credentials_create(NULL); - } - } - -end: - if (result == NULL) { - if (call_creds != NULL) { - /* Blend with default ssl credentials and add a global reference so that - it - can be cached and re-served. */ - grpc_channel_credentials *ssl_creds = - grpc_ssl_credentials_create(NULL, NULL, NULL); - default_credentials = grpc_channel_credentials_ref( - grpc_composite_channel_credentials_create(ssl_creds, call_creds, - NULL)); - GPR_ASSERT(default_credentials != NULL); - grpc_channel_credentials_unref(ssl_creds); - grpc_call_credentials_unref(call_creds); - result = default_credentials; - } else { - gpr_log(GPR_ERROR, "Could not create google default credentials."); - } - } - gpr_mu_unlock(&g_state_mu); - return result; -} - -void grpc_flush_cached_google_default_credentials(void) { - gpr_once_init(&g_once, init_default_credentials); - gpr_mu_lock(&g_state_mu); - if (default_credentials != NULL) { - grpc_channel_credentials_unref(default_credentials); - default_credentials = NULL; - } - compute_engine_detection_done = 0; - gpr_mu_unlock(&g_state_mu); -} - -/* -- Well known credentials path. -- */ - -static grpc_well_known_credentials_path_getter creds_path_getter = NULL; - -char *grpc_get_well_known_google_credentials_file_path(void) { - if (creds_path_getter != NULL) return creds_path_getter(); - return grpc_get_well_known_google_credentials_file_path_impl(); -} - -void grpc_override_well_known_credentials_path_getter( - grpc_well_known_credentials_path_getter getter) { - creds_path_getter = getter; -} diff --git a/src/core/security/handshake.c b/src/core/security/handshake.c deleted file mode 100644 index 9fb10a0ecb..0000000000 --- a/src/core/security/handshake.c +++ /dev/null @@ -1,336 +0,0 @@ -/* - * - * Copyright 2015-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/security/handshake.h" - -#include -#include - -#include -#include -#include -#include "src/core/security/secure_endpoint.h" -#include "src/core/security/security_context.h" - -#define GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE 256 - -typedef struct { - grpc_security_connector *connector; - tsi_handshaker *handshaker; - bool is_client_side; - unsigned char *handshake_buffer; - size_t handshake_buffer_size; - grpc_endpoint *wrapped_endpoint; - grpc_endpoint *secure_endpoint; - gpr_slice_buffer left_overs; - gpr_slice_buffer incoming; - gpr_slice_buffer outgoing; - grpc_security_handshake_done_cb cb; - void *user_data; - grpc_closure on_handshake_data_sent_to_peer; - grpc_closure on_handshake_data_received_from_peer; - grpc_auth_context *auth_context; -} grpc_security_handshake; - -static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx, - void *setup, bool success); - -static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx, void *setup, - bool success); - -static void security_connector_remove_handshake(grpc_security_handshake *h) { - GPR_ASSERT(!h->is_client_side); - grpc_security_connector_handshake_list *node; - grpc_security_connector_handshake_list *tmp; - grpc_server_security_connector *sc = - (grpc_server_security_connector *)h->connector; - gpr_mu_lock(&sc->mu); - node = sc->handshaking_handshakes; - if (node && node->handshake == h) { - sc->handshaking_handshakes = node->next; - gpr_free(node); - gpr_mu_unlock(&sc->mu); - return; - } - while (node) { - if (node->next->handshake == h) { - tmp = node->next; - node->next = node->next->next; - gpr_free(tmp); - gpr_mu_unlock(&sc->mu); - return; - } - node = node->next; - } - gpr_mu_unlock(&sc->mu); -} - -static void security_handshake_done(grpc_exec_ctx *exec_ctx, - grpc_security_handshake *h, - int is_success) { - if (!h->is_client_side) { - security_connector_remove_handshake(h); - } - if (is_success) { - h->cb(exec_ctx, h->user_data, GRPC_SECURITY_OK, h->secure_endpoint, - h->auth_context); - } else { - if (h->secure_endpoint != NULL) { - grpc_endpoint_shutdown(exec_ctx, h->secure_endpoint); - grpc_endpoint_destroy(exec_ctx, h->secure_endpoint); - } else { - grpc_endpoint_destroy(exec_ctx, h->wrapped_endpoint); - } - h->cb(exec_ctx, h->user_data, GRPC_SECURITY_ERROR, NULL, NULL); - } - if (h->handshaker != NULL) tsi_handshaker_destroy(h->handshaker); - if (h->handshake_buffer != NULL) gpr_free(h->handshake_buffer); - gpr_slice_buffer_destroy(&h->left_overs); - gpr_slice_buffer_destroy(&h->outgoing); - gpr_slice_buffer_destroy(&h->incoming); - GRPC_AUTH_CONTEXT_UNREF(h->auth_context, "handshake"); - GRPC_SECURITY_CONNECTOR_UNREF(h->connector, "handshake"); - gpr_free(h); -} - -static void on_peer_checked(grpc_exec_ctx *exec_ctx, void *user_data, - grpc_security_status status, - grpc_auth_context *auth_context) { - grpc_security_handshake *h = user_data; - tsi_frame_protector *protector; - tsi_result result; - if (status != GRPC_SECURITY_OK) { - gpr_log(GPR_ERROR, "Error checking peer."); - security_handshake_done(exec_ctx, h, 0); - return; - } - h->auth_context = GRPC_AUTH_CONTEXT_REF(auth_context, "handshake"); - result = - tsi_handshaker_create_frame_protector(h->handshaker, NULL, &protector); - if (result != TSI_OK) { - gpr_log(GPR_ERROR, "Frame protector creation failed with error %s.", - tsi_result_to_string(result)); - security_handshake_done(exec_ctx, h, 0); - return; - } - h->secure_endpoint = - grpc_secure_endpoint_create(protector, h->wrapped_endpoint, - h->left_overs.slices, h->left_overs.count); - h->left_overs.count = 0; - h->left_overs.length = 0; - security_handshake_done(exec_ctx, h, 1); - return; -} - -static void check_peer(grpc_exec_ctx *exec_ctx, grpc_security_handshake *h) { - tsi_peer peer; - tsi_result result = tsi_handshaker_extract_peer(h->handshaker, &peer); - - if (result != TSI_OK) { - gpr_log(GPR_ERROR, "Peer extraction failed with error %s", - tsi_result_to_string(result)); - security_handshake_done(exec_ctx, h, 0); - return; - } - grpc_security_connector_check_peer(exec_ctx, h->connector, peer, - on_peer_checked, h); -} - -static void send_handshake_bytes_to_peer(grpc_exec_ctx *exec_ctx, - grpc_security_handshake *h) { - size_t offset = 0; - tsi_result result = TSI_OK; - gpr_slice to_send; - - do { - size_t to_send_size = h->handshake_buffer_size - offset; - result = tsi_handshaker_get_bytes_to_send_to_peer( - h->handshaker, h->handshake_buffer + offset, &to_send_size); - offset += to_send_size; - if (result == TSI_INCOMPLETE_DATA) { - h->handshake_buffer_size *= 2; - h->handshake_buffer = - gpr_realloc(h->handshake_buffer, h->handshake_buffer_size); - } - } while (result == TSI_INCOMPLETE_DATA); - - if (result != TSI_OK) { - gpr_log(GPR_ERROR, "Handshake failed with error %s", - tsi_result_to_string(result)); - security_handshake_done(exec_ctx, h, 0); - return; - } - - to_send = - gpr_slice_from_copied_buffer((const char *)h->handshake_buffer, offset); - gpr_slice_buffer_reset_and_unref(&h->outgoing); - gpr_slice_buffer_add(&h->outgoing, to_send); - /* TODO(klempner,jboeuf): This should probably use the client setup - deadline */ - grpc_endpoint_write(exec_ctx, h->wrapped_endpoint, &h->outgoing, - &h->on_handshake_data_sent_to_peer); -} - -static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx, - void *handshake, - bool success) { - grpc_security_handshake *h = handshake; - size_t consumed_slice_size = 0; - tsi_result result = TSI_OK; - size_t i; - size_t num_left_overs; - int has_left_overs_in_current_slice = 0; - - if (!success) { - gpr_log(GPR_ERROR, "Read failed."); - security_handshake_done(exec_ctx, h, 0); - return; - } - - for (i = 0; i < h->incoming.count; i++) { - consumed_slice_size = GPR_SLICE_LENGTH(h->incoming.slices[i]); - result = tsi_handshaker_process_bytes_from_peer( - h->handshaker, GPR_SLICE_START_PTR(h->incoming.slices[i]), - &consumed_slice_size); - if (!tsi_handshaker_is_in_progress(h->handshaker)) break; - } - - if (tsi_handshaker_is_in_progress(h->handshaker)) { - /* We may need more data. */ - if (result == TSI_INCOMPLETE_DATA) { - grpc_endpoint_read(exec_ctx, h->wrapped_endpoint, &h->incoming, - &h->on_handshake_data_received_from_peer); - return; - } else { - send_handshake_bytes_to_peer(exec_ctx, h); - return; - } - } - - if (result != TSI_OK) { - gpr_log(GPR_ERROR, "Handshake failed with error %s", - tsi_result_to_string(result)); - security_handshake_done(exec_ctx, h, 0); - return; - } - - /* Handshake is done and successful this point. */ - has_left_overs_in_current_slice = - (consumed_slice_size < GPR_SLICE_LENGTH(h->incoming.slices[i])); - num_left_overs = - (has_left_overs_in_current_slice ? 1 : 0) + h->incoming.count - i - 1; - if (num_left_overs == 0) { - check_peer(exec_ctx, h); - return; - } - - /* Put the leftovers in our buffer (ownership transfered). */ - if (has_left_overs_in_current_slice) { - gpr_slice_buffer_add( - &h->left_overs, - gpr_slice_split_tail(&h->incoming.slices[i], consumed_slice_size)); - gpr_slice_unref( - h->incoming.slices[i]); /* split_tail above increments refcount. */ - } - gpr_slice_buffer_addn( - &h->left_overs, &h->incoming.slices[i + 1], - num_left_overs - (size_t)has_left_overs_in_current_slice); - check_peer(exec_ctx, h); -} - -/* If handshake is NULL, the handshake is done. */ -static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx, - void *handshake, bool success) { - grpc_security_handshake *h = handshake; - - /* Make sure that write is OK. */ - if (!success) { - gpr_log(GPR_ERROR, "Write failed."); - if (handshake != NULL) security_handshake_done(exec_ctx, h, 0); - return; - } - - /* We may be done. */ - if (tsi_handshaker_is_in_progress(h->handshaker)) { - /* TODO(klempner,jboeuf): This should probably use the client setup - deadline */ - grpc_endpoint_read(exec_ctx, h->wrapped_endpoint, &h->incoming, - &h->on_handshake_data_received_from_peer); - } else { - check_peer(exec_ctx, h); - } -} - -void grpc_do_security_handshake(grpc_exec_ctx *exec_ctx, - tsi_handshaker *handshaker, - grpc_security_connector *connector, - bool is_client_side, - grpc_endpoint *nonsecure_endpoint, - grpc_security_handshake_done_cb cb, - void *user_data) { - grpc_security_connector_handshake_list *handshake_node; - grpc_security_handshake *h = gpr_malloc(sizeof(grpc_security_handshake)); - memset(h, 0, sizeof(grpc_security_handshake)); - h->handshaker = handshaker; - h->connector = GRPC_SECURITY_CONNECTOR_REF(connector, "handshake"); - h->is_client_side = is_client_side; - h->handshake_buffer_size = GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE; - h->handshake_buffer = gpr_malloc(h->handshake_buffer_size); - h->wrapped_endpoint = nonsecure_endpoint; - h->user_data = user_data; - h->cb = cb; - grpc_closure_init(&h->on_handshake_data_sent_to_peer, - on_handshake_data_sent_to_peer, h); - grpc_closure_init(&h->on_handshake_data_received_from_peer, - on_handshake_data_received_from_peer, h); - gpr_slice_buffer_init(&h->left_overs); - gpr_slice_buffer_init(&h->outgoing); - gpr_slice_buffer_init(&h->incoming); - if (!is_client_side) { - grpc_server_security_connector *server_connector = - (grpc_server_security_connector *)connector; - handshake_node = gpr_malloc(sizeof(grpc_security_connector_handshake_list)); - handshake_node->handshake = h; - gpr_mu_lock(&server_connector->mu); - handshake_node->next = server_connector->handshaking_handshakes; - server_connector->handshaking_handshakes = handshake_node; - gpr_mu_unlock(&server_connector->mu); - } - send_handshake_bytes_to_peer(exec_ctx, h); -} - -void grpc_security_handshake_shutdown(grpc_exec_ctx *exec_ctx, - void *handshake) { - grpc_security_handshake *h = handshake; - grpc_endpoint_shutdown(exec_ctx, h->wrapped_endpoint); -} diff --git a/src/core/security/handshake.h b/src/core/security/handshake.h deleted file mode 100644 index 4872045874..0000000000 --- a/src/core/security/handshake.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * - * Copyright 2015-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_SECURITY_HANDSHAKE_H -#define GRPC_CORE_SECURITY_HANDSHAKE_H - -#include "src/core/iomgr/endpoint.h" -#include "src/core/security/security_connector.h" - -/* Calls the callback upon completion. Takes owership of handshaker. */ -void grpc_do_security_handshake(grpc_exec_ctx *exec_ctx, - tsi_handshaker *handshaker, - grpc_security_connector *connector, - bool is_client_side, - grpc_endpoint *nonsecure_endpoint, - grpc_security_handshake_done_cb cb, - void *user_data); - -void grpc_security_handshake_shutdown(grpc_exec_ctx *exec_ctx, void *handshake); - -#endif /* GRPC_CORE_SECURITY_HANDSHAKE_H */ diff --git a/src/core/security/json_token.c b/src/core/security/json_token.c deleted file mode 100644 index 372e5bfc5a..0000000000 --- a/src/core/security/json_token.c +++ /dev/null @@ -1,411 +0,0 @@ -/* - * - * Copyright 2015-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/security/json_token.h" - -#include - -#include -#include -#include - -#include "src/core/security/b64.h" -#include "src/core/support/string.h" - -#include -#include -#include - -/* --- Constants. --- */ - -/* 1 hour max. */ -gpr_timespec grpc_max_auth_token_lifetime() { - gpr_timespec out; - out.tv_sec = 3600; - out.tv_nsec = 0; - out.clock_type = GPR_TIMESPAN; - return out; -} - -#define GRPC_JWT_RSA_SHA256_ALGORITHM "RS256" -#define GRPC_JWT_TYPE "JWT" - -/* --- Override for testing. --- */ - -static grpc_jwt_encode_and_sign_override g_jwt_encode_and_sign_override = NULL; - -/* --- grpc_auth_json_key. --- */ - -static const char *json_get_string_property(const grpc_json *json, - const char *prop_name) { - grpc_json *child; - for (child = json->child; child != NULL; child = child->next) { - if (strcmp(child->key, prop_name) == 0) break; - } - if (child == NULL || child->type != GRPC_JSON_STRING) { - gpr_log(GPR_ERROR, "Invalid or missing %s property.", prop_name); - return NULL; - } - return child->value; -} - -static int set_json_key_string_property(const grpc_json *json, - const char *prop_name, - char **json_key_field) { - const char *prop_value = json_get_string_property(json, prop_name); - if (prop_value == NULL) return 0; - *json_key_field = gpr_strdup(prop_value); - return 1; -} - -int grpc_auth_json_key_is_valid(const grpc_auth_json_key *json_key) { - return (json_key != NULL) && - strcmp(json_key->type, GRPC_AUTH_JSON_TYPE_INVALID); -} - -grpc_auth_json_key grpc_auth_json_key_create_from_json(const grpc_json *json) { - grpc_auth_json_key result; - BIO *bio = NULL; - const char *prop_value; - int success = 0; - - memset(&result, 0, sizeof(grpc_auth_json_key)); - result.type = GRPC_AUTH_JSON_TYPE_INVALID; - if (json == NULL) { - gpr_log(GPR_ERROR, "Invalid json."); - goto end; - } - - prop_value = json_get_string_property(json, "type"); - if (prop_value == NULL || - strcmp(prop_value, GRPC_AUTH_JSON_TYPE_SERVICE_ACCOUNT)) { - goto end; - } - result.type = GRPC_AUTH_JSON_TYPE_SERVICE_ACCOUNT; - - if (!set_json_key_string_property(json, "private_key_id", - &result.private_key_id) || - !set_json_key_string_property(json, "client_id", &result.client_id) || - !set_json_key_string_property(json, "client_email", - &result.client_email)) { - goto end; - } - - prop_value = json_get_string_property(json, "private_key"); - if (prop_value == NULL) { - goto end; - } - bio = BIO_new(BIO_s_mem()); - success = BIO_puts(bio, prop_value); - if ((success < 0) || ((size_t)success != strlen(prop_value))) { - gpr_log(GPR_ERROR, "Could not write into openssl BIO."); - goto end; - } - result.private_key = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, ""); - if (result.private_key == NULL) { - gpr_log(GPR_ERROR, "Could not deserialize private key."); - goto end; - } - success = 1; - -end: - if (bio != NULL) BIO_free(bio); - if (!success) grpc_auth_json_key_destruct(&result); - return result; -} - -grpc_auth_json_key grpc_auth_json_key_create_from_string( - const char *json_string) { - char *scratchpad = gpr_strdup(json_string); - grpc_json *json = grpc_json_parse_string(scratchpad); - grpc_auth_json_key result = grpc_auth_json_key_create_from_json(json); - if (json != NULL) grpc_json_destroy(json); - gpr_free(scratchpad); - return result; -} - -void grpc_auth_json_key_destruct(grpc_auth_json_key *json_key) { - if (json_key == NULL) return; - json_key->type = GRPC_AUTH_JSON_TYPE_INVALID; - if (json_key->client_id != NULL) { - gpr_free(json_key->client_id); - json_key->client_id = NULL; - } - if (json_key->private_key_id != NULL) { - gpr_free(json_key->private_key_id); - json_key->private_key_id = NULL; - } - if (json_key->client_email != NULL) { - gpr_free(json_key->client_email); - json_key->client_email = NULL; - } - if (json_key->private_key != NULL) { - RSA_free(json_key->private_key); - json_key->private_key = NULL; - } -} - -/* --- jwt encoding and signature. --- */ - -static grpc_json *create_child(grpc_json *brother, grpc_json *parent, - const char *key, const char *value, - grpc_json_type type) { - grpc_json *child = grpc_json_create(type); - if (brother) brother->next = child; - if (!parent->child) parent->child = child; - child->parent = parent; - child->value = value; - child->key = key; - return child; -} - -static char *encoded_jwt_header(const char *key_id, const char *algorithm) { - grpc_json *json = grpc_json_create(GRPC_JSON_OBJECT); - grpc_json *child = NULL; - char *json_str = NULL; - char *result = NULL; - - child = create_child(NULL, json, "alg", algorithm, GRPC_JSON_STRING); - child = create_child(child, json, "typ", GRPC_JWT_TYPE, GRPC_JSON_STRING); - create_child(child, json, "kid", key_id, GRPC_JSON_STRING); - - json_str = grpc_json_dump_to_string(json, 0); - result = grpc_base64_encode(json_str, strlen(json_str), 1, 0); - gpr_free(json_str); - grpc_json_destroy(json); - return result; -} - -static char *encoded_jwt_claim(const grpc_auth_json_key *json_key, - const char *audience, - gpr_timespec token_lifetime, const char *scope) { - grpc_json *json = grpc_json_create(GRPC_JSON_OBJECT); - grpc_json *child = NULL; - char *json_str = NULL; - char *result = NULL; - gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME); - gpr_timespec expiration = gpr_time_add(now, token_lifetime); - char now_str[GPR_LTOA_MIN_BUFSIZE]; - char expiration_str[GPR_LTOA_MIN_BUFSIZE]; - if (gpr_time_cmp(token_lifetime, grpc_max_auth_token_lifetime()) > 0) { - gpr_log(GPR_INFO, "Cropping token lifetime to maximum allowed value."); - expiration = gpr_time_add(now, grpc_max_auth_token_lifetime()); - } - int64_ttoa(now.tv_sec, now_str); - int64_ttoa(expiration.tv_sec, expiration_str); - - child = - create_child(NULL, json, "iss", json_key->client_email, GRPC_JSON_STRING); - if (scope != NULL) { - child = create_child(child, json, "scope", scope, GRPC_JSON_STRING); - } else { - /* Unscoped JWTs need a sub field. */ - child = create_child(child, json, "sub", json_key->client_email, - GRPC_JSON_STRING); - } - - child = create_child(child, json, "aud", audience, GRPC_JSON_STRING); - child = create_child(child, json, "iat", now_str, GRPC_JSON_NUMBER); - create_child(child, json, "exp", expiration_str, GRPC_JSON_NUMBER); - - json_str = grpc_json_dump_to_string(json, 0); - result = grpc_base64_encode(json_str, strlen(json_str), 1, 0); - gpr_free(json_str); - grpc_json_destroy(json); - return result; -} - -static char *dot_concat_and_free_strings(char *str1, char *str2) { - size_t str1_len = strlen(str1); - size_t str2_len = strlen(str2); - size_t result_len = str1_len + 1 /* dot */ + str2_len; - char *result = gpr_malloc(result_len + 1 /* NULL terminated */); - char *current = result; - memcpy(current, str1, str1_len); - current += str1_len; - *(current++) = '.'; - memcpy(current, str2, str2_len); - current += str2_len; - GPR_ASSERT(current >= result); - GPR_ASSERT((uintptr_t)(current - result) == result_len); - *current = '\0'; - gpr_free(str1); - gpr_free(str2); - return result; -} - -const EVP_MD *openssl_digest_from_algorithm(const char *algorithm) { - if (strcmp(algorithm, GRPC_JWT_RSA_SHA256_ALGORITHM) == 0) { - return EVP_sha256(); - } else { - gpr_log(GPR_ERROR, "Unknown algorithm %s.", algorithm); - return NULL; - } -} - -char *compute_and_encode_signature(const grpc_auth_json_key *json_key, - const char *signature_algorithm, - const char *to_sign) { - const EVP_MD *md = openssl_digest_from_algorithm(signature_algorithm); - EVP_MD_CTX *md_ctx = NULL; - EVP_PKEY *key = EVP_PKEY_new(); - size_t sig_len = 0; - unsigned char *sig = NULL; - char *result = NULL; - if (md == NULL) return NULL; - md_ctx = EVP_MD_CTX_create(); - if (md_ctx == NULL) { - gpr_log(GPR_ERROR, "Could not create MD_CTX"); - goto end; - } - EVP_PKEY_set1_RSA(key, json_key->private_key); - if (EVP_DigestSignInit(md_ctx, NULL, md, NULL, key) != 1) { - gpr_log(GPR_ERROR, "DigestInit failed."); - goto end; - } - if (EVP_DigestSignUpdate(md_ctx, to_sign, strlen(to_sign)) != 1) { - gpr_log(GPR_ERROR, "DigestUpdate failed."); - goto end; - } - if (EVP_DigestSignFinal(md_ctx, NULL, &sig_len) != 1) { - gpr_log(GPR_ERROR, "DigestFinal (get signature length) failed."); - goto end; - } - sig = gpr_malloc(sig_len); - if (EVP_DigestSignFinal(md_ctx, sig, &sig_len) != 1) { - gpr_log(GPR_ERROR, "DigestFinal (signature compute) failed."); - goto end; - } - result = grpc_base64_encode(sig, sig_len, 1, 0); - -end: - if (key != NULL) EVP_PKEY_free(key); - if (md_ctx != NULL) EVP_MD_CTX_destroy(md_ctx); - if (sig != NULL) gpr_free(sig); - return result; -} - -char *grpc_jwt_encode_and_sign(const grpc_auth_json_key *json_key, - const char *audience, - gpr_timespec token_lifetime, const char *scope) { - if (g_jwt_encode_and_sign_override != NULL) { - return g_jwt_encode_and_sign_override(json_key, audience, token_lifetime, - scope); - } else { - const char *sig_algo = GRPC_JWT_RSA_SHA256_ALGORITHM; - char *to_sign = dot_concat_and_free_strings( - encoded_jwt_header(json_key->private_key_id, sig_algo), - encoded_jwt_claim(json_key, audience, token_lifetime, scope)); - char *sig = compute_and_encode_signature(json_key, sig_algo, to_sign); - if (sig == NULL) { - gpr_free(to_sign); - return NULL; - } - return dot_concat_and_free_strings(to_sign, sig); - } -} - -void grpc_jwt_encode_and_sign_set_override( - grpc_jwt_encode_and_sign_override func) { - g_jwt_encode_and_sign_override = func; -} - -/* --- grpc_auth_refresh_token --- */ - -int grpc_auth_refresh_token_is_valid( - const grpc_auth_refresh_token *refresh_token) { - return (refresh_token != NULL) && - strcmp(refresh_token->type, GRPC_AUTH_JSON_TYPE_INVALID); -} - -grpc_auth_refresh_token grpc_auth_refresh_token_create_from_json( - const grpc_json *json) { - grpc_auth_refresh_token result; - const char *prop_value; - int success = 0; - - memset(&result, 0, sizeof(grpc_auth_refresh_token)); - result.type = GRPC_AUTH_JSON_TYPE_INVALID; - if (json == NULL) { - gpr_log(GPR_ERROR, "Invalid json."); - goto end; - } - - prop_value = json_get_string_property(json, "type"); - if (prop_value == NULL || - strcmp(prop_value, GRPC_AUTH_JSON_TYPE_AUTHORIZED_USER)) { - goto end; - } - result.type = GRPC_AUTH_JSON_TYPE_AUTHORIZED_USER; - - if (!set_json_key_string_property(json, "client_secret", - &result.client_secret) || - !set_json_key_string_property(json, "client_id", &result.client_id) || - !set_json_key_string_property(json, "refresh_token", - &result.refresh_token)) { - goto end; - } - success = 1; - -end: - if (!success) grpc_auth_refresh_token_destruct(&result); - return result; -} - -grpc_auth_refresh_token grpc_auth_refresh_token_create_from_string( - const char *json_string) { - char *scratchpad = gpr_strdup(json_string); - grpc_json *json = grpc_json_parse_string(scratchpad); - grpc_auth_refresh_token result = - grpc_auth_refresh_token_create_from_json(json); - if (json != NULL) grpc_json_destroy(json); - gpr_free(scratchpad); - return result; -} - -void grpc_auth_refresh_token_destruct(grpc_auth_refresh_token *refresh_token) { - if (refresh_token == NULL) return; - refresh_token->type = GRPC_AUTH_JSON_TYPE_INVALID; - if (refresh_token->client_id != NULL) { - gpr_free(refresh_token->client_id); - refresh_token->client_id = NULL; - } - if (refresh_token->client_secret != NULL) { - gpr_free(refresh_token->client_secret); - refresh_token->client_secret = NULL; - } - if (refresh_token->refresh_token != NULL) { - gpr_free(refresh_token->refresh_token); - refresh_token->refresh_token = NULL; - } -} diff --git a/src/core/security/json_token.h b/src/core/security/json_token.h deleted file mode 100644 index d183f9b3a3..0000000000 --- a/src/core/security/json_token.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * - * Copyright 2015-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_SECURITY_JSON_TOKEN_H -#define GRPC_CORE_SECURITY_JSON_TOKEN_H - -#include -#include - -#include "src/core/json/json.h" - -/* --- Constants. --- */ - -#define GRPC_JWT_OAUTH2_AUDIENCE "https://www.googleapis.com/oauth2/v3/token" - -#define GRPC_AUTH_JSON_TYPE_INVALID "invalid" -#define GRPC_AUTH_JSON_TYPE_SERVICE_ACCOUNT "service_account" -#define GRPC_AUTH_JSON_TYPE_AUTHORIZED_USER "authorized_user" - -/* --- auth_json_key parsing. --- */ - -typedef struct { - const char *type; - char *private_key_id; - char *client_id; - char *client_email; - RSA *private_key; -} grpc_auth_json_key; - -/* Returns 1 if the object is valid, 0 otherwise. */ -int grpc_auth_json_key_is_valid(const grpc_auth_json_key *json_key); - -/* Creates a json_key object from string. Returns an invalid object if a parsing - error has been encountered. */ -grpc_auth_json_key grpc_auth_json_key_create_from_string( - const char *json_string); - -/* Creates a json_key object from parsed json. Returns an invalid object if a - parsing error has been encountered. */ -grpc_auth_json_key grpc_auth_json_key_create_from_json(const grpc_json *json); - -/* Destructs the object. */ -void grpc_auth_json_key_destruct(grpc_auth_json_key *json_key); - -/* --- json token encoding and signing. --- */ - -/* Caller is responsible for calling gpr_free on the returned value. May return - NULL on invalid input. The scope parameter may be NULL. */ -char *grpc_jwt_encode_and_sign(const grpc_auth_json_key *json_key, - const char *audience, - gpr_timespec token_lifetime, const char *scope); - -/* Override encode_and_sign function for testing. */ -typedef char *(*grpc_jwt_encode_and_sign_override)( - const grpc_auth_json_key *json_key, const char *audience, - gpr_timespec token_lifetime, const char *scope); - -/* Set a custom encode_and_sign override for testing. */ -void grpc_jwt_encode_and_sign_set_override( - grpc_jwt_encode_and_sign_override func); - -/* --- auth_refresh_token parsing. --- */ - -typedef struct { - const char *type; - char *client_id; - char *client_secret; - char *refresh_token; -} grpc_auth_refresh_token; - -/* Returns 1 if the object is valid, 0 otherwise. */ -int grpc_auth_refresh_token_is_valid( - const grpc_auth_refresh_token *refresh_token); - -/* Creates a refresh token object from string. Returns an invalid object if a - parsing error has been encountered. */ -grpc_auth_refresh_token grpc_auth_refresh_token_create_from_string( - const char *json_string); - -/* Creates a refresh token object from parsed json. Returns an invalid object if - a parsing error has been encountered. */ -grpc_auth_refresh_token grpc_auth_refresh_token_create_from_json( - const grpc_json *json); - -/* Destructs the object. */ -void grpc_auth_refresh_token_destruct(grpc_auth_refresh_token *refresh_token); - -#endif /* GRPC_CORE_SECURITY_JSON_TOKEN_H */ diff --git a/src/core/security/jwt_verifier.c b/src/core/security/jwt_verifier.c deleted file mode 100644 index 0bb8e05306..0000000000 --- a/src/core/security/jwt_verifier.c +++ /dev/null @@ -1,843 +0,0 @@ -/* - * - * Copyright 2015-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/security/jwt_verifier.h" - -#include -#include - -#include "src/core/http/httpcli.h" -#include "src/core/security/b64.h" -#include "src/core/tsi/ssl_types.h" - -#include -#include -#include -#include -#include - -/* --- Utils. --- */ - -const char *grpc_jwt_verifier_status_to_string( - grpc_jwt_verifier_status status) { - switch (status) { - case GRPC_JWT_VERIFIER_OK: - return "OK"; - case GRPC_JWT_VERIFIER_BAD_SIGNATURE: - return "BAD_SIGNATURE"; - case GRPC_JWT_VERIFIER_BAD_FORMAT: - return "BAD_FORMAT"; - case GRPC_JWT_VERIFIER_BAD_AUDIENCE: - return "BAD_AUDIENCE"; - case GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR: - return "KEY_RETRIEVAL_ERROR"; - case GRPC_JWT_VERIFIER_TIME_CONSTRAINT_FAILURE: - return "TIME_CONSTRAINT_FAILURE"; - case GRPC_JWT_VERIFIER_GENERIC_ERROR: - return "GENERIC_ERROR"; - default: - return "UNKNOWN"; - } -} - -static const EVP_MD *evp_md_from_alg(const char *alg) { - if (strcmp(alg, "RS256") == 0) { - return EVP_sha256(); - } else if (strcmp(alg, "RS384") == 0) { - return EVP_sha384(); - } else if (strcmp(alg, "RS512") == 0) { - return EVP_sha512(); - } else { - return NULL; - } -} - -static grpc_json *parse_json_part_from_jwt(const char *str, size_t len, - gpr_slice *buffer) { - grpc_json *json; - - *buffer = grpc_base64_decode_with_len(str, len, 1); - if (GPR_SLICE_IS_EMPTY(*buffer)) { - gpr_log(GPR_ERROR, "Invalid base64."); - return NULL; - } - json = grpc_json_parse_string_with_len((char *)GPR_SLICE_START_PTR(*buffer), - GPR_SLICE_LENGTH(*buffer)); - if (json == NULL) { - gpr_slice_unref(*buffer); - gpr_log(GPR_ERROR, "JSON parsing error."); - } - return json; -} - -static const char *validate_string_field(const grpc_json *json, - const char *key) { - if (json->type != GRPC_JSON_STRING) { - gpr_log(GPR_ERROR, "Invalid %s field [%s]", key, json->value); - return NULL; - } - return json->value; -} - -static gpr_timespec validate_time_field(const grpc_json *json, - const char *key) { - gpr_timespec result = gpr_time_0(GPR_CLOCK_REALTIME); - if (json->type != GRPC_JSON_NUMBER) { - gpr_log(GPR_ERROR, "Invalid %s field [%s]", key, json->value); - return result; - } - result.tv_sec = strtol(json->value, NULL, 10); - return result; -} - -/* --- JOSE header. see http://tools.ietf.org/html/rfc7515#section-4 --- */ - -typedef struct { - const char *alg; - const char *kid; - const char *typ; - /* TODO(jboeuf): Add others as needed (jku, jwk, x5u, x5c and so on...). */ - gpr_slice buffer; -} jose_header; - -static void jose_header_destroy(jose_header *h) { - gpr_slice_unref(h->buffer); - gpr_free(h); -} - -/* Takes ownership of json and buffer. */ -static jose_header *jose_header_from_json(grpc_json *json, gpr_slice buffer) { - grpc_json *cur; - jose_header *h = gpr_malloc(sizeof(jose_header)); - memset(h, 0, sizeof(jose_header)); - h->buffer = buffer; - for (cur = json->child; cur != NULL; cur = cur->next) { - if (strcmp(cur->key, "alg") == 0) { - /* We only support RSA-1.5 signatures for now. - Beware of this if we add HMAC support: - https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/ - */ - if (cur->type != GRPC_JSON_STRING || strncmp(cur->value, "RS", 2) || - evp_md_from_alg(cur->value) == NULL) { - gpr_log(GPR_ERROR, "Invalid alg field [%s]", cur->value); - goto error; - } - h->alg = cur->value; - } else if (strcmp(cur->key, "typ") == 0) { - h->typ = validate_string_field(cur, "typ"); - if (h->typ == NULL) goto error; - } else if (strcmp(cur->key, "kid") == 0) { - h->kid = validate_string_field(cur, "kid"); - if (h->kid == NULL) goto error; - } - } - if (h->alg == NULL) { - gpr_log(GPR_ERROR, "Missing alg field."); - goto error; - } - grpc_json_destroy(json); - h->buffer = buffer; - return h; - -error: - grpc_json_destroy(json); - jose_header_destroy(h); - return NULL; -} - -/* --- JWT claims. see http://tools.ietf.org/html/rfc7519#section-4.1 */ - -struct grpc_jwt_claims { - /* Well known properties already parsed. */ - const char *sub; - const char *iss; - const char *aud; - const char *jti; - gpr_timespec iat; - gpr_timespec exp; - gpr_timespec nbf; - - grpc_json *json; - gpr_slice buffer; -}; - -void grpc_jwt_claims_destroy(grpc_jwt_claims *claims) { - grpc_json_destroy(claims->json); - gpr_slice_unref(claims->buffer); - gpr_free(claims); -} - -const grpc_json *grpc_jwt_claims_json(const grpc_jwt_claims *claims) { - if (claims == NULL) return NULL; - return claims->json; -} - -const char *grpc_jwt_claims_subject(const grpc_jwt_claims *claims) { - if (claims == NULL) return NULL; - return claims->sub; -} - -const char *grpc_jwt_claims_issuer(const grpc_jwt_claims *claims) { - if (claims == NULL) return NULL; - return claims->iss; -} - -const char *grpc_jwt_claims_id(const grpc_jwt_claims *claims) { - if (claims == NULL) return NULL; - return claims->jti; -} - -const char *grpc_jwt_claims_audience(const grpc_jwt_claims *claims) { - if (claims == NULL) return NULL; - return claims->aud; -} - -gpr_timespec grpc_jwt_claims_issued_at(const grpc_jwt_claims *claims) { - if (claims == NULL) return gpr_inf_past(GPR_CLOCK_REALTIME); - return claims->iat; -} - -gpr_timespec grpc_jwt_claims_expires_at(const grpc_jwt_claims *claims) { - if (claims == NULL) return gpr_inf_future(GPR_CLOCK_REALTIME); - return claims->exp; -} - -gpr_timespec grpc_jwt_claims_not_before(const grpc_jwt_claims *claims) { - if (claims == NULL) return gpr_inf_past(GPR_CLOCK_REALTIME); - return claims->nbf; -} - -/* Takes ownership of json and buffer even in case of failure. */ -grpc_jwt_claims *grpc_jwt_claims_from_json(grpc_json *json, gpr_slice buffer) { - grpc_json *cur; - grpc_jwt_claims *claims = gpr_malloc(sizeof(grpc_jwt_claims)); - memset(claims, 0, sizeof(grpc_jwt_claims)); - claims->json = json; - claims->buffer = buffer; - claims->iat = gpr_inf_past(GPR_CLOCK_REALTIME); - claims->nbf = gpr_inf_past(GPR_CLOCK_REALTIME); - claims->exp = gpr_inf_future(GPR_CLOCK_REALTIME); - - /* Per the spec, all fields are optional. */ - for (cur = json->child; cur != NULL; cur = cur->next) { - if (strcmp(cur->key, "sub") == 0) { - claims->sub = validate_string_field(cur, "sub"); - if (claims->sub == NULL) goto error; - } else if (strcmp(cur->key, "iss") == 0) { - claims->iss = validate_string_field(cur, "iss"); - if (claims->iss == NULL) goto error; - } else if (strcmp(cur->key, "aud") == 0) { - claims->aud = validate_string_field(cur, "aud"); - if (claims->aud == NULL) goto error; - } else if (strcmp(cur->key, "jti") == 0) { - claims->jti = validate_string_field(cur, "jti"); - if (claims->jti == NULL) goto error; - } else if (strcmp(cur->key, "iat") == 0) { - claims->iat = validate_time_field(cur, "iat"); - if (gpr_time_cmp(claims->iat, gpr_time_0(GPR_CLOCK_REALTIME)) == 0) - goto error; - } else if (strcmp(cur->key, "exp") == 0) { - claims->exp = validate_time_field(cur, "exp"); - if (gpr_time_cmp(claims->exp, gpr_time_0(GPR_CLOCK_REALTIME)) == 0) - goto error; - } else if (strcmp(cur->key, "nbf") == 0) { - claims->nbf = validate_time_field(cur, "nbf"); - if (gpr_time_cmp(claims->nbf, gpr_time_0(GPR_CLOCK_REALTIME)) == 0) - goto error; - } - } - return claims; - -error: - grpc_jwt_claims_destroy(claims); - return NULL; -} - -grpc_jwt_verifier_status grpc_jwt_claims_check(const grpc_jwt_claims *claims, - const char *audience) { - gpr_timespec skewed_now; - int audience_ok; - - GPR_ASSERT(claims != NULL); - - skewed_now = - gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), grpc_jwt_verifier_clock_skew); - if (gpr_time_cmp(skewed_now, claims->nbf) < 0) { - gpr_log(GPR_ERROR, "JWT is not valid yet."); - return GRPC_JWT_VERIFIER_TIME_CONSTRAINT_FAILURE; - } - skewed_now = - gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), grpc_jwt_verifier_clock_skew); - if (gpr_time_cmp(skewed_now, claims->exp) > 0) { - gpr_log(GPR_ERROR, "JWT is expired."); - return GRPC_JWT_VERIFIER_TIME_CONSTRAINT_FAILURE; - } - - if (audience == NULL) { - audience_ok = claims->aud == NULL; - } else { - audience_ok = claims->aud != NULL && strcmp(audience, claims->aud) == 0; - } - if (!audience_ok) { - gpr_log(GPR_ERROR, "Audience mismatch: expected %s and found %s.", - audience == NULL ? "NULL" : audience, - claims->aud == NULL ? "NULL" : claims->aud); - return GRPC_JWT_VERIFIER_BAD_AUDIENCE; - } - return GRPC_JWT_VERIFIER_OK; -} - -/* --- verifier_cb_ctx object. --- */ - -typedef struct { - grpc_jwt_verifier *verifier; - grpc_pollset *pollset; - jose_header *header; - grpc_jwt_claims *claims; - char *audience; - gpr_slice signature; - gpr_slice signed_data; - void *user_data; - grpc_jwt_verification_done_cb user_cb; -} verifier_cb_ctx; - -/* Takes ownership of the header, claims and signature. */ -static verifier_cb_ctx *verifier_cb_ctx_create( - grpc_jwt_verifier *verifier, grpc_pollset *pollset, jose_header *header, - grpc_jwt_claims *claims, const char *audience, gpr_slice signature, - const char *signed_jwt, size_t signed_jwt_len, void *user_data, - grpc_jwt_verification_done_cb cb) { - verifier_cb_ctx *ctx = gpr_malloc(sizeof(verifier_cb_ctx)); - memset(ctx, 0, sizeof(verifier_cb_ctx)); - ctx->verifier = verifier; - ctx->pollset = pollset; - ctx->header = header; - ctx->audience = gpr_strdup(audience); - ctx->claims = claims; - ctx->signature = signature; - ctx->signed_data = gpr_slice_from_copied_buffer(signed_jwt, signed_jwt_len); - ctx->user_data = user_data; - ctx->user_cb = cb; - return ctx; -} - -void verifier_cb_ctx_destroy(verifier_cb_ctx *ctx) { - if (ctx->audience != NULL) gpr_free(ctx->audience); - if (ctx->claims != NULL) grpc_jwt_claims_destroy(ctx->claims); - gpr_slice_unref(ctx->signature); - gpr_slice_unref(ctx->signed_data); - jose_header_destroy(ctx->header); - /* TODO: see what to do with claims... */ - gpr_free(ctx); -} - -/* --- grpc_jwt_verifier object. --- */ - -/* Clock skew defaults to one minute. */ -gpr_timespec grpc_jwt_verifier_clock_skew = {60, 0, GPR_TIMESPAN}; - -/* Max delay defaults to one minute. */ -gpr_timespec grpc_jwt_verifier_max_delay = {60, 0, GPR_TIMESPAN}; - -typedef struct { - char *email_domain; - char *key_url_prefix; -} email_key_mapping; - -struct grpc_jwt_verifier { - email_key_mapping *mappings; - size_t num_mappings; /* Should be very few, linear search ok. */ - size_t allocated_mappings; - grpc_httpcli_context http_ctx; -}; - -static grpc_json *json_from_http(const grpc_httpcli_response *response) { - grpc_json *json = NULL; - - if (response == NULL) { - gpr_log(GPR_ERROR, "HTTP response is NULL."); - return NULL; - } - if (response->status != 200) { - gpr_log(GPR_ERROR, "Call to http server failed with error %d.", - response->status); - return NULL; - } - - json = grpc_json_parse_string_with_len(response->body, response->body_length); - if (json == NULL) { - gpr_log(GPR_ERROR, "Invalid JSON found in response."); - } - return json; -} - -static const grpc_json *find_property_by_name(const grpc_json *json, - const char *name) { - const grpc_json *cur; - for (cur = json->child; cur != NULL; cur = cur->next) { - if (strcmp(cur->key, name) == 0) return cur; - } - return NULL; -} - -static EVP_PKEY *extract_pkey_from_x509(const char *x509_str) { - X509 *x509 = NULL; - EVP_PKEY *result = NULL; - BIO *bio = BIO_new(BIO_s_mem()); - size_t len = strlen(x509_str); - GPR_ASSERT(len < INT_MAX); - BIO_write(bio, x509_str, (int)len); - x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); - if (x509 == NULL) { - gpr_log(GPR_ERROR, "Unable to parse x509 cert."); - goto end; - } - result = X509_get_pubkey(x509); - if (result == NULL) { - gpr_log(GPR_ERROR, "Cannot find public key in X509 cert."); - } - -end: - BIO_free(bio); - if (x509 != NULL) X509_free(x509); - return result; -} - -static BIGNUM *bignum_from_base64(const char *b64) { - BIGNUM *result = NULL; - gpr_slice bin; - - if (b64 == NULL) return NULL; - bin = grpc_base64_decode(b64, 1); - if (GPR_SLICE_IS_EMPTY(bin)) { - gpr_log(GPR_ERROR, "Invalid base64 for big num."); - return NULL; - } - result = BN_bin2bn(GPR_SLICE_START_PTR(bin), - TSI_SIZE_AS_SIZE(GPR_SLICE_LENGTH(bin)), NULL); - gpr_slice_unref(bin); - return result; -} - -static EVP_PKEY *pkey_from_jwk(const grpc_json *json, const char *kty) { - const grpc_json *key_prop; - RSA *rsa = NULL; - EVP_PKEY *result = NULL; - - GPR_ASSERT(kty != NULL && json != NULL); - if (strcmp(kty, "RSA") != 0) { - gpr_log(GPR_ERROR, "Unsupported key type %s.", kty); - goto end; - } - rsa = RSA_new(); - if (rsa == NULL) { - gpr_log(GPR_ERROR, "Could not create rsa key."); - goto end; - } - for (key_prop = json->child; key_prop != NULL; key_prop = key_prop->next) { - if (strcmp(key_prop->key, "n") == 0) { - rsa->n = bignum_from_base64(validate_string_field(key_prop, "n")); - if (rsa->n == NULL) goto end; - } else if (strcmp(key_prop->key, "e") == 0) { - rsa->e = bignum_from_base64(validate_string_field(key_prop, "e")); - if (rsa->e == NULL) goto end; - } - } - if (rsa->e == NULL || rsa->n == NULL) { - gpr_log(GPR_ERROR, "Missing RSA public key field."); - goto end; - } - result = EVP_PKEY_new(); - EVP_PKEY_set1_RSA(result, rsa); /* uprefs rsa. */ - -end: - if (rsa != NULL) RSA_free(rsa); - return result; -} - -static EVP_PKEY *find_verification_key(const grpc_json *json, - const char *header_alg, - const char *header_kid) { - const grpc_json *jkey; - const grpc_json *jwk_keys; - /* Try to parse the json as a JWK set: - https://tools.ietf.org/html/rfc7517#section-5. */ - jwk_keys = find_property_by_name(json, "keys"); - if (jwk_keys == NULL) { - /* Use the google proprietary format which is: - { : , : , ... } */ - const grpc_json *cur = find_property_by_name(json, header_kid); - if (cur == NULL) return NULL; - return extract_pkey_from_x509(cur->value); - } - - if (jwk_keys->type != GRPC_JSON_ARRAY) { - gpr_log(GPR_ERROR, - "Unexpected value type of keys property in jwks key set."); - return NULL; - } - /* Key format is specified in: - https://tools.ietf.org/html/rfc7518#section-6. */ - for (jkey = jwk_keys->child; jkey != NULL; jkey = jkey->next) { - grpc_json *key_prop; - const char *alg = NULL; - const char *kid = NULL; - const char *kty = NULL; - - if (jkey->type != GRPC_JSON_OBJECT) continue; - for (key_prop = jkey->child; key_prop != NULL; key_prop = key_prop->next) { - if (strcmp(key_prop->key, "alg") == 0 && - key_prop->type == GRPC_JSON_STRING) { - alg = key_prop->value; - } else if (strcmp(key_prop->key, "kid") == 0 && - key_prop->type == GRPC_JSON_STRING) { - kid = key_prop->value; - } else if (strcmp(key_prop->key, "kty") == 0 && - key_prop->type == GRPC_JSON_STRING) { - kty = key_prop->value; - } - } - if (alg != NULL && kid != NULL && kty != NULL && - strcmp(kid, header_kid) == 0 && strcmp(alg, header_alg) == 0) { - return pkey_from_jwk(jkey, kty); - } - } - gpr_log(GPR_ERROR, - "Could not find matching key in key set for kid=%s and alg=%s", - header_kid, header_alg); - return NULL; -} - -static int verify_jwt_signature(EVP_PKEY *key, const char *alg, - gpr_slice signature, gpr_slice signed_data) { - EVP_MD_CTX *md_ctx = EVP_MD_CTX_create(); - const EVP_MD *md = evp_md_from_alg(alg); - int result = 0; - - GPR_ASSERT(md != NULL); /* Checked before. */ - if (md_ctx == NULL) { - gpr_log(GPR_ERROR, "Could not create EVP_MD_CTX."); - goto end; - } - if (EVP_DigestVerifyInit(md_ctx, NULL, md, NULL, key) != 1) { - gpr_log(GPR_ERROR, "EVP_DigestVerifyInit failed."); - goto end; - } - if (EVP_DigestVerifyUpdate(md_ctx, GPR_SLICE_START_PTR(signed_data), - GPR_SLICE_LENGTH(signed_data)) != 1) { - gpr_log(GPR_ERROR, "EVP_DigestVerifyUpdate failed."); - goto end; - } - if (EVP_DigestVerifyFinal(md_ctx, GPR_SLICE_START_PTR(signature), - GPR_SLICE_LENGTH(signature)) != 1) { - gpr_log(GPR_ERROR, "JWT signature verification failed."); - goto end; - } - result = 1; - -end: - if (md_ctx != NULL) EVP_MD_CTX_destroy(md_ctx); - return result; -} - -static void on_keys_retrieved(grpc_exec_ctx *exec_ctx, void *user_data, - const grpc_httpcli_response *response) { - grpc_json *json = json_from_http(response); - verifier_cb_ctx *ctx = (verifier_cb_ctx *)user_data; - EVP_PKEY *verification_key = NULL; - grpc_jwt_verifier_status status = GRPC_JWT_VERIFIER_GENERIC_ERROR; - grpc_jwt_claims *claims = NULL; - - if (json == NULL) { - status = GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR; - goto end; - } - verification_key = - find_verification_key(json, ctx->header->alg, ctx->header->kid); - if (verification_key == NULL) { - gpr_log(GPR_ERROR, "Could not find verification key with kid %s.", - ctx->header->kid); - status = GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR; - goto end; - } - - if (!verify_jwt_signature(verification_key, ctx->header->alg, ctx->signature, - ctx->signed_data)) { - status = GRPC_JWT_VERIFIER_BAD_SIGNATURE; - goto end; - } - - status = grpc_jwt_claims_check(ctx->claims, ctx->audience); - if (status == GRPC_JWT_VERIFIER_OK) { - /* Pass ownership. */ - claims = ctx->claims; - ctx->claims = NULL; - } - -end: - if (json != NULL) grpc_json_destroy(json); - if (verification_key != NULL) EVP_PKEY_free(verification_key); - ctx->user_cb(ctx->user_data, status, claims); - verifier_cb_ctx_destroy(ctx); -} - -static void on_openid_config_retrieved(grpc_exec_ctx *exec_ctx, void *user_data, - const grpc_httpcli_response *response) { - const grpc_json *cur; - grpc_json *json = json_from_http(response); - verifier_cb_ctx *ctx = (verifier_cb_ctx *)user_data; - grpc_httpcli_request req; - const char *jwks_uri; - - /* TODO(jboeuf): Cache the jwks_uri in order to avoid this hop next time. */ - if (json == NULL) goto error; - cur = find_property_by_name(json, "jwks_uri"); - if (cur == NULL) { - gpr_log(GPR_ERROR, "Could not find jwks_uri in openid config."); - goto error; - } - jwks_uri = validate_string_field(cur, "jwks_uri"); - if (jwks_uri == NULL) goto error; - if (strstr(jwks_uri, "https://") != jwks_uri) { - gpr_log(GPR_ERROR, "Invalid non https jwks_uri: %s.", jwks_uri); - goto error; - } - jwks_uri += 8; - req.handshaker = &grpc_httpcli_ssl; - req.host = gpr_strdup(jwks_uri); - req.http.path = strchr(jwks_uri, '/'); - if (req.http.path == NULL) { - req.http.path = ""; - } else { - *(req.host + (req.http.path - jwks_uri)) = '\0'; - } - grpc_httpcli_get( - exec_ctx, &ctx->verifier->http_ctx, ctx->pollset, &req, - gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), grpc_jwt_verifier_max_delay), - on_keys_retrieved, ctx); - grpc_json_destroy(json); - gpr_free(req.host); - return; - -error: - if (json != NULL) grpc_json_destroy(json); - ctx->user_cb(ctx->user_data, GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR, NULL); - verifier_cb_ctx_destroy(ctx); -} - -static email_key_mapping *verifier_get_mapping(grpc_jwt_verifier *v, - const char *email_domain) { - size_t i; - if (v->mappings == NULL) return NULL; - for (i = 0; i < v->num_mappings; i++) { - if (strcmp(email_domain, v->mappings[i].email_domain) == 0) { - return &v->mappings[i]; - } - } - return NULL; -} - -static void verifier_put_mapping(grpc_jwt_verifier *v, const char *email_domain, - const char *key_url_prefix) { - email_key_mapping *mapping = verifier_get_mapping(v, email_domain); - GPR_ASSERT(v->num_mappings < v->allocated_mappings); - if (mapping != NULL) { - gpr_free(mapping->key_url_prefix); - mapping->key_url_prefix = gpr_strdup(key_url_prefix); - return; - } - v->mappings[v->num_mappings].email_domain = gpr_strdup(email_domain); - v->mappings[v->num_mappings].key_url_prefix = gpr_strdup(key_url_prefix); - v->num_mappings++; - GPR_ASSERT(v->num_mappings <= v->allocated_mappings); -} - -/* Takes ownership of ctx. */ -static void retrieve_key_and_verify(grpc_exec_ctx *exec_ctx, - verifier_cb_ctx *ctx) { - const char *at_sign; - grpc_httpcli_response_cb http_cb; - char *path_prefix = NULL; - const char *iss; - grpc_httpcli_request req; - memset(&req, 0, sizeof(grpc_httpcli_request)); - req.handshaker = &grpc_httpcli_ssl; - - GPR_ASSERT(ctx != NULL && ctx->header != NULL && ctx->claims != NULL); - iss = ctx->claims->iss; - if (ctx->header->kid == NULL) { - gpr_log(GPR_ERROR, "Missing kid in jose header."); - goto error; - } - if (iss == NULL) { - gpr_log(GPR_ERROR, "Missing iss in claims."); - goto error; - } - - /* This code relies on: - https://openid.net/specs/openid-connect-discovery-1_0.html - Nobody seems to implement the account/email/webfinger part 2. of the spec - so we will rely instead on email/url mappings if we detect such an issuer. - Part 4, on the other hand is implemented by both google and salesforce. */ - - /* Very non-sophisticated way to detect an email address. Should be good - enough for now... */ - at_sign = strchr(iss, '@'); - if (at_sign != NULL) { - email_key_mapping *mapping; - const char *email_domain = at_sign + 1; - GPR_ASSERT(ctx->verifier != NULL); - mapping = verifier_get_mapping(ctx->verifier, email_domain); - if (mapping == NULL) { - gpr_log(GPR_ERROR, "Missing mapping for issuer email."); - goto error; - } - req.host = gpr_strdup(mapping->key_url_prefix); - path_prefix = strchr(req.host, '/'); - if (path_prefix == NULL) { - gpr_asprintf(&req.http.path, "/%s", iss); - } else { - *(path_prefix++) = '\0'; - gpr_asprintf(&req.http.path, "/%s/%s", path_prefix, iss); - } - http_cb = on_keys_retrieved; - } else { - req.host = gpr_strdup(strstr(iss, "https://") == iss ? iss + 8 : iss); - path_prefix = strchr(req.host, '/'); - if (path_prefix == NULL) { - req.http.path = gpr_strdup(GRPC_OPENID_CONFIG_URL_SUFFIX); - } else { - *(path_prefix++) = 0; - gpr_asprintf(&req.http.path, "/%s%s", path_prefix, - GRPC_OPENID_CONFIG_URL_SUFFIX); - } - http_cb = on_openid_config_retrieved; - } - - grpc_httpcli_get( - exec_ctx, &ctx->verifier->http_ctx, ctx->pollset, &req, - gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), grpc_jwt_verifier_max_delay), - http_cb, ctx); - gpr_free(req.host); - gpr_free(req.http.path); - return; - -error: - ctx->user_cb(ctx->user_data, GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR, NULL); - verifier_cb_ctx_destroy(ctx); -} - -void grpc_jwt_verifier_verify(grpc_exec_ctx *exec_ctx, - grpc_jwt_verifier *verifier, - grpc_pollset *pollset, const char *jwt, - const char *audience, - grpc_jwt_verification_done_cb cb, - void *user_data) { - const char *dot = NULL; - grpc_json *json; - jose_header *header = NULL; - grpc_jwt_claims *claims = NULL; - gpr_slice header_buffer; - gpr_slice claims_buffer; - gpr_slice signature; - size_t signed_jwt_len; - const char *cur = jwt; - - GPR_ASSERT(verifier != NULL && jwt != NULL && audience != NULL && cb != NULL); - dot = strchr(cur, '.'); - if (dot == NULL) goto error; - json = parse_json_part_from_jwt(cur, (size_t)(dot - cur), &header_buffer); - if (json == NULL) goto error; - header = jose_header_from_json(json, header_buffer); - if (header == NULL) goto error; - - cur = dot + 1; - dot = strchr(cur, '.'); - if (dot == NULL) goto error; - json = parse_json_part_from_jwt(cur, (size_t)(dot - cur), &claims_buffer); - if (json == NULL) goto error; - claims = grpc_jwt_claims_from_json(json, claims_buffer); - if (claims == NULL) goto error; - - signed_jwt_len = (size_t)(dot - jwt); - cur = dot + 1; - signature = grpc_base64_decode(cur, 1); - if (GPR_SLICE_IS_EMPTY(signature)) goto error; - retrieve_key_and_verify( - exec_ctx, - verifier_cb_ctx_create(verifier, pollset, header, claims, audience, - signature, jwt, signed_jwt_len, user_data, cb)); - return; - -error: - if (header != NULL) jose_header_destroy(header); - if (claims != NULL) grpc_jwt_claims_destroy(claims); - cb(user_data, GRPC_JWT_VERIFIER_BAD_FORMAT, NULL); -} - -grpc_jwt_verifier *grpc_jwt_verifier_create( - const grpc_jwt_verifier_email_domain_key_url_mapping *mappings, - size_t num_mappings) { - grpc_jwt_verifier *v = gpr_malloc(sizeof(grpc_jwt_verifier)); - memset(v, 0, sizeof(grpc_jwt_verifier)); - grpc_httpcli_context_init(&v->http_ctx); - - /* We know at least of one mapping. */ - v->allocated_mappings = 1 + num_mappings; - v->mappings = gpr_malloc(v->allocated_mappings * sizeof(email_key_mapping)); - verifier_put_mapping(v, GRPC_GOOGLE_SERVICE_ACCOUNTS_EMAIL_DOMAIN, - GRPC_GOOGLE_SERVICE_ACCOUNTS_KEY_URL_PREFIX); - /* User-Provided mappings. */ - if (mappings != NULL) { - size_t i; - for (i = 0; i < num_mappings; i++) { - verifier_put_mapping(v, mappings[i].email_domain, - mappings[i].key_url_prefix); - } - } - return v; -} - -void grpc_jwt_verifier_destroy(grpc_jwt_verifier *v) { - size_t i; - if (v == NULL) return; - grpc_httpcli_context_destroy(&v->http_ctx); - if (v->mappings != NULL) { - for (i = 0; i < v->num_mappings; i++) { - gpr_free(v->mappings[i].email_domain); - gpr_free(v->mappings[i].key_url_prefix); - } - gpr_free(v->mappings); - } - gpr_free(v); -} diff --git a/src/core/security/jwt_verifier.h b/src/core/security/jwt_verifier.h deleted file mode 100644 index d898d2193f..0000000000 --- a/src/core/security/jwt_verifier.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * - * Copyright 2015-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_SECURITY_JWT_VERIFIER_H -#define GRPC_CORE_SECURITY_JWT_VERIFIER_H - -#include "src/core/iomgr/pollset.h" -#include "src/core/json/json.h" - -#include -#include - -/* --- Constants. --- */ - -#define GRPC_OPENID_CONFIG_URL_SUFFIX "/.well-known/openid-configuration" -#define GRPC_GOOGLE_SERVICE_ACCOUNTS_EMAIL_DOMAIN \ - "developer.gserviceaccount.com" -#define GRPC_GOOGLE_SERVICE_ACCOUNTS_KEY_URL_PREFIX \ - "www.googleapis.com/robot/v1/metadata/x509" - -/* --- grpc_jwt_verifier_status. --- */ - -typedef enum { - GRPC_JWT_VERIFIER_OK = 0, - GRPC_JWT_VERIFIER_BAD_SIGNATURE, - GRPC_JWT_VERIFIER_BAD_FORMAT, - GRPC_JWT_VERIFIER_BAD_AUDIENCE, - GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR, - GRPC_JWT_VERIFIER_TIME_CONSTRAINT_FAILURE, - GRPC_JWT_VERIFIER_GENERIC_ERROR -} grpc_jwt_verifier_status; - -const char *grpc_jwt_verifier_status_to_string(grpc_jwt_verifier_status status); - -/* --- grpc_jwt_claims. --- */ - -typedef struct grpc_jwt_claims grpc_jwt_claims; - -void grpc_jwt_claims_destroy(grpc_jwt_claims *claims); - -/* Returns the whole JSON tree of the claims. */ -const grpc_json *grpc_jwt_claims_json(const grpc_jwt_claims *claims); - -/* Access to registered claims in https://tools.ietf.org/html/rfc7519#page-9 */ -const char *grpc_jwt_claims_subject(const grpc_jwt_claims *claims); -const char *grpc_jwt_claims_issuer(const grpc_jwt_claims *claims); -const char *grpc_jwt_claims_id(const grpc_jwt_claims *claims); -const char *grpc_jwt_claims_audience(const grpc_jwt_claims *claims); -gpr_timespec grpc_jwt_claims_issued_at(const grpc_jwt_claims *claims); -gpr_timespec grpc_jwt_claims_expires_at(const grpc_jwt_claims *claims); -gpr_timespec grpc_jwt_claims_not_before(const grpc_jwt_claims *claims); - -/* --- grpc_jwt_verifier. --- */ - -typedef struct grpc_jwt_verifier grpc_jwt_verifier; - -typedef struct { - /* The email domain is the part after the @ sign. */ - const char *email_domain; - - /* The key url prefix will be used to get the public key from the issuer: - https:/// - Therefore the key_url_prefix must NOT contain https://. */ - const char *key_url_prefix; -} grpc_jwt_verifier_email_domain_key_url_mapping; - -/* Globals to control the verifier. Not thread-safe. */ -extern gpr_timespec grpc_jwt_verifier_clock_skew; -extern gpr_timespec grpc_jwt_verifier_max_delay; - -/* The verifier can be created with some custom mappings to help with key - discovery in the case where the issuer is an email address. - mappings can be NULL in which case num_mappings MUST be 0. - A verifier object has one built-in mapping (unless overridden): - GRPC_GOOGLE_SERVICE_ACCOUNTS_EMAIL_DOMAIN -> - GRPC_GOOGLE_SERVICE_ACCOUNTS_KEY_URL_PREFIX.*/ -grpc_jwt_verifier *grpc_jwt_verifier_create( - const grpc_jwt_verifier_email_domain_key_url_mapping *mappings, - size_t num_mappings); - -/*The verifier must not be destroyed if there are still outstanding callbacks.*/ -void grpc_jwt_verifier_destroy(grpc_jwt_verifier *verifier); - -/* User provided callback that will be called when the verification of the JWT - is done (maybe in another thread). - It is the responsibility of the callee to call grpc_jwt_claims_destroy on - the claims. */ -typedef void (*grpc_jwt_verification_done_cb)(void *user_data, - grpc_jwt_verifier_status status, - grpc_jwt_claims *claims); - -/* Verifies for the JWT for the given expected audience. */ -void grpc_jwt_verifier_verify(grpc_exec_ctx *exec_ctx, - grpc_jwt_verifier *verifier, - grpc_pollset *pollset, const char *jwt, - const char *audience, - grpc_jwt_verification_done_cb cb, - void *user_data); - -/* --- TESTING ONLY exposed functions. --- */ - -grpc_jwt_claims *grpc_jwt_claims_from_json(grpc_json *json, gpr_slice buffer); -grpc_jwt_verifier_status grpc_jwt_claims_check(const grpc_jwt_claims *claims, - const char *audience); - -#endif /* GRPC_CORE_SECURITY_JWT_VERIFIER_H */ diff --git a/src/core/security/secure_endpoint.c b/src/core/security/secure_endpoint.c deleted file mode 100644 index 58b081dc4a..0000000000 --- a/src/core/security/secure_endpoint.c +++ /dev/null @@ -1,384 +0,0 @@ -/* - * - * Copyright 2015-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/security/secure_endpoint.h" -#include -#include -#include -#include -#include -#include "src/core/debug/trace.h" -#include "src/core/support/string.h" -#include "src/core/tsi/transport_security_interface.h" - -#define STAGING_BUFFER_SIZE 8192 - -typedef struct { - grpc_endpoint base; - grpc_endpoint *wrapped_ep; - struct tsi_frame_protector *protector; - gpr_mu protector_mu; - /* saved upper level callbacks and user_data. */ - grpc_closure *read_cb; - grpc_closure *write_cb; - grpc_closure on_read; - gpr_slice_buffer *read_buffer; - gpr_slice_buffer source_buffer; - /* saved handshaker leftover data to unprotect. */ - gpr_slice_buffer leftover_bytes; - /* buffers for read and write */ - gpr_slice read_staging_buffer; - - gpr_slice write_staging_buffer; - gpr_slice_buffer output_buffer; - - gpr_refcount ref; -} secure_endpoint; - -int grpc_trace_secure_endpoint = 0; - -static void destroy(grpc_exec_ctx *exec_ctx, secure_endpoint *secure_ep) { - secure_endpoint *ep = secure_ep; - grpc_endpoint_destroy(exec_ctx, ep->wrapped_ep); - tsi_frame_protector_destroy(ep->protector); - gpr_slice_buffer_destroy(&ep->leftover_bytes); - gpr_slice_unref(ep->read_staging_buffer); - gpr_slice_unref(ep->write_staging_buffer); - gpr_slice_buffer_destroy(&ep->output_buffer); - gpr_slice_buffer_destroy(&ep->source_buffer); - gpr_mu_destroy(&ep->protector_mu); - gpr_free(ep); -} - -/*#define GRPC_SECURE_ENDPOINT_REFCOUNT_DEBUG*/ -#ifdef GRPC_SECURE_ENDPOINT_REFCOUNT_DEBUG -#define SECURE_ENDPOINT_UNREF(exec_ctx, ep, reason) \ - secure_endpoint_unref((exec_ctx), (ep), (reason), __FILE__, __LINE__) -#define SECURE_ENDPOINT_REF(ep, reason) \ - secure_endpoint_ref((ep), (reason), __FILE__, __LINE__) -static void secure_endpoint_unref(secure_endpoint *ep, - grpc_closure_list *closure_list, - const char *reason, const char *file, - int line) { - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "SECENDP unref %p : %s %d -> %d", - ep, reason, ep->ref.count, ep->ref.count - 1); - if (gpr_unref(&ep->ref)) { - destroy(exec_ctx, ep); - } -} - -static void secure_endpoint_ref(secure_endpoint *ep, const char *reason, - const char *file, int line) { - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "SECENDP ref %p : %s %d -> %d", - ep, reason, ep->ref.count, ep->ref.count + 1); - gpr_ref(&ep->ref); -} -#else -#define SECURE_ENDPOINT_UNREF(exec_ctx, ep, reason) \ - secure_endpoint_unref((exec_ctx), (ep)) -#define SECURE_ENDPOINT_REF(ep, reason) secure_endpoint_ref((ep)) -static void secure_endpoint_unref(grpc_exec_ctx *exec_ctx, - secure_endpoint *ep) { - if (gpr_unref(&ep->ref)) { - destroy(exec_ctx, ep); - } -} - -static void secure_endpoint_ref(secure_endpoint *ep) { gpr_ref(&ep->ref); } -#endif - -static void flush_read_staging_buffer(secure_endpoint *ep, uint8_t **cur, - uint8_t **end) { - gpr_slice_buffer_add(ep->read_buffer, ep->read_staging_buffer); - ep->read_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE); - *cur = GPR_SLICE_START_PTR(ep->read_staging_buffer); - *end = GPR_SLICE_END_PTR(ep->read_staging_buffer); -} - -static void call_read_cb(grpc_exec_ctx *exec_ctx, secure_endpoint *ep, - bool success) { - if (grpc_trace_secure_endpoint) { - size_t i; - for (i = 0; i < ep->read_buffer->count; i++) { - char *data = gpr_dump_slice(ep->read_buffer->slices[i], - GPR_DUMP_HEX | GPR_DUMP_ASCII); - gpr_log(GPR_DEBUG, "READ %p: %s", ep, data); - gpr_free(data); - } - } - ep->read_buffer = NULL; - grpc_exec_ctx_enqueue(exec_ctx, ep->read_cb, success, NULL); - SECURE_ENDPOINT_UNREF(exec_ctx, ep, "read"); -} - -static void on_read(grpc_exec_ctx *exec_ctx, void *user_data, bool success) { - unsigned i; - uint8_t keep_looping = 0; - tsi_result result = TSI_OK; - secure_endpoint *ep = (secure_endpoint *)user_data; - uint8_t *cur = GPR_SLICE_START_PTR(ep->read_staging_buffer); - uint8_t *end = GPR_SLICE_END_PTR(ep->read_staging_buffer); - - if (!success) { - gpr_slice_buffer_reset_and_unref(ep->read_buffer); - call_read_cb(exec_ctx, ep, 0); - return; - } - - /* TODO(yangg) check error, maybe bail out early */ - for (i = 0; i < ep->source_buffer.count; i++) { - gpr_slice encrypted = ep->source_buffer.slices[i]; - uint8_t *message_bytes = GPR_SLICE_START_PTR(encrypted); - size_t message_size = GPR_SLICE_LENGTH(encrypted); - - while (message_size > 0 || keep_looping) { - size_t unprotected_buffer_size_written = (size_t)(end - cur); - size_t processed_message_size = message_size; - gpr_mu_lock(&ep->protector_mu); - result = tsi_frame_protector_unprotect(ep->protector, message_bytes, - &processed_message_size, cur, - &unprotected_buffer_size_written); - gpr_mu_unlock(&ep->protector_mu); - if (result != TSI_OK) { - gpr_log(GPR_ERROR, "Decryption error: %s", - tsi_result_to_string(result)); - break; - } - message_bytes += processed_message_size; - message_size -= processed_message_size; - cur += unprotected_buffer_size_written; - - if (cur == end) { - flush_read_staging_buffer(ep, &cur, &end); - /* Force to enter the loop again to extract buffered bytes in protector. - The bytes could be buffered because of running out of staging_buffer. - If this happens at the end of all slices, doing another unprotect - avoids leaving data in the protector. */ - keep_looping = 1; - } else if (unprotected_buffer_size_written > 0) { - keep_looping = 1; - } else { - keep_looping = 0; - } - } - if (result != TSI_OK) break; - } - - if (cur != GPR_SLICE_START_PTR(ep->read_staging_buffer)) { - gpr_slice_buffer_add( - ep->read_buffer, - gpr_slice_split_head( - &ep->read_staging_buffer, - (size_t)(cur - GPR_SLICE_START_PTR(ep->read_staging_buffer)))); - } - - /* TODO(yangg) experiment with moving this block after read_cb to see if it - helps latency */ - gpr_slice_buffer_reset_and_unref(&ep->source_buffer); - - if (result != TSI_OK) { - gpr_slice_buffer_reset_and_unref(ep->read_buffer); - call_read_cb(exec_ctx, ep, 0); - return; - } - - call_read_cb(exec_ctx, ep, 1); -} - -static void endpoint_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep, - gpr_slice_buffer *slices, grpc_closure *cb) { - secure_endpoint *ep = (secure_endpoint *)secure_ep; - ep->read_cb = cb; - ep->read_buffer = slices; - gpr_slice_buffer_reset_and_unref(ep->read_buffer); - - SECURE_ENDPOINT_REF(ep, "read"); - if (ep->leftover_bytes.count) { - gpr_slice_buffer_swap(&ep->leftover_bytes, &ep->source_buffer); - GPR_ASSERT(ep->leftover_bytes.count == 0); - on_read(exec_ctx, ep, 1); - return; - } - - grpc_endpoint_read(exec_ctx, ep->wrapped_ep, &ep->source_buffer, - &ep->on_read); -} - -static void flush_write_staging_buffer(secure_endpoint *ep, uint8_t **cur, - uint8_t **end) { - gpr_slice_buffer_add(&ep->output_buffer, ep->write_staging_buffer); - ep->write_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE); - *cur = GPR_SLICE_START_PTR(ep->write_staging_buffer); - *end = GPR_SLICE_END_PTR(ep->write_staging_buffer); -} - -static void endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep, - gpr_slice_buffer *slices, grpc_closure *cb) { - unsigned i; - tsi_result result = TSI_OK; - secure_endpoint *ep = (secure_endpoint *)secure_ep; - uint8_t *cur = GPR_SLICE_START_PTR(ep->write_staging_buffer); - uint8_t *end = GPR_SLICE_END_PTR(ep->write_staging_buffer); - - gpr_slice_buffer_reset_and_unref(&ep->output_buffer); - - if (grpc_trace_secure_endpoint) { - for (i = 0; i < slices->count; i++) { - char *data = - gpr_dump_slice(slices->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII); - gpr_log(GPR_DEBUG, "WRITE %p: %s", ep, data); - gpr_free(data); - } - } - - for (i = 0; i < slices->count; i++) { - gpr_slice plain = slices->slices[i]; - uint8_t *message_bytes = GPR_SLICE_START_PTR(plain); - size_t message_size = GPR_SLICE_LENGTH(plain); - while (message_size > 0) { - size_t protected_buffer_size_to_send = (size_t)(end - cur); - size_t processed_message_size = message_size; - gpr_mu_lock(&ep->protector_mu); - result = tsi_frame_protector_protect(ep->protector, message_bytes, - &processed_message_size, cur, - &protected_buffer_size_to_send); - gpr_mu_unlock(&ep->protector_mu); - if (result != TSI_OK) { - gpr_log(GPR_ERROR, "Encryption error: %s", - tsi_result_to_string(result)); - break; - } - message_bytes += processed_message_size; - message_size -= processed_message_size; - cur += protected_buffer_size_to_send; - - if (cur == end) { - flush_write_staging_buffer(ep, &cur, &end); - } - } - if (result != TSI_OK) break; - } - if (result == TSI_OK) { - size_t still_pending_size; - do { - size_t protected_buffer_size_to_send = (size_t)(end - cur); - gpr_mu_lock(&ep->protector_mu); - result = tsi_frame_protector_protect_flush(ep->protector, cur, - &protected_buffer_size_to_send, - &still_pending_size); - gpr_mu_unlock(&ep->protector_mu); - if (result != TSI_OK) break; - cur += protected_buffer_size_to_send; - if (cur == end) { - flush_write_staging_buffer(ep, &cur, &end); - } - } while (still_pending_size > 0); - if (cur != GPR_SLICE_START_PTR(ep->write_staging_buffer)) { - gpr_slice_buffer_add( - &ep->output_buffer, - gpr_slice_split_head( - &ep->write_staging_buffer, - (size_t)(cur - GPR_SLICE_START_PTR(ep->write_staging_buffer)))); - } - } - - if (result != TSI_OK) { - /* TODO(yangg) do different things according to the error type? */ - gpr_slice_buffer_reset_and_unref(&ep->output_buffer); - grpc_exec_ctx_enqueue(exec_ctx, cb, false, NULL); - return; - } - - grpc_endpoint_write(exec_ctx, ep->wrapped_ep, &ep->output_buffer, cb); -} - -static void endpoint_shutdown(grpc_exec_ctx *exec_ctx, - grpc_endpoint *secure_ep) { - secure_endpoint *ep = (secure_endpoint *)secure_ep; - grpc_endpoint_shutdown(exec_ctx, ep->wrapped_ep); -} - -static void endpoint_destroy(grpc_exec_ctx *exec_ctx, - grpc_endpoint *secure_ep) { - secure_endpoint *ep = (secure_endpoint *)secure_ep; - SECURE_ENDPOINT_UNREF(exec_ctx, ep, "destroy"); -} - -static void endpoint_add_to_pollset(grpc_exec_ctx *exec_ctx, - grpc_endpoint *secure_ep, - grpc_pollset *pollset) { - secure_endpoint *ep = (secure_endpoint *)secure_ep; - grpc_endpoint_add_to_pollset(exec_ctx, ep->wrapped_ep, pollset); -} - -static void endpoint_add_to_pollset_set(grpc_exec_ctx *exec_ctx, - grpc_endpoint *secure_ep, - grpc_pollset_set *pollset_set) { - secure_endpoint *ep = (secure_endpoint *)secure_ep; - grpc_endpoint_add_to_pollset_set(exec_ctx, ep->wrapped_ep, pollset_set); -} - -static char *endpoint_get_peer(grpc_endpoint *secure_ep) { - secure_endpoint *ep = (secure_endpoint *)secure_ep; - return grpc_endpoint_get_peer(ep->wrapped_ep); -} - -static const grpc_endpoint_vtable vtable = { - endpoint_read, endpoint_write, - endpoint_add_to_pollset, endpoint_add_to_pollset_set, - endpoint_shutdown, endpoint_destroy, - endpoint_get_peer}; - -grpc_endpoint *grpc_secure_endpoint_create( - struct tsi_frame_protector *protector, grpc_endpoint *transport, - gpr_slice *leftover_slices, size_t leftover_nslices) { - size_t i; - secure_endpoint *ep = (secure_endpoint *)gpr_malloc(sizeof(secure_endpoint)); - ep->base.vtable = &vtable; - ep->wrapped_ep = transport; - ep->protector = protector; - gpr_slice_buffer_init(&ep->leftover_bytes); - for (i = 0; i < leftover_nslices; i++) { - gpr_slice_buffer_add(&ep->leftover_bytes, - gpr_slice_ref(leftover_slices[i])); - } - ep->write_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE); - ep->read_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE); - gpr_slice_buffer_init(&ep->output_buffer); - gpr_slice_buffer_init(&ep->source_buffer); - ep->read_buffer = NULL; - grpc_closure_init(&ep->on_read, on_read, ep); - gpr_mu_init(&ep->protector_mu); - gpr_ref_init(&ep->ref, 1); - return &ep->base; -} diff --git a/src/core/security/secure_endpoint.h b/src/core/security/secure_endpoint.h deleted file mode 100644 index 7368f8424b..0000000000 --- a/src/core/security/secure_endpoint.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * - * Copyright 2015-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_SECURITY_SECURE_ENDPOINT_H -#define GRPC_CORE_SECURITY_SECURE_ENDPOINT_H - -#include -#include "src/core/iomgr/endpoint.h" - -struct tsi_frame_protector; - -extern int grpc_trace_secure_endpoint; - -/* Takes ownership of protector and to_wrap, and refs leftover_slices. */ -grpc_endpoint *grpc_secure_endpoint_create( - struct tsi_frame_protector *protector, grpc_endpoint *to_wrap, - gpr_slice *leftover_slices, size_t leftover_nslices); - -#endif /* GRPC_CORE_SECURITY_SECURE_ENDPOINT_H */ diff --git a/src/core/security/security_connector.c b/src/core/security/security_connector.c deleted file mode 100644 index fbec263eed..0000000000 --- a/src/core/security/security_connector.c +++ /dev/null @@ -1,812 +0,0 @@ -/* - * - * Copyright 2015-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/security/security_connector.h" - -#include -#include - -#include -#include -#include -#include -#include - -#include "src/core/security/credentials.h" -#include "src/core/security/handshake.h" -#include "src/core/security/secure_endpoint.h" -#include "src/core/security/security_context.h" -#include "src/core/support/env.h" -#include "src/core/support/load_file.h" -#include "src/core/support/string.h" -#include "src/core/transport/chttp2/alpn.h" -#include "src/core/tsi/fake_transport_security.h" -#include "src/core/tsi/ssl_transport_security.h" - -/* -- Constants. -- */ - -#ifndef INSTALL_PREFIX -static const char *installed_roots_path = "/usr/share/grpc/roots.pem"; -#else -static const char *installed_roots_path = - INSTALL_PREFIX "/share/grpc/roots.pem"; -#endif - -/* -- Overridden default roots. -- */ - -static grpc_ssl_roots_override_callback ssl_roots_override_cb = NULL; - -void grpc_set_ssl_roots_override_callback(grpc_ssl_roots_override_callback cb) { - ssl_roots_override_cb = cb; -} - -/* -- Cipher suites. -- */ - -/* Defines the cipher suites that we accept by default. All these cipher suites - are compliant with HTTP2. */ -#define GRPC_SSL_CIPHER_SUITES \ - "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-" \ - "SHA384:ECDHE-RSA-AES256-GCM-SHA384" - -static gpr_once cipher_suites_once = GPR_ONCE_INIT; -static const char *cipher_suites = NULL; - -static void init_cipher_suites(void) { - char *overridden = gpr_getenv("GRPC_SSL_CIPHER_SUITES"); - cipher_suites = overridden != NULL ? overridden : GRPC_SSL_CIPHER_SUITES; -} - -static const char *ssl_cipher_suites(void) { - gpr_once_init(&cipher_suites_once, init_cipher_suites); - return cipher_suites; -} - -/* -- Common methods. -- */ - -/* Returns the first property with that name. */ -const tsi_peer_property *tsi_peer_get_property_by_name(const tsi_peer *peer, - const char *name) { - size_t i; - if (peer == NULL) return NULL; - for (i = 0; i < peer->property_count; i++) { - const tsi_peer_property *property = &peer->properties[i]; - if (name == NULL && property->name == NULL) { - return property; - } - if (name != NULL && property->name != NULL && - strcmp(property->name, name) == 0) { - return property; - } - } - return NULL; -} - -void grpc_server_security_connector_shutdown( - grpc_exec_ctx *exec_ctx, grpc_server_security_connector *connector) { - grpc_security_connector_handshake_list *tmp; - gpr_mu_lock(&connector->mu); - while (connector->handshaking_handshakes) { - tmp = connector->handshaking_handshakes; - grpc_security_handshake_shutdown( - exec_ctx, connector->handshaking_handshakes->handshake); - connector->handshaking_handshakes = tmp->next; - gpr_free(tmp); - } - gpr_mu_unlock(&connector->mu); -} - -void grpc_channel_security_connector_do_handshake( - grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc, - grpc_endpoint *nonsecure_endpoint, grpc_security_handshake_done_cb cb, - void *user_data) { - if (sc == NULL || nonsecure_endpoint == NULL) { - cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL); - } else { - sc->do_handshake(exec_ctx, sc, nonsecure_endpoint, cb, user_data); - } -} - -void grpc_server_security_connector_do_handshake( - grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc, - grpc_tcp_server_acceptor *acceptor, grpc_endpoint *nonsecure_endpoint, - grpc_security_handshake_done_cb cb, void *user_data) { - if (sc == NULL || nonsecure_endpoint == NULL) { - cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL); - } else { - sc->do_handshake(exec_ctx, sc, acceptor, nonsecure_endpoint, cb, user_data); - } -} - -void grpc_security_connector_check_peer(grpc_exec_ctx *exec_ctx, - grpc_security_connector *sc, - tsi_peer peer, - grpc_security_peer_check_cb cb, - void *user_data) { - if (sc == NULL) { - cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL); - tsi_peer_destruct(&peer); - } else { - sc->vtable->check_peer(exec_ctx, sc, peer, cb, user_data); - } -} - -void grpc_channel_security_connector_check_call_host( - grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc, - const char *host, grpc_auth_context *auth_context, - grpc_security_call_host_check_cb cb, void *user_data) { - if (sc == NULL || sc->check_call_host == NULL) { - cb(exec_ctx, user_data, GRPC_SECURITY_ERROR); - } else { - sc->check_call_host(exec_ctx, sc, host, auth_context, cb, user_data); - } -} - -#ifdef GRPC_SECURITY_CONNECTOR_REFCOUNT_DEBUG -grpc_security_connector *grpc_security_connector_ref( - grpc_security_connector *sc, const char *file, int line, - const char *reason) { - if (sc == NULL) return NULL; - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, - "SECURITY_CONNECTOR:%p ref %d -> %d %s", sc, - (int)sc->refcount.count, (int)sc->refcount.count + 1, reason); -#else -grpc_security_connector *grpc_security_connector_ref( - grpc_security_connector *sc) { - if (sc == NULL) return NULL; -#endif - gpr_ref(&sc->refcount); - return sc; -} - -#ifdef GRPC_SECURITY_CONNECTOR_REFCOUNT_DEBUG -void grpc_security_connector_unref(grpc_security_connector *sc, - const char *file, int line, - const char *reason) { - if (sc == NULL) return; - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, - "SECURITY_CONNECTOR:%p unref %d -> %d %s", sc, - (int)sc->refcount.count, (int)sc->refcount.count - 1, reason); -#else -void grpc_security_connector_unref(grpc_security_connector *sc) { - if (sc == NULL) return; -#endif - if (gpr_unref(&sc->refcount)) sc->vtable->destroy(sc); -} - -static void connector_pointer_arg_destroy(void *p) { - GRPC_SECURITY_CONNECTOR_UNREF(p, "connector_pointer_arg"); -} - -static void *connector_pointer_arg_copy(void *p) { - return GRPC_SECURITY_CONNECTOR_REF(p, "connector_pointer_arg"); -} - -static int connector_pointer_cmp(void *a, void *b) { return GPR_ICMP(a, b); } - -static const grpc_arg_pointer_vtable connector_pointer_vtable = { - connector_pointer_arg_copy, connector_pointer_arg_destroy, - connector_pointer_cmp}; - -grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc) { - grpc_arg result; - result.type = GRPC_ARG_POINTER; - result.key = GRPC_SECURITY_CONNECTOR_ARG; - result.value.pointer.vtable = &connector_pointer_vtable; - result.value.pointer.p = sc; - return result; -} - -grpc_security_connector *grpc_security_connector_from_arg(const grpc_arg *arg) { - if (strcmp(arg->key, GRPC_SECURITY_CONNECTOR_ARG)) return NULL; - if (arg->type != GRPC_ARG_POINTER) { - gpr_log(GPR_ERROR, "Invalid type %d for arg %s", arg->type, - GRPC_SECURITY_CONNECTOR_ARG); - return NULL; - } - return arg->value.pointer.p; -} - -grpc_security_connector *grpc_find_security_connector_in_args( - const grpc_channel_args *args) { - size_t i; - if (args == NULL) return NULL; - for (i = 0; i < args->num_args; i++) { - grpc_security_connector *sc = - grpc_security_connector_from_arg(&args->args[i]); - if (sc != NULL) return sc; - } - return NULL; -} - -/* -- Fake implementation. -- */ - -static void fake_channel_destroy(grpc_security_connector *sc) { - grpc_channel_security_connector *c = (grpc_channel_security_connector *)sc; - grpc_call_credentials_unref(c->request_metadata_creds); - gpr_free(sc); -} - -static void fake_server_destroy(grpc_security_connector *sc) { - grpc_server_security_connector *c = (grpc_server_security_connector *)sc; - gpr_mu_destroy(&c->mu); - gpr_free(sc); -} - -static void fake_check_peer(grpc_exec_ctx *exec_ctx, - grpc_security_connector *sc, tsi_peer peer, - grpc_security_peer_check_cb cb, void *user_data) { - const char *prop_name; - grpc_security_status status = GRPC_SECURITY_OK; - grpc_auth_context *auth_context = NULL; - if (peer.property_count != 1) { - gpr_log(GPR_ERROR, "Fake peers should only have 1 property."); - status = GRPC_SECURITY_ERROR; - goto end; - } - prop_name = peer.properties[0].name; - if (prop_name == NULL || - strcmp(prop_name, TSI_CERTIFICATE_TYPE_PEER_PROPERTY)) { - gpr_log(GPR_ERROR, "Unexpected property in fake peer: %s.", - prop_name == NULL ? "" : prop_name); - status = GRPC_SECURITY_ERROR; - goto end; - } - if (strncmp(peer.properties[0].value.data, TSI_FAKE_CERTIFICATE_TYPE, - peer.properties[0].value.length)) { - gpr_log(GPR_ERROR, "Invalid value for cert type property."); - status = GRPC_SECURITY_ERROR; - goto end; - } - auth_context = grpc_auth_context_create(NULL); - grpc_auth_context_add_cstring_property( - auth_context, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME, - GRPC_FAKE_TRANSPORT_SECURITY_TYPE); - -end: - cb(exec_ctx, user_data, status, auth_context); - grpc_auth_context_unref(auth_context); - tsi_peer_destruct(&peer); -} - -static void fake_channel_check_call_host(grpc_exec_ctx *exec_ctx, - grpc_channel_security_connector *sc, - const char *host, - grpc_auth_context *auth_context, - grpc_security_call_host_check_cb cb, - void *user_data) { - cb(exec_ctx, user_data, GRPC_SECURITY_OK); -} - -static void fake_channel_do_handshake(grpc_exec_ctx *exec_ctx, - grpc_channel_security_connector *sc, - grpc_endpoint *nonsecure_endpoint, - grpc_security_handshake_done_cb cb, - void *user_data) { - grpc_do_security_handshake(exec_ctx, tsi_create_fake_handshaker(1), &sc->base, - true, nonsecure_endpoint, cb, user_data); -} - -static void fake_server_do_handshake(grpc_exec_ctx *exec_ctx, - grpc_server_security_connector *sc, - grpc_tcp_server_acceptor *acceptor, - grpc_endpoint *nonsecure_endpoint, - grpc_security_handshake_done_cb cb, - void *user_data) { - grpc_do_security_handshake(exec_ctx, tsi_create_fake_handshaker(0), &sc->base, - false, nonsecure_endpoint, cb, user_data); -} - -static grpc_security_connector_vtable fake_channel_vtable = { - fake_channel_destroy, fake_check_peer}; - -static grpc_security_connector_vtable fake_server_vtable = {fake_server_destroy, - fake_check_peer}; - -grpc_channel_security_connector *grpc_fake_channel_security_connector_create( - grpc_call_credentials *request_metadata_creds) { - grpc_channel_security_connector *c = gpr_malloc(sizeof(*c)); - memset(c, 0, sizeof(*c)); - gpr_ref_init(&c->base.refcount, 1); - c->base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME; - c->base.vtable = &fake_channel_vtable; - c->request_metadata_creds = grpc_call_credentials_ref(request_metadata_creds); - c->check_call_host = fake_channel_check_call_host; - c->do_handshake = fake_channel_do_handshake; - return c; -} - -grpc_server_security_connector *grpc_fake_server_security_connector_create( - void) { - grpc_server_security_connector *c = - gpr_malloc(sizeof(grpc_server_security_connector)); - memset(c, 0, sizeof(*c)); - gpr_ref_init(&c->base.refcount, 1); - c->base.vtable = &fake_server_vtable; - c->base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME; - c->do_handshake = fake_server_do_handshake; - gpr_mu_init(&c->mu); - return c; -} - -/* --- Ssl implementation. --- */ - -typedef struct { - grpc_channel_security_connector base; - tsi_ssl_handshaker_factory *handshaker_factory; - char *target_name; - char *overridden_target_name; -} grpc_ssl_channel_security_connector; - -typedef struct { - grpc_server_security_connector base; - tsi_ssl_handshaker_factory *handshaker_factory; -} grpc_ssl_server_security_connector; - -static void ssl_channel_destroy(grpc_security_connector *sc) { - grpc_ssl_channel_security_connector *c = - (grpc_ssl_channel_security_connector *)sc; - grpc_call_credentials_unref(c->base.request_metadata_creds); - if (c->handshaker_factory != NULL) { - tsi_ssl_handshaker_factory_destroy(c->handshaker_factory); - } - if (c->target_name != NULL) gpr_free(c->target_name); - if (c->overridden_target_name != NULL) gpr_free(c->overridden_target_name); - gpr_free(sc); -} - -static void ssl_server_destroy(grpc_security_connector *sc) { - grpc_ssl_server_security_connector *c = - (grpc_ssl_server_security_connector *)sc; - - if (c->handshaker_factory != NULL) { - tsi_ssl_handshaker_factory_destroy(c->handshaker_factory); - } - gpr_mu_destroy(&c->base.mu); - gpr_free(sc); -} - -static grpc_security_status ssl_create_handshaker( - tsi_ssl_handshaker_factory *handshaker_factory, bool is_client, - const char *peer_name, tsi_handshaker **handshaker) { - tsi_result result = TSI_OK; - if (handshaker_factory == NULL) return GRPC_SECURITY_ERROR; - result = tsi_ssl_handshaker_factory_create_handshaker( - handshaker_factory, is_client ? peer_name : NULL, handshaker); - if (result != TSI_OK) { - gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.", - tsi_result_to_string(result)); - return GRPC_SECURITY_ERROR; - } - return GRPC_SECURITY_OK; -} - -static void ssl_channel_do_handshake(grpc_exec_ctx *exec_ctx, - grpc_channel_security_connector *sc, - grpc_endpoint *nonsecure_endpoint, - grpc_security_handshake_done_cb cb, - void *user_data) { - grpc_ssl_channel_security_connector *c = - (grpc_ssl_channel_security_connector *)sc; - tsi_handshaker *handshaker; - grpc_security_status status = ssl_create_handshaker( - c->handshaker_factory, true, - c->overridden_target_name != NULL ? c->overridden_target_name - : c->target_name, - &handshaker); - if (status != GRPC_SECURITY_OK) { - cb(exec_ctx, user_data, status, NULL, NULL); - } else { - grpc_do_security_handshake(exec_ctx, handshaker, &sc->base, true, - nonsecure_endpoint, cb, user_data); - } -} - -static void ssl_server_do_handshake(grpc_exec_ctx *exec_ctx, - grpc_server_security_connector *sc, - grpc_tcp_server_acceptor *acceptor, - grpc_endpoint *nonsecure_endpoint, - grpc_security_handshake_done_cb cb, - void *user_data) { - grpc_ssl_server_security_connector *c = - (grpc_ssl_server_security_connector *)sc; - tsi_handshaker *handshaker; - grpc_security_status status = - ssl_create_handshaker(c->handshaker_factory, false, NULL, &handshaker); - if (status != GRPC_SECURITY_OK) { - cb(exec_ctx, user_data, status, NULL, NULL); - } else { - grpc_do_security_handshake(exec_ctx, handshaker, &sc->base, false, - nonsecure_endpoint, cb, user_data); - } -} - -static int ssl_host_matches_name(const tsi_peer *peer, const char *peer_name) { - char *allocated_name = NULL; - int r; - - if (strchr(peer_name, ':') != NULL) { - char *ignored_port; - gpr_split_host_port(peer_name, &allocated_name, &ignored_port); - gpr_free(ignored_port); - peer_name = allocated_name; - if (!peer_name) return 0; - } - r = tsi_ssl_peer_matches_name(peer, peer_name); - gpr_free(allocated_name); - return r; -} - -grpc_auth_context *tsi_ssl_peer_to_auth_context(const tsi_peer *peer) { - size_t i; - grpc_auth_context *ctx = NULL; - const char *peer_identity_property_name = NULL; - - /* The caller has checked the certificate type property. */ - GPR_ASSERT(peer->property_count >= 1); - ctx = grpc_auth_context_create(NULL); - grpc_auth_context_add_cstring_property( - ctx, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME, - GRPC_SSL_TRANSPORT_SECURITY_TYPE); - for (i = 0; i < peer->property_count; i++) { - const tsi_peer_property *prop = &peer->properties[i]; - if (prop->name == NULL) continue; - if (strcmp(prop->name, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY) == 0) { - /* If there is no subject alt name, have the CN as the identity. */ - if (peer_identity_property_name == NULL) { - peer_identity_property_name = GRPC_X509_CN_PROPERTY_NAME; - } - grpc_auth_context_add_property(ctx, GRPC_X509_CN_PROPERTY_NAME, - prop->value.data, prop->value.length); - } else if (strcmp(prop->name, - TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) { - peer_identity_property_name = GRPC_X509_SAN_PROPERTY_NAME; - grpc_auth_context_add_property(ctx, GRPC_X509_SAN_PROPERTY_NAME, - prop->value.data, prop->value.length); - } else if (strcmp(prop->name, TSI_X509_PEM_CERT_PROPERTY) == 0) { - grpc_auth_context_add_property(ctx, GRPC_X509_PEM_CERT_PROPERTY_NAME, - prop->value.data, prop->value.length); - } - } - if (peer_identity_property_name != NULL) { - GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name( - ctx, peer_identity_property_name) == 1); - } - return ctx; -} - -static grpc_security_status ssl_check_peer(grpc_security_connector *sc, - const char *peer_name, - const tsi_peer *peer, - grpc_auth_context **auth_context) { - /* Check the ALPN. */ - const tsi_peer_property *p = - tsi_peer_get_property_by_name(peer, TSI_SSL_ALPN_SELECTED_PROTOCOL); - if (p == NULL) { - gpr_log(GPR_ERROR, "Missing selected ALPN property."); - return GRPC_SECURITY_ERROR; - } - if (!grpc_chttp2_is_alpn_version_supported(p->value.data, p->value.length)) { - gpr_log(GPR_ERROR, "Invalid ALPN value."); - return GRPC_SECURITY_ERROR; - } - - /* Check the peer name if specified. */ - if (peer_name != NULL && !ssl_host_matches_name(peer, peer_name)) { - gpr_log(GPR_ERROR, "Peer name %s is not in peer certificate", peer_name); - return GRPC_SECURITY_ERROR; - } - *auth_context = tsi_ssl_peer_to_auth_context(peer); - return GRPC_SECURITY_OK; -} - -static void ssl_channel_check_peer(grpc_exec_ctx *exec_ctx, - grpc_security_connector *sc, tsi_peer peer, - grpc_security_peer_check_cb cb, - void *user_data) { - grpc_ssl_channel_security_connector *c = - (grpc_ssl_channel_security_connector *)sc; - grpc_security_status status; - grpc_auth_context *auth_context = NULL; - status = ssl_check_peer(sc, c->overridden_target_name != NULL - ? c->overridden_target_name - : c->target_name, - &peer, &auth_context); - cb(exec_ctx, user_data, status, auth_context); - grpc_auth_context_unref(auth_context); - tsi_peer_destruct(&peer); -} - -static void ssl_server_check_peer(grpc_exec_ctx *exec_ctx, - grpc_security_connector *sc, tsi_peer peer, - grpc_security_peer_check_cb cb, - void *user_data) { - grpc_auth_context *auth_context = NULL; - grpc_security_status status = ssl_check_peer(sc, NULL, &peer, &auth_context); - tsi_peer_destruct(&peer); - cb(exec_ctx, user_data, status, auth_context); - grpc_auth_context_unref(auth_context); -} - -static void add_shallow_auth_property_to_peer(tsi_peer *peer, - const grpc_auth_property *prop, - const char *tsi_prop_name) { - tsi_peer_property *tsi_prop = &peer->properties[peer->property_count++]; - tsi_prop->name = (char *)tsi_prop_name; - tsi_prop->value.data = prop->value; - tsi_prop->value.length = prop->value_length; -} - -tsi_peer tsi_shallow_peer_from_ssl_auth_context( - const grpc_auth_context *auth_context) { - size_t max_num_props = 0; - grpc_auth_property_iterator it; - const grpc_auth_property *prop; - tsi_peer peer; - memset(&peer, 0, sizeof(peer)); - - it = grpc_auth_context_property_iterator(auth_context); - while (grpc_auth_property_iterator_next(&it) != NULL) max_num_props++; - - if (max_num_props > 0) { - peer.properties = gpr_malloc(max_num_props * sizeof(tsi_peer_property)); - it = grpc_auth_context_property_iterator(auth_context); - while ((prop = grpc_auth_property_iterator_next(&it)) != NULL) { - if (strcmp(prop->name, GRPC_X509_SAN_PROPERTY_NAME) == 0) { - add_shallow_auth_property_to_peer( - &peer, prop, TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY); - } else if (strcmp(prop->name, GRPC_X509_CN_PROPERTY_NAME) == 0) { - add_shallow_auth_property_to_peer( - &peer, prop, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY); - } else if (strcmp(prop->name, GRPC_X509_PEM_CERT_PROPERTY_NAME) == 0) { - add_shallow_auth_property_to_peer(&peer, prop, - TSI_X509_PEM_CERT_PROPERTY); - } - } - } - return peer; -} - -void tsi_shallow_peer_destruct(tsi_peer *peer) { - if (peer->properties != NULL) gpr_free(peer->properties); -} - -static void ssl_channel_check_call_host(grpc_exec_ctx *exec_ctx, - grpc_channel_security_connector *sc, - const char *host, - grpc_auth_context *auth_context, - grpc_security_call_host_check_cb cb, - void *user_data) { - grpc_ssl_channel_security_connector *c = - (grpc_ssl_channel_security_connector *)sc; - grpc_security_status status = GRPC_SECURITY_ERROR; - tsi_peer peer = tsi_shallow_peer_from_ssl_auth_context(auth_context); - if (ssl_host_matches_name(&peer, host)) status = GRPC_SECURITY_OK; - - /* If the target name was overridden, then the original target_name was - 'checked' transitively during the previous peer check at the end of the - handshake. */ - if (c->overridden_target_name != NULL && strcmp(host, c->target_name) == 0) { - status = GRPC_SECURITY_OK; - } - cb(exec_ctx, user_data, status); - tsi_shallow_peer_destruct(&peer); -} - -static grpc_security_connector_vtable ssl_channel_vtable = { - ssl_channel_destroy, ssl_channel_check_peer}; - -static grpc_security_connector_vtable ssl_server_vtable = { - ssl_server_destroy, ssl_server_check_peer}; - -static gpr_slice compute_default_pem_root_certs_once(void) { - gpr_slice result = gpr_empty_slice(); - - /* First try to load the roots from the environment. */ - char *default_root_certs_path = - gpr_getenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR); - if (default_root_certs_path != NULL) { - result = gpr_load_file(default_root_certs_path, 0, NULL); - gpr_free(default_root_certs_path); - } - - /* Try overridden roots if needed. */ - grpc_ssl_roots_override_result ovrd_res = GRPC_SSL_ROOTS_OVERRIDE_FAIL; - if (GPR_SLICE_IS_EMPTY(result) && ssl_roots_override_cb != NULL) { - char *pem_root_certs = NULL; - ovrd_res = ssl_roots_override_cb(&pem_root_certs); - if (ovrd_res == GRPC_SSL_ROOTS_OVERRIDE_OK) { - GPR_ASSERT(pem_root_certs != NULL); - result = gpr_slice_new(pem_root_certs, strlen(pem_root_certs), gpr_free); - } - } - - /* Fall back to installed certs if needed. */ - if (GPR_SLICE_IS_EMPTY(result) && - ovrd_res != GRPC_SSL_ROOTS_OVERRIDE_FAIL_PERMANENTLY) { - result = gpr_load_file(installed_roots_path, 0, NULL); - } - return result; -} - -static gpr_slice default_pem_root_certs; - -static void init_default_pem_root_certs(void) { - default_pem_root_certs = compute_default_pem_root_certs_once(); -} - -gpr_slice grpc_get_default_ssl_roots_for_testing(void) { - return compute_default_pem_root_certs_once(); -} - -size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs) { - /* TODO(jboeuf@google.com): Maybe revisit the approach which consists in - loading all the roots once for the lifetime of the process. */ - static gpr_once once = GPR_ONCE_INIT; - gpr_once_init(&once, init_default_pem_root_certs); - *pem_root_certs = GPR_SLICE_START_PTR(default_pem_root_certs); - return GPR_SLICE_LENGTH(default_pem_root_certs); -} - -grpc_security_status grpc_ssl_channel_security_connector_create( - grpc_call_credentials *request_metadata_creds, - const grpc_ssl_config *config, const char *target_name, - const char *overridden_target_name, grpc_channel_security_connector **sc) { - size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions(); - const unsigned char **alpn_protocol_strings = - gpr_malloc(sizeof(const char *) * num_alpn_protocols); - unsigned char *alpn_protocol_string_lengths = - gpr_malloc(sizeof(unsigned char) * num_alpn_protocols); - tsi_result result = TSI_OK; - grpc_ssl_channel_security_connector *c; - size_t i; - const unsigned char *pem_root_certs; - size_t pem_root_certs_size; - char *port; - - for (i = 0; i < num_alpn_protocols; i++) { - alpn_protocol_strings[i] = - (const unsigned char *)grpc_chttp2_get_alpn_version_index(i); - alpn_protocol_string_lengths[i] = - (unsigned char)strlen(grpc_chttp2_get_alpn_version_index(i)); - } - - if (config == NULL || target_name == NULL) { - gpr_log(GPR_ERROR, "An ssl channel needs a config and a target name."); - goto error; - } - if (config->pem_root_certs == NULL) { - pem_root_certs_size = grpc_get_default_ssl_roots(&pem_root_certs); - if (pem_root_certs == NULL || pem_root_certs_size == 0) { - gpr_log(GPR_ERROR, "Could not get default pem root certs."); - goto error; - } - } else { - pem_root_certs = config->pem_root_certs; - pem_root_certs_size = config->pem_root_certs_size; - } - - c = gpr_malloc(sizeof(grpc_ssl_channel_security_connector)); - memset(c, 0, sizeof(grpc_ssl_channel_security_connector)); - - gpr_ref_init(&c->base.base.refcount, 1); - c->base.base.vtable = &ssl_channel_vtable; - c->base.base.url_scheme = GRPC_SSL_URL_SCHEME; - c->base.request_metadata_creds = - grpc_call_credentials_ref(request_metadata_creds); - c->base.check_call_host = ssl_channel_check_call_host; - c->base.do_handshake = ssl_channel_do_handshake; - gpr_split_host_port(target_name, &c->target_name, &port); - gpr_free(port); - if (overridden_target_name != NULL) { - c->overridden_target_name = gpr_strdup(overridden_target_name); - } - result = tsi_create_ssl_client_handshaker_factory( - config->pem_private_key, config->pem_private_key_size, - config->pem_cert_chain, config->pem_cert_chain_size, pem_root_certs, - pem_root_certs_size, ssl_cipher_suites(), alpn_protocol_strings, - alpn_protocol_string_lengths, (uint16_t)num_alpn_protocols, - &c->handshaker_factory); - if (result != TSI_OK) { - gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.", - tsi_result_to_string(result)); - ssl_channel_destroy(&c->base.base); - *sc = NULL; - goto error; - } - *sc = &c->base; - gpr_free((void *)alpn_protocol_strings); - gpr_free(alpn_protocol_string_lengths); - return GRPC_SECURITY_OK; - -error: - gpr_free((void *)alpn_protocol_strings); - gpr_free(alpn_protocol_string_lengths); - return GRPC_SECURITY_ERROR; -} - -grpc_security_status grpc_ssl_server_security_connector_create( - const grpc_ssl_server_config *config, grpc_server_security_connector **sc) { - size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions(); - const unsigned char **alpn_protocol_strings = - gpr_malloc(sizeof(const char *) * num_alpn_protocols); - unsigned char *alpn_protocol_string_lengths = - gpr_malloc(sizeof(unsigned char) * num_alpn_protocols); - tsi_result result = TSI_OK; - grpc_ssl_server_security_connector *c; - size_t i; - - for (i = 0; i < num_alpn_protocols; i++) { - alpn_protocol_strings[i] = - (const unsigned char *)grpc_chttp2_get_alpn_version_index(i); - alpn_protocol_string_lengths[i] = - (unsigned char)strlen(grpc_chttp2_get_alpn_version_index(i)); - } - - if (config == NULL || config->num_key_cert_pairs == 0) { - gpr_log(GPR_ERROR, "An SSL server needs a key and a cert."); - goto error; - } - c = gpr_malloc(sizeof(grpc_ssl_server_security_connector)); - memset(c, 0, sizeof(grpc_ssl_server_security_connector)); - - gpr_ref_init(&c->base.base.refcount, 1); - c->base.base.url_scheme = GRPC_SSL_URL_SCHEME; - c->base.base.vtable = &ssl_server_vtable; - result = tsi_create_ssl_server_handshaker_factory( - (const unsigned char **)config->pem_private_keys, - config->pem_private_keys_sizes, - (const unsigned char **)config->pem_cert_chains, - config->pem_cert_chains_sizes, config->num_key_cert_pairs, - config->pem_root_certs, config->pem_root_certs_size, - config->force_client_auth, ssl_cipher_suites(), alpn_protocol_strings, - alpn_protocol_string_lengths, (uint16_t)num_alpn_protocols, - &c->handshaker_factory); - if (result != TSI_OK) { - gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.", - tsi_result_to_string(result)); - ssl_server_destroy(&c->base.base); - *sc = NULL; - goto error; - } - gpr_mu_init(&c->base.mu); - c->base.do_handshake = ssl_server_do_handshake; - *sc = &c->base; - gpr_free((void *)alpn_protocol_strings); - gpr_free(alpn_protocol_string_lengths); - return GRPC_SECURITY_OK; - -error: - gpr_free((void *)alpn_protocol_strings); - gpr_free(alpn_protocol_string_lengths); - return GRPC_SECURITY_ERROR; -} diff --git a/src/core/security/security_connector.h b/src/core/security/security_connector.h deleted file mode 100644 index 6f915ebb9d..0000000000 --- a/src/core/security/security_connector.h +++ /dev/null @@ -1,266 +0,0 @@ -/* - * - * Copyright 2015-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_SECURITY_SECURITY_CONNECTOR_H -#define GRPC_CORE_SECURITY_SECURITY_CONNECTOR_H - -#include -#include "src/core/iomgr/endpoint.h" -#include "src/core/iomgr/tcp_server.h" -#include "src/core/tsi/transport_security_interface.h" - -/* --- status enum. --- */ - -typedef enum { GRPC_SECURITY_OK = 0, GRPC_SECURITY_ERROR } grpc_security_status; - -/* --- URL schemes. --- */ - -#define GRPC_SSL_URL_SCHEME "https" -#define GRPC_FAKE_SECURITY_URL_SCHEME "http+fake_security" - -/* --- security_connector object. --- - - A security connector object represents away to configure the underlying - transport security mechanism and check the resulting trusted peer. */ - -typedef struct grpc_security_connector grpc_security_connector; - -#define GRPC_SECURITY_CONNECTOR_ARG "grpc.security_connector" - -typedef void (*grpc_security_peer_check_cb)(grpc_exec_ctx *exec_ctx, - void *user_data, - grpc_security_status status, - grpc_auth_context *auth_context); - -/* Ownership of the secure_endpoint is transfered. */ -typedef void (*grpc_security_handshake_done_cb)( - grpc_exec_ctx *exec_ctx, void *user_data, grpc_security_status status, - grpc_endpoint *secure_endpoint, grpc_auth_context *auth_context); - -typedef struct { - void (*destroy)(grpc_security_connector *sc); - void (*check_peer)(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc, - tsi_peer peer, grpc_security_peer_check_cb cb, - void *user_data); -} grpc_security_connector_vtable; - -typedef struct grpc_security_connector_handshake_list { - void *handshake; - struct grpc_security_connector_handshake_list *next; -} grpc_security_connector_handshake_list; - -struct grpc_security_connector { - const grpc_security_connector_vtable *vtable; - gpr_refcount refcount; - const char *url_scheme; -}; - -/* Refcounting. */ -#ifdef GRPC_SECURITY_CONNECTOR_REFCOUNT_DEBUG -#define GRPC_SECURITY_CONNECTOR_REF(p, r) \ - grpc_security_connector_ref((p), __FILE__, __LINE__, (r)) -#define GRPC_SECURITY_CONNECTOR_UNREF(p, r) \ - grpc_security_connector_unref((p), __FILE__, __LINE__, (r)) -grpc_security_connector *grpc_security_connector_ref( - grpc_security_connector *policy, const char *file, int line, - const char *reason); -void grpc_security_connector_unref(grpc_security_connector *policy, - const char *file, int line, - const char *reason); -#else -#define GRPC_SECURITY_CONNECTOR_REF(p, r) grpc_security_connector_ref((p)) -#define GRPC_SECURITY_CONNECTOR_UNREF(p, r) grpc_security_connector_unref((p)) -grpc_security_connector *grpc_security_connector_ref( - grpc_security_connector *policy); -void grpc_security_connector_unref(grpc_security_connector *policy); -#endif - -/* Check the peer. Callee takes ownership of the peer object. - The callback will include the resulting auth_context. */ -void grpc_security_connector_check_peer(grpc_exec_ctx *exec_ctx, - grpc_security_connector *sc, - tsi_peer peer, - grpc_security_peer_check_cb cb, - void *user_data); - -/* Util to encapsulate the connector in a channel arg. */ -grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc); - -/* Util to get the connector from a channel arg. */ -grpc_security_connector *grpc_security_connector_from_arg(const grpc_arg *arg); - -/* Util to find the connector from channel args. */ -grpc_security_connector *grpc_find_security_connector_in_args( - const grpc_channel_args *args); - -/* --- channel_security_connector object. --- - - A channel security connector object represents away to configure the - underlying transport security mechanism on the client side. */ - -typedef struct grpc_channel_security_connector grpc_channel_security_connector; - -typedef void (*grpc_security_call_host_check_cb)(grpc_exec_ctx *exec_ctx, - void *user_data, - grpc_security_status status); - -struct grpc_channel_security_connector { - grpc_security_connector base; - grpc_call_credentials *request_metadata_creds; - void (*check_call_host)(grpc_exec_ctx *exec_ctx, - grpc_channel_security_connector *sc, const char *host, - grpc_auth_context *auth_context, - grpc_security_call_host_check_cb cb, void *user_data); - void (*do_handshake)(grpc_exec_ctx *exec_ctx, - grpc_channel_security_connector *sc, - grpc_endpoint *nonsecure_endpoint, - grpc_security_handshake_done_cb cb, void *user_data); -}; - -/* Checks that the host that will be set for a call is acceptable. */ -void grpc_channel_security_connector_check_call_host( - grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc, - const char *host, grpc_auth_context *auth_context, - grpc_security_call_host_check_cb cb, void *user_data); - -/* Handshake. */ -void grpc_channel_security_connector_do_handshake( - grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *connector, - grpc_endpoint *nonsecure_endpoint, grpc_security_handshake_done_cb cb, - void *user_data); - -/* --- server_security_connector object. --- - - A server security connector object represents away to configure the - underlying transport security mechanism on the server side. */ - -typedef struct grpc_server_security_connector grpc_server_security_connector; - -struct grpc_server_security_connector { - grpc_security_connector base; - gpr_mu mu; - grpc_security_connector_handshake_list *handshaking_handshakes; - const grpc_channel_args *channel_args; - void (*do_handshake)(grpc_exec_ctx *exec_ctx, - grpc_server_security_connector *sc, - grpc_tcp_server_acceptor *acceptor, - grpc_endpoint *nonsecure_endpoint, - grpc_security_handshake_done_cb cb, void *user_data); -}; - -void grpc_server_security_connector_do_handshake( - grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc, - grpc_tcp_server_acceptor *acceptor, grpc_endpoint *nonsecure_endpoint, - grpc_security_handshake_done_cb cb, void *user_data); - -void grpc_server_security_connector_shutdown( - grpc_exec_ctx *exec_ctx, grpc_server_security_connector *connector); - -/* --- Creation security connectors. --- */ - -/* For TESTING ONLY! - Creates a fake connector that emulates real channel security. */ -grpc_channel_security_connector *grpc_fake_channel_security_connector_create( - grpc_call_credentials *request_metadata_creds); - -/* For TESTING ONLY! - Creates a fake connector that emulates real server security. */ -grpc_server_security_connector *grpc_fake_server_security_connector_create( - void); - -/* Config for ssl clients. */ -typedef struct { - unsigned char *pem_private_key; - size_t pem_private_key_size; - unsigned char *pem_cert_chain; - size_t pem_cert_chain_size; - unsigned char *pem_root_certs; - size_t pem_root_certs_size; -} grpc_ssl_config; - -/* Creates an SSL channel_security_connector. - - request_metadata_creds is the credentials object which metadata - will be sent with each request. This parameter can be NULL. - - config is the SSL config to be used for the SSL channel establishment. - - is_client should be 0 for a server or a non-0 value for a client. - - secure_peer_name is the secure peer name that should be checked in - grpc_channel_security_connector_check_peer. This parameter may be NULL in - which case the peer name will not be checked. Note that if this parameter - is not NULL, then, pem_root_certs should not be NULL either. - - sc is a pointer on the connector to be created. - This function returns GRPC_SECURITY_OK in case of success or a - specific error code otherwise. -*/ -grpc_security_status grpc_ssl_channel_security_connector_create( - grpc_call_credentials *request_metadata_creds, - const grpc_ssl_config *config, const char *target_name, - const char *overridden_target_name, grpc_channel_security_connector **sc); - -/* Gets the default ssl roots. */ -size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs); - -/* Exposed for TESTING ONLY!. */ -gpr_slice grpc_get_default_ssl_roots_for_testing(void); - -/* Config for ssl servers. */ -typedef struct { - unsigned char **pem_private_keys; - size_t *pem_private_keys_sizes; - unsigned char **pem_cert_chains; - size_t *pem_cert_chains_sizes; - size_t num_key_cert_pairs; - unsigned char *pem_root_certs; - size_t pem_root_certs_size; - int force_client_auth; -} grpc_ssl_server_config; - -/* Creates an SSL server_security_connector. - - config is the SSL config to be used for the SSL channel establishment. - - sc is a pointer on the connector to be created. - This function returns GRPC_SECURITY_OK in case of success or a - specific error code otherwise. -*/ -grpc_security_status grpc_ssl_server_security_connector_create( - const grpc_ssl_server_config *config, grpc_server_security_connector **sc); - -/* Util. */ -const tsi_peer_property *tsi_peer_get_property_by_name(const tsi_peer *peer, - const char *name); - -/* Exposed for testing only. */ -grpc_auth_context *tsi_ssl_peer_to_auth_context(const tsi_peer *peer); -tsi_peer tsi_shallow_peer_from_ssl_auth_context( - const grpc_auth_context *auth_context); -void tsi_shallow_peer_destruct(tsi_peer *peer); - -#endif /* GRPC_CORE_SECURITY_SECURITY_CONNECTOR_H */ diff --git a/src/core/security/security_context.c b/src/core/security/security_context.c deleted file mode 100644 index f6afc0f633..0000000000 --- a/src/core/security/security_context.c +++ /dev/null @@ -1,347 +0,0 @@ -/* - * - * Copyright 2015-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 - -#include "src/core/security/security_context.h" -#include "src/core/support/string.h" -#include "src/core/surface/api_trace.h" -#include "src/core/surface/call.h" - -#include -#include -#include -#include - -/* --- grpc_call --- */ - -grpc_call_error grpc_call_set_credentials(grpc_call *call, - grpc_call_credentials *creds) { - grpc_client_security_context *ctx = NULL; - GRPC_API_TRACE("grpc_call_set_credentials(call=%p, creds=%p)", 2, - (call, creds)); - if (!grpc_call_is_client(call)) { - gpr_log(GPR_ERROR, "Method is client-side only."); - return GRPC_CALL_ERROR_NOT_ON_SERVER; - } - ctx = (grpc_client_security_context *)grpc_call_context_get( - call, GRPC_CONTEXT_SECURITY); - if (ctx == NULL) { - ctx = grpc_client_security_context_create(); - ctx->creds = grpc_call_credentials_ref(creds); - grpc_call_context_set(call, GRPC_CONTEXT_SECURITY, ctx, - grpc_client_security_context_destroy); - } else { - grpc_call_credentials_unref(ctx->creds); - ctx->creds = grpc_call_credentials_ref(creds); - } - return GRPC_CALL_OK; -} - -grpc_auth_context *grpc_call_auth_context(grpc_call *call) { - void *sec_ctx = grpc_call_context_get(call, GRPC_CONTEXT_SECURITY); - GRPC_API_TRACE("grpc_call_auth_context(call=%p)", 1, (call)); - if (sec_ctx == NULL) return NULL; - return grpc_call_is_client(call) - ? GRPC_AUTH_CONTEXT_REF( - ((grpc_client_security_context *)sec_ctx)->auth_context, - "grpc_call_auth_context client") - : GRPC_AUTH_CONTEXT_REF( - ((grpc_server_security_context *)sec_ctx)->auth_context, - "grpc_call_auth_context server"); -} - -void grpc_auth_context_release(grpc_auth_context *context) { - GRPC_API_TRACE("grpc_auth_context_release(context=%p)", 1, (context)); - GRPC_AUTH_CONTEXT_UNREF(context, "grpc_auth_context_unref"); -} - -/* --- grpc_client_security_context --- */ - -grpc_client_security_context *grpc_client_security_context_create(void) { - grpc_client_security_context *ctx = - gpr_malloc(sizeof(grpc_client_security_context)); - memset(ctx, 0, sizeof(grpc_client_security_context)); - return ctx; -} - -void grpc_client_security_context_destroy(void *ctx) { - grpc_client_security_context *c = (grpc_client_security_context *)ctx; - grpc_call_credentials_unref(c->creds); - GRPC_AUTH_CONTEXT_UNREF(c->auth_context, "client_security_context"); - gpr_free(ctx); -} - -/* --- grpc_server_security_context --- */ - -grpc_server_security_context *grpc_server_security_context_create(void) { - grpc_server_security_context *ctx = - gpr_malloc(sizeof(grpc_server_security_context)); - memset(ctx, 0, sizeof(grpc_server_security_context)); - return ctx; -} - -void grpc_server_security_context_destroy(void *ctx) { - grpc_server_security_context *c = (grpc_server_security_context *)ctx; - GRPC_AUTH_CONTEXT_UNREF(c->auth_context, "server_security_context"); - gpr_free(ctx); -} - -/* --- grpc_auth_context --- */ - -static grpc_auth_property_iterator empty_iterator = {NULL, 0, NULL}; - -grpc_auth_context *grpc_auth_context_create(grpc_auth_context *chained) { - grpc_auth_context *ctx = gpr_malloc(sizeof(grpc_auth_context)); - memset(ctx, 0, sizeof(grpc_auth_context)); - gpr_ref_init(&ctx->refcount, 1); - if (chained != NULL) { - ctx->chained = GRPC_AUTH_CONTEXT_REF(chained, "chained"); - ctx->peer_identity_property_name = - ctx->chained->peer_identity_property_name; - } - return ctx; -} - -#ifdef GRPC_AUTH_CONTEXT_REFCOUNT_DEBUG -grpc_auth_context *grpc_auth_context_ref(grpc_auth_context *ctx, - const char *file, int line, - const char *reason) { - if (ctx == NULL) return NULL; - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, - "AUTH_CONTEXT:%p ref %d -> %d %s", ctx, (int)ctx->refcount.count, - (int)ctx->refcount.count + 1, reason); -#else -grpc_auth_context *grpc_auth_context_ref(grpc_auth_context *ctx) { - if (ctx == NULL) return NULL; -#endif - gpr_ref(&ctx->refcount); - return ctx; -} - -#ifdef GRPC_AUTH_CONTEXT_REFCOUNT_DEBUG -void grpc_auth_context_unref(grpc_auth_context *ctx, const char *file, int line, - const char *reason) { - if (ctx == NULL) return; - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, - "AUTH_CONTEXT:%p unref %d -> %d %s", ctx, (int)ctx->refcount.count, - (int)ctx->refcount.count - 1, reason); -#else -void grpc_auth_context_unref(grpc_auth_context *ctx) { - if (ctx == NULL) return; -#endif - if (gpr_unref(&ctx->refcount)) { - size_t i; - GRPC_AUTH_CONTEXT_UNREF(ctx->chained, "chained"); - if (ctx->properties.array != NULL) { - for (i = 0; i < ctx->properties.count; i++) { - grpc_auth_property_reset(&ctx->properties.array[i]); - } - gpr_free(ctx->properties.array); - } - gpr_free(ctx); - } -} - -const char *grpc_auth_context_peer_identity_property_name( - const grpc_auth_context *ctx) { - GRPC_API_TRACE("grpc_auth_context_peer_identity_property_name(ctx=%p)", 1, - (ctx)); - return ctx->peer_identity_property_name; -} - -int grpc_auth_context_set_peer_identity_property_name(grpc_auth_context *ctx, - const char *name) { - grpc_auth_property_iterator it = - grpc_auth_context_find_properties_by_name(ctx, name); - const grpc_auth_property *prop = grpc_auth_property_iterator_next(&it); - GRPC_API_TRACE( - "grpc_auth_context_set_peer_identity_property_name(ctx=%p, name=%s)", 2, - (ctx, name)); - if (prop == NULL) { - gpr_log(GPR_ERROR, "Property name %s not found in auth context.", - name != NULL ? name : "NULL"); - return 0; - } - ctx->peer_identity_property_name = prop->name; - return 1; -} - -int grpc_auth_context_peer_is_authenticated(const grpc_auth_context *ctx) { - GRPC_API_TRACE("grpc_auth_context_peer_is_authenticated(ctx=%p)", 1, (ctx)); - return ctx->peer_identity_property_name == NULL ? 0 : 1; -} - -grpc_auth_property_iterator grpc_auth_context_property_iterator( - const grpc_auth_context *ctx) { - grpc_auth_property_iterator it = empty_iterator; - GRPC_API_TRACE("grpc_auth_context_property_iterator(ctx=%p)", 1, (ctx)); - if (ctx == NULL) return it; - it.ctx = ctx; - return it; -} - -const grpc_auth_property *grpc_auth_property_iterator_next( - grpc_auth_property_iterator *it) { - GRPC_API_TRACE("grpc_auth_property_iterator_next(it=%p)", 1, (it)); - if (it == NULL || it->ctx == NULL) return NULL; - while (it->index == it->ctx->properties.count) { - if (it->ctx->chained == NULL) return NULL; - it->ctx = it->ctx->chained; - it->index = 0; - } - if (it->name == NULL) { - return &it->ctx->properties.array[it->index++]; - } else { - while (it->index < it->ctx->properties.count) { - const grpc_auth_property *prop = &it->ctx->properties.array[it->index++]; - GPR_ASSERT(prop->name != NULL); - if (strcmp(it->name, prop->name) == 0) { - return prop; - } - } - /* We could not find the name, try another round. */ - return grpc_auth_property_iterator_next(it); - } -} - -grpc_auth_property_iterator grpc_auth_context_find_properties_by_name( - const grpc_auth_context *ctx, const char *name) { - grpc_auth_property_iterator it = empty_iterator; - GRPC_API_TRACE("grpc_auth_context_find_properties_by_name(ctx=%p, name=%s)", - 2, (ctx, name)); - if (ctx == NULL || name == NULL) return empty_iterator; - it.ctx = ctx; - it.name = name; - return it; -} - -grpc_auth_property_iterator grpc_auth_context_peer_identity( - const grpc_auth_context *ctx) { - GRPC_API_TRACE("grpc_auth_context_peer_identity(ctx=%p)", 1, (ctx)); - if (ctx == NULL) return empty_iterator; - return grpc_auth_context_find_properties_by_name( - ctx, ctx->peer_identity_property_name); -} - -static void ensure_auth_context_capacity(grpc_auth_context *ctx) { - if (ctx->properties.count == ctx->properties.capacity) { - ctx->properties.capacity = - GPR_MAX(ctx->properties.capacity + 8, ctx->properties.capacity * 2); - ctx->properties.array = - gpr_realloc(ctx->properties.array, - ctx->properties.capacity * sizeof(grpc_auth_property)); - } -} - -void grpc_auth_context_add_property(grpc_auth_context *ctx, const char *name, - const char *value, size_t value_length) { - grpc_auth_property *prop; - GRPC_API_TRACE( - "grpc_auth_context_add_property(ctx=%p, name=%s, value=%*.*s, " - "value_length=%lu)", - 6, (ctx, name, (int)value_length, (int)value_length, value, - (unsigned long)value_length)); - ensure_auth_context_capacity(ctx); - prop = &ctx->properties.array[ctx->properties.count++]; - prop->name = gpr_strdup(name); - prop->value = gpr_malloc(value_length + 1); - memcpy(prop->value, value, value_length); - prop->value[value_length] = '\0'; - prop->value_length = value_length; -} - -void grpc_auth_context_add_cstring_property(grpc_auth_context *ctx, - const char *name, - const char *value) { - grpc_auth_property *prop; - GRPC_API_TRACE( - "grpc_auth_context_add_cstring_property(ctx=%p, name=%s, value=%s)", 3, - (ctx, name, value)); - ensure_auth_context_capacity(ctx); - prop = &ctx->properties.array[ctx->properties.count++]; - prop->name = gpr_strdup(name); - prop->value = gpr_strdup(value); - prop->value_length = strlen(value); -} - -void grpc_auth_property_reset(grpc_auth_property *property) { - gpr_free(property->name); - gpr_free(property->value); - memset(property, 0, sizeof(grpc_auth_property)); -} - -static void auth_context_pointer_arg_destroy(void *p) { - GRPC_AUTH_CONTEXT_UNREF(p, "auth_context_pointer_arg"); -} - -static void *auth_context_pointer_arg_copy(void *p) { - return GRPC_AUTH_CONTEXT_REF(p, "auth_context_pointer_arg"); -} - -static int auth_context_pointer_cmp(void *a, void *b) { return GPR_ICMP(a, b); } - -static const grpc_arg_pointer_vtable auth_context_pointer_vtable = { - auth_context_pointer_arg_copy, auth_context_pointer_arg_destroy, - auth_context_pointer_cmp}; - -grpc_arg grpc_auth_context_to_arg(grpc_auth_context *p) { - grpc_arg arg; - memset(&arg, 0, sizeof(grpc_arg)); - arg.type = GRPC_ARG_POINTER; - arg.key = GRPC_AUTH_CONTEXT_ARG; - arg.value.pointer.p = p; - arg.value.pointer.vtable = &auth_context_pointer_vtable; - return arg; -} - -grpc_auth_context *grpc_auth_context_from_arg(const grpc_arg *arg) { - if (strcmp(arg->key, GRPC_AUTH_CONTEXT_ARG) != 0) return NULL; - if (arg->type != GRPC_ARG_POINTER) { - gpr_log(GPR_ERROR, "Invalid type %d for arg %s", arg->type, - GRPC_AUTH_CONTEXT_ARG); - return NULL; - } - return arg->value.pointer.p; -} - -grpc_auth_context *grpc_find_auth_context_in_args( - const grpc_channel_args *args) { - size_t i; - if (args == NULL) return NULL; - for (i = 0; i < args->num_args; i++) { - grpc_auth_context *p = grpc_auth_context_from_arg(&args->args[i]); - if (p != NULL) return p; - } - return NULL; -} diff --git a/src/core/security/security_context.h b/src/core/security/security_context.h deleted file mode 100644 index 61601f538b..0000000000 --- a/src/core/security/security_context.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * - * Copyright 2015-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_SECURITY_SECURITY_CONTEXT_H -#define GRPC_CORE_SECURITY_SECURITY_CONTEXT_H - -#include "src/core/iomgr/pollset.h" -#include "src/core/security/credentials.h" - -/* --- grpc_auth_context --- - - High level authentication context object. Can optionally be chained. */ - -/* Property names are always NULL terminated. */ - -typedef struct { - grpc_auth_property *array; - size_t count; - size_t capacity; -} grpc_auth_property_array; - -struct grpc_auth_context { - struct grpc_auth_context *chained; - grpc_auth_property_array properties; - gpr_refcount refcount; - const char *peer_identity_property_name; - grpc_pollset *pollset; -}; - -/* Creation. */ -grpc_auth_context *grpc_auth_context_create(grpc_auth_context *chained); - -/* Refcounting. */ -#ifdef GRPC_AUTH_CONTEXT_REFCOUNT_DEBUG -#define GRPC_AUTH_CONTEXT_REF(p, r) \ - grpc_auth_context_ref((p), __FILE__, __LINE__, (r)) -#define GRPC_AUTH_CONTEXT_UNREF(p, r) \ - grpc_auth_context_unref((p), __FILE__, __LINE__, (r)) -grpc_auth_context *grpc_auth_context_ref(grpc_auth_context *policy, - const char *file, int line, - const char *reason); -void grpc_auth_context_unref(grpc_auth_context *policy, const char *file, - int line, const char *reason); -#else -#define GRPC_AUTH_CONTEXT_REF(p, r) grpc_auth_context_ref((p)) -#define GRPC_AUTH_CONTEXT_UNREF(p, r) grpc_auth_context_unref((p)) -grpc_auth_context *grpc_auth_context_ref(grpc_auth_context *policy); -void grpc_auth_context_unref(grpc_auth_context *policy); -#endif - -void grpc_auth_property_reset(grpc_auth_property *property); - -/* --- grpc_client_security_context --- - - Internal client-side security context. */ - -typedef struct { - grpc_call_credentials *creds; - grpc_auth_context *auth_context; -} grpc_client_security_context; - -grpc_client_security_context *grpc_client_security_context_create(void); -void grpc_client_security_context_destroy(void *ctx); - -/* --- grpc_server_security_context --- - - Internal server-side security context. */ - -typedef struct { - grpc_auth_context *auth_context; -} grpc_server_security_context; - -grpc_server_security_context *grpc_server_security_context_create(void); -void grpc_server_security_context_destroy(void *ctx); - -/* --- Channel args for auth context --- */ -#define GRPC_AUTH_CONTEXT_ARG "grpc.auth_context" - -grpc_arg grpc_auth_context_to_arg(grpc_auth_context *c); -grpc_auth_context *grpc_auth_context_from_arg(const grpc_arg *arg); -grpc_auth_context *grpc_find_auth_context_in_args( - const grpc_channel_args *args); - -#endif /* GRPC_CORE_SECURITY_SECURITY_CONTEXT_H */ diff --git a/src/core/security/server_auth_filter.c b/src/core/security/server_auth_filter.c deleted file mode 100644 index f3c411d6d4..0000000000 --- a/src/core/security/server_auth_filter.c +++ /dev/null @@ -1,264 +0,0 @@ -/* - * - * Copyright 2015-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 - -#include "src/core/security/auth_filters.h" -#include "src/core/security/credentials.h" -#include "src/core/security/security_context.h" - -#include -#include - -typedef struct call_data { - grpc_metadata_batch *recv_initial_metadata; - /* Closure to call when finished with the auth_on_recv hook. */ - grpc_closure *on_done_recv; - /* Receive closures are chained: we inject this closure as the on_done_recv - up-call on transport_op, and remember to call our on_done_recv member after - handling it. */ - grpc_closure auth_on_recv; - grpc_transport_stream_op transport_op; - grpc_metadata_array md; - const grpc_metadata *consumed_md; - size_t num_consumed_md; - grpc_auth_context *auth_context; -} call_data; - -typedef struct channel_data { - grpc_auth_context *auth_context; - grpc_server_credentials *creds; -} channel_data; - -static grpc_metadata_array metadata_batch_to_md_array( - const grpc_metadata_batch *batch) { - grpc_linked_mdelem *l; - grpc_metadata_array result; - grpc_metadata_array_init(&result); - for (l = batch->list.head; l != NULL; l = l->next) { - grpc_metadata *usr_md = NULL; - grpc_mdelem *md = l->md; - grpc_mdstr *key = md->key; - grpc_mdstr *value = md->value; - if (result.count == result.capacity) { - result.capacity = GPR_MAX(result.capacity + 8, result.capacity * 2); - result.metadata = - gpr_realloc(result.metadata, result.capacity * sizeof(grpc_metadata)); - } - usr_md = &result.metadata[result.count++]; - usr_md->key = grpc_mdstr_as_c_string(key); - usr_md->value = grpc_mdstr_as_c_string(value); - usr_md->value_length = GPR_SLICE_LENGTH(value->slice); - } - return result; -} - -static grpc_mdelem *remove_consumed_md(void *user_data, grpc_mdelem *md) { - grpc_call_element *elem = user_data; - call_data *calld = elem->call_data; - size_t i; - for (i = 0; i < calld->num_consumed_md; i++) { - const grpc_metadata *consumed_md = &calld->consumed_md[i]; - /* Maybe we could do a pointer comparison but we do not have any guarantee - that the metadata processor used the same pointers for consumed_md in the - callback. */ - if (GPR_SLICE_LENGTH(md->key->slice) != strlen(consumed_md->key) || - GPR_SLICE_LENGTH(md->value->slice) != consumed_md->value_length) { - continue; - } - if (memcmp(GPR_SLICE_START_PTR(md->key->slice), consumed_md->key, - GPR_SLICE_LENGTH(md->key->slice)) == 0 && - memcmp(GPR_SLICE_START_PTR(md->value->slice), consumed_md->value, - GPR_SLICE_LENGTH(md->value->slice)) == 0) { - return NULL; /* Delete. */ - } - } - return md; -} - -/* called from application code */ -static void on_md_processing_done( - void *user_data, const grpc_metadata *consumed_md, size_t num_consumed_md, - const grpc_metadata *response_md, size_t num_response_md, - grpc_status_code status, const char *error_details) { - grpc_call_element *elem = user_data; - call_data *calld = elem->call_data; - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - - /* TODO(jboeuf): Implement support for response_md. */ - if (response_md != NULL && num_response_md > 0) { - gpr_log(GPR_INFO, - "response_md in auth metadata processing not supported for now. " - "Ignoring..."); - } - - if (status == GRPC_STATUS_OK) { - calld->consumed_md = consumed_md; - calld->num_consumed_md = num_consumed_md; - grpc_metadata_batch_filter(calld->recv_initial_metadata, remove_consumed_md, - elem); - grpc_metadata_array_destroy(&calld->md); - calld->on_done_recv->cb(&exec_ctx, calld->on_done_recv->cb_arg, 1); - } else { - gpr_slice message; - grpc_transport_stream_op close_op; - memset(&close_op, 0, sizeof(close_op)); - grpc_metadata_array_destroy(&calld->md); - error_details = error_details != NULL - ? error_details - : "Authentication metadata processing failed."; - message = gpr_slice_from_copied_string(error_details); - calld->transport_op.send_initial_metadata = NULL; - if (calld->transport_op.send_message != NULL) { - grpc_byte_stream_destroy(&exec_ctx, calld->transport_op.send_message); - calld->transport_op.send_message = NULL; - } - calld->transport_op.send_trailing_metadata = NULL; - grpc_transport_stream_op_add_close(&close_op, status, &message); - grpc_call_next_op(&exec_ctx, elem, &close_op); - calld->on_done_recv->cb(&exec_ctx, calld->on_done_recv->cb_arg, 0); - } - - grpc_exec_ctx_finish(&exec_ctx); -} - -static void auth_on_recv(grpc_exec_ctx *exec_ctx, void *user_data, - bool success) { - grpc_call_element *elem = user_data; - call_data *calld = elem->call_data; - channel_data *chand = elem->channel_data; - if (success) { - if (chand->creds->processor.process != NULL) { - calld->md = metadata_batch_to_md_array(calld->recv_initial_metadata); - chand->creds->processor.process( - chand->creds->processor.state, calld->auth_context, - calld->md.metadata, calld->md.count, on_md_processing_done, elem); - return; - } - } - calld->on_done_recv->cb(exec_ctx, calld->on_done_recv->cb_arg, success); -} - -static void set_recv_ops_md_callbacks(grpc_call_element *elem, - grpc_transport_stream_op *op) { - call_data *calld = elem->call_data; - - if (op->recv_initial_metadata != NULL) { - /* substitute our callback for the higher callback */ - calld->recv_initial_metadata = op->recv_initial_metadata; - calld->on_done_recv = op->recv_initial_metadata_ready; - op->recv_initial_metadata_ready = &calld->auth_on_recv; - calld->transport_op = *op; - } -} - -/* Called either: - - in response to an API call (or similar) from above, to send something - - a network event (or similar) from below, to receive something - op contains type and call direction information, in addition to the data - that is being sent or received. */ -static void auth_start_transport_op(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_transport_stream_op *op) { - set_recv_ops_md_callbacks(elem, op); - grpc_call_next_op(exec_ctx, elem, op); -} - -/* Constructor for call_data */ -static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_call_element_args *args) { - /* grab pointers to our data from the call element */ - call_data *calld = elem->call_data; - channel_data *chand = elem->channel_data; - grpc_server_security_context *server_ctx = NULL; - - /* initialize members */ - memset(calld, 0, sizeof(*calld)); - grpc_closure_init(&calld->auth_on_recv, auth_on_recv, elem); - - if (args->context[GRPC_CONTEXT_SECURITY].value != NULL) { - args->context[GRPC_CONTEXT_SECURITY].destroy( - args->context[GRPC_CONTEXT_SECURITY].value); - } - - server_ctx = grpc_server_security_context_create(); - server_ctx->auth_context = grpc_auth_context_create(chand->auth_context); - calld->auth_context = server_ctx->auth_context; - - args->context[GRPC_CONTEXT_SECURITY].value = server_ctx; - args->context[GRPC_CONTEXT_SECURITY].destroy = - grpc_server_security_context_destroy; -} - -static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_pollset *pollset) {} - -/* Destructor for call_data */ -static void destroy_call_elem(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem) {} - -/* Constructor for channel_data */ -static void init_channel_elem(grpc_exec_ctx *exec_ctx, - grpc_channel_element *elem, - grpc_channel_element_args *args) { - grpc_auth_context *auth_context = - grpc_find_auth_context_in_args(args->channel_args); - grpc_server_credentials *creds = - grpc_find_server_credentials_in_args(args->channel_args); - /* grab pointers to our data from the channel element */ - channel_data *chand = elem->channel_data; - - GPR_ASSERT(!args->is_last); - GPR_ASSERT(auth_context != NULL); - GPR_ASSERT(creds != NULL); - - /* initialize members */ - chand->auth_context = - GRPC_AUTH_CONTEXT_REF(auth_context, "server_auth_filter"); - chand->creds = grpc_server_credentials_ref(creds); -} - -/* Destructor for channel data */ -static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, - grpc_channel_element *elem) { - /* grab pointers to our data from the channel element */ - channel_data *chand = elem->channel_data; - GRPC_AUTH_CONTEXT_UNREF(chand->auth_context, "server_auth_filter"); - grpc_server_credentials_unref(chand->creds); -} - -const grpc_channel_filter grpc_server_auth_filter = { - auth_start_transport_op, grpc_channel_next_op, sizeof(call_data), - init_call_elem, set_pollset, destroy_call_elem, - sizeof(channel_data), init_channel_elem, destroy_channel_elem, - grpc_call_next_get_peer, "server-auth"}; diff --git a/src/core/security/server_secure_chttp2.c b/src/core/security/server_secure_chttp2.c deleted file mode 100644 index da29ca934b..0000000000 --- a/src/core/security/server_secure_chttp2.c +++ /dev/null @@ -1,264 +0,0 @@ -/* - * - * Copyright 2015-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 - -#include - -#include -#include -#include -#include -#include "src/core/channel/channel_args.h" -#include "src/core/channel/http_server_filter.h" -#include "src/core/iomgr/endpoint.h" -#include "src/core/iomgr/resolve_address.h" -#include "src/core/iomgr/tcp_server.h" -#include "src/core/security/auth_filters.h" -#include "src/core/security/credentials.h" -#include "src/core/security/security_connector.h" -#include "src/core/security/security_context.h" -#include "src/core/surface/api_trace.h" -#include "src/core/surface/server.h" -#include "src/core/transport/chttp2_transport.h" - -typedef struct grpc_server_secure_state { - grpc_server *server; - grpc_tcp_server *tcp; - grpc_server_security_connector *sc; - grpc_server_credentials *creds; - int is_shutdown; - gpr_mu mu; - gpr_refcount refcount; - grpc_closure destroy_closure; - grpc_closure *destroy_callback; -} grpc_server_secure_state; - -static void state_ref(grpc_server_secure_state *state) { - gpr_ref(&state->refcount); -} - -static void state_unref(grpc_server_secure_state *state) { - if (gpr_unref(&state->refcount)) { - /* ensure all threads have unlocked */ - gpr_mu_lock(&state->mu); - gpr_mu_unlock(&state->mu); - /* clean up */ - GRPC_SECURITY_CONNECTOR_UNREF(&state->sc->base, "server"); - grpc_server_credentials_unref(state->creds); - gpr_free(state); - } -} - -static void setup_transport(grpc_exec_ctx *exec_ctx, void *statep, - grpc_transport *transport, - grpc_auth_context *auth_context) { - grpc_server_secure_state *state = statep; - grpc_channel_args *args_copy; - grpc_arg args_to_add[2]; - args_to_add[0] = grpc_server_credentials_to_arg(state->creds); - args_to_add[1] = grpc_auth_context_to_arg(auth_context); - args_copy = grpc_channel_args_copy_and_add( - grpc_server_get_channel_args(state->server), args_to_add, - GPR_ARRAY_SIZE(args_to_add)); - grpc_server_setup_transport(exec_ctx, state->server, transport, args_copy); - grpc_channel_args_destroy(args_copy); -} - -static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *statep, - grpc_security_status status, - grpc_endpoint *secure_endpoint, - grpc_auth_context *auth_context) { - grpc_server_secure_state *state = statep; - grpc_transport *transport; - if (status == GRPC_SECURITY_OK) { - if (secure_endpoint) { - gpr_mu_lock(&state->mu); - if (!state->is_shutdown) { - transport = grpc_create_chttp2_transport( - exec_ctx, grpc_server_get_channel_args(state->server), - secure_endpoint, 0); - setup_transport(exec_ctx, state, transport, auth_context); - grpc_chttp2_transport_start_reading(exec_ctx, transport, NULL, 0); - } else { - /* We need to consume this here, because the server may already have - * gone away. */ - grpc_endpoint_destroy(exec_ctx, secure_endpoint); - } - gpr_mu_unlock(&state->mu); - } - } else { - gpr_log(GPR_ERROR, "Secure transport failed with error %d", status); - } - state_unref(state); -} - -static void on_accept(grpc_exec_ctx *exec_ctx, void *statep, grpc_endpoint *tcp, - grpc_tcp_server_acceptor *acceptor) { - grpc_server_secure_state *state = statep; - state_ref(state); - grpc_server_security_connector_do_handshake( - exec_ctx, state->sc, acceptor, tcp, on_secure_handshake_done, state); -} - -/* Server callback: start listening on our ports */ -static void start(grpc_exec_ctx *exec_ctx, grpc_server *server, void *statep, - grpc_pollset **pollsets, size_t pollset_count) { - grpc_server_secure_state *state = statep; - grpc_tcp_server_start(exec_ctx, state->tcp, pollsets, pollset_count, - on_accept, state); -} - -static void destroy_done(grpc_exec_ctx *exec_ctx, void *statep, bool success) { - grpc_server_secure_state *state = statep; - if (state->destroy_callback != NULL) { - state->destroy_callback->cb(exec_ctx, state->destroy_callback->cb_arg, - success); - } - grpc_server_security_connector_shutdown(exec_ctx, state->sc); - state_unref(state); -} - -/* Server callback: destroy the tcp listener (so we don't generate further - callbacks) */ -static void destroy(grpc_exec_ctx *exec_ctx, grpc_server *server, void *statep, - grpc_closure *callback) { - grpc_server_secure_state *state = statep; - grpc_tcp_server *tcp; - gpr_mu_lock(&state->mu); - state->is_shutdown = 1; - state->destroy_callback = callback; - tcp = state->tcp; - gpr_mu_unlock(&state->mu); - grpc_tcp_server_unref(exec_ctx, tcp); -} - -int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr, - grpc_server_credentials *creds) { - grpc_resolved_addresses *resolved = NULL; - grpc_tcp_server *tcp = NULL; - grpc_server_secure_state *state = NULL; - size_t i; - unsigned count = 0; - int port_num = -1; - int port_temp; - grpc_security_status status = GRPC_SECURITY_ERROR; - grpc_server_security_connector *sc = NULL; - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - - GRPC_API_TRACE( - "grpc_server_add_secure_http2_port(" - "server=%p, addr=%s, creds=%p)", - 3, (server, addr, creds)); - - /* create security context */ - if (creds == NULL) goto error; - status = grpc_server_credentials_create_security_connector(creds, &sc); - if (status != GRPC_SECURITY_OK) { - gpr_log(GPR_ERROR, - "Unable to create secure server with credentials of type %s.", - creds->type); - goto error; - } - sc->channel_args = grpc_server_get_channel_args(server); - - /* resolve address */ - resolved = grpc_blocking_resolve_address(addr, "https"); - if (!resolved) { - goto error; - } - state = gpr_malloc(sizeof(*state)); - memset(state, 0, sizeof(*state)); - grpc_closure_init(&state->destroy_closure, destroy_done, state); - tcp = grpc_tcp_server_create(&state->destroy_closure); - if (!tcp) { - goto error; - } - - state->server = server; - state->tcp = tcp; - state->sc = sc; - state->creds = grpc_server_credentials_ref(creds); - state->is_shutdown = 0; - gpr_mu_init(&state->mu); - gpr_ref_init(&state->refcount, 1); - - for (i = 0; i < resolved->naddrs; i++) { - port_temp = grpc_tcp_server_add_port( - tcp, (struct sockaddr *)&resolved->addrs[i].addr, - resolved->addrs[i].len); - if (port_temp > 0) { - if (port_num == -1) { - port_num = port_temp; - } else { - GPR_ASSERT(port_num == port_temp); - } - count++; - } - } - if (count == 0) { - gpr_log(GPR_ERROR, "No address added out of total %d resolved", - resolved->naddrs); - goto error; - } - if (count != resolved->naddrs) { - gpr_log(GPR_ERROR, "Only %d addresses added out of total %d resolved", - count, resolved->naddrs); - /* if it's an error, don't we want to goto error; here ? */ - } - grpc_resolved_addresses_destroy(resolved); - - /* Register with the server only upon success */ - grpc_server_add_listener(&exec_ctx, server, state, start, destroy); - - grpc_exec_ctx_finish(&exec_ctx); - return port_num; - -/* Error path: cleanup and return */ -error: - if (resolved) { - grpc_resolved_addresses_destroy(resolved); - } - if (tcp) { - grpc_tcp_server_unref(&exec_ctx, tcp); - } else { - if (sc) { - GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "server"); - } - if (state) { - gpr_free(state); - } - } - grpc_exec_ctx_finish(&exec_ctx); - return 0; -} diff --git a/src/core/statistics/census_init.c b/src/core/statistics/census_init.c deleted file mode 100644 index b6a962f228..0000000000 --- a/src/core/statistics/census_init.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * - * Copyright 2015-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/statistics/census_interface.h" - -#include -#include "src/core/statistics/census_rpc_stats.h" -#include "src/core/statistics/census_tracing.h" - -void census_init(void) { - census_tracing_init(); - census_stats_store_init(); -} - -void census_shutdown(void) { - census_stats_store_shutdown(); - census_tracing_shutdown(); -} diff --git a/src/core/statistics/census_interface.h b/src/core/statistics/census_interface.h deleted file mode 100644 index ce8ff92cd4..0000000000 --- a/src/core/statistics/census_interface.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * - * Copyright 2015-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_STATISTICS_CENSUS_INTERFACE_H -#define GRPC_CORE_STATISTICS_CENSUS_INTERFACE_H - -#include - -/* Maximum length of an individual census trace annotation. */ -#define CENSUS_MAX_ANNOTATION_LENGTH 200 - -/* Structure of a census op id. Define as structure because 64bit integer is not - available on every platform for C89. */ -typedef struct census_op_id { - uint32_t upper; - uint32_t lower; -} census_op_id; - -typedef struct census_rpc_stats census_rpc_stats; - -/* Initializes Census library. No-op if Census is already initialized. */ -void census_init(void); - -/* Shutdown Census Library. */ -void census_shutdown(void); - -/* Annotates grpc method name on a census_op_id. The method name has the format - of /. Returns 0 iff - op_id and method_name are all valid. op_id is valid after its creation and - before calling census_tracing_end_op(). - - TODO(hongyu): Figure out valid characters set for service name and command - name and document requirements here.*/ -int census_add_method_tag(census_op_id op_id, const char *method_name); - -/* Annotates tracing information to a specific op_id. - Up to CENSUS_MAX_ANNOTATION_LENGTH bytes are recorded. */ -void census_tracing_print(census_op_id op_id, const char *annotation); - -/* Starts tracing for an RPC. Returns a locally unique census_op_id */ -census_op_id census_tracing_start_op(void); - -/* Ends tracing. Calling this function will invalidate the input op_id. */ -void census_tracing_end_op(census_op_id op_id); - -#endif /* GRPC_CORE_STATISTICS_CENSUS_INTERFACE_H */ diff --git a/src/core/statistics/census_log.c b/src/core/statistics/census_log.c deleted file mode 100644 index 3802d1cc7a..0000000000 --- a/src/core/statistics/census_log.c +++ /dev/null @@ -1,603 +0,0 @@ -/* - * - * Copyright 2015-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. - * - */ - -/* Available log space is divided up in blocks of - CENSUS_LOG_2_MAX_RECORD_SIZE bytes. A block can be in one of the - following three data structures: - - Free blocks (free_block_list) - - Blocks with unread data (dirty_block_list) - - Blocks currently attached to cores (core_local_blocks[]) - - census_log_start_write() moves a block from core_local_blocks[] to the - end of dirty_block_list when block: - - is out-of-space OR - - has an incomplete record (an incomplete record occurs when a thread calls - census_log_start_write() and is context-switched before calling - census_log_end_write() - So, blocks in dirty_block_list are ordered, from oldest to newest, by time - when block is detached from the core. - - census_log_read_next() first iterates over dirty_block_list and then - core_local_blocks[]. It moves completely read blocks from dirty_block_list - to free_block_list. Blocks in core_local_blocks[] are not freed, even when - completely read. - - If log is configured to discard old records and free_block_list is empty, - census_log_start_write() iterates over dirty_block_list to allocate a - new block. It moves the oldest available block (no pending read/write) to - core_local_blocks[]. - - core_local_block_struct is used to implement a map from core id to the block - associated with that core. This mapping is advisory. It is possible that the - block returned by this mapping is no longer associated with that core. This - mapping is updated, lazily, by census_log_start_write(). - - Locking in block struct: - - Exclusive g_log.lock must be held before calling any functions operatong on - block structs except census_log_start_write() and - census_log_end_write(). - - Writes to a block are serialized via writer_lock. - census_log_start_write() acquires this lock and - census_log_end_write() releases it. On failure to acquire the lock, - writer allocates a new block for the current core and updates - core_local_block accordingly. - - Simultaneous read and write access is allowed. Reader can safely read up to - committed bytes (bytes_committed). - - reader_lock protects the block, currently being read, from getting recycled. - start_read() acquires reader_lock and end_read() releases the lock. - - Read/write access to a block is disabled via try_disable_access(). It returns - with both writer_lock and reader_lock held. These locks are subsequently - released by enable_access() to enable access to the block. - - A note on naming: Most function/struct names are prepended by cl_ - (shorthand for census_log). Further, functions that manipulate structures - include the name of the structure, which will be passed as the first - argument. E.g. cl_block_initialize() will initialize a cl_block. -*/ -#include "src/core/statistics/census_log.h" -#include -#include -#include -#include -#include -#include -#include -#include - -/* End of platform specific code */ - -typedef struct census_log_block_list_struct { - struct census_log_block_list_struct *next; - struct census_log_block_list_struct *prev; - struct census_log_block *block; -} cl_block_list_struct; - -typedef struct census_log_block { - /* Pointer to underlying buffer */ - char *buffer; - gpr_atm writer_lock; - gpr_atm reader_lock; - /* Keeps completely written bytes. Declared atomic because accessed - simultaneously by reader and writer. */ - gpr_atm bytes_committed; - /* Bytes already read */ - int32_t bytes_read; - /* Links for list */ - cl_block_list_struct link; -/* We want this structure to be cacheline aligned. We assume the following - sizes for the various parts on 32/64bit systems: - type 32b size 64b size - char* 4 8 - 3x gpr_atm 12 24 - int32_t 4 8 (assumes padding) - cl_block_list_struct 12 24 - TOTAL 32 64 - - Depending on the size of our cacheline and the architecture, we - selectively add char buffering to this structure. The size is checked - via assert in census_log_initialize(). */ -#if defined(GPR_ARCH_64) -#define CL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 64) -#else -#if defined(GPR_ARCH_32) -#define CL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 32) -#else -#error "Unknown architecture" -#endif -#endif -#if CL_BLOCK_PAD_SIZE > 0 - char padding[CL_BLOCK_PAD_SIZE]; -#endif -} cl_block; - -/* A list of cl_blocks, doubly-linked through cl_block::link. */ -typedef struct census_log_block_list { - int32_t count; /* Number of items in list. */ - cl_block_list_struct ht; /* head/tail of linked list. */ -} cl_block_list; - -/* Cacheline aligned block pointers to avoid false sharing. Block pointer must - be initialized via set_block(), before calling other functions */ -typedef struct census_log_core_local_block { - gpr_atm block; -/* Ensure cachline alignment: we assume sizeof(gpr_atm) == 4 or 8 */ -#if defined(GPR_ARCH_64) -#define CL_CORE_LOCAL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 8) -#else -#if defined(GPR_ARCH_32) -#define CL_CORE_LOCAL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 4) -#else -#error "Unknown architecture" -#endif -#endif -#if CL_CORE_LOCAL_BLOCK_PAD_SIZE > 0 - char padding[CL_CORE_LOCAL_BLOCK_PAD_SIZE]; -#endif -} cl_core_local_block; - -struct census_log { - int discard_old_records; - /* Number of cores (aka hardware-contexts) */ - unsigned num_cores; - /* number of CENSUS_LOG_2_MAX_RECORD_SIZE blocks in log */ - int32_t num_blocks; - cl_block *blocks; /* Block metadata. */ - cl_core_local_block *core_local_blocks; /* Keeps core to block mappings. */ - gpr_mu lock; - int initialized; /* has log been initialized? */ - /* Keeps the state of the reader iterator. A value of 0 indicates that - iterator has reached the end. census_log_init_reader() resets the - value to num_core to restart iteration. */ - uint32_t read_iterator_state; - /* Points to the block being read. If non-NULL, the block is locked for - reading (block_being_read_->reader_lock is held). */ - cl_block *block_being_read; - /* A non-zero value indicates that log is full. */ - gpr_atm is_full; - char *buffer; - cl_block_list free_block_list; - cl_block_list dirty_block_list; - gpr_atm out_of_space_count; -}; - -/* Single internal log */ -static struct census_log g_log; - -/* Functions that operate on an atomic memory location used as a lock */ - -/* Returns non-zero if lock is acquired */ -static int cl_try_lock(gpr_atm *lock) { return gpr_atm_acq_cas(lock, 0, 1); } - -static void cl_unlock(gpr_atm *lock) { gpr_atm_rel_store(lock, 0); } - -/* Functions that operate on cl_core_local_block's */ - -static void cl_core_local_block_set_block(cl_core_local_block *clb, - cl_block *block) { - gpr_atm_rel_store(&clb->block, (gpr_atm)block); -} - -static cl_block *cl_core_local_block_get_block(cl_core_local_block *clb) { - return (cl_block *)gpr_atm_acq_load(&clb->block); -} - -/* Functions that operate on cl_block_list_struct's */ - -static void cl_block_list_struct_initialize(cl_block_list_struct *bls, - cl_block *block) { - bls->next = bls->prev = bls; - bls->block = block; -} - -/* Functions that operate on cl_block_list's */ - -static void cl_block_list_initialize(cl_block_list *list) { - list->count = 0; - cl_block_list_struct_initialize(&list->ht, NULL); -} - -/* Returns head of *this, or NULL if empty. */ -static cl_block *cl_block_list_head(cl_block_list *list) { - return list->ht.next->block; -} - -/* Insert element *e after *pos. */ -static void cl_block_list_insert(cl_block_list *list, cl_block_list_struct *pos, - cl_block_list_struct *e) { - list->count++; - e->next = pos->next; - e->prev = pos; - e->next->prev = e; - e->prev->next = e; -} - -/* Insert block at the head of the list */ -static void cl_block_list_insert_at_head(cl_block_list *list, cl_block *block) { - cl_block_list_insert(list, &list->ht, &block->link); -} - -/* Insert block at the tail of the list */ -static void cl_block_list_insert_at_tail(cl_block_list *list, cl_block *block) { - cl_block_list_insert(list, list->ht.prev, &block->link); -} - -/* Removes block *b. Requires *b be in the list. */ -static void cl_block_list_remove(cl_block_list *list, cl_block *b) { - list->count--; - b->link.next->prev = b->link.prev; - b->link.prev->next = b->link.next; -} - -/* Functions that operate on cl_block's */ - -static void cl_block_initialize(cl_block *block, char *buffer) { - block->buffer = buffer; - gpr_atm_rel_store(&block->writer_lock, 0); - gpr_atm_rel_store(&block->reader_lock, 0); - gpr_atm_rel_store(&block->bytes_committed, 0); - block->bytes_read = 0; - cl_block_list_struct_initialize(&block->link, block); -} - -/* Guards against exposing partially written buffer to the reader. */ -static void cl_block_set_bytes_committed(cl_block *block, - int32_t bytes_committed) { - gpr_atm_rel_store(&block->bytes_committed, bytes_committed); -} - -static int32_t cl_block_get_bytes_committed(cl_block *block) { - return gpr_atm_acq_load(&block->bytes_committed); -} - -/* Tries to disable future read/write access to this block. Succeeds if: - - no in-progress write AND - - no in-progress read AND - - 'discard_data' set to true OR no unread data - On success, clears the block state and returns with writer_lock_ and - reader_lock_ held. These locks are released by a subsequent - cl_block_access_enable() call. */ -static int cl_block_try_disable_access(cl_block *block, int discard_data) { - if (!cl_try_lock(&block->writer_lock)) { - return 0; - } - if (!cl_try_lock(&block->reader_lock)) { - cl_unlock(&block->writer_lock); - return 0; - } - if (!discard_data && - (block->bytes_read != cl_block_get_bytes_committed(block))) { - cl_unlock(&block->reader_lock); - cl_unlock(&block->writer_lock); - return 0; - } - cl_block_set_bytes_committed(block, 0); - block->bytes_read = 0; - return 1; -} - -static void cl_block_enable_access(cl_block *block) { - cl_unlock(&block->reader_lock); - cl_unlock(&block->writer_lock); -} - -/* Returns with writer_lock held. */ -static void *cl_block_start_write(cl_block *block, size_t size) { - int32_t bytes_committed; - if (!cl_try_lock(&block->writer_lock)) { - return NULL; - } - bytes_committed = cl_block_get_bytes_committed(block); - if (bytes_committed + size > CENSUS_LOG_MAX_RECORD_SIZE) { - cl_unlock(&block->writer_lock); - return NULL; - } - return block->buffer + bytes_committed; -} - -/* Releases writer_lock and increments committed bytes by 'bytes_written'. - 'bytes_written' must be <= 'size' specified in the corresponding - StartWrite() call. This function is thread-safe. */ -static void cl_block_end_write(cl_block *block, size_t bytes_written) { - cl_block_set_bytes_committed( - block, cl_block_get_bytes_committed(block) + bytes_written); - cl_unlock(&block->writer_lock); -} - -/* Returns a pointer to the first unread byte in buffer. The number of bytes - available are returned in 'bytes_available'. Acquires reader lock that is - released by a subsequent cl_block_end_read() call. Returns NULL if: - - read in progress - - no data available */ -static void *cl_block_start_read(cl_block *block, size_t *bytes_available) { - void *record; - if (!cl_try_lock(&block->reader_lock)) { - return NULL; - } - /* bytes_committed may change from under us. Use bytes_available to update - bytes_read below. */ - *bytes_available = cl_block_get_bytes_committed(block) - block->bytes_read; - if (*bytes_available == 0) { - cl_unlock(&block->reader_lock); - return NULL; - } - record = block->buffer + block->bytes_read; - block->bytes_read += *bytes_available; - return record; -} - -static void cl_block_end_read(cl_block *block) { - cl_unlock(&block->reader_lock); -} - -/* Internal functions operating on g_log */ - -/* Allocates a new free block (or recycles an available dirty block if log is - configured to discard old records). Returns NULL if out-of-space. */ -static cl_block *cl_allocate_block(void) { - cl_block *block = cl_block_list_head(&g_log.free_block_list); - if (block != NULL) { - cl_block_list_remove(&g_log.free_block_list, block); - return block; - } - if (!g_log.discard_old_records) { - /* No free block and log is configured to keep old records. */ - return NULL; - } - /* Recycle dirty block. Start from the oldest. */ - for (block = cl_block_list_head(&g_log.dirty_block_list); block != NULL; - block = block->link.next->block) { - if (cl_block_try_disable_access(block, 1 /* discard data */)) { - cl_block_list_remove(&g_log.dirty_block_list, block); - return block; - } - } - return NULL; -} - -/* Allocates a new block and updates core id => block mapping. 'old_block' - points to the block that the caller thinks is attached to - 'core_id'. 'old_block' may be NULL. Returns non-zero if: - - allocated a new block OR - - 'core_id' => 'old_block' mapping changed (another thread allocated a - block before lock was acquired). */ -static int cl_allocate_core_local_block(int32_t core_id, cl_block *old_block) { - /* Now that we have the lock, check if core-local mapping has changed. */ - cl_core_local_block *core_local_block = &g_log.core_local_blocks[core_id]; - cl_block *block = cl_core_local_block_get_block(core_local_block); - if ((block != NULL) && (block != old_block)) { - return 1; - } - if (block != NULL) { - cl_core_local_block_set_block(core_local_block, NULL); - cl_block_list_insert_at_tail(&g_log.dirty_block_list, block); - } - block = cl_allocate_block(); - if (block == NULL) { - gpr_atm_rel_store(&g_log.is_full, 1); - return 0; - } - cl_core_local_block_set_block(core_local_block, block); - cl_block_enable_access(block); - return 1; -} - -static cl_block *cl_get_block(void *record) { - uintptr_t p = (uintptr_t)((char *)record - g_log.buffer); - uintptr_t index = p >> CENSUS_LOG_2_MAX_RECORD_SIZE; - return &g_log.blocks[index]; -} - -/* Gets the next block to read and tries to free 'prev' block (if not NULL). - Returns NULL if reached the end. */ -static cl_block *cl_next_block_to_read(cl_block *prev) { - cl_block *block = NULL; - if (g_log.read_iterator_state == g_log.num_cores) { - /* We are traversing dirty list; find the next dirty block. */ - if (prev != NULL) { - /* Try to free the previous block if there is no unread data. This block - may have unread data if previously incomplete record completed between - read_next() calls. */ - block = prev->link.next->block; - if (cl_block_try_disable_access(prev, 0 /* do not discard data */)) { - cl_block_list_remove(&g_log.dirty_block_list, prev); - cl_block_list_insert_at_head(&g_log.free_block_list, prev); - gpr_atm_rel_store(&g_log.is_full, 0); - } - } else { - block = cl_block_list_head(&g_log.dirty_block_list); - } - if (block != NULL) { - return block; - } - /* We are done with the dirty list; moving on to core-local blocks. */ - } - while (g_log.read_iterator_state > 0) { - g_log.read_iterator_state--; - block = cl_core_local_block_get_block( - &g_log.core_local_blocks[g_log.read_iterator_state]); - if (block != NULL) { - return block; - } - } - return NULL; -} - -/* External functions: primary stats_log interface */ -void census_log_initialize(size_t size_in_mb, int discard_old_records) { - int32_t ix; - /* Check cacheline alignment. */ - GPR_ASSERT(sizeof(cl_block) % GPR_CACHELINE_SIZE == 0); - GPR_ASSERT(sizeof(cl_core_local_block) % GPR_CACHELINE_SIZE == 0); - GPR_ASSERT(!g_log.initialized); - g_log.discard_old_records = discard_old_records; - g_log.num_cores = gpr_cpu_num_cores(); - /* Ensure at least as many blocks as there are cores. */ - g_log.num_blocks = GPR_MAX( - g_log.num_cores, (size_in_mb << 20) >> CENSUS_LOG_2_MAX_RECORD_SIZE); - gpr_mu_init(&g_log.lock); - g_log.read_iterator_state = 0; - g_log.block_being_read = NULL; - gpr_atm_rel_store(&g_log.is_full, 0); - g_log.core_local_blocks = (cl_core_local_block *)gpr_malloc_aligned( - g_log.num_cores * sizeof(cl_core_local_block), GPR_CACHELINE_SIZE_LOG); - memset(g_log.core_local_blocks, 0, - g_log.num_cores * sizeof(cl_core_local_block)); - g_log.blocks = (cl_block *)gpr_malloc_aligned( - g_log.num_blocks * sizeof(cl_block), GPR_CACHELINE_SIZE_LOG); - memset(g_log.blocks, 0, g_log.num_blocks * sizeof(cl_block)); - g_log.buffer = gpr_malloc(g_log.num_blocks * CENSUS_LOG_MAX_RECORD_SIZE); - memset(g_log.buffer, 0, g_log.num_blocks * CENSUS_LOG_MAX_RECORD_SIZE); - cl_block_list_initialize(&g_log.free_block_list); - cl_block_list_initialize(&g_log.dirty_block_list); - for (ix = 0; ix < g_log.num_blocks; ++ix) { - cl_block *block = g_log.blocks + ix; - cl_block_initialize(block, - g_log.buffer + (CENSUS_LOG_MAX_RECORD_SIZE * ix)); - cl_block_try_disable_access(block, 1 /* discard data */); - cl_block_list_insert_at_tail(&g_log.free_block_list, block); - } - gpr_atm_rel_store(&g_log.out_of_space_count, 0); - g_log.initialized = 1; -} - -void census_log_shutdown(void) { - GPR_ASSERT(g_log.initialized); - gpr_mu_destroy(&g_log.lock); - gpr_free_aligned(g_log.core_local_blocks); - g_log.core_local_blocks = NULL; - gpr_free_aligned(g_log.blocks); - g_log.blocks = NULL; - gpr_free(g_log.buffer); - g_log.buffer = NULL; - g_log.initialized = 0; -} - -void *census_log_start_write(size_t size) { - /* Used to bound number of times block allocation is attempted. */ - int32_t attempts_remaining = g_log.num_blocks; - /* TODO(aveitch): move this inside the do loop when current_cpu is fixed */ - int32_t core_id = gpr_cpu_current_cpu(); - GPR_ASSERT(g_log.initialized); - if (size > CENSUS_LOG_MAX_RECORD_SIZE) { - return NULL; - } - do { - int allocated; - void *record = NULL; - cl_block *block = - cl_core_local_block_get_block(&g_log.core_local_blocks[core_id]); - if (block && (record = cl_block_start_write(block, size))) { - return record; - } - /* Need to allocate a new block. We are here if: - - No block associated with the core OR - - Write in-progress on the block OR - - block is out of space */ - if (gpr_atm_acq_load(&g_log.is_full)) { - gpr_atm_no_barrier_fetch_add(&g_log.out_of_space_count, 1); - return NULL; - } - gpr_mu_lock(&g_log.lock); - allocated = cl_allocate_core_local_block(core_id, block); - gpr_mu_unlock(&g_log.lock); - if (!allocated) { - gpr_atm_no_barrier_fetch_add(&g_log.out_of_space_count, 1); - return NULL; - } - } while (attempts_remaining--); - /* Give up. */ - gpr_atm_no_barrier_fetch_add(&g_log.out_of_space_count, 1); - return NULL; -} - -void census_log_end_write(void *record, size_t bytes_written) { - GPR_ASSERT(g_log.initialized); - cl_block_end_write(cl_get_block(record), bytes_written); -} - -void census_log_init_reader(void) { - GPR_ASSERT(g_log.initialized); - gpr_mu_lock(&g_log.lock); - /* If a block is locked for reading unlock it. */ - if (g_log.block_being_read != NULL) { - cl_block_end_read(g_log.block_being_read); - g_log.block_being_read = NULL; - } - g_log.read_iterator_state = g_log.num_cores; - gpr_mu_unlock(&g_log.lock); -} - -const void *census_log_read_next(size_t *bytes_available) { - GPR_ASSERT(g_log.initialized); - gpr_mu_lock(&g_log.lock); - if (g_log.block_being_read != NULL) { - cl_block_end_read(g_log.block_being_read); - } - do { - g_log.block_being_read = cl_next_block_to_read(g_log.block_being_read); - if (g_log.block_being_read != NULL) { - void *record = - cl_block_start_read(g_log.block_being_read, bytes_available); - if (record != NULL) { - gpr_mu_unlock(&g_log.lock); - return record; - } - } - } while (g_log.block_being_read != NULL); - gpr_mu_unlock(&g_log.lock); - return NULL; -} - -size_t census_log_remaining_space(void) { - size_t space; - GPR_ASSERT(g_log.initialized); - gpr_mu_lock(&g_log.lock); - if (g_log.discard_old_records) { - /* Remaining space is not meaningful; just return the entire log space. */ - space = g_log.num_blocks << CENSUS_LOG_2_MAX_RECORD_SIZE; - } else { - space = g_log.free_block_list.count * CENSUS_LOG_MAX_RECORD_SIZE; - } - gpr_mu_unlock(&g_log.lock); - return space; -} - -int census_log_out_of_space_count(void) { - GPR_ASSERT(g_log.initialized); - return gpr_atm_acq_load(&g_log.out_of_space_count); -} diff --git a/src/core/statistics/census_log.h b/src/core/statistics/census_log.h deleted file mode 100644 index e7ce0d4433..0000000000 --- a/src/core/statistics/census_log.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * - * Copyright 2015-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_STATISTICS_CENSUS_LOG_H -#define GRPC_CORE_STATISTICS_CENSUS_LOG_H - -#include - -/* Maximum record size, in bytes. */ -#define CENSUS_LOG_2_MAX_RECORD_SIZE 14 /* 2^14 = 16KB */ -#define CENSUS_LOG_MAX_RECORD_SIZE (1 << CENSUS_LOG_2_MAX_RECORD_SIZE) - -/* Initialize the statistics logging subsystem with the given log size. A log - size of 0 will result in the smallest possible log for the platform - (approximately CENSUS_LOG_MAX_RECORD_SIZE * gpr_cpu_num_cores()). If - discard_old_records is non-zero, then new records will displace older ones - when the log is full. This function must be called before any other - census_log functions. -*/ -void census_log_initialize(size_t size_in_mb, int discard_old_records); - -/* Shutdown the logging subsystem. Caller must ensure that: - - no in progress or future call to any census_log functions - - no incomplete records -*/ -void census_log_shutdown(void); - -/* Allocates and returns a 'size' bytes record and marks it in use. A - subsequent census_log_end_write() marks the record complete. The - 'bytes_written' census_log_end_write() argument must be <= - 'size'. Returns NULL if out-of-space AND: - - log is configured to keep old records OR - - all blocks are pinned by incomplete records. -*/ -void *census_log_start_write(size_t size); - -void census_log_end_write(void *record, size_t bytes_written); - -/* census_log_read_next() iterates over blocks with data and for each block - returns a pointer to the first unread byte. The number of bytes that can be - read are returned in 'bytes_available'. Reader is expected to read all - available data. Reading the data consumes it i.e. it cannot be read again. - census_log_read_next() returns NULL if the end is reached i.e last block - is read. census_log_init_reader() starts the iteration or aborts the - current iteration. -*/ -void census_log_init_reader(void); -const void *census_log_read_next(size_t *bytes_available); - -/* Returns estimated remaining space across all blocks, in bytes. If log is - configured to discard old records, returns total log space. Otherwise, - returns space available in empty blocks (partially filled blocks are - treated as full). -*/ -size_t census_log_remaining_space(void); - -/* Returns the number of times gprc_stats_log_start_write() failed due to - out-of-space. */ -int census_log_out_of_space_count(void); - -#endif /* GRPC_CORE_STATISTICS_CENSUS_LOG_H */ diff --git a/src/core/statistics/census_rpc_stats.c b/src/core/statistics/census_rpc_stats.c deleted file mode 100644 index c78d6fd612..0000000000 --- a/src/core/statistics/census_rpc_stats.c +++ /dev/null @@ -1,253 +0,0 @@ -/* - * - * Copyright 2015-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 - -#include -#include -#include -#include "src/core/statistics/census_interface.h" -#include "src/core/statistics/census_rpc_stats.h" -#include "src/core/statistics/census_tracing.h" -#include "src/core/statistics/hash_table.h" -#include "src/core/statistics/window_stats.h" -#include "src/core/support/murmur_hash.h" -#include "src/core/support/string.h" - -#define NUM_INTERVALS 3 -#define MINUTE_INTERVAL 0 -#define HOUR_INTERVAL 1 -#define TOTAL_INTERVAL 2 - -/* for easier typing */ -typedef census_per_method_rpc_stats per_method_stats; - -/* Ensure mu is only initialized once. */ -static gpr_once g_stats_store_mu_init = GPR_ONCE_INIT; -/* Guards two stats stores. */ -static gpr_mu g_mu; -static census_ht *g_client_stats_store = NULL; -static census_ht *g_server_stats_store = NULL; - -static void init_mutex(void) { gpr_mu_init(&g_mu); } - -static void init_mutex_once(void) { - gpr_once_init(&g_stats_store_mu_init, init_mutex); -} - -static int cmp_str_keys(const void *k1, const void *k2) { - return strcmp((const char *)k1, (const char *)k2); -} - -/* TODO(hongyu): replace it with cityhash64 */ -static uint64_t simple_hash(const void *k) { - size_t len = strlen(k); - uint64_t higher = gpr_murmur_hash3((const char *)k, len / 2, 0); - return higher << 32 | - gpr_murmur_hash3((const char *)k + len / 2, len - len / 2, 0); -} - -static void delete_stats(void *stats) { - census_window_stats_destroy((struct census_window_stats *)stats); -} - -static void delete_key(void *key) { gpr_free(key); } - -static const census_ht_option ht_opt = { - CENSUS_HT_POINTER /* key type */, 1999 /* n_of_buckets */, - simple_hash /* hash function */, cmp_str_keys /* key comparator */, - delete_stats /* data deleter */, delete_key /* key deleter */ -}; - -static void init_rpc_stats(void *stats) { - memset(stats, 0, sizeof(census_rpc_stats)); -} - -static void stat_add_proportion(double p, void *base, const void *addme) { - census_rpc_stats *b = (census_rpc_stats *)base; - census_rpc_stats *a = (census_rpc_stats *)addme; - b->cnt += p * a->cnt; - b->rpc_error_cnt += p * a->rpc_error_cnt; - b->app_error_cnt += p * a->app_error_cnt; - b->elapsed_time_ms += p * a->elapsed_time_ms; - b->api_request_bytes += p * a->api_request_bytes; - b->wire_request_bytes += p * a->wire_request_bytes; - b->api_response_bytes += p * a->api_response_bytes; - b->wire_response_bytes += p * a->wire_response_bytes; -} - -static void stat_add(void *base, const void *addme) { - stat_add_proportion(1.0, base, addme); -} - -static gpr_timespec min_hour_total_intervals[3] = { - {60, 0}, {3600, 0}, {36000000, 0}}; - -static const census_window_stats_stat_info window_stats_settings = { - sizeof(census_rpc_stats), init_rpc_stats, stat_add, stat_add_proportion}; - -census_rpc_stats *census_rpc_stats_create_empty(void) { - census_rpc_stats *ret = - (census_rpc_stats *)gpr_malloc(sizeof(census_rpc_stats)); - memset(ret, 0, sizeof(census_rpc_stats)); - return ret; -} - -void census_aggregated_rpc_stats_set_empty(census_aggregated_rpc_stats *data) { - int i = 0; - for (i = 0; i < data->num_entries; i++) { - if (data->stats[i].method != NULL) { - gpr_free((void *)data->stats[i].method); - } - } - if (data->stats != NULL) { - gpr_free(data->stats); - } - data->num_entries = 0; - data->stats = NULL; -} - -static void record_stats(census_ht *store, census_op_id op_id, - const census_rpc_stats *stats) { - gpr_mu_lock(&g_mu); - if (store != NULL) { - census_trace_obj *trace = NULL; - census_internal_lock_trace_store(); - trace = census_get_trace_obj_locked(op_id); - if (trace != NULL) { - const char *method_name = census_get_trace_method_name(trace); - struct census_window_stats *window_stats = NULL; - census_ht_key key; - key.ptr = (void *)method_name; - window_stats = census_ht_find(store, key); - census_internal_unlock_trace_store(); - if (window_stats == NULL) { - window_stats = census_window_stats_create(3, min_hour_total_intervals, - 30, &window_stats_settings); - key.ptr = gpr_strdup(key.ptr); - census_ht_insert(store, key, (void *)window_stats); - } - census_window_stats_add(window_stats, gpr_now(GPR_CLOCK_REALTIME), stats); - } else { - census_internal_unlock_trace_store(); - } - } - gpr_mu_unlock(&g_mu); -} - -void census_record_rpc_client_stats(census_op_id op_id, - const census_rpc_stats *stats) { - record_stats(g_client_stats_store, op_id, stats); -} - -void census_record_rpc_server_stats(census_op_id op_id, - const census_rpc_stats *stats) { - record_stats(g_server_stats_store, op_id, stats); -} - -/* Get stats from input stats store */ -static void get_stats(census_ht *store, census_aggregated_rpc_stats *data) { - GPR_ASSERT(data != NULL); - if (data->num_entries != 0) { - census_aggregated_rpc_stats_set_empty(data); - } - gpr_mu_lock(&g_mu); - if (store != NULL) { - size_t n; - unsigned i, j; - gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME); - census_ht_kv *kv = census_ht_get_all_elements(store, &n); - if (kv != NULL) { - data->num_entries = n; - data->stats = - (per_method_stats *)gpr_malloc(sizeof(per_method_stats) * n); - for (i = 0; i < n; i++) { - census_window_stats_sums sums[NUM_INTERVALS]; - for (j = 0; j < NUM_INTERVALS; j++) { - sums[j].statistic = (void *)census_rpc_stats_create_empty(); - } - data->stats[i].method = gpr_strdup(kv[i].k.ptr); - census_window_stats_get_sums(kv[i].v, now, sums); - data->stats[i].minute_stats = - *(census_rpc_stats *)sums[MINUTE_INTERVAL].statistic; - data->stats[i].hour_stats = - *(census_rpc_stats *)sums[HOUR_INTERVAL].statistic; - data->stats[i].total_stats = - *(census_rpc_stats *)sums[TOTAL_INTERVAL].statistic; - for (j = 0; j < NUM_INTERVALS; j++) { - gpr_free(sums[j].statistic); - } - } - gpr_free(kv); - } - } - gpr_mu_unlock(&g_mu); -} - -void census_get_client_stats(census_aggregated_rpc_stats *data) { - get_stats(g_client_stats_store, data); -} - -void census_get_server_stats(census_aggregated_rpc_stats *data) { - get_stats(g_server_stats_store, data); -} - -void census_stats_store_init(void) { - init_mutex_once(); - gpr_mu_lock(&g_mu); - if (g_client_stats_store == NULL && g_server_stats_store == NULL) { - g_client_stats_store = census_ht_create(&ht_opt); - g_server_stats_store = census_ht_create(&ht_opt); - } else { - gpr_log(GPR_ERROR, "Census stats store already initialized."); - } - gpr_mu_unlock(&g_mu); -} - -void census_stats_store_shutdown(void) { - init_mutex_once(); - gpr_mu_lock(&g_mu); - if (g_client_stats_store != NULL) { - census_ht_destroy(g_client_stats_store); - g_client_stats_store = NULL; - } else { - gpr_log(GPR_ERROR, "Census server stats store not initialized."); - } - if (g_server_stats_store != NULL) { - census_ht_destroy(g_server_stats_store); - g_server_stats_store = NULL; - } else { - gpr_log(GPR_ERROR, "Census client stats store not initialized."); - } - gpr_mu_unlock(&g_mu); -} diff --git a/src/core/statistics/census_rpc_stats.h b/src/core/statistics/census_rpc_stats.h deleted file mode 100644 index f7f220e45f..0000000000 --- a/src/core/statistics/census_rpc_stats.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * - * Copyright 2015-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_STATISTICS_CENSUS_RPC_STATS_H -#define GRPC_CORE_STATISTICS_CENSUS_RPC_STATS_H - -#include -#include "src/core/statistics/census_interface.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct census_rpc_stats { - uint64_t cnt; - uint64_t rpc_error_cnt; - uint64_t app_error_cnt; - double elapsed_time_ms; - double api_request_bytes; - double wire_request_bytes; - double api_response_bytes; - double wire_response_bytes; -}; - -/* Creates an empty rpc stats object on heap. */ -census_rpc_stats *census_rpc_stats_create_empty(void); - -typedef struct census_per_method_rpc_stats { - const char *method; - census_rpc_stats minute_stats; /* cumulative stats in the past minute */ - census_rpc_stats hour_stats; /* cumulative stats in the past hour */ - census_rpc_stats total_stats; /* cumulative stats from last gc */ -} census_per_method_rpc_stats; - -typedef struct census_aggregated_rpc_stats { - int num_entries; - census_per_method_rpc_stats *stats; -} census_aggregated_rpc_stats; - -/* Initializes an aggregated rpc stats object to an empty state. */ -void census_aggregated_rpc_stats_set_empty(census_aggregated_rpc_stats *data); - -/* Records client side stats of a rpc. */ -void census_record_rpc_client_stats(census_op_id op_id, - const census_rpc_stats *stats); - -/* Records server side stats of a rpc. */ -void census_record_rpc_server_stats(census_op_id op_id, - const census_rpc_stats *stats); - -/* The following two functions are intended for inprocess query of - per-service per-method stats from grpc implementations. */ - -/* Populates *data_map with server side aggregated per-service per-method - stats. - DO NOT CALL from outside of grpc code. */ -void census_get_server_stats(census_aggregated_rpc_stats *data_map); - -/* Populates *data_map with client side aggregated per-service per-method - stats. - DO NOT CALL from outside of grpc code. */ -void census_get_client_stats(census_aggregated_rpc_stats *data_map); - -void census_stats_store_init(void); -void census_stats_store_shutdown(void); - -#ifdef __cplusplus -} -#endif - -#endif /* GRPC_CORE_STATISTICS_CENSUS_RPC_STATS_H */ diff --git a/src/core/statistics/census_tracing.c b/src/core/statistics/census_tracing.c deleted file mode 100644 index ad82498eba..0000000000 --- a/src/core/statistics/census_tracing.c +++ /dev/null @@ -1,241 +0,0 @@ -/* - * - * Copyright 2015-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/statistics/census_tracing.h" -#include "src/core/statistics/census_interface.h" - -#include -#include - -#include -#include -#include -#include -#include "src/core/statistics/hash_table.h" -#include "src/core/support/string.h" - -void census_trace_obj_destroy(census_trace_obj *obj) { - census_trace_annotation *p = obj->annotations; - while (p != NULL) { - census_trace_annotation *next = p->next; - gpr_free(p); - p = next; - } - gpr_free(obj->method); - gpr_free(obj); -} - -static void delete_trace_obj(void *obj) { - census_trace_obj_destroy((census_trace_obj *)obj); -} - -static const census_ht_option ht_opt = { - CENSUS_HT_UINT64 /* key type */, - 571 /* n_of_buckets */, - NULL /* hash */, - NULL /* compare_keys */, - delete_trace_obj /* delete data */, - NULL /* delete key */ -}; - -static gpr_once g_init_mutex_once = GPR_ONCE_INIT; -static gpr_mu g_mu; /* Guards following two static variables. */ -static census_ht *g_trace_store = NULL; -static uint64_t g_id = 0; - -static census_ht_key op_id_as_key(census_op_id *id) { - return *(census_ht_key *)id; -} - -static uint64_t op_id_2_uint64(census_op_id *id) { - uint64_t ret; - memcpy(&ret, id, sizeof(census_op_id)); - return ret; -} - -static void init_mutex(void) { gpr_mu_init(&g_mu); } - -static void init_mutex_once(void) { - gpr_once_init(&g_init_mutex_once, init_mutex); -} - -census_op_id census_tracing_start_op(void) { - gpr_mu_lock(&g_mu); - { - census_trace_obj *ret = gpr_malloc(sizeof(census_trace_obj)); - memset(ret, 0, sizeof(census_trace_obj)); - g_id++; - memcpy(&ret->id, &g_id, sizeof(census_op_id)); - ret->rpc_stats.cnt = 1; - ret->ts = gpr_now(GPR_CLOCK_REALTIME); - census_ht_insert(g_trace_store, op_id_as_key(&ret->id), (void *)ret); - gpr_log(GPR_DEBUG, "Start tracing for id %lu", g_id); - gpr_mu_unlock(&g_mu); - return ret->id; - } -} - -int census_add_method_tag(census_op_id op_id, const char *method) { - int ret = 0; - census_trace_obj *trace = NULL; - gpr_mu_lock(&g_mu); - trace = census_ht_find(g_trace_store, op_id_as_key(&op_id)); - if (trace == NULL) { - ret = 1; - } else { - trace->method = gpr_strdup(method); - } - gpr_mu_unlock(&g_mu); - return ret; -} - -void census_tracing_print(census_op_id op_id, const char *anno_txt) { - census_trace_obj *trace = NULL; - gpr_mu_lock(&g_mu); - trace = census_ht_find(g_trace_store, op_id_as_key(&op_id)); - if (trace != NULL) { - census_trace_annotation *anno = gpr_malloc(sizeof(census_trace_annotation)); - anno->ts = gpr_now(GPR_CLOCK_REALTIME); - { - char *d = anno->txt; - const char *s = anno_txt; - int n = 0; - for (; n < CENSUS_MAX_ANNOTATION_LENGTH && *s != '\0'; ++n) { - *d++ = *s++; - } - *d = '\0'; - } - anno->next = trace->annotations; - trace->annotations = anno; - } - gpr_mu_unlock(&g_mu); -} - -void census_tracing_end_op(census_op_id op_id) { - census_trace_obj *trace = NULL; - gpr_mu_lock(&g_mu); - trace = census_ht_find(g_trace_store, op_id_as_key(&op_id)); - if (trace != NULL) { - trace->rpc_stats.elapsed_time_ms = gpr_timespec_to_micros( - gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), trace->ts)); - gpr_log(GPR_DEBUG, "End tracing for id %lu, method %s, latency %f us", - op_id_2_uint64(&op_id), trace->method, - trace->rpc_stats.elapsed_time_ms); - census_ht_erase(g_trace_store, op_id_as_key(&op_id)); - } - gpr_mu_unlock(&g_mu); -} - -void census_tracing_init(void) { - init_mutex_once(); - gpr_mu_lock(&g_mu); - if (g_trace_store == NULL) { - g_id = 1; - g_trace_store = census_ht_create(&ht_opt); - } else { - gpr_log(GPR_ERROR, "Census trace store already initialized."); - } - gpr_mu_unlock(&g_mu); -} - -void census_tracing_shutdown(void) { - gpr_mu_lock(&g_mu); - if (g_trace_store != NULL) { - census_ht_destroy(g_trace_store); - g_trace_store = NULL; - } else { - gpr_log(GPR_ERROR, "Census trace store is not initialized."); - } - gpr_mu_unlock(&g_mu); -} - -void census_internal_lock_trace_store(void) { gpr_mu_lock(&g_mu); } - -void census_internal_unlock_trace_store(void) { gpr_mu_unlock(&g_mu); } - -census_trace_obj *census_get_trace_obj_locked(census_op_id op_id) { - if (g_trace_store == NULL) { - gpr_log(GPR_ERROR, "Census trace store is not initialized."); - return NULL; - } - return (census_trace_obj *)census_ht_find(g_trace_store, - op_id_as_key(&op_id)); -} - -const char *census_get_trace_method_name(const census_trace_obj *trace) { - return trace->method; -} - -static census_trace_annotation *dup_annotation_chain( - census_trace_annotation *from) { - census_trace_annotation *ret = NULL; - census_trace_annotation **to = &ret; - for (; from != NULL; from = from->next) { - *to = gpr_malloc(sizeof(census_trace_annotation)); - memcpy(*to, from, sizeof(census_trace_annotation)); - to = &(*to)->next; - } - return ret; -} - -static census_trace_obj *trace_obj_dup(census_trace_obj *from) { - census_trace_obj *to = NULL; - GPR_ASSERT(from != NULL); - to = gpr_malloc(sizeof(census_trace_obj)); - to->id = from->id; - to->ts = from->ts; - to->rpc_stats = from->rpc_stats; - to->method = gpr_strdup(from->method); - to->annotations = dup_annotation_chain(from->annotations); - return to; -} - -census_trace_obj **census_get_active_ops(int *num_active_ops) { - census_trace_obj **ret = NULL; - gpr_mu_lock(&g_mu); - if (g_trace_store != NULL) { - size_t n = 0; - census_ht_kv *all_kvs = census_ht_get_all_elements(g_trace_store, &n); - *num_active_ops = (int)n; - if (n != 0) { - size_t i = 0; - ret = gpr_malloc(sizeof(census_trace_obj *) * n); - for (i = 0; i < n; i++) { - ret[i] = trace_obj_dup((census_trace_obj *)all_kvs[i].v); - } - } - gpr_free(all_kvs); - } - gpr_mu_unlock(&g_mu); - return ret; -} diff --git a/src/core/statistics/census_tracing.h b/src/core/statistics/census_tracing.h deleted file mode 100644 index b611e95bf4..0000000000 --- a/src/core/statistics/census_tracing.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * - * Copyright 2015-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_STATISTICS_CENSUS_TRACING_H -#define GRPC_CORE_STATISTICS_CENSUS_TRACING_H - -#include -#include "src/core/statistics/census_rpc_stats.h" - -/* WARNING: The data structures and APIs provided by this file are for GRPC - library's internal use ONLY. They might be changed in backward-incompatible - ways and are not subject to any deprecation policy. - They are not recommended for external use. - */ -#ifdef __cplusplus -extern "C" { -#endif - -/* Struct for a trace annotation. */ -typedef struct census_trace_annotation { - gpr_timespec ts; /* timestamp of the annotation */ - char txt[CENSUS_MAX_ANNOTATION_LENGTH + 1]; /* actual txt annotation */ - struct census_trace_annotation *next; -} census_trace_annotation; - -typedef struct census_trace_obj { - census_op_id id; - gpr_timespec ts; - census_rpc_stats rpc_stats; - char *method; - census_trace_annotation *annotations; -} census_trace_obj; - -/* Deletes trace object. */ -void census_trace_obj_destroy(census_trace_obj *obj); - -/* Initializes trace store. This function is thread safe. */ -void census_tracing_init(void); - -/* Shutsdown trace store. This function is thread safe. */ -void census_tracing_shutdown(void); - -/* Gets trace obj corresponding to the input op_id. Returns NULL if trace store - is not initialized or trace obj is not found. Requires trace store being - locked before calling this function. */ -census_trace_obj *census_get_trace_obj_locked(census_op_id op_id); - -/* The following two functions acquire and release the trace store global lock. - They are for census internal use only. */ -void census_internal_lock_trace_store(void); -void census_internal_unlock_trace_store(void); - -/* Gets method name associated with the input trace object. */ -const char *census_get_trace_method_name(const census_trace_obj *trace); - -/* Returns an array of pointers to trace objects of currently active operations - and fills in number of active operations. Returns NULL if there are no active - operations. - Caller owns the returned objects. */ -census_trace_obj **census_get_active_ops(int *num_active_ops); - -#ifdef __cplusplus -} -#endif - -#endif /* GRPC_CORE_STATISTICS_CENSUS_TRACING_H */ diff --git a/src/core/statistics/hash_table.c b/src/core/statistics/hash_table.c deleted file mode 100644 index 3ef79c0d7d..0000000000 --- a/src/core/statistics/hash_table.c +++ /dev/null @@ -1,303 +0,0 @@ -/* - * - * Copyright 2015-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/statistics/hash_table.h" - -#include -#include - -#include -#include -#include - -#define CENSUS_HT_NUM_BUCKETS 1999 - -/* A single hash table data entry */ -typedef struct ht_entry { - census_ht_key key; - void *data; - struct ht_entry *next; -} ht_entry; - -/* hash table bucket */ -typedef struct bucket { - /* NULL if bucket is empty */ - ht_entry *next; - /* -1 if all buckets are empty. */ - int32_t prev_non_empty_bucket; - /* -1 if all buckets are empty. */ - int32_t next_non_empty_bucket; -} bucket; - -struct unresizable_hash_table { - /* Number of entries in the table */ - size_t size; - /* Number of buckets */ - uint32_t num_buckets; - /* Array of buckets initialized at creation time. Memory consumption is - 16 bytes per bucket on a 64-bit platform. */ - bucket *buckets; - /* Index of the first non-empty bucket. -1 iff size == 0. */ - int32_t first_non_empty_bucket; - /* Index of the last non_empty bucket. -1 iff size == 0. */ - int32_t last_non_empty_bucket; - /* Immutable options of this hash table, initialized at creation time. */ - census_ht_option options; -}; - -typedef struct entry_locator { - int32_t bucket_idx; - int is_first_in_chain; - int found; - ht_entry *prev_entry; -} entry_locator; - -/* Asserts if option is not valid. */ -void check_options(const census_ht_option *option) { - GPR_ASSERT(option != NULL); - GPR_ASSERT(option->num_buckets > 0); - GPR_ASSERT(option->key_type == CENSUS_HT_UINT64 || - option->key_type == CENSUS_HT_POINTER); - if (option->key_type == CENSUS_HT_UINT64) { - GPR_ASSERT(option->hash == NULL); - } else if (option->key_type == CENSUS_HT_POINTER) { - GPR_ASSERT(option->hash != NULL); - GPR_ASSERT(option->compare_keys != NULL); - } -} - -#define REMOVE_NEXT(options, ptr) \ - do { \ - ht_entry *tmp = (ptr)->next; \ - (ptr)->next = tmp->next; \ - delete_entry(options, tmp); \ - } while (0) - -static void delete_entry(const census_ht_option *opt, ht_entry *p) { - if (opt->delete_data != NULL) { - opt->delete_data(p->data); - } - if (opt->delete_key != NULL) { - opt->delete_key(p->key.ptr); - } - gpr_free(p); -} - -static uint64_t hash(const census_ht_option *opt, census_ht_key key) { - return opt->key_type == CENSUS_HT_UINT64 ? key.val : opt->hash(key.ptr); -} - -census_ht *census_ht_create(const census_ht_option *option) { - int i; - census_ht *ret = NULL; - check_options(option); - ret = (census_ht *)gpr_malloc(sizeof(census_ht)); - ret->size = 0; - ret->num_buckets = option->num_buckets; - ret->buckets = (bucket *)gpr_malloc(sizeof(bucket) * ret->num_buckets); - ret->options = *option; - /* initialize each bucket */ - for (i = 0; i < ret->options.num_buckets; i++) { - ret->buckets[i].prev_non_empty_bucket = -1; - ret->buckets[i].next_non_empty_bucket = -1; - ret->buckets[i].next = NULL; - } - return ret; -} - -static int32_t find_bucket_idx(const census_ht *ht, census_ht_key key) { - return hash(&ht->options, key) % ht->num_buckets; -} - -static int keys_match(const census_ht_option *opt, const ht_entry *p, - const census_ht_key key) { - GPR_ASSERT(opt->key_type == CENSUS_HT_UINT64 || - opt->key_type == CENSUS_HT_POINTER); - if (opt->key_type == CENSUS_HT_UINT64) return p->key.val == key.val; - return !opt->compare_keys((p->key).ptr, key.ptr); -} - -static entry_locator ht_find(const census_ht *ht, census_ht_key key) { - entry_locator loc = {0, 0, 0, NULL}; - int32_t idx = 0; - ht_entry *ptr = NULL; - GPR_ASSERT(ht != NULL); - idx = find_bucket_idx(ht, key); - ptr = ht->buckets[idx].next; - if (ptr == NULL) { - /* bucket is empty */ - return loc; - } - if (keys_match(&ht->options, ptr, key)) { - loc.bucket_idx = idx; - loc.is_first_in_chain = 1; - loc.found = 1; - return loc; - } else { - for (; ptr->next != NULL; ptr = ptr->next) { - if (keys_match(&ht->options, ptr->next, key)) { - loc.bucket_idx = idx; - loc.is_first_in_chain = 0; - loc.found = 1; - loc.prev_entry = ptr; - return loc; - } - } - } - /* Could not find the key */ - return loc; -} - -void *census_ht_find(const census_ht *ht, census_ht_key key) { - entry_locator loc = ht_find(ht, key); - if (loc.found == 0) { - return NULL; - } - return loc.is_first_in_chain ? ht->buckets[loc.bucket_idx].next->data - : loc.prev_entry->next->data; -} - -void census_ht_insert(census_ht *ht, census_ht_key key, void *data) { - int32_t idx = find_bucket_idx(ht, key); - ht_entry *ptr = NULL; - entry_locator loc = ht_find(ht, key); - if (loc.found) { - /* Replace old value with new value. */ - ptr = loc.is_first_in_chain ? ht->buckets[loc.bucket_idx].next - : loc.prev_entry->next; - if (ht->options.delete_data != NULL) { - ht->options.delete_data(ptr->data); - } - ptr->data = data; - return; - } - - /* first entry in the table. */ - if (ht->size == 0) { - ht->buckets[idx].next_non_empty_bucket = -1; - ht->buckets[idx].prev_non_empty_bucket = -1; - ht->first_non_empty_bucket = idx; - ht->last_non_empty_bucket = idx; - } else if (ht->buckets[idx].next == NULL) { - /* first entry in the bucket. */ - ht->buckets[ht->last_non_empty_bucket].next_non_empty_bucket = idx; - ht->buckets[idx].prev_non_empty_bucket = ht->last_non_empty_bucket; - ht->buckets[idx].next_non_empty_bucket = -1; - ht->last_non_empty_bucket = idx; - } - ptr = (ht_entry *)gpr_malloc(sizeof(ht_entry)); - ptr->key = key; - ptr->data = data; - ptr->next = ht->buckets[idx].next; - ht->buckets[idx].next = ptr; - ht->size++; -} - -void census_ht_erase(census_ht *ht, census_ht_key key) { - entry_locator loc = ht_find(ht, key); - if (loc.found == 0) { - /* noop if not found */ - return; - } - ht->size--; - if (loc.is_first_in_chain) { - bucket *b = &ht->buckets[loc.bucket_idx]; - GPR_ASSERT(b->next != NULL); - /* The only entry in the bucket */ - if (b->next->next == NULL) { - int prev = b->prev_non_empty_bucket; - int next = b->next_non_empty_bucket; - if (prev != -1) { - ht->buckets[prev].next_non_empty_bucket = next; - } else { - ht->first_non_empty_bucket = next; - } - if (next != -1) { - ht->buckets[next].prev_non_empty_bucket = prev; - } else { - ht->last_non_empty_bucket = prev; - } - } - REMOVE_NEXT(&ht->options, b); - } else { - GPR_ASSERT(loc.prev_entry->next != NULL); - REMOVE_NEXT(&ht->options, loc.prev_entry); - } -} - -/* Returns NULL if input table is empty. */ -census_ht_kv *census_ht_get_all_elements(const census_ht *ht, size_t *num) { - census_ht_kv *ret = NULL; - int i = 0; - int32_t idx = -1; - GPR_ASSERT(ht != NULL && num != NULL); - *num = ht->size; - if (*num == 0) { - return NULL; - } - - ret = (census_ht_kv *)gpr_malloc(sizeof(census_ht_kv) * ht->size); - idx = ht->first_non_empty_bucket; - while (idx >= 0) { - ht_entry *ptr = ht->buckets[idx].next; - for (; ptr != NULL; ptr = ptr->next) { - ret[i].k = ptr->key; - ret[i].v = ptr->data; - i++; - } - idx = ht->buckets[idx].next_non_empty_bucket; - } - return ret; -} - -static void ht_delete_entry_chain(const census_ht_option *options, - ht_entry *first) { - if (first == NULL) { - return; - } - if (first->next != NULL) { - ht_delete_entry_chain(options, first->next); - } - delete_entry(options, first); -} - -void census_ht_destroy(census_ht *ht) { - unsigned i; - for (i = 0; i < ht->num_buckets; ++i) { - ht_delete_entry_chain(&ht->options, ht->buckets[i].next); - } - gpr_free(ht->buckets); - gpr_free(ht); -} - -size_t census_ht_get_size(const census_ht *ht) { return ht->size; } diff --git a/src/core/statistics/hash_table.h b/src/core/statistics/hash_table.h deleted file mode 100644 index f4bf2ba49a..0000000000 --- a/src/core/statistics/hash_table.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - * - * Copyright 2015-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_STATISTICS_HASH_TABLE_H -#define GRPC_CORE_STATISTICS_HASH_TABLE_H - -#include - -#include - -/* A chain based hash table with fixed number of buckets. - Your probably shouldn't use this code directly. It is implemented for the - use case in census trace store and stats store, where number of entries in - the table is in the scale of upto several thousands, entries are added and - removed from the table very frequently (~100k/s), the frequency of find() - operations is roughly several times of the frequency of insert() and erase() - Comparing to find(), the insert(), erase() and get_all_entries() operations - are much less freqent (<1/s). - - Per bucket memory overhead is about (8 + sizeof(intptr_t) bytes. - Per entry memory overhead is about (8 + 2 * sizeof(intptr_t) bytes. - - All functions are not thread-safe. Synchronization will be provided in the - upper layer (in trace store and stats store). -*/ - -/* Opaque hash table struct */ -typedef struct unresizable_hash_table census_ht; - -/* Currently, the hash_table can take two types of keys. (uint64 for trace - store and const char* for stats store). */ -typedef union { - uint64_t val; - void *ptr; -} census_ht_key; - -typedef enum census_ht_key_type { - CENSUS_HT_UINT64 = 0, - CENSUS_HT_POINTER = 1 -} census_ht_key_type; - -typedef struct census_ht_option { - /* Type of hash key */ - census_ht_key_type key_type; - /* Desired number of buckets, preferably a prime number */ - int32_t num_buckets; - /* Fucntion to calculate uint64 hash value of the key. Only takes effect if - key_type is POINTER. */ - uint64_t (*hash)(const void *); - /* Function to compare two keys, returns 0 iff equal. Only takes effect if - key_type is POINTER */ - int (*compare_keys)(const void *k1, const void *k2); - /* Value deleter. NULL if no specialized delete function is needed. */ - void (*delete_data)(void *); - /* Key deleter. NULL if table does not own the key. (e.g. key is part of the - value or key is not owned by the table.) */ - void (*delete_key)(void *); -} census_ht_option; - -/* Creates a hashtable with fixed number of buckets according to the settings - specified in 'options' arg. Function pointers "hash" and "compare_keys" must - be provided if key_type is POINTER. Asserts if fail to create. */ -census_ht *census_ht_create(const census_ht_option *options); - -/* Deletes hash table instance. Frees all dynamic memory owned by ht.*/ -void census_ht_destroy(census_ht *ht); - -/* Inserts the input key-val pair into hash_table. If an entry with the same key - exists in the table, the corresponding value will be overwritten by the input - val. */ -void census_ht_insert(census_ht *ht, census_ht_key key, void *val); - -/* Returns pointer to data, returns NULL if not found. */ -void *census_ht_find(const census_ht *ht, census_ht_key key); - -/* Erase hash table entry with input key. Noop if key is not found. */ -void census_ht_erase(census_ht *ht, census_ht_key key); - -typedef struct census_ht_kv { - census_ht_key k; - void *v; -} census_ht_kv; - -/* Returns an array of pointers to all values in the hash table. Order of the - elements can be arbitrary. Sets 'num' to the size of returned array. Caller - owns returned array. */ -census_ht_kv *census_ht_get_all_elements(const census_ht *ht, size_t *num); - -/* Returns number of elements kept. */ -size_t census_ht_get_size(const census_ht *ht); - -/* Functor applied on each key-value pair while iterating through entries in the - table. The functor should not mutate data. */ -typedef void (*census_ht_itr_cb)(census_ht_key key, const void *val_ptr, - void *state); - -/* Iterates through all key-value pairs in the hash_table. The callback function - should not invalidate data entries. */ -uint64_t census_ht_for_all(const census_ht *ht, census_ht_itr_cb); - -#endif /* GRPC_CORE_STATISTICS_HASH_TABLE_H */ diff --git a/src/core/statistics/window_stats.c b/src/core/statistics/window_stats.c deleted file mode 100644 index eb296865a0..0000000000 --- a/src/core/statistics/window_stats.c +++ /dev/null @@ -1,316 +0,0 @@ -/* - * - * Copyright 2015-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/statistics/window_stats.h" -#include -#include -#include -#include -#include -#include -#include - -/* typedefs make typing long names easier. Use cws (for census_window_stats) */ -typedef census_window_stats_stat_info cws_stat_info; -typedef struct census_window_stats_sum cws_sum; - -/* Each interval is composed of a number of buckets, which hold a count of - entries and a single statistic */ -typedef struct census_window_stats_bucket { - int64_t count; - void *statistic; -} cws_bucket; - -/* Each interval has a set of buckets, and the variables needed to keep - track of their current state */ -typedef struct census_window_stats_interval_stats { - /* The buckets. There will be 'granularity' + 1 of these. */ - cws_bucket *buckets; - /* Index of the bucket containing the smallest time interval. */ - int bottom_bucket; - /* The smallest time storable in the current window. */ - int64_t bottom; - /* The largest time storable in the current window + 1ns */ - int64_t top; - /* The width of each bucket in ns. */ - int64_t width; -} cws_interval_stats; - -typedef struct census_window_stats { - /* Number of intervals. */ - int nintervals; - /* Number of buckets in each interval. 'granularity' + 1. */ - int nbuckets; - /* Record of stat_info. */ - cws_stat_info stat_info; - /* Stats for each interval. */ - cws_interval_stats *interval_stats; - /* The time the newset stat was recorded. */ - int64_t newest_time; -} window_stats; - -/* Calculate an actual bucket index from a logical index 'IDX'. Other - parameters supply information on the interval struct and overall stats. */ -#define BUCKET_IDX(IS, IDX, WSTATS) \ - ((IS->bottom_bucket + (IDX)) % WSTATS->nbuckets) - -/* The maximum seconds value we can have in a valid timespec. More than this - will result in overflow in timespec_to_ns(). This works out to ~292 years. - TODO: consider using doubles instead of int64. */ -static int64_t max_seconds = (GPR_INT64_MAX - GPR_NS_PER_SEC) / GPR_NS_PER_SEC; - -static int64_t timespec_to_ns(const gpr_timespec ts) { - if (ts.tv_sec > max_seconds) { - return GPR_INT64_MAX - 1; - } - return ts.tv_sec * GPR_NS_PER_SEC + ts.tv_nsec; -} - -static void cws_initialize_statistic(void *statistic, - const cws_stat_info *stat_info) { - if (stat_info->stat_initialize == NULL) { - memset(statistic, 0, stat_info->stat_size); - } else { - stat_info->stat_initialize(statistic); - } -} - -/* Create and initialize a statistic */ -static void *cws_create_statistic(const cws_stat_info *stat_info) { - void *stat = gpr_malloc(stat_info->stat_size); - cws_initialize_statistic(stat, stat_info); - return stat; -} - -window_stats *census_window_stats_create(int nintervals, - const gpr_timespec intervals[], - int granularity, - const cws_stat_info *stat_info) { - window_stats *ret; - int i; - /* validate inputs */ - GPR_ASSERT(nintervals > 0 && granularity > 2 && intervals != NULL && - stat_info != NULL); - for (i = 0; i < nintervals; i++) { - int64_t ns = timespec_to_ns(intervals[i]); - GPR_ASSERT(intervals[i].tv_sec >= 0 && intervals[i].tv_nsec >= 0 && - intervals[i].tv_nsec < GPR_NS_PER_SEC && ns >= 100 && - granularity * 10 <= ns); - } - /* Allocate and initialize relevant data structures */ - ret = (window_stats *)gpr_malloc(sizeof(window_stats)); - ret->nintervals = nintervals; - ret->nbuckets = granularity + 1; - ret->stat_info = *stat_info; - ret->interval_stats = - (cws_interval_stats *)gpr_malloc(nintervals * sizeof(cws_interval_stats)); - for (i = 0; i < nintervals; i++) { - int64_t size_ns = timespec_to_ns(intervals[i]); - cws_interval_stats *is = ret->interval_stats + i; - cws_bucket *buckets = is->buckets = - (cws_bucket *)gpr_malloc(ret->nbuckets * sizeof(cws_bucket)); - int b; - for (b = 0; b < ret->nbuckets; b++) { - buckets[b].statistic = cws_create_statistic(stat_info); - buckets[b].count = 0; - } - is->bottom_bucket = 0; - is->bottom = 0; - is->width = size_ns / granularity; - /* Check for possible overflow issues, and maximize interval size if the - user requested something large enough. */ - if ((GPR_INT64_MAX - is->width) > size_ns) { - is->top = size_ns + is->width; - } else { - is->top = GPR_INT64_MAX; - is->width = GPR_INT64_MAX / (granularity + 1); - } - /* If size doesn't divide evenly, we can have a width slightly too small; - better to have it slightly large. */ - if ((size_ns - (granularity + 1) * is->width) > 0) { - is->width += 1; - } - } - ret->newest_time = 0; - return ret; -} - -/* When we try adding a measurement above the current interval range, we - need to "shift" the buckets sufficiently to cover the new range. */ -static void cws_shift_buckets(const window_stats *wstats, - cws_interval_stats *is, int64_t when_ns) { - int i; - /* number of bucket time widths to "shift" */ - int shift; - /* number of buckets to clear */ - int nclear; - GPR_ASSERT(when_ns >= is->top); - /* number of bucket time widths to "shift" */ - shift = ((when_ns - is->top) / is->width) + 1; - /* number of buckets to clear - limited by actual number of buckets */ - nclear = GPR_MIN(shift, wstats->nbuckets); - for (i = 0; i < nclear; i++) { - int b = BUCKET_IDX(is, i, wstats); - is->buckets[b].count = 0; - cws_initialize_statistic(is->buckets[b].statistic, &wstats->stat_info); - } - /* adjust top/bottom times and current bottom bucket */ - is->bottom_bucket = BUCKET_IDX(is, shift, wstats); - is->top += shift * is->width; - is->bottom += shift * is->width; -} - -void census_window_stats_add(window_stats *wstats, const gpr_timespec when, - const void *stat_value) { - int i; - int64_t when_ns = timespec_to_ns(when); - GPR_ASSERT(wstats->interval_stats != NULL); - for (i = 0; i < wstats->nintervals; i++) { - cws_interval_stats *is = wstats->interval_stats + i; - cws_bucket *bucket; - if (when_ns < is->bottom) { /* Below smallest time in interval: drop */ - continue; - } - if (when_ns >= is->top) { /* above limit: shift buckets */ - cws_shift_buckets(wstats, is, when_ns); - } - /* Add the stat. */ - GPR_ASSERT(is->bottom <= when_ns && when_ns < is->top); - bucket = is->buckets + - BUCKET_IDX(is, (when_ns - is->bottom) / is->width, wstats); - bucket->count++; - wstats->stat_info.stat_add(bucket->statistic, stat_value); - } - if (when_ns > wstats->newest_time) { - wstats->newest_time = when_ns; - } -} - -/* Add a specific bucket contents to an accumulating total. */ -static void cws_add_bucket_to_sum(cws_sum *sum, const cws_bucket *bucket, - const cws_stat_info *stat_info) { - sum->count += bucket->count; - stat_info->stat_add(sum->statistic, bucket->statistic); -} - -/* Add a proportion to an accumulating sum. */ -static void cws_add_proportion_to_sum(double p, cws_sum *sum, - const cws_bucket *bucket, - const cws_stat_info *stat_info) { - sum->count += p * bucket->count; - stat_info->stat_add_proportion(p, sum->statistic, bucket->statistic); -} - -void census_window_stats_get_sums(const window_stats *wstats, - const gpr_timespec when, cws_sum sums[]) { - int i; - int64_t when_ns = timespec_to_ns(when); - GPR_ASSERT(wstats->interval_stats != NULL); - for (i = 0; i < wstats->nintervals; i++) { - int when_bucket; - int new_bucket; - double last_proportion = 1.0; - double bottom_proportion; - cws_interval_stats *is = wstats->interval_stats + i; - cws_sum *sum = sums + i; - sum->count = 0; - cws_initialize_statistic(sum->statistic, &wstats->stat_info); - if (when_ns < is->bottom) { - continue; - } - if (when_ns >= is->top) { - cws_shift_buckets(wstats, is, when_ns); - } - /* Calculating the appropriate amount of which buckets to use can get - complicated. Essentially there are two cases: - 1) if the "top" bucket (new_bucket, where the newest additions to the - stats recorded are entered) corresponds to 'when', then we need - to take a proportion of it - (if when < newest_time) or the full - thing. We also (possibly) need to take a corresponding - proportion of the bottom bucket. - 2) Other cases, we just take a straight proportion. - */ - when_bucket = (when_ns - is->bottom) / is->width; - new_bucket = (wstats->newest_time - is->bottom) / is->width; - if (new_bucket == when_bucket) { - int64_t bottom_bucket_time = is->bottom + when_bucket * is->width; - if (when_ns < wstats->newest_time) { - last_proportion = (double)(when_ns - bottom_bucket_time) / - (double)(wstats->newest_time - bottom_bucket_time); - bottom_proportion = - (double)(is->width - (when_ns - bottom_bucket_time)) / is->width; - } else { - bottom_proportion = - (double)(is->width - (wstats->newest_time - bottom_bucket_time)) / - is->width; - } - } else { - last_proportion = - (double)(when_ns + 1 - is->bottom - when_bucket * is->width) / - is->width; - bottom_proportion = 1.0 - last_proportion; - } - cws_add_proportion_to_sum(last_proportion, sum, - is->buckets + BUCKET_IDX(is, when_bucket, wstats), - &wstats->stat_info); - if (when_bucket != 0) { /* last bucket isn't also bottom bucket */ - int b; - /* Add all of "bottom" bucket if we are looking at a subset of the - full interval, or a proportion if we are adding full interval. */ - cws_add_proportion_to_sum( - (when_bucket == wstats->nbuckets - 1 ? bottom_proportion : 1.0), sum, - is->buckets + is->bottom_bucket, &wstats->stat_info); - /* Add all the remaining buckets (everything but top and bottom). */ - for (b = 1; b < when_bucket; b++) { - cws_add_bucket_to_sum(sum, is->buckets + BUCKET_IDX(is, b, wstats), - &wstats->stat_info); - } - } - } -} - -void census_window_stats_destroy(window_stats *wstats) { - int i; - GPR_ASSERT(wstats->interval_stats != NULL); - for (i = 0; i < wstats->nintervals; i++) { - int b; - for (b = 0; b < wstats->nbuckets; b++) { - gpr_free(wstats->interval_stats[i].buckets[b].statistic); - } - gpr_free(wstats->interval_stats[i].buckets); - } - gpr_free(wstats->interval_stats); - /* Ensure any use-after free triggers assert. */ - wstats->interval_stats = NULL; - gpr_free(wstats); -} diff --git a/src/core/statistics/window_stats.h b/src/core/statistics/window_stats.h deleted file mode 100644 index 774277180f..0000000000 --- a/src/core/statistics/window_stats.h +++ /dev/null @@ -1,173 +0,0 @@ -/* - * - * Copyright 2015-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_STATISTICS_WINDOW_STATS_H -#define GRPC_CORE_STATISTICS_WINDOW_STATS_H - -#include - -/* Keep rolling sums of a user-defined statistic (containing a number of - measurements) over a a number of time intervals ("windows"). For example, - you can use a window_stats object to answer questions such as - "Approximately how many RPCs/s did I receive over the past minute, and - approximately how many bytes did I send out over that period?". - - The type of data to record, and the time intervals to keep are specified - when creating the object via a call to census_window_stats_create(). - - A window's interval is divided into one or more "buckets"; the interval - must be divisible by the number of buckets. Internally, these buckets - control the granularity of window_stats' measurements. Increasing the - number of buckets lets the object respond more quickly to changes in the - overall rate of data added into the object, at the cost of additional - memory usage. - - Here's some code which keeps one minute/hour measurements for two values - (latency in seconds and bytes transferred), with each interval divided into - 4 buckets. - - typedef struct my_stat { - double latency; - int bytes; - } my_stat; - - void add_my_stat(void* base, const void* addme) { - my_stat* b = (my_stat*)base; - const my_stat* a = (const my_stat*)addme; - b->latency += a->latency; - b->bytes += a->bytes; - } - - void add_proportion_my_stat(double p, void* base, const void* addme) { - (my_stat*)result->latency += p * (const my_stat*)base->latency; - (my_stat*)result->bytes += p * (const my_stat*)base->bytes; - } - - #define kNumIntervals 2 - #define kMinInterval 0 - #define kHourInterval 1 - #define kNumBuckets 4 - - const struct census_window_stats_stat_info kMyStatInfo - = { sizeof(my_stat), NULL, add_my_stat, add_proportion_my_stat }; - gpr_timespec intervals[kNumIntervals] = {{60, 0}, {3600, 0}}; - my_stat stat; - my_stat sums[kNumIntervals]; - census_window_stats_sums result[kNumIntervals]; - struct census_window_stats* stats - = census_window_stats_create(kNumIntervals, intervals, kNumBuckets, - &kMyStatInfo); - // Record a new event, taking 15.3ms, transferring 1784 bytes. - stat.latency = 0.153; - stat.bytes = 1784; - census_window_stats_add(stats, gpr_now(GPR_CLOCK_REALTIME), &stat); - // Get sums and print them out - result[kMinInterval].statistic = &sums[kMinInterval]; - result[kHourInterval].statistic = &sums[kHourInterval]; - census_window_stats_get_sums(stats, gpr_now(GPR_CLOCK_REALTIME), result); - printf("%d events/min, average time %gs, average bytes %g\n", - result[kMinInterval].count, - (my_stat*)result[kMinInterval].statistic->latency / - result[kMinInterval].count, - (my_stat*)result[kMinInterval].statistic->bytes / - result[kMinInterval].count - ); - printf("%d events/hr, average time %gs, average bytes %g\n", - result[kHourInterval].count, - (my_stat*)result[kHourInterval].statistic->latency / - result[kHourInterval].count, - (my_stat*)result[kHourInterval].statistic->bytes / - result[kHourInterval].count - ); -*/ - -/* Opaque structure for representing window_stats object */ -struct census_window_stats; - -/* Information provided by API user on the information they want to record */ -typedef struct census_window_stats_stat_info { - /* Number of bytes in user-defined object. */ - size_t stat_size; - /* Function to initialize a user-defined statistics object. If this is set - * to NULL, then the object will be zero-initialized. */ - void (*stat_initialize)(void *stat); - /* Function to add one user-defined statistics object ('addme') to 'base' */ - void (*stat_add)(void *base, const void *addme); - /* As for previous function, but only add a proportion 'p'. This API will - currently only use 'p' values in the range [0,1], but other values are - possible in the future, and should be supported. */ - void (*stat_add_proportion)(double p, void *base, const void *addme); -} census_window_stats_stat_info; - -/* Create a new window_stats object. 'nintervals' is the number of - 'intervals', and must be >=1. 'granularity' is the number of buckets, with - a larger number using more memory, but providing greater accuracy of - results. 'granularity should be > 2. We also require that each interval be - at least 10 * 'granularity' nanoseconds in size. 'stat_info' contains - information about the statistic to be gathered. Intervals greater than ~192 - years will be treated as essentially infinite in size. This function will - GPR_ASSERT() if the object cannot be created or any of the parameters have - invalid values. This function is thread-safe. */ -struct census_window_stats *census_window_stats_create( - int nintervals, const gpr_timespec intervals[], int granularity, - const census_window_stats_stat_info *stat_info); - -/* Add a new measurement (in 'stat_value'), as of a given time ('when'). - This function is thread-compatible. */ -void census_window_stats_add(struct census_window_stats *wstats, - const gpr_timespec when, const void *stat_value); - -/* Structure used to record a single intervals sum for a given statistic */ -typedef struct census_window_stats_sum { - /* Total count of samples. Note that because some internal interpolation - is performed, the count of samples returned for each interval may not be an - integral value. */ - double count; - /* Sum for statistic */ - void *statistic; -} census_window_stats_sums; - -/* Retrieve a set of all values stored in a window_stats object 'wstats'. The - number of 'sums' MUST be the same as the number 'nintervals' used in - census_window_stats_create(). This function is thread-compatible. */ -void census_window_stats_get_sums(const struct census_window_stats *wstats, - const gpr_timespec when, - struct census_window_stats_sum sums[]); - -/* Destroy a window_stats object. Once this function has been called, the - object will no longer be usable from any of the above functions (and - calling them will most likely result in a NULL-pointer dereference or - assertion failure). This function is thread-compatible. */ -void census_window_stats_destroy(struct census_window_stats *wstats); - -#endif /* GRPC_CORE_STATISTICS_WINDOW_STATS_H */ diff --git a/src/core/support/alloc.c b/src/core/support/alloc.c deleted file mode 100644 index fd9fb8f5e7..0000000000 --- a/src/core/support/alloc.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - * - * Copyright 2015-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 - -#include -#include -#include -#include "src/core/profiling/timers.h" - -static gpr_allocation_functions g_alloc_functions = {malloc, realloc, free}; - -gpr_allocation_functions gpr_get_allocation_functions() { - return g_alloc_functions; -} - -void gpr_set_allocation_functions(gpr_allocation_functions functions) { - GPR_ASSERT(functions.malloc_fn != NULL); - GPR_ASSERT(functions.realloc_fn != NULL); - GPR_ASSERT(functions.free_fn != NULL); - g_alloc_functions = functions; -} - -void *gpr_malloc(size_t size) { - void *p; - GPR_TIMER_BEGIN("gpr_malloc", 0); - p = g_alloc_functions.malloc_fn(size); - if (!p) { - abort(); - } - GPR_TIMER_END("gpr_malloc", 0); - return p; -} - -void gpr_free(void *p) { - GPR_TIMER_BEGIN("gpr_free", 0); - g_alloc_functions.free_fn(p); - GPR_TIMER_END("gpr_free", 0); -} - -void *gpr_realloc(void *p, size_t size) { - GPR_TIMER_BEGIN("gpr_realloc", 0); - p = g_alloc_functions.realloc_fn(p, size); - if (!p) { - abort(); - } - GPR_TIMER_END("gpr_realloc", 0); - return p; -} - -void *gpr_malloc_aligned(size_t size, size_t alignment_log) { - size_t alignment = ((size_t)1) << alignment_log; - size_t extra = alignment - 1 + sizeof(void *); - void *p = gpr_malloc(size + extra); - void **ret = (void **)(((uintptr_t)p + extra) & ~(alignment - 1)); - ret[-1] = p; - return (void *)ret; -} - -void gpr_free_aligned(void *ptr) { gpr_free(((void **)ptr)[-1]); } diff --git a/src/core/support/avl.c b/src/core/support/avl.c deleted file mode 100644 index f378b3ee17..0000000000 --- a/src/core/support/avl.c +++ /dev/null @@ -1,288 +0,0 @@ -/* - * - * Copyright 2015-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 - -#include -#include - -#include -#include -#include - -gpr_avl gpr_avl_create(const gpr_avl_vtable *vtable) { - gpr_avl out; - out.vtable = vtable; - out.root = NULL; - return out; -} - -static gpr_avl_node *ref_node(gpr_avl_node *node) { - if (node) { - gpr_ref(&node->refs); - } - return node; -} - -static void unref_node(const gpr_avl_vtable *vtable, gpr_avl_node *node) { - if (node == NULL) { - return; - } - if (gpr_unref(&node->refs)) { - vtable->destroy_key(node->key); - vtable->destroy_value(node->value); - unref_node(vtable, node->left); - unref_node(vtable, node->right); - gpr_free(node); - } -} - -static long node_height(gpr_avl_node *node) { - return node == NULL ? 0 : node->height; -} - -#ifndef NDEBUG -static long calculate_height(gpr_avl_node *node) { - return node == NULL ? 0 : 1 + GPR_MAX(calculate_height(node->left), - calculate_height(node->right)); -} - -static gpr_avl_node *assert_invariants(gpr_avl_node *n) { - if (n == NULL) return NULL; - assert_invariants(n->left); - assert_invariants(n->right); - assert(calculate_height(n) == n->height); - assert(labs(node_height(n->left) - node_height(n->right)) <= 1); - return n; -} -#else -static gpr_avl_node *assert_invariants(gpr_avl_node *n) { return n; } -#endif - -gpr_avl_node *new_node(void *key, void *value, gpr_avl_node *left, - gpr_avl_node *right) { - gpr_avl_node *node = gpr_malloc(sizeof(*node)); - gpr_ref_init(&node->refs, 1); - node->key = key; - node->value = value; - node->left = assert_invariants(left); - node->right = assert_invariants(right); - node->height = 1 + GPR_MAX(node_height(left), node_height(right)); - return node; -} - -static gpr_avl_node *get(const gpr_avl_vtable *vtable, gpr_avl_node *node, - void *key) { - long cmp; - - if (node == NULL) { - return NULL; - } - - cmp = vtable->compare_keys(node->key, key); - if (cmp == 0) { - return node; - } else if (cmp > 0) { - return get(vtable, node->left, key); - } else { - return get(vtable, node->right, key); - } -} - -void *gpr_avl_get(gpr_avl avl, void *key) { - gpr_avl_node *node = get(avl.vtable, avl.root, key); - return node ? node->value : NULL; -} - -static gpr_avl_node *rotate_left(const gpr_avl_vtable *vtable, void *key, - void *value, gpr_avl_node *left, - gpr_avl_node *right) { - gpr_avl_node *n = - new_node(vtable->copy_key(right->key), vtable->copy_value(right->value), - new_node(key, value, left, ref_node(right->left)), - ref_node(right->right)); - unref_node(vtable, right); - return n; -} - -static gpr_avl_node *rotate_right(const gpr_avl_vtable *vtable, void *key, - void *value, gpr_avl_node *left, - gpr_avl_node *right) { - gpr_avl_node *n = new_node( - vtable->copy_key(left->key), vtable->copy_value(left->value), - ref_node(left->left), new_node(key, value, ref_node(left->right), right)); - unref_node(vtable, left); - return n; -} - -static gpr_avl_node *rotate_left_right(const gpr_avl_vtable *vtable, void *key, - void *value, gpr_avl_node *left, - gpr_avl_node *right) { - /* rotate_right(..., rotate_left(left), right) */ - gpr_avl_node *n = new_node( - vtable->copy_key(left->right->key), - vtable->copy_value(left->right->value), - new_node(vtable->copy_key(left->key), vtable->copy_value(left->value), - ref_node(left->left), ref_node(left->right->left)), - new_node(key, value, ref_node(left->right->right), right)); - unref_node(vtable, left); - return n; -} - -static gpr_avl_node *rotate_right_left(const gpr_avl_vtable *vtable, void *key, - void *value, gpr_avl_node *left, - gpr_avl_node *right) { - /* rotate_left(..., left, rotate_right(right)) */ - gpr_avl_node *n = new_node( - vtable->copy_key(right->left->key), - vtable->copy_value(right->left->value), - new_node(key, value, left, ref_node(right->left->left)), - new_node(vtable->copy_key(right->key), vtable->copy_value(right->value), - ref_node(right->left->right), ref_node(right->right))); - unref_node(vtable, right); - return n; -} - -static gpr_avl_node *rebalance(const gpr_avl_vtable *vtable, void *key, - void *value, gpr_avl_node *left, - gpr_avl_node *right) { - switch (node_height(left) - node_height(right)) { - case 2: - if (node_height(left->left) - node_height(left->right) == -1) { - return assert_invariants( - rotate_left_right(vtable, key, value, left, right)); - } else { - return assert_invariants(rotate_right(vtable, key, value, left, right)); - } - case -2: - if (node_height(right->left) - node_height(right->right) == 1) { - return assert_invariants( - rotate_right_left(vtable, key, value, left, right)); - } else { - return assert_invariants(rotate_left(vtable, key, value, left, right)); - } - default: - return assert_invariants(new_node(key, value, left, right)); - } -} - -static gpr_avl_node *add(const gpr_avl_vtable *vtable, gpr_avl_node *node, - void *key, void *value) { - long cmp; - if (node == NULL) { - return new_node(key, value, NULL, NULL); - } - cmp = vtable->compare_keys(node->key, key); - if (cmp == 0) { - return new_node(key, value, ref_node(node->left), ref_node(node->right)); - } else if (cmp > 0) { - return rebalance( - vtable, vtable->copy_key(node->key), vtable->copy_value(node->value), - add(vtable, node->left, key, value), ref_node(node->right)); - } else { - return rebalance(vtable, vtable->copy_key(node->key), - vtable->copy_value(node->value), ref_node(node->left), - add(vtable, node->right, key, value)); - } -} - -gpr_avl gpr_avl_add(gpr_avl avl, void *key, void *value) { - gpr_avl_node *old_root = avl.root; - avl.root = add(avl.vtable, avl.root, key, value); - assert_invariants(avl.root); - unref_node(avl.vtable, old_root); - return avl; -} - -static gpr_avl_node *in_order_head(gpr_avl_node *node) { - while (node->left != NULL) { - node = node->left; - } - return node; -} - -static gpr_avl_node *in_order_tail(gpr_avl_node *node) { - while (node->right != NULL) { - node = node->right; - } - return node; -} - -static gpr_avl_node *remove(const gpr_avl_vtable *vtable, gpr_avl_node *node, - void *key) { - long cmp; - if (node == NULL) { - return NULL; - } - cmp = vtable->compare_keys(node->key, key); - if (cmp == 0) { - if (node->left == NULL) { - return ref_node(node->right); - } else if (node->right == NULL) { - return ref_node(node->left); - } else if (node->left->height < node->right->height) { - gpr_avl_node *h = in_order_head(node->right); - return rebalance(vtable, vtable->copy_key(h->key), - vtable->copy_value(h->value), ref_node(node->left), - remove(vtable, node->right, h->key)); - } else { - gpr_avl_node *h = in_order_tail(node->left); - return rebalance( - vtable, vtable->copy_key(h->key), vtable->copy_value(h->value), - remove(vtable, node->left, h->key), ref_node(node->right)); - } - } else if (cmp > 0) { - return rebalance(vtable, vtable->copy_key(node->key), - vtable->copy_value(node->value), - remove(vtable, node->left, key), ref_node(node->right)); - } else { - return rebalance(vtable, vtable->copy_key(node->key), - vtable->copy_value(node->value), ref_node(node->left), - remove(vtable, node->right, key)); - } -} - -gpr_avl gpr_avl_remove(gpr_avl avl, void *key) { - gpr_avl_node *old_root = avl.root; - avl.root = remove(avl.vtable, avl.root, key); - assert_invariants(avl.root); - unref_node(avl.vtable, old_root); - return avl; -} - -gpr_avl gpr_avl_ref(gpr_avl avl) { - ref_node(avl.root); - return avl; -} - -void gpr_avl_unref(gpr_avl avl) { unref_node(avl.vtable, avl.root); } diff --git a/src/core/support/backoff.c b/src/core/support/backoff.c deleted file mode 100644 index 4ccfb774ed..0000000000 --- a/src/core/support/backoff.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * - * 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/support/backoff.h" - -#include - -void gpr_backoff_init(gpr_backoff *backoff, double multiplier, double jitter, - int64_t min_timeout_millis, int64_t max_timeout_millis) { - backoff->multiplier = multiplier; - backoff->jitter = jitter; - backoff->min_timeout_millis = min_timeout_millis; - backoff->max_timeout_millis = max_timeout_millis; - backoff->rng_state = (uint32_t)gpr_now(GPR_CLOCK_REALTIME).tv_nsec; -} - -gpr_timespec gpr_backoff_begin(gpr_backoff *backoff, gpr_timespec now) { - backoff->current_timeout_millis = backoff->min_timeout_millis; - return gpr_time_add( - now, gpr_time_from_millis(backoff->current_timeout_millis, GPR_TIMESPAN)); -} - -/* Generate a random number between 0 and 1. */ -static double generate_uniform_random_number(uint32_t *rng_state) { - *rng_state = (1103515245 * *rng_state + 12345) % ((uint32_t)1 << 31); - return *rng_state / (double)((uint32_t)1 << 31); -} - -gpr_timespec gpr_backoff_step(gpr_backoff *backoff, gpr_timespec now) { - double new_timeout_millis = - backoff->multiplier * (double)backoff->current_timeout_millis; - double jitter_range = backoff->jitter * new_timeout_millis; - double jitter = - (2 * generate_uniform_random_number(&backoff->rng_state) - 1) * - jitter_range; - backoff->current_timeout_millis = - GPR_CLAMP((int64_t)(new_timeout_millis + jitter), - backoff->min_timeout_millis, backoff->max_timeout_millis); - return gpr_time_add( - now, gpr_time_from_millis(backoff->current_timeout_millis, GPR_TIMESPAN)); -} - -void gpr_backoff_reset(gpr_backoff *backoff) { - // forces step() to return a timeout of min_timeout_millis - backoff->current_timeout_millis = 0; -} diff --git a/src/core/support/backoff.h b/src/core/support/backoff.h deleted file mode 100644 index 0f933c3149..0000000000 --- a/src/core/support/backoff.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * - * 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_SUPPORT_BACKOFF_H -#define GRPC_CORE_SUPPORT_BACKOFF_H - -#include - -typedef struct { - /// const: multiplier between retry attempts - double multiplier; - /// const: amount to randomize backoffs - double jitter; - /// const: minimum time between retries in milliseconds - int64_t min_timeout_millis; - /// const: maximum time between retries in milliseconds - int64_t max_timeout_millis; - - /// random number generator - uint32_t rng_state; - - /// current retry timeout in milliseconds - int64_t current_timeout_millis; -} gpr_backoff; - -/// Initialize backoff machinery - does not need to be destroyed -void gpr_backoff_init(gpr_backoff *backoff, double multiplier, double jitter, - int64_t min_timeout_millis, int64_t max_timeout_millis); - -/// Begin retry loop: returns a timespec for the NEXT retry -gpr_timespec gpr_backoff_begin(gpr_backoff *backoff, gpr_timespec now); -/// Step a retry loop: returns a timespec for the NEXT retry -gpr_timespec gpr_backoff_step(gpr_backoff *backoff, gpr_timespec now); -/// Reset the backoff, so the next gpr_backoff_step will be a gpr_backoff_begin -/// instead -void gpr_backoff_reset(gpr_backoff *backoff); - -#endif /* GRPC_CORE_SUPPORT_BACKOFF_H */ diff --git a/src/core/support/block_annotate.h b/src/core/support/block_annotate.h deleted file mode 100644 index 79a18039f4..0000000000 --- a/src/core/support/block_annotate.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * - * Copyright 2015-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_SUPPORT_BLOCK_ANNOTATE_H -#define GRPC_CORE_SUPPORT_BLOCK_ANNOTATE_H - -/* These annotations identify the beginning and end of regions where - the code may block for reasons other than synchronization functions. - These include poll, epoll, and getaddrinfo. */ - -#define GRPC_SCHEDULING_START_BLOCKING_REGION \ - do { \ - } while (0) -#define GRPC_SCHEDULING_END_BLOCKING_REGION \ - do { \ - } while (0) - -#endif /* GRPC_CORE_SUPPORT_BLOCK_ANNOTATE_H */ diff --git a/src/core/support/cmdline.c b/src/core/support/cmdline.c deleted file mode 100644 index eff46a1655..0000000000 --- a/src/core/support/cmdline.c +++ /dev/null @@ -1,347 +0,0 @@ -/* - * - * Copyright 2015-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 - -#include -#include -#include - -#include -#include -#include -#include "src/core/support/string.h" - -typedef enum { ARGTYPE_INT, ARGTYPE_BOOL, ARGTYPE_STRING } argtype; - -typedef struct arg { - const char *name; - const char *help; - argtype type; - void *value; - struct arg *next; -} arg; - -struct gpr_cmdline { - const char *description; - arg *args; - const char *argv0; - - const char *extra_arg_name; - const char *extra_arg_help; - void (*extra_arg)(void *user_data, const char *arg); - void *extra_arg_user_data; - - int (*state)(gpr_cmdline *cl, char *arg); - arg *cur_arg; - - int survive_failure; -}; - -static int normal_state(gpr_cmdline *cl, char *arg); - -gpr_cmdline *gpr_cmdline_create(const char *description) { - gpr_cmdline *cl = gpr_malloc(sizeof(gpr_cmdline)); - memset(cl, 0, sizeof(gpr_cmdline)); - - cl->description = description; - cl->state = normal_state; - - return cl; -} - -void gpr_cmdline_set_survive_failure(gpr_cmdline *cl) { - cl->survive_failure = 1; -} - -void gpr_cmdline_destroy(gpr_cmdline *cl) { - while (cl->args) { - arg *a = cl->args; - cl->args = a->next; - gpr_free(a); - } - gpr_free(cl); -} - -static void add_arg(gpr_cmdline *cl, const char *name, const char *help, - argtype type, void *value) { - arg *a; - - for (a = cl->args; a; a = a->next) { - GPR_ASSERT(0 != strcmp(a->name, name)); - } - - a = gpr_malloc(sizeof(arg)); - memset(a, 0, sizeof(arg)); - a->name = name; - a->help = help; - a->type = type; - a->value = value; - a->next = cl->args; - cl->args = a; -} - -void gpr_cmdline_add_int(gpr_cmdline *cl, const char *name, const char *help, - int *value) { - add_arg(cl, name, help, ARGTYPE_INT, value); -} - -void gpr_cmdline_add_flag(gpr_cmdline *cl, const char *name, const char *help, - int *value) { - add_arg(cl, name, help, ARGTYPE_BOOL, value); -} - -void gpr_cmdline_add_string(gpr_cmdline *cl, const char *name, const char *help, - char **value) { - add_arg(cl, name, help, ARGTYPE_STRING, value); -} - -void gpr_cmdline_on_extra_arg( - gpr_cmdline *cl, const char *name, const char *help, - void (*on_extra_arg)(void *user_data, const char *arg), void *user_data) { - GPR_ASSERT(!cl->extra_arg); - GPR_ASSERT(on_extra_arg); - - cl->extra_arg = on_extra_arg; - cl->extra_arg_user_data = user_data; - cl->extra_arg_name = name; - cl->extra_arg_help = help; -} - -/* recursively descend argument list, adding the last element - to s first - so that arguments are added in the order they were - added to the list by api calls */ -static void add_args_to_usage(gpr_strvec *s, arg *a) { - char *tmp; - - if (!a) return; - add_args_to_usage(s, a->next); - - switch (a->type) { - case ARGTYPE_BOOL: - gpr_asprintf(&tmp, " [--%s|--no-%s]", a->name, a->name); - gpr_strvec_add(s, tmp); - break; - case ARGTYPE_STRING: - gpr_asprintf(&tmp, " [--%s=string]", a->name); - gpr_strvec_add(s, tmp); - break; - case ARGTYPE_INT: - gpr_asprintf(&tmp, " [--%s=int]", a->name); - gpr_strvec_add(s, tmp); - break; - } -} - -char *gpr_cmdline_usage_string(gpr_cmdline *cl, const char *argv0) { - /* TODO(ctiller): make this prettier */ - gpr_strvec s; - char *tmp; - const char *name = strrchr(argv0, '/'); - - if (name) { - name++; - } else { - name = argv0; - } - - gpr_strvec_init(&s); - - gpr_asprintf(&tmp, "Usage: %s", name); - gpr_strvec_add(&s, tmp); - add_args_to_usage(&s, cl->args); - if (cl->extra_arg) { - gpr_asprintf(&tmp, " [%s...]", cl->extra_arg_name); - gpr_strvec_add(&s, tmp); - } - gpr_strvec_add(&s, gpr_strdup("\n")); - - tmp = gpr_strvec_flatten(&s, NULL); - gpr_strvec_destroy(&s); - return tmp; -} - -static int print_usage_and_die(gpr_cmdline *cl) { - char *usage = gpr_cmdline_usage_string(cl, cl->argv0); - fprintf(stderr, "%s", usage); - gpr_free(usage); - if (!cl->survive_failure) { - exit(1); - } - return 0; -} - -static int extra_state(gpr_cmdline *cl, char *str) { - if (!cl->extra_arg) { - return print_usage_and_die(cl); - } - cl->extra_arg(cl->extra_arg_user_data, str); - return 1; -} - -static arg *find_arg(gpr_cmdline *cl, char *name) { - arg *a; - - for (a = cl->args; a; a = a->next) { - if (0 == strcmp(a->name, name)) { - break; - } - } - - if (!a) { - fprintf(stderr, "Unknown argument: %s\n", name); - return NULL; - } - - return a; -} - -static int value_state(gpr_cmdline *cl, char *str) { - long intval; - char *end; - - GPR_ASSERT(cl->cur_arg); - - switch (cl->cur_arg->type) { - case ARGTYPE_INT: - intval = strtol(str, &end, 0); - if (*end || intval < INT_MIN || intval > INT_MAX) { - fprintf(stderr, "expected integer, got '%s' for %s\n", str, - cl->cur_arg->name); - return print_usage_and_die(cl); - } - *(int *)cl->cur_arg->value = (int)intval; - break; - case ARGTYPE_BOOL: - if (0 == strcmp(str, "1") || 0 == strcmp(str, "true")) { - *(int *)cl->cur_arg->value = 1; - } else if (0 == strcmp(str, "0") || 0 == strcmp(str, "false")) { - *(int *)cl->cur_arg->value = 0; - } else { - fprintf(stderr, "expected boolean, got '%s' for %s\n", str, - cl->cur_arg->name); - return print_usage_and_die(cl); - } - break; - case ARGTYPE_STRING: - *(char **)cl->cur_arg->value = str; - break; - } - - cl->state = normal_state; - return 1; -} - -static int normal_state(gpr_cmdline *cl, char *str) { - char *eq = NULL; - char *tmp = NULL; - char *arg_name = NULL; - int r = 1; - - if (0 == strcmp(str, "-help") || 0 == strcmp(str, "--help") || - 0 == strcmp(str, "-h")) { - return print_usage_and_die(cl); - } - - cl->cur_arg = NULL; - - if (str[0] == '-') { - if (str[1] == '-') { - if (str[2] == 0) { - /* handle '--' to move to just extra args */ - cl->state = extra_state; - return 1; - } - str += 2; - } else { - str += 1; - } - /* first byte of str is now past the leading '-' or '--' */ - if (str[0] == 'n' && str[1] == 'o' && str[2] == '-') { - /* str is of the form '--no-foo' - it's a flag disable */ - str += 3; - cl->cur_arg = find_arg(cl, str); - if (cl->cur_arg == NULL) { - return print_usage_and_die(cl); - } - if (cl->cur_arg->type != ARGTYPE_BOOL) { - fprintf(stderr, "%s is not a flag argument\n", str); - return print_usage_and_die(cl); - } - *(int *)cl->cur_arg->value = 0; - return 1; /* early out */ - } - eq = strchr(str, '='); - if (eq != NULL) { - /* copy the string into a temp buffer and extract the name */ - tmp = arg_name = gpr_malloc((size_t)(eq - str + 1)); - memcpy(arg_name, str, (size_t)(eq - str)); - arg_name[eq - str] = 0; - } else { - arg_name = str; - } - cl->cur_arg = find_arg(cl, arg_name); - if (cl->cur_arg == NULL) { - return print_usage_and_die(cl); - } - if (eq != NULL) { - /* str was of the type --foo=value, parse the value */ - r = value_state(cl, eq + 1); - } else if (cl->cur_arg->type != ARGTYPE_BOOL) { - /* flag types don't have a '--foo value' variant, other types do */ - cl->state = value_state; - } else { - /* flag parameter: just set the value */ - *(int *)cl->cur_arg->value = 1; - } - } else { - r = extra_state(cl, str); - } - - gpr_free(tmp); - return r; -} - -int gpr_cmdline_parse(gpr_cmdline *cl, int argc, char **argv) { - int i; - - GPR_ASSERT(argc >= 1); - cl->argv0 = argv[0]; - - for (i = 1; i < argc; i++) { - if (!cl->state(cl, argv[i])) { - return 0; - } - } - return 1; -} diff --git a/src/core/support/cpu_iphone.c b/src/core/support/cpu_iphone.c deleted file mode 100644 index 82b49b47bc..0000000000 --- a/src/core/support/cpu_iphone.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include - -#ifdef GPR_CPU_IPHONE - -/* Probably 2 instead of 1, but see comment on gpr_cpu_current_cpu. */ -unsigned gpr_cpu_num_cores(void) { return 1; } - -/* Most code that's using this is using it to shard across work queues. So - unless profiling shows it's a problem or there appears a way to detect the - currently running CPU core, let's have it shard the default way. - Note that the interface in cpu.h lets gpr_cpu_num_cores return 0, but doing - it makes it impossible for gpr_cpu_current_cpu to satisfy its stated range, - and some code might be relying on it. */ -unsigned gpr_cpu_current_cpu(void) { return 0; } - -#endif /* GPR_CPU_IPHONE */ diff --git a/src/core/support/cpu_linux.c b/src/core/support/cpu_linux.c deleted file mode 100644 index 5597df2d03..0000000000 --- a/src/core/support/cpu_linux.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * - * Copyright 2015-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 _GNU_SOURCE -#define _GNU_SOURCE -#endif /* _GNU_SOURCE */ - -#include - -#ifdef GPR_CPU_LINUX - -#include -#include -#include -#include - -#include -#include -#include - -static int ncpus = 0; - -static void init_num_cpus() { - /* This must be signed. sysconf returns -1 when the number cannot be - determined */ - ncpus = (int)sysconf(_SC_NPROCESSORS_ONLN); - if (ncpus < 1) { - gpr_log(GPR_ERROR, "Cannot determine number of CPUs: assuming 1"); - ncpus = 1; - } -} - -unsigned gpr_cpu_num_cores(void) { - static gpr_once once = GPR_ONCE_INIT; - gpr_once_init(&once, init_num_cpus); - return (unsigned)ncpus; -} - -unsigned gpr_cpu_current_cpu(void) { - int cpu = sched_getcpu(); - if (cpu < 0) { - gpr_log(GPR_ERROR, "Error determining current CPU: %s\n", strerror(errno)); - return 0; - } - return (unsigned)cpu; -} - -#endif /* GPR_CPU_LINUX */ diff --git a/src/core/support/cpu_posix.c b/src/core/support/cpu_posix.c deleted file mode 100644 index e508ddd8ca..0000000000 --- a/src/core/support/cpu_posix.c +++ /dev/null @@ -1,77 +0,0 @@ -/* - * - * Copyright 2015-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 - -#ifdef GPR_CPU_POSIX - -#include -#include -#include - -#include -#include - -static __thread char magic_thread_local; - -static long ncpus = 0; - -static void init_ncpus() { - ncpus = sysconf(_SC_NPROCESSORS_ONLN); - if (ncpus < 1 || ncpus > INT32_MAX) { - gpr_log(GPR_ERROR, "Cannot determine number of CPUs: assuming 1"); - ncpus = 1; - } -} - -unsigned gpr_cpu_num_cores(void) { - static gpr_once once = GPR_ONCE_INIT; - gpr_once_init(&once, init_ncpus); - return (unsigned)ncpus; -} - -/* This is a cheap, but good enough, pointer hash for sharding things: */ -static size_t shard_ptr(const void *info) { - size_t x = (size_t)info; - return ((x >> 4) ^ (x >> 9) ^ (x >> 14)) % gpr_cpu_num_cores(); -} - -unsigned gpr_cpu_current_cpu(void) { - /* NOTE: there's no way I know to return the actual cpu index portably... - most code that's using this is using it to shard across work queues though, - so here we use thread identity instead to achieve a similar though not - identical effect */ - return (unsigned)shard_ptr(&magic_thread_local); -} - -#endif /* GPR_CPU_POSIX */ diff --git a/src/core/support/cpu_windows.c b/src/core/support/cpu_windows.c deleted file mode 100644 index ce32eb0a9d..0000000000 --- a/src/core/support/cpu_windows.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include - -#ifdef GPR_WIN32 -#include - -unsigned gpr_cpu_num_cores(void) { - SYSTEM_INFO si; - GetSystemInfo(&si); - return si.dwNumberOfProcessors; -} - -unsigned gpr_cpu_current_cpu(void) { return GetCurrentProcessorNumber(); } - -#endif /* GPR_WIN32 */ diff --git a/src/core/support/env.h b/src/core/support/env.h deleted file mode 100644 index 2902456947..0000000000 --- a/src/core/support/env.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * - * Copyright 2015-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_SUPPORT_ENV_H -#define GRPC_CORE_SUPPORT_ENV_H - -#include - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* Env utility functions */ - -/* Gets the environment variable value with the specified name. - Returns a newly allocated string. It is the responsability of the caller to - gpr_free the return value if not NULL (which means that the environment - variable exists). */ -char *gpr_getenv(const char *name); - -/* Sets the the environment with the specified name to the specified value. */ -void gpr_setenv(const char *name, const char *value); - -#ifdef __cplusplus -} -#endif - -#endif /* GRPC_CORE_SUPPORT_ENV_H */ diff --git a/src/core/support/env_linux.c b/src/core/support/env_linux.c deleted file mode 100644 index fe51f846b7..0000000000 --- a/src/core/support/env_linux.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * - * Copyright 2015-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. - * - */ - -/* for secure_getenv. */ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include - -#ifdef GPR_LINUX_ENV - -#include "src/core/support/env.h" - -#include -#include -#include -#include - -#include -#include -#include - -#include "src/core/support/string.h" - -char *gpr_getenv(const char *name) { -#if defined(GPR_BACKWARDS_COMPATIBILITY_MODE) - typedef char *(*getenv_type)(const char *); - static getenv_type getenv_func = NULL; - /* Check to see which getenv variant is supported (go from most - * to least secure) */ - const char *names[] = {"secure_getenv", "__secure_getenv", "getenv"}; - for (size_t i = 0; getenv_func == NULL && i < GPR_ARRAY_SIZE(names); i++) { - getenv_func = (getenv_type)dlsym(RTLD_DEFAULT, names[i]); - if (getenv_func != NULL && strstr(names[i], "secure") == NULL) { - gpr_log(GPR_DEBUG, - "Warning: insecure environment read function '%s' used", - names[i]); - } - } - char *result = getenv_func(name); - return result == NULL ? result : gpr_strdup(result); -#elif __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 17) - char *result = secure_getenv(name); - return result == NULL ? result : gpr_strdup(result); -#else - gpr_log(GPR_DEBUG, "Warning: insecure environment read function '%s' used", - "getenv"); - char *result = getenv(name); - return result == NULL ? result : gpr_strdup(result); -#endif -} - -void gpr_setenv(const char *name, const char *value) { - int res = setenv(name, value, 1); - GPR_ASSERT(res == 0); -} - -#endif /* GPR_LINUX_ENV */ diff --git a/src/core/support/env_posix.c b/src/core/support/env_posix.c deleted file mode 100644 index 256212be76..0000000000 --- a/src/core/support/env_posix.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * - * Copyright 2015-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 - -#ifdef GPR_POSIX_ENV - -#include "src/core/support/env.h" - -#include - -#include - -#include -#include "src/core/support/string.h" - -char *gpr_getenv(const char *name) { - char *result = getenv(name); - return result == NULL ? result : gpr_strdup(result); -} - -void gpr_setenv(const char *name, const char *value) { - int res = setenv(name, value, 1); - GPR_ASSERT(res == 0); -} - -#endif /* GPR_POSIX_ENV */ diff --git a/src/core/support/env_win32.c b/src/core/support/env_win32.c deleted file mode 100644 index 10258283ba..0000000000 --- a/src/core/support/env_win32.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * - * Copyright 2015-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 - -#ifdef GPR_WIN32 - -#include "src/core/support/env.h" -#include "src/core/support/string.h" - -#ifdef __MINGW32__ -errno_t getenv_s(size_t *size_needed, char *buffer, size_t size, - const char *varname); -#else -#include -#endif - -#include -#include -#include - -char *gpr_getenv(const char *name) { - size_t size; - char *result = NULL; - errno_t err; - - err = getenv_s(&size, NULL, 0, name); - if (err || (size == 0)) return NULL; - result = gpr_malloc(size); - err = getenv_s(&size, result, size, name); - if (err) { - gpr_free(result); - return NULL; - } - return result; -} - -void gpr_setenv(const char *name, const char *value) { - errno_t res = _putenv_s(name, value); - GPR_ASSERT(res == 0); -} - -#endif /* GPR_WIN32 */ diff --git a/src/core/support/histogram.c b/src/core/support/histogram.c deleted file mode 100644 index 62227be1a6..0000000000 --- a/src/core/support/histogram.c +++ /dev/null @@ -1,244 +0,0 @@ -/* - * - * Copyright 2015-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 - -#include -#include -#include - -#include -#include -#include -#include - -/* Histograms are stored with exponentially increasing bucket sizes. - The first bucket is [0, m) where m = 1 + resolution - Bucket n (n>=1) contains [m**n, m**(n+1)) - There are sufficient buckets to reach max_bucket_start */ - -struct gpr_histogram { - /* Sum of all values seen so far */ - double sum; - /* Sum of squares of all values seen so far */ - double sum_of_squares; - /* number of values seen so far */ - double count; - /* m in the description */ - double multiplier; - double one_on_log_multiplier; - /* minimum value seen */ - double min_seen; - /* maximum value seen */ - double max_seen; - /* maximum representable value */ - double max_possible; - /* number of buckets */ - size_t num_buckets; - /* the buckets themselves */ - uint32_t *buckets; -}; - -/* determine a bucket index given a value - does no bounds checking */ -static size_t bucket_for_unchecked(gpr_histogram *h, double x) { - return (size_t)(log(x) * h->one_on_log_multiplier); -} - -/* bounds checked version of the above */ -static size_t bucket_for(gpr_histogram *h, double x) { - size_t bucket = bucket_for_unchecked(h, GPR_CLAMP(x, 1.0, h->max_possible)); - GPR_ASSERT(bucket < h->num_buckets); - return bucket; -} - -/* at what value does a bucket start? */ -static double bucket_start(gpr_histogram *h, double x) { - return pow(h->multiplier, x); -} - -gpr_histogram *gpr_histogram_create(double resolution, - double max_bucket_start) { - gpr_histogram *h = gpr_malloc(sizeof(gpr_histogram)); - GPR_ASSERT(resolution > 0.0); - GPR_ASSERT(max_bucket_start > resolution); - h->sum = 0.0; - h->sum_of_squares = 0.0; - h->multiplier = 1.0 + resolution; - h->one_on_log_multiplier = 1.0 / log(1.0 + resolution); - h->max_possible = max_bucket_start; - h->count = 0.0; - h->min_seen = max_bucket_start; - h->max_seen = 0.0; - h->num_buckets = bucket_for_unchecked(h, max_bucket_start) + 1; - GPR_ASSERT(h->num_buckets > 1); - GPR_ASSERT(h->num_buckets < 100000000); - h->buckets = gpr_malloc(sizeof(uint32_t) * h->num_buckets); - memset(h->buckets, 0, sizeof(uint32_t) * h->num_buckets); - return h; -} - -void gpr_histogram_destroy(gpr_histogram *h) { - gpr_free(h->buckets); - gpr_free(h); -} - -void gpr_histogram_add(gpr_histogram *h, double x) { - h->sum += x; - h->sum_of_squares += x * x; - h->count++; - if (x < h->min_seen) { - h->min_seen = x; - } - if (x > h->max_seen) { - h->max_seen = x; - } - h->buckets[bucket_for(h, x)]++; -} - -int gpr_histogram_merge(gpr_histogram *dst, const gpr_histogram *src) { - if ((dst->num_buckets != src->num_buckets) || - (dst->multiplier != src->multiplier)) { - /* Fail because these histograms don't match */ - return 0; - } - gpr_histogram_merge_contents(dst, src->buckets, src->num_buckets, - src->min_seen, src->max_seen, src->sum, - src->sum_of_squares, src->count); - return 1; -} - -void gpr_histogram_merge_contents(gpr_histogram *dst, const uint32_t *data, - size_t data_count, double min_seen, - double max_seen, double sum, - double sum_of_squares, double count) { - size_t i; - GPR_ASSERT(dst->num_buckets == data_count); - dst->sum += sum; - dst->sum_of_squares += sum_of_squares; - dst->count += count; - if (min_seen < dst->min_seen) { - dst->min_seen = min_seen; - } - if (max_seen > dst->max_seen) { - dst->max_seen = max_seen; - } - for (i = 0; i < dst->num_buckets; i++) { - dst->buckets[i] += data[i]; - } -} - -static double threshold_for_count_below(gpr_histogram *h, double count_below) { - double count_so_far; - double lower_bound; - double upper_bound; - size_t lower_idx; - size_t upper_idx; - - if (h->count == 0) { - return 0.0; - } - - if (count_below <= 0) { - return h->min_seen; - } - if (count_below >= h->count) { - return h->max_seen; - } - - /* find the lowest bucket that gets us above count_below */ - count_so_far = 0.0; - for (lower_idx = 0; lower_idx < h->num_buckets; lower_idx++) { - count_so_far += h->buckets[lower_idx]; - if (count_so_far >= count_below) { - break; - } - } - if (count_so_far == count_below) { - /* this bucket hits the threshold exactly... we should be midway through - any run of zero values following the bucket */ - for (upper_idx = lower_idx + 1; upper_idx < h->num_buckets; upper_idx++) { - if (h->buckets[upper_idx]) { - break; - } - } - return (bucket_start(h, (double)lower_idx) + - bucket_start(h, (double)upper_idx)) / - 2.0; - } else { - /* treat values as uniform throughout the bucket, and find where this value - should lie */ - lower_bound = bucket_start(h, (double)lower_idx); - upper_bound = bucket_start(h, (double)(lower_idx + 1)); - return GPR_CLAMP(upper_bound - - (upper_bound - lower_bound) * - (count_so_far - count_below) / - h->buckets[lower_idx], - h->min_seen, h->max_seen); - } -} - -double gpr_histogram_percentile(gpr_histogram *h, double percentile) { - return threshold_for_count_below(h, h->count * percentile / 100.0); -} - -double gpr_histogram_mean(gpr_histogram *h) { - GPR_ASSERT(h->count != 0); - return h->sum / h->count; -} - -double gpr_histogram_stddev(gpr_histogram *h) { - return sqrt(gpr_histogram_variance(h)); -} - -double gpr_histogram_variance(gpr_histogram *h) { - if (h->count == 0) return 0.0; - return (h->sum_of_squares * h->count - h->sum * h->sum) / - (h->count * h->count); -} - -double gpr_histogram_maximum(gpr_histogram *h) { return h->max_seen; } - -double gpr_histogram_minimum(gpr_histogram *h) { return h->min_seen; } - -double gpr_histogram_count(gpr_histogram *h) { return h->count; } - -double gpr_histogram_sum(gpr_histogram *h) { return h->sum; } - -double gpr_histogram_sum_of_squares(gpr_histogram *h) { - return h->sum_of_squares; -} - -const uint32_t *gpr_histogram_get_contents(gpr_histogram *h, size_t *size) { - *size = h->num_buckets; - return h->buckets; -} diff --git a/src/core/support/host_port.c b/src/core/support/host_port.c deleted file mode 100644 index 31243a7221..0000000000 --- a/src/core/support/host_port.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * - * Copyright 2015-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 - -#include - -#include -#include -#include -#include "src/core/support/string.h" - -int gpr_join_host_port(char **out, const char *host, int port) { - if (host[0] != '[' && strchr(host, ':') != NULL) { - /* IPv6 literals must be enclosed in brackets. */ - return gpr_asprintf(out, "[%s]:%d", host, port); - } else { - /* Ordinary non-bracketed host:port. */ - return gpr_asprintf(out, "%s:%d", host, port); - } -} - -int gpr_split_host_port(const char *name, char **host, char **port) { - const char *host_start; - size_t host_len; - const char *port_start; - - *host = NULL; - *port = NULL; - - if (name[0] == '[') { - /* Parse a bracketed host, typically an IPv6 literal. */ - const char *rbracket = strchr(name, ']'); - if (rbracket == NULL) { - /* Unmatched [ */ - return 0; - } - if (rbracket[1] == '\0') { - /* ] */ - port_start = NULL; - } else if (rbracket[1] == ':') { - /* ]: */ - port_start = rbracket + 2; - } else { - /* ] */ - return 0; - } - host_start = name + 1; - host_len = (size_t)(rbracket - host_start); - if (memchr(host_start, ':', host_len) == NULL) { - /* Require all bracketed hosts to contain a colon, because a hostname or - IPv4 address should never use brackets. */ - return 0; - } - } else { - const char *colon = strchr(name, ':'); - if (colon != NULL && strchr(colon + 1, ':') == NULL) { - /* Exactly 1 colon. Split into host:port. */ - host_start = name; - host_len = (size_t)(colon - name); - port_start = colon + 1; - } else { - /* 0 or 2+ colons. Bare hostname or IPv6 litearal. */ - host_start = name; - host_len = strlen(name); - port_start = NULL; - } - } - - /* Allocate return values. */ - *host = gpr_malloc(host_len + 1); - memcpy(*host, host_start, host_len); - (*host)[host_len] = '\0'; - - if (port_start != NULL) { - *port = gpr_strdup(port_start); - } - - return 1; -} diff --git a/src/core/support/load_file.c b/src/core/support/load_file.c deleted file mode 100644 index 650bd62ccb..0000000000 --- a/src/core/support/load_file.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * - * Copyright 2015-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/support/load_file.h" - -#include -#include - -#include -#include -#include - -#include "src/core/support/block_annotate.h" -#include "src/core/support/string.h" - -gpr_slice gpr_load_file(const char *filename, int add_null_terminator, - int *success) { - unsigned char *contents = NULL; - size_t contents_size = 0; - char *error_msg = NULL; - gpr_slice result = gpr_empty_slice(); - FILE *file; - size_t bytes_read = 0; - - GRPC_SCHEDULING_START_BLOCKING_REGION; - file = fopen(filename, "rb"); - if (file == NULL) { - gpr_asprintf(&error_msg, "Could not open file %s (error = %s).", filename, - strerror(errno)); - GPR_ASSERT(error_msg != NULL); - goto end; - } - fseek(file, 0, SEEK_END); - /* Converting to size_t on the assumption that it will not fail */ - contents_size = (size_t)ftell(file); - fseek(file, 0, SEEK_SET); - contents = gpr_malloc(contents_size + (add_null_terminator ? 1 : 0)); - bytes_read = fread(contents, 1, contents_size, file); - if (bytes_read < contents_size) { - GPR_ASSERT(ferror(file)); - gpr_asprintf(&error_msg, "Error %s occured while reading file %s.", - strerror(errno), filename); - GPR_ASSERT(error_msg != NULL); - goto end; - } - if (success != NULL) *success = 1; - if (add_null_terminator) { - contents[contents_size++] = 0; - } - result = gpr_slice_new(contents, contents_size, gpr_free); - -end: - if (error_msg != NULL) { - gpr_log(GPR_ERROR, "%s", error_msg); - gpr_free(error_msg); - if (success != NULL) *success = 0; - } - if (file != NULL) fclose(file); - GRPC_SCHEDULING_END_BLOCKING_REGION; - return result; -} diff --git a/src/core/support/load_file.h b/src/core/support/load_file.h deleted file mode 100644 index 5896654e9a..0000000000 --- a/src/core/support/load_file.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * - * Copyright 2015-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_SUPPORT_LOAD_FILE_H -#define GRPC_CORE_SUPPORT_LOAD_FILE_H - -#include - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* Loads the content of a file into a slice. add_null_terminator will add - a NULL terminator if non-zero. The success parameter, if not NULL, - will be set to 1 in case of success and 0 in case of failure. */ -gpr_slice gpr_load_file(const char *filename, int add_null_terminator, - int *success); - -#ifdef __cplusplus -} -#endif - -#endif /* GRPC_CORE_SUPPORT_LOAD_FILE_H */ diff --git a/src/core/support/log.c b/src/core/support/log.c deleted file mode 100644 index 04156a5b1f..0000000000 --- a/src/core/support/log.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include -#include - -#include -#include - -extern void gpr_default_log(gpr_log_func_args *args); -static gpr_log_func g_log_func = gpr_default_log; - -const char *gpr_log_severity_string(gpr_log_severity severity) { - switch (severity) { - case GPR_LOG_SEVERITY_DEBUG: - return "D"; - case GPR_LOG_SEVERITY_INFO: - return "I"; - case GPR_LOG_SEVERITY_ERROR: - return "E"; - } - GPR_UNREACHABLE_CODE(return "UNKNOWN"); -} - -void gpr_log_message(const char *file, int line, gpr_log_severity severity, - const char *message) { - gpr_log_func_args lfargs; - memset(&lfargs, 0, sizeof(lfargs)); - lfargs.file = file; - lfargs.line = line; - lfargs.severity = severity; - lfargs.message = message; - g_log_func(&lfargs); -} - -void gpr_set_log_function(gpr_log_func f) { g_log_func = f; } diff --git a/src/core/support/log_android.c b/src/core/support/log_android.c deleted file mode 100644 index 640c9d7099..0000000000 --- a/src/core/support/log_android.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * - * Copyright 2015-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 - -#ifdef GPR_ANDROID - -#include -#include -#include -#include -#include -#include - -static android_LogPriority severity_to_log_priority(gpr_log_severity severity) { - switch (severity) { - case GPR_LOG_SEVERITY_DEBUG: - return ANDROID_LOG_DEBUG; - case GPR_LOG_SEVERITY_INFO: - return ANDROID_LOG_INFO; - case GPR_LOG_SEVERITY_ERROR: - return ANDROID_LOG_ERROR; - } - return ANDROID_LOG_DEFAULT; -} - -void gpr_log(const char *file, int line, gpr_log_severity severity, - const char *format, ...) { - char *message = NULL; - va_list args; - va_start(args, format); - vasprintf(&message, format, args); - va_end(args); - gpr_log_message(file, line, severity, message); - free(message); -} - -void gpr_default_log(gpr_log_func_args *args) { - char *final_slash; - const char *display_file; - char *output = NULL; - - final_slash = strrchr(args->file, '/'); - if (final_slash == NULL) - display_file = args->file; - else - display_file = final_slash + 1; - - asprintf(&output, "%s:%d] %s", display_file, args->line, args->message); - - __android_log_write(severity_to_log_priority(args->severity), "GRPC", output); - - /* allocated by asprintf => use free, not gpr_free */ - free(output); -} - -#endif /* GPR_ANDROID */ diff --git a/src/core/support/log_linux.c b/src/core/support/log_linux.c deleted file mode 100644 index e60512c526..0000000000 --- a/src/core/support/log_linux.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * - * Copyright 2015-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 _POSIX_SOURCE -#define _POSIX_SOURCE -#endif - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include - -#ifdef GPR_LINUX - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static long gettid(void) { return syscall(__NR_gettid); } - -void gpr_log(const char *file, int line, gpr_log_severity severity, - const char *format, ...) { - char *message = NULL; - va_list args; - va_start(args, format); - if (vasprintf(&message, format, args) == -1) { - va_end(args); - return; - } - va_end(args); - gpr_log_message(file, line, severity, message); - free(message); -} - -void gpr_default_log(gpr_log_func_args *args) { - char *final_slash; - char *prefix; - const char *display_file; - char time_buffer[64]; - time_t timer; - gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME); - struct tm tm; - - timer = (time_t)now.tv_sec; - final_slash = strrchr(args->file, '/'); - if (final_slash == NULL) - display_file = args->file; - else - display_file = final_slash + 1; - - if (!localtime_r(&timer, &tm)) { - strcpy(time_buffer, "error:localtime"); - } else if (0 == - strftime(time_buffer, sizeof(time_buffer), "%m%d %H:%M:%S", &tm)) { - strcpy(time_buffer, "error:strftime"); - } - - gpr_asprintf(&prefix, "%s%s.%09d %7tu %s:%d]", - gpr_log_severity_string(args->severity), time_buffer, - (int)(now.tv_nsec), gettid(), display_file, args->line); - - fprintf(stderr, "%-60s %s\n", prefix, args->message); - gpr_free(prefix); -} - -#endif diff --git a/src/core/support/log_posix.c b/src/core/support/log_posix.c deleted file mode 100644 index 7429dd0a2c..0000000000 --- a/src/core/support/log_posix.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - * - * Copyright 2015-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 - -#if defined(GPR_POSIX_LOG) - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static intptr_t gettid(void) { return (intptr_t)pthread_self(); } - -void gpr_log(const char *file, int line, gpr_log_severity severity, - const char *format, ...) { - char buf[64]; - char *allocated = NULL; - char *message = NULL; - int ret; - va_list args; - va_start(args, format); - ret = vsnprintf(buf, sizeof(buf), format, args); - va_end(args); - if (ret < 0) { - message = NULL; - } else if ((size_t)ret <= sizeof(buf) - 1) { - message = buf; - } else { - message = allocated = gpr_malloc((size_t)ret + 1); - va_start(args, format); - vsnprintf(message, (size_t)(ret + 1), format, args); - va_end(args); - } - gpr_log_message(file, line, severity, message); - gpr_free(allocated); -} - -void gpr_default_log(gpr_log_func_args *args) { - char *final_slash; - const char *display_file; - char time_buffer[64]; - time_t timer; - gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME); - struct tm tm; - - timer = (time_t)now.tv_sec; - final_slash = strrchr(args->file, '/'); - if (final_slash == NULL) - display_file = args->file; - else - display_file = final_slash + 1; - - if (!localtime_r(&timer, &tm)) { - strcpy(time_buffer, "error:localtime"); - } else if (0 == - strftime(time_buffer, sizeof(time_buffer), "%m%d %H:%M:%S", &tm)) { - strcpy(time_buffer, "error:strftime"); - } - - fprintf(stderr, "%s%s.%09d %7tu %s:%d] %s\n", - gpr_log_severity_string(args->severity), time_buffer, - (int)(now.tv_nsec), gettid(), display_file, args->line, - args->message); -} - -#endif /* defined(GPR_POSIX_LOG) */ diff --git a/src/core/support/log_win32.c b/src/core/support/log_win32.c deleted file mode 100644 index 89ec0917d5..0000000000 --- a/src/core/support/log_win32.c +++ /dev/null @@ -1,126 +0,0 @@ -/* - * - * Copyright 2015-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 - -#ifdef GPR_WIN32 - -#include -#include - -#include -#include -#include -#include -#include - -#include "src/core/support/string.h" -#include "src/core/support/string_win32.h" - -void gpr_log(const char *file, int line, gpr_log_severity severity, - const char *format, ...) { - char *message = NULL; - va_list args; - int ret; - - /* Determine the length. */ - va_start(args, format); - ret = _vscprintf(format, args); - va_end(args); - if (ret < 0) { - message = NULL; - } else { - /* Allocate a new buffer, with space for the NUL terminator. */ - size_t strp_buflen = (size_t)ret + 1; - message = gpr_malloc(strp_buflen); - - /* Print to the buffer. */ - va_start(args, format); - ret = vsnprintf_s(message, strp_buflen, _TRUNCATE, format, args); - va_end(args); - if ((size_t)ret != strp_buflen - 1) { - /* This should never happen. */ - gpr_free(message); - message = NULL; - } - } - - gpr_log_message(file, line, severity, message); - gpr_free(message); -} - -/* Simple starter implementation */ -void gpr_default_log(gpr_log_func_args *args) { - char *final_slash; - const char *display_file; - char time_buffer[64]; - time_t timer; - gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME); - struct tm tm; - - timer = (time_t)now.tv_sec; - final_slash = strrchr(args->file, '\\'); - if (final_slash == NULL) - display_file = args->file; - else - display_file = final_slash + 1; - - if (localtime_s(&tm, &timer)) { - strcpy(time_buffer, "error:localtime"); - } else if (0 == - strftime(time_buffer, sizeof(time_buffer), "%m%d %H:%M:%S", &tm)) { - strcpy(time_buffer, "error:strftime"); - } - - fprintf(stderr, "%s%s.%09u %5lu %s:%d] %s\n", - gpr_log_severity_string(args->severity), time_buffer, - (int)(now.tv_nsec), GetCurrentThreadId(), display_file, args->line, - args->message); - fflush(stderr); -} - -char *gpr_format_message(int messageid) { - LPTSTR tmessage; - char *message; - DWORD status = FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, (DWORD)messageid, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR)(&tmessage), 0, NULL); - if (status == 0) return gpr_strdup("Unable to retrieve error string"); - message = gpr_tchar_to_char(tmessage); - LocalFree(tmessage); - return message; -} - -#endif /* GPR_WIN32 */ diff --git a/src/core/support/murmur_hash.c b/src/core/support/murmur_hash.c deleted file mode 100644 index a5261c0cc0..0000000000 --- a/src/core/support/murmur_hash.c +++ /dev/null @@ -1,96 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/support/murmur_hash.h" - -#define ROTL32(x, r) ((x) << (r)) | ((x) >> (32 - (r))) - -#define FMIX32(h) \ - (h) ^= (h) >> 16; \ - (h) *= 0x85ebca6b; \ - (h) ^= (h) >> 13; \ - (h) *= 0xc2b2ae35; \ - (h) ^= (h) >> 16; - -/* Block read - if your platform needs to do endian-swapping or can only - handle aligned reads, do the conversion here */ -#define GETBLOCK32(p, i) (p)[(i)] - -uint32_t gpr_murmur_hash3(const void *key, size_t len, uint32_t seed) { - const uint8_t *data = (const uint8_t *)key; - const size_t nblocks = len / 4; - int i; - - uint32_t h1 = seed; - uint32_t k1; - - const uint32_t c1 = 0xcc9e2d51; - const uint32_t c2 = 0x1b873593; - - const uint32_t *blocks = ((const uint32_t *)key) + nblocks; - const uint8_t *tail = (const uint8_t *)(data + nblocks * 4); - - /* body */ - for (i = -(int)nblocks; i; i++) { - k1 = GETBLOCK32(blocks, i); - - k1 *= c1; - k1 = ROTL32(k1, 15); - k1 *= c2; - - h1 ^= k1; - h1 = ROTL32(h1, 13); - h1 = h1 * 5 + 0xe6546b64; - } - - k1 = 0; - - /* tail */ - switch (len & 3) { - case 3: - k1 ^= ((uint32_t)tail[2]) << 16; - case 2: - k1 ^= ((uint32_t)tail[1]) << 8; - case 1: - k1 ^= tail[0]; - k1 *= c1; - k1 = ROTL32(k1, 15); - k1 *= c2; - h1 ^= k1; - }; - - /* finalization */ - h1 ^= (uint32_t)len; - FMIX32(h1); - return h1; -} diff --git a/src/core/support/murmur_hash.h b/src/core/support/murmur_hash.h deleted file mode 100644 index 0f0b399e5d..0000000000 --- a/src/core/support/murmur_hash.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * - * Copyright 2015-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_SUPPORT_MURMUR_HASH_H -#define GRPC_CORE_SUPPORT_MURMUR_HASH_H - -#include - -#include - -/* compute the hash of key (length len) */ -uint32_t gpr_murmur_hash3(const void *key, size_t len, uint32_t seed); - -#endif /* GRPC_CORE_SUPPORT_MURMUR_HASH_H */ diff --git a/src/core/support/slice.c b/src/core/support/slice.c deleted file mode 100644 index b9a7c77bda..0000000000 --- a/src/core/support/slice.c +++ /dev/null @@ -1,343 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include -#include -#include - -#include - -gpr_slice gpr_empty_slice(void) { - gpr_slice out; - out.refcount = 0; - out.data.inlined.length = 0; - return out; -} - -gpr_slice gpr_slice_ref(gpr_slice slice) { - if (slice.refcount) { - slice.refcount->ref(slice.refcount); - } - return slice; -} - -void gpr_slice_unref(gpr_slice slice) { - if (slice.refcount) { - slice.refcount->unref(slice.refcount); - } -} - -/* gpr_slice_from_static_string support structure - a refcount that does - nothing */ -static void noop_ref_or_unref(void *unused) {} - -static gpr_slice_refcount noop_refcount = {noop_ref_or_unref, - noop_ref_or_unref}; - -gpr_slice gpr_slice_from_static_string(const char *s) { - gpr_slice slice; - slice.refcount = &noop_refcount; - slice.data.refcounted.bytes = (uint8_t *)s; - slice.data.refcounted.length = strlen(s); - return slice; -} - -/* gpr_slice_new support structures - we create a refcount object extended - with the user provided data pointer & destroy function */ -typedef struct new_slice_refcount { - gpr_slice_refcount rc; - gpr_refcount refs; - void (*user_destroy)(void *); - void *user_data; -} new_slice_refcount; - -static void new_slice_ref(void *p) { - new_slice_refcount *r = p; - gpr_ref(&r->refs); -} - -static void new_slice_unref(void *p) { - new_slice_refcount *r = p; - if (gpr_unref(&r->refs)) { - r->user_destroy(r->user_data); - gpr_free(r); - } -} - -gpr_slice gpr_slice_new(void *p, size_t len, void (*destroy)(void *)) { - gpr_slice slice; - new_slice_refcount *rc = gpr_malloc(sizeof(new_slice_refcount)); - gpr_ref_init(&rc->refs, 1); - rc->rc.ref = new_slice_ref; - rc->rc.unref = new_slice_unref; - rc->user_destroy = destroy; - rc->user_data = p; - - slice.refcount = &rc->rc; - slice.data.refcounted.bytes = p; - slice.data.refcounted.length = len; - return slice; -} - -/* gpr_slice_new_with_len support structures - we create a refcount object - extended with the user provided data pointer & destroy function */ -typedef struct new_with_len_slice_refcount { - gpr_slice_refcount rc; - gpr_refcount refs; - void *user_data; - size_t user_length; - void (*user_destroy)(void *, size_t); -} new_with_len_slice_refcount; - -static void new_with_len_ref(void *p) { - new_with_len_slice_refcount *r = p; - gpr_ref(&r->refs); -} - -static void new_with_len_unref(void *p) { - new_with_len_slice_refcount *r = p; - if (gpr_unref(&r->refs)) { - r->user_destroy(r->user_data, r->user_length); - gpr_free(r); - } -} - -gpr_slice gpr_slice_new_with_len(void *p, size_t len, - void (*destroy)(void *, size_t)) { - gpr_slice slice; - new_with_len_slice_refcount *rc = - gpr_malloc(sizeof(new_with_len_slice_refcount)); - gpr_ref_init(&rc->refs, 1); - rc->rc.ref = new_with_len_ref; - rc->rc.unref = new_with_len_unref; - rc->user_destroy = destroy; - rc->user_data = p; - rc->user_length = len; - - slice.refcount = &rc->rc; - slice.data.refcounted.bytes = p; - slice.data.refcounted.length = len; - return slice; -} - -gpr_slice gpr_slice_from_copied_buffer(const char *source, size_t length) { - gpr_slice slice = gpr_slice_malloc(length); - memcpy(GPR_SLICE_START_PTR(slice), source, length); - return slice; -} - -gpr_slice gpr_slice_from_copied_string(const char *source) { - return gpr_slice_from_copied_buffer(source, strlen(source)); -} - -typedef struct { - gpr_slice_refcount base; - gpr_refcount refs; -} malloc_refcount; - -static void malloc_ref(void *p) { - malloc_refcount *r = p; - gpr_ref(&r->refs); -} - -static void malloc_unref(void *p) { - malloc_refcount *r = p; - if (gpr_unref(&r->refs)) { - gpr_free(r); - } -} - -gpr_slice gpr_slice_malloc(size_t length) { - gpr_slice slice; - - if (length > sizeof(slice.data.inlined.bytes)) { - /* Memory layout used by the slice created here: - - +-----------+----------------------------------------------------------+ - | refcount | bytes | - +-----------+----------------------------------------------------------+ - - refcount is a malloc_refcount - bytes is an array of bytes of the requested length - Both parts are placed in the same allocation returned from gpr_malloc */ - malloc_refcount *rc = gpr_malloc(sizeof(malloc_refcount) + length); - - /* Initial refcount on rc is 1 - and it's up to the caller to release - this reference. */ - gpr_ref_init(&rc->refs, 1); - - rc->base.ref = malloc_ref; - rc->base.unref = malloc_unref; - - /* Build up the slice to be returned. */ - /* The slices refcount points back to the allocated block. */ - slice.refcount = &rc->base; - /* The data bytes are placed immediately after the refcount struct */ - slice.data.refcounted.bytes = (uint8_t *)(rc + 1); - /* And the length of the block is set to the requested length */ - slice.data.refcounted.length = length; - } else { - /* small slice: just inline the data */ - slice.refcount = NULL; - slice.data.inlined.length = (uint8_t)length; - } - return slice; -} - -gpr_slice gpr_slice_sub_no_ref(gpr_slice source, size_t begin, size_t end) { - gpr_slice subset; - - GPR_ASSERT(end >= begin); - - if (source.refcount) { - /* Enforce preconditions */ - GPR_ASSERT(source.data.refcounted.length >= end); - - /* Build the result */ - subset.refcount = source.refcount; - /* Point into the source array */ - subset.data.refcounted.bytes = source.data.refcounted.bytes + begin; - subset.data.refcounted.length = end - begin; - } else { - /* Enforce preconditions */ - GPR_ASSERT(source.data.inlined.length >= end); - subset.refcount = NULL; - subset.data.inlined.length = (uint8_t)(end - begin); - memcpy(subset.data.inlined.bytes, source.data.inlined.bytes + begin, - end - begin); - } - return subset; -} - -gpr_slice gpr_slice_sub(gpr_slice source, size_t begin, size_t end) { - gpr_slice subset; - - if (end - begin <= sizeof(subset.data.inlined.bytes)) { - subset.refcount = NULL; - subset.data.inlined.length = (uint8_t)(end - begin); - memcpy(subset.data.inlined.bytes, GPR_SLICE_START_PTR(source) + begin, - end - begin); - } else { - subset = gpr_slice_sub_no_ref(source, begin, end); - /* Bump the refcount */ - subset.refcount->ref(subset.refcount); - } - return subset; -} - -gpr_slice gpr_slice_split_tail(gpr_slice *source, size_t split) { - gpr_slice tail; - - if (source->refcount == NULL) { - /* inlined data, copy it out */ - GPR_ASSERT(source->data.inlined.length >= split); - tail.refcount = NULL; - tail.data.inlined.length = (uint8_t)(source->data.inlined.length - split); - memcpy(tail.data.inlined.bytes, source->data.inlined.bytes + split, - tail.data.inlined.length); - source->data.inlined.length = (uint8_t)split; - } else { - size_t tail_length = source->data.refcounted.length - split; - GPR_ASSERT(source->data.refcounted.length >= split); - if (tail_length < sizeof(tail.data.inlined.bytes)) { - /* Copy out the bytes - it'll be cheaper than refcounting */ - tail.refcount = NULL; - tail.data.inlined.length = (uint8_t)tail_length; - memcpy(tail.data.inlined.bytes, source->data.refcounted.bytes + split, - tail_length); - } else { - /* Build the result */ - tail.refcount = source->refcount; - /* Bump the refcount */ - tail.refcount->ref(tail.refcount); - /* Point into the source array */ - tail.data.refcounted.bytes = source->data.refcounted.bytes + split; - tail.data.refcounted.length = tail_length; - } - source->data.refcounted.length = split; - } - - return tail; -} - -gpr_slice gpr_slice_split_head(gpr_slice *source, size_t split) { - gpr_slice head; - - if (source->refcount == NULL) { - GPR_ASSERT(source->data.inlined.length >= split); - - head.refcount = NULL; - head.data.inlined.length = (uint8_t)split; - memcpy(head.data.inlined.bytes, source->data.inlined.bytes, split); - source->data.inlined.length = - (uint8_t)(source->data.inlined.length - split); - memmove(source->data.inlined.bytes, source->data.inlined.bytes + split, - source->data.inlined.length); - } else if (split < sizeof(head.data.inlined.bytes)) { - GPR_ASSERT(source->data.refcounted.length >= split); - - head.refcount = NULL; - head.data.inlined.length = (uint8_t)split; - memcpy(head.data.inlined.bytes, source->data.refcounted.bytes, split); - source->data.refcounted.bytes += split; - source->data.refcounted.length -= split; - } else { - GPR_ASSERT(source->data.refcounted.length >= split); - - /* Build the result */ - head.refcount = source->refcount; - /* Bump the refcount */ - head.refcount->ref(head.refcount); - /* Point into the source array */ - head.data.refcounted.bytes = source->data.refcounted.bytes; - head.data.refcounted.length = split; - source->data.refcounted.bytes += split; - source->data.refcounted.length -= split; - } - - return head; -} - -int gpr_slice_cmp(gpr_slice a, gpr_slice b) { - int d = (int)(GPR_SLICE_LENGTH(a) - GPR_SLICE_LENGTH(b)); - if (d != 0) return d; - return memcmp(GPR_SLICE_START_PTR(a), GPR_SLICE_START_PTR(b), - GPR_SLICE_LENGTH(a)); -} - -int gpr_slice_str_cmp(gpr_slice a, const char *b) { - size_t b_length = strlen(b); - int d = (int)(GPR_SLICE_LENGTH(a) - b_length); - if (d != 0) return d; - return memcmp(GPR_SLICE_START_PTR(a), b, b_length); -} diff --git a/src/core/support/slice_buffer.c b/src/core/support/slice_buffer.c deleted file mode 100644 index 66f111d767..0000000000 --- a/src/core/support/slice_buffer.c +++ /dev/null @@ -1,282 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include -#include - -#include - -#include -#include -#include - -/* grow a buffer; requires GRPC_SLICE_BUFFER_INLINE_ELEMENTS > 1 */ -#define GROW(x) (3 * (x) / 2) - -static void maybe_embiggen(gpr_slice_buffer *sb) { - if (sb->count == sb->capacity) { - sb->capacity = GROW(sb->capacity); - GPR_ASSERT(sb->capacity > sb->count); - if (sb->slices == sb->inlined) { - sb->slices = gpr_malloc(sb->capacity * sizeof(gpr_slice)); - memcpy(sb->slices, sb->inlined, sb->count * sizeof(gpr_slice)); - } else { - sb->slices = gpr_realloc(sb->slices, sb->capacity * sizeof(gpr_slice)); - } - } -} - -void gpr_slice_buffer_init(gpr_slice_buffer *sb) { - sb->count = 0; - sb->length = 0; - sb->capacity = GRPC_SLICE_BUFFER_INLINE_ELEMENTS; - sb->slices = sb->inlined; -} - -void gpr_slice_buffer_destroy(gpr_slice_buffer *sb) { - gpr_slice_buffer_reset_and_unref(sb); - if (sb->slices != sb->inlined) { - gpr_free(sb->slices); - } -} - -uint8_t *gpr_slice_buffer_tiny_add(gpr_slice_buffer *sb, size_t n) { - gpr_slice *back; - uint8_t *out; - - sb->length += n; - - if (sb->count == 0) goto add_new; - back = &sb->slices[sb->count - 1]; - if (back->refcount) goto add_new; - if ((back->data.inlined.length + n) > sizeof(back->data.inlined.bytes)) - goto add_new; - out = back->data.inlined.bytes + back->data.inlined.length; - back->data.inlined.length = (uint8_t)(back->data.inlined.length + n); - return out; - -add_new: - maybe_embiggen(sb); - back = &sb->slices[sb->count]; - sb->count++; - back->refcount = NULL; - back->data.inlined.length = (uint8_t)n; - return back->data.inlined.bytes; -} - -size_t gpr_slice_buffer_add_indexed(gpr_slice_buffer *sb, gpr_slice s) { - size_t out = sb->count; - maybe_embiggen(sb); - sb->slices[out] = s; - sb->length += GPR_SLICE_LENGTH(s); - sb->count = out + 1; - return out; -} - -void gpr_slice_buffer_add(gpr_slice_buffer *sb, gpr_slice s) { - size_t n = sb->count; - /* if both the last slice in the slice buffer and the slice being added - are inlined (that is, that they carry their data inside the slice data - structure), and the back slice is not full, then concatenate directly - into the back slice, preventing many small slices being passed into - writes */ - if (!s.refcount && n) { - gpr_slice *back = &sb->slices[n - 1]; - if (!back->refcount && back->data.inlined.length < GPR_SLICE_INLINED_SIZE) { - if (s.data.inlined.length + back->data.inlined.length <= - GPR_SLICE_INLINED_SIZE) { - memcpy(back->data.inlined.bytes + back->data.inlined.length, - s.data.inlined.bytes, s.data.inlined.length); - back->data.inlined.length = - (uint8_t)(back->data.inlined.length + s.data.inlined.length); - } else { - size_t cp1 = GPR_SLICE_INLINED_SIZE - back->data.inlined.length; - memcpy(back->data.inlined.bytes + back->data.inlined.length, - s.data.inlined.bytes, cp1); - back->data.inlined.length = GPR_SLICE_INLINED_SIZE; - maybe_embiggen(sb); - back = &sb->slices[n]; - sb->count = n + 1; - back->refcount = NULL; - back->data.inlined.length = (uint8_t)(s.data.inlined.length - cp1); - memcpy(back->data.inlined.bytes, s.data.inlined.bytes + cp1, - s.data.inlined.length - cp1); - } - sb->length += s.data.inlined.length; - return; /* early out */ - } - } - gpr_slice_buffer_add_indexed(sb, s); -} - -void gpr_slice_buffer_addn(gpr_slice_buffer *sb, gpr_slice *s, size_t n) { - size_t i; - for (i = 0; i < n; i++) { - gpr_slice_buffer_add(sb, s[i]); - } -} - -void gpr_slice_buffer_pop(gpr_slice_buffer *sb) { - if (sb->count != 0) { - size_t count = --sb->count; - sb->length -= GPR_SLICE_LENGTH(sb->slices[count]); - } -} - -void gpr_slice_buffer_reset_and_unref(gpr_slice_buffer *sb) { - size_t i; - - for (i = 0; i < sb->count; i++) { - gpr_slice_unref(sb->slices[i]); - } - - sb->count = 0; - sb->length = 0; -} - -void gpr_slice_buffer_swap(gpr_slice_buffer *a, gpr_slice_buffer *b) { - GPR_SWAP(size_t, a->count, b->count); - GPR_SWAP(size_t, a->capacity, b->capacity); - GPR_SWAP(size_t, a->length, b->length); - - if (a->slices == a->inlined) { - if (b->slices == b->inlined) { - /* swap contents of inlined buffer */ - gpr_slice temp[GRPC_SLICE_BUFFER_INLINE_ELEMENTS]; - memcpy(temp, a->slices, b->count * sizeof(gpr_slice)); - memcpy(a->slices, b->slices, a->count * sizeof(gpr_slice)); - memcpy(b->slices, temp, b->count * sizeof(gpr_slice)); - } else { - /* a is inlined, b is not - copy a inlined into b, fix pointers */ - a->slices = b->slices; - b->slices = b->inlined; - memcpy(b->slices, a->inlined, b->count * sizeof(gpr_slice)); - } - } else if (b->slices == b->inlined) { - /* b is inlined, a is not - copy b inlined int a, fix pointers */ - b->slices = a->slices; - a->slices = a->inlined; - memcpy(a->slices, b->inlined, a->count * sizeof(gpr_slice)); - } else { - /* no inlining: easy swap */ - GPR_SWAP(gpr_slice *, a->slices, b->slices); - } -} - -void gpr_slice_buffer_move_into(gpr_slice_buffer *src, gpr_slice_buffer *dst) { - /* anything to move? */ - if (src->count == 0) { - return; - } - /* anything in dst? */ - if (dst->count == 0) { - gpr_slice_buffer_swap(src, dst); - return; - } - /* both buffers have data - copy, and reset src */ - gpr_slice_buffer_addn(dst, src->slices, src->count); - src->count = 0; - src->length = 0; -} - -void gpr_slice_buffer_move_first(gpr_slice_buffer *src, size_t n, - gpr_slice_buffer *dst) { - size_t src_idx; - size_t output_len = dst->length + n; - size_t new_input_len = src->length - n; - GPR_ASSERT(src->length >= n); - if (src->length == n) { - gpr_slice_buffer_move_into(src, dst); - return; - } - src_idx = 0; - while (src_idx < src->capacity) { - gpr_slice slice = src->slices[src_idx]; - size_t slice_len = GPR_SLICE_LENGTH(slice); - if (n > slice_len) { - gpr_slice_buffer_add(dst, slice); - n -= slice_len; - src_idx++; - } else if (n == slice_len) { - gpr_slice_buffer_add(dst, slice); - src_idx++; - break; - } else { /* n < slice_len */ - src->slices[src_idx] = gpr_slice_split_tail(&slice, n); - GPR_ASSERT(GPR_SLICE_LENGTH(slice) == n); - GPR_ASSERT(GPR_SLICE_LENGTH(src->slices[src_idx]) == slice_len - n); - gpr_slice_buffer_add(dst, slice); - break; - } - } - GPR_ASSERT(dst->length == output_len); - memmove(src->slices, src->slices + src_idx, - sizeof(gpr_slice) * (src->count - src_idx)); - src->count -= src_idx; - src->length = new_input_len; - GPR_ASSERT(src->count > 0); -} - -void gpr_slice_buffer_trim_end(gpr_slice_buffer *sb, size_t n, - gpr_slice_buffer *garbage) { - GPR_ASSERT(n <= sb->length); - sb->length -= n; - for (;;) { - size_t idx = sb->count - 1; - gpr_slice slice = sb->slices[idx]; - size_t slice_len = GPR_SLICE_LENGTH(slice); - if (slice_len > n) { - sb->slices[idx] = gpr_slice_split_head(&slice, slice_len - n); - gpr_slice_buffer_add_indexed(garbage, slice); - return; - } else if (slice_len == n) { - gpr_slice_buffer_add_indexed(garbage, slice); - sb->count = idx; - return; - } else { - gpr_slice_buffer_add_indexed(garbage, slice); - n -= slice_len; - sb->count = idx; - } - } -} - -gpr_slice gpr_slice_buffer_take_first(gpr_slice_buffer *sb) { - gpr_slice slice; - GPR_ASSERT(sb->count > 0); - slice = sb->slices[0]; - memmove(&sb->slices[0], &sb->slices[1], (sb->count - 1) * sizeof(gpr_slice)); - sb->count--; - sb->length -= GPR_SLICE_LENGTH(slice); - return slice; -} diff --git a/src/core/support/stack_lockfree.c b/src/core/support/stack_lockfree.c deleted file mode 100644 index 8e0bbfaee8..0000000000 --- a/src/core/support/stack_lockfree.c +++ /dev/null @@ -1,185 +0,0 @@ -/* - * - * Copyright 2015-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/support/stack_lockfree.h" - -#include -#include - -#include -#include -#include -#include - -/* The lockfree node structure is a single architecture-level - word that allows for an atomic CAS to set it up. */ -struct lockfree_node_contents { - /* next thing to look at. Actual index for head, next index otherwise */ - uint16_t index; -#ifdef GPR_ARCH_64 - uint16_t pad; - uint32_t aba_ctr; -#else -#ifdef GPR_ARCH_32 - uint16_t aba_ctr; -#else -#error Unsupported bit width architecture -#endif -#endif -}; - -/* Use a union to make sure that these are in the same bits as an atm word */ -typedef union lockfree_node { - gpr_atm atm; - struct lockfree_node_contents contents; -} lockfree_node; - -/* make sure that entries aligned to 8-bytes */ -#define ENTRY_ALIGNMENT_BITS 3 -/* reserve this entry as invalid */ -#define INVALID_ENTRY_INDEX ((1 << 16) - 1) - -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(size_t entries) { - gpr_stack_lockfree *stack; - stack = gpr_malloc(sizeof(*stack)); - /* Since we only allocate 16 bits to represent an entry number, - * make sure that we are within the desired range */ - /* Reserve the highest entry number as a dummy */ - GPR_ASSERT(entries < INVALID_ENTRY_INDEX); - stack->entries = gpr_malloc_aligned(entries * sizeof(stack->entries[0]), - ENTRY_ALIGNMENT_BITS); - /* Clear out all entries */ - memset(stack->entries, 0, entries * sizeof(stack->entries[0])); - memset(&stack->head, 0, sizeof(stack->head)); -#ifndef NDEBUG - memset(&stack->pushed, 0, sizeof(stack->pushed)); -#endif - - GPR_ASSERT(sizeof(stack->entries->atm) == sizeof(stack->entries->contents)); - - /* Point the head at reserved dummy entry */ - stack->head.contents.index = INVALID_ENTRY_INDEX; -/* Fill in the pad and aba_ctr to avoid confusing memcheck tools */ -#ifdef GPR_ARCH_64 - stack->head.contents.pad = 0; -#endif - stack->head.contents.aba_ctr = 0; - return stack; -} - -void gpr_stack_lockfree_destroy(gpr_stack_lockfree *stack) { - gpr_free_aligned(stack->entries); - gpr_free(stack); -} - -int gpr_stack_lockfree_push(gpr_stack_lockfree *stack, int entry) { - lockfree_node head; - lockfree_node newhead; - lockfree_node curent; - lockfree_node newent; - - /* First fill in the entry's index and aba ctr for new head */ - newhead.contents.index = (uint16_t)entry; -#ifdef GPR_ARCH_64 - /* Fill in the pad to avoid confusing memcheck tools */ - newhead.contents.pad = 0; -#endif - - /* Also post-increment the aba_ctr */ - curent.atm = gpr_atm_no_barrier_load(&stack->entries[entry].atm); - newhead.contents.aba_ctr = ++curent.contents.aba_ctr; - gpr_atm_no_barrier_store(&stack->entries[entry].atm, curent.atm); - -#ifndef NDEBUG - /* Check for double push */ - { - int pushed_index = entry / (int)(8 * sizeof(gpr_atm)); - int pushed_bit = entry % (int)(8 * sizeof(gpr_atm)); - gpr_atm old_val; - - old_val = gpr_atm_no_barrier_fetch_add(&stack->pushed[pushed_index], - ((gpr_atm)1 << pushed_bit)); - GPR_ASSERT((old_val & (((gpr_atm)1) << pushed_bit)) == 0); - } -#endif - - do { - /* Atomically get the existing head value for use */ - head.atm = gpr_atm_no_barrier_load(&(stack->head.atm)); - /* Point to it */ - newent.atm = gpr_atm_no_barrier_load(&stack->entries[entry].atm); - newent.contents.index = head.contents.index; - gpr_atm_no_barrier_store(&stack->entries[entry].atm, newent.atm); - } while (!gpr_atm_rel_cas(&(stack->head.atm), head.atm, newhead.atm)); - /* Use rel_cas above to make sure that entry index is set properly */ - return head.contents.index == INVALID_ENTRY_INDEX; -} - -int gpr_stack_lockfree_pop(gpr_stack_lockfree *stack) { - lockfree_node head; - lockfree_node newhead; - - do { - head.atm = gpr_atm_acq_load(&(stack->head.atm)); - if (head.contents.index == INVALID_ENTRY_INDEX) { - return -1; - } - newhead.atm = - gpr_atm_no_barrier_load(&(stack->entries[head.contents.index].atm)); - - } while (!gpr_atm_no_barrier_cas(&(stack->head.atm), head.atm, newhead.atm)); -#ifndef NDEBUG - /* Check for valid pop */ - { - int pushed_index = head.contents.index / (8 * sizeof(gpr_atm)); - int pushed_bit = head.contents.index % (8 * sizeof(gpr_atm)); - gpr_atm old_val; - - old_val = gpr_atm_no_barrier_fetch_add(&stack->pushed[pushed_index], - -((gpr_atm)1 << pushed_bit)); - GPR_ASSERT((old_val & (((gpr_atm)1) << pushed_bit)) != 0); - } -#endif - - return head.contents.index; -} diff --git a/src/core/support/stack_lockfree.h b/src/core/support/stack_lockfree.h deleted file mode 100644 index d6fd06d67c..0000000000 --- a/src/core/support/stack_lockfree.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * - * Copyright 2015-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_SUPPORT_STACK_LOCKFREE_H -#define GRPC_CORE_SUPPORT_STACK_LOCKFREE_H - -#include - -typedef struct gpr_stack_lockfree gpr_stack_lockfree; - -/* This stack must specify the maximum number of entries to track. - The current implementation only allows up to 65534 entries */ -gpr_stack_lockfree *gpr_stack_lockfree_create(size_t entries); -void gpr_stack_lockfree_destroy(gpr_stack_lockfree *stack); - -/* Pass in a valid entry number for the next stack entry */ -/* Returns 1 if this is the first element on the stack, 0 otherwise */ -int gpr_stack_lockfree_push(gpr_stack_lockfree *, int entry); - -/* Returns -1 on empty or the actual entry number */ -int gpr_stack_lockfree_pop(gpr_stack_lockfree *stack); - -#endif /* GRPC_CORE_SUPPORT_STACK_LOCKFREE_H */ diff --git a/src/core/support/string.c b/src/core/support/string.c deleted file mode 100644 index 1f541de40f..0000000000 --- a/src/core/support/string.c +++ /dev/null @@ -1,296 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/support/string.h" - -#include -#include -#include - -#include -#include -#include -#include - -char *gpr_strdup(const char *src) { - char *dst; - size_t len; - - if (!src) { - return NULL; - } - - len = strlen(src) + 1; - dst = gpr_malloc(len); - - memcpy(dst, src, len); - - return dst; -} - -typedef struct { - size_t capacity; - size_t length; - char *data; -} dump_out; - -static dump_out dump_out_create(void) { - dump_out r = {0, 0, NULL}; - return r; -} - -static void dump_out_append(dump_out *out, char c) { - if (out->length == out->capacity) { - out->capacity = GPR_MAX(8, 2 * out->capacity); - out->data = gpr_realloc(out->data, out->capacity); - } - out->data[out->length++] = c; -} - -static void hexdump(dump_out *out, const char *buf, size_t len) { - static const char hex[16] = "0123456789abcdef"; - - const uint8_t *const beg = (const uint8_t *)buf; - const uint8_t *const end = beg + len; - const uint8_t *cur; - - for (cur = beg; cur != end; ++cur) { - if (cur != beg) dump_out_append(out, ' '); - dump_out_append(out, hex[*cur >> 4]); - dump_out_append(out, hex[*cur & 0xf]); - } -} - -static void asciidump(dump_out *out, const char *buf, size_t len) { - const uint8_t *const beg = (const uint8_t *)buf; - const uint8_t *const end = beg + len; - const uint8_t *cur; - int out_was_empty = (out->length == 0); - if (!out_was_empty) { - dump_out_append(out, ' '); - dump_out_append(out, '\''); - } - for (cur = beg; cur != end; ++cur) { - dump_out_append(out, (char)(isprint(*cur) ? *(char *)cur : '.')); - } - if (!out_was_empty) { - dump_out_append(out, '\''); - } -} - -char *gpr_dump(const char *buf, size_t len, uint32_t flags) { - dump_out out = dump_out_create(); - if (flags & GPR_DUMP_HEX) { - hexdump(&out, buf, len); - } - if (flags & GPR_DUMP_ASCII) { - asciidump(&out, buf, len); - } - dump_out_append(&out, 0); - return out.data; -} - -char *gpr_dump_slice(gpr_slice s, uint32_t flags) { - return gpr_dump((const char *)GPR_SLICE_START_PTR(s), GPR_SLICE_LENGTH(s), - flags); -} - -int gpr_parse_bytes_to_uint32(const char *buf, size_t len, uint32_t *result) { - uint32_t out = 0; - uint32_t new; - size_t i; - - if (len == 0) return 0; /* must have some bytes */ - - for (i = 0; i < len; i++) { - if (buf[i] < '0' || buf[i] > '9') return 0; /* bad char */ - new = 10 * out + (uint32_t)(buf[i] - '0'); - if (new < out) return 0; /* overflow */ - out = new; - } - - *result = out; - return 1; -} - -void gpr_reverse_bytes(char *str, int len) { - char *p1, *p2; - for (p1 = str, p2 = str + len - 1; p2 > p1; ++p1, --p2) { - char temp = *p1; - *p1 = *p2; - *p2 = temp; - } -} - -int gpr_ltoa(long value, char *string) { - long sign; - int i = 0; - - if (value == 0) { - string[0] = '0'; - string[1] = 0; - return 1; - } - - sign = value < 0 ? -1 : 1; - while (value) { - string[i++] = (char)('0' + sign * (value % 10)); - value /= 10; - } - if (sign < 0) string[i++] = '-'; - gpr_reverse_bytes(string, i); - string[i] = 0; - return i; -} - -int int64_ttoa(int64_t value, char *string) { - int64_t sign; - int i = 0; - - if (value == 0) { - string[0] = '0'; - string[1] = 0; - return 1; - } - - sign = value < 0 ? -1 : 1; - while (value) { - string[i++] = (char)('0' + sign * (value % 10)); - value /= 10; - } - if (sign < 0) string[i++] = '-'; - gpr_reverse_bytes(string, i); - string[i] = 0; - return i; -} - -char *gpr_strjoin(const char **strs, size_t nstrs, size_t *final_length) { - return gpr_strjoin_sep(strs, nstrs, "", final_length); -} - -char *gpr_strjoin_sep(const char **strs, size_t nstrs, const char *sep, - size_t *final_length) { - const size_t sep_len = strlen(sep); - size_t out_length = 0; - size_t i; - char *out; - for (i = 0; i < nstrs; i++) { - out_length += strlen(strs[i]); - } - out_length += 1; /* null terminator */ - if (nstrs > 0) { - out_length += sep_len * (nstrs - 1); /* separators */ - } - out = gpr_malloc(out_length); - out_length = 0; - for (i = 0; i < nstrs; i++) { - const size_t slen = strlen(strs[i]); - if (i != 0) { - memcpy(out + out_length, sep, sep_len); - out_length += sep_len; - } - memcpy(out + out_length, strs[i], slen); - out_length += slen; - } - out[out_length] = 0; - if (final_length != NULL) { - *final_length = out_length; - } - return out; -} - -/** Finds the initial (\a begin) and final (\a end) offsets of the next - * substring from \a str + \a read_offset until the next \a sep or the end of \a - * str. - * - * Returns 1 and updates \a begin and \a end. Returns 0 otherwise. */ -static int slice_find_separator_offset(const gpr_slice str, const char *sep, - const size_t read_offset, size_t *begin, - size_t *end) { - size_t i; - const uint8_t *str_ptr = GPR_SLICE_START_PTR(str) + read_offset; - const size_t str_len = GPR_SLICE_LENGTH(str) - read_offset; - const size_t sep_len = strlen(sep); - if (str_len < sep_len) { - return 0; - } - - for (i = 0; i <= str_len - sep_len; i++) { - if (memcmp(str_ptr + i, sep, sep_len) == 0) { - *begin = read_offset; - *end = read_offset + i; - return 1; - } - } - return 0; -} - -void gpr_slice_split(gpr_slice str, const char *sep, gpr_slice_buffer *dst) { - const size_t sep_len = strlen(sep); - size_t begin, end; - - GPR_ASSERT(sep_len > 0); - - if (slice_find_separator_offset(str, sep, 0, &begin, &end) != 0) { - do { - gpr_slice_buffer_add_indexed(dst, gpr_slice_sub(str, begin, end)); - } while (slice_find_separator_offset(str, sep, end + sep_len, &begin, - &end) != 0); - gpr_slice_buffer_add_indexed( - dst, gpr_slice_sub(str, end + sep_len, GPR_SLICE_LENGTH(str))); - } else { /* no sep found, add whole input */ - gpr_slice_buffer_add_indexed(dst, gpr_slice_ref(str)); - } -} - -void gpr_strvec_init(gpr_strvec *sv) { memset(sv, 0, sizeof(*sv)); } - -void gpr_strvec_destroy(gpr_strvec *sv) { - size_t i; - for (i = 0; i < sv->count; i++) { - gpr_free(sv->strs[i]); - } - gpr_free(sv->strs); -} - -void gpr_strvec_add(gpr_strvec *sv, char *str) { - if (sv->count == sv->capacity) { - sv->capacity = GPR_MAX(sv->capacity + 8, sv->capacity * 2); - sv->strs = gpr_realloc(sv->strs, sizeof(char *) * sv->capacity); - } - sv->strs[sv->count++] = str; -} - -char *gpr_strvec_flatten(gpr_strvec *sv, size_t *final_length) { - return gpr_strjoin((const char **)sv->strs, sv->count, final_length); -} diff --git a/src/core/support/string.h b/src/core/support/string.h deleted file mode 100644 index 8ff16882ab..0000000000 --- a/src/core/support/string.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * - * Copyright 2015-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_SUPPORT_STRING_H -#define GRPC_CORE_SUPPORT_STRING_H - -#include - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* String utility functions */ - -/* Flags for gpr_dump function. */ -#define GPR_DUMP_HEX 0x00000001 -#define GPR_DUMP_ASCII 0x00000002 - -/* Converts array buf, of length len, into a C string according to the flags. - Result should be freed with gpr_free() */ -char *gpr_dump(const char *buf, size_t len, uint32_t flags); - -/* Calls gpr_dump on a slice. */ -char *gpr_dump_slice(gpr_slice slice, uint32_t flags); - -/* Parses an array of bytes into an integer (base 10). Returns 1 on success, - 0 on failure. */ -int gpr_parse_bytes_to_uint32(const char *data, size_t length, - uint32_t *result); - -/* Minimum buffer size for calling ltoa */ -#define GPR_LTOA_MIN_BUFSIZE (3 * sizeof(long)) - -/* Convert a long to a string in base 10; returns the length of the - output string (or 0 on failure). - output must be at least GPR_LTOA_MIN_BUFSIZE bytes long. */ -int gpr_ltoa(long value, char *output); - -/* Minimum buffer size for calling int64toa */ -#define GPR_INT64TOA_MIN_BUFSIZE (3 * sizeof(int64_t)) - -/* Convert an int64 to a string in base 10; returns the length of the -output string (or 0 on failure). -output must be at least GPR_INT64TOA_MIN_BUFSIZE bytes long. -NOTE: This function ensures sufficient bit width even on Win x64, -where long is 32bit is size.*/ -int int64_ttoa(int64_t value, char *output); - -/* Reverse a run of bytes */ -void gpr_reverse_bytes(char *str, int len); - -/* Join a set of strings, returning the resulting string. - Total combined length (excluding null terminator) is returned in total_length - if it is non-null. */ -char *gpr_strjoin(const char **strs, size_t nstrs, size_t *total_length); - -/* Join a set of strings using a separator, returning the resulting string. - Total combined length (excluding null terminator) is returned in total_length - if it is non-null. */ -char *gpr_strjoin_sep(const char **strs, size_t nstrs, const char *sep, - size_t *total_length); - -/** Split \a str by the separator \a sep. Results are stored in \a dst, which - * should be a properly initialized instance. */ -void gpr_slice_split(gpr_slice str, const char *sep, gpr_slice_buffer *dst); - -/* A vector of strings... for building up a final string one piece at a time */ -typedef struct { - char **strs; - size_t count; - size_t capacity; -} gpr_strvec; - -/* Initialize/destroy */ -void gpr_strvec_init(gpr_strvec *strs); -void gpr_strvec_destroy(gpr_strvec *strs); -/* Add a string to a strvec, takes ownership of the string */ -void gpr_strvec_add(gpr_strvec *strs, char *add); -/* Return a joined string with all added substrings, optionally setting - total_length as per gpr_strjoin */ -char *gpr_strvec_flatten(gpr_strvec *strs, size_t *total_length); - -#ifdef __cplusplus -} -#endif - -#endif /* GRPC_CORE_SUPPORT_STRING_H */ diff --git a/src/core/support/string_posix.c b/src/core/support/string_posix.c deleted file mode 100644 index a73b3106a5..0000000000 --- a/src/core/support/string_posix.c +++ /dev/null @@ -1,86 +0,0 @@ -/* - * - * Copyright 2015-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 - -#ifdef GPR_POSIX_STRING - -#include -#include -#include - -#include - -int gpr_asprintf(char **strp, const char *format, ...) { - va_list args; - int ret; - char buf[64]; - size_t strp_buflen; - - /* Use a constant-sized buffer to determine the length. */ - va_start(args, format); - ret = vsnprintf(buf, sizeof(buf), format, args); - va_end(args); - if (ret < 0) { - *strp = NULL; - return -1; - } - - /* Allocate a new buffer, with space for the NUL terminator. */ - strp_buflen = (size_t)ret + 1; - if ((*strp = gpr_malloc(strp_buflen)) == NULL) { - /* This shouldn't happen, because gpr_malloc() calls abort(). */ - return -1; - } - - /* Return early if we have all the bytes. */ - if (strp_buflen <= sizeof(buf)) { - memcpy(*strp, buf, strp_buflen); - return ret; - } - - /* Try again using the larger buffer. */ - va_start(args, format); - ret = vsnprintf(*strp, strp_buflen, format, args); - va_end(args); - if ((size_t)ret == strp_buflen - 1) { - return ret; - } - - /* This should never happen. */ - gpr_free(*strp); - *strp = NULL; - return -1; -} - -#endif /* GPR_POSIX_STRING */ diff --git a/src/core/support/string_win32.c b/src/core/support/string_win32.c deleted file mode 100644 index 0780907994..0000000000 --- a/src/core/support/string_win32.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * - * Copyright 2015-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. - * - */ - -/* Posix code for gpr snprintf support. */ - -#include - -#ifdef GPR_WIN32 - -#include -#include -#include - -#include - -#include "src/core/support/string.h" - -int gpr_asprintf(char **strp, const char *format, ...) { - va_list args; - int ret; - size_t strp_buflen; - - /* Determine the length. */ - va_start(args, format); - ret = _vscprintf(format, args); - va_end(args); - if (ret < 0) { - *strp = NULL; - return -1; - } - - /* Allocate a new buffer, with space for the NUL terminator. */ - strp_buflen = (size_t)ret + 1; - if ((*strp = gpr_malloc(strp_buflen)) == NULL) { - /* This shouldn't happen, because gpr_malloc() calls abort(). */ - return -1; - } - - /* Print to the buffer. */ - va_start(args, format); - ret = vsnprintf_s(*strp, strp_buflen, _TRUNCATE, format, args); - va_end(args); - if ((size_t)ret == strp_buflen - 1) { - return ret; - } - - /* This should never happen. */ - gpr_free(*strp); - *strp = NULL; - return -1; -} - -#if defined UNICODE || defined _UNICODE -LPTSTR -gpr_char_to_tchar(LPCSTR input) { - LPTSTR ret; - int needed = MultiByteToWideChar(CP_UTF8, 0, input, -1, NULL, 0); - if (needed <= 0) return NULL; - ret = gpr_malloc((unsigned)needed * sizeof(TCHAR)); - MultiByteToWideChar(CP_UTF8, 0, input, -1, ret, needed); - return ret; -} - -LPSTR -gpr_tchar_to_char(LPCTSTR input) { - LPSTR ret; - int needed = WideCharToMultiByte(CP_UTF8, 0, input, -1, NULL, 0, NULL, NULL); - if (needed <= 0) return NULL; - ret = gpr_malloc((unsigned)needed); - WideCharToMultiByte(CP_UTF8, 0, input, -1, ret, needed, NULL, NULL); - return ret; -} -#else -char *gpr_tchar_to_char(LPTSTR input) { return gpr_strdup(input); } - -char *gpr_char_to_tchar(LPTSTR input) { return gpr_strdup(input); } -#endif - -#endif /* GPR_WIN32 */ diff --git a/src/core/support/string_win32.h b/src/core/support/string_win32.h deleted file mode 100644 index c9ae8d9932..0000000000 --- a/src/core/support/string_win32.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * - * Copyright 2015-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_SUPPORT_STRING_WIN32_H -#define GRPC_CORE_SUPPORT_STRING_WIN32_H - -#include - -#ifdef GPR_WIN32 - -/* These allocate new strings using gpr_malloc to convert from and to utf-8. */ -LPTSTR gpr_char_to_tchar(LPCSTR input); -LPSTR gpr_tchar_to_char(LPCTSTR input); - -#endif /* GPR_WIN32 */ - -#endif /* GRPC_CORE_SUPPORT_STRING_WIN32_H */ diff --git a/src/core/support/subprocess_posix.c b/src/core/support/subprocess_posix.c deleted file mode 100644 index 662e7dd999..0000000000 --- a/src/core/support/subprocess_posix.c +++ /dev/null @@ -1,112 +0,0 @@ -/* - * - * Copyright 2015-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 - -#ifdef GPR_POSIX_SUBPROCESS - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -struct gpr_subprocess { - int pid; - int joined; -}; - -const char *gpr_subprocess_binary_extension() { return ""; } - -gpr_subprocess *gpr_subprocess_create(int argc, const char **argv) { - gpr_subprocess *r; - int pid; - char **exec_args; - - pid = fork(); - if (pid == -1) { - return NULL; - } else if (pid == 0) { - exec_args = gpr_malloc(((size_t)argc + 1) * sizeof(char *)); - memcpy(exec_args, argv, (size_t)argc * sizeof(char *)); - exec_args[argc] = NULL; - execv(exec_args[0], exec_args); - /* if we reach here, an error has occurred */ - gpr_log(GPR_ERROR, "execv '%s' failed: %s", exec_args[0], strerror(errno)); - _exit(1); - return NULL; - } else { - r = gpr_malloc(sizeof(gpr_subprocess)); - memset(r, 0, sizeof(*r)); - r->pid = pid; - return r; - } -} - -void gpr_subprocess_destroy(gpr_subprocess *p) { - if (!p->joined) { - kill(p->pid, SIGKILL); - gpr_subprocess_join(p); - } - gpr_free(p); -} - -int gpr_subprocess_join(gpr_subprocess *p) { - int status; -retry: - if (waitpid(p->pid, &status, 0) == -1) { - if (errno == EINTR) { - goto retry; - } - gpr_log(GPR_ERROR, "waitpid failed: %s", strerror(errno)); - return -1; - } - return status; -} - -void gpr_subprocess_interrupt(gpr_subprocess *p) { - if (!p->joined) { - kill(p->pid, SIGINT); - } -} - -#endif /* GPR_POSIX_SUBPROCESS */ diff --git a/src/core/support/subprocess_windows.c b/src/core/support/subprocess_windows.c deleted file mode 100644 index 6afbefeb2b..0000000000 --- a/src/core/support/subprocess_windows.c +++ /dev/null @@ -1,141 +0,0 @@ -/* - * - * 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 - -#ifdef GPR_WINDOWS_SUBPROCESS - -#include -#include -#include - -#include -#include -#include -#include "src/core/support/string.h" -#include "src/core/support/string_win32.h" - -struct gpr_subprocess { - PROCESS_INFORMATION pi; - int joined; - int interrupted; -}; - -const char *gpr_subprocess_binary_extension() { return ".exe"; } - -gpr_subprocess *gpr_subprocess_create(int argc, const char **argv) { - gpr_subprocess *r; - - STARTUPINFO si; - PROCESS_INFORMATION pi; - - char *args = gpr_strjoin_sep(argv, (size_t)argc, " ", NULL); - TCHAR *args_tchar; - - args_tchar = gpr_char_to_tchar(args); - gpr_free(args); - - memset(&si, 0, sizeof(si)); - si.cb = sizeof(si); - memset(&pi, 0, sizeof(pi)); - - if (!CreateProcess(NULL, args_tchar, NULL, NULL, FALSE, - CREATE_NEW_PROCESS_GROUP, NULL, NULL, &si, &pi)) { - gpr_free(args_tchar); - return NULL; - } - gpr_free(args_tchar); - - r = gpr_malloc(sizeof(gpr_subprocess)); - memset(r, 0, sizeof(*r)); - r->pi = pi; - return r; -} - -void gpr_subprocess_destroy(gpr_subprocess *p) { - if (p) { - if (!p->joined) { - gpr_subprocess_interrupt(p); - gpr_subprocess_join(p); - } - if (p->pi.hProcess) { - CloseHandle(p->pi.hProcess); - } - if (p->pi.hThread) { - CloseHandle(p->pi.hThread); - } - gpr_free(p); - } -} - -int gpr_subprocess_join(gpr_subprocess *p) { - DWORD dwExitCode; - if (GetExitCodeProcess(p->pi.hProcess, &dwExitCode)) { - if (dwExitCode == STILL_ACTIVE) { - if (WaitForSingleObject(p->pi.hProcess, INFINITE) == WAIT_OBJECT_0) { - p->joined = 1; - goto getExitCode; - } - return -1; // failed to join - } else { - goto getExitCode; - } - } else { - return -1; // failed to get exit code - } - -getExitCode: - if (p->interrupted) { - return 0; - } - if (GetExitCodeProcess(p->pi.hProcess, &dwExitCode)) { - return (int)dwExitCode; - } else { - return -1; // failed to get exit code - } -} - -void gpr_subprocess_interrupt(gpr_subprocess *p) { - DWORD dwExitCode; - if (GetExitCodeProcess(p->pi.hProcess, &dwExitCode)) { - if (dwExitCode == STILL_ACTIVE) { - gpr_log(GPR_INFO, "sending ctrl-break"); - GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, p->pi.dwProcessId); - p->joined = 1; - p->interrupted = 1; - } - } - return; -} - -#endif /* GPR_WINDOWS_SUBPROCESS */ diff --git a/src/core/support/sync.c b/src/core/support/sync.c deleted file mode 100644 index 800cf20287..0000000000 --- a/src/core/support/sync.c +++ /dev/null @@ -1,127 +0,0 @@ -/* - * - * Copyright 2015-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. - * - */ - -/* Generic implementation of synchronization primitives. */ - -#include -#include -#include - -/* Number of mutexes to allocate for events, to avoid lock contention. - Should be a prime. */ -enum { event_sync_partitions = 31 }; - -/* Events are partitioned by address to avoid lock contention. */ -static struct sync_array_s { - gpr_mu mu; - gpr_cv cv; -} sync_array[event_sync_partitions]; - -/* This routine is executed once on first use, via event_once */ -static gpr_once event_once = GPR_ONCE_INIT; -static void event_initialize(void) { - int i; - for (i = 0; i != event_sync_partitions; i++) { - gpr_mu_init(&sync_array[i].mu); - gpr_cv_init(&sync_array[i].cv); - } -} - -/* Hash ev into an element of sync_array[]. */ -static struct sync_array_s *hash(gpr_event *ev) { - return &sync_array[((uintptr_t)ev) % event_sync_partitions]; -} - -void gpr_event_init(gpr_event *ev) { - gpr_once_init(&event_once, &event_initialize); - ev->state = 0; -} - -void gpr_event_set(gpr_event *ev, void *value) { - struct sync_array_s *s = hash(ev); - gpr_mu_lock(&s->mu); - GPR_ASSERT(gpr_atm_acq_load(&ev->state) == 0); - gpr_atm_rel_store(&ev->state, (gpr_atm)value); - gpr_cv_broadcast(&s->cv); - gpr_mu_unlock(&s->mu); - GPR_ASSERT(value != NULL); -} - -void *gpr_event_get(gpr_event *ev) { - return (void *)gpr_atm_acq_load(&ev->state); -} - -void *gpr_event_wait(gpr_event *ev, gpr_timespec abs_deadline) { - void *result = (void *)gpr_atm_acq_load(&ev->state); - if (result == NULL) { - struct sync_array_s *s = hash(ev); - gpr_mu_lock(&s->mu); - do { - result = (void *)gpr_atm_acq_load(&ev->state); - } while (result == NULL && !gpr_cv_wait(&s->cv, &s->mu, abs_deadline)); - gpr_mu_unlock(&s->mu); - } - return result; -} - -void gpr_ref_init(gpr_refcount *r, int n) { gpr_atm_rel_store(&r->count, n); } - -void gpr_ref(gpr_refcount *r) { gpr_atm_no_barrier_fetch_add(&r->count, 1); } - -void gpr_ref_non_zero(gpr_refcount *r) { - gpr_atm prior = gpr_atm_no_barrier_fetch_add(&r->count, 1); - GPR_ASSERT(prior > 0); -} - -void gpr_refn(gpr_refcount *r, int n) { - gpr_atm_no_barrier_fetch_add(&r->count, n); -} - -int gpr_unref(gpr_refcount *r) { - gpr_atm prior = gpr_atm_full_fetch_add(&r->count, -1); - GPR_ASSERT(prior > 0); - return prior == 1; -} - -void gpr_stats_init(gpr_stats_counter *c, intptr_t n) { - gpr_atm_rel_store(&c->value, n); -} - -void gpr_stats_inc(gpr_stats_counter *c, intptr_t inc) { - gpr_atm_no_barrier_fetch_add(&c->value, inc); -} - -intptr_t gpr_stats_read(const gpr_stats_counter *c) { - /* don't need acquire-load, but we have no no-barrier load yet */ - return gpr_atm_acq_load(&c->value); -} diff --git a/src/core/support/sync_posix.c b/src/core/support/sync_posix.c deleted file mode 100644 index be4d0ac1c9..0000000000 --- a/src/core/support/sync_posix.c +++ /dev/null @@ -1,104 +0,0 @@ -/* - * - * Copyright 2015-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 - -#ifdef GPR_POSIX_SYNC - -#include -#include -#include -#include -#include -#include "src/core/profiling/timers.h" - -void gpr_mu_init(gpr_mu* mu) { GPR_ASSERT(pthread_mutex_init(mu, NULL) == 0); } - -void gpr_mu_destroy(gpr_mu* mu) { GPR_ASSERT(pthread_mutex_destroy(mu) == 0); } - -void gpr_mu_lock(gpr_mu* mu) { - GPR_TIMER_BEGIN("gpr_mu_lock", 0); - GPR_ASSERT(pthread_mutex_lock(mu) == 0); - GPR_TIMER_END("gpr_mu_lock", 0); -} - -void gpr_mu_unlock(gpr_mu* mu) { - GPR_TIMER_BEGIN("gpr_mu_unlock", 0); - GPR_ASSERT(pthread_mutex_unlock(mu) == 0); - GPR_TIMER_END("gpr_mu_unlock", 0); -} - -int gpr_mu_trylock(gpr_mu* mu) { - int err; - GPR_TIMER_BEGIN("gpr_mu_trylock", 0); - err = pthread_mutex_trylock(mu); - GPR_ASSERT(err == 0 || err == EBUSY); - GPR_TIMER_END("gpr_mu_trylock", 0); - return err == 0; -} - -/*----------------------------------------*/ - -void gpr_cv_init(gpr_cv* cv) { GPR_ASSERT(pthread_cond_init(cv, NULL) == 0); } - -void gpr_cv_destroy(gpr_cv* cv) { GPR_ASSERT(pthread_cond_destroy(cv) == 0); } - -int gpr_cv_wait(gpr_cv* cv, gpr_mu* mu, gpr_timespec abs_deadline) { - int err = 0; - if (gpr_time_cmp(abs_deadline, gpr_inf_future(abs_deadline.clock_type)) == - 0) { - err = pthread_cond_wait(cv, mu); - } else { - struct timespec abs_deadline_ts; - abs_deadline = gpr_convert_clock_type(abs_deadline, GPR_CLOCK_REALTIME); - abs_deadline_ts.tv_sec = (time_t)abs_deadline.tv_sec; - abs_deadline_ts.tv_nsec = abs_deadline.tv_nsec; - err = pthread_cond_timedwait(cv, mu, &abs_deadline_ts); - } - GPR_ASSERT(err == 0 || err == ETIMEDOUT || err == EAGAIN); - return err == ETIMEDOUT; -} - -void gpr_cv_signal(gpr_cv* cv) { GPR_ASSERT(pthread_cond_signal(cv) == 0); } - -void gpr_cv_broadcast(gpr_cv* cv) { - GPR_ASSERT(pthread_cond_broadcast(cv) == 0); -} - -/*----------------------------------------*/ - -void gpr_once_init(gpr_once* once, void (*init_function)(void)) { - GPR_ASSERT(pthread_once(once, init_function) == 0); -} - -#endif /* GRP_POSIX_SYNC */ diff --git a/src/core/support/sync_win32.c b/src/core/support/sync_win32.c deleted file mode 100644 index 41998ebcb6..0000000000 --- a/src/core/support/sync_win32.c +++ /dev/null @@ -1,133 +0,0 @@ -/* - * - * Copyright 2015-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. - * - */ - -/* Win32 code for gpr synchronization support. */ - -#include - -#ifdef GPR_WIN32 - -#include -#include -#include - -void gpr_mu_init(gpr_mu *mu) { - InitializeCriticalSection(&mu->cs); - mu->locked = 0; -} - -void gpr_mu_destroy(gpr_mu *mu) { DeleteCriticalSection(&mu->cs); } - -void gpr_mu_lock(gpr_mu *mu) { - EnterCriticalSection(&mu->cs); - GPR_ASSERT(!mu->locked); - mu->locked = 1; -} - -void gpr_mu_unlock(gpr_mu *mu) { - mu->locked = 0; - LeaveCriticalSection(&mu->cs); -} - -int gpr_mu_trylock(gpr_mu *mu) { - int result = TryEnterCriticalSection(&mu->cs); - if (result) { - if (mu->locked) { /* This thread already holds the lock. */ - LeaveCriticalSection(&mu->cs); /* Decrement lock count. */ - result = 0; /* Indicate failure */ - } - mu->locked = 1; - } - return result; -} - -/*----------------------------------------*/ - -void gpr_cv_init(gpr_cv *cv) { InitializeConditionVariable(cv); } - -void gpr_cv_destroy(gpr_cv *cv) { - /* Condition variables don't need destruction in Win32. */ -} - -int gpr_cv_wait(gpr_cv *cv, gpr_mu *mu, gpr_timespec abs_deadline) { - int timeout = 0; - DWORD timeout_max_ms; - mu->locked = 0; - if (gpr_time_cmp(abs_deadline, gpr_inf_future(abs_deadline.clock_type)) == - 0) { - SleepConditionVariableCS(cv, &mu->cs, INFINITE); - } else { - abs_deadline = gpr_convert_clock_type(abs_deadline, GPR_CLOCK_REALTIME); - gpr_timespec now = gpr_now(abs_deadline.clock_type); - int64_t now_ms = (int64_t)now.tv_sec * 1000 + now.tv_nsec / 1000000; - int64_t deadline_ms = - (int64_t)abs_deadline.tv_sec * 1000 + abs_deadline.tv_nsec / 1000000; - if (now_ms >= deadline_ms) { - timeout = 1; - } else { - if ((deadline_ms - now_ms) >= INFINITE) { - timeout_max_ms = INFINITE - 1; - } else { - timeout_max_ms = (DWORD)(deadline_ms - now_ms); - } - timeout = (SleepConditionVariableCS(cv, &mu->cs, timeout_max_ms) == 0 && - GetLastError() == ERROR_TIMEOUT); - } - } - mu->locked = 1; - return timeout; -} - -void gpr_cv_signal(gpr_cv *cv) { WakeConditionVariable(cv); } - -void gpr_cv_broadcast(gpr_cv *cv) { WakeAllConditionVariable(cv); } - -/*----------------------------------------*/ - -static void *dummy; -struct run_once_func_arg { - void (*init_function)(void); -}; -static BOOL CALLBACK run_once_func(gpr_once *once, void *v, void **pv) { - struct run_once_func_arg *arg = v; - (*arg->init_function)(); - return 1; -} - -void gpr_once_init(gpr_once *once, void (*init_function)(void)) { - struct run_once_func_arg arg; - arg.init_function = init_function; - InitOnceExecuteOnce(once, run_once_func, &arg, &dummy); -} - -#endif /* GPR_WIN32 */ diff --git a/src/core/support/thd.c b/src/core/support/thd.c deleted file mode 100644 index 41daeb5d0e..0000000000 --- a/src/core/support/thd.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -/* Posix implementation for gpr threads. */ - -#include - -#include - -enum { GPR_THD_JOINABLE = 1 }; - -gpr_thd_options gpr_thd_options_default(void) { - gpr_thd_options options; - memset(&options, 0, sizeof(options)); - return options; -} - -void gpr_thd_options_set_detached(gpr_thd_options* options) { - options->flags &= ~GPR_THD_JOINABLE; -} - -void gpr_thd_options_set_joinable(gpr_thd_options* options) { - options->flags |= GPR_THD_JOINABLE; -} - -int gpr_thd_options_is_detached(const gpr_thd_options* options) { - if (!options) return 1; - return (options->flags & GPR_THD_JOINABLE) == 0; -} - -int gpr_thd_options_is_joinable(const gpr_thd_options* options) { - if (!options) return 0; - return (options->flags & GPR_THD_JOINABLE) == GPR_THD_JOINABLE; -} diff --git a/src/core/support/thd_internal.h b/src/core/support/thd_internal.h deleted file mode 100644 index 33b904e59b..0000000000 --- a/src/core/support/thd_internal.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * - * Copyright 2015-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_SUPPORT_THD_INTERNAL_H -#define GRPC_CORE_SUPPORT_THD_INTERNAL_H - -/* Internal interfaces between modules within the gpr support library. */ - -#endif /* GRPC_CORE_SUPPORT_THD_INTERNAL_H */ diff --git a/src/core/support/thd_posix.c b/src/core/support/thd_posix.c deleted file mode 100644 index 4d874d3656..0000000000 --- a/src/core/support/thd_posix.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * - * Copyright 2015-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. - * - */ - -/* Posix implementation for gpr threads. */ - -#include - -#ifdef GPR_POSIX_SYNC - -#include -#include -#include -#include -#include -#include -#include - -struct thd_arg { - void (*body)(void *arg); /* body of a thread */ - void *arg; /* argument to a thread */ -}; - -/* Body of every thread started via gpr_thd_new. */ -static void *thread_body(void *v) { - struct thd_arg a = *(struct thd_arg *)v; - free(v); - (*a.body)(a.arg); - return NULL; -} - -int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg, - const gpr_thd_options *options) { - int thread_started; - pthread_attr_t attr; - pthread_t p; - /* don't use gpr_malloc as we may cause an infinite recursion with - * the profiling code */ - struct thd_arg *a = malloc(sizeof(*a)); - GPR_ASSERT(a != NULL); - a->body = thd_body; - a->arg = arg; - - GPR_ASSERT(pthread_attr_init(&attr) == 0); - if (gpr_thd_options_is_detached(options)) { - GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) == - 0); - } else { - GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) == - 0); - } - thread_started = (pthread_create(&p, &attr, &thread_body, a) == 0); - GPR_ASSERT(pthread_attr_destroy(&attr) == 0); - if (!thread_started) { - free(a); - } - *t = (gpr_thd_id)p; - return thread_started; -} - -gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)pthread_self(); } - -void gpr_thd_join(gpr_thd_id t) { pthread_join((pthread_t)t, NULL); } - -#endif /* GPR_POSIX_SYNC */ diff --git a/src/core/support/thd_win32.c b/src/core/support/thd_win32.c deleted file mode 100644 index 630eb7f625..0000000000 --- a/src/core/support/thd_win32.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * - * Copyright 2015-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. - * - */ - -/* Windows implementation for gpr threads. */ - -#include - -#ifdef GPR_WIN32 - -#include -#include -#include -#include - -#if defined(_MSC_VER) -#define thread_local __declspec(thread) -#elif defined(__GNUC__) -#define thread_local __thread -#else -#error "Unknown compiler - please file a bug report" -#endif - -struct thd_info { - void (*body)(void *arg); /* body of a thread */ - void *arg; /* argument to a thread */ - HANDLE join_event; /* if joinable, the join event */ - int joinable; /* true if not detached */ -}; - -static thread_local struct thd_info *g_thd_info; - -/* Destroys a thread info */ -static void destroy_thread(struct thd_info *t) { - if (t->joinable) CloseHandle(t->join_event); - gpr_free(t); -} - -/* Body of every thread started via gpr_thd_new. */ -static DWORD WINAPI thread_body(void *v) { - g_thd_info = (struct thd_info *)v; - g_thd_info->body(g_thd_info->arg); - if (g_thd_info->joinable) { - BOOL ret = SetEvent(g_thd_info->join_event); - GPR_ASSERT(ret); - } else { - destroy_thread(g_thd_info); - } - return 0; -} - -int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg, - const gpr_thd_options *options) { - HANDLE handle; - struct thd_info *info = gpr_malloc(sizeof(*info)); - info->body = thd_body; - info->arg = arg; - *t = 0; - if (gpr_thd_options_is_joinable(options)) { - info->joinable = 1; - info->join_event = CreateEvent(NULL, FALSE, FALSE, NULL); - if (info->join_event == NULL) { - gpr_free(info); - return 0; - } - } else { - info->joinable = 0; - } - handle = CreateThread(NULL, 64 * 1024, thread_body, info, 0, NULL); - if (handle == NULL) { - destroy_thread(info); - } else { - *t = (gpr_thd_id)info; - CloseHandle(handle); - } - return handle != NULL; -} - -gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)g_thd_info; } - -void gpr_thd_join(gpr_thd_id t) { - struct thd_info *info = (struct thd_info *)t; - DWORD ret = WaitForSingleObject(info->join_event, INFINITE); - GPR_ASSERT(ret == WAIT_OBJECT_0); - destroy_thread(info); -} - -#endif /* GPR_WIN32 */ diff --git a/src/core/support/time.c b/src/core/support/time.c deleted file mode 100644 index 0e2c8fcf1a..0000000000 --- a/src/core/support/time.c +++ /dev/null @@ -1,304 +0,0 @@ -/* - * - * Copyright 2015-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. - * - */ - -/* Generic implementation of time calls. */ - -#include -#include -#include -#include -#include - -int gpr_time_cmp(gpr_timespec a, gpr_timespec b) { - int cmp = (a.tv_sec > b.tv_sec) - (a.tv_sec < b.tv_sec); - GPR_ASSERT(a.clock_type == b.clock_type); - if (cmp == 0) { - cmp = (a.tv_nsec > b.tv_nsec) - (a.tv_nsec < b.tv_nsec); - } - return cmp; -} - -gpr_timespec gpr_time_min(gpr_timespec a, gpr_timespec b) { - return gpr_time_cmp(a, b) < 0 ? a : b; -} - -gpr_timespec gpr_time_max(gpr_timespec a, gpr_timespec b) { - return gpr_time_cmp(a, b) > 0 ? a : b; -} - -gpr_timespec gpr_time_0(gpr_clock_type type) { - gpr_timespec out; - out.tv_sec = 0; - out.tv_nsec = 0; - out.clock_type = type; - return out; -} - -gpr_timespec gpr_inf_future(gpr_clock_type type) { - gpr_timespec out; - out.tv_sec = INT64_MAX; - out.tv_nsec = 0; - out.clock_type = type; - return out; -} - -gpr_timespec gpr_inf_past(gpr_clock_type type) { - gpr_timespec out; - out.tv_sec = INT64_MIN; - out.tv_nsec = 0; - out.clock_type = type; - return out; -} - -/* TODO(ctiller): consider merging _nanos, _micros, _millis into a single - function for maintainability. Similarly for _seconds, _minutes, and _hours */ - -gpr_timespec gpr_time_from_nanos(int64_t ns, gpr_clock_type type) { - gpr_timespec result; - result.clock_type = type; - if (ns == INT64_MAX) { - result = gpr_inf_future(type); - } else if (ns == INT64_MIN) { - result = gpr_inf_past(type); - } else if (ns >= 0) { - result.tv_sec = ns / GPR_NS_PER_SEC; - result.tv_nsec = (int32_t)(ns - result.tv_sec * GPR_NS_PER_SEC); - } else { - /* Calculation carefully formulated to avoid any possible under/overflow. */ - result.tv_sec = (-(999999999 - (ns + GPR_NS_PER_SEC)) / GPR_NS_PER_SEC) - 1; - result.tv_nsec = (int32_t)(ns - result.tv_sec * GPR_NS_PER_SEC); - } - return result; -} - -gpr_timespec gpr_time_from_micros(int64_t us, gpr_clock_type type) { - gpr_timespec result; - result.clock_type = type; - if (us == INT64_MAX) { - result = gpr_inf_future(type); - } else if (us == INT64_MIN) { - result = gpr_inf_past(type); - } else if (us >= 0) { - result.tv_sec = us / 1000000; - result.tv_nsec = (int32_t)((us - result.tv_sec * 1000000) * 1000); - } else { - /* Calculation carefully formulated to avoid any possible under/overflow. */ - result.tv_sec = (-(999999 - (us + 1000000)) / 1000000) - 1; - result.tv_nsec = (int32_t)((us - result.tv_sec * 1000000) * 1000); - } - return result; -} - -gpr_timespec gpr_time_from_millis(int64_t ms, gpr_clock_type type) { - gpr_timespec result; - result.clock_type = type; - if (ms == INT64_MAX) { - result = gpr_inf_future(type); - } else if (ms == INT64_MIN) { - result = gpr_inf_past(type); - } else if (ms >= 0) { - result.tv_sec = ms / 1000; - result.tv_nsec = (int32_t)((ms - result.tv_sec * 1000) * 1000000); - } else { - /* Calculation carefully formulated to avoid any possible under/overflow. */ - result.tv_sec = (-(999 - (ms + 1000)) / 1000) - 1; - result.tv_nsec = (int32_t)((ms - result.tv_sec * 1000) * 1000000); - } - return result; -} - -gpr_timespec gpr_time_from_seconds(int64_t s, gpr_clock_type type) { - gpr_timespec result; - result.clock_type = type; - if (s == INT64_MAX) { - result = gpr_inf_future(type); - } else if (s == INT64_MIN) { - result = gpr_inf_past(type); - } else { - result.tv_sec = s; - result.tv_nsec = 0; - } - return result; -} - -gpr_timespec gpr_time_from_minutes(int64_t m, gpr_clock_type type) { - gpr_timespec result; - result.clock_type = type; - if (m >= INT64_MAX / 60) { - result = gpr_inf_future(type); - } else if (m <= INT64_MIN / 60) { - result = gpr_inf_past(type); - } else { - result.tv_sec = m * 60; - result.tv_nsec = 0; - } - return result; -} - -gpr_timespec gpr_time_from_hours(int64_t h, gpr_clock_type type) { - gpr_timespec result; - result.clock_type = type; - if (h >= INT64_MAX / 3600) { - result = gpr_inf_future(type); - } else if (h <= INT64_MIN / 3600) { - result = gpr_inf_past(type); - } else { - result.tv_sec = h * 3600; - result.tv_nsec = 0; - } - return result; -} - -gpr_timespec gpr_time_add(gpr_timespec a, gpr_timespec b) { - gpr_timespec sum; - int64_t inc = 0; - GPR_ASSERT(b.clock_type == GPR_TIMESPAN); - sum.clock_type = a.clock_type; - sum.tv_nsec = a.tv_nsec + b.tv_nsec; - if (sum.tv_nsec >= GPR_NS_PER_SEC) { - sum.tv_nsec -= GPR_NS_PER_SEC; - inc++; - } - if (a.tv_sec == INT64_MAX || a.tv_sec == INT64_MIN) { - sum = a; - } else if (b.tv_sec == INT64_MAX || - (b.tv_sec >= 0 && a.tv_sec >= INT64_MAX - b.tv_sec)) { - sum = gpr_inf_future(sum.clock_type); - } else if (b.tv_sec == INT64_MIN || - (b.tv_sec <= 0 && a.tv_sec <= INT64_MIN - b.tv_sec)) { - sum = gpr_inf_past(sum.clock_type); - } else { - sum.tv_sec = a.tv_sec + b.tv_sec; - if (inc != 0 && sum.tv_sec == INT64_MAX - 1) { - sum = gpr_inf_future(sum.clock_type); - } else { - sum.tv_sec += inc; - } - } - return sum; -} - -gpr_timespec gpr_time_sub(gpr_timespec a, gpr_timespec b) { - gpr_timespec diff; - int64_t dec = 0; - if (b.clock_type == GPR_TIMESPAN) { - diff.clock_type = a.clock_type; - } else { - GPR_ASSERT(a.clock_type == b.clock_type); - diff.clock_type = GPR_TIMESPAN; - } - diff.tv_nsec = a.tv_nsec - b.tv_nsec; - if (diff.tv_nsec < 0) { - diff.tv_nsec += GPR_NS_PER_SEC; - dec++; - } - if (a.tv_sec == INT64_MAX || a.tv_sec == INT64_MIN) { - diff = a; - } else if (b.tv_sec == INT64_MIN || - (b.tv_sec <= 0 && a.tv_sec >= INT64_MAX + b.tv_sec)) { - diff = gpr_inf_future(GPR_CLOCK_REALTIME); - } else if (b.tv_sec == INT64_MAX || - (b.tv_sec >= 0 && a.tv_sec <= INT64_MIN + b.tv_sec)) { - diff = gpr_inf_past(GPR_CLOCK_REALTIME); - } else { - diff.tv_sec = a.tv_sec - b.tv_sec; - if (dec != 0 && diff.tv_sec == INT64_MIN + 1) { - diff = gpr_inf_past(GPR_CLOCK_REALTIME); - } else { - diff.tv_sec -= dec; - } - } - return diff; -} - -int gpr_time_similar(gpr_timespec a, gpr_timespec b, gpr_timespec threshold) { - int cmp_ab; - - GPR_ASSERT(a.clock_type == b.clock_type); - GPR_ASSERT(threshold.clock_type == GPR_TIMESPAN); - - cmp_ab = gpr_time_cmp(a, b); - if (cmp_ab == 0) return 1; - if (cmp_ab < 0) { - return gpr_time_cmp(gpr_time_sub(b, a), threshold) <= 0; - } else { - return gpr_time_cmp(gpr_time_sub(a, b), threshold) <= 0; - } -} - -int32_t gpr_time_to_millis(gpr_timespec t) { - if (t.tv_sec >= 2147483) { - if (t.tv_sec == 2147483 && t.tv_nsec < 648 * GPR_NS_PER_MS) { - return 2147483 * GPR_MS_PER_SEC + t.tv_nsec / GPR_NS_PER_MS; - } - return 2147483647; - } else if (t.tv_sec <= -2147483) { - /* TODO(ctiller): correct handling here (it's so far in the past do we - care?) */ - return -2147483647; - } else { - return (int32_t)(t.tv_sec * GPR_MS_PER_SEC + t.tv_nsec / GPR_NS_PER_MS); - } -} - -double gpr_timespec_to_micros(gpr_timespec t) { - return (double)t.tv_sec * GPR_US_PER_SEC + t.tv_nsec * 1e-3; -} - -gpr_timespec gpr_convert_clock_type(gpr_timespec t, gpr_clock_type clock_type) { - if (t.clock_type == clock_type) { - return t; - } - - if (t.tv_nsec == 0) { - if (t.tv_sec == INT64_MAX) { - t.clock_type = clock_type; - return t; - } - if (t.tv_sec == INT64_MIN) { - t.clock_type = clock_type; - return t; - } - } - - if (clock_type == GPR_TIMESPAN) { - return gpr_time_sub(t, gpr_now(t.clock_type)); - } - - if (t.clock_type == GPR_TIMESPAN) { - return gpr_time_add(gpr_now(clock_type), t); - } - - return gpr_time_add(gpr_now(clock_type), - gpr_time_sub(t, gpr_now(t.clock_type))); -} diff --git a/src/core/support/time_posix.c b/src/core/support/time_posix.c deleted file mode 100644 index f999e08cb0..0000000000 --- a/src/core/support/time_posix.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - * - * Copyright 2015-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 -#include - -#ifdef GPR_POSIX_TIME - -#include -#include -#include -#ifdef __linux__ -#include -#endif -#include -#include -#include "src/core/support/block_annotate.h" - -static struct timespec timespec_from_gpr(gpr_timespec gts) { - struct timespec rv; - if (sizeof(time_t) < sizeof(int64_t)) { - /* fine to assert, as this is only used in gpr_sleep_until */ - GPR_ASSERT(gts.tv_sec <= INT32_MAX && gts.tv_sec >= INT32_MIN); - } - rv.tv_sec = (time_t)gts.tv_sec; - rv.tv_nsec = gts.tv_nsec; - return rv; -} - -#if _POSIX_TIMERS > 0 -static gpr_timespec gpr_from_timespec(struct timespec ts, - gpr_clock_type clock_type) { - /* - * timespec.tv_sec can have smaller size than gpr_timespec.tv_sec, - * but we are only using this function to implement gpr_now - * so there's no need to handle "infinity" values. - */ - gpr_timespec rv; - rv.tv_sec = ts.tv_sec; - rv.tv_nsec = (int32_t)ts.tv_nsec; - rv.clock_type = clock_type; - return rv; -} - -/** maps gpr_clock_type --> clockid_t for clock_gettime */ -static const clockid_t clockid_for_gpr_clock[] = {CLOCK_MONOTONIC, - CLOCK_REALTIME}; - -void gpr_time_init(void) { gpr_precise_clock_init(); } - -gpr_timespec gpr_now(gpr_clock_type clock_type) { - struct timespec now; - GPR_ASSERT(clock_type != GPR_TIMESPAN); - if (clock_type == GPR_CLOCK_PRECISE) { - gpr_timespec ret; - gpr_precise_clock_now(&ret); - return ret; - } else { -#if defined(GPR_BACKWARDS_COMPATIBILITY_MODE) && defined(__linux__) - /* avoid ABI problems by invoking syscalls directly */ - syscall(SYS_clock_gettime, clockid_for_gpr_clock[clock_type], &now); -#else - clock_gettime(clockid_for_gpr_clock[clock_type], &now); -#endif - return gpr_from_timespec(now, clock_type); - } -} -#else -/* For some reason Apple's OSes haven't implemented clock_gettime. */ - -#include -#include -#include - -static double g_time_scale; -static uint64_t g_time_start; - -void gpr_time_init(void) { - mach_timebase_info_data_t tb = {0, 1}; - gpr_precise_clock_init(); - mach_timebase_info(&tb); - g_time_scale = tb.numer; - g_time_scale /= tb.denom; - g_time_start = mach_absolute_time(); -} - -gpr_timespec gpr_now(gpr_clock_type clock) { - gpr_timespec now; - struct timeval now_tv; - double now_dbl; - - now.clock_type = clock; - switch (clock) { - case GPR_CLOCK_REALTIME: - gettimeofday(&now_tv, NULL); - now.tv_sec = now_tv.tv_sec; - now.tv_nsec = now_tv.tv_usec * 1000; - break; - case GPR_CLOCK_MONOTONIC: - now_dbl = (mach_absolute_time() - g_time_start) * g_time_scale; - now.tv_sec = (int64_t)(now_dbl * 1e-9); - now.tv_nsec = (int32_t)(now_dbl - ((double)now.tv_sec) * 1e9); - break; - case GPR_CLOCK_PRECISE: - gpr_precise_clock_now(&now); - break; - case GPR_TIMESPAN: - abort(); - } - - return now; -} -#endif - -void gpr_sleep_until(gpr_timespec until) { - gpr_timespec now; - gpr_timespec delta; - struct timespec delta_ts; - int ns_result; - - for (;;) { - /* We could simplify by using clock_nanosleep instead, but it might be - * slightly less portable. */ - now = gpr_now(until.clock_type); - if (gpr_time_cmp(until, now) <= 0) { - return; - } - - delta = gpr_time_sub(until, now); - delta_ts = timespec_from_gpr(delta); - GRPC_SCHEDULING_START_BLOCKING_REGION; - ns_result = nanosleep(&delta_ts, NULL); - GRPC_SCHEDULING_END_BLOCKING_REGION; - if (ns_result == 0) { - break; - } - } -} - -#endif /* GPR_POSIX_TIME */ diff --git a/src/core/support/time_precise.c b/src/core/support/time_precise.c deleted file mode 100644 index a2cf74bc84..0000000000 --- a/src/core/support/time_precise.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include -#include -#include - -#ifdef GRPC_TIMERS_RDTSC -#if defined(__i386__) -static void gpr_get_cycle_counter(long long int *clk) { - long long int ret; - __asm__ volatile("rdtsc" : "=A"(ret)); - *clk = ret; -} - -// ---------------------------------------------------------------- -#elif defined(__x86_64__) || defined(__amd64__) -static void gpr_get_cycle_counter(long long int *clk) { - unsigned long long low, high; - __asm__ volatile("rdtsc" : "=a"(low), "=d"(high)); - *clk = (long long)(high << 32) | (long long)low; -} -#endif - -static double cycles_per_second = 0; -static long long int start_cycle; -void gpr_precise_clock_init(void) { - time_t start; - long long end_cycle; - gpr_log(GPR_DEBUG, "Calibrating timers"); - start = time(NULL); - while (time(NULL) == start) - ; - gpr_get_cycle_counter(&start_cycle); - while (time(NULL) <= start + 10) - ; - gpr_get_cycle_counter(&end_cycle); - cycles_per_second = (double)(end_cycle - start_cycle) / 10.0; - gpr_log(GPR_DEBUG, "... cycles_per_second = %f\n", cycles_per_second); -} - -void gpr_precise_clock_now(gpr_timespec *clk) { - long long int counter; - double secs; - gpr_get_cycle_counter(&counter); - secs = (double)(counter - start_cycle) / cycles_per_second; - clk->clock_type = GPR_CLOCK_PRECISE; - clk->tv_sec = (int64_t)secs; - clk->tv_nsec = (int32_t)(1e9 * (secs - (double)clk->tv_sec)); -} - -#else /* GRPC_TIMERS_RDTSC */ -void gpr_precise_clock_init(void) {} - -void gpr_precise_clock_now(gpr_timespec *clk) { - *clk = gpr_now(GPR_CLOCK_REALTIME); - clk->clock_type = GPR_CLOCK_PRECISE; -} -#endif /* GRPC_TIMERS_RDTSC */ diff --git a/src/core/support/time_precise.h b/src/core/support/time_precise.h deleted file mode 100644 index 871c99a623..0000000000 --- a/src/core/support/time_precise.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * - * Copyright 2015-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_SUPPORT_TIME_PRECISE_H -#define GRPC_CORE_SUPPORT_TIME_PRECISE_H - -#include - -void gpr_precise_clock_init(void); -void gpr_precise_clock_now(gpr_timespec *clk); - -#endif /* GRPC_CORE_SUPPORT_TIME_PRECISE_H */ diff --git a/src/core/support/time_win32.c b/src/core/support/time_win32.c deleted file mode 100644 index 2c344d3f3b..0000000000 --- a/src/core/support/time_win32.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * - * Copyright 2015-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. - * - */ - -/* Win32 code for gpr time support. */ - -#include - -#ifdef GPR_WIN32 - -#include -#include -#include -#include -#include -#include - -#include "src/core/support/block_annotate.h" - -static LARGE_INTEGER g_start_time; -static double g_time_scale; - -void gpr_time_init(void) { - LARGE_INTEGER frequency; - QueryPerformanceFrequency(&frequency); - QueryPerformanceCounter(&g_start_time); - g_time_scale = 1.0 / (double)frequency.QuadPart; -} - -gpr_timespec gpr_now(gpr_clock_type clock) { - gpr_timespec now_tv; - LONGLONG diff; - struct _timeb now_tb; - LARGE_INTEGER timestamp; - double now_dbl; - now_tv.clock_type = clock; - switch (clock) { - case GPR_CLOCK_REALTIME: - _ftime_s(&now_tb); - now_tv.tv_sec = (int64_t)now_tb.time; - now_tv.tv_nsec = now_tb.millitm * 1000000; - break; - case GPR_CLOCK_MONOTONIC: - case GPR_CLOCK_PRECISE: - QueryPerformanceCounter(×tamp); - diff = timestamp.QuadPart - g_start_time.QuadPart; - now_dbl = (double)diff * g_time_scale; - now_tv.tv_sec = (int64_t)now_dbl; - now_tv.tv_nsec = (int32_t)((now_dbl - (double)now_tv.tv_sec) * 1e9); - break; - case GPR_TIMESPAN: - abort(); - break; - } - return now_tv; -} - -void gpr_sleep_until(gpr_timespec until) { - gpr_timespec now; - gpr_timespec delta; - int64_t sleep_millis; - - for (;;) { - /* We could simplify by using clock_nanosleep instead, but it might be - * slightly less portable. */ - now = gpr_now(until.clock_type); - if (gpr_time_cmp(until, now) <= 0) { - return; - } - - delta = gpr_time_sub(until, now); - sleep_millis = - delta.tv_sec * GPR_MS_PER_SEC + delta.tv_nsec / GPR_NS_PER_MS; - GPR_ASSERT((sleep_millis >= 0) && (sleep_millis <= INT_MAX)); - GRPC_SCHEDULING_START_BLOCKING_REGION; - Sleep((DWORD)sleep_millis); - GRPC_SCHEDULING_END_BLOCKING_REGION; - } -} - -#endif /* GPR_WIN32 */ diff --git a/src/core/support/tls_pthread.c b/src/core/support/tls_pthread.c deleted file mode 100644 index 9683a6e547..0000000000 --- a/src/core/support/tls_pthread.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include - -#ifdef GPR_PTHREAD_TLS - -#include - -intptr_t gpr_tls_set(struct gpr_pthread_thread_local *tls, intptr_t value) { - GPR_ASSERT(0 == pthread_setspecific(tls->key, (void *)value)); - return value; -} - -#endif /* GPR_PTHREAD_TLS */ diff --git a/src/core/support/tmpfile.h b/src/core/support/tmpfile.h deleted file mode 100644 index df6f8692bb..0000000000 --- a/src/core/support/tmpfile.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * - * Copyright 2015-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_SUPPORT_TMPFILE_H -#define GRPC_CORE_SUPPORT_TMPFILE_H - -#include - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* Creates a temporary file from a prefix. - If tmp_filename is not NULL, *tmp_filename is assigned the name of the - created file and it is the responsibility of the caller to gpr_free it - unless an error occurs in which case it will be set to NULL. */ -FILE *gpr_tmpfile(const char *prefix, char **tmp_filename); - -#ifdef __cplusplus -} -#endif - -#endif /* GRPC_CORE_SUPPORT_TMPFILE_H */ diff --git a/src/core/support/tmpfile_posix.c b/src/core/support/tmpfile_posix.c deleted file mode 100644 index b16eeacf9d..0000000000 --- a/src/core/support/tmpfile_posix.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * - * Copyright 2015-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 - -#ifdef GPR_POSIX_FILE - -#include "src/core/support/tmpfile.h" - -#include -#include -#include -#include - -#include -#include -#include - -#include "src/core/support/string.h" - -FILE *gpr_tmpfile(const char *prefix, char **tmp_filename) { - FILE *result = NULL; - char *template; - int fd; - - if (tmp_filename != NULL) *tmp_filename = NULL; - - gpr_asprintf(&template, "/tmp/%s_XXXXXX", prefix); - GPR_ASSERT(template != NULL); - - fd = mkstemp(template); - if (fd == -1) { - gpr_log(GPR_ERROR, "mkstemp failed for template %s with error %s.", - template, strerror(errno)); - goto end; - } - result = fdopen(fd, "w+"); - if (result == NULL) { - gpr_log(GPR_ERROR, "Could not open file %s from fd %d (error = %s).", - template, fd, strerror(errno)); - unlink(template); - close(fd); - goto end; - } - -end: - if (result != NULL && tmp_filename != NULL) { - *tmp_filename = template; - } else { - gpr_free(template); - } - return result; -} - -#endif /* GPR_POSIX_FILE */ diff --git a/src/core/support/tmpfile_win32.c b/src/core/support/tmpfile_win32.c deleted file mode 100644 index 3000f0029f..0000000000 --- a/src/core/support/tmpfile_win32.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * - * Copyright 2015-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 - -#ifdef GPR_WIN32 - -#include -#include -#include -#include - -#include -#include -#include - -#include "src/core/support/string_win32.h" -#include "src/core/support/tmpfile.h" - -FILE *gpr_tmpfile(const char *prefix, char **tmp_filename_out) { - FILE *result = NULL; - LPTSTR template_string = NULL; - TCHAR tmp_path[MAX_PATH]; - TCHAR tmp_filename[MAX_PATH]; - DWORD status; - UINT success; - - if (tmp_filename_out != NULL) *tmp_filename_out = NULL; - - /* Convert our prefix to TCHAR. */ - template_string = gpr_char_to_tchar(prefix); - GPR_ASSERT(template_string); - - /* Get the path to the best temporary folder available. */ - status = GetTempPath(MAX_PATH, tmp_path); - if (status == 0 || status > MAX_PATH) goto end; - - /* Generate a unique filename with our template + temporary path. */ - success = GetTempFileName(tmp_path, template_string, 0, tmp_filename); - if (!success) goto end; - - /* Open a file there. */ - if (_tfopen_s(&result, tmp_filename, TEXT("wb+")) != 0) goto end; - -end: - if (result && tmp_filename_out) { - *tmp_filename_out = gpr_tchar_to_char(tmp_filename); - } - - gpr_free(template_string); - return result; -} - -#endif /* GPR_WIN32 */ diff --git a/src/core/support/wrap_memcpy.c b/src/core/support/wrap_memcpy.c deleted file mode 100644 index 15c289f7b8..0000000000 --- a/src/core/support/wrap_memcpy.c +++ /dev/null @@ -1,53 +0,0 @@ -/* - * - * 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 - -/* Provide a wrapped memcpy for targets that need to be backwards - * compatible with older libc's. - * - * Enable by setting LDFLAGS=-Wl,-wrap,memcpy when linking. - */ - -#ifdef __linux__ -#ifdef __x86_64__ -__asm__(".symver memcpy,memcpy@GLIBC_2.2.5"); -void *__wrap_memcpy(void *destination, const void *source, size_t num) { - return memcpy(destination, source, num); -} -#else /* !__x86_64__ */ -void *__wrap_memcpy(void *destination, const void *source, size_t num) { - return memmove(destination, source, num); -} -#endif -#endif diff --git a/src/core/surface/alarm.c b/src/core/surface/alarm.c deleted file mode 100644 index 1085285f95..0000000000 --- a/src/core/surface/alarm.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * - * Copyright 2015-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 -#include -#include "src/core/iomgr/timer.h" -#include "src/core/surface/completion_queue.h" - -struct grpc_alarm { - grpc_timer alarm; - grpc_cq_completion completion; - /** completion queue where events about this alarm will be posted */ - grpc_completion_queue *cq; - /** user supplied tag */ - void *tag; -}; - -static void do_nothing_end_completion(grpc_exec_ctx *exec_ctx, void *arg, - grpc_cq_completion *c) {} - -static void alarm_cb(grpc_exec_ctx *exec_ctx, void *arg, bool success) { - grpc_alarm *alarm = arg; - grpc_cq_end_op(exec_ctx, alarm->cq, alarm->tag, success, - do_nothing_end_completion, NULL, &alarm->completion); -} - -grpc_alarm *grpc_alarm_create(grpc_completion_queue *cq, gpr_timespec deadline, - void *tag) { - grpc_alarm *alarm = gpr_malloc(sizeof(grpc_alarm)); - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - - GRPC_CQ_INTERNAL_REF(cq, "alarm"); - alarm->cq = cq; - alarm->tag = tag; - - grpc_cq_begin_op(cq, tag); - grpc_timer_init(&exec_ctx, &alarm->alarm, - gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC), - alarm_cb, alarm, gpr_now(GPR_CLOCK_MONOTONIC)); - grpc_exec_ctx_finish(&exec_ctx); - return alarm; -} - -void grpc_alarm_cancel(grpc_alarm *alarm) { - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_timer_cancel(&exec_ctx, &alarm->alarm); - grpc_exec_ctx_finish(&exec_ctx); -} - -void grpc_alarm_destroy(grpc_alarm *alarm) { - grpc_alarm_cancel(alarm); - GRPC_CQ_INTERNAL_UNREF(alarm->cq, "alarm"); - gpr_free(alarm); -} diff --git a/src/core/surface/api_trace.c b/src/core/surface/api_trace.c deleted file mode 100644 index 9f0b900d46..0000000000 --- a/src/core/surface/api_trace.c +++ /dev/null @@ -1,36 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/surface/api_trace.h" - -int grpc_api_trace = 0; diff --git a/src/core/surface/api_trace.h b/src/core/surface/api_trace.h deleted file mode 100644 index af53829de4..0000000000 --- a/src/core/surface/api_trace.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * - * Copyright 2015-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_SURFACE_API_TRACE_H -#define GRPC_CORE_SURFACE_API_TRACE_H - -#include -#include "src/core/debug/trace.h" - -extern int grpc_api_trace; - -/* Provide unwrapping macros because we're in C89 and variadic macros weren't - introduced until C99... */ -#define GRPC_API_TRACE_UNWRAP0() -#define GRPC_API_TRACE_UNWRAP1(a) , a -#define GRPC_API_TRACE_UNWRAP2(a, b) , a, b -#define GRPC_API_TRACE_UNWRAP3(a, b, c) , a, b, c -#define GRPC_API_TRACE_UNWRAP4(a, b, c, d) , a, b, c, d -#define GRPC_API_TRACE_UNWRAP5(a, b, c, d, e) , a, b, c, d, e -#define GRPC_API_TRACE_UNWRAP6(a, b, c, d, e, f) , a, b, c, d, e, f -#define GRPC_API_TRACE_UNWRAP7(a, b, c, d, e, f, g) , a, b, c, d, e, f, g -#define GRPC_API_TRACE_UNWRAP8(a, b, c, d, e, f, g, h) , a, b, c, d, e, f, g, h -#define GRPC_API_TRACE_UNWRAP9(a, b, c, d, e, f, g, h, i) \ - , a, b, c, d, e, f, g, h, i -#define GRPC_API_TRACE_UNWRAP10(a, b, c, d, e, f, g, h, i, j) \ - , a, b, c, d, e, f, g, h, i, j - -/* Due to the limitations of C89's preprocessor, the arity of the var-arg list - 'nargs' must be specified. */ -#define GRPC_API_TRACE(fmt, nargs, args) \ - if (grpc_api_trace) { \ - gpr_log(GPR_INFO, fmt GRPC_API_TRACE_UNWRAP##nargs args); \ - } - -#endif /* GRPC_CORE_SURFACE_API_TRACE_H */ diff --git a/src/core/surface/byte_buffer.c b/src/core/surface/byte_buffer.c deleted file mode 100644 index fb39c4531d..0000000000 --- a/src/core/surface/byte_buffer.c +++ /dev/null @@ -1,97 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include -#include -#include - -grpc_byte_buffer *grpc_raw_byte_buffer_create(gpr_slice *slices, - size_t nslices) { - return grpc_raw_compressed_byte_buffer_create(slices, nslices, - GRPC_COMPRESS_NONE); -} - -grpc_byte_buffer *grpc_raw_compressed_byte_buffer_create( - gpr_slice *slices, size_t nslices, grpc_compression_algorithm compression) { - size_t i; - grpc_byte_buffer *bb = malloc(sizeof(grpc_byte_buffer)); - bb->type = GRPC_BB_RAW; - bb->data.raw.compression = compression; - gpr_slice_buffer_init(&bb->data.raw.slice_buffer); - for (i = 0; i < nslices; i++) { - gpr_slice_ref(slices[i]); - gpr_slice_buffer_add(&bb->data.raw.slice_buffer, slices[i]); - } - return bb; -} - -grpc_byte_buffer *grpc_raw_byte_buffer_from_reader( - grpc_byte_buffer_reader *reader) { - grpc_byte_buffer *bb = malloc(sizeof(grpc_byte_buffer)); - gpr_slice slice; - bb->type = GRPC_BB_RAW; - bb->data.raw.compression = GRPC_COMPRESS_NONE; - gpr_slice_buffer_init(&bb->data.raw.slice_buffer); - - while (grpc_byte_buffer_reader_next(reader, &slice)) { - gpr_slice_buffer_add(&bb->data.raw.slice_buffer, slice); - } - return bb; -} - -grpc_byte_buffer *grpc_byte_buffer_copy(grpc_byte_buffer *bb) { - switch (bb->type) { - case GRPC_BB_RAW: - return grpc_raw_byte_buffer_create(bb->data.raw.slice_buffer.slices, - bb->data.raw.slice_buffer.count); - } - GPR_UNREACHABLE_CODE(return NULL); -} - -void grpc_byte_buffer_destroy(grpc_byte_buffer *bb) { - if (!bb) return; - switch (bb->type) { - case GRPC_BB_RAW: - gpr_slice_buffer_destroy(&bb->data.raw.slice_buffer); - break; - } - free(bb); -} - -size_t grpc_byte_buffer_length(grpc_byte_buffer *bb) { - switch (bb->type) { - case GRPC_BB_RAW: - return bb->data.raw.slice_buffer.length; - } - GPR_UNREACHABLE_CODE(return 0); -} diff --git a/src/core/surface/byte_buffer_reader.c b/src/core/surface/byte_buffer_reader.c deleted file mode 100644 index 4a418faaed..0000000000 --- a/src/core/surface/byte_buffer_reader.c +++ /dev/null @@ -1,123 +0,0 @@ -/* - * - * Copyright 2015-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 -#include - -#include -#include -#include -#include -#include -#include - -#include "src/core/compression/message_compress.h" - -static int is_compressed(grpc_byte_buffer *buffer) { - switch (buffer->type) { - case GRPC_BB_RAW: - if (buffer->data.raw.compression == GRPC_COMPRESS_NONE) { - return 0 /* GPR_FALSE */; - } - break; - } - return 1 /* GPR_TRUE */; -} - -void grpc_byte_buffer_reader_init(grpc_byte_buffer_reader *reader, - grpc_byte_buffer *buffer) { - gpr_slice_buffer decompressed_slices_buffer; - reader->buffer_in = buffer; - switch (reader->buffer_in->type) { - case GRPC_BB_RAW: - gpr_slice_buffer_init(&decompressed_slices_buffer); - if (is_compressed(reader->buffer_in)) { - grpc_msg_decompress(reader->buffer_in->data.raw.compression, - &reader->buffer_in->data.raw.slice_buffer, - &decompressed_slices_buffer); - reader->buffer_out = - grpc_raw_byte_buffer_create(decompressed_slices_buffer.slices, - decompressed_slices_buffer.count); - gpr_slice_buffer_destroy(&decompressed_slices_buffer); - } else { /* not compressed, use the input buffer as output */ - reader->buffer_out = reader->buffer_in; - } - reader->current.index = 0; - break; - } -} - -void grpc_byte_buffer_reader_destroy(grpc_byte_buffer_reader *reader) { - switch (reader->buffer_in->type) { - case GRPC_BB_RAW: - /* keeping the same if-else structure as in the init function */ - if (is_compressed(reader->buffer_in)) { - grpc_byte_buffer_destroy(reader->buffer_out); - } - break; - } -} - -int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader *reader, - gpr_slice *slice) { - switch (reader->buffer_in->type) { - case GRPC_BB_RAW: { - gpr_slice_buffer *slice_buffer; - slice_buffer = &reader->buffer_out->data.raw.slice_buffer; - if (reader->current.index < slice_buffer->count) { - *slice = gpr_slice_ref(slice_buffer->slices[reader->current.index]); - reader->current.index += 1; - return 1; - } - break; - } - } - return 0; -} - -gpr_slice grpc_byte_buffer_reader_readall(grpc_byte_buffer_reader *reader) { - gpr_slice in_slice; - size_t bytes_read = 0; - const size_t input_size = grpc_byte_buffer_length(reader->buffer_out); - gpr_slice out_slice = gpr_slice_malloc(input_size); - uint8_t *const outbuf = GPR_SLICE_START_PTR(out_slice); /* just an alias */ - - while (grpc_byte_buffer_reader_next(reader, &in_slice) != 0) { - const size_t slice_length = GPR_SLICE_LENGTH(in_slice); - memcpy(&(outbuf[bytes_read]), GPR_SLICE_START_PTR(in_slice), slice_length); - bytes_read += slice_length; - gpr_slice_unref(in_slice); - GPR_ASSERT(bytes_read <= input_size); - } - return out_slice; -} diff --git a/src/core/surface/call.c b/src/core/surface/call.c deleted file mode 100644 index 6f1cd1df10..0000000000 --- a/src/core/surface/call.c +++ /dev/null @@ -1,1491 +0,0 @@ -/* - * - * Copyright 2015-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 -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "src/core/channel/channel_stack.h" -#include "src/core/compression/algorithm_metadata.h" -#include "src/core/iomgr/timer.h" -#include "src/core/profiling/timers.h" -#include "src/core/support/string.h" -#include "src/core/surface/api_trace.h" -#include "src/core/surface/call.h" -#include "src/core/surface/channel.h" -#include "src/core/surface/completion_queue.h" -#include "src/core/transport/static_metadata.h" - -/** The maximum number of concurrent batches possible. - Based upon the maximum number of individually queueable ops in the batch - api: - - initial metadata send - - message send - - status/close send (depending on client/server) - - initial metadata recv - - message recv - - status/close recv (depending on client/server) */ -#define MAX_CONCURRENT_BATCHES 6 - -typedef struct { - grpc_ioreq_completion_func on_complete; - void *user_data; - int success; -} completed_request; - -#define MAX_SEND_EXTRA_METADATA_COUNT 3 - -/* Status data for a request can come from several sources; this - enumerates them all, and acts as a priority sorting for which - status to return to the application - earlier entries override - later ones */ -typedef enum { - /* Status came from the application layer overriding whatever - the wire says */ - STATUS_FROM_API_OVERRIDE = 0, - /* Status was created by some internal channel stack operation */ - STATUS_FROM_CORE, - /* Status came from 'the wire' - or somewhere below the surface - layer */ - STATUS_FROM_WIRE, - /* Status came from the server sending status */ - STATUS_FROM_SERVER_STATUS, - STATUS_SOURCE_COUNT -} status_source; - -typedef struct { - uint8_t is_set; - grpc_status_code code; - grpc_mdstr *details; -} received_status; - -/* How far through the GRPC stream have we read? */ -typedef enum { - /* We are still waiting for initial metadata to complete */ - READ_STATE_INITIAL = 0, - /* We have gotten initial metadata, and are reading either - messages or trailing metadata */ - READ_STATE_GOT_INITIAL_METADATA, - /* The stream is closed for reading */ - READ_STATE_READ_CLOSED, - /* The stream is closed for reading & writing */ - READ_STATE_STREAM_CLOSED -} read_state; - -typedef enum { - WRITE_STATE_INITIAL = 0, - WRITE_STATE_STARTED, - WRITE_STATE_WRITE_CLOSED -} write_state; - -typedef struct batch_control { - grpc_call *call; - grpc_cq_completion cq_completion; - grpc_closure finish_batch; - void *notify_tag; - gpr_refcount steps_to_complete; - - uint8_t send_initial_metadata; - uint8_t send_message; - uint8_t send_final_op; - uint8_t recv_initial_metadata; - uint8_t recv_message; - uint8_t recv_final_op; - uint8_t is_notify_tag_closure; - uint8_t success; -} batch_control; - -struct grpc_call { - grpc_completion_queue *cq; - grpc_channel *channel; - grpc_call *parent; - grpc_call *first_child; - /* TODO(ctiller): share with cq if possible? */ - gpr_mu mu; - - /* client or server call */ - uint8_t is_client; - /* is the alarm set */ - uint8_t have_alarm; - /** has grpc_call_destroy been called */ - uint8_t destroy_called; - /** flag indicating that cancellation is inherited */ - uint8_t cancellation_is_inherited; - /** bitmask of live batches */ - uint8_t used_batches; - /** which ops are in-flight */ - uint8_t sent_initial_metadata; - uint8_t sending_message; - uint8_t sent_final_op; - uint8_t received_initial_metadata; - uint8_t receiving_message; - uint8_t received_final_op; - - /* have we received initial metadata */ - bool has_initial_md_been_received; - - batch_control active_batches[MAX_CONCURRENT_BATCHES]; - - /* first idx: is_receiving, second idx: is_trailing */ - grpc_metadata_batch metadata_batch[2][2]; - - /* Buffered read metadata waiting to be returned to the application. - Element 0 is initial metadata, element 1 is trailing metadata. */ - grpc_metadata_array *buffered_metadata[2]; - - /* Received call statuses from various sources */ - received_status status[STATUS_SOURCE_COUNT]; - - /* Compression algorithm for the call */ - grpc_compression_algorithm compression_algorithm; - /* Supported encodings (compression algorithms), a bitset */ - uint32_t encodings_accepted_by_peer; - - /* Contexts for various subsystems (security, tracing, ...). */ - grpc_call_context_element context[GRPC_CONTEXT_COUNT]; - - /* Deadline alarm - if have_alarm is non-zero */ - grpc_timer alarm; - - /* for the client, extra metadata is initial metadata; for the - server, it's trailing metadata */ - grpc_linked_mdelem send_extra_metadata[MAX_SEND_EXTRA_METADATA_COUNT]; - int send_extra_metadata_count; - gpr_timespec send_deadline; - - /** siblings: children of the same parent form a list, and this list is - protected under - parent->mu */ - grpc_call *sibling_next; - grpc_call *sibling_prev; - - grpc_slice_buffer_stream sending_stream; - grpc_byte_stream *receiving_stream; - grpc_byte_buffer **receiving_buffer; - gpr_slice receiving_slice; - grpc_closure receiving_slice_ready; - grpc_closure receiving_stream_ready; - grpc_closure receiving_initial_metadata_ready; - uint32_t test_only_last_message_flags; - - union { - struct { - grpc_status_code *status; - char **status_details; - size_t *status_details_capacity; - } client; - struct { - int *cancelled; - } server; - } final_op; - - struct { - void *bctlp; - bool success; - } saved_receiving_stream_ready_ctx; -}; - -#define CALL_STACK_FROM_CALL(call) ((grpc_call_stack *)((call) + 1)) -#define CALL_FROM_CALL_STACK(call_stack) (((grpc_call *)(call_stack)) - 1) -#define CALL_ELEM_FROM_CALL(call, idx) \ - grpc_call_stack_element(CALL_STACK_FROM_CALL(call), idx) -#define CALL_FROM_TOP_ELEM(top_elem) \ - CALL_FROM_CALL_STACK(grpc_call_stack_from_top_element(top_elem)) - -static void set_deadline_alarm(grpc_exec_ctx *exec_ctx, grpc_call *call, - gpr_timespec deadline); -static void execute_op(grpc_exec_ctx *exec_ctx, grpc_call *call, - grpc_transport_stream_op *op); -static grpc_call_error cancel_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, - bool success); - -grpc_call *grpc_call_create(grpc_channel *channel, grpc_call *parent_call, - uint32_t propagation_mask, - grpc_completion_queue *cq, - const void *server_transport_data, - grpc_mdelem **add_initial_metadata, - size_t add_initial_metadata_count, - gpr_timespec send_deadline) { - size_t i, j; - grpc_channel_stack *channel_stack = grpc_channel_get_channel_stack(channel); - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_call *call; - GPR_TIMER_BEGIN("grpc_call_create", 0); - call = gpr_malloc(sizeof(grpc_call) + channel_stack->call_stack_size); - memset(call, 0, sizeof(grpc_call)); - gpr_mu_init(&call->mu); - call->channel = channel; - call->cq = cq; - call->parent = parent_call; - call->is_client = server_transport_data == NULL; - if (call->is_client) { - GPR_ASSERT(add_initial_metadata_count < MAX_SEND_EXTRA_METADATA_COUNT); - for (i = 0; i < add_initial_metadata_count; i++) { - call->send_extra_metadata[i].md = add_initial_metadata[i]; - } - call->send_extra_metadata_count = (int)add_initial_metadata_count; - } else { - GPR_ASSERT(add_initial_metadata_count == 0); - call->send_extra_metadata_count = 0; - } - for (i = 0; i < 2; i++) { - for (j = 0; j < 2; j++) { - call->metadata_batch[i][j].deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC); - } - } - call->send_deadline = send_deadline; - GRPC_CHANNEL_INTERNAL_REF(channel, "call"); - /* initial refcount dropped by grpc_call_destroy */ - grpc_call_stack_init(&exec_ctx, channel_stack, 1, destroy_call, call, - call->context, server_transport_data, - CALL_STACK_FROM_CALL(call)); - if (cq != NULL) { - GRPC_CQ_INTERNAL_REF(cq, "bind"); - grpc_call_stack_set_pollset(&exec_ctx, CALL_STACK_FROM_CALL(call), - grpc_cq_pollset(cq)); - } - if (parent_call != NULL) { - GRPC_CALL_INTERNAL_REF(parent_call, "child"); - GPR_ASSERT(call->is_client); - GPR_ASSERT(!parent_call->is_client); - - gpr_mu_lock(&parent_call->mu); - - if (propagation_mask & GRPC_PROPAGATE_DEADLINE) { - send_deadline = gpr_time_min( - gpr_convert_clock_type(send_deadline, - parent_call->send_deadline.clock_type), - parent_call->send_deadline); - } - /* for now GRPC_PROPAGATE_TRACING_CONTEXT *MUST* be passed with - * GRPC_PROPAGATE_STATS_CONTEXT */ - /* TODO(ctiller): This should change to use the appropriate census start_op - * call. */ - if (propagation_mask & GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT) { - GPR_ASSERT(propagation_mask & GRPC_PROPAGATE_CENSUS_STATS_CONTEXT); - grpc_call_context_set(call, GRPC_CONTEXT_TRACING, - parent_call->context[GRPC_CONTEXT_TRACING].value, - NULL); - } else { - GPR_ASSERT(propagation_mask & GRPC_PROPAGATE_CENSUS_STATS_CONTEXT); - } - if (propagation_mask & GRPC_PROPAGATE_CANCELLATION) { - call->cancellation_is_inherited = 1; - } - - if (parent_call->first_child == NULL) { - parent_call->first_child = call; - call->sibling_next = call->sibling_prev = call; - } else { - call->sibling_next = parent_call->first_child; - call->sibling_prev = parent_call->first_child->sibling_prev; - call->sibling_next->sibling_prev = call->sibling_prev->sibling_next = - call; - } - - gpr_mu_unlock(&parent_call->mu); - } - if (gpr_time_cmp(send_deadline, gpr_inf_future(send_deadline.clock_type)) != - 0) { - set_deadline_alarm(&exec_ctx, call, send_deadline); - } - grpc_exec_ctx_finish(&exec_ctx); - GPR_TIMER_END("grpc_call_create", 0); - return call; -} - -void grpc_call_set_completion_queue(grpc_exec_ctx *exec_ctx, grpc_call *call, - grpc_completion_queue *cq) { - GPR_ASSERT(cq); - call->cq = cq; - GRPC_CQ_INTERNAL_REF(cq, "bind"); - grpc_call_stack_set_pollset(exec_ctx, CALL_STACK_FROM_CALL(call), - grpc_cq_pollset(cq)); -} - -#ifdef GRPC_STREAM_REFCOUNT_DEBUG -#define REF_REASON reason -#define REF_ARG , const char *reason -#else -#define REF_REASON "" -#define REF_ARG -#endif -void grpc_call_internal_ref(grpc_call *c REF_ARG) { - GRPC_CALL_STACK_REF(CALL_STACK_FROM_CALL(c), REF_REASON); -} -void grpc_call_internal_unref(grpc_exec_ctx *exec_ctx, grpc_call *c REF_ARG) { - GRPC_CALL_STACK_UNREF(exec_ctx, CALL_STACK_FROM_CALL(c), REF_REASON); -} - -static void destroy_call(grpc_exec_ctx *exec_ctx, void *call, bool success) { - size_t i; - int ii; - grpc_call *c = call; - GPR_TIMER_BEGIN("destroy_call", 0); - for (i = 0; i < 2; i++) { - grpc_metadata_batch_destroy( - &c->metadata_batch[1 /* is_receiving */][i /* is_initial */]); - } - if (c->receiving_stream != NULL) { - grpc_byte_stream_destroy(exec_ctx, c->receiving_stream); - } - grpc_call_stack_destroy(exec_ctx, CALL_STACK_FROM_CALL(c)); - GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, c->channel, "call"); - gpr_mu_destroy(&c->mu); - for (i = 0; i < STATUS_SOURCE_COUNT; i++) { - if (c->status[i].details) { - GRPC_MDSTR_UNREF(c->status[i].details); - } - } - for (ii = 0; ii < c->send_extra_metadata_count; ii++) { - GRPC_MDELEM_UNREF(c->send_extra_metadata[ii].md); - } - for (i = 0; i < GRPC_CONTEXT_COUNT; i++) { - if (c->context[i].destroy) { - c->context[i].destroy(c->context[i].value); - } - } - if (c->cq) { - GRPC_CQ_INTERNAL_UNREF(c->cq, "bind"); - } - gpr_free(c); - GPR_TIMER_END("destroy_call", 0); -} - -static void set_status_code(grpc_call *call, status_source source, - uint32_t status) { - if (call->status[source].is_set) return; - - call->status[source].is_set = 1; - call->status[source].code = (grpc_status_code)status; - - /* TODO(ctiller): what to do about the flush that was previously here */ -} - -static void set_compression_algorithm(grpc_call *call, - grpc_compression_algorithm algo) { - call->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; - gpr_mu_unlock(&call->mu); - return algorithm; -} - -uint32_t grpc_call_test_only_get_message_flags(grpc_call *call) { - uint32_t flags; - gpr_mu_lock(&call->mu); - flags = call->test_only_last_message_flags; - gpr_mu_unlock(&call->mu); - return flags; -} - -static void destroy_encodings_accepted_by_peer(void *p) { return; } - -static void set_encodings_accepted_by_peer(grpc_call *call, grpc_mdelem *mdel) { - size_t i; - grpc_compression_algorithm algorithm; - gpr_slice_buffer accept_encoding_parts; - gpr_slice accept_encoding_slice; - void *accepted_user_data; - - accepted_user_data = - grpc_mdelem_get_user_data(mdel, destroy_encodings_accepted_by_peer); - if (accepted_user_data != NULL) { - call->encodings_accepted_by_peer = - (uint32_t)(((uintptr_t)accepted_user_data) - 1); - return; - } - - accept_encoding_slice = mdel->value->slice; - gpr_slice_buffer_init(&accept_encoding_parts); - gpr_slice_split(accept_encoding_slice, ",", &accept_encoding_parts); - - /* No need to zero call->encodings_accepted_by_peer: grpc_call_create already - * zeroes the whole grpc_call */ - /* Always support no compression */ - GPR_BITSET(&call->encodings_accepted_by_peer, GRPC_COMPRESS_NONE); - for (i = 0; i < accept_encoding_parts.count; i++) { - const gpr_slice *accept_encoding_entry_slice = - &accept_encoding_parts.slices[i]; - if (grpc_compression_algorithm_parse( - (const char *)GPR_SLICE_START_PTR(*accept_encoding_entry_slice), - GPR_SLICE_LENGTH(*accept_encoding_entry_slice), &algorithm)) { - GPR_BITSET(&call->encodings_accepted_by_peer, algorithm); - } else { - char *accept_encoding_entry_str = - gpr_dump_slice(*accept_encoding_entry_slice, GPR_DUMP_ASCII); - gpr_log(GPR_ERROR, - "Invalid entry in accept encoding metadata: '%s'. Ignoring.", - accept_encoding_entry_str); - gpr_free(accept_encoding_entry_str); - } - } - - gpr_slice_buffer_destroy(&accept_encoding_parts); - - grpc_mdelem_set_user_data( - mdel, destroy_encodings_accepted_by_peer, - (void *)(((uintptr_t)call->encodings_accepted_by_peer) + 1)); -} - -uint32_t grpc_call_test_only_get_encodings_accepted_by_peer(grpc_call *call) { - uint32_t encodings_accepted_by_peer; - gpr_mu_lock(&call->mu); - encodings_accepted_by_peer = call->encodings_accepted_by_peer; - gpr_mu_unlock(&call->mu); - return encodings_accepted_by_peer; -} - -static void set_status_details(grpc_call *call, status_source source, - grpc_mdstr *status) { - if (call->status[source].details != NULL) { - GRPC_MDSTR_UNREF(call->status[source].details); - } - call->status[source].details = status; -} - -static void get_final_status(grpc_call *call, - void (*set_value)(grpc_status_code code, - void *user_data), - void *set_value_user_data) { - int i; - for (i = 0; i < STATUS_SOURCE_COUNT; i++) { - if (call->status[i].is_set) { - set_value(call->status[i].code, set_value_user_data); - return; - } - } - if (call->is_client) { - set_value(GRPC_STATUS_UNKNOWN, set_value_user_data); - } else { - set_value(GRPC_STATUS_OK, set_value_user_data); - } -} - -static void get_final_details(grpc_call *call, char **out_details, - size_t *out_details_capacity) { - int i; - for (i = 0; i < STATUS_SOURCE_COUNT; i++) { - if (call->status[i].is_set) { - if (call->status[i].details) { - gpr_slice details = call->status[i].details->slice; - size_t len = GPR_SLICE_LENGTH(details); - if (len + 1 > *out_details_capacity) { - *out_details_capacity = - GPR_MAX(len + 1, *out_details_capacity * 3 / 2); - *out_details = gpr_realloc(*out_details, *out_details_capacity); - } - memcpy(*out_details, GPR_SLICE_START_PTR(details), len); - (*out_details)[len] = 0; - } else { - goto no_details; - } - return; - } - } - -no_details: - if (0 == *out_details_capacity) { - *out_details_capacity = 8; - *out_details = gpr_malloc(*out_details_capacity); - } - **out_details = 0; -} - -static grpc_linked_mdelem *linked_from_md(grpc_metadata *md) { - return (grpc_linked_mdelem *)&md->internal_data; -} - -static int prepare_application_metadata(grpc_call *call, int count, - grpc_metadata *metadata, - int is_trailing, - int prepend_extra_metadata) { - int i; - grpc_metadata_batch *batch = - &call->metadata_batch[0 /* is_receiving */][is_trailing]; - if (prepend_extra_metadata) { - if (call->send_extra_metadata_count == 0) { - prepend_extra_metadata = 0; - } else { - for (i = 0; i < call->send_extra_metadata_count; i++) { - GRPC_MDELEM_REF(call->send_extra_metadata[i].md); - } - for (i = 1; i < call->send_extra_metadata_count; i++) { - call->send_extra_metadata[i].prev = &call->send_extra_metadata[i - 1]; - } - for (i = 0; i < call->send_extra_metadata_count - 1; i++) { - call->send_extra_metadata[i].next = &call->send_extra_metadata[i + 1]; - } - } - } - for (i = 0; i < count; i++) { - grpc_metadata *md = &metadata[i]; - 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( - md->key, (const uint8_t *)md->value, md->value_length); - if (!grpc_header_key_is_legal(grpc_mdstr_as_c_string(l->md->key), - GRPC_MDSTR_LENGTH(l->md->key))) { - gpr_log(GPR_ERROR, "attempt to send invalid metadata key: %s", - grpc_mdstr_as_c_string(l->md->key)); - return 0; - } else if (!grpc_is_binary_header(grpc_mdstr_as_c_string(l->md->key), - GRPC_MDSTR_LENGTH(l->md->key)) && - !grpc_header_nonbin_value_is_legal( - grpc_mdstr_as_c_string(l->md->value), - GRPC_MDSTR_LENGTH(l->md->value))) { - gpr_log(GPR_ERROR, "attempt to send invalid metadata value"); - return 0; - } - } - for (i = 1; i < count; i++) { - linked_from_md(&metadata[i])->prev = linked_from_md(&metadata[i - 1]); - } - for (i = 0; i < count - 1; i++) { - linked_from_md(&metadata[i])->next = linked_from_md(&metadata[i + 1]); - } - switch (prepend_extra_metadata * 2 + (count != 0)) { - case 0: - /* no prepend, no metadata => nothing to do */ - batch->list.head = batch->list.tail = NULL; - break; - case 1: - /* metadata, but no prepend */ - batch->list.head = linked_from_md(&metadata[0]); - batch->list.tail = linked_from_md(&metadata[count - 1]); - 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]; - batch->list.tail = - &call->send_extra_metadata[call->send_extra_metadata_count - 1]; - batch->list.head->prev = NULL; - batch->list.tail->next = NULL; - break; - case 3: - /* prepend AND md */ - 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 = - &call->send_extra_metadata[call->send_extra_metadata_count - 1]; - batch->list.tail = linked_from_md(&metadata[count - 1]); - batch->list.head->prev = NULL; - batch->list.tail->next = NULL; - break; - default: - GPR_UNREACHABLE_CODE(return 0); - } - - return 1; -} - -void grpc_call_destroy(grpc_call *c) { - int cancel; - grpc_call *parent = c->parent; - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - - GPR_TIMER_BEGIN("grpc_call_destroy", 0); - GRPC_API_TRACE("grpc_call_destroy(c=%p)", 1, (c)); - - if (parent) { - gpr_mu_lock(&parent->mu); - if (c == parent->first_child) { - parent->first_child = c->sibling_next; - if (c == parent->first_child) { - parent->first_child = NULL; - } - c->sibling_prev->sibling_next = c->sibling_next; - c->sibling_next->sibling_prev = c->sibling_prev; - } - gpr_mu_unlock(&parent->mu); - GRPC_CALL_INTERNAL_UNREF(&exec_ctx, parent, "child"); - } - - gpr_mu_lock(&c->mu); - GPR_ASSERT(!c->destroy_called); - c->destroy_called = 1; - if (c->have_alarm) { - grpc_timer_cancel(&exec_ctx, &c->alarm); - } - cancel = !c->received_final_op; - gpr_mu_unlock(&c->mu); - if (cancel) grpc_call_cancel(c, NULL); - GRPC_CALL_INTERNAL_UNREF(&exec_ctx, c, "destroy"); - grpc_exec_ctx_finish(&exec_ctx); - GPR_TIMER_END("grpc_call_destroy", 0); -} - -grpc_call_error grpc_call_cancel(grpc_call *call, void *reserved) { - GRPC_API_TRACE("grpc_call_cancel(call=%p, reserved=%p)", 2, (call, reserved)); - GPR_ASSERT(!reserved); - return grpc_call_cancel_with_status(call, GRPC_STATUS_CANCELLED, "Cancelled", - NULL); -} - -grpc_call_error grpc_call_cancel_with_status(grpc_call *c, - grpc_status_code status, - const char *description, - void *reserved) { - grpc_call_error r; - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - GRPC_API_TRACE( - "grpc_call_cancel_with_status(" - "c=%p, status=%d, description=%s, reserved=%p)", - 4, (c, (int)status, description, reserved)); - GPR_ASSERT(reserved == NULL); - gpr_mu_lock(&c->mu); - r = cancel_with_status(&exec_ctx, c, status, description); - gpr_mu_unlock(&c->mu); - grpc_exec_ctx_finish(&exec_ctx); - return r; -} - -typedef struct cancel_closure { - grpc_closure closure; - grpc_call *call; - grpc_status_code status; -} cancel_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 send_cancel(grpc_exec_ctx *exec_ctx, void *ccp, bool success) { - grpc_transport_stream_op op; - cancel_closure *cc = ccp; - memset(&op, 0, sizeof(op)); - op.cancel_with_status = cc->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); -} - -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)); - - GPR_ASSERT(status != GRPC_STATUS_OK); - - set_status_code(c, STATUS_FROM_API_OVERRIDE, (uint32_t)status); - set_status_details(c, STATUS_FROM_API_OVERRIDE, details); - - 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); - - return GRPC_CALL_OK; -} - -static void execute_op(grpc_exec_ctx *exec_ctx, grpc_call *call, - grpc_transport_stream_op *op) { - grpc_call_element *elem; - - GPR_TIMER_BEGIN("execute_op", 0); - elem = CALL_ELEM_FROM_CALL(call, 0); - op->context = call->context; - elem->filter->start_transport_stream_op(exec_ctx, elem, op); - GPR_TIMER_END("execute_op", 0); -} - -char *grpc_call_get_peer(grpc_call *call) { - grpc_call_element *elem = CALL_ELEM_FROM_CALL(call, 0); - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - char *result; - GRPC_API_TRACE("grpc_call_get_peer(%p)", 1, (call)); - result = elem->filter->get_peer(&exec_ctx, elem); - if (result == NULL) { - result = grpc_channel_get_target(call->channel); - } - if (result == NULL) { - result = gpr_strdup("unknown"); - } - grpc_exec_ctx_finish(&exec_ctx); - return result; -} - -grpc_call *grpc_call_from_top_element(grpc_call_element *elem) { - return CALL_FROM_TOP_ELEM(elem); -} - -static void call_alarm(grpc_exec_ctx *exec_ctx, void *arg, bool success) { - grpc_call *call = arg; - gpr_mu_lock(&call->mu); - call->have_alarm = 0; - if (success) { - cancel_with_status(exec_ctx, call, GRPC_STATUS_DEADLINE_EXCEEDED, - "Deadline Exceeded"); - } - gpr_mu_unlock(&call->mu); - GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, "alarm"); -} - -static void set_deadline_alarm(grpc_exec_ctx *exec_ctx, grpc_call *call, - gpr_timespec deadline) { - if (call->have_alarm) { - gpr_log(GPR_ERROR, "Attempt to set deadline alarm twice"); - assert(0); - return; - } - GRPC_CALL_INTERNAL_REF(call, "alarm"); - call->have_alarm = 1; - call->send_deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC); - grpc_timer_init(exec_ctx, &call->alarm, call->send_deadline, call_alarm, call, - gpr_now(GPR_CLOCK_MONOTONIC)); -} - -/* we offset status by a small amount when storing it into transport metadata - as metadata cannot store a 0 value (which is used as OK for grpc_status_codes - */ -#define STATUS_OFFSET 1 -static void destroy_status(void *ignored) {} - -static uint32_t decode_status(grpc_mdelem *md) { - uint32_t status; - void *user_data; - if (md == GRPC_MDELEM_GRPC_STATUS_0) return 0; - if (md == GRPC_MDELEM_GRPC_STATUS_1) return 1; - if (md == GRPC_MDELEM_GRPC_STATUS_2) return 2; - user_data = grpc_mdelem_get_user_data(md, destroy_status); - if (user_data != NULL) { - status = ((uint32_t)(intptr_t)user_data) - STATUS_OFFSET; - } else { - if (!gpr_parse_bytes_to_uint32(grpc_mdstr_as_c_string(md->value), - GPR_SLICE_LENGTH(md->value->slice), - &status)) { - status = GRPC_STATUS_UNKNOWN; /* could not parse status code */ - } - grpc_mdelem_set_user_data(md, destroy_status, - (void *)(intptr_t)(status + STATUS_OFFSET)); - } - return status; -} - -static uint32_t decode_compression(grpc_mdelem *md) { - grpc_compression_algorithm algorithm = - grpc_compression_algorithm_from_mdstr(md->value); - if (algorithm == GRPC_COMPRESS_ALGORITHMS_COUNT) { - const char *md_c_str = grpc_mdstr_as_c_string(md->value); - gpr_log(GPR_ERROR, "Invalid compression algorithm: '%s'", md_c_str); - } - return algorithm; -} - -static grpc_mdelem *recv_common_filter(grpc_call *call, grpc_mdelem *elem) { - if (elem->key == GRPC_MDSTR_GRPC_STATUS) { - GPR_TIMER_BEGIN("status", 0); - set_status_code(call, STATUS_FROM_WIRE, decode_status(elem)); - GPR_TIMER_END("status", 0); - return NULL; - } else if (elem->key == GRPC_MDSTR_GRPC_MESSAGE) { - GPR_TIMER_BEGIN("status-details", 0); - set_status_details(call, STATUS_FROM_WIRE, GRPC_MDSTR_REF(elem->value)); - GPR_TIMER_END("status-details", 0); - return NULL; - } - return elem; -} - -static grpc_mdelem *publish_app_metadata(grpc_call *call, grpc_mdelem *elem, - int is_trailing) { - grpc_metadata_array *dest; - grpc_metadata *mdusr; - GPR_TIMER_BEGIN("publish_app_metadata", 0); - dest = call->buffered_metadata[is_trailing]; - if (dest->count == dest->capacity) { - dest->capacity = GPR_MAX(dest->capacity + 8, dest->capacity * 2); - dest->metadata = - gpr_realloc(dest->metadata, sizeof(grpc_metadata) * dest->capacity); - } - mdusr = &dest->metadata[dest->count++]; - mdusr->key = grpc_mdstr_as_c_string(elem->key); - mdusr->value = grpc_mdstr_as_c_string(elem->value); - mdusr->value_length = GPR_SLICE_LENGTH(elem->value->slice); - GPR_TIMER_END("publish_app_metadata", 0); - return elem; -} - -static grpc_mdelem *recv_initial_filter(void *callp, grpc_mdelem *elem) { - grpc_call *call = callp; - elem = recv_common_filter(call, 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); - return NULL; - } else if (elem->key == GRPC_MDSTR_GRPC_ACCEPT_ENCODING) { - GPR_TIMER_BEGIN("encodings_accepted_by_peer", 0); - set_encodings_accepted_by_peer(call, elem); - GPR_TIMER_END("encodings_accepted_by_peer", 0); - return NULL; - } else { - return publish_app_metadata(call, elem, 0); - } -} - -static grpc_mdelem *recv_trailing_filter(void *callp, grpc_mdelem *elem) { - grpc_call *call = callp; - elem = recv_common_filter(call, elem); - if (elem == NULL) { - return NULL; - } else { - return publish_app_metadata(call, elem, 1); - } -} - -grpc_call_stack *grpc_call_get_call_stack(grpc_call *call) { - return CALL_STACK_FROM_CALL(call); -} - -/* - * BATCH API IMPLEMENTATION - */ - -static void set_status_value_directly(grpc_status_code status, void *dest) { - *(grpc_status_code *)dest = status; -} - -static void set_cancelled_value(grpc_status_code status, void *dest) { - *(int *)dest = (status != GRPC_STATUS_OK); -} - -static int are_write_flags_valid(uint32_t flags) { - /* check that only bits in GRPC_WRITE_(INTERNAL?)_USED_MASK are set */ - const uint32_t allowed_write_positions = - (GRPC_WRITE_USED_MASK | GRPC_WRITE_INTERNAL_USED_MASK); - const uint32_t invalid_positions = ~allowed_write_positions; - return !(flags & invalid_positions); -} - -static batch_control *allocate_batch_control(grpc_call *call) { - size_t i; - for (i = 0; i < MAX_CONCURRENT_BATCHES; i++) { - if ((call->used_batches & (1 << i)) == 0) { - call->used_batches = (uint8_t)(call->used_batches | (uint8_t)(1 << i)); - return &call->active_batches[i]; - } - } - return NULL; -} - -static void finish_batch_completion(grpc_exec_ctx *exec_ctx, void *user_data, - grpc_cq_completion *storage) { - batch_control *bctl = user_data; - grpc_call *call = bctl->call; - gpr_mu_lock(&call->mu); - call->used_batches = (uint8_t)( - call->used_batches & ~(uint8_t)(1 << (bctl - call->active_batches))); - gpr_mu_unlock(&call->mu); - GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, "completion"); -} - -static void post_batch_completion(grpc_exec_ctx *exec_ctx, - batch_control *bctl) { - grpc_call *call = bctl->call; - if (bctl->is_notify_tag_closure) { - grpc_exec_ctx_enqueue(exec_ctx, bctl->notify_tag, bctl->success, NULL); - gpr_mu_lock(&call->mu); - bctl->call->used_batches = - (uint8_t)(bctl->call->used_batches & - ~(uint8_t)(1 << (bctl - bctl->call->active_batches))); - gpr_mu_unlock(&call->mu); - GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, "completion"); - } else { - grpc_cq_end_op(exec_ctx, bctl->call->cq, bctl->notify_tag, bctl->success, - finish_batch_completion, bctl, &bctl->cq_completion); - } -} - -static void continue_receiving_slices(grpc_exec_ctx *exec_ctx, - batch_control *bctl) { - grpc_call *call = bctl->call; - for (;;) { - size_t remaining = call->receiving_stream->length - - (*call->receiving_buffer)->data.raw.slice_buffer.length; - if (remaining == 0) { - call->receiving_message = 0; - grpc_byte_stream_destroy(exec_ctx, call->receiving_stream); - call->receiving_stream = NULL; - if (gpr_unref(&bctl->steps_to_complete)) { - post_batch_completion(exec_ctx, bctl); - } - return; - } - if (grpc_byte_stream_next(exec_ctx, call->receiving_stream, - &call->receiving_slice, remaining, - &call->receiving_slice_ready)) { - gpr_slice_buffer_add(&(*call->receiving_buffer)->data.raw.slice_buffer, - call->receiving_slice); - } else { - return; - } - } -} - -static void receiving_slice_ready(grpc_exec_ctx *exec_ctx, void *bctlp, - bool success) { - batch_control *bctl = bctlp; - grpc_call *call = bctl->call; - - if (success) { - gpr_slice_buffer_add(&(*call->receiving_buffer)->data.raw.slice_buffer, - call->receiving_slice); - continue_receiving_slices(exec_ctx, bctl); - } else { - grpc_byte_stream_destroy(exec_ctx, call->receiving_stream); - call->receiving_stream = NULL; - grpc_byte_buffer_destroy(*call->receiving_buffer); - *call->receiving_buffer = NULL; - if (gpr_unref(&bctl->steps_to_complete)) { - post_batch_completion(exec_ctx, bctl); - } - } -} - -static void process_data_after_md(grpc_exec_ctx *exec_ctx, batch_control *bctl, - bool success) { - grpc_call *call = bctl->call; - if (call->receiving_stream == NULL) { - *call->receiving_buffer = NULL; - call->receiving_message = 0; - if (gpr_unref(&bctl->steps_to_complete)) { - post_batch_completion(exec_ctx, bctl); - } - } else if (call->receiving_stream->length > - grpc_channel_get_max_message_length(call->channel)) { - cancel_with_status(exec_ctx, call, GRPC_STATUS_INTERNAL, - "Max message size exceeded"); - grpc_byte_stream_destroy(exec_ctx, call->receiving_stream); - call->receiving_stream = NULL; - *call->receiving_buffer = NULL; - call->receiving_message = 0; - if (gpr_unref(&bctl->steps_to_complete)) { - post_batch_completion(exec_ctx, 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->receiving_buffer = grpc_raw_compressed_byte_buffer_create( - NULL, 0, call->compression_algorithm); - } else { - *call->receiving_buffer = grpc_raw_byte_buffer_create(NULL, 0); - } - grpc_closure_init(&call->receiving_slice_ready, receiving_slice_ready, - bctl); - continue_receiving_slices(exec_ctx, bctl); - /* early out */ - return; - } -} - -static void receiving_stream_ready(grpc_exec_ctx *exec_ctx, void *bctlp, - bool success) { - batch_control *bctl = bctlp; - grpc_call *call = bctl->call; - - gpr_mu_lock(&bctl->call->mu); - if (bctl->call->has_initial_md_been_received) { - gpr_mu_unlock(&bctl->call->mu); - process_data_after_md(exec_ctx, bctlp, success); - } else { - call->saved_receiving_stream_ready_ctx.bctlp = bctlp; - call->saved_receiving_stream_ready_ctx.success = success; - gpr_mu_unlock(&bctl->call->mu); - } -} - -static void receiving_initial_metadata_ready(grpc_exec_ctx *exec_ctx, - void *bctlp, bool success) { - batch_control *bctl = bctlp; - grpc_call *call = bctl->call; - - gpr_mu_lock(&call->mu); - - grpc_metadata_batch *md = - &call->metadata_batch[1 /* is_receiving */][0 /* is_trailing */]; - grpc_metadata_batch_filter(md, recv_initial_filter, call); - call->has_initial_md_been_received = true; - - if (gpr_time_cmp(md->deadline, gpr_inf_future(md->deadline.clock_type)) != - 0 && - !call->is_client) { - GPR_TIMER_BEGIN("set_deadline_alarm", 0); - set_deadline_alarm(exec_ctx, call, md->deadline); - GPR_TIMER_END("set_deadline_alarm", 0); - } - - if (call->saved_receiving_stream_ready_ctx.bctlp != NULL) { - grpc_closure *saved_rsr_closure = grpc_closure_create( - receiving_stream_ready, call->saved_receiving_stream_ready_ctx.bctlp); - grpc_exec_ctx_enqueue(exec_ctx, saved_rsr_closure, - call->saved_receiving_stream_ready_ctx.success, NULL); - call->saved_receiving_stream_ready_ctx.bctlp = NULL; - } - - gpr_mu_unlock(&call->mu); - - if (gpr_unref(&bctl->steps_to_complete)) { - post_batch_completion(exec_ctx, bctl); - } -} - -static void finish_batch(grpc_exec_ctx *exec_ctx, void *bctlp, bool success) { - batch_control *bctl = bctlp; - grpc_call *call = bctl->call; - grpc_call *child_call; - grpc_call *next_child_call; - - gpr_mu_lock(&call->mu); - if (bctl->send_initial_metadata) { - grpc_metadata_batch_destroy( - &call->metadata_batch[0 /* is_receiving */][0 /* is_trailing */]); - } - if (bctl->send_message) { - call->sending_message = 0; - } - if (bctl->send_final_op) { - grpc_metadata_batch_destroy( - &call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */]); - } - if (bctl->recv_final_op) { - grpc_metadata_batch *md = - &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */]; - grpc_metadata_batch_filter(md, recv_trailing_filter, call); - - if (call->have_alarm) { - grpc_timer_cancel(exec_ctx, &call->alarm); - } - /* propagate cancellation to any interested children */ - child_call = call->first_child; - if (child_call != NULL) { - do { - next_child_call = child_call->sibling_next; - if (child_call->cancellation_is_inherited) { - GRPC_CALL_INTERNAL_REF(child_call, "propagate_cancel"); - grpc_call_cancel(child_call, NULL); - GRPC_CALL_INTERNAL_UNREF(exec_ctx, child_call, "propagate_cancel"); - } - child_call = next_child_call; - } while (child_call != call->first_child); - } - - if (call->is_client) { - get_final_status(call, set_status_value_directly, - call->final_op.client.status); - get_final_details(call, call->final_op.client.status_details, - call->final_op.client.status_details_capacity); - } else { - get_final_status(call, set_cancelled_value, - call->final_op.server.cancelled); - } - - success = 1; - } - bctl->success = success != 0; - gpr_mu_unlock(&call->mu); - if (gpr_unref(&bctl->steps_to_complete)) { - post_batch_completion(exec_ctx, bctl); - } -} - -static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx, - grpc_call *call, const grpc_op *ops, - size_t nops, void *notify_tag, - int is_notify_tag_closure) { - grpc_transport_stream_op stream_op; - size_t i; - const grpc_op *op; - batch_control *bctl; - int num_completion_callbacks_needed = 1; - grpc_call_error error = GRPC_CALL_OK; - - GPR_TIMER_BEGIN("grpc_call_start_batch", 0); - - GRPC_CALL_LOG_BATCH(GPR_INFO, call, ops, nops, notify_tag); - - memset(&stream_op, 0, sizeof(stream_op)); - - /* TODO(ctiller): this feels like it could be made lock-free */ - gpr_mu_lock(&call->mu); - bctl = allocate_batch_control(call); - memset(bctl, 0, sizeof(*bctl)); - bctl->call = call; - bctl->notify_tag = notify_tag; - bctl->is_notify_tag_closure = (uint8_t)(is_notify_tag_closure != 0); - - if (nops == 0) { - GRPC_CALL_INTERNAL_REF(call, "completion"); - bctl->success = 1; - if (!is_notify_tag_closure) { - grpc_cq_begin_op(call->cq, notify_tag); - } - gpr_mu_unlock(&call->mu); - post_batch_completion(exec_ctx, bctl); - error = GRPC_CALL_OK; - goto done; - } - - /* rewrite batch ops into a transport op */ - for (i = 0; i < nops; i++) { - op = &ops[i]; - if (op->reserved != NULL) { - error = GRPC_CALL_ERROR; - goto done_with_error; - } - switch (op->op) { - case GRPC_OP_SEND_INITIAL_METADATA: - /* Flag validation: currently allow no flags */ - if (op->flags != 0) { - error = GRPC_CALL_ERROR_INVALID_FLAGS; - goto done_with_error; - } - if (call->sent_initial_metadata) { - error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; - goto done_with_error; - } - if (op->data.send_initial_metadata.count > INT_MAX) { - error = GRPC_CALL_ERROR_INVALID_METADATA; - goto done_with_error; - } - bctl->send_initial_metadata = 1; - 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)) { - error = GRPC_CALL_ERROR_INVALID_METADATA; - goto done_with_error; - } - /* TODO(ctiller): just make these the same variable? */ - call->metadata_batch[0][0].deadline = call->send_deadline; - stream_op.send_initial_metadata = - &call->metadata_batch[0 /* is_receiving */][0 /* is_trailing */]; - break; - case GRPC_OP_SEND_MESSAGE: - if (!are_write_flags_valid(op->flags)) { - error = GRPC_CALL_ERROR_INVALID_FLAGS; - goto done_with_error; - } - if (op->data.send_message == NULL) { - error = GRPC_CALL_ERROR_INVALID_MESSAGE; - goto done_with_error; - } - if (call->sending_message) { - error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; - goto done_with_error; - } - bctl->send_message = 1; - call->sending_message = 1; - grpc_slice_buffer_stream_init( - &call->sending_stream, - &op->data.send_message->data.raw.slice_buffer, op->flags); - stream_op.send_message = &call->sending_stream.base; - break; - case GRPC_OP_SEND_CLOSE_FROM_CLIENT: - /* Flag validation: currently allow no flags */ - if (op->flags != 0) { - error = GRPC_CALL_ERROR_INVALID_FLAGS; - goto done_with_error; - } - if (!call->is_client) { - error = GRPC_CALL_ERROR_NOT_ON_SERVER; - goto done_with_error; - } - if (call->sent_final_op) { - error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; - goto done_with_error; - } - bctl->send_final_op = 1; - call->sent_final_op = 1; - stream_op.send_trailing_metadata = - &call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */]; - break; - case GRPC_OP_SEND_STATUS_FROM_SERVER: - /* Flag validation: currently allow no flags */ - if (op->flags != 0) { - error = GRPC_CALL_ERROR_INVALID_FLAGS; - goto done_with_error; - } - if (call->is_client) { - error = GRPC_CALL_ERROR_NOT_ON_CLIENT; - goto done_with_error; - } - if (call->sent_final_op) { - error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; - goto done_with_error; - } - if (op->data.send_status_from_server.trailing_metadata_count > - INT_MAX) { - error = GRPC_CALL_ERROR_INVALID_METADATA; - goto done_with_error; - } - bctl->send_final_op = 1; - call->sent_final_op = 1; - call->send_extra_metadata_count = 1; - call->send_extra_metadata[0].md = grpc_channel_get_reffed_status_elem( - call->channel, op->data.send_status_from_server.status); - if (op->data.send_status_from_server.status_details != NULL) { - call->send_extra_metadata[1].md = grpc_mdelem_from_metadata_strings( - GRPC_MDSTR_GRPC_MESSAGE, - grpc_mdstr_from_string( - op->data.send_status_from_server.status_details)); - call->send_extra_metadata_count++; - set_status_details( - call, STATUS_FROM_API_OVERRIDE, - GRPC_MDSTR_REF(call->send_extra_metadata[1].md->value)); - } - set_status_code(call, STATUS_FROM_API_OVERRIDE, - (uint32_t)op->data.send_status_from_server.status); - 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)) { - error = GRPC_CALL_ERROR_INVALID_METADATA; - goto done_with_error; - } - stream_op.send_trailing_metadata = - &call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */]; - break; - case GRPC_OP_RECV_INITIAL_METADATA: - /* Flag validation: currently allow no flags */ - if (op->flags != 0) { - error = GRPC_CALL_ERROR_INVALID_FLAGS; - goto done_with_error; - } - if (call->received_initial_metadata) { - error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; - goto done_with_error; - } - call->received_initial_metadata = 1; - call->buffered_metadata[0] = op->data.recv_initial_metadata; - grpc_closure_init(&call->receiving_initial_metadata_ready, - receiving_initial_metadata_ready, bctl); - bctl->recv_initial_metadata = 1; - stream_op.recv_initial_metadata = - &call->metadata_batch[1 /* is_receiving */][0 /* is_trailing */]; - stream_op.recv_initial_metadata_ready = - &call->receiving_initial_metadata_ready; - num_completion_callbacks_needed++; - break; - case GRPC_OP_RECV_MESSAGE: - /* Flag validation: currently allow no flags */ - if (op->flags != 0) { - error = GRPC_CALL_ERROR_INVALID_FLAGS; - goto done_with_error; - } - if (call->receiving_message) { - error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; - goto done_with_error; - } - call->receiving_message = 1; - bctl->recv_message = 1; - call->receiving_buffer = op->data.recv_message; - stream_op.recv_message = &call->receiving_stream; - grpc_closure_init(&call->receiving_stream_ready, receiving_stream_ready, - bctl); - stream_op.recv_message_ready = &call->receiving_stream_ready; - num_completion_callbacks_needed++; - break; - case GRPC_OP_RECV_STATUS_ON_CLIENT: - /* Flag validation: currently allow no flags */ - if (op->flags != 0) { - error = GRPC_CALL_ERROR_INVALID_FLAGS; - goto done_with_error; - } - if (!call->is_client) { - error = GRPC_CALL_ERROR_NOT_ON_SERVER; - goto done_with_error; - } - if (call->received_final_op) { - error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; - goto done_with_error; - } - call->received_final_op = 1; - call->buffered_metadata[1] = - op->data.recv_status_on_client.trailing_metadata; - call->final_op.client.status = op->data.recv_status_on_client.status; - call->final_op.client.status_details = - op->data.recv_status_on_client.status_details; - call->final_op.client.status_details_capacity = - op->data.recv_status_on_client.status_details_capacity; - bctl->recv_final_op = 1; - stream_op.recv_trailing_metadata = - &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */]; - break; - case GRPC_OP_RECV_CLOSE_ON_SERVER: - /* Flag validation: currently allow no flags */ - if (op->flags != 0) { - error = GRPC_CALL_ERROR_INVALID_FLAGS; - goto done_with_error; - } - if (call->is_client) { - error = GRPC_CALL_ERROR_NOT_ON_CLIENT; - goto done_with_error; - } - if (call->received_final_op) { - error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; - goto done_with_error; - } - call->received_final_op = 1; - call->final_op.server.cancelled = - op->data.recv_close_on_server.cancelled; - bctl->recv_final_op = 1; - stream_op.recv_trailing_metadata = - &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */]; - break; - } - } - - GRPC_CALL_INTERNAL_REF(call, "completion"); - if (!is_notify_tag_closure) { - grpc_cq_begin_op(call->cq, notify_tag); - } - gpr_ref_init(&bctl->steps_to_complete, num_completion_callbacks_needed); - - stream_op.context = call->context; - grpc_closure_init(&bctl->finish_batch, finish_batch, bctl); - stream_op.on_complete = &bctl->finish_batch; - gpr_mu_unlock(&call->mu); - - execute_op(exec_ctx, call, &stream_op); - -done: - GPR_TIMER_END("grpc_call_start_batch", 0); - return error; - -done_with_error: - /* reverse any mutations that occured */ - if (bctl->send_initial_metadata) { - call->sent_initial_metadata = 0; - grpc_metadata_batch_clear(&call->metadata_batch[0][0]); - } - if (bctl->send_message) { - call->sending_message = 0; - grpc_byte_stream_destroy(exec_ctx, &call->sending_stream.base); - } - if (bctl->send_final_op) { - call->sent_final_op = 0; - grpc_metadata_batch_clear(&call->metadata_batch[0][1]); - } - if (bctl->recv_initial_metadata) { - call->received_initial_metadata = 0; - } - if (bctl->recv_message) { - call->receiving_message = 0; - } - if (bctl->recv_final_op) { - call->received_final_op = 0; - } - gpr_mu_unlock(&call->mu); - goto done; -} - -grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops, - size_t nops, void *tag, void *reserved) { - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_call_error err; - - GRPC_API_TRACE( - "grpc_call_start_batch(call=%p, ops=%p, nops=%lu, tag=%p, reserved=%p)", - 5, (call, ops, (unsigned long)nops, tag, reserved)); - - if (reserved != NULL) { - err = GRPC_CALL_ERROR; - } else { - err = call_start_batch(&exec_ctx, call, ops, nops, tag, 0); - } - - grpc_exec_ctx_finish(&exec_ctx); - return err; -} - -grpc_call_error grpc_call_start_batch_and_execute(grpc_exec_ctx *exec_ctx, - grpc_call *call, - const grpc_op *ops, - size_t nops, - grpc_closure *closure) { - return call_start_batch(exec_ctx, call, ops, nops, closure, 1); -} - -void grpc_call_context_set(grpc_call *call, grpc_context_index elem, - void *value, void (*destroy)(void *value)) { - if (call->context[elem].destroy) { - call->context[elem].destroy(call->context[elem].value); - } - call->context[elem].value = value; - call->context[elem].destroy = destroy; -} - -void *grpc_call_context_get(grpc_call *call, grpc_context_index elem) { - return call->context[elem].value; -} - -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; - gpr_mu_unlock(&call->mu); - return grpc_compression_algorithm_for_level(level, accepted_encodings); -} diff --git a/src/core/surface/call.h b/src/core/surface/call.h deleted file mode 100644 index d2edf03d45..0000000000 --- a/src/core/surface/call.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * - * Copyright 2015-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_SURFACE_CALL_H -#define GRPC_CORE_SURFACE_CALL_H - -#include "src/core/channel/channel_stack.h" -#include "src/core/channel/context.h" -#include "src/core/surface/api_trace.h" -#include "src/core/surface/surface_trace.h" - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void (*grpc_ioreq_completion_func)(grpc_exec_ctx *exec_ctx, - grpc_call *call, int success, - void *user_data); - -grpc_call *grpc_call_create(grpc_channel *channel, grpc_call *parent_call, - uint32_t propagation_mask, - grpc_completion_queue *cq, - const void *server_transport_data, - grpc_mdelem **add_initial_metadata, - size_t add_initial_metadata_count, - gpr_timespec send_deadline); - -void grpc_call_set_completion_queue(grpc_exec_ctx *exec_ctx, grpc_call *call, - grpc_completion_queue *cq); - -#ifdef GRPC_STREAM_REFCOUNT_DEBUG -void grpc_call_internal_ref(grpc_call *call, const char *reason); -void grpc_call_internal_unref(grpc_exec_ctx *exec_ctx, grpc_call *call, - const char *reason); -#define GRPC_CALL_INTERNAL_REF(call, reason) \ - grpc_call_internal_ref(call, reason) -#define GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, reason) \ - grpc_call_internal_unref(exec_ctx, call, reason) -#else -void grpc_call_internal_ref(grpc_call *call); -void grpc_call_internal_unref(grpc_exec_ctx *exec_ctx, grpc_call *call); -#define GRPC_CALL_INTERNAL_REF(call, reason) grpc_call_internal_ref(call) -#define GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, reason) \ - grpc_call_internal_unref(exec_ctx, call) -#endif - -grpc_call_stack *grpc_call_get_call_stack(grpc_call *call); - -grpc_call_error grpc_call_start_batch_and_execute(grpc_exec_ctx *exec_ctx, - grpc_call *call, - const grpc_op *ops, - size_t nops, - grpc_closure *closure); - -/* Given the top call_element, get the call object. */ -grpc_call *grpc_call_from_top_element(grpc_call_element *surface_element); - -void grpc_call_log_batch(char *file, int line, gpr_log_severity severity, - grpc_call *call, const grpc_op *ops, size_t nops, - void *tag); - -/* Set a context pointer. - No thread safety guarantees are made wrt this value. */ -void grpc_call_context_set(grpc_call *call, grpc_context_index elem, - void *value, void (*destroy)(void *value)); -/* Get a context pointer. */ -void *grpc_call_context_get(grpc_call *call, grpc_context_index elem); - -#define GRPC_CALL_LOG_BATCH(sev, call, ops, nops, tag) \ - if (grpc_api_trace) grpc_call_log_batch(sev, call, ops, nops, tag) - -uint8_t grpc_call_is_client(grpc_call *call); - -/* Return an appropriate compression algorithm for the requested compression \a - * level in the context of \a call. */ -grpc_compression_algorithm grpc_call_compression_for_level( - grpc_call *call, grpc_compression_level level); - -#ifdef __cplusplus -} -#endif - -#endif /* GRPC_CORE_SURFACE_CALL_H */ diff --git a/src/core/surface/call_details.c b/src/core/surface/call_details.c deleted file mode 100644 index 60f0029819..0000000000 --- a/src/core/surface/call_details.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include -#include - -#include - -#include "src/core/surface/api_trace.h" - -void grpc_call_details_init(grpc_call_details* cd) { - GRPC_API_TRACE("grpc_call_details_init(cd=%p)", 1, (cd)); - memset(cd, 0, sizeof(*cd)); -} - -void grpc_call_details_destroy(grpc_call_details* cd) { - GRPC_API_TRACE("grpc_call_details_destroy(cd=%p)", 1, (cd)); - gpr_free(cd->method); - gpr_free(cd->host); -} diff --git a/src/core/surface/call_log_batch.c b/src/core/surface/call_log_batch.c deleted file mode 100644 index 044211616c..0000000000 --- a/src/core/surface/call_log_batch.c +++ /dev/null @@ -1,118 +0,0 @@ -/* - * - * Copyright 2015-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/surface/call.h" - -#include -#include -#include "src/core/support/string.h" - -static void add_metadata(gpr_strvec *b, const grpc_metadata *md, size_t count) { - size_t i; - for (i = 0; i < count; i++) { - gpr_strvec_add(b, gpr_strdup("\nkey=")); - gpr_strvec_add(b, gpr_strdup(md[i].key)); - - gpr_strvec_add(b, gpr_strdup(" value=")); - gpr_strvec_add(b, gpr_dump(md[i].value, md[i].value_length, - GPR_DUMP_HEX | GPR_DUMP_ASCII)); - } -} - -char *grpc_op_string(const grpc_op *op) { - char *tmp; - char *out; - - gpr_strvec b; - gpr_strvec_init(&b); - - switch (op->op) { - case GRPC_OP_SEND_INITIAL_METADATA: - gpr_strvec_add(&b, gpr_strdup("SEND_INITIAL_METADATA")); - add_metadata(&b, op->data.send_initial_metadata.metadata, - op->data.send_initial_metadata.count); - break; - case GRPC_OP_SEND_MESSAGE: - gpr_asprintf(&tmp, "SEND_MESSAGE ptr=%p", op->data.send_message); - gpr_strvec_add(&b, tmp); - break; - case GRPC_OP_SEND_CLOSE_FROM_CLIENT: - gpr_strvec_add(&b, gpr_strdup("SEND_CLOSE_FROM_CLIENT")); - break; - case GRPC_OP_SEND_STATUS_FROM_SERVER: - gpr_asprintf(&tmp, "SEND_STATUS_FROM_SERVER status=%d details=%s", - op->data.send_status_from_server.status, - op->data.send_status_from_server.status_details); - gpr_strvec_add(&b, tmp); - add_metadata(&b, op->data.send_status_from_server.trailing_metadata, - op->data.send_status_from_server.trailing_metadata_count); - break; - case GRPC_OP_RECV_INITIAL_METADATA: - gpr_asprintf(&tmp, "RECV_INITIAL_METADATA ptr=%p", - op->data.recv_initial_metadata); - gpr_strvec_add(&b, tmp); - break; - case GRPC_OP_RECV_MESSAGE: - gpr_asprintf(&tmp, "RECV_MESSAGE ptr=%p", op->data.recv_message); - gpr_strvec_add(&b, tmp); - break; - case GRPC_OP_RECV_STATUS_ON_CLIENT: - gpr_asprintf(&tmp, - "RECV_STATUS_ON_CLIENT metadata=%p status=%p details=%p", - op->data.recv_status_on_client.trailing_metadata, - op->data.recv_status_on_client.status, - op->data.recv_status_on_client.status_details); - gpr_strvec_add(&b, tmp); - break; - case GRPC_OP_RECV_CLOSE_ON_SERVER: - gpr_asprintf(&tmp, "RECV_CLOSE_ON_SERVER cancelled=%p", - op->data.recv_close_on_server.cancelled); - gpr_strvec_add(&b, tmp); - } - out = gpr_strvec_flatten(&b, NULL); - gpr_strvec_destroy(&b); - - return out; -} - -void grpc_call_log_batch(char *file, int line, gpr_log_severity severity, - grpc_call *call, const grpc_op *ops, size_t nops, - void *tag) { - char *tmp; - size_t i; - for (i = 0; i < nops; i++) { - tmp = grpc_op_string(&ops[i]); - gpr_log(file, line, severity, "ops[%d]: %s", i, tmp); - gpr_free(tmp); - } -} diff --git a/src/core/surface/call_test_only.h b/src/core/surface/call_test_only.h deleted file mode 100644 index fdc43a383b..0000000000 --- a/src/core/surface/call_test_only.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * - * Copyright 2015-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_SURFACE_CALL_TEST_ONLY_H -#define GRPC_CORE_SURFACE_CALL_TEST_ONLY_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** Return the compression algorithm from \a call. - * - * \warning This function should \b only be used in test code. */ -grpc_compression_algorithm grpc_call_test_only_get_compression_algorithm( - grpc_call *call); - -/** Return the message flags from \a call. - * - * \warning This function should \b only be used in test code. */ -uint32_t grpc_call_test_only_get_message_flags(grpc_call *call); - -/** Returns a bitset for the encodings (compression algorithms) supported by \a - * call's peer. - * - * To be indexed by grpc_compression_algorithm enum values. */ -uint32_t grpc_call_test_only_get_encodings_accepted_by_peer(grpc_call *call); - -#ifdef __cplusplus -} -#endif - -#endif /* GRPC_CORE_SURFACE_CALL_TEST_ONLY_H */ diff --git a/src/core/surface/channel.c b/src/core/surface/channel.c deleted file mode 100644 index 0010b64c7d..0000000000 --- a/src/core/surface/channel.c +++ /dev/null @@ -1,324 +0,0 @@ -/* - * - * Copyright 2015-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/surface/channel.h" - -#include -#include - -#include -#include -#include - -#include "src/core/client_config/resolver_registry.h" -#include "src/core/iomgr/iomgr.h" -#include "src/core/support/string.h" -#include "src/core/surface/api_trace.h" -#include "src/core/surface/call.h" -#include "src/core/surface/channel_init.h" -#include "src/core/surface/init.h" -#include "src/core/transport/static_metadata.h" - -/** Cache grpc-status: X mdelems for X = 0..NUM_CACHED_STATUS_ELEMS. - * Avoids needing to take a metadata context lock for sending status - * if the status code is <= NUM_CACHED_STATUS_ELEMS. - * Sized to allow the most commonly used codes to fit in - * (OK, Cancelled, Unknown). */ -#define NUM_CACHED_STATUS_ELEMS 3 - -typedef struct registered_call { - grpc_mdelem *path; - grpc_mdelem *authority; - struct registered_call *next; -} registered_call; - -struct grpc_channel { - int is_client; - uint32_t max_message_length; - grpc_mdelem *default_authority; - - gpr_mu registered_call_mu; - registered_call *registered_calls; - char *target; -}; - -#define CHANNEL_STACK_FROM_CHANNEL(c) ((grpc_channel_stack *)((c) + 1)) -#define CHANNEL_FROM_CHANNEL_STACK(channel_stack) \ - (((grpc_channel *)(channel_stack)) - 1) -#define CHANNEL_FROM_TOP_ELEM(top_elem) \ - CHANNEL_FROM_CHANNEL_STACK(grpc_channel_stack_from_top_element(top_elem)) - -/* the protobuf library will (by default) start warning at 100megs */ -#define DEFAULT_MAX_MESSAGE_LENGTH (100 * 1024 * 1024) - -static void destroy_channel(grpc_exec_ctx *exec_ctx, void *arg, bool success); - -grpc_channel *grpc_channel_create(grpc_exec_ctx *exec_ctx, const char *target, - const grpc_channel_args *args, - grpc_channel_stack_type channel_stack_type, - grpc_transport *optional_transport) { - bool is_client = grpc_channel_stack_type_is_client(channel_stack_type); - - grpc_channel *channel = grpc_channel_init_create_stack( - exec_ctx, channel_stack_type, sizeof(grpc_channel), args, 1, - destroy_channel, NULL, optional_transport); - - memset(channel, 0, sizeof(*channel)); - channel->target = gpr_strdup(target); - channel->is_client = is_client; - gpr_mu_init(&channel->registered_call_mu); - channel->registered_calls = NULL; - - channel->max_message_length = DEFAULT_MAX_MESSAGE_LENGTH; - if (args) { - for (size_t i = 0; i < args->num_args; i++) { - if (0 == strcmp(args->args[i].key, GRPC_ARG_MAX_MESSAGE_LENGTH)) { - if (args->args[i].type != GRPC_ARG_INTEGER) { - gpr_log(GPR_ERROR, "%s ignored: it must be an integer", - GRPC_ARG_MAX_MESSAGE_LENGTH); - } else if (args->args[i].value.integer < 0) { - gpr_log(GPR_ERROR, "%s ignored: it must be >= 0", - GRPC_ARG_MAX_MESSAGE_LENGTH); - } else { - channel->max_message_length = (uint32_t)args->args[i].value.integer; - } - } else if (0 == strcmp(args->args[i].key, GRPC_ARG_DEFAULT_AUTHORITY)) { - if (args->args[i].type != GRPC_ARG_STRING) { - gpr_log(GPR_ERROR, "%s ignored: it must be a string", - GRPC_ARG_DEFAULT_AUTHORITY); - } else { - if (channel->default_authority) { - /* setting this takes precedence over anything else */ - GRPC_MDELEM_UNREF(channel->default_authority); - } - channel->default_authority = grpc_mdelem_from_strings( - ":authority", args->args[i].value.string); - } - } else if (0 == - strcmp(args->args[i].key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG)) { - if (args->args[i].type != GRPC_ARG_STRING) { - gpr_log(GPR_ERROR, "%s ignored: it must be a string", - GRPC_SSL_TARGET_NAME_OVERRIDE_ARG); - } else { - if (channel->default_authority) { - /* other ways of setting this (notably ssl) take precedence */ - gpr_log(GPR_ERROR, - "%s ignored: default host already set some other way", - GRPC_SSL_TARGET_NAME_OVERRIDE_ARG); - } else { - channel->default_authority = grpc_mdelem_from_strings( - ":authority", args->args[i].value.string); - } - } - } - } - } - - if (channel->is_client && channel->default_authority == NULL && - target != NULL) { - char *default_authority = grpc_get_default_authority(target); - if (default_authority) { - channel->default_authority = - grpc_mdelem_from_strings(":authority", default_authority); - } - gpr_free(default_authority); - } - - return channel; -} - -char *grpc_channel_get_target(grpc_channel *channel) { - GRPC_API_TRACE("grpc_channel_get_target(channel=%p)", 1, (channel)); - return gpr_strdup(channel->target); -} - -static grpc_call *grpc_channel_create_call_internal( - grpc_channel *channel, grpc_call *parent_call, uint32_t propagation_mask, - grpc_completion_queue *cq, grpc_mdelem *path_mdelem, - grpc_mdelem *authority_mdelem, gpr_timespec deadline) { - grpc_mdelem *send_metadata[2]; - size_t num_metadata = 0; - - GPR_ASSERT(channel->is_client); - - send_metadata[num_metadata++] = path_mdelem; - if (authority_mdelem != NULL) { - send_metadata[num_metadata++] = authority_mdelem; - } else if (channel->default_authority != NULL) { - send_metadata[num_metadata++] = GRPC_MDELEM_REF(channel->default_authority); - } - - return grpc_call_create(channel, parent_call, propagation_mask, cq, NULL, - send_metadata, num_metadata, deadline); -} - -grpc_call *grpc_channel_create_call(grpc_channel *channel, - grpc_call *parent_call, - uint32_t propagation_mask, - grpc_completion_queue *cq, - const char *method, const char *host, - gpr_timespec deadline, void *reserved) { - GRPC_API_TRACE( - "grpc_channel_create_call(" - "channel=%p, parent_call=%p, propagation_mask=%x, cq=%p, method=%s, " - "host=%s, " - "deadline=gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, " - "reserved=%p)", - 10, (channel, parent_call, (unsigned)propagation_mask, cq, method, host, - (long long)deadline.tv_sec, (int)deadline.tv_nsec, - (int)deadline.clock_type, reserved)); - GPR_ASSERT(!reserved); - return grpc_channel_create_call_internal( - channel, parent_call, propagation_mask, cq, - grpc_mdelem_from_metadata_strings(GRPC_MDSTR_PATH, - grpc_mdstr_from_string(method)), - host ? grpc_mdelem_from_metadata_strings(GRPC_MDSTR_AUTHORITY, - grpc_mdstr_from_string(host)) - : NULL, - deadline); -} - -void *grpc_channel_register_call(grpc_channel *channel, const char *method, - const char *host, void *reserved) { - registered_call *rc = gpr_malloc(sizeof(registered_call)); - GRPC_API_TRACE( - "grpc_channel_register_call(channel=%p, method=%s, host=%s, reserved=%p)", - 4, (channel, method, host, reserved)); - GPR_ASSERT(!reserved); - rc->path = grpc_mdelem_from_metadata_strings(GRPC_MDSTR_PATH, - grpc_mdstr_from_string(method)); - rc->authority = host ? grpc_mdelem_from_metadata_strings( - GRPC_MDSTR_AUTHORITY, grpc_mdstr_from_string(host)) - : NULL; - gpr_mu_lock(&channel->registered_call_mu); - rc->next = channel->registered_calls; - channel->registered_calls = rc; - gpr_mu_unlock(&channel->registered_call_mu); - return rc; -} - -grpc_call *grpc_channel_create_registered_call( - grpc_channel *channel, grpc_call *parent_call, uint32_t propagation_mask, - grpc_completion_queue *completion_queue, void *registered_call_handle, - gpr_timespec deadline, void *reserved) { - registered_call *rc = registered_call_handle; - GRPC_API_TRACE( - "grpc_channel_create_registered_call(" - "channel=%p, parent_call=%p, propagation_mask=%x, completion_queue=%p, " - "registered_call_handle=%p, " - "deadline=gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, " - "reserved=%p)", - 9, (channel, parent_call, (unsigned)propagation_mask, completion_queue, - registered_call_handle, (long long)deadline.tv_sec, - (int)deadline.tv_nsec, (int)deadline.clock_type, reserved)); - GPR_ASSERT(!reserved); - return grpc_channel_create_call_internal( - channel, parent_call, propagation_mask, completion_queue, - GRPC_MDELEM_REF(rc->path), - rc->authority ? GRPC_MDELEM_REF(rc->authority) : NULL, deadline); -} - -#ifdef GRPC_STREAM_REFCOUNT_DEBUG -#define REF_REASON reason -#define REF_ARG , const char *reason -#else -#define REF_REASON "" -#define REF_ARG -#endif -void grpc_channel_internal_ref(grpc_channel *c REF_ARG) { - GRPC_CHANNEL_STACK_REF(CHANNEL_STACK_FROM_CHANNEL(c), REF_REASON); -} - -void grpc_channel_internal_unref(grpc_exec_ctx *exec_ctx, - grpc_channel *c REF_ARG) { - GRPC_CHANNEL_STACK_UNREF(exec_ctx, CHANNEL_STACK_FROM_CHANNEL(c), REF_REASON); -} - -static void destroy_channel(grpc_exec_ctx *exec_ctx, void *arg, - bool iomgr_success) { - grpc_channel *channel = arg; - grpc_channel_stack_destroy(exec_ctx, CHANNEL_STACK_FROM_CHANNEL(channel)); - while (channel->registered_calls) { - registered_call *rc = channel->registered_calls; - channel->registered_calls = rc->next; - GRPC_MDELEM_UNREF(rc->path); - if (rc->authority) { - GRPC_MDELEM_UNREF(rc->authority); - } - gpr_free(rc); - } - if (channel->default_authority != NULL) { - GRPC_MDELEM_UNREF(channel->default_authority); - } - gpr_mu_destroy(&channel->registered_call_mu); - gpr_free(channel->target); - gpr_free(channel); -} - -void grpc_channel_destroy(grpc_channel *channel) { - grpc_transport_op op; - grpc_channel_element *elem; - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - GRPC_API_TRACE("grpc_channel_destroy(channel=%p)", 1, (channel)); - memset(&op, 0, sizeof(op)); - op.disconnect = 1; - elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CHANNEL(channel), 0); - elem->filter->start_transport_op(&exec_ctx, elem, &op); - - GRPC_CHANNEL_INTERNAL_UNREF(&exec_ctx, channel, "channel"); - - grpc_exec_ctx_finish(&exec_ctx); -} - -grpc_channel_stack *grpc_channel_get_channel_stack(grpc_channel *channel) { - return CHANNEL_STACK_FROM_CHANNEL(channel); -} - -grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel, int i) { - char tmp[GPR_LTOA_MIN_BUFSIZE]; - switch (i) { - case 0: - return GRPC_MDELEM_GRPC_STATUS_0; - case 1: - return GRPC_MDELEM_GRPC_STATUS_1; - case 2: - return GRPC_MDELEM_GRPC_STATUS_2; - } - gpr_ltoa(i, tmp); - return grpc_mdelem_from_metadata_strings(GRPC_MDSTR_GRPC_STATUS, - grpc_mdstr_from_string(tmp)); -} - -uint32_t grpc_channel_get_max_message_length(grpc_channel *channel) { - return channel->max_message_length; -} diff --git a/src/core/surface/channel.h b/src/core/surface/channel.h deleted file mode 100644 index 6a803ffe23..0000000000 --- a/src/core/surface/channel.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * - * Copyright 2015-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_SURFACE_CHANNEL_H -#define GRPC_CORE_SURFACE_CHANNEL_H - -#include "src/core/channel/channel_stack.h" -#include "src/core/client_config/subchannel_factory.h" -#include "src/core/surface/channel_stack_type.h" - -grpc_channel *grpc_channel_create(grpc_exec_ctx *exec_ctx, const char *target, - const grpc_channel_args *args, - grpc_channel_stack_type channel_stack_type, - grpc_transport *optional_transport); - -/** Get a (borrowed) pointer to this channels underlying channel stack */ -grpc_channel_stack *grpc_channel_get_channel_stack(grpc_channel *channel); - -/** Get a grpc_mdelem of grpc-status: X where X is the numeric value of - status_code. - - The returned elem is owned by the caller. */ -grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel, - int status_code); -uint32_t grpc_channel_get_max_message_length(grpc_channel *channel); - -#ifdef GRPC_STREAM_REFCOUNT_DEBUG -void grpc_channel_internal_ref(grpc_channel *channel, const char *reason); -void grpc_channel_internal_unref(grpc_exec_ctx *exec_ctx, grpc_channel *channel, - const char *reason); -#define GRPC_CHANNEL_INTERNAL_REF(channel, reason) \ - grpc_channel_internal_ref(channel, reason) -#define GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, channel, reason) \ - grpc_channel_internal_unref(exec_ctx, channel, reason) -#else -void grpc_channel_internal_ref(grpc_channel *channel); -void grpc_channel_internal_unref(grpc_exec_ctx *exec_ctx, - grpc_channel *channel); -#define GRPC_CHANNEL_INTERNAL_REF(channel, reason) \ - grpc_channel_internal_ref(channel) -#define GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, channel, reason) \ - grpc_channel_internal_unref(exec_ctx, channel) -#endif - -#endif /* GRPC_CORE_SURFACE_CHANNEL_H */ diff --git a/src/core/surface/channel_connectivity.c b/src/core/surface/channel_connectivity.c deleted file mode 100644 index 18267939ed..0000000000 --- a/src/core/surface/channel_connectivity.c +++ /dev/null @@ -1,207 +0,0 @@ -/* - * - * Copyright 2015-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/surface/channel.h" - -#include -#include - -#include "src/core/channel/client_channel.h" -#include "src/core/iomgr/timer.h" -#include "src/core/surface/api_trace.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)); - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_connectivity_state state; - GRPC_API_TRACE( - "grpc_channel_check_connectivity_state(channel=%p, try_to_connect=%d)", 2, - (channel, try_to_connect)); - if (client_channel_elem->filter == &grpc_client_channel_filter) { - state = grpc_client_channel_check_connectivity_state( - &exec_ctx, client_channel_elem, try_to_connect); - grpc_exec_ctx_finish(&exec_ctx); - return state; - } - gpr_log(GPR_ERROR, - "grpc_channel_check_connectivity_state called on something that is " - "not a (u)client channel, but '%s'", - client_channel_elem->filter->name); - grpc_exec_ctx_finish(&exec_ctx); - return GRPC_CHANNEL_FATAL_FAILURE; -} - -typedef enum { - WAITING, - CALLING_BACK, - CALLING_BACK_AND_FINISHED, - CALLED_BACK -} callback_phase; - -typedef struct { - gpr_mu mu; - callback_phase phase; - int success; - grpc_closure on_complete; - grpc_timer alarm; - grpc_connectivity_state state; - grpc_completion_queue *cq; - grpc_cq_completion completion_storage; - grpc_channel *channel; - void *tag; -} state_watcher; - -static void delete_state_watcher(grpc_exec_ctx *exec_ctx, state_watcher *w) { - grpc_channel_element *client_channel_elem = grpc_channel_stack_last_element( - grpc_channel_get_channel_stack(w->channel)); - if (client_channel_elem->filter == &grpc_client_channel_filter) { - GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, w->channel, - "watch_channel_connectivity"); - } else { - abort(); - } - gpr_mu_destroy(&w->mu); - gpr_free(w); -} - -static void finished_completion(grpc_exec_ctx *exec_ctx, 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_UNREACHABLE_CODE(return ); - 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(exec_ctx, w); - } -} - -static void partly_done(grpc_exec_ctx *exec_ctx, state_watcher *w, - int due_to_completion) { - int delete = 0; - - if (due_to_completion) { - grpc_timer_cancel(exec_ctx, &w->alarm); - } - - gpr_mu_lock(&w->mu); - if (due_to_completion) { - w->success = 1; - } - switch (w->phase) { - case WAITING: - w->phase = CALLING_BACK; - grpc_cq_end_op(exec_ctx, 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_UNREACHABLE_CODE(return ); - case CALLED_BACK: - delete = 1; - break; - } - gpr_mu_unlock(&w->mu); - - if (delete) { - delete_state_watcher(exec_ctx, w); - } -} - -static void watch_complete(grpc_exec_ctx *exec_ctx, void *pw, bool success) { - partly_done(exec_ctx, pw, 1); -} - -static void timeout_complete(grpc_exec_ctx *exec_ctx, void *pw, bool success) { - partly_done(exec_ctx, pw, 0); -} - -void grpc_channel_watch_connectivity_state( - grpc_channel *channel, grpc_connectivity_state last_observed_state, - gpr_timespec deadline, grpc_completion_queue *cq, void *tag) { - grpc_channel_element *client_channel_elem = - grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel)); - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - state_watcher *w = gpr_malloc(sizeof(*w)); - - GRPC_API_TRACE( - "grpc_channel_watch_connectivity_state(" - "channel=%p, last_observed_state=%d, " - "deadline=gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, " - "cq=%p, tag=%p)", - 7, (channel, (int)last_observed_state, (long long)deadline.tv_sec, - (int)deadline.tv_nsec, (int)deadline.clock_type, cq, tag)); - - grpc_cq_begin_op(cq, tag); - - gpr_mu_init(&w->mu); - grpc_closure_init(&w->on_complete, watch_complete, w); - w->phase = WAITING; - w->state = last_observed_state; - w->success = 0; - w->cq = cq; - w->tag = tag; - w->channel = channel; - - grpc_timer_init(&exec_ctx, &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) { - GRPC_CHANNEL_INTERNAL_REF(channel, "watch_channel_connectivity"); - grpc_client_channel_watch_connectivity_state(&exec_ctx, client_channel_elem, - grpc_cq_pollset(cq), &w->state, - &w->on_complete); - } else { - abort(); - } - - grpc_exec_ctx_finish(&exec_ctx); -} diff --git a/src/core/surface/channel_create.c b/src/core/surface/channel_create.c deleted file mode 100644 index 123447c8ed..0000000000 --- a/src/core/surface/channel_create.c +++ /dev/null @@ -1,223 +0,0 @@ -/* - * - * Copyright 2015-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 - -#include -#include - -#include -#include -#include - -#include "src/core/census/grpc_filter.h" -#include "src/core/channel/channel_args.h" -#include "src/core/channel/client_channel.h" -#include "src/core/channel/compress_filter.h" -#include "src/core/channel/http_client_filter.h" -#include "src/core/client_config/resolver_registry.h" -#include "src/core/iomgr/tcp_client.h" -#include "src/core/surface/api_trace.h" -#include "src/core/surface/channel.h" -#include "src/core/transport/chttp2_transport.h" - -typedef struct { - grpc_connector base; - gpr_refcount refs; - - grpc_closure *notify; - grpc_connect_in_args args; - grpc_connect_out_args *result; - grpc_closure initial_string_sent; - gpr_slice_buffer initial_string_buffer; - - grpc_endpoint *tcp; - - grpc_closure connected; -} connector; - -static void connector_ref(grpc_connector *con) { - connector *c = (connector *)con; - gpr_ref(&c->refs); -} - -static void connector_unref(grpc_exec_ctx *exec_ctx, grpc_connector *con) { - connector *c = (connector *)con; - if (gpr_unref(&c->refs)) { - /* c->initial_string_buffer does not need to be destroyed */ - gpr_free(c); - } -} - -static void on_initial_connect_string_sent(grpc_exec_ctx *exec_ctx, void *arg, - bool success) { - connector_unref(exec_ctx, arg); -} - -static void connected(grpc_exec_ctx *exec_ctx, void *arg, bool success) { - connector *c = arg; - grpc_closure *notify; - grpc_endpoint *tcp = c->tcp; - if (tcp != NULL) { - if (!GPR_SLICE_IS_EMPTY(c->args.initial_connect_string)) { - grpc_closure_init(&c->initial_string_sent, on_initial_connect_string_sent, - c); - gpr_slice_buffer_init(&c->initial_string_buffer); - gpr_slice_buffer_add(&c->initial_string_buffer, - c->args.initial_connect_string); - connector_ref(arg); - grpc_endpoint_write(exec_ctx, tcp, &c->initial_string_buffer, - &c->initial_string_sent); - } - c->result->transport = - grpc_create_chttp2_transport(exec_ctx, c->args.channel_args, tcp, 1); - grpc_chttp2_transport_start_reading(exec_ctx, c->result->transport, NULL, - 0); - GPR_ASSERT(c->result->transport); - c->result->channel_args = c->args.channel_args; - } else { - memset(c->result, 0, sizeof(*c->result)); - } - notify = c->notify; - c->notify = NULL; - notify->cb(exec_ctx, notify->cb_arg, 1); -} - -static void connector_shutdown(grpc_exec_ctx *exec_ctx, grpc_connector *con) {} - -static void connector_connect(grpc_exec_ctx *exec_ctx, grpc_connector *con, - const grpc_connect_in_args *args, - grpc_connect_out_args *result, - grpc_closure *notify) { - connector *c = (connector *)con; - GPR_ASSERT(c->notify == NULL); - GPR_ASSERT(notify->cb); - c->notify = notify; - c->args = *args; - c->result = result; - c->tcp = NULL; - grpc_closure_init(&c->connected, connected, c); - grpc_tcp_client_connect(exec_ctx, &c->connected, &c->tcp, - args->interested_parties, args->addr, args->addr_len, - args->deadline); -} - -static const grpc_connector_vtable connector_vtable = { - connector_ref, connector_unref, connector_shutdown, connector_connect}; - -typedef struct { - grpc_subchannel_factory base; - gpr_refcount refs; - grpc_channel_args *merge_args; - grpc_channel *master; -} subchannel_factory; - -static void subchannel_factory_ref(grpc_subchannel_factory *scf) { - subchannel_factory *f = (subchannel_factory *)scf; - gpr_ref(&f->refs); -} - -static void subchannel_factory_unref(grpc_exec_ctx *exec_ctx, - grpc_subchannel_factory *scf) { - subchannel_factory *f = (subchannel_factory *)scf; - if (gpr_unref(&f->refs)) { - GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, f->master, "subchannel_factory"); - grpc_channel_args_destroy(f->merge_args); - gpr_free(f); - } -} - -static grpc_subchannel *subchannel_factory_create_subchannel( - grpc_exec_ctx *exec_ctx, grpc_subchannel_factory *scf, - grpc_subchannel_args *args) { - subchannel_factory *f = (subchannel_factory *)scf; - connector *c = gpr_malloc(sizeof(*c)); - grpc_channel_args *final_args = - grpc_channel_args_merge(args->args, f->merge_args); - grpc_subchannel *s; - memset(c, 0, sizeof(*c)); - c->base.vtable = &connector_vtable; - gpr_ref_init(&c->refs, 1); - args->args = final_args; - s = grpc_subchannel_create(exec_ctx, &c->base, args); - grpc_connector_unref(exec_ctx, &c->base); - grpc_channel_args_destroy(final_args); - return s; -} - -static const grpc_subchannel_factory_vtable subchannel_factory_vtable = { - subchannel_factory_ref, subchannel_factory_unref, - subchannel_factory_create_subchannel}; - -/* Create a client channel: - Asynchronously: - resolve target - - connect to it (trying alternatives as presented) - - perform handshakes */ -grpc_channel *grpc_insecure_channel_create(const char *target, - const grpc_channel_args *args, - void *reserved) { - grpc_channel *channel = NULL; - grpc_resolver *resolver; - subchannel_factory *f; - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - GRPC_API_TRACE( - "grpc_insecure_channel_create(target=%p, args=%p, reserved=%p)", 3, - (target, args, reserved)); - GPR_ASSERT(!reserved); - - channel = - grpc_channel_create(&exec_ctx, target, args, GRPC_CLIENT_CHANNEL, NULL); - - f = gpr_malloc(sizeof(*f)); - f->base.vtable = &subchannel_factory_vtable; - gpr_ref_init(&f->refs, 1); - 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) { - GRPC_CHANNEL_INTERNAL_UNREF(&exec_ctx, f->master, "subchannel_factory"); - grpc_subchannel_factory_unref(&exec_ctx, &f->base); - grpc_exec_ctx_finish(&exec_ctx); - return NULL; - } - - grpc_client_channel_set_resolver( - &exec_ctx, grpc_channel_get_channel_stack(channel), resolver); - GRPC_RESOLVER_UNREF(&exec_ctx, resolver, "create"); - grpc_subchannel_factory_unref(&exec_ctx, &f->base); - - grpc_exec_ctx_finish(&exec_ctx); - - return channel; -} diff --git a/src/core/surface/channel_init.c b/src/core/surface/channel_init.c deleted file mode 100644 index ac962f3972..0000000000 --- a/src/core/surface/channel_init.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * - * 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/surface/channel_init.h" - -#include -#include - -typedef struct stage_slot { - grpc_channel_init_stage fn; - void *arg; - int priority; - size_t insertion_order; -} stage_slot; - -typedef struct stage_slots { - stage_slot *slots; - size_t num_slots; - size_t cap_slots; -} stage_slots; - -static stage_slots g_slots[GRPC_NUM_CHANNEL_STACK_TYPES]; -static bool g_finalized; - -void grpc_channel_init_init(void) { - for (int i = 0; i < GRPC_NUM_CHANNEL_STACK_TYPES; i++) { - g_slots[i].slots = NULL; - g_slots[i].num_slots = 0; - g_slots[i].cap_slots = 0; - } - g_finalized = false; -} - -void grpc_channel_init_register_stage(grpc_channel_stack_type type, - int priority, - grpc_channel_init_stage stage, - void *stage_arg) { - GPR_ASSERT(!g_finalized); - if (g_slots[type].cap_slots == g_slots[type].num_slots) { - g_slots[type].cap_slots = GPR_MAX(8, 3 * g_slots[type].cap_slots / 2); - g_slots[type].slots = - gpr_realloc(g_slots[type].slots, - g_slots[type].cap_slots * sizeof(*g_slots[type].slots)); - } - stage_slot *s = &g_slots[type].slots[g_slots[type].num_slots++]; - s->insertion_order = g_slots[type].num_slots; - s->priority = priority; - s->fn = stage; - s->arg = stage_arg; -} - -static int compare_slots(const void *a, const void *b) { - const stage_slot *sa = a; - const stage_slot *sb = b; - - int c = GPR_ICMP(sa->priority, sb->priority); - if (c != 0) return c; - return GPR_ICMP(sa->insertion_order, sb->insertion_order); -} - -void grpc_channel_init_finalize(void) { - GPR_ASSERT(!g_finalized); - for (int i = 0; i < GRPC_NUM_CHANNEL_STACK_TYPES; i++) { - qsort(g_slots[i].slots, g_slots[i].num_slots, sizeof(*g_slots[i].slots), - compare_slots); - } - g_finalized = true; -} - -void grpc_channel_init_shutdown(void) { - for (int i = 0; i < GRPC_NUM_CHANNEL_STACK_TYPES; i++) { - gpr_free(g_slots[i].slots); - g_slots[i].slots = (void *)(uintptr_t)0xdeadbeef; - } -} - -static const char *name_for_type(grpc_channel_stack_type type) { - switch (type) { - case GRPC_CLIENT_CHANNEL: - return "CLIENT_CHANNEL"; - case GRPC_CLIENT_SUBCHANNEL: - return "CLIENT_SUBCHANNEL"; - case GRPC_SERVER_CHANNEL: - return "SERVER_CHANNEL"; - case GRPC_CLIENT_LAME_CHANNEL: - return "CLIENT_LAME_CHANNEL"; - case GRPC_CLIENT_DIRECT_CHANNEL: - return "CLIENT_DIRECT_CHANNEL"; - case GRPC_NUM_CHANNEL_STACK_TYPES: - break; - } - GPR_UNREACHABLE_CODE(return "UNKNOWN"); -} - -void *grpc_channel_init_create_stack( - grpc_exec_ctx *exec_ctx, grpc_channel_stack_type type, size_t prefix_bytes, - const grpc_channel_args *args, int initial_refs, grpc_iomgr_cb_func destroy, - void *destroy_arg, grpc_transport *transport) { - GPR_ASSERT(g_finalized); - - grpc_channel_stack_builder *builder = grpc_channel_stack_builder_create(); - grpc_channel_stack_builder_set_name(builder, name_for_type(type)); - grpc_channel_stack_builder_set_channel_arguments(builder, args); - grpc_channel_stack_builder_set_transport(builder, transport); - - for (size_t i = 0; i < g_slots[type].num_slots; i++) { - const stage_slot *slot = &g_slots[type].slots[i]; - if (!slot->fn(builder, slot->arg)) { - grpc_channel_stack_builder_destroy(builder); - return NULL; - } - } - - return grpc_channel_stack_builder_finish(exec_ctx, builder, prefix_bytes, - initial_refs, destroy, destroy_arg); -} diff --git a/src/core/surface/channel_init.h b/src/core/surface/channel_init.h deleted file mode 100644 index 06faef6ddb..0000000000 --- a/src/core/surface/channel_init.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * - * 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_SURFACE_CHANNEL_INIT_H -#define GRPC_CORE_SURFACE_CHANNEL_INIT_H - -#include "src/core/channel/channel_stack_builder.h" -#include "src/core/surface/channel_stack_type.h" -#include "src/core/transport/transport.h" - -/// This module provides a way for plugins (and the grpc core library itself) -/// to register mutators for channel stacks. -/// It also provides a universal entry path to run those mutators to build -/// a channel stack for various subsystems. - -/// One stage of mutation: call functions against \a builder to influence the -/// finally constructed channel stack -typedef bool (*grpc_channel_init_stage)(grpc_channel_stack_builder *builder, - void *arg); - -/// Global initialization of the system -void grpc_channel_init_init(void); - -/// Register one stage of mutators. -/// Stages are run in priority order (lowest to highest), and then in -/// registration order (in the case of a tie). -/// Stages are registered against one of the pre-determined channel stack -/// types. -void grpc_channel_init_register_stage(grpc_channel_stack_type type, - int priority, - grpc_channel_init_stage stage_fn, - void *stage_arg); - -/// Finalize registration. No more calls to grpc_channel_init_register_stage are -/// allowed. -void grpc_channel_init_finalize(void); -/// Shutdown the channel init system -void grpc_channel_init_shutdown(void); - -/// Construct a channel stack of some sort: see channel_stack.h for details -/// \a type is the type of channel stack to create -/// \a prefix_bytes is the number of bytes before the channel stack to allocate -/// \a args are configuration arguments for the channel stack -/// \a initial_refs is the initial refcount to give the channel stack -/// \a destroy and \a destroy_arg specify how to destroy the channel stack -/// if destroy_arg is NULL, the returned value from this function will be -/// substituted -/// \a optional_transport is either NULL or a constructed transport object -/// Returns a pointer to the base of the memory allocated (the actual channel -/// stack object will be prefix_bytes past that pointer) -void *grpc_channel_init_create_stack( - grpc_exec_ctx *exec_ctx, grpc_channel_stack_type type, size_t prefix_bytes, - const grpc_channel_args *args, int initial_refs, grpc_iomgr_cb_func destroy, - void *destroy_arg, grpc_transport *optional_transport); - -#endif /* GRPC_CORE_SURFACE_CHANNEL_INIT_H */ diff --git a/src/core/surface/channel_ping.c b/src/core/surface/channel_ping.c deleted file mode 100644 index 983f1c8a66..0000000000 --- a/src/core/surface/channel_ping.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * - * Copyright 2015-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/surface/channel.h" - -#include - -#include -#include - -#include "src/core/surface/api_trace.h" -#include "src/core/surface/completion_queue.h" - -typedef struct { - grpc_closure closure; - void *tag; - grpc_completion_queue *cq; - grpc_cq_completion completion_storage; -} ping_result; - -static void ping_destroy(grpc_exec_ctx *exec_ctx, void *arg, - grpc_cq_completion *storage) { - gpr_free(arg); -} - -static void ping_done(grpc_exec_ctx *exec_ctx, void *arg, bool success) { - ping_result *pr = arg; - grpc_cq_end_op(exec_ctx, pr->cq, pr->tag, success, ping_destroy, pr, - &pr->completion_storage); -} - -void grpc_channel_ping(grpc_channel *channel, grpc_completion_queue *cq, - void *tag, void *reserved) { - grpc_transport_op op; - ping_result *pr = gpr_malloc(sizeof(*pr)); - grpc_channel_element *top_elem = - grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0); - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - GPR_ASSERT(reserved == NULL); - memset(&op, 0, sizeof(op)); - pr->tag = tag; - pr->cq = cq; - grpc_closure_init(&pr->closure, ping_done, pr); - op.send_ping = &pr->closure; - op.bind_pollset = grpc_cq_pollset(cq); - grpc_cq_begin_op(cq, tag); - top_elem->filter->start_transport_op(&exec_ctx, top_elem, &op); - grpc_exec_ctx_finish(&exec_ctx); -} diff --git a/src/core/surface/channel_stack_type.c b/src/core/surface/channel_stack_type.c deleted file mode 100644 index 1a6e949ffe..0000000000 --- a/src/core/surface/channel_stack_type.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * - * 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/surface/channel_stack_type.h" -#include -#include - -bool grpc_channel_stack_type_is_client(grpc_channel_stack_type type) { - switch (type) { - case GRPC_CLIENT_CHANNEL: - return true; - case GRPC_CLIENT_SUBCHANNEL: - return true; - case GRPC_CLIENT_LAME_CHANNEL: - return true; - case GRPC_CLIENT_DIRECT_CHANNEL: - return true; - case GRPC_SERVER_CHANNEL: - return false; - case GRPC_NUM_CHANNEL_STACK_TYPES: - break; - } - GPR_UNREACHABLE_CODE(return true;); -} diff --git a/src/core/surface/channel_stack_type.h b/src/core/surface/channel_stack_type.h deleted file mode 100644 index 75a1b9c072..0000000000 --- a/src/core/surface/channel_stack_type.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * - * Copyright 2015-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_SURFACE_CHANNEL_STACK_TYPE_H -#define GRPC_CORE_SURFACE_CHANNEL_STACK_TYPE_H - -#include - -typedef enum { - // normal top-half client channel with load-balancing, connection management - GRPC_CLIENT_CHANNEL, - // bottom-half of a client channel: everything that happens post-load - // balancing (bound to a specific transport) - GRPC_CLIENT_SUBCHANNEL, - // a permanently broken client channel - GRPC_CLIENT_LAME_CHANNEL, - // a directly connected client channel (without load-balancing, directly talks - // to a transport) - GRPC_CLIENT_DIRECT_CHANNEL, - // server side channel - GRPC_SERVER_CHANNEL, - // must be last - GRPC_NUM_CHANNEL_STACK_TYPES -} grpc_channel_stack_type; - -bool grpc_channel_stack_type_is_client(grpc_channel_stack_type type); - -#endif /* GRPC_CORE_SURFACE_CHANNEL_STACK_TYPE_H */ diff --git a/src/core/surface/completion_queue.c b/src/core/surface/completion_queue.c deleted file mode 100644 index b22818ea87..0000000000 --- a/src/core/surface/completion_queue.c +++ /dev/null @@ -1,512 +0,0 @@ -/* - * - * Copyright 2015-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/surface/completion_queue.h" - -#include -#include - -#include -#include -#include -#include - -#include "src/core/iomgr/pollset.h" -#include "src/core/iomgr/timer.h" -#include "src/core/profiling/timers.h" -#include "src/core/support/string.h" -#include "src/core/surface/api_trace.h" -#include "src/core/surface/call.h" -#include "src/core/surface/event_string.h" -#include "src/core/surface/surface_trace.h" - -typedef struct { - grpc_pollset_worker **worker; - void *tag; -} plucker; - -/* Completion queue structure */ -struct grpc_completion_queue { - /** owned by pollset */ - gpr_mu *mu; - /** completed events */ - grpc_cq_completion completed_head; - grpc_cq_completion *completed_tail; - /** Number of pending events (+1 if we're not shutdown) */ - gpr_refcount pending_events; - /** Once owning_refs drops to zero, we will destroy the cq */ - gpr_refcount owning_refs; - /** 0 initially, 1 once we've begun shutting down */ - int shutdown; - int shutdown_called; - int is_server_cq; - int num_pluckers; - plucker pluckers[GRPC_MAX_COMPLETION_QUEUE_PLUCKERS]; - grpc_closure pollset_shutdown_done; - -#ifndef NDEBUG - void **outstanding_tags; - size_t outstanding_tag_count; - size_t outstanding_tag_capacity; -#endif - - grpc_completion_queue *next_free; -}; - -#define POLLSET_FROM_CQ(cq) ((grpc_pollset *)(cq + 1)) - -static gpr_mu g_freelist_mu; -static grpc_completion_queue *g_freelist; - -static void on_pollset_shutdown_done(grpc_exec_ctx *exec_ctx, void *cc, - bool success); - -void grpc_cq_global_init(void) { gpr_mu_init(&g_freelist_mu); } - -void grpc_cq_global_shutdown(void) { - gpr_mu_destroy(&g_freelist_mu); - while (g_freelist) { - grpc_completion_queue *next = g_freelist->next_free; - grpc_pollset_destroy(POLLSET_FROM_CQ(g_freelist)); -#ifndef NDEBUG - gpr_free(g_freelist->outstanding_tags); -#endif - gpr_free(g_freelist); - g_freelist = next; - } -} - -struct grpc_cq_alarm { - grpc_timer alarm; - grpc_cq_completion completion; - /** completion queue where events about this alarm will be posted */ - grpc_completion_queue *cq; - /** user supplied tag */ - void *tag; -}; - -grpc_completion_queue *grpc_completion_queue_create(void *reserved) { - grpc_completion_queue *cc; - GPR_ASSERT(!reserved); - - GPR_TIMER_BEGIN("grpc_completion_queue_create", 0); - - GRPC_API_TRACE("grpc_completion_queue_create(reserved=%p)", 1, (reserved)); - - gpr_mu_lock(&g_freelist_mu); - if (g_freelist == NULL) { - gpr_mu_unlock(&g_freelist_mu); - - cc = gpr_malloc(sizeof(grpc_completion_queue) + grpc_pollset_size()); - grpc_pollset_init(POLLSET_FROM_CQ(cc), &cc->mu); -#ifndef NDEBUG - cc->outstanding_tags = NULL; - cc->outstanding_tag_capacity = 0; -#endif - } else { - cc = g_freelist; - g_freelist = g_freelist->next_free; - gpr_mu_unlock(&g_freelist_mu); - /* pollset already initialized */ - } - - /* Initial ref is dropped by grpc_completion_queue_shutdown */ - gpr_ref_init(&cc->pending_events, 1); - /* One for destroy(), one for pollset_shutdown */ - gpr_ref_init(&cc->owning_refs, 2); - cc->completed_tail = &cc->completed_head; - cc->completed_head.next = (uintptr_t)cc->completed_tail; - cc->shutdown = 0; - cc->shutdown_called = 0; - cc->is_server_cq = 0; - cc->num_pluckers = 0; -#ifndef NDEBUG - cc->outstanding_tag_count = 0; -#endif - grpc_closure_init(&cc->pollset_shutdown_done, on_pollset_shutdown_done, cc); - - GPR_TIMER_END("grpc_completion_queue_create", 0); - - return cc; -} - -#ifdef GRPC_CQ_REF_COUNT_DEBUG -void grpc_cq_internal_ref(grpc_completion_queue *cc, const char *reason, - const char *file, int line) { - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "CQ:%p ref %d -> %d %s", cc, - (int)cc->owning_refs.count, (int)cc->owning_refs.count + 1, reason); -#else -void grpc_cq_internal_ref(grpc_completion_queue *cc) { -#endif - gpr_ref(&cc->owning_refs); -} - -static void on_pollset_shutdown_done(grpc_exec_ctx *exec_ctx, void *arg, - bool success) { - grpc_completion_queue *cc = arg; - GRPC_CQ_INTERNAL_UNREF(cc, "pollset_destroy"); -} - -#ifdef GRPC_CQ_REF_COUNT_DEBUG -void grpc_cq_internal_unref(grpc_completion_queue *cc, const char *reason, - const char *file, int line) { - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "CQ:%p unref %d -> %d %s", cc, - (int)cc->owning_refs.count, (int)cc->owning_refs.count - 1, reason); -#else -void grpc_cq_internal_unref(grpc_completion_queue *cc) { -#endif - if (gpr_unref(&cc->owning_refs)) { - GPR_ASSERT(cc->completed_head.next == (uintptr_t)&cc->completed_head); - grpc_pollset_reset(POLLSET_FROM_CQ(cc)); - gpr_mu_lock(&g_freelist_mu); - cc->next_free = g_freelist; - g_freelist = cc; - gpr_mu_unlock(&g_freelist_mu); - } -} - -void grpc_cq_begin_op(grpc_completion_queue *cc, void *tag) { -#ifndef NDEBUG - gpr_mu_lock(cc->mu); - GPR_ASSERT(!cc->shutdown_called); - if (cc->outstanding_tag_count == cc->outstanding_tag_capacity) { - cc->outstanding_tag_capacity = GPR_MAX(4, 2 * cc->outstanding_tag_capacity); - cc->outstanding_tags = - gpr_realloc(cc->outstanding_tags, sizeof(*cc->outstanding_tags) * - cc->outstanding_tag_capacity); - } - cc->outstanding_tags[cc->outstanding_tag_count++] = tag; - gpr_mu_unlock(cc->mu); -#endif - gpr_ref(&cc->pending_events); -} - -/* Signal the end of an operation - if this is the last waiting-to-be-queued - event, then enter shutdown mode */ -/* Queue a GRPC_OP_COMPLETED operation */ -void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc, - void *tag, int success, - void (*done)(grpc_exec_ctx *exec_ctx, void *done_arg, - grpc_cq_completion *storage), - void *done_arg, grpc_cq_completion *storage) { - int shutdown; - int i; - grpc_pollset_worker *pluck_worker; -#ifndef NDEBUG - int found = 0; -#endif - - GPR_TIMER_BEGIN("grpc_cq_end_op", 0); - - storage->tag = tag; - storage->done = done; - storage->done_arg = done_arg; - storage->next = - ((uintptr_t)&cc->completed_head) | ((uintptr_t)(success != 0)); - - gpr_mu_lock(cc->mu); -#ifndef NDEBUG - for (i = 0; i < (int)cc->outstanding_tag_count; i++) { - if (cc->outstanding_tags[i] == tag) { - cc->outstanding_tag_count--; - GPR_SWAP(void *, cc->outstanding_tags[i], - cc->outstanding_tags[cc->outstanding_tag_count]); - found = 1; - break; - } - } - GPR_ASSERT(found); -#endif - shutdown = gpr_unref(&cc->pending_events); - if (!shutdown) { - cc->completed_tail->next = - ((uintptr_t)storage) | (1u & (uintptr_t)cc->completed_tail->next); - cc->completed_tail = storage; - pluck_worker = NULL; - for (i = 0; i < cc->num_pluckers; i++) { - if (cc->pluckers[i].tag == tag) { - pluck_worker = *cc->pluckers[i].worker; - break; - } - } - grpc_pollset_kick(POLLSET_FROM_CQ(cc), pluck_worker); - gpr_mu_unlock(cc->mu); - } else { - cc->completed_tail->next = - ((uintptr_t)storage) | (1u & (uintptr_t)cc->completed_tail->next); - cc->completed_tail = storage; - GPR_ASSERT(!cc->shutdown); - GPR_ASSERT(cc->shutdown_called); - cc->shutdown = 1; - grpc_pollset_shutdown(exec_ctx, POLLSET_FROM_CQ(cc), - &cc->pollset_shutdown_done); - gpr_mu_unlock(cc->mu); - } - - GPR_TIMER_END("grpc_cq_end_op", 0); -} - -grpc_event grpc_completion_queue_next(grpc_completion_queue *cc, - gpr_timespec deadline, void *reserved) { - grpc_event ret; - grpc_pollset_worker *worker = NULL; - int first_loop = 1; - gpr_timespec now; - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - - GPR_TIMER_BEGIN("grpc_completion_queue_next", 0); - - GRPC_API_TRACE( - "grpc_completion_queue_next(" - "cc=%p, " - "deadline=gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, " - "reserved=%p)", - 5, (cc, (long long)deadline.tv_sec, (int)deadline.tv_nsec, - (int)deadline.clock_type, reserved)); - GPR_ASSERT(!reserved); - - deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC); - - GRPC_CQ_INTERNAL_REF(cc, "next"); - gpr_mu_lock(cc->mu); - for (;;) { - if (cc->completed_tail != &cc->completed_head) { - grpc_cq_completion *c = (grpc_cq_completion *)cc->completed_head.next; - cc->completed_head.next = c->next & ~(uintptr_t)1; - if (c == cc->completed_tail) { - cc->completed_tail = &cc->completed_head; - } - gpr_mu_unlock(cc->mu); - ret.type = GRPC_OP_COMPLETE; - ret.success = c->next & 1u; - ret.tag = c->tag; - c->done(&exec_ctx, c->done_arg, c); - break; - } - if (cc->shutdown) { - gpr_mu_unlock(cc->mu); - memset(&ret, 0, sizeof(ret)); - ret.type = GRPC_QUEUE_SHUTDOWN; - break; - } - now = gpr_now(GPR_CLOCK_MONOTONIC); - if (!first_loop && gpr_time_cmp(now, deadline) >= 0) { - gpr_mu_unlock(cc->mu); - memset(&ret, 0, sizeof(ret)); - ret.type = GRPC_QUEUE_TIMEOUT; - break; - } - first_loop = 0; - /* Check alarms - these are a global resource so we just ping - each time through on every pollset. - May update deadline to ensure timely wakeups. - TODO(ctiller): can this work be localized? */ - gpr_timespec iteration_deadline = deadline; - if (grpc_timer_check(&exec_ctx, now, &iteration_deadline)) { - GPR_TIMER_MARK("alarm_triggered", 0); - gpr_mu_unlock(cc->mu); - grpc_exec_ctx_flush(&exec_ctx); - gpr_mu_lock(cc->mu); - continue; - } else { - grpc_pollset_work(&exec_ctx, POLLSET_FROM_CQ(cc), &worker, now, - iteration_deadline); - } - } - GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret); - GRPC_CQ_INTERNAL_UNREF(cc, "next"); - grpc_exec_ctx_finish(&exec_ctx); - - GPR_TIMER_END("grpc_completion_queue_next", 0); - - return ret; -} - -static int add_plucker(grpc_completion_queue *cc, void *tag, - grpc_pollset_worker **worker) { - if (cc->num_pluckers == GRPC_MAX_COMPLETION_QUEUE_PLUCKERS) { - return 0; - } - cc->pluckers[cc->num_pluckers].tag = tag; - cc->pluckers[cc->num_pluckers].worker = worker; - cc->num_pluckers++; - return 1; -} - -static void del_plucker(grpc_completion_queue *cc, void *tag, - grpc_pollset_worker **worker) { - int i; - for (i = 0; i < cc->num_pluckers; i++) { - if (cc->pluckers[i].tag == tag && cc->pluckers[i].worker == worker) { - cc->num_pluckers--; - GPR_SWAP(plucker, cc->pluckers[i], cc->pluckers[cc->num_pluckers]); - return; - } - } - GPR_UNREACHABLE_CODE(return ); -} - -grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag, - gpr_timespec deadline, void *reserved) { - grpc_event ret; - grpc_cq_completion *c; - grpc_cq_completion *prev; - grpc_pollset_worker *worker = NULL; - gpr_timespec now; - int first_loop = 1; - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - - GPR_TIMER_BEGIN("grpc_completion_queue_pluck", 0); - - GRPC_API_TRACE( - "grpc_completion_queue_pluck(" - "cc=%p, tag=%p, " - "deadline=gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, " - "reserved=%p)", - 6, (cc, tag, (long long)deadline.tv_sec, (int)deadline.tv_nsec, - (int)deadline.clock_type, reserved)); - GPR_ASSERT(!reserved); - - deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC); - - GRPC_CQ_INTERNAL_REF(cc, "pluck"); - gpr_mu_lock(cc->mu); - for (;;) { - prev = &cc->completed_head; - while ((c = (grpc_cq_completion *)(prev->next & ~(uintptr_t)1)) != - &cc->completed_head) { - if (c->tag == tag) { - prev->next = (prev->next & (uintptr_t)1) | (c->next & ~(uintptr_t)1); - if (c == cc->completed_tail) { - cc->completed_tail = prev; - } - gpr_mu_unlock(cc->mu); - ret.type = GRPC_OP_COMPLETE; - ret.success = c->next & 1u; - ret.tag = c->tag; - c->done(&exec_ctx, c->done_arg, c); - goto done; - } - prev = c; - } - if (cc->shutdown) { - gpr_mu_unlock(cc->mu); - memset(&ret, 0, sizeof(ret)); - ret.type = GRPC_QUEUE_SHUTDOWN; - break; - } - if (!add_plucker(cc, tag, &worker)) { - gpr_log(GPR_DEBUG, - "Too many outstanding grpc_completion_queue_pluck calls: maximum " - "is %d", - GRPC_MAX_COMPLETION_QUEUE_PLUCKERS); - gpr_mu_unlock(cc->mu); - memset(&ret, 0, sizeof(ret)); - /* TODO(ctiller): should we use a different result here */ - ret.type = GRPC_QUEUE_TIMEOUT; - break; - } - now = gpr_now(GPR_CLOCK_MONOTONIC); - if (!first_loop && gpr_time_cmp(now, deadline) >= 0) { - del_plucker(cc, tag, &worker); - gpr_mu_unlock(cc->mu); - memset(&ret, 0, sizeof(ret)); - ret.type = GRPC_QUEUE_TIMEOUT; - break; - } - first_loop = 0; - /* Check alarms - these are a global resource so we just ping - each time through on every pollset. - May update deadline to ensure timely wakeups. - TODO(ctiller): can this work be localized? */ - gpr_timespec iteration_deadline = deadline; - if (grpc_timer_check(&exec_ctx, now, &iteration_deadline)) { - GPR_TIMER_MARK("alarm_triggered", 0); - gpr_mu_unlock(cc->mu); - grpc_exec_ctx_flush(&exec_ctx); - gpr_mu_lock(cc->mu); - } else { - grpc_pollset_work(&exec_ctx, POLLSET_FROM_CQ(cc), &worker, now, - iteration_deadline); - } - del_plucker(cc, tag, &worker); - } -done: - GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret); - GRPC_CQ_INTERNAL_UNREF(cc, "pluck"); - grpc_exec_ctx_finish(&exec_ctx); - - GPR_TIMER_END("grpc_completion_queue_pluck", 0); - - return ret; -} - -/* Shutdown simply drops a ref that we reserved at creation time; if we drop - to zero here, then enter shutdown mode and wake up any waiters */ -void grpc_completion_queue_shutdown(grpc_completion_queue *cc) { - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - GPR_TIMER_BEGIN("grpc_completion_queue_shutdown", 0); - GRPC_API_TRACE("grpc_completion_queue_shutdown(cc=%p)", 1, (cc)); - gpr_mu_lock(cc->mu); - if (cc->shutdown_called) { - gpr_mu_unlock(cc->mu); - GPR_TIMER_END("grpc_completion_queue_shutdown", 0); - return; - } - cc->shutdown_called = 1; - if (gpr_unref(&cc->pending_events)) { - GPR_ASSERT(!cc->shutdown); - cc->shutdown = 1; - grpc_pollset_shutdown(&exec_ctx, POLLSET_FROM_CQ(cc), - &cc->pollset_shutdown_done); - } - gpr_mu_unlock(cc->mu); - grpc_exec_ctx_finish(&exec_ctx); - GPR_TIMER_END("grpc_completion_queue_shutdown", 0); -} - -void grpc_completion_queue_destroy(grpc_completion_queue *cc) { - GRPC_API_TRACE("grpc_completion_queue_destroy(cc=%p)", 1, (cc)); - GPR_TIMER_BEGIN("grpc_completion_queue_destroy", 0); - grpc_completion_queue_shutdown(cc); - GRPC_CQ_INTERNAL_UNREF(cc, "destroy"); - GPR_TIMER_END("grpc_completion_queue_destroy", 0); -} - -grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cc) { - return POLLSET_FROM_CQ(cc); -} - -void grpc_cq_mark_server_cq(grpc_completion_queue *cc) { cc->is_server_cq = 1; } - -int grpc_cq_is_server_cq(grpc_completion_queue *cc) { return cc->is_server_cq; } diff --git a/src/core/surface/completion_queue.h b/src/core/surface/completion_queue.h deleted file mode 100644 index 213d89c079..0000000000 --- a/src/core/surface/completion_queue.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * - * Copyright 2015-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_SURFACE_COMPLETION_QUEUE_H -#define GRPC_CORE_SURFACE_COMPLETION_QUEUE_H - -/* Internal API for completion queues */ - -#include -#include "src/core/iomgr/pollset.h" - -typedef struct grpc_cq_completion { - /** user supplied tag */ - void *tag; - /** done callback - called when this queue element is no longer - needed by the completion queue */ - void (*done)(grpc_exec_ctx *exec_ctx, void *done_arg, - struct grpc_cq_completion *c); - void *done_arg; - /** next pointer; low bit is used to indicate success or not */ - uintptr_t next; -} grpc_cq_completion; - -#ifdef GRPC_CQ_REF_COUNT_DEBUG -void grpc_cq_internal_ref(grpc_completion_queue *cc, const char *reason, - const char *file, int line); -void grpc_cq_internal_unref(grpc_completion_queue *cc, const char *reason, - const char *file, int line); -#define GRPC_CQ_INTERNAL_REF(cc, reason) \ - grpc_cq_internal_ref(cc, reason, __FILE__, __LINE__) -#define GRPC_CQ_INTERNAL_UNREF(cc, reason) \ - grpc_cq_internal_unref(cc, reason, __FILE__, __LINE__) -#else -void grpc_cq_internal_ref(grpc_completion_queue *cc); -void grpc_cq_internal_unref(grpc_completion_queue *cc); -#define GRPC_CQ_INTERNAL_REF(cc, reason) grpc_cq_internal_ref(cc) -#define GRPC_CQ_INTERNAL_UNREF(cc, reason) grpc_cq_internal_unref(cc) -#endif - -/* Flag that an operation is beginning: the completion channel will not finish - shutdown until a corrensponding grpc_cq_end_* call is made. - \a tag is currently used only in debug builds. */ -void grpc_cq_begin_op(grpc_completion_queue *cc, void *tag); - -/* Queue a GRPC_OP_COMPLETED operation; tag must correspond to the tag passed to - grpc_cq_begin_op */ -void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc, - void *tag, int success, - void (*done)(grpc_exec_ctx *exec_ctx, void *done_arg, - grpc_cq_completion *storage), - void *done_arg, grpc_cq_completion *storage); - -grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cc); - -void grpc_cq_mark_server_cq(grpc_completion_queue *cc); -int grpc_cq_is_server_cq(grpc_completion_queue *cc); - -void grpc_cq_global_init(void); -void grpc_cq_global_shutdown(void); - -#endif /* GRPC_CORE_SURFACE_COMPLETION_QUEUE_H */ diff --git a/src/core/surface/event_string.c b/src/core/surface/event_string.c deleted file mode 100644 index 85a372b9ad..0000000000 --- a/src/core/surface/event_string.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * - * Copyright 2015-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/surface/event_string.h" - -#include - -#include -#include -#include "src/core/support/string.h" - -static void addhdr(gpr_strvec *buf, grpc_event *ev) { - char *tmp; - gpr_asprintf(&tmp, "tag:%p", ev->tag); - gpr_strvec_add(buf, tmp); -} - -static const char *errstr(int success) { return success ? "OK" : "ERROR"; } - -static void adderr(gpr_strvec *buf, int success) { - char *tmp; - gpr_asprintf(&tmp, " %s", errstr(success)); - gpr_strvec_add(buf, tmp); -} - -char *grpc_event_string(grpc_event *ev) { - char *out; - gpr_strvec buf; - - if (ev == NULL) return gpr_strdup("null"); - - gpr_strvec_init(&buf); - - switch (ev->type) { - case GRPC_QUEUE_TIMEOUT: - gpr_strvec_add(&buf, gpr_strdup("QUEUE_TIMEOUT")); - break; - case GRPC_QUEUE_SHUTDOWN: - gpr_strvec_add(&buf, gpr_strdup("QUEUE_SHUTDOWN")); - break; - case GRPC_OP_COMPLETE: - gpr_strvec_add(&buf, gpr_strdup("OP_COMPLETE: ")); - addhdr(&buf, ev); - adderr(&buf, ev->success); - break; - } - - out = gpr_strvec_flatten(&buf, NULL); - gpr_strvec_destroy(&buf); - return out; -} diff --git a/src/core/surface/event_string.h b/src/core/surface/event_string.h deleted file mode 100644 index d0598cecca..0000000000 --- a/src/core/surface/event_string.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * - * Copyright 2015-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_SURFACE_EVENT_STRING_H -#define GRPC_CORE_SURFACE_EVENT_STRING_H - -#include - -/* Returns a string describing an event. Must be later freed with gpr_free() */ -char *grpc_event_string(grpc_event *ev); - -#endif /* GRPC_CORE_SURFACE_EVENT_STRING_H */ diff --git a/src/core/surface/init.c b/src/core/surface/init.c deleted file mode 100644 index 3c4db3e6cc..0000000000 --- a/src/core/surface/init.c +++ /dev/null @@ -1,239 +0,0 @@ -/* - * - * Copyright 2015-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 - -#include -#include - -#include -#include -#include -/* TODO(ctiller): find another way? - better not to include census here */ -#include "src/core/census/grpc_plugin.h" -#include "src/core/channel/channel_stack.h" -#include "src/core/channel/client_channel.h" -#include "src/core/channel/compress_filter.h" -#include "src/core/channel/connected_channel.h" -#include "src/core/channel/http_client_filter.h" -#include "src/core/channel/http_server_filter.h" -#include "src/core/client_config/lb_policies/pick_first.h" -#include "src/core/client_config/lb_policies/round_robin.h" -#include "src/core/client_config/lb_policy_registry.h" -#include "src/core/client_config/resolver_registry.h" -#include "src/core/client_config/resolvers/dns_resolver.h" -#include "src/core/client_config/resolvers/sockaddr_resolver.h" -#include "src/core/client_config/subchannel.h" -#include "src/core/client_config/subchannel_index.h" -#include "src/core/debug/trace.h" -#include "src/core/iomgr/executor.h" -#include "src/core/iomgr/iomgr.h" -#include "src/core/profiling/timers.h" -#include "src/core/surface/api_trace.h" -#include "src/core/surface/call.h" -#include "src/core/surface/channel_init.h" -#include "src/core/surface/completion_queue.h" -#include "src/core/surface/init.h" -#include "src/core/surface/lame_client.h" -#include "src/core/surface/server.h" -#include "src/core/surface/surface_trace.h" -#include "src/core/transport/chttp2_transport.h" -#include "src/core/transport/connectivity_state.h" -#include "src/core/transport/transport_impl.h" - -#ifndef GRPC_DEFAULT_NAME_PREFIX -#define GRPC_DEFAULT_NAME_PREFIX "dns:///" -#endif - -#define MAX_PLUGINS 128 - -static gpr_once g_basic_init = GPR_ONCE_INIT; -static gpr_mu g_init_mu; -static int g_initializations; - -static void do_basic_init(void) { - gpr_mu_init(&g_init_mu); - /* TODO(ctiller): ideally remove this strict linkage */ - grpc_register_plugin(census_grpc_plugin_init, census_grpc_plugin_destroy); - g_initializations = 0; -} - -static bool append_filter(grpc_channel_stack_builder *builder, void *arg) { - return grpc_channel_stack_builder_append_filter( - builder, (const grpc_channel_filter *)arg, NULL, NULL); -} - -static bool prepend_filter(grpc_channel_stack_builder *builder, void *arg) { - return grpc_channel_stack_builder_prepend_filter( - builder, (const grpc_channel_filter *)arg, NULL, NULL); -} - -static bool maybe_add_http_filter(grpc_channel_stack_builder *builder, - void *arg) { - grpc_transport *t = grpc_channel_stack_builder_get_transport(builder); - if (t && strstr(t->vtable->name, "http")) { - return grpc_channel_stack_builder_prepend_filter( - builder, (const grpc_channel_filter *)arg, NULL, NULL); - } - return true; -} - -static void register_builtin_channel_init() { - grpc_channel_init_register_stage(GRPC_CLIENT_CHANNEL, INT_MAX, prepend_filter, - (void *)&grpc_compress_filter); - grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL, INT_MAX, - prepend_filter, - (void *)&grpc_compress_filter); - grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX, prepend_filter, - (void *)&grpc_compress_filter); - grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL, INT_MAX, - maybe_add_http_filter, - (void *)&grpc_http_client_filter); - grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL, INT_MAX, - grpc_add_connected_filter, NULL); - grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL, INT_MAX, - maybe_add_http_filter, - (void *)&grpc_http_client_filter); - grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL, INT_MAX, - grpc_add_connected_filter, NULL); - grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX, - maybe_add_http_filter, - (void *)&grpc_http_server_filter); - grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX, - grpc_add_connected_filter, NULL); - grpc_channel_init_register_stage(GRPC_CLIENT_CHANNEL, INT_MAX, append_filter, - (void *)&grpc_client_channel_filter); - grpc_channel_init_register_stage(GRPC_CLIENT_LAME_CHANNEL, INT_MAX, - append_filter, (void *)&grpc_lame_filter); - grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX, prepend_filter, - (void *)&grpc_server_top_filter); -} - -typedef struct grpc_plugin { - void (*init)(); - void (*destroy)(); -} grpc_plugin; - -static grpc_plugin g_all_of_the_plugins[MAX_PLUGINS]; -static int g_number_of_plugins = 0; - -void grpc_register_plugin(void (*init)(void), void (*destroy)(void)) { - GRPC_API_TRACE("grpc_register_plugin(init=%p, destroy=%p)", 2, - ((void *)(intptr_t)init, (void *)(intptr_t)destroy)); - GPR_ASSERT(g_number_of_plugins != MAX_PLUGINS); - g_all_of_the_plugins[g_number_of_plugins].init = init; - g_all_of_the_plugins[g_number_of_plugins].destroy = destroy; - g_number_of_plugins++; -} - -void grpc_init(void) { - int i; - gpr_once_init(&g_basic_init, do_basic_init); - - gpr_mu_lock(&g_init_mu); - if (++g_initializations == 1) { - gpr_time_init(); - grpc_mdctx_global_init(); - grpc_channel_init_init(); - grpc_lb_policy_registry_init(grpc_pick_first_lb_factory_create()); - grpc_register_lb_policy(grpc_pick_first_lb_factory_create()); - grpc_register_lb_policy(grpc_round_robin_lb_factory_create()); - grpc_resolver_registry_init(GRPC_DEFAULT_NAME_PREFIX); - grpc_register_resolver_type(grpc_dns_resolver_factory_create()); - grpc_register_resolver_type(grpc_ipv4_resolver_factory_create()); - grpc_register_resolver_type(grpc_ipv6_resolver_factory_create()); -#ifdef GPR_POSIX_SOCKET - grpc_register_resolver_type(grpc_unix_resolver_factory_create()); -#endif - grpc_register_tracer("api", &grpc_api_trace); - grpc_register_tracer("channel", &grpc_trace_channel); - grpc_register_tracer("http", &grpc_http_trace); - grpc_register_tracer("flowctl", &grpc_flowctl_trace); - grpc_register_tracer("connectivity_state", &grpc_connectivity_state_trace); - grpc_register_tracer("channel_stack_builder", - &grpc_trace_channel_stack_builder); - grpc_security_pre_init(); - grpc_iomgr_init(); - grpc_executor_init(); - grpc_tracer_init("GRPC_TRACE"); - gpr_timers_global_init(); - grpc_cq_global_init(); - grpc_subchannel_index_init(); - for (i = 0; i < g_number_of_plugins; i++) { - if (g_all_of_the_plugins[i].init != NULL) { - g_all_of_the_plugins[i].init(); - } - } - /* register channel finalization AFTER all plugins, to ensure that it's run - * at the appropriate time */ - grpc_register_security_filters(); - register_builtin_channel_init(); - /* no more changes to channel init pipelines */ - grpc_channel_init_finalize(); - } - gpr_mu_unlock(&g_init_mu); - GRPC_API_TRACE("grpc_init(void)", 0, ()); -} - -void grpc_shutdown(void) { - int i; - GRPC_API_TRACE("grpc_shutdown(void)", 0, ()); - gpr_mu_lock(&g_init_mu); - if (--g_initializations == 0) { - grpc_executor_shutdown(); - grpc_cq_global_shutdown(); - grpc_iomgr_shutdown(); - grpc_subchannel_index_shutdown(); - gpr_timers_global_destroy(); - grpc_tracer_shutdown(); - grpc_resolver_registry_shutdown(); - grpc_lb_policy_registry_shutdown(); - for (i = 0; i < g_number_of_plugins; i++) { - if (g_all_of_the_plugins[i].destroy != NULL) { - g_all_of_the_plugins[i].destroy(); - } - } - grpc_channel_init_shutdown(); - grpc_mdctx_global_shutdown(); - } - gpr_mu_unlock(&g_init_mu); -} - -int grpc_is_initialized(void) { - int r; - gpr_once_init(&g_basic_init, do_basic_init); - gpr_mu_lock(&g_init_mu); - r = g_initializations > 0; - gpr_mu_unlock(&g_init_mu); - return r; -} diff --git a/src/core/surface/init.h b/src/core/surface/init.h deleted file mode 100644 index 5e358c7022..0000000000 --- a/src/core/surface/init.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * - * Copyright 2015-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_SURFACE_INIT_H -#define GRPC_CORE_SURFACE_INIT_H - -void grpc_register_security_filters(void); -void grpc_security_pre_init(void); -int grpc_is_initialized(void); - -#endif /* GRPC_CORE_SURFACE_INIT_H */ diff --git a/src/core/surface/init_secure.c b/src/core/surface/init_secure.c deleted file mode 100644 index e0d66a8d46..0000000000 --- a/src/core/surface/init_secure.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * - * Copyright 2015-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/surface/init.h" - -#include -#include - -#include "src/core/debug/trace.h" -#include "src/core/security/auth_filters.h" -#include "src/core/security/credentials.h" -#include "src/core/security/secure_endpoint.h" -#include "src/core/security/security_connector.h" -#include "src/core/surface/channel_init.h" -#include "src/core/tsi/transport_security_interface.h" - -void grpc_security_pre_init(void) { - grpc_register_tracer("secure_endpoint", &grpc_trace_secure_endpoint); - grpc_register_tracer("transport_security", &tsi_tracing_enabled); -} - -static bool maybe_prepend_client_auth_filter( - grpc_channel_stack_builder *builder, void *arg) { - const grpc_channel_args *args = - grpc_channel_stack_builder_get_channel_arguments(builder); - if (args) { - for (size_t i = 0; i < args->num_args; i++) { - if (0 == strcmp(GRPC_SECURITY_CONNECTOR_ARG, args->args[i].key)) { - return grpc_channel_stack_builder_prepend_filter( - builder, &grpc_client_auth_filter, NULL, NULL); - } - } - } - return true; -} - -static bool maybe_prepend_server_auth_filter( - grpc_channel_stack_builder *builder, void *arg) { - const grpc_channel_args *args = - grpc_channel_stack_builder_get_channel_arguments(builder); - if (args) { - for (size_t i = 0; i < args->num_args; i++) { - if (0 == strcmp(GRPC_SERVER_CREDENTIALS_ARG, args->args[i].key)) { - return grpc_channel_stack_builder_prepend_filter( - builder, &grpc_server_auth_filter, NULL, NULL); - } - } - } - return true; -} - -void grpc_register_security_filters(void) { - grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL, INT_MAX, - maybe_prepend_client_auth_filter, NULL); - grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL, INT_MAX, - maybe_prepend_client_auth_filter, NULL); - grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX, - maybe_prepend_server_auth_filter, NULL); -} diff --git a/src/core/surface/init_unsecure.c b/src/core/surface/init_unsecure.c deleted file mode 100644 index 278fcc83ac..0000000000 --- a/src/core/surface/init_unsecure.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * - * Copyright 2015-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/surface/init.h" - -void grpc_security_pre_init(void) {} - -void grpc_register_security_filters(void) {} diff --git a/src/core/surface/lame_client.c b/src/core/surface/lame_client.c deleted file mode 100644 index 25f3a74349..0000000000 --- a/src/core/surface/lame_client.c +++ /dev/null @@ -1,155 +0,0 @@ -/* - * - * Copyright 2015-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/surface/lame_client.h" - -#include - -#include - -#include -#include -#include "src/core/channel/channel_stack.h" -#include "src/core/support/string.h" -#include "src/core/surface/api_trace.h" -#include "src/core/surface/call.h" -#include "src/core/surface/channel.h" - -typedef struct { - grpc_linked_mdelem status; - grpc_linked_mdelem details; -} call_data; - -typedef struct { - grpc_status_code error_code; - const char *error_message; -} channel_data; - -static void fill_metadata(grpc_call_element *elem, grpc_metadata_batch *mdb) { - call_data *calld = elem->call_data; - channel_data *chand = elem->channel_data; - char tmp[GPR_LTOA_MIN_BUFSIZE]; - gpr_ltoa(chand->error_code, tmp); - calld->status.md = grpc_mdelem_from_strings("grpc-status", tmp); - calld->details.md = - grpc_mdelem_from_strings("grpc-message", chand->error_message); - calld->status.prev = calld->details.next = NULL; - calld->status.next = &calld->details; - calld->details.prev = &calld->status; - mdb->list.head = &calld->status; - mdb->list.tail = &calld->details; - mdb->deadline = gpr_inf_future(GPR_CLOCK_REALTIME); -} - -static void lame_start_transport_stream_op(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_transport_stream_op *op) { - GRPC_CALL_LOG_OP(GPR_INFO, elem, op); - if (op->recv_initial_metadata != NULL) { - fill_metadata(elem, op->recv_initial_metadata); - } else if (op->recv_trailing_metadata != NULL) { - fill_metadata(elem, op->recv_trailing_metadata); - } - grpc_transport_stream_op_finish_with_failure(exec_ctx, op); -} - -static char *lame_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) { - return NULL; -} - -static void lame_start_transport_op(grpc_exec_ctx *exec_ctx, - grpc_channel_element *elem, - grpc_transport_op *op) { - if (op->on_connectivity_state_change) { - GPR_ASSERT(*op->connectivity_state != GRPC_CHANNEL_FATAL_FAILURE); - *op->connectivity_state = GRPC_CHANNEL_FATAL_FAILURE; - op->on_connectivity_state_change->cb( - exec_ctx, op->on_connectivity_state_change->cb_arg, 1); - } - if (op->on_consumed != NULL) { - op->on_consumed->cb(exec_ctx, op->on_consumed->cb_arg, 1); - } -} - -static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_call_element_args *args) {} - -static void destroy_call_elem(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem) {} - -static void init_channel_elem(grpc_exec_ctx *exec_ctx, - grpc_channel_element *elem, - grpc_channel_element_args *args) { - GPR_ASSERT(args->is_first); - GPR_ASSERT(args->is_last); -} - -static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, - grpc_channel_element *elem) {} - -const grpc_channel_filter grpc_lame_filter = { - lame_start_transport_stream_op, - lame_start_transport_op, - sizeof(call_data), - init_call_elem, - grpc_call_stack_ignore_set_pollset, - destroy_call_elem, - sizeof(channel_data), - init_channel_elem, - destroy_channel_elem, - lame_get_peer, - "lame-client", -}; - -#define CHANNEL_STACK_FROM_CHANNEL(c) ((grpc_channel_stack *)((c) + 1)) - -grpc_channel *grpc_lame_client_channel_create(const char *target, - grpc_status_code error_code, - const char *error_message) { - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_channel_element *elem; - channel_data *chand; - grpc_channel *channel = grpc_channel_create(&exec_ctx, target, NULL, - GRPC_CLIENT_LAME_CHANNEL, NULL); - elem = grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0); - GRPC_API_TRACE( - "grpc_lame_client_channel_create(target=%s, error_code=%d, " - "error_message=%s)", - 3, (target, (int)error_code, error_message)); - GPR_ASSERT(elem->filter == &grpc_lame_filter); - chand = (channel_data *)elem->channel_data; - chand->error_code = error_code; - chand->error_message = error_message; - grpc_exec_ctx_finish(&exec_ctx); - return channel; -} diff --git a/src/core/surface/lame_client.h b/src/core/surface/lame_client.h deleted file mode 100644 index 3f3abd2ffe..0000000000 --- a/src/core/surface/lame_client.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * - * 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_SURFACE_LAME_CLIENT_H -#define GRPC_CORE_SURFACE_LAME_CLIENT_H - -#include "src/core/channel/channel_stack.h" - -extern const grpc_channel_filter grpc_lame_filter; - -#endif /* GRPC_CORE_SURFACE_LAME_CLIENT_H */ diff --git a/src/core/surface/metadata_array.c b/src/core/surface/metadata_array.c deleted file mode 100644 index 4c7bf17835..0000000000 --- a/src/core/surface/metadata_array.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include -#include - -#include - -#include "src/core/surface/api_trace.h" - -void grpc_metadata_array_init(grpc_metadata_array* array) { - GRPC_API_TRACE("grpc_metadata_array_init(array=%p)", 1, (array)); - memset(array, 0, sizeof(*array)); -} - -void grpc_metadata_array_destroy(grpc_metadata_array* array) { - GRPC_API_TRACE("grpc_metadata_array_destroy(array=%p)", 1, (array)); - gpr_free(array->metadata); -} diff --git a/src/core/surface/secure_channel_create.c b/src/core/surface/secure_channel_create.c deleted file mode 100644 index cc752227ee..0000000000 --- a/src/core/surface/secure_channel_create.c +++ /dev/null @@ -1,319 +0,0 @@ -/* - * - * Copyright 2015-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 - -#include -#include - -#include -#include -#include - -#include "src/core/channel/channel_args.h" -#include "src/core/channel/client_channel.h" -#include "src/core/client_config/resolver_registry.h" -#include "src/core/iomgr/tcp_client.h" -#include "src/core/security/auth_filters.h" -#include "src/core/security/credentials.h" -#include "src/core/security/security_context.h" -#include "src/core/surface/api_trace.h" -#include "src/core/surface/channel.h" -#include "src/core/transport/chttp2_transport.h" -#include "src/core/tsi/transport_security_interface.h" - -typedef struct { - grpc_connector base; - gpr_refcount refs; - - grpc_channel_security_connector *security_connector; - - grpc_closure *notify; - grpc_connect_in_args args; - grpc_connect_out_args *result; - grpc_closure initial_string_sent; - gpr_slice_buffer initial_string_buffer; - - gpr_mu mu; - grpc_endpoint *connecting_endpoint; - grpc_endpoint *newly_connecting_endpoint; - - grpc_closure connected_closure; -} connector; - -static void connector_ref(grpc_connector *con) { - connector *c = (connector *)con; - gpr_ref(&c->refs); -} - -static void connector_unref(grpc_exec_ctx *exec_ctx, grpc_connector *con) { - connector *c = (connector *)con; - if (gpr_unref(&c->refs)) { - /* c->initial_string_buffer does not need to be destroyed */ - gpr_free(c); - } -} - -static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *arg, - grpc_security_status status, - grpc_endpoint *secure_endpoint, - grpc_auth_context *auth_context) { - connector *c = arg; - grpc_closure *notify; - grpc_channel_args *args_copy = NULL; - gpr_mu_lock(&c->mu); - if (c->connecting_endpoint == NULL) { - memset(c->result, 0, sizeof(*c->result)); - gpr_mu_unlock(&c->mu); - } else if (status != GRPC_SECURITY_OK) { - gpr_log(GPR_ERROR, "Secure handshake failed with error %d.", status); - memset(c->result, 0, sizeof(*c->result)); - c->connecting_endpoint = NULL; - gpr_mu_unlock(&c->mu); - } else { - grpc_arg auth_context_arg; - c->connecting_endpoint = NULL; - gpr_mu_unlock(&c->mu); - c->result->transport = grpc_create_chttp2_transport( - exec_ctx, c->args.channel_args, secure_endpoint, 1); - grpc_chttp2_transport_start_reading(exec_ctx, c->result->transport, NULL, - 0); - auth_context_arg = grpc_auth_context_to_arg(auth_context); - args_copy = grpc_channel_args_copy_and_add(c->args.channel_args, - &auth_context_arg, 1); - c->result->channel_args = args_copy; - } - notify = c->notify; - c->notify = NULL; - /* look at c->args which are connector args. */ - notify->cb(exec_ctx, notify->cb_arg, 1); - if (args_copy != NULL) grpc_channel_args_destroy(args_copy); -} - -static void on_initial_connect_string_sent(grpc_exec_ctx *exec_ctx, void *arg, - bool success) { - connector *c = arg; - grpc_channel_security_connector_do_handshake(exec_ctx, c->security_connector, - c->connecting_endpoint, - on_secure_handshake_done, c); -} - -static void connected(grpc_exec_ctx *exec_ctx, void *arg, bool success) { - connector *c = arg; - grpc_closure *notify; - grpc_endpoint *tcp = c->newly_connecting_endpoint; - if (tcp != NULL) { - gpr_mu_lock(&c->mu); - GPR_ASSERT(c->connecting_endpoint == NULL); - c->connecting_endpoint = tcp; - gpr_mu_unlock(&c->mu); - if (!GPR_SLICE_IS_EMPTY(c->args.initial_connect_string)) { - grpc_closure_init(&c->initial_string_sent, on_initial_connect_string_sent, - c); - gpr_slice_buffer_init(&c->initial_string_buffer); - gpr_slice_buffer_add(&c->initial_string_buffer, - c->args.initial_connect_string); - grpc_endpoint_write(exec_ctx, tcp, &c->initial_string_buffer, - &c->initial_string_sent); - } else { - grpc_channel_security_connector_do_handshake( - exec_ctx, c->security_connector, tcp, on_secure_handshake_done, c); - } - } else { - memset(c->result, 0, sizeof(*c->result)); - notify = c->notify; - c->notify = NULL; - notify->cb(exec_ctx, notify->cb_arg, 1); - } -} - -static void connector_shutdown(grpc_exec_ctx *exec_ctx, grpc_connector *con) { - connector *c = (connector *)con; - grpc_endpoint *ep; - gpr_mu_lock(&c->mu); - ep = c->connecting_endpoint; - c->connecting_endpoint = NULL; - gpr_mu_unlock(&c->mu); - if (ep) { - grpc_endpoint_shutdown(exec_ctx, ep); - } -} - -static void connector_connect(grpc_exec_ctx *exec_ctx, grpc_connector *con, - const grpc_connect_in_args *args, - grpc_connect_out_args *result, - grpc_closure *notify) { - connector *c = (connector *)con; - GPR_ASSERT(c->notify == NULL); - GPR_ASSERT(notify->cb); - c->notify = notify; - c->args = *args; - c->result = result; - gpr_mu_lock(&c->mu); - GPR_ASSERT(c->connecting_endpoint == NULL); - gpr_mu_unlock(&c->mu); - grpc_closure_init(&c->connected_closure, connected, c); - grpc_tcp_client_connect( - exec_ctx, &c->connected_closure, &c->newly_connecting_endpoint, - args->interested_parties, args->addr, args->addr_len, args->deadline); -} - -static const grpc_connector_vtable connector_vtable = { - connector_ref, connector_unref, connector_shutdown, connector_connect}; - -typedef struct { - grpc_subchannel_factory base; - gpr_refcount refs; - grpc_channel_args *merge_args; - grpc_channel_security_connector *security_connector; - grpc_channel *master; -} subchannel_factory; - -static void subchannel_factory_ref(grpc_subchannel_factory *scf) { - subchannel_factory *f = (subchannel_factory *)scf; - gpr_ref(&f->refs); -} - -static void subchannel_factory_unref(grpc_exec_ctx *exec_ctx, - grpc_subchannel_factory *scf) { - subchannel_factory *f = (subchannel_factory *)scf; - if (gpr_unref(&f->refs)) { - GRPC_SECURITY_CONNECTOR_UNREF(&f->security_connector->base, - "subchannel_factory"); - GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, f->master, "subchannel_factory"); - grpc_channel_args_destroy(f->merge_args); - gpr_free(f); - } -} - -static grpc_subchannel *subchannel_factory_create_subchannel( - grpc_exec_ctx *exec_ctx, grpc_subchannel_factory *scf, - grpc_subchannel_args *args) { - subchannel_factory *f = (subchannel_factory *)scf; - connector *c = gpr_malloc(sizeof(*c)); - grpc_channel_args *final_args = - grpc_channel_args_merge(args->args, f->merge_args); - grpc_subchannel *s; - memset(c, 0, sizeof(*c)); - c->base.vtable = &connector_vtable; - c->security_connector = f->security_connector; - gpr_mu_init(&c->mu); - gpr_ref_init(&c->refs, 1); - args->args = final_args; - s = grpc_subchannel_create(exec_ctx, &c->base, args); - grpc_connector_unref(exec_ctx, &c->base); - grpc_channel_args_destroy(final_args); - return s; -} - -static const grpc_subchannel_factory_vtable subchannel_factory_vtable = { - subchannel_factory_ref, subchannel_factory_unref, - subchannel_factory_create_subchannel}; - -/* Create a secure client channel: - Asynchronously: - resolve target - - connect to it (trying alternatives as presented) - - perform handshakes */ -grpc_channel *grpc_secure_channel_create(grpc_channel_credentials *creds, - const char *target, - const grpc_channel_args *args, - void *reserved) { - grpc_channel *channel; - grpc_arg connector_arg; - grpc_channel_args *args_copy; - grpc_channel_args *new_args_from_connector; - grpc_channel_security_connector *security_connector; - grpc_resolver *resolver; - subchannel_factory *f; - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - - GRPC_API_TRACE( - "grpc_secure_channel_create(creds=%p, target=%s, args=%p, " - "reserved=%p)", - 4, (creds, target, args, reserved)); - GPR_ASSERT(reserved == NULL); - - if (grpc_find_security_connector_in_args(args) != NULL) { - gpr_log(GPR_ERROR, "Cannot set security context in channel args."); - grpc_exec_ctx_finish(&exec_ctx); - return grpc_lame_client_channel_create( - target, GRPC_STATUS_INVALID_ARGUMENT, - "Security connector exists in channel args."); - } - - if (grpc_channel_credentials_create_security_connector( - creds, target, args, &security_connector, &new_args_from_connector) != - GRPC_SECURITY_OK) { - grpc_exec_ctx_finish(&exec_ctx); - return grpc_lame_client_channel_create( - target, GRPC_STATUS_INVALID_ARGUMENT, - "Failed to create security connector."); - } - - connector_arg = grpc_security_connector_to_arg(&security_connector->base); - args_copy = grpc_channel_args_copy_and_add( - new_args_from_connector != NULL ? new_args_from_connector : args, - &connector_arg, 1); - - channel = grpc_channel_create(&exec_ctx, target, args_copy, - GRPC_CLIENT_CHANNEL, NULL); - - f = gpr_malloc(sizeof(*f)); - f->base.vtable = &subchannel_factory_vtable; - gpr_ref_init(&f->refs, 1); - GRPC_SECURITY_CONNECTOR_REF(&security_connector->base, "subchannel_factory"); - f->security_connector = security_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) { - grpc_client_channel_set_resolver( - &exec_ctx, grpc_channel_get_channel_stack(channel), resolver); - GRPC_RESOLVER_UNREF(&exec_ctx, resolver, "create"); - } - grpc_subchannel_factory_unref(&exec_ctx, &f->base); - GRPC_SECURITY_CONNECTOR_UNREF(&security_connector->base, "channel_create"); - grpc_channel_args_destroy(args_copy); - if (new_args_from_connector != NULL) { - grpc_channel_args_destroy(new_args_from_connector); - } - - if (!resolver) { - GRPC_CHANNEL_INTERNAL_UNREF(&exec_ctx, channel, "subchannel_factory"); - channel = NULL; - } - grpc_exec_ctx_finish(&exec_ctx); - - return channel; -} diff --git a/src/core/surface/server.c b/src/core/surface/server.c deleted file mode 100644 index a92f2b3e38..0000000000 --- a/src/core/surface/server.c +++ /dev/null @@ -1,1319 +0,0 @@ -/* - * - * Copyright 2015-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/surface/server.h" - -#include -#include -#include - -#include -#include -#include -#include - -#include "src/core/channel/channel_args.h" -#include "src/core/channel/connected_channel.h" -#include "src/core/iomgr/iomgr.h" -#include "src/core/support/stack_lockfree.h" -#include "src/core/support/string.h" -#include "src/core/surface/api_trace.h" -#include "src/core/surface/call.h" -#include "src/core/surface/channel.h" -#include "src/core/surface/completion_queue.h" -#include "src/core/surface/init.h" -#include "src/core/transport/metadata.h" -#include "src/core/transport/static_metadata.h" - -typedef struct listener { - void *arg; - void (*start)(grpc_exec_ctx *exec_ctx, grpc_server *server, void *arg, - grpc_pollset **pollsets, size_t pollset_count); - void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_server *server, void *arg, - grpc_closure *closure); - struct listener *next; - grpc_closure destroy_done; -} listener; - -typedef struct call_data call_data; -typedef struct channel_data channel_data; -typedef struct registered_method registered_method; - -typedef struct { - call_data *next; - call_data *prev; -} call_link; - -typedef enum { BATCH_CALL, REGISTERED_CALL } requested_call_type; - -typedef struct requested_call { - requested_call_type type; - void *tag; - grpc_server *server; - grpc_completion_queue *cq_bound_to_call; - grpc_completion_queue *cq_for_notification; - grpc_call **call; - grpc_cq_completion completion; - grpc_metadata_array *initial_metadata; - union { - struct { - grpc_call_details *details; - } batch; - struct { - registered_method *registered_method; - gpr_timespec *deadline; - grpc_byte_buffer **optional_payload; - } registered; - } data; - grpc_closure publish; -} requested_call; - -typedef struct channel_registered_method { - registered_method *server_registered_method; - grpc_mdstr *method; - grpc_mdstr *host; -} channel_registered_method; - -struct channel_data { - grpc_server *server; - grpc_connectivity_state connectivity_state; - grpc_channel *channel; - /* linked list of all channels on a server */ - channel_data *next; - channel_data *prev; - channel_registered_method *registered_methods; - uint32_t registered_method_slots; - uint32_t registered_method_max_probes; - grpc_closure finish_destroy_channel_closure; - grpc_closure channel_connectivity_changed; -}; - -typedef struct shutdown_tag { - void *tag; - grpc_completion_queue *cq; - grpc_cq_completion completion; -} shutdown_tag; - -typedef enum { - /* waiting for metadata */ - NOT_STARTED, - /* inital metadata read, not flow controlled in yet */ - PENDING, - /* flow controlled in, on completion queue */ - ACTIVATED, - /* cancelled before being queued */ - ZOMBIED -} call_state; - -typedef struct request_matcher request_matcher; - -struct call_data { - grpc_call *call; - - /** protects state */ - gpr_mu mu_state; - /** the current state of a call - see call_state */ - call_state state; - - grpc_mdstr *path; - grpc_mdstr *host; - gpr_timespec deadline; - - grpc_completion_queue *cq_new; - - grpc_metadata_batch *recv_initial_metadata; - grpc_metadata_array initial_metadata; - - grpc_closure got_initial_metadata; - grpc_closure server_on_recv_initial_metadata; - grpc_closure kill_zombie_closure; - grpc_closure *on_done_recv_initial_metadata; - - call_data *pending_next; -}; - -struct request_matcher { - call_data *pending_head; - call_data *pending_tail; - gpr_stack_lockfree *requests; -}; - -struct registered_method { - char *method; - char *host; - request_matcher request_matcher; - registered_method *next; -}; - -typedef struct { - grpc_channel **channels; - size_t num_channels; -} channel_broadcaster; - -struct grpc_server { - grpc_channel_args *channel_args; - - grpc_completion_queue **cqs; - grpc_pollset **pollsets; - size_t cq_count; - - /* The two following mutexes control access to server-state - mu_global controls access to non-call-related state (e.g., channel state) - mu_call controls access to call-related state (e.g., the call lists) - - If they are ever required to be nested, you must lock mu_global - before mu_call. This is currently used in shutdown processing - (grpc_server_shutdown_and_notify and maybe_finish_shutdown) */ - gpr_mu mu_global; /* mutex for server and channel state */ - gpr_mu mu_call; /* mutex for call-specific state */ - - registered_method *registered_methods; - request_matcher unregistered_request_matcher; - /** free list of available requested_calls indices */ - gpr_stack_lockfree *request_freelist; - /** requested call backing data */ - requested_call *requested_calls; - size_t max_requested_calls; - - gpr_atm shutdown_flag; - uint8_t shutdown_published; - size_t num_shutdown_tags; - shutdown_tag *shutdown_tags; - - channel_data root_channel_data; - - listener *listeners; - int listeners_destroyed; - gpr_refcount internal_refcount; - - /** when did we print the last shutdown progress message */ - gpr_timespec last_shutdown_message_time; -}; - -#define SERVER_FROM_CALL_ELEM(elem) \ - (((channel_data *)(elem)->channel_data)->server) - -static void begin_call(grpc_exec_ctx *exec_ctx, grpc_server *server, - call_data *calld, requested_call *rc); -static void fail_call(grpc_exec_ctx *exec_ctx, grpc_server *server, - requested_call *rc); -/* Before calling maybe_finish_shutdown, we must hold mu_global and not - hold mu_call */ -static void maybe_finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_server *server); - -/* - * channel broadcaster - */ - -/* assumes server locked */ -static void channel_broadcaster_init(grpc_server *s, channel_broadcaster *cb) { - channel_data *c; - size_t count = 0; - for (c = s->root_channel_data.next; c != &s->root_channel_data; c = c->next) { - count++; - } - cb->num_channels = count; - cb->channels = gpr_malloc(sizeof(*cb->channels) * cb->num_channels); - count = 0; - for (c = s->root_channel_data.next; c != &s->root_channel_data; c = c->next) { - cb->channels[count++] = c->channel; - GRPC_CHANNEL_INTERNAL_REF(c->channel, "broadcast"); - } -} - -struct shutdown_cleanup_args { - grpc_closure closure; - gpr_slice slice; -}; - -static void shutdown_cleanup(grpc_exec_ctx *exec_ctx, void *arg, - bool iomgr_status_ignored) { - struct shutdown_cleanup_args *a = arg; - gpr_slice_unref(a->slice); - gpr_free(a); -} - -static void send_shutdown(grpc_exec_ctx *exec_ctx, grpc_channel *channel, - int send_goaway, int send_disconnect) { - grpc_transport_op op; - struct shutdown_cleanup_args *sc; - grpc_channel_element *elem; - - memset(&op, 0, sizeof(op)); - op.send_goaway = send_goaway; - sc = gpr_malloc(sizeof(*sc)); - sc->slice = gpr_slice_from_copied_string("Server shutdown"); - op.goaway_message = &sc->slice; - op.goaway_status = GRPC_STATUS_OK; - op.disconnect = send_disconnect; - grpc_closure_init(&sc->closure, shutdown_cleanup, sc); - op.on_consumed = &sc->closure; - - elem = grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0); - elem->filter->start_transport_op(exec_ctx, elem, &op); -} - -static void channel_broadcaster_shutdown(grpc_exec_ctx *exec_ctx, - channel_broadcaster *cb, - int send_goaway, - int force_disconnect) { - size_t i; - - for (i = 0; i < cb->num_channels; i++) { - send_shutdown(exec_ctx, cb->channels[i], send_goaway, force_disconnect); - GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, cb->channels[i], "broadcast"); - } - gpr_free(cb->channels); -} - -/* - * request_matcher - */ - -static void request_matcher_init(request_matcher *rm, size_t entries) { - memset(rm, 0, sizeof(*rm)); - rm->requests = gpr_stack_lockfree_create(entries); -} - -static void request_matcher_destroy(request_matcher *rm) { - GPR_ASSERT(gpr_stack_lockfree_pop(rm->requests) == -1); - gpr_stack_lockfree_destroy(rm->requests); -} - -static void kill_zombie(grpc_exec_ctx *exec_ctx, void *elem, bool success) { - grpc_call_destroy(grpc_call_from_top_element(elem)); -} - -static void request_matcher_zombify_all_pending_calls(grpc_exec_ctx *exec_ctx, - request_matcher *rm) { - while (rm->pending_head) { - call_data *calld = rm->pending_head; - rm->pending_head = calld->pending_next; - gpr_mu_lock(&calld->mu_state); - calld->state = ZOMBIED; - gpr_mu_unlock(&calld->mu_state); - grpc_closure_init( - &calld->kill_zombie_closure, kill_zombie, - grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0)); - grpc_exec_ctx_enqueue(exec_ctx, &calld->kill_zombie_closure, true, NULL); - } -} - -static void request_matcher_kill_requests(grpc_exec_ctx *exec_ctx, - grpc_server *server, - request_matcher *rm) { - int request_id; - while ((request_id = gpr_stack_lockfree_pop(rm->requests)) != -1) { - fail_call(exec_ctx, server, &server->requested_calls[request_id]); - } -} - -/* - * server proper - */ - -static void server_ref(grpc_server *server) { - gpr_ref(&server->internal_refcount); -} - -static void server_delete(grpc_exec_ctx *exec_ctx, grpc_server *server) { - registered_method *rm; - size_t i; - grpc_channel_args_destroy(server->channel_args); - gpr_mu_destroy(&server->mu_global); - gpr_mu_destroy(&server->mu_call); - while ((rm = server->registered_methods) != NULL) { - server->registered_methods = rm->next; - request_matcher_destroy(&rm->request_matcher); - gpr_free(rm->method); - gpr_free(rm->host); - gpr_free(rm); - } - for (i = 0; i < server->cq_count; i++) { - GRPC_CQ_INTERNAL_UNREF(server->cqs[i], "server"); - } - request_matcher_destroy(&server->unregistered_request_matcher); - gpr_stack_lockfree_destroy(server->request_freelist); - gpr_free(server->cqs); - gpr_free(server->pollsets); - gpr_free(server->shutdown_tags); - gpr_free(server->requested_calls); - gpr_free(server); -} - -static void server_unref(grpc_exec_ctx *exec_ctx, grpc_server *server) { - if (gpr_unref(&server->internal_refcount)) { - server_delete(exec_ctx, server); - } -} - -static int is_channel_orphaned(channel_data *chand) { - return chand->next == chand; -} - -static void orphan_channel(channel_data *chand) { - chand->next->prev = chand->prev; - chand->prev->next = chand->next; - chand->next = chand->prev = chand; -} - -static void finish_destroy_channel(grpc_exec_ctx *exec_ctx, void *cd, - bool success) { - channel_data *chand = cd; - grpc_server *server = chand->server; - GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, chand->channel, "server"); - server_unref(exec_ctx, server); -} - -static void destroy_channel(grpc_exec_ctx *exec_ctx, channel_data *chand) { - if (is_channel_orphaned(chand)) return; - GPR_ASSERT(chand->server != NULL); - orphan_channel(chand); - server_ref(chand->server); - maybe_finish_shutdown(exec_ctx, chand->server); - chand->finish_destroy_channel_closure.cb = finish_destroy_channel; - chand->finish_destroy_channel_closure.cb_arg = chand; - - grpc_transport_op op; - memset(&op, 0, sizeof(op)); - op.set_accept_stream = true; - op.on_consumed = &chand->finish_destroy_channel_closure; - grpc_channel_next_op(exec_ctx, - grpc_channel_stack_element( - grpc_channel_get_channel_stack(chand->channel), 0), - &op); -} - -static void finish_start_new_rpc(grpc_exec_ctx *exec_ctx, grpc_server *server, - grpc_call_element *elem, request_matcher *rm) { - call_data *calld = elem->call_data; - int request_id; - - if (gpr_atm_acq_load(&server->shutdown_flag)) { - gpr_mu_lock(&calld->mu_state); - calld->state = ZOMBIED; - gpr_mu_unlock(&calld->mu_state); - grpc_closure_init(&calld->kill_zombie_closure, kill_zombie, elem); - grpc_exec_ctx_enqueue(exec_ctx, &calld->kill_zombie_closure, true, NULL); - return; - } - - request_id = gpr_stack_lockfree_pop(rm->requests); - if (request_id == -1) { - gpr_mu_lock(&server->mu_call); - gpr_mu_lock(&calld->mu_state); - calld->state = PENDING; - gpr_mu_unlock(&calld->mu_state); - if (rm->pending_head == NULL) { - rm->pending_tail = rm->pending_head = calld; - } else { - rm->pending_tail->pending_next = calld; - rm->pending_tail = calld; - } - calld->pending_next = NULL; - gpr_mu_unlock(&server->mu_call); - } else { - gpr_mu_lock(&calld->mu_state); - calld->state = ACTIVATED; - gpr_mu_unlock(&calld->mu_state); - begin_call(exec_ctx, server, calld, &server->requested_calls[request_id]); - } -} - -static void start_new_rpc(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) { - channel_data *chand = elem->channel_data; - call_data *calld = elem->call_data; - grpc_server *server = chand->server; - uint32_t i; - uint32_t hash; - channel_registered_method *rm; - - if (chand->registered_methods && calld->path && calld->host) { - /* TODO(ctiller): unify these two searches */ - /* check for an exact match with host */ - hash = GRPC_MDSTR_KV_HASH(calld->host->hash, calld->path->hash); - for (i = 0; i <= chand->registered_method_max_probes; i++) { - rm = &chand->registered_methods[(hash + i) % - chand->registered_method_slots]; - if (!rm) break; - if (rm->host != calld->host) continue; - if (rm->method != calld->path) continue; - finish_start_new_rpc(exec_ctx, server, elem, - &rm->server_registered_method->request_matcher); - return; - } - /* check for a wildcard method definition (no host set) */ - hash = GRPC_MDSTR_KV_HASH(0, calld->path->hash); - for (i = 0; i <= chand->registered_method_max_probes; i++) { - rm = &chand->registered_methods[(hash + i) % - chand->registered_method_slots]; - if (!rm) break; - if (rm->host != NULL) continue; - if (rm->method != calld->path) continue; - finish_start_new_rpc(exec_ctx, server, elem, - &rm->server_registered_method->request_matcher); - return; - } - } - finish_start_new_rpc(exec_ctx, server, elem, - &server->unregistered_request_matcher); -} - -static int num_listeners(grpc_server *server) { - listener *l; - int n = 0; - for (l = server->listeners; l; l = l->next) { - n++; - } - return n; -} - -static void done_shutdown_event(grpc_exec_ctx *exec_ctx, void *server, - grpc_cq_completion *completion) { - server_unref(exec_ctx, server); -} - -static int num_channels(grpc_server *server) { - channel_data *chand; - int n = 0; - for (chand = server->root_channel_data.next; - chand != &server->root_channel_data; chand = chand->next) { - n++; - } - return n; -} - -static void kill_pending_work_locked(grpc_exec_ctx *exec_ctx, - grpc_server *server) { - registered_method *rm; - request_matcher_kill_requests(exec_ctx, server, - &server->unregistered_request_matcher); - request_matcher_zombify_all_pending_calls( - exec_ctx, &server->unregistered_request_matcher); - for (rm = server->registered_methods; rm; rm = rm->next) { - request_matcher_kill_requests(exec_ctx, server, &rm->request_matcher); - request_matcher_zombify_all_pending_calls(exec_ctx, &rm->request_matcher); - } -} - -static void maybe_finish_shutdown(grpc_exec_ctx *exec_ctx, - grpc_server *server) { - size_t i; - if (!gpr_atm_acq_load(&server->shutdown_flag) || server->shutdown_published) { - return; - } - - kill_pending_work_locked(exec_ctx, server); - - if (server->root_channel_data.next != &server->root_channel_data || - server->listeners_destroyed < num_listeners(server)) { - if (gpr_time_cmp(gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), - server->last_shutdown_message_time), - gpr_time_from_seconds(1, GPR_TIMESPAN)) >= 0) { - server->last_shutdown_message_time = gpr_now(GPR_CLOCK_REALTIME); - gpr_log(GPR_DEBUG, - "Waiting for %d channels and %d/%d listeners to be destroyed" - " before shutting down server", - num_channels(server), - num_listeners(server) - server->listeners_destroyed, - num_listeners(server)); - } - return; - } - server->shutdown_published = 1; - for (i = 0; i < server->num_shutdown_tags; i++) { - server_ref(server); - grpc_cq_end_op(exec_ctx, server->shutdown_tags[i].cq, - server->shutdown_tags[i].tag, 1, done_shutdown_event, server, - &server->shutdown_tags[i].completion); - } -} - -static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) { - grpc_call_element *elem = user_data; - call_data *calld = elem->call_data; - if (md->key == GRPC_MDSTR_PATH) { - calld->path = GRPC_MDSTR_REF(md->value); - return NULL; - } else if (md->key == GRPC_MDSTR_AUTHORITY) { - calld->host = GRPC_MDSTR_REF(md->value); - return NULL; - } - return md; -} - -static void server_on_recv_initial_metadata(grpc_exec_ctx *exec_ctx, void *ptr, - bool success) { - grpc_call_element *elem = ptr; - call_data *calld = elem->call_data; - gpr_timespec op_deadline; - - grpc_metadata_batch_filter(calld->recv_initial_metadata, server_filter, elem); - op_deadline = calld->recv_initial_metadata->deadline; - if (0 != gpr_time_cmp(op_deadline, gpr_inf_future(op_deadline.clock_type))) { - calld->deadline = op_deadline; - } - if (calld->host && calld->path) { - /* do nothing */ - } else { - success = 0; - } - - calld->on_done_recv_initial_metadata->cb( - exec_ctx, calld->on_done_recv_initial_metadata->cb_arg, success); -} - -static void server_mutate_op(grpc_call_element *elem, - grpc_transport_stream_op *op) { - call_data *calld = elem->call_data; - - if (op->recv_initial_metadata != NULL) { - calld->recv_initial_metadata = op->recv_initial_metadata; - calld->on_done_recv_initial_metadata = op->recv_initial_metadata_ready; - op->recv_initial_metadata_ready = &calld->server_on_recv_initial_metadata; - } -} - -static void server_start_transport_stream_op(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem, - grpc_transport_stream_op *op) { - GRPC_CALL_LOG_OP(GPR_INFO, elem, op); - server_mutate_op(elem, op); - grpc_call_next_op(exec_ctx, elem, op); -} - -static void got_initial_metadata(grpc_exec_ctx *exec_ctx, void *ptr, - bool success) { - grpc_call_element *elem = ptr; - call_data *calld = elem->call_data; - if (success) { - start_new_rpc(exec_ctx, elem); - } else { - gpr_mu_lock(&calld->mu_state); - if (calld->state == NOT_STARTED) { - calld->state = ZOMBIED; - gpr_mu_unlock(&calld->mu_state); - grpc_closure_init(&calld->kill_zombie_closure, kill_zombie, elem); - grpc_exec_ctx_enqueue(exec_ctx, &calld->kill_zombie_closure, true, NULL); - } else if (calld->state == PENDING) { - calld->state = ZOMBIED; - gpr_mu_unlock(&calld->mu_state); - /* zombied call will be destroyed when it's removed from the pending - queue... later */ - } else { - gpr_mu_unlock(&calld->mu_state); - } - } -} - -static void accept_stream(grpc_exec_ctx *exec_ctx, void *cd, - grpc_transport *transport, - const void *transport_server_data) { - channel_data *chand = cd; - /* create a call */ - grpc_call *call = - grpc_call_create(chand->channel, NULL, 0, NULL, transport_server_data, - NULL, 0, gpr_inf_future(GPR_CLOCK_MONOTONIC)); - grpc_call_element *elem = - grpc_call_stack_element(grpc_call_get_call_stack(call), 0); - call_data *calld = elem->call_data; - grpc_op op; - memset(&op, 0, sizeof(op)); - op.op = GRPC_OP_RECV_INITIAL_METADATA; - op.data.recv_initial_metadata = &calld->initial_metadata; - grpc_closure_init(&calld->got_initial_metadata, got_initial_metadata, elem); - grpc_call_start_batch_and_execute(exec_ctx, call, &op, 1, - &calld->got_initial_metadata); -} - -static void channel_connectivity_changed(grpc_exec_ctx *exec_ctx, void *cd, - bool iomgr_status_ignored) { - channel_data *chand = cd; - grpc_server *server = chand->server; - if (chand->connectivity_state != GRPC_CHANNEL_FATAL_FAILURE) { - grpc_transport_op op; - memset(&op, 0, sizeof(op)); - op.on_connectivity_state_change = &chand->channel_connectivity_changed, - op.connectivity_state = &chand->connectivity_state; - grpc_channel_next_op(exec_ctx, - grpc_channel_stack_element( - grpc_channel_get_channel_stack(chand->channel), 0), - &op); - } else { - gpr_mu_lock(&server->mu_global); - destroy_channel(exec_ctx, chand); - gpr_mu_unlock(&server->mu_global); - GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, chand->channel, "connectivity"); - } -} - -static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, - grpc_call_element_args *args) { - call_data *calld = elem->call_data; - channel_data *chand = elem->channel_data; - memset(calld, 0, sizeof(call_data)); - calld->deadline = gpr_inf_future(GPR_CLOCK_REALTIME); - calld->call = grpc_call_from_top_element(elem); - gpr_mu_init(&calld->mu_state); - - grpc_closure_init(&calld->server_on_recv_initial_metadata, - server_on_recv_initial_metadata, elem); - - server_ref(chand->server); -} - -static void destroy_call_elem(grpc_exec_ctx *exec_ctx, - grpc_call_element *elem) { - channel_data *chand = elem->channel_data; - call_data *calld = elem->call_data; - - GPR_ASSERT(calld->state != PENDING); - - if (calld->host) { - GRPC_MDSTR_UNREF(calld->host); - } - if (calld->path) { - GRPC_MDSTR_UNREF(calld->path); - } - grpc_metadata_array_destroy(&calld->initial_metadata); - - gpr_mu_destroy(&calld->mu_state); - - server_unref(exec_ctx, chand->server); -} - -static void init_channel_elem(grpc_exec_ctx *exec_ctx, - grpc_channel_element *elem, - grpc_channel_element_args *args) { - channel_data *chand = elem->channel_data; - GPR_ASSERT(args->is_first); - GPR_ASSERT(!args->is_last); - chand->server = NULL; - chand->channel = NULL; - chand->next = chand->prev = chand; - chand->registered_methods = NULL; - chand->connectivity_state = GRPC_CHANNEL_IDLE; - grpc_closure_init(&chand->channel_connectivity_changed, - channel_connectivity_changed, chand); -} - -static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, - grpc_channel_element *elem) { - size_t i; - channel_data *chand = elem->channel_data; - if (chand->registered_methods) { - for (i = 0; i < chand->registered_method_slots; i++) { - if (chand->registered_methods[i].method) { - GRPC_MDSTR_UNREF(chand->registered_methods[i].method); - } - if (chand->registered_methods[i].host) { - GRPC_MDSTR_UNREF(chand->registered_methods[i].host); - } - } - gpr_free(chand->registered_methods); - } - if (chand->server) { - gpr_mu_lock(&chand->server->mu_global); - chand->next->prev = chand->prev; - chand->prev->next = chand->next; - chand->next = chand->prev = chand; - maybe_finish_shutdown(exec_ctx, chand->server); - gpr_mu_unlock(&chand->server->mu_global); - server_unref(exec_ctx, chand->server); - } -} - -const grpc_channel_filter grpc_server_top_filter = { - server_start_transport_stream_op, - grpc_channel_next_op, - sizeof(call_data), - init_call_elem, - grpc_call_stack_ignore_set_pollset, - destroy_call_elem, - sizeof(channel_data), - init_channel_elem, - destroy_channel_elem, - grpc_call_next_get_peer, - "server", -}; - -void grpc_server_register_completion_queue(grpc_server *server, - grpc_completion_queue *cq, - void *reserved) { - size_t i, n; - GRPC_API_TRACE( - "grpc_server_register_completion_queue(server=%p, cq=%p, reserved=%p)", 3, - (server, cq, reserved)); - GPR_ASSERT(!reserved); - for (i = 0; i < server->cq_count; i++) { - if (server->cqs[i] == cq) return; - } - GRPC_CQ_INTERNAL_REF(cq, "server"); - grpc_cq_mark_server_cq(cq); - n = server->cq_count++; - server->cqs = gpr_realloc(server->cqs, - server->cq_count * sizeof(grpc_completion_queue *)); - server->cqs[n] = cq; -} - -grpc_server *grpc_server_create(const grpc_channel_args *args, void *reserved) { - size_t i; - - GRPC_API_TRACE("grpc_server_create(%p, %p)", 2, (args, reserved)); - - grpc_server *server = gpr_malloc(sizeof(grpc_server)); - - GPR_ASSERT(grpc_is_initialized() && "call grpc_init()"); - - memset(server, 0, sizeof(grpc_server)); - - gpr_mu_init(&server->mu_global); - gpr_mu_init(&server->mu_call); - - /* decremented by grpc_server_destroy */ - gpr_ref_init(&server->internal_refcount, 1); - server->root_channel_data.next = server->root_channel_data.prev = - &server->root_channel_data; - - /* TODO(ctiller): expose a channel_arg for this */ - server->max_requested_calls = 32768; - server->request_freelist = - gpr_stack_lockfree_create(server->max_requested_calls); - for (i = 0; i < (size_t)server->max_requested_calls; i++) { - gpr_stack_lockfree_push(server->request_freelist, (int)i); - } - request_matcher_init(&server->unregistered_request_matcher, - server->max_requested_calls); - server->requested_calls = gpr_malloc(server->max_requested_calls * - sizeof(*server->requested_calls)); - - server->channel_args = grpc_channel_args_copy(args); - - return server; -} - -static int streq(const char *a, const char *b) { - if (a == NULL && b == NULL) return 1; - if (a == NULL) return 0; - if (b == NULL) return 0; - return 0 == strcmp(a, b); -} - -void *grpc_server_register_method(grpc_server *server, const char *method, - const char *host) { - registered_method *m; - GRPC_API_TRACE("grpc_server_register_method(server=%p, method=%s, host=%s)", - 3, (server, method, host)); - if (!method) { - gpr_log(GPR_ERROR, - "grpc_server_register_method method string cannot be NULL"); - return NULL; - } - for (m = server->registered_methods; m; m = m->next) { - if (streq(m->method, method) && streq(m->host, host)) { - gpr_log(GPR_ERROR, "duplicate registration for %s@%s", method, - host ? host : "*"); - return NULL; - } - } - m = gpr_malloc(sizeof(registered_method)); - memset(m, 0, sizeof(*m)); - request_matcher_init(&m->request_matcher, server->max_requested_calls); - m->method = gpr_strdup(method); - m->host = gpr_strdup(host); - m->next = server->registered_methods; - server->registered_methods = m; - return m; -} - -void grpc_server_start(grpc_server *server) { - listener *l; - size_t i; - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - - GRPC_API_TRACE("grpc_server_start(server=%p)", 1, (server)); - - server->pollsets = gpr_malloc(sizeof(grpc_pollset *) * server->cq_count); - for (i = 0; i < server->cq_count; i++) { - server->pollsets[i] = grpc_cq_pollset(server->cqs[i]); - } - - for (l = server->listeners; l; l = l->next) { - l->start(&exec_ctx, server, l->arg, server->pollsets, server->cq_count); - } - - grpc_exec_ctx_finish(&exec_ctx); -} - -void grpc_server_setup_transport(grpc_exec_ctx *exec_ctx, grpc_server *s, - grpc_transport *transport, - const grpc_channel_args *args) { - size_t i; - size_t num_registered_methods; - size_t alloc; - registered_method *rm; - channel_registered_method *crm; - grpc_channel *channel; - channel_data *chand; - grpc_mdstr *host; - grpc_mdstr *method; - uint32_t hash; - size_t slots; - uint32_t probes; - uint32_t max_probes = 0; - grpc_transport_op op; - - for (i = 0; i < s->cq_count; i++) { - memset(&op, 0, sizeof(op)); - op.bind_pollset = grpc_cq_pollset(s->cqs[i]); - grpc_transport_perform_op(exec_ctx, transport, &op); - } - - channel = - grpc_channel_create(exec_ctx, NULL, args, GRPC_SERVER_CHANNEL, transport); - chand = (channel_data *)grpc_channel_stack_element( - grpc_channel_get_channel_stack(channel), 0) - ->channel_data; - chand->server = s; - server_ref(s); - chand->channel = channel; - - num_registered_methods = 0; - for (rm = s->registered_methods; rm; rm = rm->next) { - num_registered_methods++; - } - /* build a lookup table phrased in terms of mdstr's in this channels context - to quickly find registered methods */ - if (num_registered_methods > 0) { - slots = 2 * num_registered_methods; - alloc = sizeof(channel_registered_method) * slots; - chand->registered_methods = gpr_malloc(alloc); - memset(chand->registered_methods, 0, alloc); - for (rm = s->registered_methods; rm; rm = rm->next) { - host = rm->host ? grpc_mdstr_from_string(rm->host) : NULL; - method = grpc_mdstr_from_string(rm->method); - hash = GRPC_MDSTR_KV_HASH(host ? host->hash : 0, method->hash); - for (probes = 0; chand->registered_methods[(hash + probes) % slots] - .server_registered_method != NULL; - probes++) - ; - if (probes > max_probes) max_probes = probes; - crm = &chand->registered_methods[(hash + probes) % slots]; - crm->server_registered_method = rm; - crm->host = host; - crm->method = method; - } - GPR_ASSERT(slots <= UINT32_MAX); - chand->registered_method_slots = (uint32_t)slots; - chand->registered_method_max_probes = max_probes; - } - - gpr_mu_lock(&s->mu_global); - chand->next = &s->root_channel_data; - chand->prev = chand->next->prev; - chand->next->prev = chand->prev->next = chand; - gpr_mu_unlock(&s->mu_global); - - GRPC_CHANNEL_INTERNAL_REF(channel, "connectivity"); - memset(&op, 0, sizeof(op)); - op.set_accept_stream = true; - op.set_accept_stream_fn = accept_stream; - op.set_accept_stream_user_data = chand; - op.on_connectivity_state_change = &chand->channel_connectivity_changed; - op.connectivity_state = &chand->connectivity_state; - op.disconnect = gpr_atm_acq_load(&s->shutdown_flag) != 0; - grpc_transport_perform_op(exec_ctx, transport, &op); -} - -void done_published_shutdown(grpc_exec_ctx *exec_ctx, void *done_arg, - grpc_cq_completion *storage) { - (void)done_arg; - gpr_free(storage); -} - -static void listener_destroy_done(grpc_exec_ctx *exec_ctx, void *s, - bool success) { - grpc_server *server = s; - gpr_mu_lock(&server->mu_global); - server->listeners_destroyed++; - maybe_finish_shutdown(exec_ctx, server); - gpr_mu_unlock(&server->mu_global); -} - -void grpc_server_shutdown_and_notify(grpc_server *server, - grpc_completion_queue *cq, void *tag) { - listener *l; - shutdown_tag *sdt; - channel_broadcaster broadcaster; - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - - GRPC_API_TRACE("grpc_server_shutdown_and_notify(server=%p, cq=%p, tag=%p)", 3, - (server, cq, tag)); - - /* lock, and gather up some stuff to do */ - gpr_mu_lock(&server->mu_global); - grpc_cq_begin_op(cq, tag); - if (server->shutdown_published) { - grpc_cq_end_op(&exec_ctx, cq, tag, 1, done_published_shutdown, NULL, - gpr_malloc(sizeof(grpc_cq_completion))); - gpr_mu_unlock(&server->mu_global); - goto done; - } - server->shutdown_tags = - gpr_realloc(server->shutdown_tags, - sizeof(shutdown_tag) * (server->num_shutdown_tags + 1)); - sdt = &server->shutdown_tags[server->num_shutdown_tags++]; - sdt->tag = tag; - sdt->cq = cq; - if (gpr_atm_acq_load(&server->shutdown_flag)) { - gpr_mu_unlock(&server->mu_global); - goto done; - } - - server->last_shutdown_message_time = gpr_now(GPR_CLOCK_REALTIME); - - channel_broadcaster_init(server, &broadcaster); - - gpr_atm_rel_store(&server->shutdown_flag, 1); - - /* collect all unregistered then registered calls */ - gpr_mu_lock(&server->mu_call); - kill_pending_work_locked(&exec_ctx, server); - gpr_mu_unlock(&server->mu_call); - - maybe_finish_shutdown(&exec_ctx, server); - gpr_mu_unlock(&server->mu_global); - - /* Shutdown listeners */ - for (l = server->listeners; l; l = l->next) { - grpc_closure_init(&l->destroy_done, listener_destroy_done, server); - l->destroy(&exec_ctx, server, l->arg, &l->destroy_done); - } - - channel_broadcaster_shutdown(&exec_ctx, &broadcaster, 1, 0); - -done: - grpc_exec_ctx_finish(&exec_ctx); -} - -void grpc_server_cancel_all_calls(grpc_server *server) { - channel_broadcaster broadcaster; - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - - GRPC_API_TRACE("grpc_server_cancel_all_calls(server=%p)", 1, (server)); - - gpr_mu_lock(&server->mu_global); - channel_broadcaster_init(server, &broadcaster); - gpr_mu_unlock(&server->mu_global); - - channel_broadcaster_shutdown(&exec_ctx, &broadcaster, 0, 1); - grpc_exec_ctx_finish(&exec_ctx); -} - -void grpc_server_destroy(grpc_server *server) { - listener *l; - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - - GRPC_API_TRACE("grpc_server_destroy(server=%p)", 1, (server)); - - gpr_mu_lock(&server->mu_global); - GPR_ASSERT(gpr_atm_acq_load(&server->shutdown_flag) || !server->listeners); - GPR_ASSERT(server->listeners_destroyed == num_listeners(server)); - - while (server->listeners) { - l = server->listeners; - server->listeners = l->next; - gpr_free(l); - } - - gpr_mu_unlock(&server->mu_global); - - server_unref(&exec_ctx, server); - grpc_exec_ctx_finish(&exec_ctx); -} - -void grpc_server_add_listener( - grpc_exec_ctx *exec_ctx, grpc_server *server, void *arg, - void (*start)(grpc_exec_ctx *exec_ctx, grpc_server *server, void *arg, - grpc_pollset **pollsets, size_t pollset_count), - void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_server *server, void *arg, - grpc_closure *on_done)) { - listener *l = gpr_malloc(sizeof(listener)); - l->arg = arg; - l->start = start; - l->destroy = destroy; - l->next = server->listeners; - server->listeners = l; -} - -static grpc_call_error queue_call_request(grpc_exec_ctx *exec_ctx, - grpc_server *server, - requested_call *rc) { - call_data *calld = NULL; - request_matcher *rm = NULL; - int request_id; - if (gpr_atm_acq_load(&server->shutdown_flag)) { - fail_call(exec_ctx, server, rc); - return GRPC_CALL_OK; - } - request_id = gpr_stack_lockfree_pop(server->request_freelist); - if (request_id == -1) { - /* out of request ids: just fail this one */ - fail_call(exec_ctx, server, rc); - return GRPC_CALL_OK; - } - switch (rc->type) { - case BATCH_CALL: - rm = &server->unregistered_request_matcher; - break; - case REGISTERED_CALL: - rm = &rc->data.registered.registered_method->request_matcher; - break; - } - server->requested_calls[request_id] = *rc; - gpr_free(rc); - if (gpr_stack_lockfree_push(rm->requests, request_id)) { - /* this was the first queued request: we need to lock and start - matching calls */ - gpr_mu_lock(&server->mu_call); - while ((calld = rm->pending_head) != NULL) { - request_id = gpr_stack_lockfree_pop(rm->requests); - if (request_id == -1) break; - rm->pending_head = calld->pending_next; - gpr_mu_unlock(&server->mu_call); - gpr_mu_lock(&calld->mu_state); - if (calld->state == ZOMBIED) { - gpr_mu_unlock(&calld->mu_state); - grpc_closure_init( - &calld->kill_zombie_closure, kill_zombie, - grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0)); - grpc_exec_ctx_enqueue(exec_ctx, &calld->kill_zombie_closure, true, - NULL); - } else { - GPR_ASSERT(calld->state == PENDING); - calld->state = ACTIVATED; - gpr_mu_unlock(&calld->mu_state); - begin_call(exec_ctx, server, calld, - &server->requested_calls[request_id]); - } - gpr_mu_lock(&server->mu_call); - } - gpr_mu_unlock(&server->mu_call); - } - return GRPC_CALL_OK; -} - -grpc_call_error grpc_server_request_call( - grpc_server *server, grpc_call **call, grpc_call_details *details, - grpc_metadata_array *initial_metadata, - grpc_completion_queue *cq_bound_to_call, - grpc_completion_queue *cq_for_notification, void *tag) { - grpc_call_error error; - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - requested_call *rc = gpr_malloc(sizeof(*rc)); - GRPC_API_TRACE( - "grpc_server_request_call(" - "server=%p, call=%p, details=%p, initial_metadata=%p, " - "cq_bound_to_call=%p, cq_for_notification=%p, tag=%p)", - 7, (server, call, details, initial_metadata, cq_bound_to_call, - cq_for_notification, tag)); - if (!grpc_cq_is_server_cq(cq_for_notification)) { - gpr_free(rc); - error = GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE; - goto done; - } - grpc_cq_begin_op(cq_for_notification, tag); - details->reserved = NULL; - rc->type = BATCH_CALL; - rc->server = server; - rc->tag = tag; - rc->cq_bound_to_call = cq_bound_to_call; - rc->cq_for_notification = cq_for_notification; - rc->call = call; - rc->data.batch.details = details; - rc->initial_metadata = initial_metadata; - error = queue_call_request(&exec_ctx, server, rc); -done: - grpc_exec_ctx_finish(&exec_ctx); - return error; -} - -grpc_call_error grpc_server_request_registered_call( - grpc_server *server, void *rmp, grpc_call **call, gpr_timespec *deadline, - grpc_metadata_array *initial_metadata, grpc_byte_buffer **optional_payload, - grpc_completion_queue *cq_bound_to_call, - grpc_completion_queue *cq_for_notification, void *tag) { - grpc_call_error error; - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - requested_call *rc = gpr_malloc(sizeof(*rc)); - registered_method *rm = rmp; - GRPC_API_TRACE( - "grpc_server_request_registered_call(" - "server=%p, rmp=%p, call=%p, deadline=%p, initial_metadata=%p, " - "optional_payload=%p, cq_bound_to_call=%p, cq_for_notification=%p, " - "tag=%p)", - 9, (server, rmp, call, deadline, initial_metadata, optional_payload, - cq_bound_to_call, cq_for_notification, tag)); - if (!grpc_cq_is_server_cq(cq_for_notification)) { - gpr_free(rc); - error = GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE; - goto done; - } - grpc_cq_begin_op(cq_for_notification, tag); - rc->type = REGISTERED_CALL; - rc->server = server; - rc->tag = tag; - rc->cq_bound_to_call = cq_bound_to_call; - rc->cq_for_notification = cq_for_notification; - rc->call = call; - rc->data.registered.registered_method = rm; - rc->data.registered.deadline = deadline; - rc->initial_metadata = initial_metadata; - rc->data.registered.optional_payload = optional_payload; - error = queue_call_request(&exec_ctx, server, rc); -done: - grpc_exec_ctx_finish(&exec_ctx); - return error; -} - -static void publish_registered_or_batch(grpc_exec_ctx *exec_ctx, - void *user_data, bool success); - -static void cpstr(char **dest, size_t *capacity, grpc_mdstr *value) { - gpr_slice slice = value->slice; - size_t len = GPR_SLICE_LENGTH(slice); - - if (len + 1 > *capacity) { - *capacity = GPR_MAX(len + 1, *capacity * 2); - *dest = gpr_realloc(*dest, *capacity); - } - memcpy(*dest, grpc_mdstr_as_c_string(value), len + 1); -} - -static void begin_call(grpc_exec_ctx *exec_ctx, grpc_server *server, - call_data *calld, requested_call *rc) { - grpc_op ops[1]; - grpc_op *op = ops; - - memset(ops, 0, sizeof(ops)); - - /* called once initial metadata has been read by the call, but BEFORE - the ioreq to fetch it out of the call has been executed. - This means metadata related fields can be relied on in calld, but to - fill in the metadata array passed by the client, we need to perform - an ioreq op, that should complete immediately. */ - - grpc_call_set_completion_queue(exec_ctx, calld->call, rc->cq_bound_to_call); - grpc_closure_init(&rc->publish, publish_registered_or_batch, rc); - *rc->call = calld->call; - calld->cq_new = rc->cq_for_notification; - GPR_SWAP(grpc_metadata_array, *rc->initial_metadata, calld->initial_metadata); - switch (rc->type) { - case BATCH_CALL: - GPR_ASSERT(calld->host != NULL); - GPR_ASSERT(calld->path != NULL); - cpstr(&rc->data.batch.details->host, - &rc->data.batch.details->host_capacity, calld->host); - cpstr(&rc->data.batch.details->method, - &rc->data.batch.details->method_capacity, calld->path); - rc->data.batch.details->deadline = calld->deadline; - break; - case REGISTERED_CALL: - *rc->data.registered.deadline = calld->deadline; - if (rc->data.registered.optional_payload) { - op->op = GRPC_OP_RECV_MESSAGE; - op->data.recv_message = rc->data.registered.optional_payload; - op++; - } - break; - default: - GPR_UNREACHABLE_CODE(return ); - } - - GRPC_CALL_INTERNAL_REF(calld->call, "server"); - grpc_call_start_batch_and_execute(exec_ctx, calld->call, ops, - (size_t)(op - ops), &rc->publish); -} - -static void done_request_event(grpc_exec_ctx *exec_ctx, void *req, - grpc_cq_completion *c) { - requested_call *rc = req; - grpc_server *server = rc->server; - - if (rc >= server->requested_calls && - rc < server->requested_calls + server->max_requested_calls) { - GPR_ASSERT(rc - server->requested_calls <= INT_MAX); - gpr_stack_lockfree_push(server->request_freelist, - (int)(rc - server->requested_calls)); - } else { - gpr_free(req); - } - - server_unref(exec_ctx, server); -} - -static void fail_call(grpc_exec_ctx *exec_ctx, grpc_server *server, - requested_call *rc) { - *rc->call = NULL; - rc->initial_metadata->count = 0; - - server_ref(server); - grpc_cq_end_op(exec_ctx, rc->cq_for_notification, rc->tag, 0, - done_request_event, rc, &rc->completion); -} - -static void publish_registered_or_batch(grpc_exec_ctx *exec_ctx, void *prc, - bool success) { - requested_call *rc = prc; - grpc_call *call = *rc->call; - grpc_call_element *elem = - grpc_call_stack_element(grpc_call_get_call_stack(call), 0); - call_data *calld = elem->call_data; - channel_data *chand = elem->channel_data; - server_ref(chand->server); - grpc_cq_end_op(exec_ctx, calld->cq_new, rc->tag, success, done_request_event, - rc, &rc->completion); - GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, "server"); -} - -const grpc_channel_args *grpc_server_get_channel_args(grpc_server *server) { - return server->channel_args; -} - -int grpc_server_has_open_connections(grpc_server *server) { - int r; - gpr_mu_lock(&server->mu_global); - r = server->root_channel_data.next != &server->root_channel_data; - gpr_mu_unlock(&server->mu_global); - return r; -} diff --git a/src/core/surface/server.h b/src/core/surface/server.h deleted file mode 100644 index cd62eadd7f..0000000000 --- a/src/core/surface/server.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * - * Copyright 2015-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_SURFACE_SERVER_H -#define GRPC_CORE_SURFACE_SERVER_H - -#include -#include "src/core/channel/channel_stack.h" -#include "src/core/transport/transport.h" - -extern const grpc_channel_filter grpc_server_top_filter; - -/* Add a listener to the server: when the server starts, it will call start, - and when it shuts down, it will call destroy */ -void grpc_server_add_listener( - grpc_exec_ctx *exec_ctx, grpc_server *server, void *listener, - void (*start)(grpc_exec_ctx *exec_ctx, grpc_server *server, void *arg, - grpc_pollset **pollsets, size_t npollsets), - void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_server *server, void *arg, - grpc_closure *on_done)); - -/* Setup a transport - creates a channel stack, binds the transport to the - server */ -void grpc_server_setup_transport(grpc_exec_ctx *exec_ctx, grpc_server *server, - grpc_transport *transport, - const grpc_channel_args *args); - -const grpc_channel_args *grpc_server_get_channel_args(grpc_server *server); - -int grpc_server_has_open_connections(grpc_server *server); - -#endif /* GRPC_CORE_SURFACE_SERVER_H */ diff --git a/src/core/surface/server_chttp2.c b/src/core/surface/server_chttp2.c deleted file mode 100644 index 546760ecfa..0000000000 --- a/src/core/surface/server_chttp2.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * - * Copyright 2015-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 - -#include -#include -#include -#include "src/core/channel/http_server_filter.h" -#include "src/core/iomgr/resolve_address.h" -#include "src/core/iomgr/tcp_server.h" -#include "src/core/surface/api_trace.h" -#include "src/core/surface/server.h" -#include "src/core/transport/chttp2_transport.h" - -static void setup_transport(grpc_exec_ctx *exec_ctx, void *server, - grpc_transport *transport) { - grpc_server_setup_transport(exec_ctx, server, transport, - grpc_server_get_channel_args(server)); -} - -static void new_transport(grpc_exec_ctx *exec_ctx, void *server, - grpc_endpoint *tcp, - grpc_tcp_server_acceptor *acceptor) { - /* - * Beware that the call to grpc_create_chttp2_transport() has to happen before - * grpc_tcp_server_destroy(). This is fine here, but similar code - * asynchronously doing a handshake instead of calling grpc_tcp_server_start() - * (as in server_secure_chttp2.c) needs to add synchronization to avoid this - * case. - */ - grpc_transport *transport = grpc_create_chttp2_transport( - exec_ctx, grpc_server_get_channel_args(server), tcp, 0); - setup_transport(exec_ctx, server, transport); - grpc_chttp2_transport_start_reading(exec_ctx, transport, NULL, 0); -} - -/* Server callback: start listening on our ports */ -static void start(grpc_exec_ctx *exec_ctx, grpc_server *server, void *tcpp, - grpc_pollset **pollsets, size_t pollset_count) { - grpc_tcp_server *tcp = tcpp; - grpc_tcp_server_start(exec_ctx, tcp, pollsets, pollset_count, new_transport, - server); -} - -/* Server callback: destroy the tcp listener (so we don't generate further - callbacks) */ -static void destroy(grpc_exec_ctx *exec_ctx, grpc_server *server, void *tcpp, - grpc_closure *destroy_done) { - grpc_tcp_server *tcp = tcpp; - grpc_tcp_server_unref(exec_ctx, tcp); - grpc_exec_ctx_enqueue(exec_ctx, destroy_done, true, NULL); -} - -int grpc_server_add_insecure_http2_port(grpc_server *server, const char *addr) { - grpc_resolved_addresses *resolved = NULL; - grpc_tcp_server *tcp = NULL; - size_t i; - unsigned count = 0; - int port_num = -1; - int port_temp; - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - - GRPC_API_TRACE("grpc_server_add_insecure_http2_port(server=%p, addr=%s)", 2, - (server, addr)); - - resolved = grpc_blocking_resolve_address(addr, "http"); - if (!resolved) { - goto error; - } - - tcp = grpc_tcp_server_create(NULL); - GPR_ASSERT(tcp); - - for (i = 0; i < resolved->naddrs; i++) { - port_temp = grpc_tcp_server_add_port( - tcp, (struct sockaddr *)&resolved->addrs[i].addr, - resolved->addrs[i].len); - if (port_temp > 0) { - if (port_num == -1) { - port_num = port_temp; - } else { - GPR_ASSERT(port_num == port_temp); - } - count++; - } - } - if (count == 0) { - gpr_log(GPR_ERROR, "No address added out of total %d resolved", - resolved->naddrs); - goto error; - } - if (count != resolved->naddrs) { - gpr_log(GPR_ERROR, "Only %d addresses added out of total %d resolved", - count, resolved->naddrs); - } - grpc_resolved_addresses_destroy(resolved); - - /* Register with the server only upon success */ - grpc_server_add_listener(&exec_ctx, server, tcp, start, destroy); - goto done; - -/* Error path: cleanup and return */ -error: - if (resolved) { - grpc_resolved_addresses_destroy(resolved); - } - if (tcp) { - grpc_tcp_server_unref(&exec_ctx, tcp); - } - port_num = 0; - -done: - grpc_exec_ctx_finish(&exec_ctx); - return port_num; -} diff --git a/src/core/surface/surface_trace.h b/src/core/surface/surface_trace.h deleted file mode 100644 index a55a88e44d..0000000000 --- a/src/core/surface/surface_trace.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * - * Copyright 2015-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_SURFACE_SURFACE_TRACE_H -#define GRPC_CORE_SURFACE_SURFACE_TRACE_H - -#include -#include "src/core/debug/trace.h" -#include "src/core/surface/api_trace.h" - -#define GRPC_SURFACE_TRACE_RETURNED_EVENT(cq, event) \ - if (grpc_api_trace) { \ - char *_ev = grpc_event_string(event); \ - gpr_log(GPR_INFO, "RETURN_EVENT[%p]: %s", cq, _ev); \ - gpr_free(_ev); \ - } - -#endif /* GRPC_CORE_SURFACE_SURFACE_TRACE_H */ diff --git a/src/core/surface/validate_metadata.c b/src/core/surface/validate_metadata.c deleted file mode 100644 index bf4126867f..0000000000 --- a/src/core/surface/validate_metadata.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * - * 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 -#include - -#include - -static int conforms_to(const char *s, size_t len, const uint8_t *legal_bits) { - const char *p = s; - const char *e = s + len; - for (; p != e; p++) { - int idx = *p; - int byte = idx / 8; - int bit = idx % 8; - if ((legal_bits[byte] & (1 << bit)) == 0) return 0; - } - return 1; -} - -int grpc_header_key_is_legal(const char *key, size_t length) { - static const uint8_t legal_header_bits[256 / 8] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xff, 0x03, 0x00, 0x00, 0x00, - 0x80, 0xfe, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - if (length == 0) { - return 0; - } - return conforms_to(key, length, legal_header_bits); -} - -int grpc_header_nonbin_value_is_legal(const char *value, size_t length) { - static const uint8_t legal_header_bits[256 / 8] = { - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - return conforms_to(value, length, legal_header_bits); -} - -int grpc_is_binary_header(const char *key, size_t length) { - if (length < 5) return 0; - return 0 == memcmp(key + length - 4, "-bin", 4); -} diff --git a/src/core/surface/version.c b/src/core/surface/version.c deleted file mode 100644 index 7723f39401..0000000000 --- a/src/core/surface/version.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * - * Copyright 2015-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. - * - */ - -/* This file is autogenerated from: - templates/src/core/surface/version.c.template */ - -#include - -const char *grpc_version_string(void) { return "0.14.0-dev"; } diff --git a/src/core/transport/byte_stream.c b/src/core/transport/byte_stream.c deleted file mode 100644 index 8e6fb2cbef..0000000000 --- a/src/core/transport/byte_stream.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/transport/byte_stream.h" - -#include - -#include - -int grpc_byte_stream_next(grpc_exec_ctx *exec_ctx, - grpc_byte_stream *byte_stream, gpr_slice *slice, - size_t max_size_hint, grpc_closure *on_complete) { - return byte_stream->next(exec_ctx, byte_stream, slice, max_size_hint, - on_complete); -} - -void grpc_byte_stream_destroy(grpc_exec_ctx *exec_ctx, - grpc_byte_stream *byte_stream) { - byte_stream->destroy(exec_ctx, byte_stream); -} - -/* slice_buffer_stream */ - -static int slice_buffer_stream_next(grpc_exec_ctx *exec_ctx, - grpc_byte_stream *byte_stream, - gpr_slice *slice, size_t max_size_hint, - grpc_closure *on_complete) { - grpc_slice_buffer_stream *stream = (grpc_slice_buffer_stream *)byte_stream; - GPR_ASSERT(stream->cursor < stream->backing_buffer->count); - *slice = gpr_slice_ref(stream->backing_buffer->slices[stream->cursor]); - stream->cursor++; - return 1; -} - -static void slice_buffer_stream_destroy(grpc_exec_ctx *exec_ctx, - grpc_byte_stream *byte_stream) {} - -void grpc_slice_buffer_stream_init(grpc_slice_buffer_stream *stream, - gpr_slice_buffer *slice_buffer, - uint32_t flags) { - GPR_ASSERT(slice_buffer->length <= UINT32_MAX); - stream->base.length = (uint32_t)slice_buffer->length; - stream->base.flags = flags; - stream->base.next = slice_buffer_stream_next; - stream->base.destroy = slice_buffer_stream_destroy; - stream->backing_buffer = slice_buffer; - stream->cursor = 0; -} diff --git a/src/core/transport/byte_stream.h b/src/core/transport/byte_stream.h deleted file mode 100644 index ab42d07e7e..0000000000 --- a/src/core/transport/byte_stream.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * - * Copyright 2015-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_TRANSPORT_BYTE_STREAM_H -#define GRPC_CORE_TRANSPORT_BYTE_STREAM_H - -#include -#include "src/core/iomgr/exec_ctx.h" - -/** Internal bit flag for grpc_begin_message's \a flags signaling the use of - * compression for the message */ -#define GRPC_WRITE_INTERNAL_COMPRESS (0x80000000u) -/** Mask of all valid internal flags. */ -#define GRPC_WRITE_INTERNAL_USED_MASK (GRPC_WRITE_INTERNAL_COMPRESS) - -struct grpc_byte_stream; -typedef struct grpc_byte_stream grpc_byte_stream; - -struct grpc_byte_stream { - uint32_t length; - uint32_t flags; - int (*next)(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream, - gpr_slice *slice, size_t max_size_hint, - grpc_closure *on_complete); - void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream); -}; - -/* returns 1 if the bytes are available immediately (in which case - * on_complete will not be called), 0 if the bytes will be available - * asynchronously. - * - * on entry, *remaining can be set as a hint as to the maximum number - * of bytes that would be acceptable to read. - * - * fills *buffer, *length, *remaining with the bytes, length of bytes - * and length of data remaining to be read before either returning 1 - * or calling on_complete. - * - * once a slice is returned into *slice, it is owned by the caller. - */ -int grpc_byte_stream_next(grpc_exec_ctx *exec_ctx, - grpc_byte_stream *byte_stream, gpr_slice *slice, - size_t max_size_hint, grpc_closure *on_complete); - -void grpc_byte_stream_destroy(grpc_exec_ctx *exec_ctx, - grpc_byte_stream *byte_stream); - -/* grpc_byte_stream that wraps a slice buffer */ -typedef struct grpc_slice_buffer_stream { - grpc_byte_stream base; - gpr_slice_buffer *backing_buffer; - size_t cursor; -} grpc_slice_buffer_stream; - -void grpc_slice_buffer_stream_init(grpc_slice_buffer_stream *stream, - gpr_slice_buffer *slice_buffer, - uint32_t flags); - -#endif /* GRPC_CORE_TRANSPORT_BYTE_STREAM_H */ diff --git a/src/core/transport/chttp2/alpn.c b/src/core/transport/chttp2/alpn.c deleted file mode 100644 index 69da4e6718..0000000000 --- a/src/core/transport/chttp2/alpn.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/transport/chttp2/alpn.h" -#include -#include - -/* in order of preference */ -static const char *const supported_versions[] = {"h2"}; - -int grpc_chttp2_is_alpn_version_supported(const char *version, size_t size) { - size_t i; - for (i = 0; i < GPR_ARRAY_SIZE(supported_versions); i++) { - if (!strncmp(version, supported_versions[i], size)) return 1; - } - return 0; -} - -size_t grpc_chttp2_num_alpn_versions(void) { - return GPR_ARRAY_SIZE(supported_versions); -} - -const char *grpc_chttp2_get_alpn_version_index(size_t i) { - GPR_ASSERT(i < GPR_ARRAY_SIZE(supported_versions)); - return supported_versions[i]; -} diff --git a/src/core/transport/chttp2/alpn.h b/src/core/transport/chttp2/alpn.h deleted file mode 100644 index 68010e3155..0000000000 --- a/src/core/transport/chttp2/alpn.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * - * Copyright 2015-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_TRANSPORT_CHTTP2_ALPN_H -#define GRPC_CORE_TRANSPORT_CHTTP2_ALPN_H - -#include - -/* Retuns 1 if the version is supported, 0 otherwise. */ -int grpc_chttp2_is_alpn_version_supported(const char *version, size_t size); - -/* Returns the number of protocol versions to advertise */ -size_t grpc_chttp2_num_alpn_versions(void); - -/* Returns the protocol version at index i (0 <= i < - * grpc_chttp2_num_alpn_versions()) */ -const char *grpc_chttp2_get_alpn_version_index(size_t i); - -#endif /* GRPC_CORE_TRANSPORT_CHTTP2_ALPN_H */ diff --git a/src/core/transport/chttp2/bin_encoder.c b/src/core/transport/chttp2/bin_encoder.c deleted file mode 100644 index 3d31162499..0000000000 --- a/src/core/transport/chttp2/bin_encoder.c +++ /dev/null @@ -1,233 +0,0 @@ -/* - * - * Copyright 2015-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/transport/chttp2/bin_encoder.h" - -#include - -#include -#include "src/core/transport/chttp2/huffsyms.h" - -static const char alphabet[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -typedef struct { - uint16_t bits; - uint8_t length; -} b64_huff_sym; - -static const b64_huff_sym huff_alphabet[64] = { - {0x21, 6}, {0x5d, 7}, {0x5e, 7}, {0x5f, 7}, {0x60, 7}, {0x61, 7}, - {0x62, 7}, {0x63, 7}, {0x64, 7}, {0x65, 7}, {0x66, 7}, {0x67, 7}, - {0x68, 7}, {0x69, 7}, {0x6a, 7}, {0x6b, 7}, {0x6c, 7}, {0x6d, 7}, - {0x6e, 7}, {0x6f, 7}, {0x70, 7}, {0x71, 7}, {0x72, 7}, {0xfc, 8}, - {0x73, 7}, {0xfd, 8}, {0x3, 5}, {0x23, 6}, {0x4, 5}, {0x24, 6}, - {0x5, 5}, {0x25, 6}, {0x26, 6}, {0x27, 6}, {0x6, 5}, {0x74, 7}, - {0x75, 7}, {0x28, 6}, {0x29, 6}, {0x2a, 6}, {0x7, 5}, {0x2b, 6}, - {0x76, 7}, {0x2c, 6}, {0x8, 5}, {0x9, 5}, {0x2d, 6}, {0x77, 7}, - {0x78, 7}, {0x79, 7}, {0x7a, 7}, {0x7b, 7}, {0x0, 5}, {0x1, 5}, - {0x2, 5}, {0x19, 6}, {0x1a, 6}, {0x1b, 6}, {0x1c, 6}, {0x1d, 6}, - {0x1e, 6}, {0x1f, 6}, {0x7fb, 11}, {0x18, 6}}; - -static const uint8_t tail_xtra[3] = {0, 2, 3}; - -gpr_slice grpc_chttp2_base64_encode(gpr_slice input) { - size_t input_length = GPR_SLICE_LENGTH(input); - size_t input_triplets = input_length / 3; - size_t tail_case = input_length % 3; - size_t output_length = input_triplets * 4 + tail_xtra[tail_case]; - gpr_slice output = gpr_slice_malloc(output_length); - uint8_t *in = GPR_SLICE_START_PTR(input); - char *out = (char *)GPR_SLICE_START_PTR(output); - size_t i; - - /* encode full triplets */ - for (i = 0; i < input_triplets; i++) { - out[0] = alphabet[in[0] >> 2]; - out[1] = alphabet[((in[0] & 0x3) << 4) | (in[1] >> 4)]; - out[2] = alphabet[((in[1] & 0xf) << 2) | (in[2] >> 6)]; - out[3] = alphabet[in[2] & 0x3f]; - out += 4; - in += 3; - } - - /* encode the remaining bytes */ - switch (tail_case) { - case 0: - break; - case 1: - out[0] = alphabet[in[0] >> 2]; - out[1] = alphabet[(in[0] & 0x3) << 4]; - out += 2; - in += 1; - break; - case 2: - out[0] = alphabet[in[0] >> 2]; - out[1] = alphabet[((in[0] & 0x3) << 4) | (in[1] >> 4)]; - out[2] = alphabet[(in[1] & 0xf) << 2]; - out += 3; - in += 2; - break; - } - - GPR_ASSERT(out == (char *)GPR_SLICE_END_PTR(output)); - GPR_ASSERT(in == GPR_SLICE_END_PTR(input)); - return output; -} - -gpr_slice grpc_chttp2_huffman_compress(gpr_slice input) { - size_t nbits; - uint8_t *in; - uint8_t *out; - gpr_slice output; - uint32_t temp = 0; - uint32_t temp_length = 0; - - nbits = 0; - for (in = GPR_SLICE_START_PTR(input); in != GPR_SLICE_END_PTR(input); ++in) { - nbits += grpc_chttp2_huffsyms[*in].length; - } - - output = gpr_slice_malloc(nbits / 8 + (nbits % 8 != 0)); - out = GPR_SLICE_START_PTR(output); - for (in = GPR_SLICE_START_PTR(input); in != GPR_SLICE_END_PTR(input); ++in) { - int sym = *in; - temp <<= grpc_chttp2_huffsyms[sym].length; - temp |= grpc_chttp2_huffsyms[sym].bits; - temp_length += grpc_chttp2_huffsyms[sym].length; - - while (temp_length > 8) { - temp_length -= 8; - *out++ = (uint8_t)(temp >> temp_length); - } - } - - if (temp_length) { - /* NB: the following integer arithmetic operation needs to be in its - * expanded form due to the "integral promotion" performed (see section - * 3.2.1.1 of the C89 draft standard). A cast to the smaller container type - * is then required to avoid the compiler warning */ - *out++ = (uint8_t)((uint8_t)(temp << (8u - temp_length)) | - (uint8_t)(0xffu >> temp_length)); - } - - GPR_ASSERT(out == GPR_SLICE_END_PTR(output)); - - return output; -} - -typedef struct { - uint32_t temp; - uint32_t temp_length; - uint8_t *out; -} huff_out; - -static void enc_flush_some(huff_out *out) { - while (out->temp_length > 8) { - out->temp_length -= 8; - *out->out++ = (uint8_t)(out->temp >> out->temp_length); - } -} - -static void enc_add2(huff_out *out, uint8_t a, uint8_t b) { - b64_huff_sym sa = huff_alphabet[a]; - b64_huff_sym sb = huff_alphabet[b]; - out->temp = (out->temp << (sa.length + sb.length)) | - ((uint32_t)sa.bits << sb.length) | sb.bits; - out->temp_length += (uint32_t)sa.length + (uint32_t)sb.length; - enc_flush_some(out); -} - -static void enc_add1(huff_out *out, uint8_t a) { - b64_huff_sym sa = huff_alphabet[a]; - out->temp = (out->temp << sa.length) | sa.bits; - out->temp_length += sa.length; - enc_flush_some(out); -} - -gpr_slice grpc_chttp2_base64_encode_and_huffman_compress(gpr_slice input) { - size_t input_length = GPR_SLICE_LENGTH(input); - size_t input_triplets = input_length / 3; - size_t tail_case = input_length % 3; - size_t output_syms = input_triplets * 4 + tail_xtra[tail_case]; - size_t max_output_bits = 11 * output_syms; - size_t max_output_length = max_output_bits / 8 + (max_output_bits % 8 != 0); - gpr_slice output = gpr_slice_malloc(max_output_length); - uint8_t *in = GPR_SLICE_START_PTR(input); - uint8_t *start_out = GPR_SLICE_START_PTR(output); - huff_out out; - size_t i; - - out.temp = 0; - out.temp_length = 0; - out.out = start_out; - - /* encode full triplets */ - for (i = 0; i < input_triplets; i++) { - enc_add2(&out, in[0] >> 2, (uint8_t)((in[0] & 0x3) << 4) | (in[1] >> 4)); - enc_add2(&out, (uint8_t)((in[1] & 0xf) << 2) | (in[2] >> 6), - (uint8_t)(in[2] & 0x3f)); - in += 3; - } - - /* encode the remaining bytes */ - switch (tail_case) { - case 0: - break; - case 1: - enc_add2(&out, in[0] >> 2, (uint8_t)((in[0] & 0x3) << 4)); - in += 1; - break; - case 2: - enc_add2(&out, in[0] >> 2, - (uint8_t)((in[0] & 0x3) << 4) | (uint8_t)(in[1] >> 4)); - enc_add1(&out, (uint8_t)((in[1] & 0xf) << 2)); - in += 2; - break; - } - - if (out.temp_length) { - /* NB: the following integer arithmetic operation needs to be in its - * expanded form due to the "integral promotion" performed (see section - * 3.2.1.1 of the C89 draft standard). A cast to the smaller container type - * is then required to avoid the compiler warning */ - *out.out++ = (uint8_t)((uint8_t)(out.temp << (8u - out.temp_length)) | - (uint8_t)(0xffu >> out.temp_length)); - } - - GPR_ASSERT(out.out <= GPR_SLICE_END_PTR(output)); - GPR_SLICE_SET_LENGTH(output, out.out - start_out); - - GPR_ASSERT(in == GPR_SLICE_END_PTR(input)); - return output; -} diff --git a/src/core/transport/chttp2/bin_encoder.h b/src/core/transport/chttp2/bin_encoder.h deleted file mode 100644 index edb6f2dad1..0000000000 --- a/src/core/transport/chttp2/bin_encoder.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * - * Copyright 2015-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_TRANSPORT_CHTTP2_BIN_ENCODER_H -#define GRPC_CORE_TRANSPORT_CHTTP2_BIN_ENCODER_H - -#include - -/* base64 encode a slice. Returns a new slice, does not take ownership of the - input */ -gpr_slice grpc_chttp2_base64_encode(gpr_slice input); - -/* Compress a slice with the static huffman encoder detailed in the hpack - standard. Returns a new slice, does not take ownership of the input */ -gpr_slice grpc_chttp2_huffman_compress(gpr_slice input); - -/* equivalent to: - gpr_slice x = grpc_chttp2_base64_encode(input); - gpr_slice y = grpc_chttp2_huffman_compress(x); - gpr_slice_unref(x); - return y; */ -gpr_slice grpc_chttp2_base64_encode_and_huffman_compress(gpr_slice input); - -#endif /* GRPC_CORE_TRANSPORT_CHTTP2_BIN_ENCODER_H */ diff --git a/src/core/transport/chttp2/frame.h b/src/core/transport/chttp2/frame.h deleted file mode 100644 index 560a6675af..0000000000 --- a/src/core/transport/chttp2/frame.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * - * Copyright 2015-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_TRANSPORT_CHTTP2_FRAME_H -#define GRPC_CORE_TRANSPORT_CHTTP2_FRAME_H - -#include -#include - -/* Common definitions for frame handling in the chttp2 transport */ - -typedef enum { - GRPC_CHTTP2_PARSE_OK, - GRPC_CHTTP2_STREAM_ERROR, - GRPC_CHTTP2_CONNECTION_ERROR -} grpc_chttp2_parse_error; - -/* defined in internal.h */ -typedef struct grpc_chttp2_stream_parsing grpc_chttp2_stream_parsing; -typedef struct grpc_chttp2_transport_parsing grpc_chttp2_transport_parsing; - -#define GRPC_CHTTP2_FRAME_DATA 0 -#define GRPC_CHTTP2_FRAME_HEADER 1 -#define GRPC_CHTTP2_FRAME_CONTINUATION 9 -#define GRPC_CHTTP2_FRAME_RST_STREAM 3 -#define GRPC_CHTTP2_FRAME_SETTINGS 4 -#define GRPC_CHTTP2_FRAME_PING 6 -#define GRPC_CHTTP2_FRAME_GOAWAY 7 -#define GRPC_CHTTP2_FRAME_WINDOW_UPDATE 8 - -#define GRPC_CHTTP2_MAX_PAYLOAD_LENGTH ((1 << 14) - 1) - -#define GRPC_CHTTP2_DATA_FLAG_END_STREAM 1 -#define GRPC_CHTTP2_FLAG_ACK 1 -#define GRPC_CHTTP2_DATA_FLAG_END_HEADERS 4 -#define GRPC_CHTTP2_DATA_FLAG_PADDED 8 -#define GRPC_CHTTP2_FLAG_HAS_PRIORITY 0x20 - -#endif /* GRPC_CORE_TRANSPORT_CHTTP2_FRAME_H */ diff --git a/src/core/transport/chttp2/frame_data.c b/src/core/transport/chttp2/frame_data.c deleted file mode 100644 index 6cc6d4eaf2..0000000000 --- a/src/core/transport/chttp2/frame_data.c +++ /dev/null @@ -1,248 +0,0 @@ -/* - * - * Copyright 2015-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/transport/chttp2/frame_data.h" - -#include - -#include -#include -#include -#include "src/core/support/string.h" -#include "src/core/transport/chttp2/internal.h" -#include "src/core/transport/transport.h" - -grpc_chttp2_parse_error grpc_chttp2_data_parser_init( - grpc_chttp2_data_parser *parser) { - parser->state = GRPC_CHTTP2_DATA_FH_0; - parser->parsing_frame = NULL; - return GRPC_CHTTP2_PARSE_OK; -} - -void grpc_chttp2_data_parser_destroy(grpc_exec_ctx *exec_ctx, - grpc_chttp2_data_parser *parser) { - grpc_byte_stream *bs; - if (parser->parsing_frame) { - grpc_chttp2_incoming_byte_stream_finished(exec_ctx, parser->parsing_frame, - 0, 1); - } - while ( - (bs = grpc_chttp2_incoming_frame_queue_pop(&parser->incoming_frames))) { - grpc_byte_stream_destroy(exec_ctx, bs); - } -} - -grpc_chttp2_parse_error grpc_chttp2_data_parser_begin_frame( - grpc_chttp2_data_parser *parser, uint8_t flags) { - if (flags & ~GRPC_CHTTP2_DATA_FLAG_END_STREAM) { - gpr_log(GPR_ERROR, "unsupported data flags: 0x%02x", flags); - return GRPC_CHTTP2_STREAM_ERROR; - } - - if (flags & GRPC_CHTTP2_DATA_FLAG_END_STREAM) { - parser->is_last_frame = 1; - } else { - parser->is_last_frame = 0; - } - - return GRPC_CHTTP2_PARSE_OK; -} - -void grpc_chttp2_incoming_frame_queue_merge( - grpc_chttp2_incoming_frame_queue *head_dst, - grpc_chttp2_incoming_frame_queue *tail_src) { - if (tail_src->head == NULL) { - return; - } - - if (head_dst->head == NULL) { - *head_dst = *tail_src; - memset(tail_src, 0, sizeof(*tail_src)); - return; - } - - head_dst->tail->next_message = tail_src->head; - head_dst->tail = tail_src->tail; - memset(tail_src, 0, sizeof(*tail_src)); -} - -grpc_byte_stream *grpc_chttp2_incoming_frame_queue_pop( - grpc_chttp2_incoming_frame_queue *q) { - grpc_byte_stream *out; - if (q->head == NULL) { - return NULL; - } - out = &q->head->base; - if (q->head == q->tail) { - memset(q, 0, sizeof(*q)); - } else { - q->head = q->head->next_message; - } - return out; -} - -void grpc_chttp2_encode_data(uint32_t id, gpr_slice_buffer *inbuf, - uint32_t write_bytes, int is_eof, - gpr_slice_buffer *outbuf) { - gpr_slice hdr; - uint8_t *p; - - hdr = gpr_slice_malloc(9); - p = GPR_SLICE_START_PTR(hdr); - GPR_ASSERT(write_bytes < (1 << 24)); - *p++ = (uint8_t)(write_bytes >> 16); - *p++ = (uint8_t)(write_bytes >> 8); - *p++ = (uint8_t)(write_bytes); - *p++ = GRPC_CHTTP2_FRAME_DATA; - *p++ = is_eof ? GRPC_CHTTP2_DATA_FLAG_END_STREAM : 0; - *p++ = (uint8_t)(id >> 24); - *p++ = (uint8_t)(id >> 16); - *p++ = (uint8_t)(id >> 8); - *p++ = (uint8_t)(id); - gpr_slice_buffer_add(outbuf, hdr); - - gpr_slice_buffer_move_first(inbuf, write_bytes, outbuf); -} - -grpc_chttp2_parse_error grpc_chttp2_data_parser_parse( - grpc_exec_ctx *exec_ctx, void *parser, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { - uint8_t *const beg = GPR_SLICE_START_PTR(slice); - uint8_t *const end = GPR_SLICE_END_PTR(slice); - uint8_t *cur = beg; - grpc_chttp2_data_parser *p = parser; - uint32_t message_flags; - grpc_chttp2_incoming_byte_stream *incoming_byte_stream; - - if (is_last && p->is_last_frame) { - stream_parsing->received_close = 1; - } - - if (cur == end) { - return GRPC_CHTTP2_PARSE_OK; - } - - switch (p->state) { - fh_0: - case GRPC_CHTTP2_DATA_FH_0: - p->frame_type = *cur; - switch (p->frame_type) { - case 0: - p->is_frame_compressed = 0; /* GPR_FALSE */ - break; - case 1: - p->is_frame_compressed = 1; /* GPR_TRUE */ - break; - default: - gpr_log(GPR_ERROR, "Bad GRPC frame type 0x%02x", p->frame_type); - return GRPC_CHTTP2_STREAM_ERROR; - } - if (++cur == end) { - p->state = GRPC_CHTTP2_DATA_FH_1; - return GRPC_CHTTP2_PARSE_OK; - } - /* fallthrough */ - case GRPC_CHTTP2_DATA_FH_1: - p->frame_size = ((uint32_t)*cur) << 24; - if (++cur == end) { - p->state = GRPC_CHTTP2_DATA_FH_2; - return GRPC_CHTTP2_PARSE_OK; - } - /* fallthrough */ - case GRPC_CHTTP2_DATA_FH_2: - p->frame_size |= ((uint32_t)*cur) << 16; - if (++cur == end) { - p->state = GRPC_CHTTP2_DATA_FH_3; - return GRPC_CHTTP2_PARSE_OK; - } - /* fallthrough */ - case GRPC_CHTTP2_DATA_FH_3: - p->frame_size |= ((uint32_t)*cur) << 8; - if (++cur == end) { - p->state = GRPC_CHTTP2_DATA_FH_4; - return GRPC_CHTTP2_PARSE_OK; - } - /* fallthrough */ - case GRPC_CHTTP2_DATA_FH_4: - p->frame_size |= ((uint32_t)*cur); - p->state = GRPC_CHTTP2_DATA_FRAME; - ++cur; - message_flags = 0; - if (p->is_frame_compressed) { - message_flags |= GRPC_WRITE_INTERNAL_COMPRESS; - } - p->parsing_frame = incoming_byte_stream = - grpc_chttp2_incoming_byte_stream_create( - exec_ctx, transport_parsing, stream_parsing, p->frame_size, - message_flags, &p->incoming_frames); - /* fallthrough */ - case GRPC_CHTTP2_DATA_FRAME: - if (cur == end) { - grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, - stream_parsing); - return GRPC_CHTTP2_PARSE_OK; - } - grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, - stream_parsing); - if ((uint32_t)(end - cur) == p->frame_size) { - grpc_chttp2_incoming_byte_stream_push( - exec_ctx, p->parsing_frame, - gpr_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg))); - grpc_chttp2_incoming_byte_stream_finished(exec_ctx, p->parsing_frame, 1, - 1); - p->parsing_frame = NULL; - p->state = GRPC_CHTTP2_DATA_FH_0; - return GRPC_CHTTP2_PARSE_OK; - } else if ((uint32_t)(end - cur) > p->frame_size) { - grpc_chttp2_incoming_byte_stream_push( - exec_ctx, p->parsing_frame, - gpr_slice_sub(slice, (size_t)(cur - beg), - (size_t)(cur + p->frame_size - beg))); - grpc_chttp2_incoming_byte_stream_finished(exec_ctx, p->parsing_frame, 1, - 1); - p->parsing_frame = NULL; - cur += p->frame_size; - goto fh_0; /* loop */ - } else { - grpc_chttp2_incoming_byte_stream_push( - exec_ctx, p->parsing_frame, - gpr_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg))); - GPR_ASSERT((size_t)(end - cur) <= p->frame_size); - p->frame_size -= (uint32_t)(end - cur); - return GRPC_CHTTP2_PARSE_OK; - } - } - - GPR_UNREACHABLE_CODE(return GRPC_CHTTP2_CONNECTION_ERROR); -} diff --git a/src/core/transport/chttp2/frame_data.h b/src/core/transport/chttp2/frame_data.h deleted file mode 100644 index 9dbaa60d44..0000000000 --- a/src/core/transport/chttp2/frame_data.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * - * Copyright 2015-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_TRANSPORT_CHTTP2_FRAME_DATA_H -#define GRPC_CORE_TRANSPORT_CHTTP2_FRAME_DATA_H - -/* Parser for GRPC streams embedded in DATA frames */ - -#include -#include -#include "src/core/iomgr/exec_ctx.h" -#include "src/core/transport/byte_stream.h" -#include "src/core/transport/chttp2/frame.h" - -typedef enum { - GRPC_CHTTP2_DATA_FH_0, - GRPC_CHTTP2_DATA_FH_1, - GRPC_CHTTP2_DATA_FH_2, - GRPC_CHTTP2_DATA_FH_3, - GRPC_CHTTP2_DATA_FH_4, - GRPC_CHTTP2_DATA_FRAME -} grpc_chttp2_stream_state; - -typedef struct grpc_chttp2_incoming_byte_stream - grpc_chttp2_incoming_byte_stream; - -typedef struct grpc_chttp2_incoming_frame_queue { - grpc_chttp2_incoming_byte_stream *head; - grpc_chttp2_incoming_byte_stream *tail; -} grpc_chttp2_incoming_frame_queue; - -typedef struct { - grpc_chttp2_stream_state state; - uint8_t is_last_frame; - uint8_t frame_type; - uint32_t frame_size; - - int is_frame_compressed; - grpc_chttp2_incoming_frame_queue incoming_frames; - grpc_chttp2_incoming_byte_stream *parsing_frame; -} grpc_chttp2_data_parser; - -void grpc_chttp2_incoming_frame_queue_merge( - grpc_chttp2_incoming_frame_queue *head_dst, - grpc_chttp2_incoming_frame_queue *tail_src); -grpc_byte_stream *grpc_chttp2_incoming_frame_queue_pop( - grpc_chttp2_incoming_frame_queue *q); - -/* initialize per-stream state for data frame parsing */ -grpc_chttp2_parse_error grpc_chttp2_data_parser_init( - grpc_chttp2_data_parser *parser); - -void grpc_chttp2_data_parser_destroy(grpc_exec_ctx *exec_ctx, - grpc_chttp2_data_parser *parser); - -/* start processing a new data frame */ -grpc_chttp2_parse_error grpc_chttp2_data_parser_begin_frame( - grpc_chttp2_data_parser *parser, uint8_t flags); - -/* handle a slice of a data frame - is_last indicates the last slice of a - frame */ -grpc_chttp2_parse_error grpc_chttp2_data_parser_parse( - grpc_exec_ctx *exec_ctx, void *parser, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); - -void grpc_chttp2_encode_data(uint32_t id, gpr_slice_buffer *inbuf, - uint32_t write_bytes, int is_eof, - gpr_slice_buffer *outbuf); - -#endif /* GRPC_CORE_TRANSPORT_CHTTP2_FRAME_DATA_H */ diff --git a/src/core/transport/chttp2/frame_goaway.c b/src/core/transport/chttp2/frame_goaway.c deleted file mode 100644 index 2fa525e989..0000000000 --- a/src/core/transport/chttp2/frame_goaway.c +++ /dev/null @@ -1,193 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/transport/chttp2/frame_goaway.h" -#include "src/core/transport/chttp2/internal.h" - -#include - -#include -#include - -void grpc_chttp2_goaway_parser_init(grpc_chttp2_goaway_parser *p) { - p->debug_data = NULL; -} - -void grpc_chttp2_goaway_parser_destroy(grpc_chttp2_goaway_parser *p) { - gpr_free(p->debug_data); -} - -grpc_chttp2_parse_error grpc_chttp2_goaway_parser_begin_frame( - grpc_chttp2_goaway_parser *p, uint32_t length, uint8_t flags) { - if (length < 8) { - gpr_log(GPR_ERROR, "goaway frame too short (%d bytes)", length); - return GRPC_CHTTP2_CONNECTION_ERROR; - } - - gpr_free(p->debug_data); - p->debug_length = length - 8; - p->debug_data = gpr_malloc(p->debug_length); - p->debug_pos = 0; - p->state = GRPC_CHTTP2_GOAWAY_LSI0; - return GRPC_CHTTP2_PARSE_OK; -} - -grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse( - grpc_exec_ctx *exec_ctx, void *parser, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { - uint8_t *const beg = GPR_SLICE_START_PTR(slice); - uint8_t *const end = GPR_SLICE_END_PTR(slice); - uint8_t *cur = beg; - grpc_chttp2_goaway_parser *p = parser; - - switch (p->state) { - case GRPC_CHTTP2_GOAWAY_LSI0: - if (cur == end) { - p->state = GRPC_CHTTP2_GOAWAY_LSI0; - return GRPC_CHTTP2_PARSE_OK; - } - p->last_stream_id = ((uint32_t)*cur) << 24; - ++cur; - /* fallthrough */ - case GRPC_CHTTP2_GOAWAY_LSI1: - if (cur == end) { - p->state = GRPC_CHTTP2_GOAWAY_LSI1; - return GRPC_CHTTP2_PARSE_OK; - } - p->last_stream_id |= ((uint32_t)*cur) << 16; - ++cur; - /* fallthrough */ - case GRPC_CHTTP2_GOAWAY_LSI2: - if (cur == end) { - p->state = GRPC_CHTTP2_GOAWAY_LSI2; - return GRPC_CHTTP2_PARSE_OK; - } - p->last_stream_id |= ((uint32_t)*cur) << 8; - ++cur; - /* fallthrough */ - case GRPC_CHTTP2_GOAWAY_LSI3: - if (cur == end) { - p->state = GRPC_CHTTP2_GOAWAY_LSI3; - return GRPC_CHTTP2_PARSE_OK; - } - p->last_stream_id |= ((uint32_t)*cur); - ++cur; - /* fallthrough */ - case GRPC_CHTTP2_GOAWAY_ERR0: - if (cur == end) { - p->state = GRPC_CHTTP2_GOAWAY_ERR0; - return GRPC_CHTTP2_PARSE_OK; - } - p->error_code = ((uint32_t)*cur) << 24; - ++cur; - /* fallthrough */ - case GRPC_CHTTP2_GOAWAY_ERR1: - if (cur == end) { - p->state = GRPC_CHTTP2_GOAWAY_ERR1; - return GRPC_CHTTP2_PARSE_OK; - } - p->error_code |= ((uint32_t)*cur) << 16; - ++cur; - /* fallthrough */ - case GRPC_CHTTP2_GOAWAY_ERR2: - if (cur == end) { - p->state = GRPC_CHTTP2_GOAWAY_ERR2; - return GRPC_CHTTP2_PARSE_OK; - } - p->error_code |= ((uint32_t)*cur) << 8; - ++cur; - /* fallthrough */ - case GRPC_CHTTP2_GOAWAY_ERR3: - if (cur == end) { - p->state = GRPC_CHTTP2_GOAWAY_ERR3; - return GRPC_CHTTP2_PARSE_OK; - } - p->error_code |= ((uint32_t)*cur); - ++cur; - /* fallthrough */ - case GRPC_CHTTP2_GOAWAY_DEBUG: - memcpy(p->debug_data + p->debug_pos, cur, (size_t)(end - cur)); - GPR_ASSERT((size_t)(end - cur) < UINT32_MAX - p->debug_pos); - p->debug_pos += (uint32_t)(end - cur); - p->state = GRPC_CHTTP2_GOAWAY_DEBUG; - if (is_last) { - transport_parsing->goaway_received = 1; - transport_parsing->goaway_last_stream_index = p->last_stream_id; - gpr_slice_unref(transport_parsing->goaway_text); - transport_parsing->goaway_error = (grpc_status_code)p->error_code; - transport_parsing->goaway_text = - gpr_slice_new(p->debug_data, p->debug_length, gpr_free); - p->debug_data = NULL; - } - return GRPC_CHTTP2_PARSE_OK; - } - GPR_UNREACHABLE_CODE(return GRPC_CHTTP2_CONNECTION_ERROR); -} - -void grpc_chttp2_goaway_append(uint32_t last_stream_id, uint32_t error_code, - gpr_slice debug_data, - gpr_slice_buffer *slice_buffer) { - gpr_slice header = gpr_slice_malloc(9 + 4 + 4); - uint8_t *p = GPR_SLICE_START_PTR(header); - uint32_t frame_length; - GPR_ASSERT(GPR_SLICE_LENGTH(debug_data) < UINT32_MAX - 4 - 4); - frame_length = 4 + 4 + (uint32_t)GPR_SLICE_LENGTH(debug_data); - - /* frame header: length */ - *p++ = (uint8_t)(frame_length >> 16); - *p++ = (uint8_t)(frame_length >> 8); - *p++ = (uint8_t)(frame_length); - /* frame header: type */ - *p++ = GRPC_CHTTP2_FRAME_GOAWAY; - /* frame header: flags */ - *p++ = 0; - /* frame header: stream id */ - *p++ = 0; - *p++ = 0; - *p++ = 0; - *p++ = 0; - /* payload: last stream id */ - *p++ = (uint8_t)(last_stream_id >> 24); - *p++ = (uint8_t)(last_stream_id >> 16); - *p++ = (uint8_t)(last_stream_id >> 8); - *p++ = (uint8_t)(last_stream_id); - /* payload: error code */ - *p++ = (uint8_t)(error_code >> 24); - *p++ = (uint8_t)(error_code >> 16); - *p++ = (uint8_t)(error_code >> 8); - *p++ = (uint8_t)(error_code); - GPR_ASSERT(p == GPR_SLICE_END_PTR(header)); - gpr_slice_buffer_add(slice_buffer, header); - gpr_slice_buffer_add(slice_buffer, debug_data); -} diff --git a/src/core/transport/chttp2/frame_goaway.h b/src/core/transport/chttp2/frame_goaway.h deleted file mode 100644 index b980e47723..0000000000 --- a/src/core/transport/chttp2/frame_goaway.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * - * Copyright 2015-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_TRANSPORT_CHTTP2_FRAME_GOAWAY_H -#define GRPC_CORE_TRANSPORT_CHTTP2_FRAME_GOAWAY_H - -#include -#include -#include -#include "src/core/iomgr/exec_ctx.h" -#include "src/core/transport/chttp2/frame.h" - -typedef enum { - GRPC_CHTTP2_GOAWAY_LSI0, - GRPC_CHTTP2_GOAWAY_LSI1, - GRPC_CHTTP2_GOAWAY_LSI2, - GRPC_CHTTP2_GOAWAY_LSI3, - GRPC_CHTTP2_GOAWAY_ERR0, - GRPC_CHTTP2_GOAWAY_ERR1, - GRPC_CHTTP2_GOAWAY_ERR2, - GRPC_CHTTP2_GOAWAY_ERR3, - GRPC_CHTTP2_GOAWAY_DEBUG -} grpc_chttp2_goaway_parse_state; - -typedef struct { - grpc_chttp2_goaway_parse_state state; - uint32_t last_stream_id; - uint32_t error_code; - char *debug_data; - uint32_t debug_length; - uint32_t debug_pos; -} grpc_chttp2_goaway_parser; - -void grpc_chttp2_goaway_parser_init(grpc_chttp2_goaway_parser *p); -void grpc_chttp2_goaway_parser_destroy(grpc_chttp2_goaway_parser *p); -grpc_chttp2_parse_error grpc_chttp2_goaway_parser_begin_frame( - grpc_chttp2_goaway_parser *parser, uint32_t length, uint8_t flags); -grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse( - grpc_exec_ctx *exec_ctx, void *parser, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); - -void grpc_chttp2_goaway_append(uint32_t last_stream_id, uint32_t error_code, - gpr_slice debug_data, - gpr_slice_buffer *slice_buffer); - -#endif /* GRPC_CORE_TRANSPORT_CHTTP2_FRAME_GOAWAY_H */ diff --git a/src/core/transport/chttp2/frame_ping.c b/src/core/transport/chttp2/frame_ping.c deleted file mode 100644 index c6ab522283..0000000000 --- a/src/core/transport/chttp2/frame_ping.c +++ /dev/null @@ -1,97 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/transport/chttp2/frame_ping.h" -#include "src/core/transport/chttp2/internal.h" - -#include - -#include -#include - -gpr_slice grpc_chttp2_ping_create(uint8_t ack, uint8_t *opaque_8bytes) { - gpr_slice slice = gpr_slice_malloc(9 + 8); - uint8_t *p = GPR_SLICE_START_PTR(slice); - - *p++ = 0; - *p++ = 0; - *p++ = 8; - *p++ = GRPC_CHTTP2_FRAME_PING; - *p++ = ack ? 1 : 0; - *p++ = 0; - *p++ = 0; - *p++ = 0; - *p++ = 0; - memcpy(p, opaque_8bytes, 8); - - return slice; -} - -grpc_chttp2_parse_error grpc_chttp2_ping_parser_begin_frame( - grpc_chttp2_ping_parser *parser, uint32_t length, uint8_t flags) { - if (flags & 0xfe || length != 8) { - gpr_log(GPR_ERROR, "invalid ping: length=%d, flags=%02x", length, flags); - return GRPC_CHTTP2_CONNECTION_ERROR; - } - parser->byte = 0; - parser->is_ack = flags; - return GRPC_CHTTP2_PARSE_OK; -} - -grpc_chttp2_parse_error grpc_chttp2_ping_parser_parse( - grpc_exec_ctx *exec_ctx, void *parser, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { - uint8_t *const beg = GPR_SLICE_START_PTR(slice); - uint8_t *const end = GPR_SLICE_END_PTR(slice); - uint8_t *cur = beg; - grpc_chttp2_ping_parser *p = parser; - - while (p->byte != 8 && cur != end) { - p->opaque_8bytes[p->byte] = *cur; - cur++; - p->byte++; - } - - if (p->byte == 8) { - GPR_ASSERT(is_last); - if (p->is_ack) { - grpc_chttp2_ack_ping(exec_ctx, transport_parsing, p->opaque_8bytes); - } else { - gpr_slice_buffer_add(&transport_parsing->qbuf, - grpc_chttp2_ping_create(1, p->opaque_8bytes)); - } - } - - return GRPC_CHTTP2_PARSE_OK; -} diff --git a/src/core/transport/chttp2/frame_ping.h b/src/core/transport/chttp2/frame_ping.h deleted file mode 100644 index 2412cd7a6f..0000000000 --- a/src/core/transport/chttp2/frame_ping.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * - * Copyright 2015-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_TRANSPORT_CHTTP2_FRAME_PING_H -#define GRPC_CORE_TRANSPORT_CHTTP2_FRAME_PING_H - -#include -#include "src/core/iomgr/exec_ctx.h" -#include "src/core/transport/chttp2/frame.h" - -typedef struct { - uint8_t byte; - uint8_t is_ack; - uint8_t opaque_8bytes[8]; -} grpc_chttp2_ping_parser; - -gpr_slice grpc_chttp2_ping_create(uint8_t ack, uint8_t *opaque_8bytes); - -grpc_chttp2_parse_error grpc_chttp2_ping_parser_begin_frame( - grpc_chttp2_ping_parser *parser, uint32_t length, uint8_t flags); -grpc_chttp2_parse_error grpc_chttp2_ping_parser_parse( - grpc_exec_ctx *exec_ctx, void *parser, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); - -#endif /* GRPC_CORE_TRANSPORT_CHTTP2_FRAME_PING_H */ diff --git a/src/core/transport/chttp2/frame_rst_stream.c b/src/core/transport/chttp2/frame_rst_stream.c deleted file mode 100644 index 754529e4b9..0000000000 --- a/src/core/transport/chttp2/frame_rst_stream.c +++ /dev/null @@ -1,99 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/transport/chttp2/frame_rst_stream.h" -#include "src/core/transport/chttp2/internal.h" - -#include - -#include "src/core/transport/chttp2/frame.h" - -gpr_slice grpc_chttp2_rst_stream_create(uint32_t id, uint32_t code) { - gpr_slice slice = gpr_slice_malloc(13); - uint8_t *p = GPR_SLICE_START_PTR(slice); - - *p++ = 0; - *p++ = 0; - *p++ = 4; - *p++ = GRPC_CHTTP2_FRAME_RST_STREAM; - *p++ = 0; - *p++ = (uint8_t)(id >> 24); - *p++ = (uint8_t)(id >> 16); - *p++ = (uint8_t)(id >> 8); - *p++ = (uint8_t)(id); - *p++ = (uint8_t)(code >> 24); - *p++ = (uint8_t)(code >> 16); - *p++ = (uint8_t)(code >> 8); - *p++ = (uint8_t)(code); - - return slice; -} - -grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_begin_frame( - grpc_chttp2_rst_stream_parser *parser, uint32_t length, uint8_t flags) { - if (length != 4) { - gpr_log(GPR_ERROR, "invalid rst_stream: length=%d, flags=%02x", length, - flags); - return GRPC_CHTTP2_CONNECTION_ERROR; - } - parser->byte = 0; - return GRPC_CHTTP2_PARSE_OK; -} - -grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_parse( - grpc_exec_ctx *exec_ctx, void *parser, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { - uint8_t *const beg = GPR_SLICE_START_PTR(slice); - uint8_t *const end = GPR_SLICE_END_PTR(slice); - uint8_t *cur = beg; - grpc_chttp2_rst_stream_parser *p = parser; - - while (p->byte != 4 && cur != end) { - p->reason_bytes[p->byte] = *cur; - cur++; - p->byte++; - } - - if (p->byte == 4) { - GPR_ASSERT(is_last); - stream_parsing->received_close = 1; - stream_parsing->saw_rst_stream = 1; - stream_parsing->rst_stream_reason = (((uint32_t)p->reason_bytes[0]) << 24) | - (((uint32_t)p->reason_bytes[1]) << 16) | - (((uint32_t)p->reason_bytes[2]) << 8) | - (((uint32_t)p->reason_bytes[3])); - } - - return GRPC_CHTTP2_PARSE_OK; -} diff --git a/src/core/transport/chttp2/frame_rst_stream.h b/src/core/transport/chttp2/frame_rst_stream.h deleted file mode 100644 index f725c5d767..0000000000 --- a/src/core/transport/chttp2/frame_rst_stream.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * - * Copyright 2015-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_TRANSPORT_CHTTP2_FRAME_RST_STREAM_H -#define GRPC_CORE_TRANSPORT_CHTTP2_FRAME_RST_STREAM_H - -#include -#include "src/core/iomgr/exec_ctx.h" -#include "src/core/transport/chttp2/frame.h" - -typedef struct { - uint8_t byte; - uint8_t reason_bytes[4]; -} grpc_chttp2_rst_stream_parser; - -gpr_slice grpc_chttp2_rst_stream_create(uint32_t stream_id, uint32_t code); - -grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_begin_frame( - grpc_chttp2_rst_stream_parser *parser, uint32_t length, uint8_t flags); -grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_parse( - grpc_exec_ctx *exec_ctx, void *parser, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); - -#endif /* GRPC_CORE_TRANSPORT_CHTTP2_FRAME_RST_STREAM_H */ diff --git a/src/core/transport/chttp2/frame_settings.c b/src/core/transport/chttp2/frame_settings.c deleted file mode 100644 index cc49dd4f69..0000000000 --- a/src/core/transport/chttp2/frame_settings.c +++ /dev/null @@ -1,259 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/transport/chttp2/frame_settings.h" -#include "src/core/transport/chttp2/internal.h" - -#include - -#include -#include - -#include "src/core/debug/trace.h" -#include "src/core/transport/chttp2/frame.h" -#include "src/core/transport/chttp2/http2_errors.h" -#include "src/core/transport/chttp2_transport.h" - -#define MAX_MAX_HEADER_LIST_SIZE (1024 * 1024 * 1024) - -/* HTTP/2 mandated initial connection settings */ -const grpc_chttp2_setting_parameters - grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS] = { - {NULL, 0, 0, 0, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, - GRPC_CHTTP2_PROTOCOL_ERROR}, - {"HEADER_TABLE_SIZE", 4096, 0, 0xffffffff, - GRPC_CHTTP2_CLAMP_INVALID_VALUE, GRPC_CHTTP2_PROTOCOL_ERROR}, - {"ENABLE_PUSH", 1, 0, 1, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, - GRPC_CHTTP2_PROTOCOL_ERROR}, - {"MAX_CONCURRENT_STREAMS", 0xffffffffu, 0, 0xffffffffu, - GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, GRPC_CHTTP2_PROTOCOL_ERROR}, - {"INITIAL_WINDOW_SIZE", 65535, 0, 0x7fffffffu, - GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, - GRPC_CHTTP2_FLOW_CONTROL_ERROR}, - {"MAX_FRAME_SIZE", 16384, 16384, 16777215, - GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, GRPC_CHTTP2_PROTOCOL_ERROR}, - {"MAX_HEADER_LIST_SIZE", MAX_MAX_HEADER_LIST_SIZE, 0, - MAX_MAX_HEADER_LIST_SIZE, GRPC_CHTTP2_CLAMP_INVALID_VALUE, - GRPC_CHTTP2_PROTOCOL_ERROR}, -}; - -static uint8_t *fill_header(uint8_t *out, uint32_t length, uint8_t flags) { - *out++ = (uint8_t)(length >> 16); - *out++ = (uint8_t)(length >> 8); - *out++ = (uint8_t)(length); - *out++ = GRPC_CHTTP2_FRAME_SETTINGS; - *out++ = flags; - *out++ = 0; - *out++ = 0; - *out++ = 0; - *out++ = 0; - return out; -} - -gpr_slice grpc_chttp2_settings_create(uint32_t *old, const uint32_t *new, - uint32_t force_mask, size_t count) { - size_t i; - uint32_t n = 0; - gpr_slice output; - uint8_t *p; - - for (i = 0; i < count; i++) { - n += (new[i] != old[i] || (force_mask & (1u << i)) != 0); - } - - output = gpr_slice_malloc(9 + 6 * n); - p = fill_header(GPR_SLICE_START_PTR(output), 6 * n, 0); - - for (i = 0; i < count; i++) { - if (new[i] != old[i] || (force_mask & (1u << i)) != 0) { - GPR_ASSERT(i); - *p++ = (uint8_t)(i >> 8); - *p++ = (uint8_t)(i); - *p++ = (uint8_t)(new[i] >> 24); - *p++ = (uint8_t)(new[i] >> 16); - *p++ = (uint8_t)(new[i] >> 8); - *p++ = (uint8_t)(new[i]); - old[i] = new[i]; - } - } - - GPR_ASSERT(p == GPR_SLICE_END_PTR(output)); - - return output; -} - -gpr_slice grpc_chttp2_settings_ack_create(void) { - gpr_slice output = gpr_slice_malloc(9); - fill_header(GPR_SLICE_START_PTR(output), 0, GRPC_CHTTP2_FLAG_ACK); - return output; -} - -grpc_chttp2_parse_error grpc_chttp2_settings_parser_begin_frame( - grpc_chttp2_settings_parser *parser, uint32_t length, uint8_t flags, - uint32_t *settings) { - parser->target_settings = settings; - memcpy(parser->incoming_settings, settings, - GRPC_CHTTP2_NUM_SETTINGS * sizeof(uint32_t)); - parser->is_ack = 0; - parser->state = GRPC_CHTTP2_SPS_ID0; - if (flags == GRPC_CHTTP2_FLAG_ACK) { - parser->is_ack = 1; - if (length != 0) { - gpr_log(GPR_ERROR, "non-empty settings ack frame received"); - return GRPC_CHTTP2_CONNECTION_ERROR; - } - return GRPC_CHTTP2_PARSE_OK; - } else if (flags != 0) { - gpr_log(GPR_ERROR, "invalid flags on settings frame"); - return GRPC_CHTTP2_CONNECTION_ERROR; - } else if (length % 6 != 0) { - gpr_log(GPR_ERROR, "settings frames must be a multiple of six bytes"); - return GRPC_CHTTP2_CONNECTION_ERROR; - } else { - return GRPC_CHTTP2_PARSE_OK; - } -} - -grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse( - grpc_exec_ctx *exec_ctx, void *p, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { - grpc_chttp2_settings_parser *parser = p; - const uint8_t *cur = GPR_SLICE_START_PTR(slice); - const uint8_t *end = GPR_SLICE_END_PTR(slice); - - if (parser->is_ack) { - return GRPC_CHTTP2_PARSE_OK; - } - - for (;;) { - switch (parser->state) { - case GRPC_CHTTP2_SPS_ID0: - if (cur == end) { - parser->state = GRPC_CHTTP2_SPS_ID0; - if (is_last) { - transport_parsing->settings_updated = 1; - memcpy(parser->target_settings, parser->incoming_settings, - GRPC_CHTTP2_NUM_SETTINGS * sizeof(uint32_t)); - gpr_slice_buffer_add(&transport_parsing->qbuf, - grpc_chttp2_settings_ack_create()); - } - return GRPC_CHTTP2_PARSE_OK; - } - parser->id = (uint16_t)(((uint16_t)*cur) << 8); - cur++; - /* fallthrough */ - case GRPC_CHTTP2_SPS_ID1: - if (cur == end) { - parser->state = GRPC_CHTTP2_SPS_ID1; - return GRPC_CHTTP2_PARSE_OK; - } - parser->id = (uint16_t)(parser->id | (*cur)); - cur++; - /* fallthrough */ - case GRPC_CHTTP2_SPS_VAL0: - if (cur == end) { - parser->state = GRPC_CHTTP2_SPS_VAL0; - return GRPC_CHTTP2_PARSE_OK; - } - parser->value = ((uint32_t)*cur) << 24; - cur++; - /* fallthrough */ - case GRPC_CHTTP2_SPS_VAL1: - if (cur == end) { - parser->state = GRPC_CHTTP2_SPS_VAL1; - return GRPC_CHTTP2_PARSE_OK; - } - parser->value |= ((uint32_t)*cur) << 16; - cur++; - /* fallthrough */ - case GRPC_CHTTP2_SPS_VAL2: - if (cur == end) { - parser->state = GRPC_CHTTP2_SPS_VAL2; - return GRPC_CHTTP2_PARSE_OK; - } - parser->value |= ((uint32_t)*cur) << 8; - cur++; - /* fallthrough */ - case GRPC_CHTTP2_SPS_VAL3: - if (cur == end) { - parser->state = GRPC_CHTTP2_SPS_VAL3; - return GRPC_CHTTP2_PARSE_OK; - } else { - parser->state = GRPC_CHTTP2_SPS_ID0; - } - parser->value |= *cur; - cur++; - - if (parser->id > 0 && parser->id < GRPC_CHTTP2_NUM_SETTINGS) { - const grpc_chttp2_setting_parameters *sp = - &grpc_chttp2_settings_parameters[parser->id]; - if (parser->value < sp->min_value || parser->value > sp->max_value) { - switch (sp->invalid_value_behavior) { - case GRPC_CHTTP2_CLAMP_INVALID_VALUE: - parser->value = - GPR_CLAMP(parser->value, sp->min_value, sp->max_value); - break; - case GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE: - grpc_chttp2_goaway_append( - transport_parsing->last_incoming_stream_id, sp->error_value, - gpr_slice_from_static_string("HTTP2 settings error"), - &transport_parsing->qbuf); - gpr_log(GPR_ERROR, "invalid value %u passed for %s", - parser->value, sp->name); - return GRPC_CHTTP2_CONNECTION_ERROR; - } - } - if (parser->id == GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE && - parser->incoming_settings[parser->id] != parser->value) { - transport_parsing->initial_window_update = - (int64_t)parser->value - parser->incoming_settings[parser->id]; - if (grpc_http_trace) { - gpr_log(GPR_DEBUG, "adding %d for initial_window change", - (int)transport_parsing->initial_window_update); - } - } - parser->incoming_settings[parser->id] = parser->value; - if (grpc_http_trace) { - gpr_log(GPR_DEBUG, "CHTTP2:%s: got setting %d = %d", - transport_parsing->is_client ? "CLI" : "SVR", parser->id, - parser->value); - } - } else { - gpr_log(GPR_ERROR, "CHTTP2: Ignoring unknown setting %d (value %d)", - parser->id, parser->value); - } - break; - } - } -} diff --git a/src/core/transport/chttp2/frame_settings.h b/src/core/transport/chttp2/frame_settings.h deleted file mode 100644 index 59dbff9b40..0000000000 --- a/src/core/transport/chttp2/frame_settings.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * - * Copyright 2015-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_TRANSPORT_CHTTP2_FRAME_SETTINGS_H -#define GRPC_CORE_TRANSPORT_CHTTP2_FRAME_SETTINGS_H - -#include -#include -#include "src/core/iomgr/exec_ctx.h" -#include "src/core/transport/chttp2/frame.h" - -typedef enum { - GRPC_CHTTP2_SPS_ID0, - GRPC_CHTTP2_SPS_ID1, - GRPC_CHTTP2_SPS_VAL0, - GRPC_CHTTP2_SPS_VAL1, - GRPC_CHTTP2_SPS_VAL2, - GRPC_CHTTP2_SPS_VAL3 -} grpc_chttp2_settings_parse_state; - -/* The things HTTP/2 defines as connection level settings */ -typedef enum { - GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE = 1, - GRPC_CHTTP2_SETTINGS_ENABLE_PUSH = 2, - GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS = 3, - GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE = 4, - GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE = 5, - GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE = 6, - GRPC_CHTTP2_NUM_SETTINGS -} grpc_chttp2_setting_id; - -typedef struct { - grpc_chttp2_settings_parse_state state; - uint32_t *target_settings; - uint8_t is_ack; - uint16_t id; - uint32_t value; - uint32_t incoming_settings[GRPC_CHTTP2_NUM_SETTINGS]; -} grpc_chttp2_settings_parser; - -typedef enum { - GRPC_CHTTP2_CLAMP_INVALID_VALUE, - GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE -} grpc_chttp2_invalid_value_behavior; - -typedef struct { - const char *name; - uint32_t default_value; - uint32_t min_value; - uint32_t max_value; - grpc_chttp2_invalid_value_behavior invalid_value_behavior; - uint32_t error_value; -} grpc_chttp2_setting_parameters; - -/* HTTP/2 mandated connection setting parameters */ -extern const grpc_chttp2_setting_parameters - grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS]; - -/* Create a settings frame by diffing old & new, and updating old to be new */ -gpr_slice grpc_chttp2_settings_create(uint32_t *old, const uint32_t *new, - uint32_t force_mask, size_t count); -/* Create an ack settings frame */ -gpr_slice grpc_chttp2_settings_ack_create(void); - -grpc_chttp2_parse_error grpc_chttp2_settings_parser_begin_frame( - grpc_chttp2_settings_parser *parser, uint32_t length, uint8_t flags, - uint32_t *settings); -grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse( - grpc_exec_ctx *exec_ctx, void *parser, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); - -#endif /* GRPC_CORE_TRANSPORT_CHTTP2_FRAME_SETTINGS_H */ diff --git a/src/core/transport/chttp2/frame_window_update.c b/src/core/transport/chttp2/frame_window_update.c deleted file mode 100644 index 62d9bac117..0000000000 --- a/src/core/transport/chttp2/frame_window_update.c +++ /dev/null @@ -1,113 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/transport/chttp2/frame_window_update.h" -#include "src/core/transport/chttp2/internal.h" - -#include - -gpr_slice grpc_chttp2_window_update_create(uint32_t id, - uint32_t window_update) { - gpr_slice slice = gpr_slice_malloc(13); - uint8_t *p = GPR_SLICE_START_PTR(slice); - - GPR_ASSERT(window_update); - - *p++ = 0; - *p++ = 0; - *p++ = 4; - *p++ = GRPC_CHTTP2_FRAME_WINDOW_UPDATE; - *p++ = 0; - *p++ = (uint8_t)(id >> 24); - *p++ = (uint8_t)(id >> 16); - *p++ = (uint8_t)(id >> 8); - *p++ = (uint8_t)(id); - *p++ = (uint8_t)(window_update >> 24); - *p++ = (uint8_t)(window_update >> 16); - *p++ = (uint8_t)(window_update >> 8); - *p++ = (uint8_t)(window_update); - - return slice; -} - -grpc_chttp2_parse_error grpc_chttp2_window_update_parser_begin_frame( - grpc_chttp2_window_update_parser *parser, uint32_t length, uint8_t flags) { - if (flags || length != 4) { - gpr_log(GPR_ERROR, "invalid window update: length=%d, flags=%02x", length, - flags); - return GRPC_CHTTP2_CONNECTION_ERROR; - } - parser->byte = 0; - parser->amount = 0; - return GRPC_CHTTP2_PARSE_OK; -} - -grpc_chttp2_parse_error grpc_chttp2_window_update_parser_parse( - grpc_exec_ctx *exec_ctx, void *parser, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { - uint8_t *const beg = GPR_SLICE_START_PTR(slice); - uint8_t *const end = GPR_SLICE_END_PTR(slice); - uint8_t *cur = beg; - grpc_chttp2_window_update_parser *p = parser; - - while (p->byte != 4 && cur != end) { - p->amount |= ((uint32_t)*cur) << (8 * (3 - p->byte)); - cur++; - p->byte++; - } - - if (p->byte == 4) { - uint32_t received_update = p->amount; - if (received_update == 0 || (received_update & 0x80000000u)) { - gpr_log(GPR_ERROR, "invalid window update bytes: %d", p->amount); - return GRPC_CHTTP2_CONNECTION_ERROR; - } - GPR_ASSERT(is_last); - - if (transport_parsing->incoming_stream_id != 0) { - if (stream_parsing != NULL) { - GRPC_CHTTP2_FLOW_CREDIT_STREAM("parse", transport_parsing, - stream_parsing, outgoing_window, - received_update); - grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, - stream_parsing); - } - } else { - GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parse", transport_parsing, - outgoing_window, received_update); - } - } - - return GRPC_CHTTP2_PARSE_OK; -} diff --git a/src/core/transport/chttp2/frame_window_update.h b/src/core/transport/chttp2/frame_window_update.h deleted file mode 100644 index 9b7ca3ce63..0000000000 --- a/src/core/transport/chttp2/frame_window_update.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * - * Copyright 2015-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_TRANSPORT_CHTTP2_FRAME_WINDOW_UPDATE_H -#define GRPC_CORE_TRANSPORT_CHTTP2_FRAME_WINDOW_UPDATE_H - -#include -#include "src/core/iomgr/exec_ctx.h" -#include "src/core/transport/chttp2/frame.h" - -typedef struct { - uint8_t byte; - uint8_t is_connection_update; - uint32_t amount; -} grpc_chttp2_window_update_parser; - -gpr_slice grpc_chttp2_window_update_create(uint32_t id, uint32_t window_delta); - -grpc_chttp2_parse_error grpc_chttp2_window_update_parser_begin_frame( - grpc_chttp2_window_update_parser *parser, uint32_t length, uint8_t flags); -grpc_chttp2_parse_error grpc_chttp2_window_update_parser_parse( - grpc_exec_ctx *exec_ctx, void *parser, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); - -#endif /* GRPC_CORE_TRANSPORT_CHTTP2_FRAME_WINDOW_UPDATE_H */ diff --git a/src/core/transport/chttp2/hpack_encoder.c b/src/core/transport/chttp2/hpack_encoder.c deleted file mode 100644 index f30f574d06..0000000000 --- a/src/core/transport/chttp2/hpack_encoder.c +++ /dev/null @@ -1,568 +0,0 @@ -/* - * - * Copyright 2015-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/transport/chttp2/hpack_encoder.h" - -#include -#include - -/* This is here for grpc_is_binary_header - * TODO(murgatroid99): Remove this - */ -#include - -#include -#include -#include - -#include "src/core/transport/chttp2/bin_encoder.h" -#include "src/core/transport/chttp2/hpack_table.h" -#include "src/core/transport/chttp2/timeout_encoding.h" -#include "src/core/transport/chttp2/varint.h" -#include "src/core/transport/static_metadata.h" - -#define HASH_FRAGMENT_1(x) ((x)&255) -#define HASH_FRAGMENT_2(x) ((x >> 8) & 255) -#define HASH_FRAGMENT_3(x) ((x >> 16) & 255) -#define HASH_FRAGMENT_4(x) ((x >> 24) & 255) - -/* if the probability of this item being seen again is < 1/x then don't add - it to the table */ -#define ONE_ON_ADD_PROBABILITY 128 -/* don't consider adding anything bigger than this to the hpack table */ -#define MAX_DECODER_SPACE_USAGE 512 - -typedef struct { - int is_first_frame; - /* number of bytes in 'output' when we started the frame - used to calculate - frame length */ - size_t output_length_at_start_of_frame; - /* index (in output) of the header for the current frame */ - size_t header_idx; - /* have we seen a regular (non-colon-prefixed) header yet? */ - uint8_t seen_regular_header; - /* output stream id */ - uint32_t stream_id; - gpr_slice_buffer *output; -} framer_state; - -/* fills p (which is expected to be 9 bytes long) with a data frame header */ -static void fill_header(uint8_t *p, uint8_t type, uint32_t id, size_t len, - uint8_t flags) { - GPR_ASSERT(len < 16777316); - *p++ = (uint8_t)(len >> 16); - *p++ = (uint8_t)(len >> 8); - *p++ = (uint8_t)(len); - *p++ = type; - *p++ = flags; - *p++ = (uint8_t)(id >> 24); - *p++ = (uint8_t)(id >> 16); - *p++ = (uint8_t)(id >> 8); - *p++ = (uint8_t)(id); -} - -/* finish a frame - fill in the previously reserved header */ -static void finish_frame(framer_state *st, int is_header_boundary, - int is_last_in_stream) { - uint8_t type = 0xff; - type = st->is_first_frame ? GRPC_CHTTP2_FRAME_HEADER - : GRPC_CHTTP2_FRAME_CONTINUATION; - fill_header( - GPR_SLICE_START_PTR(st->output->slices[st->header_idx]), type, - st->stream_id, st->output->length - st->output_length_at_start_of_frame, - (uint8_t)((is_last_in_stream ? GRPC_CHTTP2_DATA_FLAG_END_STREAM : 0) | - (is_header_boundary ? GRPC_CHTTP2_DATA_FLAG_END_HEADERS : 0))); - st->is_first_frame = 0; -} - -/* begin a new frame: reserve off header space, remember how many bytes we'd - output before beginning */ -static void begin_frame(framer_state *st) { - st->header_idx = - gpr_slice_buffer_add_indexed(st->output, gpr_slice_malloc(9)); - st->output_length_at_start_of_frame = st->output->length; -} - -/* make sure that the current frame is of the type desired, and has sufficient - space to add at least about_to_add bytes -- finishes the current frame if - needed */ -static void ensure_space(framer_state *st, size_t need_bytes) { - if (st->output->length - st->output_length_at_start_of_frame + need_bytes <= - GRPC_CHTTP2_MAX_PAYLOAD_LENGTH) { - return; - } - finish_frame(st, 0, 0); - begin_frame(st); -} - -/* increment a filter count, halve all counts if one element reaches max */ -static void inc_filter(uint8_t idx, uint32_t *sum, uint8_t *elems) { - elems[idx]++; - if (elems[idx] < 255) { - (*sum)++; - } else { - int i; - *sum = 0; - for (i = 0; i < GRPC_CHTTP2_HPACKC_NUM_FILTERS; i++) { - elems[i] /= 2; - (*sum) += elems[i]; - } - } -} - -static void add_header_data(framer_state *st, gpr_slice slice) { - size_t len = GPR_SLICE_LENGTH(slice); - size_t remaining; - if (len == 0) return; - remaining = GRPC_CHTTP2_MAX_PAYLOAD_LENGTH + - st->output_length_at_start_of_frame - st->output->length; - if (len <= remaining) { - gpr_slice_buffer_add(st->output, slice); - } else { - gpr_slice_buffer_add(st->output, gpr_slice_split_head(&slice, remaining)); - finish_frame(st, 0, 0); - begin_frame(st); - add_header_data(st, slice); - } -} - -static uint8_t *add_tiny_header_data(framer_state *st, size_t len) { - ensure_space(st, len); - return gpr_slice_buffer_tiny_add(st->output, len); -} - -static void evict_entry(grpc_chttp2_hpack_compressor *c) { - c->tail_remote_index++; - GPR_ASSERT(c->tail_remote_index > 0); - GPR_ASSERT(c->table_size >= - c->table_elem_size[c->tail_remote_index % c->cap_table_elems]); - GPR_ASSERT(c->table_elems > 0); - c->table_size = - (uint16_t)(c->table_size - - c->table_elem_size[c->tail_remote_index % c->cap_table_elems]); - c->table_elems--; -} - -/* add an element to the decoder table */ -static void add_elem(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem) { - uint32_t key_hash = elem->key->hash; - uint32_t elem_hash = GRPC_MDSTR_KV_HASH(key_hash, elem->value->hash); - uint32_t new_index = c->tail_remote_index + c->table_elems + 1; - size_t elem_size = 32 + GPR_SLICE_LENGTH(elem->key->slice) + - GPR_SLICE_LENGTH(elem->value->slice); - - GPR_ASSERT(elem_size < 65536); - - if (elem_size > c->max_table_size) { - while (c->table_size > 0) { - evict_entry(c); - } - return; - } - - /* Reserve space for this element in the remote table: if this overflows - the current table, drop elements until it fits, matching the decompressor - algorithm */ - while (c->table_size + elem_size > c->max_table_size) { - evict_entry(c); - } - GPR_ASSERT(c->table_elems < c->max_table_size); - c->table_elem_size[new_index % c->cap_table_elems] = (uint16_t)elem_size; - c->table_size = (uint16_t)(c->table_size + elem_size); - c->table_elems++; - - /* Store this element into {entries,indices}_elem */ - if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == elem) { - /* already there: update with new index */ - c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index; - } else if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == elem) { - /* already there (cuckoo): update with new index */ - c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index; - } else if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == NULL) { - /* not there, but a free element: add */ - c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = GRPC_MDELEM_REF(elem); - c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index; - } else if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == NULL) { - /* not there (cuckoo), but a free element: add */ - c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = GRPC_MDELEM_REF(elem); - c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index; - } else if (c->indices_elems[HASH_FRAGMENT_2(elem_hash)] < - c->indices_elems[HASH_FRAGMENT_3(elem_hash)]) { - /* not there: replace oldest */ - GRPC_MDELEM_UNREF(c->entries_elems[HASH_FRAGMENT_2(elem_hash)]); - c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = GRPC_MDELEM_REF(elem); - c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index; - } else { - /* not there: replace oldest */ - GRPC_MDELEM_UNREF(c->entries_elems[HASH_FRAGMENT_3(elem_hash)]); - c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = GRPC_MDELEM_REF(elem); - c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index; - } - - /* do exactly the same for the key (so we can find by that again too) */ - - if (c->entries_keys[HASH_FRAGMENT_2(key_hash)] == elem->key) { - c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index; - } else if (c->entries_keys[HASH_FRAGMENT_3(key_hash)] == elem->key) { - c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index; - } else if (c->entries_keys[HASH_FRAGMENT_2(key_hash)] == NULL) { - c->entries_keys[HASH_FRAGMENT_2(key_hash)] = GRPC_MDSTR_REF(elem->key); - c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index; - } else if (c->entries_keys[HASH_FRAGMENT_3(key_hash)] == NULL) { - c->entries_keys[HASH_FRAGMENT_3(key_hash)] = GRPC_MDSTR_REF(elem->key); - c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index; - } else if (c->indices_keys[HASH_FRAGMENT_2(key_hash)] < - c->indices_keys[HASH_FRAGMENT_3(key_hash)]) { - GRPC_MDSTR_UNREF(c->entries_keys[HASH_FRAGMENT_2(key_hash)]); - c->entries_keys[HASH_FRAGMENT_2(key_hash)] = GRPC_MDSTR_REF(elem->key); - c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index; - } else { - GRPC_MDSTR_UNREF(c->entries_keys[HASH_FRAGMENT_3(key_hash)]); - c->entries_keys[HASH_FRAGMENT_3(key_hash)] = GRPC_MDSTR_REF(elem->key); - c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index; - } -} - -static void emit_indexed(grpc_chttp2_hpack_compressor *c, uint32_t elem_index, - framer_state *st) { - uint32_t len = GRPC_CHTTP2_VARINT_LENGTH(elem_index, 1); - GRPC_CHTTP2_WRITE_VARINT(elem_index, 1, 0x80, add_tiny_header_data(st, len), - len); -} - -static gpr_slice get_wire_value(grpc_mdelem *elem, uint8_t *huffman_prefix) { - if (grpc_is_binary_header((const char *)GPR_SLICE_START_PTR(elem->key->slice), - GPR_SLICE_LENGTH(elem->key->slice))) { - *huffman_prefix = 0x80; - return grpc_mdstr_as_base64_encoded_and_huffman_compressed(elem->value); - } - /* TODO(ctiller): opportunistically compress non-binary headers */ - *huffman_prefix = 0x00; - return elem->value->slice; -} - -static void emit_lithdr_incidx(grpc_chttp2_hpack_compressor *c, - uint32_t key_index, grpc_mdelem *elem, - framer_state *st) { - uint32_t len_pfx = GRPC_CHTTP2_VARINT_LENGTH(key_index, 2); - uint8_t huffman_prefix; - gpr_slice value_slice = get_wire_value(elem, &huffman_prefix); - size_t len_val = GPR_SLICE_LENGTH(value_slice); - uint32_t len_val_len; - GPR_ASSERT(len_val <= UINT32_MAX); - len_val_len = GRPC_CHTTP2_VARINT_LENGTH((uint32_t)len_val, 1); - GRPC_CHTTP2_WRITE_VARINT(key_index, 2, 0x40, - add_tiny_header_data(st, len_pfx), len_pfx); - GRPC_CHTTP2_WRITE_VARINT((uint32_t)len_val, 1, huffman_prefix, - add_tiny_header_data(st, len_val_len), len_val_len); - add_header_data(st, gpr_slice_ref(value_slice)); -} - -static void emit_lithdr_noidx(grpc_chttp2_hpack_compressor *c, - uint32_t key_index, grpc_mdelem *elem, - framer_state *st) { - uint32_t len_pfx = GRPC_CHTTP2_VARINT_LENGTH(key_index, 4); - uint8_t huffman_prefix; - gpr_slice value_slice = get_wire_value(elem, &huffman_prefix); - size_t len_val = GPR_SLICE_LENGTH(value_slice); - uint32_t len_val_len; - GPR_ASSERT(len_val <= UINT32_MAX); - len_val_len = GRPC_CHTTP2_VARINT_LENGTH((uint32_t)len_val, 1); - GRPC_CHTTP2_WRITE_VARINT(key_index, 4, 0x00, - add_tiny_header_data(st, len_pfx), len_pfx); - GRPC_CHTTP2_WRITE_VARINT((uint32_t)len_val, 1, huffman_prefix, - add_tiny_header_data(st, len_val_len), len_val_len); - add_header_data(st, gpr_slice_ref(value_slice)); -} - -static void emit_lithdr_incidx_v(grpc_chttp2_hpack_compressor *c, - grpc_mdelem *elem, framer_state *st) { - uint32_t len_key = (uint32_t)GPR_SLICE_LENGTH(elem->key->slice); - uint8_t huffman_prefix; - gpr_slice value_slice = get_wire_value(elem, &huffman_prefix); - uint32_t len_val = (uint32_t)GPR_SLICE_LENGTH(value_slice); - uint32_t len_key_len = GRPC_CHTTP2_VARINT_LENGTH(len_key, 1); - uint32_t len_val_len = GRPC_CHTTP2_VARINT_LENGTH(len_val, 1); - GPR_ASSERT(len_key <= UINT32_MAX); - GPR_ASSERT(GPR_SLICE_LENGTH(value_slice) <= UINT32_MAX); - *add_tiny_header_data(st, 1) = 0x40; - GRPC_CHTTP2_WRITE_VARINT(len_key, 1, 0x00, - add_tiny_header_data(st, len_key_len), len_key_len); - add_header_data(st, gpr_slice_ref(elem->key->slice)); - GRPC_CHTTP2_WRITE_VARINT(len_val, 1, huffman_prefix, - add_tiny_header_data(st, len_val_len), len_val_len); - add_header_data(st, gpr_slice_ref(value_slice)); -} - -static void emit_lithdr_noidx_v(grpc_chttp2_hpack_compressor *c, - grpc_mdelem *elem, framer_state *st) { - uint32_t len_key = (uint32_t)GPR_SLICE_LENGTH(elem->key->slice); - uint8_t huffman_prefix; - gpr_slice value_slice = get_wire_value(elem, &huffman_prefix); - uint32_t len_val = (uint32_t)GPR_SLICE_LENGTH(value_slice); - uint32_t len_key_len = GRPC_CHTTP2_VARINT_LENGTH(len_key, 1); - uint32_t len_val_len = GRPC_CHTTP2_VARINT_LENGTH(len_val, 1); - GPR_ASSERT(len_key <= UINT32_MAX); - GPR_ASSERT(GPR_SLICE_LENGTH(value_slice) <= UINT32_MAX); - *add_tiny_header_data(st, 1) = 0x00; - GRPC_CHTTP2_WRITE_VARINT(len_key, 1, 0x00, - add_tiny_header_data(st, len_key_len), len_key_len); - add_header_data(st, gpr_slice_ref(elem->key->slice)); - GRPC_CHTTP2_WRITE_VARINT(len_val, 1, huffman_prefix, - add_tiny_header_data(st, len_val_len), len_val_len); - add_header_data(st, gpr_slice_ref(value_slice)); -} - -static void emit_advertise_table_size_change(grpc_chttp2_hpack_compressor *c, - framer_state *st) { - uint32_t len = GRPC_CHTTP2_VARINT_LENGTH(c->max_table_size, 3); - GRPC_CHTTP2_WRITE_VARINT(c->max_table_size, 3, 0x20, - add_tiny_header_data(st, len), len); - c->advertise_table_size_change = 0; -} - -static uint32_t dynidx(grpc_chttp2_hpack_compressor *c, uint32_t elem_index) { - return 1 + GRPC_CHTTP2_LAST_STATIC_ENTRY + c->tail_remote_index + - c->table_elems - elem_index; -} - -/* encode an mdelem */ -static void hpack_enc(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem, - framer_state *st) { - uint32_t key_hash = elem->key->hash; - uint32_t elem_hash = GRPC_MDSTR_KV_HASH(key_hash, elem->value->hash); - size_t decoder_space_usage; - uint32_t indices_key; - int should_add_elem; - - GPR_ASSERT(GPR_SLICE_LENGTH(elem->key->slice) > 0); - if (GPR_SLICE_START_PTR(elem->key->slice)[0] != ':') { /* regular header */ - st->seen_regular_header = 1; - } else { - GPR_ASSERT( - st->seen_regular_header == 0 && - "Reserved header (colon-prefixed) happening after regular ones."); - } - - inc_filter(HASH_FRAGMENT_1(elem_hash), &c->filter_elems_sum, c->filter_elems); - - /* is this elem currently in the decoders table? */ - - if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == elem && - c->indices_elems[HASH_FRAGMENT_2(elem_hash)] > c->tail_remote_index) { - /* HIT: complete element (first cuckoo hash) */ - emit_indexed(c, dynidx(c, c->indices_elems[HASH_FRAGMENT_2(elem_hash)]), - st); - return; - } - - if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == elem && - c->indices_elems[HASH_FRAGMENT_3(elem_hash)] > c->tail_remote_index) { - /* HIT: complete element (second cuckoo hash) */ - emit_indexed(c, dynidx(c, c->indices_elems[HASH_FRAGMENT_3(elem_hash)]), - st); - return; - } - - /* should this elem be in the table? */ - decoder_space_usage = 32 + GPR_SLICE_LENGTH(elem->key->slice) + - GPR_SLICE_LENGTH(elem->value->slice); - should_add_elem = decoder_space_usage < MAX_DECODER_SPACE_USAGE && - c->filter_elems[HASH_FRAGMENT_1(elem_hash)] >= - c->filter_elems_sum / ONE_ON_ADD_PROBABILITY; - - /* no hits for the elem... maybe there's a key? */ - - indices_key = c->indices_keys[HASH_FRAGMENT_2(key_hash)]; - if (c->entries_keys[HASH_FRAGMENT_2(key_hash)] == elem->key && - indices_key > c->tail_remote_index) { - /* HIT: key (first cuckoo hash) */ - if (should_add_elem) { - emit_lithdr_incidx(c, dynidx(c, indices_key), elem, st); - add_elem(c, elem); - return; - } else { - emit_lithdr_noidx(c, dynidx(c, indices_key), elem, st); - return; - } - GPR_UNREACHABLE_CODE(return ); - } - - indices_key = c->indices_keys[HASH_FRAGMENT_3(key_hash)]; - if (c->entries_keys[HASH_FRAGMENT_3(key_hash)] == elem->key && - indices_key > c->tail_remote_index) { - /* HIT: key (first cuckoo hash) */ - if (should_add_elem) { - emit_lithdr_incidx(c, dynidx(c, indices_key), elem, st); - add_elem(c, elem); - return; - } else { - emit_lithdr_noidx(c, dynidx(c, indices_key), elem, st); - return; - } - GPR_UNREACHABLE_CODE(return ); - } - - /* no elem, key in the table... fall back to literal emission */ - - if (should_add_elem) { - emit_lithdr_incidx_v(c, elem, st); - add_elem(c, elem); - return; - } else { - emit_lithdr_noidx_v(c, elem, st); - return; - } - GPR_UNREACHABLE_CODE(return ); -} - -#define STRLEN_LIT(x) (sizeof(x) - 1) -#define TIMEOUT_KEY "grpc-timeout" - -static void deadline_enc(grpc_chttp2_hpack_compressor *c, gpr_timespec deadline, - framer_state *st) { - char timeout_str[GRPC_CHTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE]; - grpc_mdelem *mdelem; - grpc_chttp2_encode_timeout( - gpr_time_sub(deadline, gpr_now(deadline.clock_type)), timeout_str); - mdelem = grpc_mdelem_from_metadata_strings( - GRPC_MDSTR_GRPC_TIMEOUT, grpc_mdstr_from_string(timeout_str)); - hpack_enc(c, mdelem, st); - GRPC_MDELEM_UNREF(mdelem); -} - -static uint32_t elems_for_bytes(uint32_t bytes) { return (bytes + 31) / 32; } - -void grpc_chttp2_hpack_compressor_init(grpc_chttp2_hpack_compressor *c) { - memset(c, 0, sizeof(*c)); - c->max_table_size = GRPC_CHTTP2_HPACKC_INITIAL_TABLE_SIZE; - c->cap_table_elems = elems_for_bytes(c->max_table_size); - c->max_table_elems = c->cap_table_elems; - c->max_usable_size = GRPC_CHTTP2_HPACKC_INITIAL_TABLE_SIZE; - c->table_elem_size = - gpr_malloc(sizeof(*c->table_elem_size) * c->cap_table_elems); - memset(c->table_elem_size, 0, - sizeof(*c->table_elem_size) * c->cap_table_elems); -} - -void grpc_chttp2_hpack_compressor_destroy(grpc_chttp2_hpack_compressor *c) { - int i; - for (i = 0; i < GRPC_CHTTP2_HPACKC_NUM_VALUES; i++) { - if (c->entries_keys[i]) GRPC_MDSTR_UNREF(c->entries_keys[i]); - if (c->entries_elems[i]) GRPC_MDELEM_UNREF(c->entries_elems[i]); - } - gpr_free(c->table_elem_size); -} - -void grpc_chttp2_hpack_compressor_set_max_usable_size( - grpc_chttp2_hpack_compressor *c, uint32_t max_table_size) { - c->max_usable_size = max_table_size; - grpc_chttp2_hpack_compressor_set_max_table_size( - c, GPR_MIN(c->max_table_size, max_table_size)); -} - -static void rebuild_elems(grpc_chttp2_hpack_compressor *c, uint32_t new_cap) { - uint16_t *table_elem_size = gpr_malloc(sizeof(*table_elem_size) * new_cap); - uint32_t i; - - memset(table_elem_size, 0, sizeof(*table_elem_size) * new_cap); - GPR_ASSERT(c->table_elems <= new_cap); - - for (i = 0; i < c->table_elems; i++) { - uint32_t ofs = c->tail_remote_index + i + 1; - table_elem_size[ofs % new_cap] = - c->table_elem_size[ofs % c->cap_table_elems]; - } - - c->cap_table_elems = new_cap; - gpr_free(c->table_elem_size); - c->table_elem_size = table_elem_size; -} - -void grpc_chttp2_hpack_compressor_set_max_table_size( - grpc_chttp2_hpack_compressor *c, uint32_t max_table_size) { - max_table_size = GPR_MIN(max_table_size, c->max_usable_size); - if (max_table_size == c->max_table_size) { - return; - } - while (c->table_size > 0 && c->table_size > max_table_size) { - evict_entry(c); - } - c->max_table_size = max_table_size; - c->max_table_elems = elems_for_bytes(max_table_size); - if (c->max_table_elems > c->cap_table_elems) { - rebuild_elems(c, GPR_MAX(c->max_table_elems, 2 * c->cap_table_elems)); - } else if (c->max_table_elems < c->cap_table_elems / 3) { - uint32_t new_cap = GPR_MAX(c->max_table_elems, 16); - if (new_cap != c->cap_table_elems) { - rebuild_elems(c, new_cap); - } - } - c->advertise_table_size_change = 1; - gpr_log(GPR_DEBUG, "set max table size from encoder to %d", max_table_size); -} - -void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor *c, - uint32_t stream_id, - grpc_metadata_batch *metadata, int is_eof, - gpr_slice_buffer *outbuf) { - framer_state st; - grpc_linked_mdelem *l; - gpr_timespec deadline; - - GPR_ASSERT(stream_id != 0); - - st.seen_regular_header = 0; - st.stream_id = stream_id; - st.output = outbuf; - st.is_first_frame = 1; - - /* Encode a metadata batch; store the returned values, representing - a metadata element that needs to be unreffed back into the metadata - slot. THIS MAY NOT BE THE SAME ELEMENT (if a decoder table slot got - updated). After this loop, we'll do a batch unref of elements. */ - begin_frame(&st); - if (c->advertise_table_size_change != 0) { - emit_advertise_table_size_change(c, &st); - } - grpc_metadata_batch_assert_ok(metadata); - for (l = metadata->list.head; l; l = l->next) { - hpack_enc(c, l->md, &st); - } - deadline = metadata->deadline; - if (gpr_time_cmp(deadline, gpr_inf_future(deadline.clock_type)) != 0) { - deadline_enc(c, deadline, &st); - } - - finish_frame(&st, 1, is_eof); -} diff --git a/src/core/transport/chttp2/hpack_encoder.h b/src/core/transport/chttp2/hpack_encoder.h deleted file mode 100644 index 6d86eb7c83..0000000000 --- a/src/core/transport/chttp2/hpack_encoder.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * - * Copyright 2015-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_TRANSPORT_CHTTP2_HPACK_ENCODER_H -#define GRPC_CORE_TRANSPORT_CHTTP2_HPACK_ENCODER_H - -#include -#include -#include -#include "src/core/transport/chttp2/frame.h" -#include "src/core/transport/metadata.h" -#include "src/core/transport/metadata_batch.h" - -#define GRPC_CHTTP2_HPACKC_NUM_FILTERS 256 -#define GRPC_CHTTP2_HPACKC_NUM_VALUES 256 -/* initial table size, per spec */ -#define GRPC_CHTTP2_HPACKC_INITIAL_TABLE_SIZE 4096 -/* maximum table size we'll actually use */ -#define GRPC_CHTTP2_HPACKC_MAX_TABLE_SIZE (1024 * 1024) - -typedef struct { - uint32_t filter_elems_sum; - uint32_t max_table_size; - uint32_t max_table_elems; - uint32_t cap_table_elems; - /** if non-zero, advertise to the decoder that we'll start using a table - of this size */ - uint8_t advertise_table_size_change; - /** maximum number of bytes we'll use for the decode table (to guard against - peers ooming us by setting decode table size high) */ - uint32_t max_usable_size; - /* one before the lowest usable table index */ - uint32_t tail_remote_index; - uint32_t table_size; - uint32_t table_elems; - - /* filter tables for elems: this tables provides an approximate - popularity count for particular hashes, and are used to determine whether - a new literal should be added to the compression table or not. - They track a single integer that counts how often a particular value has - been seen. When that count reaches max (255), all values are halved. */ - uint8_t filter_elems[GRPC_CHTTP2_HPACKC_NUM_FILTERS]; - - /* entry tables for keys & elems: these tables track values that have been - seen and *may* be in the decompressor table */ - grpc_mdstr *entries_keys[GRPC_CHTTP2_HPACKC_NUM_VALUES]; - grpc_mdelem *entries_elems[GRPC_CHTTP2_HPACKC_NUM_VALUES]; - uint32_t indices_keys[GRPC_CHTTP2_HPACKC_NUM_VALUES]; - uint32_t indices_elems[GRPC_CHTTP2_HPACKC_NUM_VALUES]; - - uint16_t *table_elem_size; -} grpc_chttp2_hpack_compressor; - -void grpc_chttp2_hpack_compressor_init(grpc_chttp2_hpack_compressor *c); -void grpc_chttp2_hpack_compressor_destroy(grpc_chttp2_hpack_compressor *c); -void grpc_chttp2_hpack_compressor_set_max_table_size( - grpc_chttp2_hpack_compressor *c, uint32_t max_table_size); -void grpc_chttp2_hpack_compressor_set_max_usable_size( - grpc_chttp2_hpack_compressor *c, uint32_t max_table_size); - -void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor *c, uint32_t id, - grpc_metadata_batch *metadata, int is_eof, - gpr_slice_buffer *outbuf); - -#endif /* GRPC_CORE_TRANSPORT_CHTTP2_HPACK_ENCODER_H */ diff --git a/src/core/transport/chttp2/hpack_parser.c b/src/core/transport/chttp2/hpack_parser.c deleted file mode 100644 index b6e36923cb..0000000000 --- a/src/core/transport/chttp2/hpack_parser.c +++ /dev/null @@ -1,1449 +0,0 @@ -/* - * - * Copyright 2015-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/transport/chttp2/hpack_parser.h" -#include "src/core/transport/chttp2/internal.h" - -#include -#include -#include - -/* This is here for grpc_is_binary_header - * TODO(murgatroid99): Remove this - */ -#include - -#include -#include -#include -#include - -#include "src/core/profiling/timers.h" -#include "src/core/support/string.h" -#include "src/core/transport/chttp2/bin_encoder.h" - -typedef enum { - NOT_BINARY, - B64_BYTE0, - B64_BYTE1, - B64_BYTE2, - B64_BYTE3 -} binary_state; - -/* How parsing works: - - The parser object keeps track of a function pointer which represents the - current parse state. - - Each time new bytes are presented, we call into the current state, which - recursively parses until all bytes in the given chunk are exhausted. - - The parse state that terminates then saves its function pointer to be the - current state so that it can resume when more bytes are available. - - It's expected that most optimizing compilers will turn this code into - a set of indirect jumps, and so not waste stack space. */ - -/* forward declarations for parsing states */ -static int parse_begin(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end); -static int parse_error(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end); -static int parse_illegal_op(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end); - -static int parse_string_prefix(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end); -static int parse_key_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end); -static int parse_value_string_with_indexed_key(grpc_chttp2_hpack_parser *p, - const uint8_t *cur, - const uint8_t *end); -static int parse_value_string_with_literal_key(grpc_chttp2_hpack_parser *p, - const uint8_t *cur, - const uint8_t *end); - -static int parse_value0(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end); -static int parse_value1(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end); -static int parse_value2(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end); -static int parse_value3(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end); -static int parse_value4(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end); -static int parse_value5up(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end); - -static int parse_indexed_field(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end); -static int parse_indexed_field_x(grpc_chttp2_hpack_parser *p, - const uint8_t *cur, const uint8_t *end); -static int parse_lithdr_incidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end); -static int parse_lithdr_incidx_x(grpc_chttp2_hpack_parser *p, - const uint8_t *cur, const uint8_t *end); -static int parse_lithdr_incidx_v(grpc_chttp2_hpack_parser *p, - const uint8_t *cur, const uint8_t *end); -static int parse_lithdr_notidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end); -static int parse_lithdr_notidx_x(grpc_chttp2_hpack_parser *p, - const uint8_t *cur, const uint8_t *end); -static int parse_lithdr_notidx_v(grpc_chttp2_hpack_parser *p, - const uint8_t *cur, const uint8_t *end); -static int parse_lithdr_nvridx(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end); -static int parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser *p, - const uint8_t *cur, const uint8_t *end); -static int parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p, - const uint8_t *cur, const uint8_t *end); -static int parse_max_tbl_size(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end); -static int parse_max_tbl_size_x(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end); - -/* we translate the first byte of a hpack field into one of these decoding - cases, then use a lookup table to jump directly to the appropriate parser. - - _X => the integer index is all ones, meaning we need to do varint decoding - _V => the integer index is all zeros, meaning we need to decode an additional - string value */ -typedef enum { - INDEXED_FIELD, - INDEXED_FIELD_X, - LITHDR_INCIDX, - LITHDR_INCIDX_X, - LITHDR_INCIDX_V, - LITHDR_NOTIDX, - LITHDR_NOTIDX_X, - LITHDR_NOTIDX_V, - LITHDR_NVRIDX, - LITHDR_NVRIDX_X, - LITHDR_NVRIDX_V, - MAX_TBL_SIZE, - MAX_TBL_SIZE_X, - ILLEGAL -} first_byte_type; - -/* jump table of parse state functions -- order must match first_byte_type - above */ -static const grpc_chttp2_hpack_parser_state first_byte_action[] = { - parse_indexed_field, parse_indexed_field_x, parse_lithdr_incidx, - parse_lithdr_incidx_x, parse_lithdr_incidx_v, parse_lithdr_notidx, - parse_lithdr_notidx_x, parse_lithdr_notidx_v, parse_lithdr_nvridx, - parse_lithdr_nvridx_x, parse_lithdr_nvridx_v, parse_max_tbl_size, - parse_max_tbl_size_x, parse_illegal_op}; - -/* indexes the first byte to a parse state function - generated by - gen_hpack_tables.c */ -static const uint8_t first_byte_lut[256] = { - LITHDR_NOTIDX_V, LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX, - LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX, - LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX, - LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX_X, - LITHDR_NVRIDX_V, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, - LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, - LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, - LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX_X, - MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, - MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, - MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, - MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, - MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, - MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, - MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, - MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE_X, - LITHDR_INCIDX_V, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, - LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, - LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, - LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, - LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, - LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, - LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, - LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, - LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, - LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, - LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, - LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, - LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, - LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, - LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, - LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX_X, - ILLEGAL, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, - INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, - INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, - INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, - INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, - INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, - INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, - INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, - INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, - INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, - INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, - INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, - INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, - INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, - INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, - INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, - INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, - INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, - INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, - INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, - INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, - INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, - INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, - INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, - INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, - INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, - INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, - INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, - INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, - INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, - INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, - INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD, INDEXED_FIELD_X, -}; - -/* state table for huffman decoding: given a state, gives an index/16 into - next_sub_tbl. Taking that index and adding the value of the nibble being - considered returns the next state. - - generated by gen_hpack_tables.c */ -static const uint8_t next_tbl[256] = { - 0, 1, 2, 3, 4, 1, 2, 5, 6, 1, 7, 8, 1, 3, 3, 9, 10, 11, 1, 1, - 1, 12, 1, 2, 13, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, - 14, 1, 15, 16, 1, 17, 1, 15, 2, 7, 3, 18, 19, 1, 1, 1, 1, 20, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 15, 2, 2, 7, 21, 1, 22, 1, 1, 1, 1, 1, - 1, 1, 1, 15, 2, 2, 2, 2, 2, 2, 23, 24, 25, 1, 1, 1, 1, 2, 2, 2, - 26, 3, 3, 27, 10, 28, 1, 1, 1, 1, 1, 1, 2, 3, 29, 10, 30, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 31, 1, 1, 1, 1, 1, 1, 1, 2, - 2, 2, 2, 2, 2, 2, 2, 32, 1, 1, 15, 33, 1, 34, 35, 9, 36, 1, 1, 1, - 1, 1, 1, 1, 37, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 26, 9, - 38, 1, 1, 1, 1, 1, 1, 1, 15, 2, 2, 2, 2, 26, 3, 3, 39, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 7, 3, 3, 3, 40, 2, - 41, 1, 1, 1, 42, 43, 1, 1, 44, 1, 1, 1, 1, 15, 2, 2, 2, 2, 2, 2, - 3, 3, 3, 45, 46, 1, 1, 2, 2, 2, 35, 3, 3, 18, 47, 2, -}; - -/* next state, based upon current state and the current nibble: see above. - generated by gen_hpack_tables.c */ -static const int16_t next_sub_tbl[48 * 16] = { - 1, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, - 218, 2, 6, 10, 13, 14, 15, 16, 17, 2, 6, 10, 13, 14, 15, - 16, 17, 3, 7, 11, 24, 3, 7, 11, 24, 3, 7, 11, 24, 3, - 7, 11, 24, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, - 4, 8, 4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, - 199, 200, 201, 202, 203, 4, 8, 4, 8, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 9, 133, 134, 135, 136, 137, 138, 139, 140, - 141, 142, 143, 144, 145, 146, 147, 3, 7, 11, 24, 3, 7, 11, 24, - 4, 8, 4, 8, 4, 8, 4, 8, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 12, 132, 4, 8, 4, 8, 4, 8, - 4, 8, 4, 8, 4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 18, 19, 20, 21, 4, 8, 4, - 8, 4, 8, 4, 8, 4, 8, 0, 0, 0, 22, 23, 91, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 3, - 7, 11, 24, 3, 7, 11, 24, 0, 0, 0, 0, 0, 41, 42, 43, - 2, 6, 10, 13, 14, 15, 16, 17, 3, 7, 11, 24, 3, 7, 11, - 24, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 0, 0, - 44, 45, 2, 6, 10, 13, 14, 15, 16, 17, 46, 47, 48, 49, 50, - 51, 52, 57, 4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 53, 54, 55, 56, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, - 68, 69, 70, 71, 72, 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 73, 75, 76, 77, 78, 79, 80, 81, 82, - 83, 84, 85, 86, 87, 88, 89, 90, 3, 7, 11, 24, 3, 7, 11, - 24, 3, 7, 11, 24, 0, 0, 0, 0, 3, 7, 11, 24, 3, 7, - 11, 24, 4, 8, 4, 8, 0, 0, 0, 92, 0, 0, 0, 93, 94, - 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 3, 7, 11, 24, - 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, - 8, 4, 8, 4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 4, - 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 0, 0, - 0, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, - 131, 2, 6, 10, 13, 14, 15, 16, 17, 4, 8, 4, 8, 4, 8, - 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 148, - 149, 150, 151, 3, 7, 11, 24, 4, 8, 4, 8, 0, 0, 0, 0, - 0, 0, 152, 153, 3, 7, 11, 24, 3, 7, 11, 24, 3, 7, 11, - 24, 154, 155, 156, 164, 3, 7, 11, 24, 3, 7, 11, 24, 3, 7, - 11, 24, 4, 8, 4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 157, 158, 159, 160, 161, 162, 163, 165, 166, 167, 168, 169, 170, 171, 172, - 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, - 188, 189, 190, 191, 192, 193, 194, 195, 196, 4, 8, 4, 8, 4, 8, - 4, 8, 4, 8, 4, 8, 4, 8, 197, 198, 4, 8, 4, 8, 4, - 8, 4, 8, 0, 0, 0, 0, 0, 0, 219, 220, 3, 7, 11, 24, - 4, 8, 4, 8, 4, 8, 0, 0, 221, 222, 223, 224, 3, 7, 11, - 24, 3, 7, 11, 24, 4, 8, 4, 8, 4, 8, 225, 228, 4, 8, - 4, 8, 4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 226, 227, 229, - 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, - 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 245, 246, 247, 248, 249, 250, 251, 252, - 253, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 255, -}; - -/* emission table: indexed like next_tbl, ultimately gives the byte to be - emitted, or -1 for no byte, or 256 for end of stream - - generated by gen_hpack_tables.c */ -static const uint16_t emit_tbl[256] = { - 0, 1, 2, 3, 4, 5, 6, 7, 0, 8, 9, 10, 11, 12, 13, - 14, 15, 16, 17, 18, 19, 20, 21, 22, 0, 23, 24, 25, 26, 27, - 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, - 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 0, 55, 56, - 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 0, - 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, - 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, - 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, - 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 0, - 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, - 0, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, - 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, - 219, 220, 221, 0, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, - 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, - 248, -}; - -/* generated by gen_hpack_tables.c */ -static const int16_t emit_sub_tbl[249 * 16] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 48, 48, 48, 48, 48, 48, 48, 48, 49, 49, 49, 49, 49, 49, - 49, 49, 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 97, - 97, 97, 97, 48, 48, 49, 49, 50, 50, 97, 97, 99, 99, 101, 101, - 105, 105, 111, 111, 48, 49, 50, 97, 99, 101, 105, 111, 115, 116, -1, - -1, -1, -1, -1, -1, 32, 32, 32, 32, 32, 32, 32, 32, 37, 37, - 37, 37, 37, 37, 37, 37, 99, 99, 99, 99, 101, 101, 101, 101, 105, - 105, 105, 105, 111, 111, 111, 111, 115, 115, 116, 116, 32, 37, 45, 46, - 47, 51, 52, 53, 54, 55, 56, 57, 61, 61, 61, 61, 61, 61, 61, - 61, 65, 65, 65, 65, 65, 65, 65, 65, 115, 115, 115, 115, 116, 116, - 116, 116, 32, 32, 37, 37, 45, 45, 46, 46, 61, 65, 95, 98, 100, - 102, 103, 104, 108, 109, 110, 112, 114, 117, -1, -1, 58, 58, 58, 58, - 58, 58, 58, 58, 66, 66, 66, 66, 66, 66, 66, 66, 47, 47, 51, - 51, 52, 52, 53, 53, 54, 54, 55, 55, 56, 56, 57, 57, 61, 61, - 65, 65, 95, 95, 98, 98, 100, 100, 102, 102, 103, 103, 104, 104, 108, - 108, 109, 109, 110, 110, 112, 112, 114, 114, 117, 117, 58, 66, 67, 68, - 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, - 84, 85, 86, 87, 89, 106, 107, 113, 118, 119, 120, 121, 122, -1, -1, - -1, -1, 38, 38, 38, 38, 38, 38, 38, 38, 42, 42, 42, 42, 42, - 42, 42, 42, 44, 44, 44, 44, 44, 44, 44, 44, 59, 59, 59, 59, - 59, 59, 59, 59, 88, 88, 88, 88, 88, 88, 88, 88, 90, 90, 90, - 90, 90, 90, 90, 90, 33, 33, 34, 34, 40, 40, 41, 41, 63, 63, - 39, 43, 124, -1, -1, -1, 35, 35, 35, 35, 35, 35, 35, 35, 62, - 62, 62, 62, 62, 62, 62, 62, 0, 0, 0, 0, 36, 36, 36, 36, - 64, 64, 64, 64, 91, 91, 91, 91, 69, 69, 69, 69, 69, 69, 69, - 69, 70, 70, 70, 70, 70, 70, 70, 70, 71, 71, 71, 71, 71, 71, - 71, 71, 72, 72, 72, 72, 72, 72, 72, 72, 73, 73, 73, 73, 73, - 73, 73, 73, 74, 74, 74, 74, 74, 74, 74, 74, 75, 75, 75, 75, - 75, 75, 75, 75, 76, 76, 76, 76, 76, 76, 76, 76, 77, 77, 77, - 77, 77, 77, 77, 77, 78, 78, 78, 78, 78, 78, 78, 78, 79, 79, - 79, 79, 79, 79, 79, 79, 80, 80, 80, 80, 80, 80, 80, 80, 81, - 81, 81, 81, 81, 81, 81, 81, 82, 82, 82, 82, 82, 82, 82, 82, - 83, 83, 83, 83, 83, 83, 83, 83, 84, 84, 84, 84, 84, 84, 84, - 84, 85, 85, 85, 85, 85, 85, 85, 85, 86, 86, 86, 86, 86, 86, - 86, 86, 87, 87, 87, 87, 87, 87, 87, 87, 89, 89, 89, 89, 89, - 89, 89, 89, 106, 106, 106, 106, 106, 106, 106, 106, 107, 107, 107, 107, - 107, 107, 107, 107, 113, 113, 113, 113, 113, 113, 113, 113, 118, 118, 118, - 118, 118, 118, 118, 118, 119, 119, 119, 119, 119, 119, 119, 119, 120, 120, - 120, 120, 120, 120, 120, 120, 121, 121, 121, 121, 121, 121, 121, 121, 122, - 122, 122, 122, 122, 122, 122, 122, 38, 38, 38, 38, 42, 42, 42, 42, - 44, 44, 44, 44, 59, 59, 59, 59, 88, 88, 88, 88, 90, 90, 90, - 90, 33, 34, 40, 41, 63, -1, -1, -1, 39, 39, 39, 39, 39, 39, - 39, 39, 43, 43, 43, 43, 43, 43, 43, 43, 124, 124, 124, 124, 124, - 124, 124, 124, 35, 35, 35, 35, 62, 62, 62, 62, 0, 0, 36, 36, - 64, 64, 91, 91, 93, 93, 126, 126, 94, 125, -1, -1, 60, 60, 60, - 60, 60, 60, 60, 60, 96, 96, 96, 96, 96, 96, 96, 96, 123, 123, - 123, 123, 123, 123, 123, 123, -1, -1, -1, -1, -1, -1, -1, -1, 92, - 92, 92, 92, 92, 92, 92, 92, 195, 195, 195, 195, 195, 195, 195, 195, - 208, 208, 208, 208, 208, 208, 208, 208, 128, 128, 128, 128, 130, 130, 130, - 130, 131, 131, 131, 131, 162, 162, 162, 162, 184, 184, 184, 184, 194, 194, - 194, 194, 224, 224, 224, 224, 226, 226, 226, 226, 153, 153, 161, 161, 167, - 167, 172, 172, 176, 176, 177, 177, 179, 179, 209, 209, 216, 216, 217, 217, - 227, 227, 229, 229, 230, 230, 129, 132, 133, 134, 136, 146, 154, 156, 160, - 163, 164, 169, 170, 173, 178, 181, 185, 186, 187, 189, 190, 196, 198, 228, - 232, 233, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 135, - 135, 135, 135, 135, 135, 135, 135, 137, 137, 137, 137, 137, 137, 137, 137, - 138, 138, 138, 138, 138, 138, 138, 138, 139, 139, 139, 139, 139, 139, 139, - 139, 140, 140, 140, 140, 140, 140, 140, 140, 141, 141, 141, 141, 141, 141, - 141, 141, 143, 143, 143, 143, 143, 143, 143, 143, 147, 147, 147, 147, 147, - 147, 147, 147, 149, 149, 149, 149, 149, 149, 149, 149, 150, 150, 150, 150, - 150, 150, 150, 150, 151, 151, 151, 151, 151, 151, 151, 151, 152, 152, 152, - 152, 152, 152, 152, 152, 155, 155, 155, 155, 155, 155, 155, 155, 157, 157, - 157, 157, 157, 157, 157, 157, 158, 158, 158, 158, 158, 158, 158, 158, 165, - 165, 165, 165, 165, 165, 165, 165, 166, 166, 166, 166, 166, 166, 166, 166, - 168, 168, 168, 168, 168, 168, 168, 168, 174, 174, 174, 174, 174, 174, 174, - 174, 175, 175, 175, 175, 175, 175, 175, 175, 180, 180, 180, 180, 180, 180, - 180, 180, 182, 182, 182, 182, 182, 182, 182, 182, 183, 183, 183, 183, 183, - 183, 183, 183, 188, 188, 188, 188, 188, 188, 188, 188, 191, 191, 191, 191, - 191, 191, 191, 191, 197, 197, 197, 197, 197, 197, 197, 197, 231, 231, 231, - 231, 231, 231, 231, 231, 239, 239, 239, 239, 239, 239, 239, 239, 9, 9, - 9, 9, 142, 142, 142, 142, 144, 144, 144, 144, 145, 145, 145, 145, 148, - 148, 148, 148, 159, 159, 159, 159, 171, 171, 171, 171, 206, 206, 206, 206, - 215, 215, 215, 215, 225, 225, 225, 225, 236, 236, 236, 236, 237, 237, 237, - 237, 199, 199, 207, 207, 234, 234, 235, 235, 192, 193, 200, 201, 202, 205, - 210, 213, 218, 219, 238, 240, 242, 243, 255, -1, 203, 203, 203, 203, 203, - 203, 203, 203, 204, 204, 204, 204, 204, 204, 204, 204, 211, 211, 211, 211, - 211, 211, 211, 211, 212, 212, 212, 212, 212, 212, 212, 212, 214, 214, 214, - 214, 214, 214, 214, 214, 221, 221, 221, 221, 221, 221, 221, 221, 222, 222, - 222, 222, 222, 222, 222, 222, 223, 223, 223, 223, 223, 223, 223, 223, 241, - 241, 241, 241, 241, 241, 241, 241, 244, 244, 244, 244, 244, 244, 244, 244, - 245, 245, 245, 245, 245, 245, 245, 245, 246, 246, 246, 246, 246, 246, 246, - 246, 247, 247, 247, 247, 247, 247, 247, 247, 248, 248, 248, 248, 248, 248, - 248, 248, 250, 250, 250, 250, 250, 250, 250, 250, 251, 251, 251, 251, 251, - 251, 251, 251, 252, 252, 252, 252, 252, 252, 252, 252, 253, 253, 253, 253, - 253, 253, 253, 253, 254, 254, 254, 254, 254, 254, 254, 254, 2, 2, 2, - 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, - 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 11, 11, 11, 11, 12, - 12, 12, 12, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, - 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, - 20, 21, 21, 21, 21, 23, 23, 23, 23, 24, 24, 24, 24, 25, 25, - 25, 25, 26, 26, 26, 26, 27, 27, 27, 27, 28, 28, 28, 28, 29, - 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31, 127, 127, 127, 127, - 220, 220, 220, 220, 249, 249, 249, 249, 10, 13, 22, 256, 93, 93, 93, - 93, 126, 126, 126, 126, 94, 94, 125, 125, 60, 96, 123, -1, 92, 195, - 208, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 128, - 128, 128, 128, 128, 128, 128, 128, 130, 130, 130, 130, 130, 130, 130, 130, - 131, 131, 131, 131, 131, 131, 131, 131, 162, 162, 162, 162, 162, 162, 162, - 162, 184, 184, 184, 184, 184, 184, 184, 184, 194, 194, 194, 194, 194, 194, - 194, 194, 224, 224, 224, 224, 224, 224, 224, 224, 226, 226, 226, 226, 226, - 226, 226, 226, 153, 153, 153, 153, 161, 161, 161, 161, 167, 167, 167, 167, - 172, 172, 172, 172, 176, 176, 176, 176, 177, 177, 177, 177, 179, 179, 179, - 179, 209, 209, 209, 209, 216, 216, 216, 216, 217, 217, 217, 217, 227, 227, - 227, 227, 229, 229, 229, 229, 230, 230, 230, 230, 129, 129, 132, 132, 133, - 133, 134, 134, 136, 136, 146, 146, 154, 154, 156, 156, 160, 160, 163, 163, - 164, 164, 169, 169, 170, 170, 173, 173, 178, 178, 181, 181, 185, 185, 186, - 186, 187, 187, 189, 189, 190, 190, 196, 196, 198, 198, 228, 228, 232, 232, - 233, 233, 1, 135, 137, 138, 139, 140, 141, 143, 147, 149, 150, 151, 152, - 155, 157, 158, 165, 166, 168, 174, 175, 180, 182, 183, 188, 191, 197, 231, - 239, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 9, 9, 9, - 9, 9, 9, 9, 9, 142, 142, 142, 142, 142, 142, 142, 142, 144, 144, - 144, 144, 144, 144, 144, 144, 145, 145, 145, 145, 145, 145, 145, 145, 148, - 148, 148, 148, 148, 148, 148, 148, 159, 159, 159, 159, 159, 159, 159, 159, - 171, 171, 171, 171, 171, 171, 171, 171, 206, 206, 206, 206, 206, 206, 206, - 206, 215, 215, 215, 215, 215, 215, 215, 215, 225, 225, 225, 225, 225, 225, - 225, 225, 236, 236, 236, 236, 236, 236, 236, 236, 237, 237, 237, 237, 237, - 237, 237, 237, 199, 199, 199, 199, 207, 207, 207, 207, 234, 234, 234, 234, - 235, 235, 235, 235, 192, 192, 193, 193, 200, 200, 201, 201, 202, 202, 205, - 205, 210, 210, 213, 213, 218, 218, 219, 219, 238, 238, 240, 240, 242, 242, - 243, 243, 255, 255, 203, 204, 211, 212, 214, 221, 222, 223, 241, 244, 245, - 246, 247, 248, 250, 251, 252, 253, 254, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 2, 2, 2, 2, 2, 2, 2, - 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, - 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, - 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, - 8, 8, 8, 8, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, - 12, 12, 12, 12, 12, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, - 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 17, - 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, - 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, - 20, 21, 21, 21, 21, 21, 21, 21, 21, 23, 23, 23, 23, 23, 23, - 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, - 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, - 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, - 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, - 31, 31, 31, 31, 31, 31, 127, 127, 127, 127, 127, 127, 127, 127, 220, - 220, 220, 220, 220, 220, 220, 220, 249, 249, 249, 249, 249, 249, 249, 249, - 10, 10, 13, 13, 22, 22, 256, 256, 67, 67, 67, 67, 67, 67, 67, - 67, 68, 68, 68, 68, 68, 68, 68, 68, 95, 95, 95, 95, 95, 95, - 95, 95, 98, 98, 98, 98, 98, 98, 98, 98, 100, 100, 100, 100, 100, - 100, 100, 100, 102, 102, 102, 102, 102, 102, 102, 102, 103, 103, 103, 103, - 103, 103, 103, 103, 104, 104, 104, 104, 104, 104, 104, 104, 108, 108, 108, - 108, 108, 108, 108, 108, 109, 109, 109, 109, 109, 109, 109, 109, 110, 110, - 110, 110, 110, 110, 110, 110, 112, 112, 112, 112, 112, 112, 112, 112, 114, - 114, 114, 114, 114, 114, 114, 114, 117, 117, 117, 117, 117, 117, 117, 117, - 58, 58, 58, 58, 66, 66, 66, 66, 67, 67, 67, 67, 68, 68, 68, - 68, 69, 69, 69, 69, 70, 70, 70, 70, 71, 71, 71, 71, 72, 72, - 72, 72, 73, 73, 73, 73, 74, 74, 74, 74, 75, 75, 75, 75, 76, - 76, 76, 76, 77, 77, 77, 77, 78, 78, 78, 78, 79, 79, 79, 79, - 80, 80, 80, 80, 81, 81, 81, 81, 82, 82, 82, 82, 83, 83, 83, - 83, 84, 84, 84, 84, 85, 85, 85, 85, 86, 86, 86, 86, 87, 87, - 87, 87, 89, 89, 89, 89, 106, 106, 106, 106, 107, 107, 107, 107, 113, - 113, 113, 113, 118, 118, 118, 118, 119, 119, 119, 119, 120, 120, 120, 120, - 121, 121, 121, 121, 122, 122, 122, 122, 38, 38, 42, 42, 44, 44, 59, - 59, 88, 88, 90, 90, -1, -1, -1, -1, 33, 33, 33, 33, 33, 33, - 33, 33, 34, 34, 34, 34, 34, 34, 34, 34, 40, 40, 40, 40, 40, - 40, 40, 40, 41, 41, 41, 41, 41, 41, 41, 41, 63, 63, 63, 63, - 63, 63, 63, 63, 39, 39, 39, 39, 43, 43, 43, 43, 124, 124, 124, - 124, 35, 35, 62, 62, 0, 36, 64, 91, 93, 126, -1, -1, 94, 94, - 94, 94, 94, 94, 94, 94, 125, 125, 125, 125, 125, 125, 125, 125, 60, - 60, 60, 60, 96, 96, 96, 96, 123, 123, 123, 123, -1, -1, -1, -1, - 92, 92, 92, 92, 195, 195, 195, 195, 208, 208, 208, 208, 128, 128, 130, - 130, 131, 131, 162, 162, 184, 184, 194, 194, 224, 224, 226, 226, 153, 161, - 167, 172, 176, 177, 179, 209, 216, 217, 227, 229, 230, -1, -1, -1, -1, - -1, -1, -1, 129, 129, 129, 129, 129, 129, 129, 129, 132, 132, 132, 132, - 132, 132, 132, 132, 133, 133, 133, 133, 133, 133, 133, 133, 134, 134, 134, - 134, 134, 134, 134, 134, 136, 136, 136, 136, 136, 136, 136, 136, 146, 146, - 146, 146, 146, 146, 146, 146, 154, 154, 154, 154, 154, 154, 154, 154, 156, - 156, 156, 156, 156, 156, 156, 156, 160, 160, 160, 160, 160, 160, 160, 160, - 163, 163, 163, 163, 163, 163, 163, 163, 164, 164, 164, 164, 164, 164, 164, - 164, 169, 169, 169, 169, 169, 169, 169, 169, 170, 170, 170, 170, 170, 170, - 170, 170, 173, 173, 173, 173, 173, 173, 173, 173, 178, 178, 178, 178, 178, - 178, 178, 178, 181, 181, 181, 181, 181, 181, 181, 181, 185, 185, 185, 185, - 185, 185, 185, 185, 186, 186, 186, 186, 186, 186, 186, 186, 187, 187, 187, - 187, 187, 187, 187, 187, 189, 189, 189, 189, 189, 189, 189, 189, 190, 190, - 190, 190, 190, 190, 190, 190, 196, 196, 196, 196, 196, 196, 196, 196, 198, - 198, 198, 198, 198, 198, 198, 198, 228, 228, 228, 228, 228, 228, 228, 228, - 232, 232, 232, 232, 232, 232, 232, 232, 233, 233, 233, 233, 233, 233, 233, - 233, 1, 1, 1, 1, 135, 135, 135, 135, 137, 137, 137, 137, 138, 138, - 138, 138, 139, 139, 139, 139, 140, 140, 140, 140, 141, 141, 141, 141, 143, - 143, 143, 143, 147, 147, 147, 147, 149, 149, 149, 149, 150, 150, 150, 150, - 151, 151, 151, 151, 152, 152, 152, 152, 155, 155, 155, 155, 157, 157, 157, - 157, 158, 158, 158, 158, 165, 165, 165, 165, 166, 166, 166, 166, 168, 168, - 168, 168, 174, 174, 174, 174, 175, 175, 175, 175, 180, 180, 180, 180, 182, - 182, 182, 182, 183, 183, 183, 183, 188, 188, 188, 188, 191, 191, 191, 191, - 197, 197, 197, 197, 231, 231, 231, 231, 239, 239, 239, 239, 9, 9, 142, - 142, 144, 144, 145, 145, 148, 148, 159, 159, 171, 171, 206, 206, 215, 215, - 225, 225, 236, 236, 237, 237, 199, 207, 234, 235, 192, 192, 192, 192, 192, - 192, 192, 192, 193, 193, 193, 193, 193, 193, 193, 193, 200, 200, 200, 200, - 200, 200, 200, 200, 201, 201, 201, 201, 201, 201, 201, 201, 202, 202, 202, - 202, 202, 202, 202, 202, 205, 205, 205, 205, 205, 205, 205, 205, 210, 210, - 210, 210, 210, 210, 210, 210, 213, 213, 213, 213, 213, 213, 213, 213, 218, - 218, 218, 218, 218, 218, 218, 218, 219, 219, 219, 219, 219, 219, 219, 219, - 238, 238, 238, 238, 238, 238, 238, 238, 240, 240, 240, 240, 240, 240, 240, - 240, 242, 242, 242, 242, 242, 242, 242, 242, 243, 243, 243, 243, 243, 243, - 243, 243, 255, 255, 255, 255, 255, 255, 255, 255, 203, 203, 203, 203, 204, - 204, 204, 204, 211, 211, 211, 211, 212, 212, 212, 212, 214, 214, 214, 214, - 221, 221, 221, 221, 222, 222, 222, 222, 223, 223, 223, 223, 241, 241, 241, - 241, 244, 244, 244, 244, 245, 245, 245, 245, 246, 246, 246, 246, 247, 247, - 247, 247, 248, 248, 248, 248, 250, 250, 250, 250, 251, 251, 251, 251, 252, - 252, 252, 252, 253, 253, 253, 253, 254, 254, 254, 254, 2, 2, 3, 3, - 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 11, 11, 12, 12, 14, - 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, - 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, - 30, 31, 31, 127, 127, 220, 220, 249, 249, -1, -1, 10, 10, 10, 10, - 10, 10, 10, 10, 13, 13, 13, 13, 13, 13, 13, 13, 22, 22, 22, - 22, 22, 22, 22, 22, 256, 256, 256, 256, 256, 256, 256, 256, 45, 45, - 45, 45, 45, 45, 45, 45, 46, 46, 46, 46, 46, 46, 46, 46, 47, - 47, 47, 47, 47, 47, 47, 47, 51, 51, 51, 51, 51, 51, 51, 51, - 52, 52, 52, 52, 52, 52, 52, 52, 53, 53, 53, 53, 53, 53, 53, - 53, 54, 54, 54, 54, 54, 54, 54, 54, 55, 55, 55, 55, 55, 55, - 55, 55, 56, 56, 56, 56, 56, 56, 56, 56, 57, 57, 57, 57, 57, - 57, 57, 57, 50, 50, 50, 50, 50, 50, 50, 50, 97, 97, 97, 97, - 97, 97, 97, 97, 99, 99, 99, 99, 99, 99, 99, 99, 101, 101, 101, - 101, 101, 101, 101, 101, 105, 105, 105, 105, 105, 105, 105, 105, 111, 111, - 111, 111, 111, 111, 111, 111, 115, 115, 115, 115, 115, 115, 115, 115, 116, - 116, 116, 116, 116, 116, 116, 116, 32, 32, 32, 32, 37, 37, 37, 37, - 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47, 51, 51, 51, - 51, 52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, - 55, 55, 56, 56, 56, 56, 57, 57, 57, 57, 61, 61, 61, 61, 65, - 65, 65, 65, 95, 95, 95, 95, 98, 98, 98, 98, 100, 100, 100, 100, - 102, 102, 102, 102, 103, 103, 103, 103, 104, 104, 104, 104, 108, 108, 108, - 108, 109, 109, 109, 109, 110, 110, 110, 110, 112, 112, 112, 112, 114, 114, - 114, 114, 117, 117, 117, 117, 58, 58, 66, 66, 67, 67, 68, 68, 69, - 69, 70, 70, 71, 71, 72, 72, 73, 73, 74, 74, 75, 75, 76, 76, - 77, 77, 78, 78, 79, 79, 80, 80, 81, 81, 82, 82, 83, 83, 84, - 84, 85, 85, 86, 86, 87, 87, 89, 89, 106, 106, 107, 107, 113, 113, - 118, 118, 119, 119, 120, 120, 121, 121, 122, 122, 38, 42, 44, 59, 88, - 90, -1, -1, 33, 33, 33, 33, 34, 34, 34, 34, 40, 40, 40, 40, - 41, 41, 41, 41, 63, 63, 63, 63, 39, 39, 43, 43, 124, 124, 35, - 62, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 36, 36, - 36, 36, 36, 36, 36, 36, 64, 64, 64, 64, 64, 64, 64, 64, 91, - 91, 91, 91, 91, 91, 91, 91, 93, 93, 93, 93, 93, 93, 93, 93, - 126, 126, 126, 126, 126, 126, 126, 126, 94, 94, 94, 94, 125, 125, 125, - 125, 60, 60, 96, 96, 123, 123, -1, -1, 92, 92, 195, 195, 208, 208, - 128, 130, 131, 162, 184, 194, 224, 226, -1, -1, 153, 153, 153, 153, 153, - 153, 153, 153, 161, 161, 161, 161, 161, 161, 161, 161, 167, 167, 167, 167, - 167, 167, 167, 167, 172, 172, 172, 172, 172, 172, 172, 172, 176, 176, 176, - 176, 176, 176, 176, 176, 177, 177, 177, 177, 177, 177, 177, 177, 179, 179, - 179, 179, 179, 179, 179, 179, 209, 209, 209, 209, 209, 209, 209, 209, 216, - 216, 216, 216, 216, 216, 216, 216, 217, 217, 217, 217, 217, 217, 217, 217, - 227, 227, 227, 227, 227, 227, 227, 227, 229, 229, 229, 229, 229, 229, 229, - 229, 230, 230, 230, 230, 230, 230, 230, 230, 129, 129, 129, 129, 132, 132, - 132, 132, 133, 133, 133, 133, 134, 134, 134, 134, 136, 136, 136, 136, 146, - 146, 146, 146, 154, 154, 154, 154, 156, 156, 156, 156, 160, 160, 160, 160, - 163, 163, 163, 163, 164, 164, 164, 164, 169, 169, 169, 169, 170, 170, 170, - 170, 173, 173, 173, 173, 178, 178, 178, 178, 181, 181, 181, 181, 185, 185, - 185, 185, 186, 186, 186, 186, 187, 187, 187, 187, 189, 189, 189, 189, 190, - 190, 190, 190, 196, 196, 196, 196, 198, 198, 198, 198, 228, 228, 228, 228, - 232, 232, 232, 232, 233, 233, 233, 233, 1, 1, 135, 135, 137, 137, 138, - 138, 139, 139, 140, 140, 141, 141, 143, 143, 147, 147, 149, 149, 150, 150, - 151, 151, 152, 152, 155, 155, 157, 157, 158, 158, 165, 165, 166, 166, 168, - 168, 174, 174, 175, 175, 180, 180, 182, 182, 183, 183, 188, 188, 191, 191, - 197, 197, 231, 231, 239, 239, 9, 142, 144, 145, 148, 159, 171, 206, 215, - 225, 236, 237, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 199, 199, - 199, 199, 199, 199, 199, 199, 207, 207, 207, 207, 207, 207, 207, 207, 234, - 234, 234, 234, 234, 234, 234, 234, 235, 235, 235, 235, 235, 235, 235, 235, - 192, 192, 192, 192, 193, 193, 193, 193, 200, 200, 200, 200, 201, 201, 201, - 201, 202, 202, 202, 202, 205, 205, 205, 205, 210, 210, 210, 210, 213, 213, - 213, 213, 218, 218, 218, 218, 219, 219, 219, 219, 238, 238, 238, 238, 240, - 240, 240, 240, 242, 242, 242, 242, 243, 243, 243, 243, 255, 255, 255, 255, - 203, 203, 204, 204, 211, 211, 212, 212, 214, 214, 221, 221, 222, 222, 223, - 223, 241, 241, 244, 244, 245, 245, 246, 246, 247, 247, 248, 248, 250, 250, - 251, 251, 252, 252, 253, 253, 254, 254, 2, 3, 4, 5, 6, 7, 8, - 11, 12, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, - 28, 29, 30, 31, 127, 220, 249, -1, 10, 10, 10, 10, 13, 13, 13, - 13, 22, 22, 22, 22, 256, 256, 256, 256, -}; - -static const uint8_t inverse_base64[256] = { - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, - 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, - 255, 64, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 255, 255, 255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33, - 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, -}; - -/* emission helpers */ -static int on_hdr(grpc_chttp2_hpack_parser *p, grpc_mdelem *md, - int add_to_table) { - if (add_to_table) { - if (!grpc_chttp2_hptbl_add(&p->table, md)) { - return 0; - } - } - p->on_header(p->on_header_user_data, md); - return 1; -} - -static grpc_mdstr *take_string(grpc_chttp2_hpack_parser *p, - grpc_chttp2_hpack_parser_string *str) { - grpc_mdstr *s = grpc_mdstr_from_buffer((uint8_t *)str->str, str->length); - str->length = 0; - return s; -} - -/* jump to the next state */ -static int parse_next(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end) { - p->state = *p->next_state++; - return p->state(p, cur, end); -} - -/* begin parsing a header: all functionality is encoded into lookup tables - above */ -static int parse_begin(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end) { - if (cur == end) { - p->state = parse_begin; - return 1; - } - - return first_byte_action[first_byte_lut[*cur]](p, cur, end); -} - -/* stream dependency and prioritization data: we just skip it */ -static int parse_stream_weight(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end) { - if (cur == end) { - p->state = parse_stream_weight; - return 1; - } - - return p->after_prioritization(p, cur + 1, end); -} - -static int parse_stream_dep3(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end) { - if (cur == end) { - p->state = parse_stream_dep3; - return 1; - } - - return parse_stream_weight(p, cur + 1, end); -} - -static int parse_stream_dep2(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end) { - if (cur == end) { - p->state = parse_stream_dep2; - return 1; - } - - return parse_stream_dep3(p, cur + 1, end); -} - -static int parse_stream_dep1(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end) { - if (cur == end) { - p->state = parse_stream_dep1; - return 1; - } - - return parse_stream_dep2(p, cur + 1, end); -} - -static int parse_stream_dep0(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end) { - if (cur == end) { - p->state = parse_stream_dep0; - return 1; - } - - return parse_stream_dep1(p, cur + 1, end); -} - -/* emit an indexed field; for now just logs it to console; jumps to - begin the next field on completion */ -static int finish_indexed_field(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end) { - grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index); - if (md == NULL) { - gpr_log(GPR_ERROR, "Invalid HPACK index received: %d", p->index); - return 0; - } - GRPC_MDELEM_REF(md); - return on_hdr(p, md, 0) && parse_begin(p, cur, end); -} - -/* parse an indexed field with index < 127 */ -static int parse_indexed_field(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end) { - p->dynamic_table_update_allowed = 0; - p->index = (*cur) & 0x7f; - return finish_indexed_field(p, cur + 1, end); -} - -/* parse an indexed field with index >= 127 */ -static int parse_indexed_field_x(grpc_chttp2_hpack_parser *p, - const uint8_t *cur, const uint8_t *end) { - static const grpc_chttp2_hpack_parser_state and_then[] = { - finish_indexed_field}; - p->dynamic_table_update_allowed = 0; - p->next_state = and_then; - p->index = 0x7f; - p->parsing.value = &p->index; - return parse_value0(p, cur + 1, end); -} - -/* finish a literal header with incremental indexing: just log, and jump to ' - begin */ -static int finish_lithdr_incidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end) { - grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index); - GPR_ASSERT(md != NULL); /* handled in string parsing */ - return on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key), - take_string(p, &p->value)), - 1) && - parse_begin(p, cur, end); -} - -/* finish a literal header with incremental indexing with no index */ -static int finish_lithdr_incidx_v(grpc_chttp2_hpack_parser *p, - const uint8_t *cur, const uint8_t *end) { - return on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key), - take_string(p, &p->value)), - 1) && - parse_begin(p, cur, end); -} - -/* parse a literal header with incremental indexing; index < 63 */ -static int parse_lithdr_incidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end) { - static const grpc_chttp2_hpack_parser_state and_then[] = { - parse_value_string_with_indexed_key, finish_lithdr_incidx}; - p->dynamic_table_update_allowed = 0; - p->next_state = and_then; - p->index = (*cur) & 0x3f; - return parse_string_prefix(p, cur + 1, end); -} - -/* parse a literal header with incremental indexing; index >= 63 */ -static int parse_lithdr_incidx_x(grpc_chttp2_hpack_parser *p, - const uint8_t *cur, const uint8_t *end) { - static const grpc_chttp2_hpack_parser_state and_then[] = { - parse_string_prefix, parse_value_string_with_indexed_key, - finish_lithdr_incidx}; - p->dynamic_table_update_allowed = 0; - p->next_state = and_then; - p->index = 0x3f; - p->parsing.value = &p->index; - return parse_value0(p, cur + 1, end); -} - -/* parse a literal header with incremental indexing; index = 0 */ -static int parse_lithdr_incidx_v(grpc_chttp2_hpack_parser *p, - const uint8_t *cur, const uint8_t *end) { - static const grpc_chttp2_hpack_parser_state and_then[] = { - parse_key_string, parse_string_prefix, - parse_value_string_with_literal_key, finish_lithdr_incidx_v}; - p->dynamic_table_update_allowed = 0; - p->next_state = and_then; - return parse_string_prefix(p, cur + 1, end); -} - -/* finish a literal header without incremental indexing */ -static int finish_lithdr_notidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end) { - grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index); - GPR_ASSERT(md != NULL); /* handled in string parsing */ - return on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key), - take_string(p, &p->value)), - 0) && - parse_begin(p, cur, end); -} - -/* finish a literal header without incremental indexing with index = 0 */ -static int finish_lithdr_notidx_v(grpc_chttp2_hpack_parser *p, - const uint8_t *cur, const uint8_t *end) { - return on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key), - take_string(p, &p->value)), - 0) && - parse_begin(p, cur, end); -} - -/* parse a literal header without incremental indexing; index < 15 */ -static int parse_lithdr_notidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end) { - static const grpc_chttp2_hpack_parser_state and_then[] = { - parse_value_string_with_indexed_key, finish_lithdr_notidx}; - p->dynamic_table_update_allowed = 0; - p->next_state = and_then; - p->index = (*cur) & 0xf; - return parse_string_prefix(p, cur + 1, end); -} - -/* parse a literal header without incremental indexing; index >= 15 */ -static int parse_lithdr_notidx_x(grpc_chttp2_hpack_parser *p, - const uint8_t *cur, const uint8_t *end) { - static const grpc_chttp2_hpack_parser_state and_then[] = { - parse_string_prefix, parse_value_string_with_indexed_key, - finish_lithdr_notidx}; - p->dynamic_table_update_allowed = 0; - p->next_state = and_then; - p->index = 0xf; - p->parsing.value = &p->index; - return parse_value0(p, cur + 1, end); -} - -/* parse a literal header without incremental indexing; index == 0 */ -static int parse_lithdr_notidx_v(grpc_chttp2_hpack_parser *p, - const uint8_t *cur, const uint8_t *end) { - static const grpc_chttp2_hpack_parser_state and_then[] = { - parse_key_string, parse_string_prefix, - parse_value_string_with_literal_key, finish_lithdr_notidx_v}; - p->dynamic_table_update_allowed = 0; - p->next_state = and_then; - return parse_string_prefix(p, cur + 1, end); -} - -/* finish a literal header that is never indexed */ -static int finish_lithdr_nvridx(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end) { - grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index); - GPR_ASSERT(md != NULL); /* handled in string parsing */ - return on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key), - take_string(p, &p->value)), - 0) && - parse_begin(p, cur, end); -} - -/* finish a literal header that is never indexed with an extra value */ -static int finish_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p, - const uint8_t *cur, const uint8_t *end) { - return on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key), - take_string(p, &p->value)), - 0) && - parse_begin(p, cur, end); -} - -/* parse a literal header that is never indexed; index < 15 */ -static int parse_lithdr_nvridx(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end) { - static const grpc_chttp2_hpack_parser_state and_then[] = { - parse_value_string_with_indexed_key, finish_lithdr_nvridx}; - p->dynamic_table_update_allowed = 0; - p->next_state = and_then; - p->index = (*cur) & 0xf; - return parse_string_prefix(p, cur + 1, end); -} - -/* parse a literal header that is never indexed; index >= 15 */ -static int parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser *p, - const uint8_t *cur, const uint8_t *end) { - static const grpc_chttp2_hpack_parser_state and_then[] = { - parse_string_prefix, parse_value_string_with_indexed_key, - finish_lithdr_nvridx}; - p->dynamic_table_update_allowed = 0; - p->next_state = and_then; - p->index = 0xf; - p->parsing.value = &p->index; - return parse_value0(p, cur + 1, end); -} - -/* parse a literal header that is never indexed; index == 0 */ -static int parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p, - const uint8_t *cur, const uint8_t *end) { - static const grpc_chttp2_hpack_parser_state and_then[] = { - parse_key_string, parse_string_prefix, - parse_value_string_with_literal_key, finish_lithdr_nvridx_v}; - p->dynamic_table_update_allowed = 0; - p->next_state = and_then; - return parse_string_prefix(p, cur + 1, end); -} - -/* finish parsing a max table size change */ -static int finish_max_tbl_size(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end) { - gpr_log(GPR_INFO, "MAX TABLE SIZE: %d", p->index); - return grpc_chttp2_hptbl_set_current_table_size(&p->table, p->index) && - parse_begin(p, cur, end); -} - -/* parse a max table size change, max size < 15 */ -static int parse_max_tbl_size(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end) { - if (p->dynamic_table_update_allowed == 0) { - return 0; - } - p->dynamic_table_update_allowed--; - p->index = (*cur) & 0x1f; - return finish_max_tbl_size(p, cur + 1, end); -} - -/* parse a max table size change, max size >= 15 */ -static int parse_max_tbl_size_x(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end) { - static const grpc_chttp2_hpack_parser_state and_then[] = { - finish_max_tbl_size}; - if (p->dynamic_table_update_allowed == 0) { - return 0; - } - p->dynamic_table_update_allowed--; - p->next_state = and_then; - p->index = 0x1f; - p->parsing.value = &p->index; - return parse_value0(p, cur + 1, end); -} - -/* a parse error: jam the parse state into parse_error, and return error */ -static int parse_error(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end) { - p->state = parse_error; - return 0; -} - -static int parse_illegal_op(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end) { - GPR_ASSERT(cur != end); - gpr_log(GPR_DEBUG, "Illegal hpack op code %d", *cur); - return parse_error(p, cur, end); -} - -/* parse the 1st byte of a varint into p->parsing.value - no overflow is possible */ -static int parse_value0(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end) { - if (cur == end) { - p->state = parse_value0; - return 1; - } - - *p->parsing.value += (*cur) & 0x7f; - - if ((*cur) & 0x80) { - return parse_value1(p, cur + 1, end); - } else { - return parse_next(p, cur + 1, end); - } -} - -/* parse the 2nd byte of a varint into p->parsing.value - no overflow is possible */ -static int parse_value1(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end) { - if (cur == end) { - p->state = parse_value1; - return 1; - } - - *p->parsing.value += (((uint32_t)*cur) & 0x7f) << 7; - - if ((*cur) & 0x80) { - return parse_value2(p, cur + 1, end); - } else { - return parse_next(p, cur + 1, end); - } -} - -/* parse the 3rd byte of a varint into p->parsing.value - no overflow is possible */ -static int parse_value2(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end) { - if (cur == end) { - p->state = parse_value2; - return 1; - } - - *p->parsing.value += (((uint32_t)*cur) & 0x7f) << 14; - - if ((*cur) & 0x80) { - return parse_value3(p, cur + 1, end); - } else { - return parse_next(p, cur + 1, end); - } -} - -/* parse the 4th byte of a varint into p->parsing.value - no overflow is possible */ -static int parse_value3(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end) { - if (cur == end) { - p->state = parse_value3; - return 1; - } - - *p->parsing.value += (((uint32_t)*cur) & 0x7f) << 21; - - if ((*cur) & 0x80) { - return parse_value4(p, cur + 1, end); - } else { - return parse_next(p, cur + 1, end); - } -} - -/* parse the 5th byte of a varint into p->parsing.value - depending on the byte, we may overflow, and care must be taken */ -static int parse_value4(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end) { - uint8_t c; - uint32_t cur_value; - uint32_t add_value; - - if (cur == end) { - p->state = parse_value4; - return 1; - } - - c = (*cur) & 0x7f; - if (c > 0xf) { - goto error; - } - - cur_value = *p->parsing.value; - add_value = ((uint32_t)c) << 28; - if (add_value > 0xffffffffu - cur_value) { - goto error; - } - - *p->parsing.value = cur_value + add_value; - - if ((*cur) & 0x80) { - return parse_value5up(p, cur + 1, end); - } else { - return parse_next(p, cur + 1, end); - } - -error: - gpr_log(GPR_ERROR, - "integer overflow in hpack integer decoding: have 0x%08x, " - "got byte 0x%02x on byte 5", - *p->parsing.value, *cur); - return parse_error(p, cur, end); -} - -/* parse any trailing bytes in a varint: it's possible to append an arbitrary - number of 0x80's and not affect the value - a zero will terminate - and - anything else will overflow */ -static int parse_value5up(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end) { - while (cur != end && *cur == 0x80) { - ++cur; - } - - if (cur == end) { - p->state = parse_value5up; - return 1; - } - - if (*cur == 0) { - return parse_next(p, cur + 1, end); - } - - gpr_log(GPR_ERROR, - "integer overflow in hpack integer decoding: have 0x%08x, " - "got byte 0x%02x sometime after byte 5", - *p->parsing.value, *cur); - return parse_error(p, cur, end); -} - -/* parse a string prefix */ -static int parse_string_prefix(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end) { - if (cur == end) { - p->state = parse_string_prefix; - return 1; - } - - p->strlen = (*cur) & 0x7f; - p->huff = (*cur) >> 7; - if (p->strlen == 0x7f) { - p->parsing.value = &p->strlen; - return parse_value0(p, cur + 1, end); - } else { - return parse_next(p, cur + 1, end); - } -} - -/* append some bytes to a string */ -static void append_bytes(grpc_chttp2_hpack_parser_string *str, - const uint8_t *data, size_t length) { - if (length + str->length > str->capacity) { - GPR_ASSERT(str->length + length <= UINT32_MAX); - str->capacity = (uint32_t)(str->length + length); - str->str = gpr_realloc(str->str, str->capacity); - } - memcpy(str->str + str->length, data, length); - GPR_ASSERT(length <= UINT32_MAX - str->length); - str->length += (uint32_t)length; -} - -static int append_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end) { - grpc_chttp2_hpack_parser_string *str = p->parsing.str; - uint32_t bits; - uint8_t decoded[3]; - switch ((binary_state)p->binary) { - case NOT_BINARY: - append_bytes(str, cur, (size_t)(end - cur)); - return 1; - b64_byte0: - case B64_BYTE0: - if (cur == end) { - p->binary = B64_BYTE0; - return 1; - } - bits = inverse_base64[*cur]; - ++cur; - if (bits == 255) - return 0; - else if (bits == 64) - goto b64_byte0; - p->base64_buffer = bits << 18; - /* fallthrough */ - b64_byte1: - case B64_BYTE1: - if (cur == end) { - p->binary = B64_BYTE1; - return 1; - } - bits = inverse_base64[*cur]; - ++cur; - if (bits == 255) - return 0; - else if (bits == 64) - goto b64_byte1; - p->base64_buffer |= bits << 12; - /* fallthrough */ - b64_byte2: - case B64_BYTE2: - if (cur == end) { - p->binary = B64_BYTE2; - return 1; - } - bits = inverse_base64[*cur]; - ++cur; - if (bits == 255) - return 0; - else if (bits == 64) - goto b64_byte2; - p->base64_buffer |= bits << 6; - /* fallthrough */ - b64_byte3: - case B64_BYTE3: - if (cur == end) { - p->binary = B64_BYTE3; - return 1; - } - bits = inverse_base64[*cur]; - ++cur; - if (bits == 255) - return 0; - else if (bits == 64) - goto b64_byte3; - p->base64_buffer |= bits; - bits = p->base64_buffer; - decoded[0] = (uint8_t)(bits >> 16); - decoded[1] = (uint8_t)(bits >> 8); - decoded[2] = (uint8_t)(bits); - append_bytes(str, decoded, 3); - goto b64_byte0; - } - GPR_UNREACHABLE_CODE(return 1); -} - -/* append a null terminator to a string */ -static int finish_str(grpc_chttp2_hpack_parser *p) { - uint8_t terminator = 0; - uint8_t decoded[2]; - uint32_t bits; - grpc_chttp2_hpack_parser_string *str = p->parsing.str; - switch ((binary_state)p->binary) { - case NOT_BINARY: - break; - case B64_BYTE0: - break; - case B64_BYTE1: - gpr_log(GPR_ERROR, "illegal base64 encoding"); - return 0; /* illegal encoding */ - case B64_BYTE2: - bits = p->base64_buffer; - if (bits & 0xffff) { - gpr_log(GPR_ERROR, "trailing bits in base64 encoding: 0x%04x", - bits & 0xffff); - return 0; - } - decoded[0] = (uint8_t)(bits >> 16); - append_bytes(str, decoded, 1); - break; - case B64_BYTE3: - bits = p->base64_buffer; - if (bits & 0xff) { - gpr_log(GPR_ERROR, "trailing bits in base64 encoding: 0x%02x", - bits & 0xff); - return 0; - } - decoded[0] = (uint8_t)(bits >> 16); - decoded[1] = (uint8_t)(bits >> 8); - append_bytes(str, decoded, 2); - break; - } - append_bytes(str, &terminator, 1); - p->parsing.str->length--; /* don't actually count the null terminator */ - return 1; -} - -/* decode a nibble from a huffman encoded stream */ -static int huff_nibble(grpc_chttp2_hpack_parser *p, uint8_t nibble) { - int16_t emit = emit_sub_tbl[16 * emit_tbl[p->huff_state] + nibble]; - int16_t next = next_sub_tbl[16 * next_tbl[p->huff_state] + nibble]; - if (emit != -1) { - if (emit >= 0 && emit < 256) { - uint8_t c = (uint8_t)emit; - if (!append_string(p, &c, (&c) + 1)) return 0; - } else { - assert(emit == 256); - } - } - p->huff_state = next; - return 1; -} - -/* decode full bytes from a huffman encoded stream */ -static int add_huff_bytes(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end) { - for (; cur != end; ++cur) { - if (!huff_nibble(p, *cur >> 4) || !huff_nibble(p, *cur & 0xf)) return 0; - } - return 1; -} - -/* decode some string bytes based on the current decoding mode - (huffman or not) */ -static int add_str_bytes(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end) { - if (p->huff) { - return add_huff_bytes(p, cur, end); - } else { - return append_string(p, cur, end); - } -} - -/* parse a string - tries to do large chunks at a time */ -static int parse_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end) { - size_t remaining = p->strlen - p->strgot; - size_t given = (size_t)(end - cur); - if (remaining <= given) { - return add_str_bytes(p, cur, cur + remaining) && finish_str(p) && - parse_next(p, cur + remaining, end); - } else { - if (!add_str_bytes(p, cur, cur + given)) return 0; - GPR_ASSERT(given <= UINT32_MAX - p->strgot); - p->strgot += (uint32_t)given; - p->state = parse_string; - return 1; - } -} - -/* begin parsing a string - performs setup, calls parse_string */ -static int begin_parse_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end, uint8_t binary, - grpc_chttp2_hpack_parser_string *str) { - p->strgot = 0; - str->length = 0; - p->parsing.str = str; - p->huff_state = 0; - p->binary = binary; - return parse_string(p, cur, end); -} - -/* parse the key string */ -static int parse_key_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end) { - return begin_parse_string(p, cur, end, NOT_BINARY, &p->key); -} - -/* check if a key represents a binary header or not */ -typedef enum { BINARY_HEADER, PLAINTEXT_HEADER, ERROR_HEADER } is_binary_header; - -static is_binary_header is_binary_literal_header(grpc_chttp2_hpack_parser *p) { - return grpc_is_binary_header(p->key.str, p->key.length) ? BINARY_HEADER - : PLAINTEXT_HEADER; -} - -static is_binary_header is_binary_indexed_header(grpc_chttp2_hpack_parser *p) { - grpc_mdelem *elem = grpc_chttp2_hptbl_lookup(&p->table, p->index); - if (!elem) { - gpr_log(GPR_ERROR, "Invalid HPACK index received: %d", p->index); - return ERROR_HEADER; - } - return grpc_is_binary_header( - (const char *)GPR_SLICE_START_PTR(elem->key->slice), - GPR_SLICE_LENGTH(elem->key->slice)) - ? BINARY_HEADER - : PLAINTEXT_HEADER; -} - -/* parse the value string */ -static int parse_value_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur, - const uint8_t *end, is_binary_header type) { - switch (type) { - case BINARY_HEADER: - return begin_parse_string(p, cur, end, B64_BYTE0, &p->value); - case PLAINTEXT_HEADER: - return begin_parse_string(p, cur, end, NOT_BINARY, &p->value); - case ERROR_HEADER: - return 0; - } - /* Add code to prevent return without value error */ - GPR_UNREACHABLE_CODE(return 0); -} - -static int parse_value_string_with_indexed_key(grpc_chttp2_hpack_parser *p, - const uint8_t *cur, - const uint8_t *end) { - return parse_value_string(p, cur, end, is_binary_indexed_header(p)); -} - -static int parse_value_string_with_literal_key(grpc_chttp2_hpack_parser *p, - const uint8_t *cur, - const uint8_t *end) { - return parse_value_string(p, cur, end, is_binary_literal_header(p)); -} - -/* PUBLIC INTERFACE */ - -static void on_header_not_set(void *user_data, grpc_mdelem *md) { - GPR_UNREACHABLE_CODE(return ); -} - -void grpc_chttp2_hpack_parser_init(grpc_chttp2_hpack_parser *p) { - p->on_header = on_header_not_set; - p->on_header_user_data = NULL; - p->state = parse_begin; - p->key.str = NULL; - p->key.capacity = 0; - p->key.length = 0; - p->value.str = NULL; - p->value.capacity = 0; - p->value.length = 0; - p->dynamic_table_update_allowed = 2; - grpc_chttp2_hptbl_init(&p->table); -} - -void grpc_chttp2_hpack_parser_set_has_priority(grpc_chttp2_hpack_parser *p) { - p->after_prioritization = p->state; - p->state = parse_stream_dep0; -} - -void grpc_chttp2_hpack_parser_destroy(grpc_chttp2_hpack_parser *p) { - grpc_chttp2_hptbl_destroy(&p->table); - gpr_free(p->key.str); - gpr_free(p->value.str); -} - -int grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser *p, - const uint8_t *beg, const uint8_t *end) { - /* TODO(ctiller): limit the distance of end from beg, and perform multiple - steps in the event of a large chunk of data to limit - stack space usage when no tail call optimization is - available */ - return p->state(p, beg, end); -} - -grpc_chttp2_parse_error grpc_chttp2_header_parser_parse( - grpc_exec_ctx *exec_ctx, void *hpack_parser, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { - grpc_chttp2_hpack_parser *parser = hpack_parser; - GPR_TIMER_BEGIN("grpc_chttp2_hpack_parser_parse", 0); - if (!grpc_chttp2_hpack_parser_parse(parser, GPR_SLICE_START_PTR(slice), - GPR_SLICE_END_PTR(slice))) { - GPR_TIMER_END("grpc_chttp2_hpack_parser_parse", 0); - return GRPC_CHTTP2_CONNECTION_ERROR; - } - if (is_last) { - if (parser->is_boundary && parser->state != parse_begin) { - gpr_log(GPR_ERROR, - "end of header frame not aligned with a hpack record boundary"); - GPR_TIMER_END("grpc_chttp2_hpack_parser_parse", 0); - return GRPC_CHTTP2_CONNECTION_ERROR; - } - /* need to check for null stream: this can occur if we receive an invalid - stream id on a header */ - if (stream_parsing != NULL) { - if (parser->is_boundary) { - stream_parsing - ->got_metadata_on_parse[stream_parsing->header_frames_received] = 1; - stream_parsing->header_frames_received++; - grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, - stream_parsing); - } - if (parser->is_eof) { - stream_parsing->received_close = 1; - } - } - parser->on_header = on_header_not_set; - parser->on_header_user_data = NULL; - parser->is_boundary = 0xde; - parser->is_eof = 0xde; - parser->dynamic_table_update_allowed = 2; - } - GPR_TIMER_END("grpc_chttp2_hpack_parser_parse", 0); - return GRPC_CHTTP2_PARSE_OK; -} diff --git a/src/core/transport/chttp2/hpack_parser.h b/src/core/transport/chttp2/hpack_parser.h deleted file mode 100644 index 6a6d136da2..0000000000 --- a/src/core/transport/chttp2/hpack_parser.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * - * Copyright 2015-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_TRANSPORT_CHTTP2_HPACK_PARSER_H -#define GRPC_CORE_TRANSPORT_CHTTP2_HPACK_PARSER_H - -#include - -#include -#include "src/core/iomgr/exec_ctx.h" -#include "src/core/transport/chttp2/frame.h" -#include "src/core/transport/chttp2/hpack_table.h" -#include "src/core/transport/metadata.h" - -typedef struct grpc_chttp2_hpack_parser grpc_chttp2_hpack_parser; - -typedef int (*grpc_chttp2_hpack_parser_state)(grpc_chttp2_hpack_parser *p, - const uint8_t *beg, - const uint8_t *end); - -typedef struct { - char *str; - uint32_t length; - uint32_t capacity; -} grpc_chttp2_hpack_parser_string; - -struct grpc_chttp2_hpack_parser { - /* user specified callback for each header output */ - void (*on_header)(void *user_data, grpc_mdelem *md); - void *on_header_user_data; - - /* current parse state - or a function that implements it */ - grpc_chttp2_hpack_parser_state state; - /* future states dependent on the opening op code */ - const grpc_chttp2_hpack_parser_state *next_state; - /* what to do after skipping prioritization data */ - grpc_chttp2_hpack_parser_state after_prioritization; - /* the value we're currently parsing */ - union { - uint32_t *value; - grpc_chttp2_hpack_parser_string *str; - } parsing; - /* string parameters for each chunk */ - grpc_chttp2_hpack_parser_string key; - grpc_chttp2_hpack_parser_string value; - /* parsed index */ - uint32_t index; - /* length of source bytes for the currently parsing string */ - uint32_t strlen; - /* number of source bytes read for the currently parsing string */ - uint32_t strgot; - /* huffman decoding state */ - int16_t huff_state; - /* is the string being decoded binary? */ - uint8_t binary; - /* is the current string huffman encoded? */ - uint8_t huff; - /* is a dynamic table update allowed? */ - uint8_t dynamic_table_update_allowed; - /* set by higher layers, used by grpc_chttp2_header_parser_parse to signal - it should append a metadata boundary at the end of frame */ - uint8_t is_boundary; - uint8_t is_eof; - uint32_t base64_buffer; - - /* hpack table */ - grpc_chttp2_hptbl table; -}; - -void grpc_chttp2_hpack_parser_init(grpc_chttp2_hpack_parser *p); -void grpc_chttp2_hpack_parser_destroy(grpc_chttp2_hpack_parser *p); - -void grpc_chttp2_hpack_parser_set_has_priority(grpc_chttp2_hpack_parser *p); - -/* returns 1 on success, 0 on error */ -int grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser *p, - const uint8_t *beg, const uint8_t *end); - -/* wraps grpc_chttp2_hpack_parser_parse to provide a frame level parser for - the transport */ -grpc_chttp2_parse_error grpc_chttp2_header_parser_parse( - grpc_exec_ctx *exec_ctx, void *hpack_parser, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); - -#endif /* GRPC_CORE_TRANSPORT_CHTTP2_HPACK_PARSER_H */ diff --git a/src/core/transport/chttp2/hpack_table.c b/src/core/transport/chttp2/hpack_table.c deleted file mode 100644 index f1ce3b84fd..0000000000 --- a/src/core/transport/chttp2/hpack_table.c +++ /dev/null @@ -1,361 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/transport/chttp2/hpack_table.h" - -#include -#include - -#include -#include - -#include "src/core/support/murmur_hash.h" - -static struct { - const char *key; - const char *value; -} static_table[] = { - /* 0: */ - {NULL, NULL}, - /* 1: */ - {":authority", ""}, - /* 2: */ - {":method", "GET"}, - /* 3: */ - {":method", "POST"}, - /* 4: */ - {":path", "/"}, - /* 5: */ - {":path", "/index.html"}, - /* 6: */ - {":scheme", "http"}, - /* 7: */ - {":scheme", "https"}, - /* 8: */ - {":status", "200"}, - /* 9: */ - {":status", "204"}, - /* 10: */ - {":status", "206"}, - /* 11: */ - {":status", "304"}, - /* 12: */ - {":status", "400"}, - /* 13: */ - {":status", "404"}, - /* 14: */ - {":status", "500"}, - /* 15: */ - {"accept-charset", ""}, - /* 16: */ - {"accept-encoding", "gzip, deflate"}, - /* 17: */ - {"accept-language", ""}, - /* 18: */ - {"accept-ranges", ""}, - /* 19: */ - {"accept", ""}, - /* 20: */ - {"access-control-allow-origin", ""}, - /* 21: */ - {"age", ""}, - /* 22: */ - {"allow", ""}, - /* 23: */ - {"authorization", ""}, - /* 24: */ - {"cache-control", ""}, - /* 25: */ - {"content-disposition", ""}, - /* 26: */ - {"content-encoding", ""}, - /* 27: */ - {"content-language", ""}, - /* 28: */ - {"content-length", ""}, - /* 29: */ - {"content-location", ""}, - /* 30: */ - {"content-range", ""}, - /* 31: */ - {"content-type", ""}, - /* 32: */ - {"cookie", ""}, - /* 33: */ - {"date", ""}, - /* 34: */ - {"etag", ""}, - /* 35: */ - {"expect", ""}, - /* 36: */ - {"expires", ""}, - /* 37: */ - {"from", ""}, - /* 38: */ - {"host", ""}, - /* 39: */ - {"if-match", ""}, - /* 40: */ - {"if-modified-since", ""}, - /* 41: */ - {"if-none-match", ""}, - /* 42: */ - {"if-range", ""}, - /* 43: */ - {"if-unmodified-since", ""}, - /* 44: */ - {"last-modified", ""}, - /* 45: */ - {"link", ""}, - /* 46: */ - {"location", ""}, - /* 47: */ - {"max-forwards", ""}, - /* 48: */ - {"proxy-authenticate", ""}, - /* 49: */ - {"proxy-authorization", ""}, - /* 50: */ - {"range", ""}, - /* 51: */ - {"referer", ""}, - /* 52: */ - {"refresh", ""}, - /* 53: */ - {"retry-after", ""}, - /* 54: */ - {"server", ""}, - /* 55: */ - {"set-cookie", ""}, - /* 56: */ - {"strict-transport-security", ""}, - /* 57: */ - {"transfer-encoding", ""}, - /* 58: */ - {"user-agent", ""}, - /* 59: */ - {"vary", ""}, - /* 60: */ - {"via", ""}, - /* 61: */ - {"www-authenticate", ""}, -}; - -static uint32_t entries_for_bytes(uint32_t bytes) { - return (bytes + GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD - 1) / - GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD; -} - -void grpc_chttp2_hptbl_init(grpc_chttp2_hptbl *tbl) { - size_t i; - - memset(tbl, 0, sizeof(*tbl)); - tbl->current_table_bytes = tbl->max_bytes = - GRPC_CHTTP2_INITIAL_HPACK_TABLE_SIZE; - tbl->max_entries = tbl->cap_entries = - entries_for_bytes(tbl->current_table_bytes); - tbl->ents = gpr_malloc(sizeof(*tbl->ents) * tbl->cap_entries); - memset(tbl->ents, 0, sizeof(*tbl->ents) * tbl->cap_entries); - for (i = 1; i <= GRPC_CHTTP2_LAST_STATIC_ENTRY; i++) { - tbl->static_ents[i - 1] = - grpc_mdelem_from_strings(static_table[i].key, static_table[i].value); - } -} - -void grpc_chttp2_hptbl_destroy(grpc_chttp2_hptbl *tbl) { - size_t i; - for (i = 0; i < GRPC_CHTTP2_LAST_STATIC_ENTRY; i++) { - GRPC_MDELEM_UNREF(tbl->static_ents[i]); - } - for (i = 0; i < tbl->num_ents; i++) { - GRPC_MDELEM_UNREF(tbl->ents[(tbl->first_ent + i) % tbl->cap_entries]); - } - gpr_free(tbl->ents); -} - -grpc_mdelem *grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl, - uint32_t tbl_index) { - /* Static table comes first, just return an entry from it */ - if (tbl_index <= GRPC_CHTTP2_LAST_STATIC_ENTRY) { - return tbl->static_ents[tbl_index - 1]; - } - /* Otherwise, find the value in the list of valid entries */ - tbl_index -= (GRPC_CHTTP2_LAST_STATIC_ENTRY + 1); - if (tbl_index < tbl->num_ents) { - uint32_t offset = - (tbl->num_ents - 1u - tbl_index + tbl->first_ent) % tbl->cap_entries; - return tbl->ents[offset]; - } - /* Invalid entry: return error */ - return NULL; -} - -/* Evict one element from the table */ -static void evict1(grpc_chttp2_hptbl *tbl) { - grpc_mdelem *first_ent = tbl->ents[tbl->first_ent]; - size_t elem_bytes = GPR_SLICE_LENGTH(first_ent->key->slice) + - GPR_SLICE_LENGTH(first_ent->value->slice) + - GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD; - GPR_ASSERT(elem_bytes <= tbl->mem_used); - tbl->mem_used -= (uint32_t)elem_bytes; - tbl->first_ent = ((tbl->first_ent + 1) % tbl->cap_entries); - tbl->num_ents--; - GRPC_MDELEM_UNREF(first_ent); -} - -static void rebuild_ents(grpc_chttp2_hptbl *tbl, uint32_t new_cap) { - grpc_mdelem **ents = gpr_malloc(sizeof(*ents) * new_cap); - uint32_t i; - - for (i = 0; i < tbl->num_ents; i++) { - ents[i] = tbl->ents[(tbl->first_ent + i) % tbl->cap_entries]; - } - gpr_free(tbl->ents); - tbl->ents = ents; - tbl->cap_entries = new_cap; - tbl->first_ent = 0; -} - -void grpc_chttp2_hptbl_set_max_bytes(grpc_chttp2_hptbl *tbl, - uint32_t max_bytes) { - if (tbl->max_bytes == max_bytes) { - return; - } - gpr_log(GPR_DEBUG, "Update hpack parser max size to %d", max_bytes); - while (tbl->mem_used > max_bytes) { - evict1(tbl); - } - tbl->max_bytes = max_bytes; -} - -int grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl, - uint32_t bytes) { - if (tbl->current_table_bytes == bytes) { - return 1; - } - if (bytes > tbl->max_bytes) { - gpr_log(GPR_ERROR, - "Attempt to make hpack table %d bytes when max is %d bytes", bytes, - tbl->max_bytes); - return 0; - } - gpr_log(GPR_DEBUG, "Update hpack parser table size to %d", bytes); - while (tbl->mem_used > bytes) { - evict1(tbl); - } - tbl->current_table_bytes = bytes; - tbl->max_entries = entries_for_bytes(bytes); - if (tbl->max_entries > tbl->cap_entries) { - rebuild_ents(tbl, GPR_MAX(tbl->max_entries, 2 * tbl->cap_entries)); - } else if (tbl->max_entries < tbl->cap_entries / 3) { - uint32_t new_cap = GPR_MAX(tbl->max_entries, 16u); - if (new_cap != tbl->cap_entries) { - rebuild_ents(tbl, new_cap); - } - } - return 1; -} - -int grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) { - /* determine how many bytes of buffer this entry represents */ - size_t elem_bytes = GPR_SLICE_LENGTH(md->key->slice) + - GPR_SLICE_LENGTH(md->value->slice) + - GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD; - - if (tbl->current_table_bytes > tbl->max_bytes) { - gpr_log(GPR_ERROR, - "HPACK max table size reduced to %d but not reflected by hpack " - "stream (still at %d)", - tbl->max_bytes, tbl->current_table_bytes); - return 0; - } - - /* we can't add elements bigger than the max table size */ - if (elem_bytes > tbl->current_table_bytes) { - /* HPACK draft 10 section 4.4 states: - * If the size of the new entry is less than or equal to the maximum - * size, that entry is added to the table. It is not an error to - * attempt to add an entry that is larger than the maximum size; an - * attempt to add an entry larger than the entire table causes - * the table - * to be emptied of all existing entries, and results in an - * empty table. - */ - while (tbl->num_ents) { - evict1(tbl); - } - return 1; - } - - /* evict entries to ensure no overflow */ - while (elem_bytes > (size_t)tbl->current_table_bytes - tbl->mem_used) { - evict1(tbl); - } - - /* copy the finalized entry in */ - tbl->ents[(tbl->first_ent + tbl->num_ents) % tbl->cap_entries] = - GRPC_MDELEM_REF(md); - - /* update accounting values */ - tbl->num_ents++; - tbl->mem_used += (uint32_t)elem_bytes; - return 1; -} - -grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find( - const grpc_chttp2_hptbl *tbl, grpc_mdelem *md) { - grpc_chttp2_hptbl_find_result r = {0, 0}; - uint32_t i; - - /* See if the string is in the static table */ - for (i = 0; i < GRPC_CHTTP2_LAST_STATIC_ENTRY; i++) { - grpc_mdelem *ent = tbl->static_ents[i]; - if (md->key != ent->key) continue; - r.index = i + 1u; - r.has_value = md->value == ent->value; - if (r.has_value) return r; - } - - /* Scan the dynamic table */ - for (i = 0; i < tbl->num_ents; i++) { - uint32_t idx = - (uint32_t)(tbl->num_ents - i + GRPC_CHTTP2_LAST_STATIC_ENTRY); - grpc_mdelem *ent = tbl->ents[(tbl->first_ent + i) % tbl->cap_entries]; - if (md->key != ent->key) continue; - r.index = idx; - r.has_value = md->value == ent->value; - if (r.has_value) return r; - } - - return r; -} diff --git a/src/core/transport/chttp2/hpack_table.h b/src/core/transport/chttp2/hpack_table.h deleted file mode 100644 index c984ca35e4..0000000000 --- a/src/core/transport/chttp2/hpack_table.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * - * Copyright 2015-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_TRANSPORT_CHTTP2_HPACK_TABLE_H -#define GRPC_CORE_TRANSPORT_CHTTP2_HPACK_TABLE_H - -#include -#include -#include "src/core/transport/metadata.h" - -/* HPACK header table */ - -/* last index in the static table */ -#define GRPC_CHTTP2_LAST_STATIC_ENTRY 61 - -/* Initial table size as per the spec */ -#define GRPC_CHTTP2_INITIAL_HPACK_TABLE_SIZE 4096 -/* Maximum table size that we'll use */ -#define GRPC_CHTTP2_MAX_HPACK_TABLE_SIZE GRPC_CHTTP2_INITIAL_HPACK_TABLE_SIZE -/* Per entry overhead bytes as per the spec */ -#define GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD 32 -#if 0 -/* Maximum number of entries we could possibly fit in the table, given defined - overheads */ -#define GRPC_CHTTP2_MAX_TABLE_COUNT \ - ((GRPC_CHTTP2_MAX_HPACK_TABLE_SIZE + GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD - 1) / \ - GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD) -#endif - -/* hpack decoder table */ -typedef struct { - /* the first used entry in ents */ - uint32_t first_ent; - /* how many entries are in the table */ - uint32_t num_ents; - /* the amount of memory used by the table, according to the hpack algorithm */ - uint32_t mem_used; - /* the max memory allowed to be used by the table, according to the hpack - algorithm */ - uint32_t max_bytes; - /* the currently agreed size of the table, according to the hpack algorithm */ - uint32_t current_table_bytes; - /* Maximum number of entries we could possibly fit in the table, given defined - overheads */ - uint32_t max_entries; - /* Number of entries allocated in ents */ - uint32_t cap_entries; - /* a circular buffer of headers - this is stored in the opposite order to - what hpack specifies, in order to simplify table management a little... - meaning lookups need to SUBTRACT from the end position */ - grpc_mdelem **ents; - grpc_mdelem *static_ents[GRPC_CHTTP2_LAST_STATIC_ENTRY]; -} grpc_chttp2_hptbl; - -/* initialize a hpack table */ -void grpc_chttp2_hptbl_init(grpc_chttp2_hptbl *tbl); -void grpc_chttp2_hptbl_destroy(grpc_chttp2_hptbl *tbl); -void grpc_chttp2_hptbl_set_max_bytes(grpc_chttp2_hptbl *tbl, - uint32_t max_bytes); -int grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl, - uint32_t bytes); - -/* lookup a table entry based on its hpack index */ -grpc_mdelem *grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl, - uint32_t index); -/* add a table entry to the index */ -int grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, - grpc_mdelem *md) GRPC_MUST_USE_RESULT; -/* Find a key/value pair in the table... returns the index in the table of the - most similar entry, or 0 if the value was not found */ -typedef struct { - uint32_t index; - int has_value; -} grpc_chttp2_hptbl_find_result; -grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find( - const grpc_chttp2_hptbl *tbl, grpc_mdelem *md); - -#endif /* GRPC_CORE_TRANSPORT_CHTTP2_HPACK_TABLE_H */ diff --git a/src/core/transport/chttp2/hpack_tables.txt b/src/core/transport/chttp2/hpack_tables.txt deleted file mode 100644 index 08842a0267..0000000000 --- a/src/core/transport/chttp2/hpack_tables.txt +++ /dev/null @@ -1,66 +0,0 @@ -Static table, from the spec: - +-------+-----------------------------+---------------+ - | Index | Header Name | Header Value | - +-------+-----------------------------+---------------+ - | 1 | :authority | | - | 2 | :method | GET | - | 3 | :method | POST | - | 4 | :path | / | - | 5 | :path | /index.html | - | 6 | :scheme | http | - | 7 | :scheme | https | - | 8 | :status | 200 | - | 9 | :status | 204 | - | 10 | :status | 206 | - | 11 | :status | 304 | - | 12 | :status | 400 | - | 13 | :status | 404 | - | 14 | :status | 500 | - | 15 | accept-charset | | - | 16 | accept-encoding | gzip, deflate | - | 17 | accept-language | | - | 18 | accept-ranges | | - | 19 | accept | | - | 20 | access-control-allow-origin | | - | 21 | age | | - | 22 | allow | | - | 23 | authorization | | - | 24 | cache-control | | - | 25 | content-disposition | | - | 26 | content-encoding | | - | 27 | content-language | | - | 28 | content-length | | - | 29 | content-location | | - | 30 | content-range | | - | 31 | content-type | | - | 32 | cookie | | - | 33 | date | | - | 34 | etag | | - | 35 | expect | | - | 36 | expires | | - | 37 | from | | - | 38 | host | | - | 39 | if-match | | - | 40 | if-modified-since | | - | 41 | if-none-match | | - | 42 | if-range | | - | 43 | if-unmodified-since | | - | 44 | last-modified | | - | 45 | link | | - | 46 | location | | - | 47 | max-forwards | | - | 48 | proxy-authenticate | | - | 49 | proxy-authorization | | - | 50 | range | | - | 51 | referer | | - | 52 | refresh | | - | 53 | retry-after | | - | 54 | server | | - | 55 | set-cookie | | - | 56 | strict-transport-security | | - | 57 | transfer-encoding | | - | 58 | user-agent | | - | 59 | vary | | - | 60 | via | | - | 61 | www-authenticate | | - +-------+-----------------------------+---------------+ diff --git a/src/core/transport/chttp2/http2_errors.h b/src/core/transport/chttp2/http2_errors.h deleted file mode 100644 index 4290df3d89..0000000000 --- a/src/core/transport/chttp2/http2_errors.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * - * Copyright 2015-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_TRANSPORT_CHTTP2_HTTP2_ERRORS_H -#define GRPC_CORE_TRANSPORT_CHTTP2_HTTP2_ERRORS_H - -/* error codes for RST_STREAM from http2 draft 14 section 7 */ -typedef enum { - GRPC_CHTTP2_NO_ERROR = 0x0, - GRPC_CHTTP2_PROTOCOL_ERROR = 0x1, - GRPC_CHTTP2_INTERNAL_ERROR = 0x2, - GRPC_CHTTP2_FLOW_CONTROL_ERROR = 0x3, - GRPC_CHTTP2_SETTINGS_TIMEOUT = 0x4, - GRPC_CHTTP2_STREAM_CLOSED = 0x5, - GRPC_CHTTP2_FRAME_SIZE_ERROR = 0x6, - GRPC_CHTTP2_REFUSED_STREAM = 0x7, - GRPC_CHTTP2_CANCEL = 0x8, - GRPC_CHTTP2_COMPRESSION_ERROR = 0x9, - GRPC_CHTTP2_CONNECT_ERROR = 0xa, - GRPC_CHTTP2_ENHANCE_YOUR_CALM = 0xb, - GRPC_CHTTP2_INADEQUATE_SECURITY = 0xc, - /* force use of a default clause */ - GRPC_CHTTP2__ERROR_DO_NOT_USE = -1 -} grpc_chttp2_error_code; - -#endif /* GRPC_CORE_TRANSPORT_CHTTP2_HTTP2_ERRORS_H */ diff --git a/src/core/transport/chttp2/huffsyms.c b/src/core/transport/chttp2/huffsyms.c deleted file mode 100644 index ebc85d3378..0000000000 --- a/src/core/transport/chttp2/huffsyms.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * - * Copyright 2015-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/transport/chttp2/huffsyms.h" - -/* Constants pulled from the HPACK spec, and converted to C using the vim - command: - :%s/.* \([0-9a-f]\+\) \[ *\([0-9]\+\)\]/{0x\1, \2},/g */ -const grpc_chttp2_huffsym grpc_chttp2_huffsyms[GRPC_CHTTP2_NUM_HUFFSYMS] = { - {0x1ff8, 13}, {0x7fffd8, 23}, {0xfffffe2, 28}, {0xfffffe3, 28}, - {0xfffffe4, 28}, {0xfffffe5, 28}, {0xfffffe6, 28}, {0xfffffe7, 28}, - {0xfffffe8, 28}, {0xffffea, 24}, {0x3ffffffc, 30}, {0xfffffe9, 28}, - {0xfffffea, 28}, {0x3ffffffd, 30}, {0xfffffeb, 28}, {0xfffffec, 28}, - {0xfffffed, 28}, {0xfffffee, 28}, {0xfffffef, 28}, {0xffffff0, 28}, - {0xffffff1, 28}, {0xffffff2, 28}, {0x3ffffffe, 30}, {0xffffff3, 28}, - {0xffffff4, 28}, {0xffffff5, 28}, {0xffffff6, 28}, {0xffffff7, 28}, - {0xffffff8, 28}, {0xffffff9, 28}, {0xffffffa, 28}, {0xffffffb, 28}, - {0x14, 6}, {0x3f8, 10}, {0x3f9, 10}, {0xffa, 12}, - {0x1ff9, 13}, {0x15, 6}, {0xf8, 8}, {0x7fa, 11}, - {0x3fa, 10}, {0x3fb, 10}, {0xf9, 8}, {0x7fb, 11}, - {0xfa, 8}, {0x16, 6}, {0x17, 6}, {0x18, 6}, - {0x0, 5}, {0x1, 5}, {0x2, 5}, {0x19, 6}, - {0x1a, 6}, {0x1b, 6}, {0x1c, 6}, {0x1d, 6}, - {0x1e, 6}, {0x1f, 6}, {0x5c, 7}, {0xfb, 8}, - {0x7ffc, 15}, {0x20, 6}, {0xffb, 12}, {0x3fc, 10}, - {0x1ffa, 13}, {0x21, 6}, {0x5d, 7}, {0x5e, 7}, - {0x5f, 7}, {0x60, 7}, {0x61, 7}, {0x62, 7}, - {0x63, 7}, {0x64, 7}, {0x65, 7}, {0x66, 7}, - {0x67, 7}, {0x68, 7}, {0x69, 7}, {0x6a, 7}, - {0x6b, 7}, {0x6c, 7}, {0x6d, 7}, {0x6e, 7}, - {0x6f, 7}, {0x70, 7}, {0x71, 7}, {0x72, 7}, - {0xfc, 8}, {0x73, 7}, {0xfd, 8}, {0x1ffb, 13}, - {0x7fff0, 19}, {0x1ffc, 13}, {0x3ffc, 14}, {0x22, 6}, - {0x7ffd, 15}, {0x3, 5}, {0x23, 6}, {0x4, 5}, - {0x24, 6}, {0x5, 5}, {0x25, 6}, {0x26, 6}, - {0x27, 6}, {0x6, 5}, {0x74, 7}, {0x75, 7}, - {0x28, 6}, {0x29, 6}, {0x2a, 6}, {0x7, 5}, - {0x2b, 6}, {0x76, 7}, {0x2c, 6}, {0x8, 5}, - {0x9, 5}, {0x2d, 6}, {0x77, 7}, {0x78, 7}, - {0x79, 7}, {0x7a, 7}, {0x7b, 7}, {0x7ffe, 15}, - {0x7fc, 11}, {0x3ffd, 14}, {0x1ffd, 13}, {0xffffffc, 28}, - {0xfffe6, 20}, {0x3fffd2, 22}, {0xfffe7, 20}, {0xfffe8, 20}, - {0x3fffd3, 22}, {0x3fffd4, 22}, {0x3fffd5, 22}, {0x7fffd9, 23}, - {0x3fffd6, 22}, {0x7fffda, 23}, {0x7fffdb, 23}, {0x7fffdc, 23}, - {0x7fffdd, 23}, {0x7fffde, 23}, {0xffffeb, 24}, {0x7fffdf, 23}, - {0xffffec, 24}, {0xffffed, 24}, {0x3fffd7, 22}, {0x7fffe0, 23}, - {0xffffee, 24}, {0x7fffe1, 23}, {0x7fffe2, 23}, {0x7fffe3, 23}, - {0x7fffe4, 23}, {0x1fffdc, 21}, {0x3fffd8, 22}, {0x7fffe5, 23}, - {0x3fffd9, 22}, {0x7fffe6, 23}, {0x7fffe7, 23}, {0xffffef, 24}, - {0x3fffda, 22}, {0x1fffdd, 21}, {0xfffe9, 20}, {0x3fffdb, 22}, - {0x3fffdc, 22}, {0x7fffe8, 23}, {0x7fffe9, 23}, {0x1fffde, 21}, - {0x7fffea, 23}, {0x3fffdd, 22}, {0x3fffde, 22}, {0xfffff0, 24}, - {0x1fffdf, 21}, {0x3fffdf, 22}, {0x7fffeb, 23}, {0x7fffec, 23}, - {0x1fffe0, 21}, {0x1fffe1, 21}, {0x3fffe0, 22}, {0x1fffe2, 21}, - {0x7fffed, 23}, {0x3fffe1, 22}, {0x7fffee, 23}, {0x7fffef, 23}, - {0xfffea, 20}, {0x3fffe2, 22}, {0x3fffe3, 22}, {0x3fffe4, 22}, - {0x7ffff0, 23}, {0x3fffe5, 22}, {0x3fffe6, 22}, {0x7ffff1, 23}, - {0x3ffffe0, 26}, {0x3ffffe1, 26}, {0xfffeb, 20}, {0x7fff1, 19}, - {0x3fffe7, 22}, {0x7ffff2, 23}, {0x3fffe8, 22}, {0x1ffffec, 25}, - {0x3ffffe2, 26}, {0x3ffffe3, 26}, {0x3ffffe4, 26}, {0x7ffffde, 27}, - {0x7ffffdf, 27}, {0x3ffffe5, 26}, {0xfffff1, 24}, {0x1ffffed, 25}, - {0x7fff2, 19}, {0x1fffe3, 21}, {0x3ffffe6, 26}, {0x7ffffe0, 27}, - {0x7ffffe1, 27}, {0x3ffffe7, 26}, {0x7ffffe2, 27}, {0xfffff2, 24}, - {0x1fffe4, 21}, {0x1fffe5, 21}, {0x3ffffe8, 26}, {0x3ffffe9, 26}, - {0xffffffd, 28}, {0x7ffffe3, 27}, {0x7ffffe4, 27}, {0x7ffffe5, 27}, - {0xfffec, 20}, {0xfffff3, 24}, {0xfffed, 20}, {0x1fffe6, 21}, - {0x3fffe9, 22}, {0x1fffe7, 21}, {0x1fffe8, 21}, {0x7ffff3, 23}, - {0x3fffea, 22}, {0x3fffeb, 22}, {0x1ffffee, 25}, {0x1ffffef, 25}, - {0xfffff4, 24}, {0xfffff5, 24}, {0x3ffffea, 26}, {0x7ffff4, 23}, - {0x3ffffeb, 26}, {0x7ffffe6, 27}, {0x3ffffec, 26}, {0x3ffffed, 26}, - {0x7ffffe7, 27}, {0x7ffffe8, 27}, {0x7ffffe9, 27}, {0x7ffffea, 27}, - {0x7ffffeb, 27}, {0xffffffe, 28}, {0x7ffffec, 27}, {0x7ffffed, 27}, - {0x7ffffee, 27}, {0x7ffffef, 27}, {0x7fffff0, 27}, {0x3ffffee, 26}, - {0x3fffffff, 30}, -}; diff --git a/src/core/transport/chttp2/huffsyms.h b/src/core/transport/chttp2/huffsyms.h deleted file mode 100644 index 9c4f09dcf6..0000000000 --- a/src/core/transport/chttp2/huffsyms.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * - * Copyright 2015-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_TRANSPORT_CHTTP2_HUFFSYMS_H -#define GRPC_CORE_TRANSPORT_CHTTP2_HUFFSYMS_H - -/* HPACK static huffman table */ - -#define GRPC_CHTTP2_NUM_HUFFSYMS 257 - -typedef struct { - unsigned bits; - unsigned length; -} grpc_chttp2_huffsym; - -extern const grpc_chttp2_huffsym grpc_chttp2_huffsyms[GRPC_CHTTP2_NUM_HUFFSYMS]; - -#endif /* GRPC_CORE_TRANSPORT_CHTTP2_HUFFSYMS_H */ diff --git a/src/core/transport/chttp2/incoming_metadata.c b/src/core/transport/chttp2/incoming_metadata.c deleted file mode 100644 index 315bc2faa1..0000000000 --- a/src/core/transport/chttp2/incoming_metadata.c +++ /dev/null @@ -1,96 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/transport/chttp2/incoming_metadata.h" - -#include - -#include "src/core/transport/chttp2/internal.h" - -#include -#include - -void grpc_chttp2_incoming_metadata_buffer_init( - grpc_chttp2_incoming_metadata_buffer *buffer) { - buffer->deadline = gpr_inf_future(GPR_CLOCK_REALTIME); -} - -void grpc_chttp2_incoming_metadata_buffer_destroy( - grpc_chttp2_incoming_metadata_buffer *buffer) { - size_t i; - if (!buffer->published) { - for (i = 0; i < buffer->count; i++) { - GRPC_MDELEM_UNREF(buffer->elems[i].md); - } - } - gpr_free(buffer->elems); -} - -void grpc_chttp2_incoming_metadata_buffer_add( - grpc_chttp2_incoming_metadata_buffer *buffer, grpc_mdelem *elem) { - GPR_ASSERT(!buffer->published); - if (buffer->capacity == buffer->count) { - buffer->capacity = GPR_MAX(8, 2 * buffer->capacity); - buffer->elems = - gpr_realloc(buffer->elems, sizeof(*buffer->elems) * buffer->capacity); - } - buffer->elems[buffer->count++].md = elem; -} - -void grpc_chttp2_incoming_metadata_buffer_set_deadline( - grpc_chttp2_incoming_metadata_buffer *buffer, gpr_timespec deadline) { - GPR_ASSERT(!buffer->published); - buffer->deadline = deadline; -} - -void grpc_chttp2_incoming_metadata_buffer_publish( - grpc_chttp2_incoming_metadata_buffer *buffer, grpc_metadata_batch *batch) { - GPR_ASSERT(!buffer->published); - buffer->published = 1; - if (buffer->count > 0) { - size_t i; - for (i = 1; i < buffer->count; i++) { - buffer->elems[i].prev = &buffer->elems[i - 1]; - } - for (i = 0; i < buffer->count - 1; i++) { - buffer->elems[i].next = &buffer->elems[i + 1]; - } - buffer->elems[0].prev = NULL; - buffer->elems[buffer->count - 1].next = NULL; - batch->list.head = &buffer->elems[0]; - batch->list.tail = &buffer->elems[buffer->count - 1]; - } else { - batch->list.head = batch->list.tail = NULL; - } - batch->deadline = buffer->deadline; -} diff --git a/src/core/transport/chttp2/incoming_metadata.h b/src/core/transport/chttp2/incoming_metadata.h deleted file mode 100644 index 52454f348c..0000000000 --- a/src/core/transport/chttp2/incoming_metadata.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * - * Copyright 2015-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_TRANSPORT_CHTTP2_INCOMING_METADATA_H -#define GRPC_CORE_TRANSPORT_CHTTP2_INCOMING_METADATA_H - -#include "src/core/transport/transport.h" - -typedef struct { - grpc_linked_mdelem *elems; - size_t count; - size_t capacity; - gpr_timespec deadline; - int published; -} grpc_chttp2_incoming_metadata_buffer; - -/** assumes everything initially zeroed */ -void grpc_chttp2_incoming_metadata_buffer_init( - grpc_chttp2_incoming_metadata_buffer *buffer); -void grpc_chttp2_incoming_metadata_buffer_destroy( - grpc_chttp2_incoming_metadata_buffer *buffer); -void grpc_chttp2_incoming_metadata_buffer_publish( - grpc_chttp2_incoming_metadata_buffer *buffer, grpc_metadata_batch *batch); - -void grpc_chttp2_incoming_metadata_buffer_add( - grpc_chttp2_incoming_metadata_buffer *buffer, grpc_mdelem *elem); -void grpc_chttp2_incoming_metadata_buffer_set_deadline( - grpc_chttp2_incoming_metadata_buffer *buffer, gpr_timespec deadline); - -#endif /* GRPC_CORE_TRANSPORT_CHTTP2_INCOMING_METADATA_H */ diff --git a/src/core/transport/chttp2/internal.h b/src/core/transport/chttp2/internal.h deleted file mode 100644 index 0690cb37cd..0000000000 --- a/src/core/transport/chttp2/internal.h +++ /dev/null @@ -1,780 +0,0 @@ -/* - * - * Copyright 2015-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_TRANSPORT_CHTTP2_INTERNAL_H -#define GRPC_CORE_TRANSPORT_CHTTP2_INTERNAL_H - -#include -#include - -#include "src/core/iomgr/endpoint.h" -#include "src/core/transport/chttp2/frame.h" -#include "src/core/transport/chttp2/frame_data.h" -#include "src/core/transport/chttp2/frame_goaway.h" -#include "src/core/transport/chttp2/frame_ping.h" -#include "src/core/transport/chttp2/frame_rst_stream.h" -#include "src/core/transport/chttp2/frame_settings.h" -#include "src/core/transport/chttp2/frame_window_update.h" -#include "src/core/transport/chttp2/hpack_encoder.h" -#include "src/core/transport/chttp2/hpack_parser.h" -#include "src/core/transport/chttp2/incoming_metadata.h" -#include "src/core/transport/chttp2/stream_map.h" -#include "src/core/transport/connectivity_state.h" -#include "src/core/transport/transport_impl.h" - -typedef struct grpc_chttp2_transport grpc_chttp2_transport; -typedef struct grpc_chttp2_stream grpc_chttp2_stream; - -/* streams are kept in various linked lists depending on what things need to - happen to them... this enum labels each list */ -typedef enum { - GRPC_CHTTP2_LIST_ALL_STREAMS, - GRPC_CHTTP2_LIST_CHECK_READ_OPS, - GRPC_CHTTP2_LIST_UNANNOUNCED_INCOMING_WINDOW_AVAILABLE, - GRPC_CHTTP2_LIST_WRITABLE, - GRPC_CHTTP2_LIST_WRITING, - GRPC_CHTTP2_LIST_WRITTEN, - GRPC_CHTTP2_LIST_PARSING_SEEN, - GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_PARSING, - GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_WRITING, - GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT, - /* streams waiting for the outgoing window in the writing path, they will be - * merged to the stalled list or writable list under transport lock. */ - GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT, - /** streams that are waiting to start because there are too many concurrent - streams on the connection */ - GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY, - STREAM_LIST_COUNT /* must be last */ -} grpc_chttp2_stream_list_id; - -/* deframer state for the overall http2 stream of bytes */ -typedef enum { - /* prefix: one entry per http2 connection prefix byte */ - GRPC_DTS_CLIENT_PREFIX_0 = 0, - GRPC_DTS_CLIENT_PREFIX_1, - GRPC_DTS_CLIENT_PREFIX_2, - GRPC_DTS_CLIENT_PREFIX_3, - GRPC_DTS_CLIENT_PREFIX_4, - GRPC_DTS_CLIENT_PREFIX_5, - GRPC_DTS_CLIENT_PREFIX_6, - GRPC_DTS_CLIENT_PREFIX_7, - GRPC_DTS_CLIENT_PREFIX_8, - GRPC_DTS_CLIENT_PREFIX_9, - GRPC_DTS_CLIENT_PREFIX_10, - GRPC_DTS_CLIENT_PREFIX_11, - GRPC_DTS_CLIENT_PREFIX_12, - GRPC_DTS_CLIENT_PREFIX_13, - GRPC_DTS_CLIENT_PREFIX_14, - GRPC_DTS_CLIENT_PREFIX_15, - GRPC_DTS_CLIENT_PREFIX_16, - GRPC_DTS_CLIENT_PREFIX_17, - GRPC_DTS_CLIENT_PREFIX_18, - GRPC_DTS_CLIENT_PREFIX_19, - GRPC_DTS_CLIENT_PREFIX_20, - GRPC_DTS_CLIENT_PREFIX_21, - GRPC_DTS_CLIENT_PREFIX_22, - GRPC_DTS_CLIENT_PREFIX_23, - /* frame header byte 0... */ - /* must follow from the prefix states */ - GRPC_DTS_FH_0, - GRPC_DTS_FH_1, - GRPC_DTS_FH_2, - GRPC_DTS_FH_3, - GRPC_DTS_FH_4, - GRPC_DTS_FH_5, - GRPC_DTS_FH_6, - GRPC_DTS_FH_7, - /* ... frame header byte 8 */ - GRPC_DTS_FH_8, - /* inside a http2 frame */ - GRPC_DTS_FRAME -} grpc_chttp2_deframe_transport_state; - -typedef struct { - grpc_chttp2_stream *head; - grpc_chttp2_stream *tail; -} grpc_chttp2_stream_list; - -typedef struct { - grpc_chttp2_stream *next; - grpc_chttp2_stream *prev; -} grpc_chttp2_stream_link; - -/* We keep several sets of connection wide parameters */ -typedef enum { - /* The settings our peer has asked for (and we have acked) */ - GRPC_PEER_SETTINGS = 0, - /* The settings we'd like to have */ - GRPC_LOCAL_SETTINGS, - /* The settings we've published to our peer */ - GRPC_SENT_SETTINGS, - /* The settings the peer has acked */ - GRPC_ACKED_SETTINGS, - GRPC_NUM_SETTING_SETS -} grpc_chttp2_setting_set; - -/* Outstanding ping request data */ -typedef struct grpc_chttp2_outstanding_ping { - uint8_t id[8]; - grpc_closure *on_recv; - struct grpc_chttp2_outstanding_ping *next; - struct grpc_chttp2_outstanding_ping *prev; -} grpc_chttp2_outstanding_ping; - -/* forward declared in frame_data.h */ -struct grpc_chttp2_incoming_byte_stream { - grpc_byte_stream base; - gpr_refcount refs; - struct grpc_chttp2_incoming_byte_stream *next_message; - int failed; - - grpc_chttp2_transport *transport; - grpc_chttp2_stream *stream; - int is_tail; - gpr_slice_buffer slices; - grpc_closure *on_next; - gpr_slice *next; -}; - -typedef struct { - /** data to write next write */ - gpr_slice_buffer qbuf; - - /** window available for us to send to peer */ - int64_t outgoing_window; - /** window available to announce to peer */ - int64_t announce_incoming_window; - /** how much window would we like to have for incoming_window */ - uint32_t connection_window_target; - - /** have we seen a goaway */ - uint8_t seen_goaway; - /** have we sent a goaway */ - uint8_t sent_goaway; - - /** is this transport a client? */ - uint8_t is_client; - /** are the local settings dirty and need to be sent? */ - uint8_t dirtied_local_settings; - /** have local settings been sent? */ - uint8_t sent_local_settings; - /** bitmask of setting indexes to send out */ - uint32_t force_send_settings; - /** settings values */ - uint32_t settings[GRPC_NUM_SETTING_SETS][GRPC_CHTTP2_NUM_SETTINGS]; - - /** what is the next stream id to be allocated by this peer? - copied to next_stream_id in parsing when parsing commences */ - uint32_t next_stream_id; - - /** how far to lookahead in a stream? */ - uint32_t stream_lookahead; - - /** last received stream id */ - uint32_t last_incoming_stream_id; - - /** pings awaiting responses */ - grpc_chttp2_outstanding_ping pings; - /** next payload for an outgoing ping */ - uint64_t ping_counter; - - /** concurrent stream count: updated when not parsing, - so this is a strict over-estimation on the client */ - uint32_t concurrent_stream_count; -} grpc_chttp2_transport_global; - -typedef struct { - /** data to write now */ - gpr_slice_buffer outbuf; - /** hpack encoding */ - grpc_chttp2_hpack_compressor hpack_compressor; - int64_t outgoing_window; - /** is this a client? */ - uint8_t is_client; - /** callback for when writing is done */ - grpc_closure done_cb; -} grpc_chttp2_transport_writing; - -struct grpc_chttp2_transport_parsing { - /** is this transport a client? (boolean) */ - uint8_t is_client; - - /** were settings updated? */ - uint8_t settings_updated; - /** was a settings ack received? */ - uint8_t settings_ack_received; - /** was a goaway frame received? */ - uint8_t goaway_received; - - /** the last sent max_table_size setting */ - uint32_t last_sent_max_table_size; - - /** initial window change */ - int64_t initial_window_update; - - /** data to write later - after parsing */ - gpr_slice_buffer qbuf; - /** parser for headers */ - grpc_chttp2_hpack_parser hpack_parser; - /** simple one shot parsers */ - union { - grpc_chttp2_window_update_parser window_update; - grpc_chttp2_settings_parser settings; - grpc_chttp2_ping_parser ping; - grpc_chttp2_rst_stream_parser rst_stream; - } simple; - /** parser for goaway frames */ - grpc_chttp2_goaway_parser goaway_parser; - - /** window available for peer to send to us */ - int64_t incoming_window; - - /** next stream id available at the time of beginning parsing */ - uint32_t next_stream_id; - uint32_t last_incoming_stream_id; - - /* deframing */ - grpc_chttp2_deframe_transport_state deframe_state; - uint8_t incoming_frame_type; - uint8_t incoming_frame_flags; - uint8_t header_eof; - uint32_t expect_continuation_stream_id; - uint32_t incoming_frame_size; - uint32_t incoming_stream_id; - - /* active parser */ - void *parser_data; - grpc_chttp2_stream_parsing *incoming_stream; - grpc_chttp2_parse_error (*parser)( - grpc_exec_ctx *exec_ctx, void *parser_user_data, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); - - /* received settings */ - uint32_t settings[GRPC_CHTTP2_NUM_SETTINGS]; - - /* goaway data */ - grpc_status_code goaway_error; - uint32_t goaway_last_stream_index; - gpr_slice goaway_text; - - int64_t outgoing_window; -}; - -struct grpc_chttp2_transport { - grpc_transport base; /* must be first */ - grpc_endpoint *ep; - gpr_refcount refs; - char *peer_string; - - /** when this drops to zero it's safe to shutdown the endpoint */ - gpr_refcount shutdown_ep_refs; - - gpr_mu mu; - - /** is the transport destroying itself? */ - uint8_t destroying; - /** has the upper layer closed the transport? */ - uint8_t closed; - - /** is a thread currently writing */ - uint8_t writing_active; - /** is a thread currently parsing */ - uint8_t parsing_active; - - /** is there a read request to the endpoint outstanding? */ - uint8_t endpoint_reading; - - /** various lists of streams */ - grpc_chttp2_stream_list lists[STREAM_LIST_COUNT]; - - /** global state for reading/writing */ - grpc_chttp2_transport_global global; - /** state only accessible by the chain of execution that - set writing_active=1 */ - grpc_chttp2_transport_writing writing; - /** state only accessible by the chain of execution that - set parsing_active=1 */ - grpc_chttp2_transport_parsing parsing; - - /** maps stream id to grpc_chttp2_stream objects; - owned by the parsing thread when parsing */ - grpc_chttp2_stream_map parsing_stream_map; - - /** streams created by the client (possibly during parsing); - merged with parsing_stream_map during unlock when no - parsing is occurring */ - grpc_chttp2_stream_map new_stream_map; - - /** closure to execute writing */ - grpc_closure writing_action; - /** closure to finish reading from the endpoint */ - grpc_closure recv_data; - - /** incoming read bytes */ - gpr_slice_buffer read_buffer; - - /** address to place a newly accepted stream - set and unset by - grpc_chttp2_parsing_accept_stream; used by init_stream to - publish the accepted server stream */ - grpc_chttp2_stream **accepting_stream; - - struct { - /* accept stream callback */ - void (*accept_stream)(grpc_exec_ctx *exec_ctx, void *user_data, - grpc_transport *transport, const void *server_data); - void *accept_stream_user_data; - - /** connectivity tracking */ - grpc_connectivity_state_tracker state_tracker; - } channel_callback; - - /** Transport op to be applied post-parsing */ - grpc_transport_op *post_parsing_op; -}; - -typedef struct { - /** HTTP2 stream id for this stream, or zero if one has not been assigned */ - uint32_t id; - - /** window available for us to send to peer */ - int64_t outgoing_window; - /** The number of bytes the upper layers have offered to receive. - As the upper layer offers more bytes, this value increases. - As bytes are read, this value decreases. */ - uint32_t max_recv_bytes; - /** The number of bytes the upper layer has offered to read but we have - not yet announced to HTTP2 flow control. - As the upper layers offer to read more bytes, this value increases. - As we advertise incoming flow control window, this value decreases. */ - uint32_t unannounced_incoming_window_for_parse; - uint32_t unannounced_incoming_window_for_writing; - /** things the upper layers would like to send */ - grpc_metadata_batch *send_initial_metadata; - grpc_closure *send_initial_metadata_finished; - grpc_byte_stream *send_message; - grpc_closure *send_message_finished; - grpc_metadata_batch *send_trailing_metadata; - grpc_closure *send_trailing_metadata_finished; - - grpc_metadata_batch *recv_initial_metadata; - grpc_closure *recv_initial_metadata_ready; - grpc_byte_stream **recv_message; - grpc_closure *recv_message_ready; - grpc_metadata_batch *recv_trailing_metadata; - grpc_closure *recv_trailing_metadata_finished; - - /** when the application requests writes be closed, the write_closed is - 'queued'; when the close is flow controlled into the send path, we are - 'sending' it; when the write has been performed it is 'sent' */ - uint8_t write_closed; - /** is this stream reading half-closed (boolean) */ - uint8_t read_closed; - /** is this stream in the stream map? (boolean) */ - uint8_t in_stream_map; - /** has this stream seen an error? if 1, then pending incoming frames - can be thrown away */ - uint8_t seen_error; - - uint8_t published_initial_metadata; - uint8_t published_trailing_metadata; - uint8_t faked_trailing_metadata; - - grpc_chttp2_incoming_metadata_buffer received_initial_metadata; - grpc_chttp2_incoming_metadata_buffer received_trailing_metadata; - - grpc_chttp2_incoming_frame_queue incoming_frames; -} grpc_chttp2_stream_global; - -typedef struct { - /** HTTP2 stream id for this stream, or zero if one has not been assigned */ - uint32_t id; - uint8_t fetching; - bool sent_initial_metadata; - uint8_t sent_message; - uint8_t sent_trailing_metadata; - uint8_t read_closed; - /** send this initial metadata */ - grpc_metadata_batch *send_initial_metadata; - grpc_byte_stream *send_message; - grpc_metadata_batch *send_trailing_metadata; - int64_t outgoing_window; - /** how much window should we announce? */ - uint32_t announce_window; - gpr_slice_buffer flow_controlled_buffer; - gpr_slice fetching_slice; - size_t stream_fetched; - grpc_closure finished_fetch; -} grpc_chttp2_stream_writing; - -struct grpc_chttp2_stream_parsing { - /** HTTP2 stream id for this stream, or zero if one has not been assigned */ - uint32_t id; - /** has this stream received a close */ - uint8_t received_close; - /** saw a rst_stream */ - uint8_t saw_rst_stream; - /** how many header frames have we received? */ - uint8_t header_frames_received; - /** which metadata did we get (on this parse) */ - uint8_t got_metadata_on_parse[2]; - /** should we raise the seen_error flag in transport_global */ - uint8_t seen_error; - /** window available for peer to send to us */ - int64_t incoming_window; - /** parsing state for data frames */ - grpc_chttp2_data_parser data_parser; - /** reason give to rst_stream */ - uint32_t rst_stream_reason; - /** amount of window given */ - int64_t outgoing_window; - /** number of bytes received - reset at end of parse thread execution */ - int64_t received_bytes; - - /** incoming metadata */ - grpc_chttp2_incoming_metadata_buffer metadata_buffer[2]; -}; - -struct grpc_chttp2_stream { - grpc_stream_refcount *refcount; - grpc_chttp2_stream_global global; - grpc_chttp2_stream_writing writing; - grpc_chttp2_stream_parsing parsing; - - grpc_chttp2_stream_link links[STREAM_LIST_COUNT]; - uint8_t included[STREAM_LIST_COUNT]; -}; - -/** Transport writing call flow: - chttp2_transport.c calls grpc_chttp2_unlocking_check_writes to see if writes - are required; - if they are, chttp2_transport.c calls grpc_chttp2_perform_writes to do the - writes. - Once writes have been completed (meaning another write could potentially be - started), - grpc_chttp2_terminate_writing is called. This will call - grpc_chttp2_cleanup_writing, at which - point the write phase is complete. */ - -/** Someone is unlocking the transport mutex: check to see if writes - are required, and schedule them if so */ -int grpc_chttp2_unlocking_check_writes(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_global *global, - grpc_chttp2_transport_writing *writing, - int is_parsing); -void grpc_chttp2_perform_writes( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing, - grpc_endpoint *endpoint); -void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx, - void *transport_writing, bool success); -void grpc_chttp2_cleanup_writing(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_global *global, - grpc_chttp2_transport_writing *writing); - -void grpc_chttp2_prepare_to_read(grpc_chttp2_transport_global *global, - grpc_chttp2_transport_parsing *parsing); -/** Process one slice of incoming data; return 1 if the connection is still - viable after reading, or 0 if the connection should be torn down */ -int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_parsing *transport_parsing, - gpr_slice slice); -void grpc_chttp2_publish_reads(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_global *global, - grpc_chttp2_transport_parsing *parsing); - -bool grpc_chttp2_list_add_writable_stream( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global); -/** Get a writable stream - returns non-zero if there was a stream available */ -int grpc_chttp2_list_pop_writable_stream( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_transport_writing *transport_writing, - grpc_chttp2_stream_global **stream_global, - grpc_chttp2_stream_writing **stream_writing); -bool grpc_chttp2_list_remove_writable_stream( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global) GRPC_MUST_USE_RESULT; - -void grpc_chttp2_list_add_writing_stream( - grpc_chttp2_transport_writing *transport_writing, - grpc_chttp2_stream_writing *stream_writing); -int grpc_chttp2_list_have_writing_streams( - grpc_chttp2_transport_writing *transport_writing); -int grpc_chttp2_list_pop_writing_stream( - grpc_chttp2_transport_writing *transport_writing, - grpc_chttp2_stream_writing **stream_writing); - -void grpc_chttp2_list_add_written_stream( - grpc_chttp2_transport_writing *transport_writing, - grpc_chttp2_stream_writing *stream_writing); -int grpc_chttp2_list_pop_written_stream( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_transport_writing *transport_writing, - grpc_chttp2_stream_global **stream_global, - grpc_chttp2_stream_writing **stream_writing); - -void grpc_chttp2_list_add_parsing_seen_stream( - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing); -int grpc_chttp2_list_pop_parsing_seen_stream( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_global **stream_global, - grpc_chttp2_stream_parsing **stream_parsing); - -void grpc_chttp2_list_add_waiting_for_concurrency( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global); -int grpc_chttp2_list_pop_waiting_for_concurrency( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global **stream_global); - -void grpc_chttp2_list_add_check_read_ops( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global); -int grpc_chttp2_list_pop_check_read_ops( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global **stream_global); - -void grpc_chttp2_list_add_writing_stalled_by_transport( - grpc_chttp2_transport_writing *transport_writing, - grpc_chttp2_stream_writing *stream_writing); -void grpc_chttp2_list_flush_writing_stalled_by_transport( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing, - bool is_window_available); - -void grpc_chttp2_list_add_stalled_by_transport( - grpc_chttp2_transport_writing *transport_writing, - grpc_chttp2_stream_writing *stream_writing); -int grpc_chttp2_list_pop_stalled_by_transport( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global **stream_global); -void grpc_chttp2_list_remove_stalled_by_transport( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global); - -void grpc_chttp2_list_add_unannounced_incoming_window_available( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global); -void grpc_chttp2_list_remove_unannounced_incoming_window_available( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global); -int grpc_chttp2_list_pop_unannounced_incoming_window_available( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_global **stream_global, - grpc_chttp2_stream_parsing **stream_parsing); - -void grpc_chttp2_list_add_closed_waiting_for_parsing( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global); -int grpc_chttp2_list_pop_closed_waiting_for_parsing( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global **stream_global); - -void grpc_chttp2_list_add_closed_waiting_for_writing( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global); -int grpc_chttp2_list_pop_closed_waiting_for_writing( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global **stream_global); - -grpc_chttp2_stream_parsing *grpc_chttp2_parsing_lookup_stream( - grpc_chttp2_transport_parsing *transport_parsing, uint32_t id); -grpc_chttp2_stream_parsing *grpc_chttp2_parsing_accept_stream( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, - uint32_t id); - -void grpc_chttp2_add_incoming_goaway( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, - uint32_t goaway_error, gpr_slice goaway_text); - -void grpc_chttp2_register_stream(grpc_chttp2_transport *t, - grpc_chttp2_stream *s); -/* returns 1 if this is the last stream, 0 otherwise */ -int grpc_chttp2_unregister_stream(grpc_chttp2_transport *t, - grpc_chttp2_stream *s) GRPC_MUST_USE_RESULT; -int grpc_chttp2_has_streams(grpc_chttp2_transport *t); -void grpc_chttp2_for_all_streams( - grpc_chttp2_transport_global *transport_global, void *user_data, - void (*cb)(grpc_chttp2_transport_global *transport_global, void *user_data, - grpc_chttp2_stream_global *stream_global)); - -void grpc_chttp2_parsing_become_skip_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing); - -void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx, - grpc_closure **pclosure, int success); - -#define GRPC_CHTTP2_CLIENT_CONNECT_STRING "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" -#define GRPC_CHTTP2_CLIENT_CONNECT_STRLEN \ - (sizeof(GRPC_CHTTP2_CLIENT_CONNECT_STRING) - 1) - -extern int grpc_http_trace; -extern int grpc_flowctl_trace; - -#define GRPC_CHTTP2_IF_TRACING(stmt) \ - if (!(grpc_http_trace)) \ - ; \ - else \ - stmt - -typedef enum { - GRPC_CHTTP2_FLOWCTL_MOVE, - GRPC_CHTTP2_FLOWCTL_CREDIT, - GRPC_CHTTP2_FLOWCTL_DEBIT -} grpc_chttp2_flowctl_op; - -#define GRPC_CHTTP2_FLOW_MOVE_COMMON(phase, transport, id1, id2, dst_context, \ - dst_var, src_context, src_var) \ - do { \ - assert(id1 == id2); \ - if (grpc_flowctl_trace) { \ - grpc_chttp2_flowctl_trace( \ - __FILE__, __LINE__, phase, GRPC_CHTTP2_FLOWCTL_MOVE, #dst_context, \ - #dst_var, #src_context, #src_var, transport->is_client, id1, \ - dst_context->dst_var, src_context->src_var); \ - } \ - dst_context->dst_var += src_context->src_var; \ - src_context->src_var = 0; \ - } while (0) - -#define GRPC_CHTTP2_FLOW_MOVE_STREAM(phase, transport, dst_context, dst_var, \ - src_context, src_var) \ - GRPC_CHTTP2_FLOW_MOVE_COMMON(phase, transport, dst_context->id, \ - src_context->id, dst_context, dst_var, \ - src_context, src_var) -#define GRPC_CHTTP2_FLOW_MOVE_TRANSPORT(phase, dst_context, dst_var, \ - src_context, src_var) \ - GRPC_CHTTP2_FLOW_MOVE_COMMON(phase, dst_context, 0, 0, dst_context, dst_var, \ - src_context, src_var) - -#define GRPC_CHTTP2_FLOW_CREDIT_COMMON(phase, transport, id, dst_context, \ - dst_var, amount) \ - do { \ - if (grpc_flowctl_trace) { \ - grpc_chttp2_flowctl_trace(__FILE__, __LINE__, phase, \ - GRPC_CHTTP2_FLOWCTL_CREDIT, #dst_context, \ - #dst_var, NULL, #amount, transport->is_client, \ - id, dst_context->dst_var, amount); \ - } \ - dst_context->dst_var += amount; \ - } while (0) - -#define GRPC_CHTTP2_FLOW_CREDIT_STREAM(phase, transport, dst_context, dst_var, \ - amount) \ - GRPC_CHTTP2_FLOW_CREDIT_COMMON(phase, transport, dst_context->id, \ - dst_context, dst_var, amount) -#define GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT(phase, dst_context, dst_var, amount) \ - GRPC_CHTTP2_FLOW_CREDIT_COMMON(phase, dst_context, 0, dst_context, dst_var, \ - amount) - -#define GRPC_CHTTP2_FLOW_DEBIT_COMMON(phase, transport, id, dst_context, \ - dst_var, amount) \ - do { \ - if (grpc_flowctl_trace) { \ - grpc_chttp2_flowctl_trace(__FILE__, __LINE__, phase, \ - GRPC_CHTTP2_FLOWCTL_DEBIT, #dst_context, \ - #dst_var, NULL, #amount, transport->is_client, \ - id, dst_context->dst_var, amount); \ - } \ - dst_context->dst_var -= amount; \ - } while (0) - -#define GRPC_CHTTP2_FLOW_DEBIT_STREAM(phase, transport, dst_context, dst_var, \ - amount) \ - GRPC_CHTTP2_FLOW_DEBIT_COMMON(phase, transport, dst_context->id, \ - dst_context, dst_var, amount) -#define GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT(phase, dst_context, dst_var, amount) \ - GRPC_CHTTP2_FLOW_DEBIT_COMMON(phase, dst_context, 0, dst_context, dst_var, \ - amount) - -void grpc_chttp2_flowctl_trace(const char *file, int line, const char *phase, - grpc_chttp2_flowctl_op op, const char *context1, - const char *var1, const char *context2, - const char *var2, int is_client, - uint32_t stream_id, int64_t val1, int64_t val2); - -void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream, - grpc_status_code status, gpr_slice *details); -void grpc_chttp2_mark_stream_closed( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global, int close_reads, - int close_writes); -void grpc_chttp2_start_writing(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_global *transport_global); - -#ifdef GRPC_STREAM_REFCOUNT_DEBUG -#define GRPC_CHTTP2_STREAM_REF(stream_global, reason) \ - grpc_chttp2_stream_ref(stream_global, reason) -#define GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, reason) \ - grpc_chttp2_stream_unref(exec_ctx, stream_global, reason) -void grpc_chttp2_stream_ref(grpc_chttp2_stream_global *stream_global, - const char *reason); -void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx, - grpc_chttp2_stream_global *stream_global, - const char *reason); -#else -#define GRPC_CHTTP2_STREAM_REF(stream_global, reason) \ - grpc_chttp2_stream_ref(stream_global) -#define GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, reason) \ - grpc_chttp2_stream_unref(exec_ctx, stream_global) -void grpc_chttp2_stream_ref(grpc_chttp2_stream_global *stream_global); -void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx, - grpc_chttp2_stream_global *stream_global); -#endif - -grpc_chttp2_incoming_byte_stream *grpc_chttp2_incoming_byte_stream_create( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing, uint32_t frame_size, - uint32_t flags, grpc_chttp2_incoming_frame_queue *add_to_queue); -void grpc_chttp2_incoming_byte_stream_push(grpc_exec_ctx *exec_ctx, - grpc_chttp2_incoming_byte_stream *bs, - gpr_slice slice); -void grpc_chttp2_incoming_byte_stream_finished( - grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs, int success, - int from_parsing_thread); - -void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_parsing *parsing, - const uint8_t *opaque_8bytes); - -/** add a ref to the stream and add it to the writable list; - ref will be dropped in writing.c */ -void grpc_chttp2_become_writable(grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global); - -#endif /* GRPC_CORE_TRANSPORT_CHTTP2_INTERNAL_H */ diff --git a/src/core/transport/chttp2/parsing.c b/src/core/transport/chttp2/parsing.c deleted file mode 100644 index 0516f39fa9..0000000000 --- a/src/core/transport/chttp2/parsing.c +++ /dev/null @@ -1,866 +0,0 @@ -/* - * - * Copyright 2015-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/transport/chttp2/internal.h" - -#include - -#include -#include -#include - -#include "src/core/profiling/timers.h" -#include "src/core/transport/chttp2/http2_errors.h" -#include "src/core/transport/chttp2/status_conversion.h" -#include "src/core/transport/chttp2/timeout_encoding.h" -#include "src/core/transport/static_metadata.h" - -static int init_frame_parser(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_parsing *transport_parsing); -static int init_header_frame_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, - int is_continuation); -static int init_data_frame_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing); -static int init_rst_stream_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing); -static int init_settings_frame_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing); -static int init_window_update_frame_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing); -static int init_ping_parser(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_parsing *transport_parsing); -static int init_goaway_parser(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_parsing *transport_parsing); -static int init_skip_frame_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, - int is_header); - -static int parse_frame_slice(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_parsing *transport_parsing, - gpr_slice slice, int is_last); - -void grpc_chttp2_prepare_to_read( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_transport_parsing *transport_parsing) { - grpc_chttp2_stream_global *stream_global; - grpc_chttp2_stream_parsing *stream_parsing; - - GPR_TIMER_BEGIN("grpc_chttp2_prepare_to_read", 0); - - transport_parsing->next_stream_id = transport_global->next_stream_id; - transport_parsing->last_sent_max_table_size = - transport_global->settings[GRPC_SENT_SETTINGS] - [GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE]; - - /* update the parsing view of incoming window */ - while (grpc_chttp2_list_pop_unannounced_incoming_window_available( - transport_global, transport_parsing, &stream_global, &stream_parsing)) { - GRPC_CHTTP2_FLOW_MOVE_STREAM("parse", transport_parsing, stream_parsing, - incoming_window, stream_global, - unannounced_incoming_window_for_parse); - } - - GPR_TIMER_END("grpc_chttp2_prepare_to_read", 0); -} - -void grpc_chttp2_publish_reads( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, - grpc_chttp2_transport_parsing *transport_parsing) { - grpc_chttp2_stream_global *stream_global; - grpc_chttp2_stream_parsing *stream_parsing; - int was_zero; - int is_zero; - - /* transport_parsing->last_incoming_stream_id is used as - last-grpc_chttp2_stream-id when - sending GOAWAY frame. - https://tools.ietf.org/html/draft-ietf-httpbis-http2-17#section-6.8 - says that last-grpc_chttp2_stream-id is peer-initiated grpc_chttp2_stream - ID. So, - since we don't have server pushed streams, client should send - GOAWAY last-grpc_chttp2_stream-id=0 in this case. */ - if (!transport_parsing->is_client) { - transport_global->last_incoming_stream_id = - transport_parsing->incoming_stream_id; - } - - /* update global settings */ - if (transport_parsing->settings_updated) { - memcpy(transport_global->settings[GRPC_PEER_SETTINGS], - transport_parsing->settings, sizeof(transport_parsing->settings)); - transport_parsing->settings_updated = 0; - } - - /* update settings based on ack if received */ - if (transport_parsing->settings_ack_received) { - memcpy(transport_global->settings[GRPC_ACKED_SETTINGS], - transport_global->settings[GRPC_SENT_SETTINGS], - GRPC_CHTTP2_NUM_SETTINGS * sizeof(uint32_t)); - transport_parsing->settings_ack_received = 0; - transport_global->sent_local_settings = 0; - } - - /* move goaway to the global state if we received one (it will be - published later */ - if (transport_parsing->goaway_received) { - grpc_chttp2_add_incoming_goaway(exec_ctx, transport_global, - (uint32_t)transport_parsing->goaway_error, - transport_parsing->goaway_text); - transport_parsing->goaway_text = gpr_empty_slice(); - transport_parsing->goaway_received = 0; - } - - /* propagate flow control tokens to global state */ - was_zero = transport_global->outgoing_window <= 0; - GRPC_CHTTP2_FLOW_MOVE_TRANSPORT("parsed", transport_global, outgoing_window, - transport_parsing, outgoing_window); - is_zero = transport_global->outgoing_window <= 0; - if (was_zero && !is_zero) { - while (grpc_chttp2_list_pop_stalled_by_transport(transport_global, - &stream_global)) { - grpc_chttp2_become_writable(transport_global, stream_global); - } - } - - if (transport_parsing->incoming_window < - transport_global->connection_window_target * 3 / 4) { - int64_t announce_bytes = transport_global->connection_window_target - - transport_parsing->incoming_window; - GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parsed", transport_global, - announce_incoming_window, announce_bytes); - GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parsed", transport_parsing, - incoming_window, announce_bytes); - } - - /* for each stream that saw an update, fixup global state */ - while (grpc_chttp2_list_pop_parsing_seen_stream( - transport_global, transport_parsing, &stream_global, &stream_parsing)) { - if (stream_parsing->seen_error) { - stream_global->seen_error = 1; - grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); - } - - /* update outgoing flow control window */ - was_zero = stream_global->outgoing_window <= 0; - GRPC_CHTTP2_FLOW_MOVE_STREAM("parsed", transport_global, stream_global, - outgoing_window, stream_parsing, - outgoing_window); - is_zero = stream_global->outgoing_window <= 0; - if (was_zero && !is_zero) { - grpc_chttp2_become_writable(transport_global, stream_global); - } - - stream_global->max_recv_bytes -= (uint32_t)GPR_MIN( - stream_global->max_recv_bytes, stream_parsing->received_bytes); - stream_parsing->received_bytes = 0; - - /* publish incoming stream ops */ - if (stream_global->incoming_frames.tail != NULL) { - stream_global->incoming_frames.tail->is_tail = 0; - } - if (stream_parsing->data_parser.incoming_frames.head != NULL) { - grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); - } - grpc_chttp2_incoming_frame_queue_merge( - &stream_global->incoming_frames, - &stream_parsing->data_parser.incoming_frames); - if (stream_global->incoming_frames.tail != NULL) { - stream_global->incoming_frames.tail->is_tail = 1; - } - - if (!stream_global->published_initial_metadata && - stream_parsing->got_metadata_on_parse[0]) { - stream_parsing->got_metadata_on_parse[0] = 0; - stream_global->published_initial_metadata = 1; - GPR_SWAP(grpc_chttp2_incoming_metadata_buffer, - stream_parsing->metadata_buffer[0], - stream_global->received_initial_metadata); - grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); - } - if (!stream_global->published_trailing_metadata && - stream_parsing->got_metadata_on_parse[1]) { - stream_parsing->got_metadata_on_parse[1] = 0; - stream_global->published_trailing_metadata = 1; - GPR_SWAP(grpc_chttp2_incoming_metadata_buffer, - stream_parsing->metadata_buffer[1], - stream_global->received_trailing_metadata); - grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); - } - - if (stream_parsing->saw_rst_stream) { - if (stream_parsing->rst_stream_reason != GRPC_CHTTP2_NO_ERROR) { - grpc_status_code status_code = grpc_chttp2_http2_error_to_grpc_status( - (grpc_chttp2_error_code)stream_parsing->rst_stream_reason); - char *status_details; - gpr_slice slice_details; - gpr_asprintf(&status_details, "Received RST_STREAM err=%d", - stream_parsing->rst_stream_reason); - slice_details = gpr_slice_from_copied_string(status_details); - gpr_free(status_details); - grpc_chttp2_fake_status(exec_ctx, transport_global, stream_global, - status_code, &slice_details); - } - grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, - 1, 1); - } - - if (stream_parsing->received_close) { - grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, - 1, 0); - } - } -} - -int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_parsing *transport_parsing, - gpr_slice slice) { - uint8_t *beg = GPR_SLICE_START_PTR(slice); - uint8_t *end = GPR_SLICE_END_PTR(slice); - uint8_t *cur = beg; - - if (cur == end) return 1; - - switch (transport_parsing->deframe_state) { - case GRPC_DTS_CLIENT_PREFIX_0: - case GRPC_DTS_CLIENT_PREFIX_1: - case GRPC_DTS_CLIENT_PREFIX_2: - case GRPC_DTS_CLIENT_PREFIX_3: - case GRPC_DTS_CLIENT_PREFIX_4: - case GRPC_DTS_CLIENT_PREFIX_5: - case GRPC_DTS_CLIENT_PREFIX_6: - case GRPC_DTS_CLIENT_PREFIX_7: - case GRPC_DTS_CLIENT_PREFIX_8: - case GRPC_DTS_CLIENT_PREFIX_9: - case GRPC_DTS_CLIENT_PREFIX_10: - case GRPC_DTS_CLIENT_PREFIX_11: - case GRPC_DTS_CLIENT_PREFIX_12: - case GRPC_DTS_CLIENT_PREFIX_13: - case GRPC_DTS_CLIENT_PREFIX_14: - case GRPC_DTS_CLIENT_PREFIX_15: - case GRPC_DTS_CLIENT_PREFIX_16: - case GRPC_DTS_CLIENT_PREFIX_17: - case GRPC_DTS_CLIENT_PREFIX_18: - case GRPC_DTS_CLIENT_PREFIX_19: - case GRPC_DTS_CLIENT_PREFIX_20: - case GRPC_DTS_CLIENT_PREFIX_21: - case GRPC_DTS_CLIENT_PREFIX_22: - case GRPC_DTS_CLIENT_PREFIX_23: - while (cur != end && transport_parsing->deframe_state != GRPC_DTS_FH_0) { - if (*cur != GRPC_CHTTP2_CLIENT_CONNECT_STRING[transport_parsing - ->deframe_state]) { - gpr_log(GPR_INFO, - "Connect string mismatch: expected '%c' (%d) got '%c' (%d) " - "at byte %d", - GRPC_CHTTP2_CLIENT_CONNECT_STRING[transport_parsing - ->deframe_state], - (int)(uint8_t)GRPC_CHTTP2_CLIENT_CONNECT_STRING - [transport_parsing->deframe_state], - *cur, (int)*cur, transport_parsing->deframe_state); - return 0; - } - ++cur; - ++transport_parsing->deframe_state; - } - if (cur == end) { - return 1; - } - /* fallthrough */ - dts_fh_0: - case GRPC_DTS_FH_0: - GPR_ASSERT(cur < end); - transport_parsing->incoming_frame_size = ((uint32_t)*cur) << 16; - if (++cur == end) { - transport_parsing->deframe_state = GRPC_DTS_FH_1; - return 1; - } - /* fallthrough */ - case GRPC_DTS_FH_1: - GPR_ASSERT(cur < end); - transport_parsing->incoming_frame_size |= ((uint32_t)*cur) << 8; - if (++cur == end) { - transport_parsing->deframe_state = GRPC_DTS_FH_2; - return 1; - } - /* fallthrough */ - case GRPC_DTS_FH_2: - GPR_ASSERT(cur < end); - transport_parsing->incoming_frame_size |= *cur; - if (++cur == end) { - transport_parsing->deframe_state = GRPC_DTS_FH_3; - return 1; - } - /* fallthrough */ - case GRPC_DTS_FH_3: - GPR_ASSERT(cur < end); - transport_parsing->incoming_frame_type = *cur; - if (++cur == end) { - transport_parsing->deframe_state = GRPC_DTS_FH_4; - return 1; - } - /* fallthrough */ - case GRPC_DTS_FH_4: - GPR_ASSERT(cur < end); - transport_parsing->incoming_frame_flags = *cur; - if (++cur == end) { - transport_parsing->deframe_state = GRPC_DTS_FH_5; - return 1; - } - /* fallthrough */ - case GRPC_DTS_FH_5: - GPR_ASSERT(cur < end); - transport_parsing->incoming_stream_id = (((uint32_t)*cur) & 0x7f) << 24; - if (++cur == end) { - transport_parsing->deframe_state = GRPC_DTS_FH_6; - return 1; - } - /* fallthrough */ - case GRPC_DTS_FH_6: - GPR_ASSERT(cur < end); - transport_parsing->incoming_stream_id |= ((uint32_t)*cur) << 16; - if (++cur == end) { - transport_parsing->deframe_state = GRPC_DTS_FH_7; - return 1; - } - /* fallthrough */ - case GRPC_DTS_FH_7: - GPR_ASSERT(cur < end); - transport_parsing->incoming_stream_id |= ((uint32_t)*cur) << 8; - if (++cur == end) { - transport_parsing->deframe_state = GRPC_DTS_FH_8; - return 1; - } - /* fallthrough */ - case GRPC_DTS_FH_8: - GPR_ASSERT(cur < end); - transport_parsing->incoming_stream_id |= ((uint32_t)*cur); - transport_parsing->deframe_state = GRPC_DTS_FRAME; - if (!init_frame_parser(exec_ctx, transport_parsing)) { - return 0; - } - if (transport_parsing->incoming_stream_id) { - transport_parsing->last_incoming_stream_id = - transport_parsing->incoming_stream_id; - } - if (transport_parsing->incoming_frame_size == 0) { - if (!parse_frame_slice(exec_ctx, transport_parsing, gpr_empty_slice(), - 1)) { - return 0; - } - transport_parsing->incoming_stream = NULL; - if (++cur == end) { - transport_parsing->deframe_state = GRPC_DTS_FH_0; - return 1; - } - goto dts_fh_0; /* loop */ - } - if (++cur == end) { - return 1; - } - /* fallthrough */ - case GRPC_DTS_FRAME: - GPR_ASSERT(cur < end); - if ((uint32_t)(end - cur) == transport_parsing->incoming_frame_size) { - if (!parse_frame_slice(exec_ctx, transport_parsing, - gpr_slice_sub_no_ref(slice, (size_t)(cur - beg), - (size_t)(end - beg)), - 1)) { - return 0; - } - transport_parsing->deframe_state = GRPC_DTS_FH_0; - transport_parsing->incoming_stream = NULL; - return 1; - } else if ((uint32_t)(end - cur) > - transport_parsing->incoming_frame_size) { - size_t cur_offset = (size_t)(cur - beg); - if (!parse_frame_slice( - exec_ctx, transport_parsing, - gpr_slice_sub_no_ref( - slice, cur_offset, - cur_offset + transport_parsing->incoming_frame_size), - 1)) { - return 0; - } - cur += transport_parsing->incoming_frame_size; - transport_parsing->incoming_stream = NULL; - goto dts_fh_0; /* loop */ - } else { - if (!parse_frame_slice(exec_ctx, transport_parsing, - gpr_slice_sub_no_ref(slice, (size_t)(cur - beg), - (size_t)(end - beg)), - 0)) { - return 0; - } - transport_parsing->incoming_frame_size -= (uint32_t)(end - cur); - return 1; - } - GPR_UNREACHABLE_CODE(return 0); - } - - GPR_UNREACHABLE_CODE(return 0); -} - -static int init_frame_parser(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_parsing *transport_parsing) { - if (transport_parsing->expect_continuation_stream_id != 0) { - if (transport_parsing->incoming_frame_type != - GRPC_CHTTP2_FRAME_CONTINUATION) { - gpr_log(GPR_ERROR, "Expected CONTINUATION frame, got frame type %02x", - transport_parsing->incoming_frame_type); - return 0; - } - if (transport_parsing->expect_continuation_stream_id != - transport_parsing->incoming_stream_id) { - gpr_log(GPR_ERROR, - "Expected CONTINUATION frame for grpc_chttp2_stream %08x, got " - "grpc_chttp2_stream %08x", - transport_parsing->expect_continuation_stream_id, - transport_parsing->incoming_stream_id); - return 0; - } - return init_header_frame_parser(exec_ctx, transport_parsing, 1); - } - switch (transport_parsing->incoming_frame_type) { - case GRPC_CHTTP2_FRAME_DATA: - return init_data_frame_parser(exec_ctx, transport_parsing); - case GRPC_CHTTP2_FRAME_HEADER: - return init_header_frame_parser(exec_ctx, transport_parsing, 0); - case GRPC_CHTTP2_FRAME_CONTINUATION: - gpr_log(GPR_ERROR, "Unexpected CONTINUATION frame"); - return 0; - case GRPC_CHTTP2_FRAME_RST_STREAM: - return init_rst_stream_parser(exec_ctx, transport_parsing); - case GRPC_CHTTP2_FRAME_SETTINGS: - return init_settings_frame_parser(exec_ctx, transport_parsing); - case GRPC_CHTTP2_FRAME_WINDOW_UPDATE: - return init_window_update_frame_parser(exec_ctx, transport_parsing); - case GRPC_CHTTP2_FRAME_PING: - return init_ping_parser(exec_ctx, transport_parsing); - case GRPC_CHTTP2_FRAME_GOAWAY: - return init_goaway_parser(exec_ctx, transport_parsing); - default: - gpr_log(GPR_ERROR, "Unknown frame type %02x", - transport_parsing->incoming_frame_type); - return init_skip_frame_parser(exec_ctx, transport_parsing, 0); - } -} - -static grpc_chttp2_parse_error skip_parser( - grpc_exec_ctx *exec_ctx, void *parser, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { - return GRPC_CHTTP2_PARSE_OK; -} - -static void skip_header(void *tp, grpc_mdelem *md) { GRPC_MDELEM_UNREF(md); } - -static int init_skip_frame_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, - int is_header) { - if (is_header) { - uint8_t is_eoh = transport_parsing->expect_continuation_stream_id != 0; - transport_parsing->parser = grpc_chttp2_header_parser_parse; - transport_parsing->parser_data = &transport_parsing->hpack_parser; - transport_parsing->hpack_parser.on_header = skip_header; - transport_parsing->hpack_parser.on_header_user_data = NULL; - transport_parsing->hpack_parser.is_boundary = is_eoh; - transport_parsing->hpack_parser.is_eof = - (uint8_t)(is_eoh ? transport_parsing->header_eof : 0); - } else { - transport_parsing->parser = skip_parser; - } - return 1; -} - -void grpc_chttp2_parsing_become_skip_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) { - init_skip_frame_parser( - exec_ctx, transport_parsing, - transport_parsing->parser == grpc_chttp2_header_parser_parse); -} - -static grpc_chttp2_parse_error update_incoming_window( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, - 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", - 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", - transport_parsing->incoming_frame_size, - stream_parsing->incoming_window); - return GRPC_CHTTP2_CONNECTION_ERROR; - } - - GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("parse", transport_parsing, incoming_window, - incoming_frame_size); - GRPC_CHTTP2_FLOW_DEBIT_STREAM("parse", transport_parsing, stream_parsing, - incoming_window, incoming_frame_size); - stream_parsing->received_bytes += incoming_frame_size; - - grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing); - - return GRPC_CHTTP2_PARSE_OK; -} - -static int init_data_frame_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) { - grpc_chttp2_stream_parsing *stream_parsing = - grpc_chttp2_parsing_lookup_stream(transport_parsing, - transport_parsing->incoming_stream_id); - grpc_chttp2_parse_error err = GRPC_CHTTP2_PARSE_OK; - if (!stream_parsing || stream_parsing->received_close) - return init_skip_frame_parser(exec_ctx, transport_parsing, 0); - if (err == GRPC_CHTTP2_PARSE_OK) { - err = update_incoming_window(exec_ctx, transport_parsing, stream_parsing); - } - if (err == GRPC_CHTTP2_PARSE_OK) { - err = grpc_chttp2_data_parser_begin_frame( - &stream_parsing->data_parser, transport_parsing->incoming_frame_flags); - } - switch (err) { - case GRPC_CHTTP2_PARSE_OK: - transport_parsing->incoming_stream = stream_parsing; - transport_parsing->parser = grpc_chttp2_data_parser_parse; - transport_parsing->parser_data = &stream_parsing->data_parser; - return 1; - case GRPC_CHTTP2_STREAM_ERROR: - stream_parsing->received_close = 1; - stream_parsing->saw_rst_stream = 1; - stream_parsing->rst_stream_reason = GRPC_CHTTP2_PROTOCOL_ERROR; - gpr_slice_buffer_add( - &transport_parsing->qbuf, - grpc_chttp2_rst_stream_create(transport_parsing->incoming_stream_id, - GRPC_CHTTP2_PROTOCOL_ERROR)); - return init_skip_frame_parser(exec_ctx, transport_parsing, 0); - case GRPC_CHTTP2_CONNECTION_ERROR: - return 0; - } - GPR_UNREACHABLE_CODE(return 0); -} - -static void free_timeout(void *p) { gpr_free(p); } - -static void on_initial_header(void *tp, grpc_mdelem *md) { - grpc_chttp2_transport_parsing *transport_parsing = tp; - grpc_chttp2_stream_parsing *stream_parsing = - transport_parsing->incoming_stream; - - GPR_TIMER_BEGIN("on_initial_header", 0); - - GPR_ASSERT(stream_parsing); - - GRPC_CHTTP2_IF_TRACING(gpr_log( - GPR_INFO, "HTTP:%d:HDR:%s: %s: %s", stream_parsing->id, - transport_parsing->is_client ? "CLI" : "SVR", - grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value))); - - if (md->key == GRPC_MDSTR_GRPC_STATUS && md != GRPC_MDELEM_GRPC_STATUS_0) { - /* TODO(ctiller): check for a status like " 0" */ - stream_parsing->seen_error = 1; - } - - if (md->key == GRPC_MDSTR_GRPC_TIMEOUT) { - gpr_timespec *cached_timeout = grpc_mdelem_get_user_data(md, free_timeout); - if (!cached_timeout) { - /* not already parsed: parse it now, and store the result away */ - cached_timeout = gpr_malloc(sizeof(gpr_timespec)); - if (!grpc_chttp2_decode_timeout(grpc_mdstr_as_c_string(md->value), - cached_timeout)) { - gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'", - grpc_mdstr_as_c_string(md->value)); - *cached_timeout = gpr_inf_future(GPR_TIMESPAN); - } - grpc_mdelem_set_user_data(md, free_timeout, cached_timeout); - } - grpc_chttp2_incoming_metadata_buffer_set_deadline( - &stream_parsing->metadata_buffer[0], - gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), *cached_timeout)); - GRPC_MDELEM_UNREF(md); - } else { - grpc_chttp2_incoming_metadata_buffer_add( - &stream_parsing->metadata_buffer[0], md); - } - - grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing); - - GPR_TIMER_END("on_initial_header", 0); -} - -static void on_trailing_header(void *tp, grpc_mdelem *md) { - grpc_chttp2_transport_parsing *transport_parsing = tp; - grpc_chttp2_stream_parsing *stream_parsing = - transport_parsing->incoming_stream; - - GPR_TIMER_BEGIN("on_trailing_header", 0); - - GPR_ASSERT(stream_parsing); - - GRPC_CHTTP2_IF_TRACING(gpr_log( - GPR_INFO, "HTTP:%d:TRL:%s: %s: %s", stream_parsing->id, - transport_parsing->is_client ? "CLI" : "SVR", - grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value))); - - if (md->key == GRPC_MDSTR_GRPC_STATUS && md != GRPC_MDELEM_GRPC_STATUS_0) { - /* TODO(ctiller): check for a status like " 0" */ - stream_parsing->seen_error = 1; - } - - grpc_chttp2_incoming_metadata_buffer_add(&stream_parsing->metadata_buffer[1], - md); - - grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing); - - GPR_TIMER_END("on_trailing_header", 0); -} - -static int init_header_frame_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, - int is_continuation) { - uint8_t is_eoh = (transport_parsing->incoming_frame_flags & - GRPC_CHTTP2_DATA_FLAG_END_HEADERS) != 0; - int via_accept = 0; - grpc_chttp2_stream_parsing *stream_parsing; - - /* TODO(ctiller): when to increment header_frames_received? */ - - if (is_eoh) { - transport_parsing->expect_continuation_stream_id = 0; - } else { - transport_parsing->expect_continuation_stream_id = - transport_parsing->incoming_stream_id; - } - - if (!is_continuation) { - transport_parsing->header_eof = (transport_parsing->incoming_frame_flags & - GRPC_CHTTP2_DATA_FLAG_END_STREAM) != 0; - } - - /* could be a new grpc_chttp2_stream or an existing grpc_chttp2_stream */ - stream_parsing = grpc_chttp2_parsing_lookup_stream( - transport_parsing, transport_parsing->incoming_stream_id); - if (stream_parsing == NULL) { - if (is_continuation) { - gpr_log(GPR_ERROR, - "grpc_chttp2_stream disbanded before CONTINUATION received"); - return init_skip_frame_parser(exec_ctx, transport_parsing, 1); - } - if (transport_parsing->is_client) { - if ((transport_parsing->incoming_stream_id & 1) && - transport_parsing->incoming_stream_id < - transport_parsing->next_stream_id) { - /* this is an old (probably cancelled) grpc_chttp2_stream */ - } else { - gpr_log(GPR_ERROR, - "ignoring new grpc_chttp2_stream creation on client"); - } - return init_skip_frame_parser(exec_ctx, transport_parsing, 1); - } else if (transport_parsing->last_incoming_stream_id > - transport_parsing->incoming_stream_id) { - gpr_log(GPR_ERROR, - "ignoring out of order new grpc_chttp2_stream request on server; " - "last grpc_chttp2_stream " - "id=%d, new grpc_chttp2_stream id=%d", - transport_parsing->last_incoming_stream_id, - transport_parsing->incoming_stream_id); - return init_skip_frame_parser(exec_ctx, transport_parsing, 1); - } else if ((transport_parsing->incoming_stream_id & 1) == 0) { - gpr_log(GPR_ERROR, - "ignoring grpc_chttp2_stream with non-client generated index %d", - transport_parsing->incoming_stream_id); - return init_skip_frame_parser(exec_ctx, transport_parsing, 1); - } - stream_parsing = transport_parsing->incoming_stream = - grpc_chttp2_parsing_accept_stream( - exec_ctx, transport_parsing, transport_parsing->incoming_stream_id); - if (stream_parsing == NULL) { - gpr_log(GPR_ERROR, "grpc_chttp2_stream not accepted"); - return init_skip_frame_parser(exec_ctx, transport_parsing, 1); - } - via_accept = 1; - } else { - transport_parsing->incoming_stream = stream_parsing; - } - GPR_ASSERT(stream_parsing != NULL && (via_accept == 0 || via_accept == 1)); - if (stream_parsing->received_close) { - gpr_log(GPR_ERROR, "skipping already closed grpc_chttp2_stream header"); - transport_parsing->incoming_stream = NULL; - return init_skip_frame_parser(exec_ctx, transport_parsing, 1); - } - transport_parsing->parser = grpc_chttp2_header_parser_parse; - transport_parsing->parser_data = &transport_parsing->hpack_parser; - switch (stream_parsing->header_frames_received) { - case 0: - transport_parsing->hpack_parser.on_header = on_initial_header; - break; - case 1: - transport_parsing->hpack_parser.on_header = on_trailing_header; - break; - case 2: - gpr_log(GPR_ERROR, "too many header frames received"); - return init_skip_frame_parser(exec_ctx, transport_parsing, 1); - } - transport_parsing->hpack_parser.on_header_user_data = transport_parsing; - transport_parsing->hpack_parser.is_boundary = is_eoh; - transport_parsing->hpack_parser.is_eof = - (uint8_t)(is_eoh ? transport_parsing->header_eof : 0); - if (!is_continuation && (transport_parsing->incoming_frame_flags & - GRPC_CHTTP2_FLAG_HAS_PRIORITY)) { - grpc_chttp2_hpack_parser_set_has_priority(&transport_parsing->hpack_parser); - } - return 1; -} - -static int init_window_update_frame_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) { - int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_window_update_parser_begin_frame( - &transport_parsing->simple.window_update, - transport_parsing->incoming_frame_size, - transport_parsing->incoming_frame_flags); - if (transport_parsing->incoming_stream_id) { - transport_parsing->incoming_stream = grpc_chttp2_parsing_lookup_stream( - transport_parsing, transport_parsing->incoming_stream_id); - } - transport_parsing->parser = grpc_chttp2_window_update_parser_parse; - transport_parsing->parser_data = &transport_parsing->simple.window_update; - return ok; -} - -static int init_ping_parser(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_parsing *transport_parsing) { - int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_ping_parser_begin_frame( - &transport_parsing->simple.ping, - transport_parsing->incoming_frame_size, - transport_parsing->incoming_frame_flags); - transport_parsing->parser = grpc_chttp2_ping_parser_parse; - transport_parsing->parser_data = &transport_parsing->simple.ping; - return ok; -} - -static int init_rst_stream_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) { - int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_rst_stream_parser_begin_frame( - &transport_parsing->simple.rst_stream, - transport_parsing->incoming_frame_size, - transport_parsing->incoming_frame_flags); - transport_parsing->incoming_stream = grpc_chttp2_parsing_lookup_stream( - transport_parsing, transport_parsing->incoming_stream_id); - if (!transport_parsing->incoming_stream) { - return init_skip_frame_parser(exec_ctx, transport_parsing, 0); - } - transport_parsing->parser = grpc_chttp2_rst_stream_parser_parse; - transport_parsing->parser_data = &transport_parsing->simple.rst_stream; - return ok; -} - -static int init_goaway_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) { - int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_goaway_parser_begin_frame( - &transport_parsing->goaway_parser, - transport_parsing->incoming_frame_size, - transport_parsing->incoming_frame_flags); - transport_parsing->parser = grpc_chttp2_goaway_parser_parse; - transport_parsing->parser_data = &transport_parsing->goaway_parser; - return ok; -} - -static int init_settings_frame_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) { - int ok; - - if (transport_parsing->incoming_stream_id != 0) { - gpr_log(GPR_ERROR, "settings frame received for grpc_chttp2_stream %d", - transport_parsing->incoming_stream_id); - return 0; - } - - ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_settings_parser_begin_frame( - &transport_parsing->simple.settings, - transport_parsing->incoming_frame_size, - transport_parsing->incoming_frame_flags, - transport_parsing->settings); - if (!ok) { - return 0; - } - if (transport_parsing->incoming_frame_flags & GRPC_CHTTP2_FLAG_ACK) { - transport_parsing->settings_ack_received = 1; - grpc_chttp2_hptbl_set_max_bytes( - &transport_parsing->hpack_parser.table, - transport_parsing->last_sent_max_table_size); - } - transport_parsing->parser = grpc_chttp2_settings_parser_parse; - transport_parsing->parser_data = &transport_parsing->simple.settings; - return ok; -} - -/* -static int is_window_update_legal(int64_t window_update, int64_t window) { - return window + window_update < MAX_WINDOW; -} -*/ - -static int parse_frame_slice(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_parsing *transport_parsing, - gpr_slice slice, int is_last) { - grpc_chttp2_stream_parsing *stream_parsing = - transport_parsing->incoming_stream; - switch (transport_parsing->parser(exec_ctx, transport_parsing->parser_data, - transport_parsing, stream_parsing, slice, - is_last)) { - case GRPC_CHTTP2_PARSE_OK: - if (stream_parsing) { - grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, - stream_parsing); - } - return 1; - case GRPC_CHTTP2_STREAM_ERROR: - grpc_chttp2_parsing_become_skip_parser(exec_ctx, transport_parsing); - if (stream_parsing) { - stream_parsing->saw_rst_stream = 1; - stream_parsing->rst_stream_reason = GRPC_CHTTP2_PROTOCOL_ERROR; - gpr_slice_buffer_add( - &transport_parsing->qbuf, - grpc_chttp2_rst_stream_create(transport_parsing->incoming_stream_id, - GRPC_CHTTP2_PROTOCOL_ERROR)); - } - return 1; - case GRPC_CHTTP2_CONNECTION_ERROR: - return 0; - } - GPR_UNREACHABLE_CODE(return 0); -} diff --git a/src/core/transport/chttp2/status_conversion.c b/src/core/transport/chttp2/status_conversion.c deleted file mode 100644 index bf214b017a..0000000000 --- a/src/core/transport/chttp2/status_conversion.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/transport/chttp2/status_conversion.h" - -int grpc_chttp2_grpc_status_to_http2_error(grpc_status_code status) { - switch (status) { - case GRPC_STATUS_OK: - return GRPC_CHTTP2_NO_ERROR; - case GRPC_STATUS_CANCELLED: - return GRPC_CHTTP2_CANCEL; - case GRPC_STATUS_RESOURCE_EXHAUSTED: - return GRPC_CHTTP2_ENHANCE_YOUR_CALM; - case GRPC_STATUS_PERMISSION_DENIED: - return GRPC_CHTTP2_INADEQUATE_SECURITY; - case GRPC_STATUS_UNAVAILABLE: - return GRPC_CHTTP2_REFUSED_STREAM; - default: - return GRPC_CHTTP2_INTERNAL_ERROR; - } -} - -grpc_status_code grpc_chttp2_http2_error_to_grpc_status( - grpc_chttp2_error_code error) { - switch (error) { - case GRPC_CHTTP2_NO_ERROR: - /* should never be received */ - return GRPC_STATUS_INTERNAL; - case GRPC_CHTTP2_CANCEL: - return GRPC_STATUS_CANCELLED; - case GRPC_CHTTP2_ENHANCE_YOUR_CALM: - return GRPC_STATUS_RESOURCE_EXHAUSTED; - case GRPC_CHTTP2_INADEQUATE_SECURITY: - return GRPC_STATUS_PERMISSION_DENIED; - case GRPC_CHTTP2_REFUSED_STREAM: - return GRPC_STATUS_UNAVAILABLE; - default: - return GRPC_STATUS_INTERNAL; - } -} - -grpc_status_code grpc_chttp2_http2_status_to_grpc_status(int status) { - switch (status) { - /* these HTTP2 status codes are called out explicitly in status.proto */ - case 200: - return GRPC_STATUS_OK; - case 400: - return GRPC_STATUS_INVALID_ARGUMENT; - case 401: - return GRPC_STATUS_UNAUTHENTICATED; - case 403: - return GRPC_STATUS_PERMISSION_DENIED; - case 404: - return GRPC_STATUS_NOT_FOUND; - case 409: - return GRPC_STATUS_ABORTED; - case 412: - return GRPC_STATUS_FAILED_PRECONDITION; - case 429: - return GRPC_STATUS_RESOURCE_EXHAUSTED; - case 499: - return GRPC_STATUS_CANCELLED; - case 500: - return GRPC_STATUS_UNKNOWN; - case 501: - return GRPC_STATUS_UNIMPLEMENTED; - case 503: - return GRPC_STATUS_UNAVAILABLE; - case 504: - return GRPC_STATUS_DEADLINE_EXCEEDED; - /* everything else is unknown */ - default: - return GRPC_STATUS_UNKNOWN; - } -} - -int grpc_chttp2_grpc_status_to_http2_status(grpc_status_code status) { - return 200; -} diff --git a/src/core/transport/chttp2/status_conversion.h b/src/core/transport/chttp2/status_conversion.h deleted file mode 100644 index c6e066bb5d..0000000000 --- a/src/core/transport/chttp2/status_conversion.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * - * Copyright 2015-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_TRANSPORT_CHTTP2_STATUS_CONVERSION_H -#define GRPC_CORE_TRANSPORT_CHTTP2_STATUS_CONVERSION_H - -#include -#include "src/core/transport/chttp2/http2_errors.h" - -/* Conversion of grpc status codes to http2 error codes (for RST_STREAM) */ -grpc_chttp2_error_code grpc_chttp2_grpc_status_to_http2_error( - grpc_status_code status); -grpc_status_code grpc_chttp2_http2_error_to_grpc_status( - grpc_chttp2_error_code error); - -/* Conversion of HTTP status codes (:status) to grpc status codes */ -grpc_status_code grpc_chttp2_http2_status_to_grpc_status(int status); -int grpc_chttp2_grpc_status_to_http2_status(grpc_status_code status); - -#endif /* GRPC_CORE_TRANSPORT_CHTTP2_STATUS_CONVERSION_H */ diff --git a/src/core/transport/chttp2/stream_lists.c b/src/core/transport/chttp2/stream_lists.c deleted file mode 100644 index 60fe735cfc..0000000000 --- a/src/core/transport/chttp2/stream_lists.c +++ /dev/null @@ -1,442 +0,0 @@ -/* - * - * Copyright 2015-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/transport/chttp2/internal.h" - -#include - -#define TRANSPORT_FROM_GLOBAL(tg) \ - ((grpc_chttp2_transport *)((char *)(tg)-offsetof(grpc_chttp2_transport, \ - global))) - -#define STREAM_FROM_GLOBAL(sg) \ - ((grpc_chttp2_stream *)((char *)(sg)-offsetof(grpc_chttp2_stream, global))) - -#define TRANSPORT_FROM_WRITING(tw) \ - ((grpc_chttp2_transport *)((char *)(tw)-offsetof(grpc_chttp2_transport, \ - writing))) - -#define STREAM_FROM_WRITING(sw) \ - ((grpc_chttp2_stream *)((char *)(sw)-offsetof(grpc_chttp2_stream, writing))) - -#define TRANSPORT_FROM_PARSING(tp) \ - ((grpc_chttp2_transport *)((char *)(tp)-offsetof(grpc_chttp2_transport, \ - parsing))) - -#define STREAM_FROM_PARSING(sp) \ - ((grpc_chttp2_stream *)((char *)(sp)-offsetof(grpc_chttp2_stream, parsing))) - -/* core list management */ - -static int stream_list_empty(grpc_chttp2_transport *t, - grpc_chttp2_stream_list_id id) { - return t->lists[id].head == NULL; -} - -static int stream_list_pop(grpc_chttp2_transport *t, - grpc_chttp2_stream **stream, - grpc_chttp2_stream_list_id id) { - grpc_chttp2_stream *s = t->lists[id].head; - if (s) { - grpc_chttp2_stream *new_head = s->links[id].next; - GPR_ASSERT(s->included[id]); - if (new_head) { - t->lists[id].head = new_head; - new_head->links[id].prev = NULL; - } else { - t->lists[id].head = NULL; - t->lists[id].tail = NULL; - } - s->included[id] = 0; - } - *stream = s; - return s != 0; -} - -static void stream_list_remove(grpc_chttp2_transport *t, grpc_chttp2_stream *s, - grpc_chttp2_stream_list_id id) { - GPR_ASSERT(s->included[id]); - s->included[id] = 0; - if (s->links[id].prev) { - s->links[id].prev->links[id].next = s->links[id].next; - } else { - GPR_ASSERT(t->lists[id].head == s); - t->lists[id].head = s->links[id].next; - } - if (s->links[id].next) { - s->links[id].next->links[id].prev = s->links[id].prev; - } else { - t->lists[id].tail = s->links[id].prev; - } -} - -static bool stream_list_maybe_remove(grpc_chttp2_transport *t, - grpc_chttp2_stream *s, - grpc_chttp2_stream_list_id id) { - if (s->included[id]) { - stream_list_remove(t, s, id); - return true; - } else { - return false; - } -} - -static void stream_list_add_tail(grpc_chttp2_transport *t, - grpc_chttp2_stream *s, - grpc_chttp2_stream_list_id id) { - grpc_chttp2_stream *old_tail; - GPR_ASSERT(!s->included[id]); - old_tail = t->lists[id].tail; - s->links[id].next = NULL; - s->links[id].prev = old_tail; - if (old_tail) { - old_tail->links[id].next = s; - } else { - t->lists[id].head = s; - } - t->lists[id].tail = s; - s->included[id] = 1; -} - -static bool stream_list_add(grpc_chttp2_transport *t, grpc_chttp2_stream *s, - grpc_chttp2_stream_list_id id) { - if (s->included[id]) { - return false; - } - stream_list_add_tail(t, s, id); - return true; -} - -/* wrappers for specializations */ - -bool grpc_chttp2_list_add_writable_stream( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global) { - GPR_ASSERT(stream_global->id != 0); - return stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global), - STREAM_FROM_GLOBAL(stream_global), - GRPC_CHTTP2_LIST_WRITABLE); -} - -int grpc_chttp2_list_pop_writable_stream( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_transport_writing *transport_writing, - grpc_chttp2_stream_global **stream_global, - grpc_chttp2_stream_writing **stream_writing) { - grpc_chttp2_stream *stream; - int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream, - GRPC_CHTTP2_LIST_WRITABLE); - if (r != 0) { - *stream_global = &stream->global; - *stream_writing = &stream->writing; - } - return r; -} - -bool grpc_chttp2_list_remove_writable_stream( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global) { - return stream_list_maybe_remove(TRANSPORT_FROM_GLOBAL(transport_global), - STREAM_FROM_GLOBAL(stream_global), - GRPC_CHTTP2_LIST_WRITABLE); -} - -void grpc_chttp2_list_add_writing_stream( - grpc_chttp2_transport_writing *transport_writing, - grpc_chttp2_stream_writing *stream_writing) { - GPR_ASSERT(stream_list_add(TRANSPORT_FROM_WRITING(transport_writing), - STREAM_FROM_WRITING(stream_writing), - GRPC_CHTTP2_LIST_WRITING)); -} - -int grpc_chttp2_list_have_writing_streams( - grpc_chttp2_transport_writing *transport_writing) { - return !stream_list_empty(TRANSPORT_FROM_WRITING(transport_writing), - GRPC_CHTTP2_LIST_WRITING); -} - -int grpc_chttp2_list_pop_writing_stream( - grpc_chttp2_transport_writing *transport_writing, - grpc_chttp2_stream_writing **stream_writing) { - grpc_chttp2_stream *stream; - int r = stream_list_pop(TRANSPORT_FROM_WRITING(transport_writing), &stream, - GRPC_CHTTP2_LIST_WRITING); - if (r != 0) { - *stream_writing = &stream->writing; - } - return r; -} - -void grpc_chttp2_list_add_written_stream( - grpc_chttp2_transport_writing *transport_writing, - grpc_chttp2_stream_writing *stream_writing) { - stream_list_add(TRANSPORT_FROM_WRITING(transport_writing), - STREAM_FROM_WRITING(stream_writing), - GRPC_CHTTP2_LIST_WRITTEN); -} - -int grpc_chttp2_list_pop_written_stream( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_transport_writing *transport_writing, - grpc_chttp2_stream_global **stream_global, - grpc_chttp2_stream_writing **stream_writing) { - grpc_chttp2_stream *stream; - int r = stream_list_pop(TRANSPORT_FROM_WRITING(transport_writing), &stream, - GRPC_CHTTP2_LIST_WRITTEN); - if (r != 0) { - *stream_global = &stream->global; - *stream_writing = &stream->writing; - } - return r; -} - -void grpc_chttp2_list_add_unannounced_incoming_window_available( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global) { - GPR_ASSERT(stream_global->id != 0); - stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global), - STREAM_FROM_GLOBAL(stream_global), - GRPC_CHTTP2_LIST_UNANNOUNCED_INCOMING_WINDOW_AVAILABLE); -} - -void grpc_chttp2_list_remove_unannounced_incoming_window_available( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global) { - stream_list_maybe_remove( - TRANSPORT_FROM_GLOBAL(transport_global), - STREAM_FROM_GLOBAL(stream_global), - GRPC_CHTTP2_LIST_UNANNOUNCED_INCOMING_WINDOW_AVAILABLE); -} - -int grpc_chttp2_list_pop_unannounced_incoming_window_available( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_global **stream_global, - grpc_chttp2_stream_parsing **stream_parsing) { - grpc_chttp2_stream *stream; - int r = - stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream, - GRPC_CHTTP2_LIST_UNANNOUNCED_INCOMING_WINDOW_AVAILABLE); - if (r != 0) { - *stream_global = &stream->global; - *stream_parsing = &stream->parsing; - } - return r; -} - -void grpc_chttp2_list_add_parsing_seen_stream( - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing) { - stream_list_add(TRANSPORT_FROM_PARSING(transport_parsing), - STREAM_FROM_PARSING(stream_parsing), - GRPC_CHTTP2_LIST_PARSING_SEEN); -} - -int grpc_chttp2_list_pop_parsing_seen_stream( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_global **stream_global, - grpc_chttp2_stream_parsing **stream_parsing) { - grpc_chttp2_stream *stream; - int r = stream_list_pop(TRANSPORT_FROM_PARSING(transport_parsing), &stream, - GRPC_CHTTP2_LIST_PARSING_SEEN); - if (r != 0) { - *stream_global = &stream->global; - *stream_parsing = &stream->parsing; - } - return r; -} - -void grpc_chttp2_list_add_waiting_for_concurrency( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global) { - stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global), - STREAM_FROM_GLOBAL(stream_global), - GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY); -} - -int grpc_chttp2_list_pop_waiting_for_concurrency( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global **stream_global) { - grpc_chttp2_stream *stream; - int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream, - GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY); - if (r != 0) { - *stream_global = &stream->global; - } - return r; -} - -void grpc_chttp2_list_add_check_read_ops( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global) { - stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global), - STREAM_FROM_GLOBAL(stream_global), - GRPC_CHTTP2_LIST_CHECK_READ_OPS); -} - -int grpc_chttp2_list_pop_check_read_ops( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global **stream_global) { - grpc_chttp2_stream *stream; - int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream, - GRPC_CHTTP2_LIST_CHECK_READ_OPS); - if (r != 0) { - *stream_global = &stream->global; - } - return r; -} - -void grpc_chttp2_list_add_writing_stalled_by_transport( - grpc_chttp2_transport_writing *transport_writing, - grpc_chttp2_stream_writing *stream_writing) { - grpc_chttp2_stream *stream = STREAM_FROM_WRITING(stream_writing); - if (!stream->included[GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT]) { - GRPC_CHTTP2_STREAM_REF(&stream->global, "chttp2_writing_stalled"); - } - stream_list_add(TRANSPORT_FROM_WRITING(transport_writing), stream, - GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT); -} - -void grpc_chttp2_list_flush_writing_stalled_by_transport( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing, - bool is_window_available) { - grpc_chttp2_stream *stream; - grpc_chttp2_transport *transport = TRANSPORT_FROM_WRITING(transport_writing); - while (stream_list_pop(transport, &stream, - GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT)) { - if (is_window_available) { - grpc_chttp2_become_writable(&transport->global, &stream->global); - } else { - grpc_chttp2_list_add_stalled_by_transport(transport_writing, - &stream->writing); - } - GRPC_CHTTP2_STREAM_UNREF(exec_ctx, &stream->global, - "chttp2_writing_stalled"); - } -} - -void grpc_chttp2_list_add_stalled_by_transport( - grpc_chttp2_transport_writing *transport_writing, - grpc_chttp2_stream_writing *stream_writing) { - stream_list_add(TRANSPORT_FROM_WRITING(transport_writing), - STREAM_FROM_WRITING(stream_writing), - GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT); -} - -int grpc_chttp2_list_pop_stalled_by_transport( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global **stream_global) { - grpc_chttp2_stream *stream; - int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream, - GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT); - if (r != 0) { - *stream_global = &stream->global; - } - return r; -} - -void grpc_chttp2_list_remove_stalled_by_transport( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global) { - stream_list_maybe_remove(TRANSPORT_FROM_GLOBAL(transport_global), - STREAM_FROM_GLOBAL(stream_global), - GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT); -} - -void grpc_chttp2_list_add_closed_waiting_for_parsing( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global) { - stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global), - STREAM_FROM_GLOBAL(stream_global), - GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_PARSING); -} - -int grpc_chttp2_list_pop_closed_waiting_for_parsing( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global **stream_global) { - grpc_chttp2_stream *stream; - int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream, - GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_PARSING); - if (r != 0) { - *stream_global = &stream->global; - } - return r; -} - -void grpc_chttp2_list_add_closed_waiting_for_writing( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global) { - stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global), - STREAM_FROM_GLOBAL(stream_global), - GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_WRITING); -} - -int grpc_chttp2_list_pop_closed_waiting_for_writing( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global **stream_global) { - grpc_chttp2_stream *stream; - int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream, - GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_WRITING); - if (r != 0) { - *stream_global = &stream->global; - } - return r; -} - -void grpc_chttp2_register_stream(grpc_chttp2_transport *t, - grpc_chttp2_stream *s) { - stream_list_add_tail(t, s, GRPC_CHTTP2_LIST_ALL_STREAMS); -} - -int grpc_chttp2_unregister_stream(grpc_chttp2_transport *t, - grpc_chttp2_stream *s) { - stream_list_maybe_remove(t, s, GRPC_CHTTP2_LIST_ALL_STREAMS); - return stream_list_empty(t, GRPC_CHTTP2_LIST_ALL_STREAMS); -} - -int grpc_chttp2_has_streams(grpc_chttp2_transport *t) { - return !stream_list_empty(t, GRPC_CHTTP2_LIST_ALL_STREAMS); -} - -void grpc_chttp2_for_all_streams( - grpc_chttp2_transport_global *transport_global, void *user_data, - void (*cb)(grpc_chttp2_transport_global *transport_global, void *user_data, - grpc_chttp2_stream_global *stream_global)) { - grpc_chttp2_stream *s; - grpc_chttp2_transport *t = TRANSPORT_FROM_GLOBAL(transport_global); - for (s = t->lists[GRPC_CHTTP2_LIST_ALL_STREAMS].head; s != NULL; - s = s->links[GRPC_CHTTP2_LIST_ALL_STREAMS].next) { - cb(transport_global, user_data, &s->global); - } -} diff --git a/src/core/transport/chttp2/stream_map.c b/src/core/transport/chttp2/stream_map.c deleted file mode 100644 index 555a16fb72..0000000000 --- a/src/core/transport/chttp2/stream_map.c +++ /dev/null @@ -1,197 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/transport/chttp2/stream_map.h" - -#include - -#include -#include -#include - -void grpc_chttp2_stream_map_init(grpc_chttp2_stream_map *map, - size_t initial_capacity) { - GPR_ASSERT(initial_capacity > 1); - map->keys = gpr_malloc(sizeof(uint32_t) * initial_capacity); - map->values = gpr_malloc(sizeof(void *) * initial_capacity); - map->count = 0; - map->free = 0; - map->capacity = initial_capacity; -} - -void grpc_chttp2_stream_map_destroy(grpc_chttp2_stream_map *map) { - gpr_free(map->keys); - gpr_free(map->values); -} - -static size_t compact(uint32_t *keys, void **values, size_t count) { - size_t i, out; - - for (i = 0, out = 0; i < count; i++) { - if (values[i]) { - keys[out] = keys[i]; - values[out] = values[i]; - out++; - } - } - - return out; -} - -void grpc_chttp2_stream_map_add(grpc_chttp2_stream_map *map, uint32_t key, - void *value) { - size_t count = map->count; - size_t capacity = map->capacity; - uint32_t *keys = map->keys; - void **values = map->values; - - GPR_ASSERT(count == 0 || keys[count - 1] < key); - GPR_ASSERT(value); - - if (count == capacity) { - if (map->free > capacity / 4) { - count = compact(keys, values, count); - map->free = 0; - } else { - /* resize when less than 25% of the table is free, because compaction - won't help much */ - map->capacity = capacity = 3 * capacity / 2; - map->keys = keys = gpr_realloc(keys, capacity * sizeof(uint32_t)); - map->values = values = gpr_realloc(values, capacity * sizeof(void *)); - } - } - - keys[count] = key; - values[count] = value; - map->count = count + 1; -} - -void grpc_chttp2_stream_map_move_into(grpc_chttp2_stream_map *src, - grpc_chttp2_stream_map *dst) { - /* if src is empty we dont need to do anything */ - if (src->count == src->free) { - return; - } - /* if dst is empty we simply need to swap */ - if (dst->count == dst->free) { - GPR_SWAP(grpc_chttp2_stream_map, *src, *dst); - return; - } - /* the first element of src must be greater than the last of dst... - * however the maps may need compacting for this property to hold */ - if (src->keys[0] <= dst->keys[dst->count - 1]) { - src->count = compact(src->keys, src->values, src->count); - src->free = 0; - dst->count = compact(dst->keys, dst->values, dst->count); - dst->free = 0; - } - GPR_ASSERT(src->keys[0] > dst->keys[dst->count - 1]); - /* if dst doesn't have capacity, resize */ - if (dst->count + src->count > dst->capacity) { - dst->capacity = GPR_MAX(dst->capacity * 3 / 2, dst->count + src->count); - dst->keys = gpr_realloc(dst->keys, dst->capacity * sizeof(uint32_t)); - dst->values = gpr_realloc(dst->values, dst->capacity * sizeof(void *)); - } - memcpy(dst->keys + dst->count, src->keys, src->count * sizeof(uint32_t)); - memcpy(dst->values + dst->count, src->values, src->count * sizeof(void *)); - dst->count += src->count; - dst->free += src->free; - src->count = 0; - src->free = 0; -} - -static void **find(grpc_chttp2_stream_map *map, uint32_t key) { - size_t min_idx = 0; - size_t max_idx = map->count; - size_t mid_idx; - uint32_t *keys = map->keys; - void **values = map->values; - uint32_t mid_key; - - if (max_idx == 0) return NULL; - - while (min_idx < max_idx) { - /* find the midpoint, avoiding overflow */ - mid_idx = min_idx + ((max_idx - min_idx) / 2); - mid_key = keys[mid_idx]; - - if (mid_key < key) { - min_idx = mid_idx + 1; - } else if (mid_key > key) { - max_idx = mid_idx; - } else /* mid_key == key */ - { - return &values[mid_idx]; - } - } - - return NULL; -} - -void *grpc_chttp2_stream_map_delete(grpc_chttp2_stream_map *map, uint32_t key) { - void **pvalue = find(map, key); - void *out = NULL; - if (pvalue != NULL) { - out = *pvalue; - *pvalue = NULL; - map->free += (out != NULL); - /* recognize complete emptyness and ensure we can skip - * defragmentation later */ - if (map->free == map->count) { - map->free = map->count = 0; - } - } - return out; -} - -void *grpc_chttp2_stream_map_find(grpc_chttp2_stream_map *map, uint32_t key) { - void **pvalue = find(map, key); - return pvalue != NULL ? *pvalue : NULL; -} - -size_t grpc_chttp2_stream_map_size(grpc_chttp2_stream_map *map) { - return map->count - map->free; -} - -void grpc_chttp2_stream_map_for_each(grpc_chttp2_stream_map *map, - void (*f)(void *user_data, uint32_t key, - void *value), - void *user_data) { - size_t i; - - for (i = 0; i < map->count; i++) { - if (map->values[i]) { - f(user_data, map->keys[i], map->values[i]); - } - } -} diff --git a/src/core/transport/chttp2/stream_map.h b/src/core/transport/chttp2/stream_map.h deleted file mode 100644 index 957a58a4f2..0000000000 --- a/src/core/transport/chttp2/stream_map.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * - * Copyright 2015-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_TRANSPORT_CHTTP2_STREAM_MAP_H -#define GRPC_CORE_TRANSPORT_CHTTP2_STREAM_MAP_H - -#include - -#include - -/* Data structure to map a uint32_t to a data object (represented by a void*) - - Represented as a sorted array of keys, and a corresponding array of values. - Lookups are performed with binary search. - Adds are restricted to strictly higher keys than previously seen (this is - guaranteed by http2). */ -typedef struct { - uint32_t *keys; - void **values; - size_t count; - size_t free; - size_t capacity; -} grpc_chttp2_stream_map; - -void grpc_chttp2_stream_map_init(grpc_chttp2_stream_map *map, - size_t initial_capacity); -void grpc_chttp2_stream_map_destroy(grpc_chttp2_stream_map *map); - -/* Add a new key: given http2 semantics, new keys must always be greater than - existing keys - this is asserted */ -void grpc_chttp2_stream_map_add(grpc_chttp2_stream_map *map, uint32_t key, - void *value); - -/* Delete an existing key - returns the previous value of the key if it existed, - or NULL otherwise */ -void *grpc_chttp2_stream_map_delete(grpc_chttp2_stream_map *map, uint32_t key); - -/* Move all elements of src into dst */ -void grpc_chttp2_stream_map_move_into(grpc_chttp2_stream_map *src, - grpc_chttp2_stream_map *dst); - -/* Return an existing key, or NULL if it does not exist */ -void *grpc_chttp2_stream_map_find(grpc_chttp2_stream_map *map, uint32_t key); - -/* How many (populated) entries are in the stream map? */ -size_t grpc_chttp2_stream_map_size(grpc_chttp2_stream_map *map); - -/* Callback on each stream */ -void grpc_chttp2_stream_map_for_each(grpc_chttp2_stream_map *map, - void (*f)(void *user_data, uint32_t key, - void *value), - void *user_data); - -#endif /* GRPC_CORE_TRANSPORT_CHTTP2_STREAM_MAP_H */ diff --git a/src/core/transport/chttp2/timeout_encoding.c b/src/core/transport/chttp2/timeout_encoding.c deleted file mode 100644 index c4802e050e..0000000000 --- a/src/core/transport/chttp2/timeout_encoding.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - * - * Copyright 2015-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/transport/chttp2/timeout_encoding.h" - -#include -#include - -#include -#include "src/core/support/string.h" - -static int64_t round_up(int64_t x, int64_t divisor) { - return (x / divisor + (x % divisor != 0)) * divisor; -} - -/* round an integer up to the next value with three significant figures */ -static int64_t round_up_to_three_sig_figs(int64_t x) { - if (x < 1000) return x; - if (x < 10000) return round_up(x, 10); - if (x < 100000) return round_up(x, 100); - if (x < 1000000) return round_up(x, 1000); - if (x < 10000000) return round_up(x, 10000); - if (x < 100000000) return round_up(x, 100000); - if (x < 1000000000) return round_up(x, 1000000); - return round_up(x, 10000000); -} - -/* encode our minimum viable timeout value */ -static void enc_tiny(char *buffer) { memcpy(buffer, "1n", 3); } - -static void enc_ext(char *buffer, int64_t value, char ext) { - int n = int64_ttoa(value, buffer); - buffer[n] = ext; - buffer[n + 1] = 0; -} - -static void enc_seconds(char *buffer, int64_t sec) { - if (sec % 3600 == 0) { - enc_ext(buffer, sec / 3600, 'H'); - } else if (sec % 60 == 0) { - enc_ext(buffer, sec / 60, 'M'); - } else { - enc_ext(buffer, sec, 'S'); - } -} - -static void enc_nanos(char *buffer, int64_t x) { - x = round_up_to_three_sig_figs(x); - if (x < 100000) { - if (x % 1000 == 0) { - enc_ext(buffer, x / 1000, 'u'); - } else { - enc_ext(buffer, x, 'n'); - } - } else if (x < 100000000) { - if (x % 1000000 == 0) { - enc_ext(buffer, x / 1000000, 'm'); - } else { - enc_ext(buffer, x / 1000, 'u'); - } - } else if (x < 1000000000) { - enc_ext(buffer, x / 1000000, 'm'); - } else { - /* note that this is only ever called with times of less than one second, - so if we reach here the time must have been rounded up to a whole second - (and no more) */ - memcpy(buffer, "1S", 3); - } -} - -static void enc_micros(char *buffer, int64_t x) { - x = round_up_to_three_sig_figs(x); - if (x < 100000) { - if (x % 1000 == 0) { - enc_ext(buffer, x / 1000, 'm'); - } else { - enc_ext(buffer, x, 'u'); - } - } else if (x < 100000000) { - if (x % 1000000 == 0) { - enc_ext(buffer, x / 1000000, 'S'); - } else { - enc_ext(buffer, x / 1000, 'm'); - } - } else { - enc_ext(buffer, x / 1000000, 'S'); - } -} - -void grpc_chttp2_encode_timeout(gpr_timespec timeout, char *buffer) { - if (timeout.tv_sec < 0) { - enc_tiny(buffer); - } else if (timeout.tv_sec == 0) { - enc_nanos(buffer, timeout.tv_nsec); - } else if (timeout.tv_sec < 1000 && timeout.tv_nsec != 0) { - enc_micros(buffer, - (int64_t)(timeout.tv_sec * 1000000) + - (timeout.tv_nsec / 1000 + (timeout.tv_nsec % 1000 != 0))); - } else { - enc_seconds(buffer, timeout.tv_sec + (timeout.tv_nsec != 0)); - } -} - -static int is_all_whitespace(const char *p) { - while (*p == ' ') p++; - return *p == 0; -} - -int grpc_chttp2_decode_timeout(const char *buffer, gpr_timespec *timeout) { - int32_t x = 0; - const uint8_t *p = (const uint8_t *)buffer; - int have_digit = 0; - /* skip whitespace */ - for (; *p == ' '; p++) - ; - /* decode numeric part */ - for (; *p >= '0' && *p <= '9'; p++) { - int32_t digit = (int32_t)(*p - (uint8_t)'0'); - have_digit = 1; - /* spec allows max. 8 digits, but we allow values up to 1,000,000,000 */ - if (x >= (100 * 1000 * 1000)) { - if (x != (100 * 1000 * 1000) || digit != 0) { - *timeout = gpr_inf_future(GPR_TIMESPAN); - return 1; - } - } - x = x * 10 + digit; - } - if (!have_digit) return 0; - /* skip whitespace */ - for (; *p == ' '; p++) - ; - /* decode unit specifier */ - switch (*p) { - case 'n': - *timeout = gpr_time_from_nanos(x, GPR_TIMESPAN); - break; - case 'u': - *timeout = gpr_time_from_micros(x, GPR_TIMESPAN); - break; - case 'm': - *timeout = gpr_time_from_millis(x, GPR_TIMESPAN); - break; - case 'S': - *timeout = gpr_time_from_seconds(x, GPR_TIMESPAN); - break; - case 'M': - *timeout = gpr_time_from_minutes(x, GPR_TIMESPAN); - break; - case 'H': - *timeout = gpr_time_from_hours(x, GPR_TIMESPAN); - break; - default: - return 0; - } - p++; - return is_all_whitespace((const char *)p); -} diff --git a/src/core/transport/chttp2/timeout_encoding.h b/src/core/transport/chttp2/timeout_encoding.h deleted file mode 100644 index f8e25226eb..0000000000 --- a/src/core/transport/chttp2/timeout_encoding.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * - * Copyright 2015-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_TRANSPORT_CHTTP2_TIMEOUT_ENCODING_H -#define GRPC_CORE_TRANSPORT_CHTTP2_TIMEOUT_ENCODING_H - -#include -#include "src/core/support/string.h" - -#define GRPC_CHTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE (GPR_LTOA_MIN_BUFSIZE + 1) - -/* Encode/decode timeouts to the GRPC over HTTP2 format; - encoding may round up arbitrarily */ -void grpc_chttp2_encode_timeout(gpr_timespec timeout, char *buffer); -int grpc_chttp2_decode_timeout(const char *buffer, gpr_timespec *timeout); - -#endif /* GRPC_CORE_TRANSPORT_CHTTP2_TIMEOUT_ENCODING_H */ diff --git a/src/core/transport/chttp2/varint.c b/src/core/transport/chttp2/varint.c deleted file mode 100644 index 1cc235e989..0000000000 --- a/src/core/transport/chttp2/varint.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/transport/chttp2/varint.h" - -uint32_t grpc_chttp2_hpack_varint_length(uint32_t tail_value) { - if (tail_value < (1 << 7)) { - return 2; - } else if (tail_value < (1 << 14)) { - return 3; - } else if (tail_value < (1 << 21)) { - return 4; - } else if (tail_value < (1 << 28)) { - return 5; - } else { - return 6; - } -} - -void grpc_chttp2_hpack_write_varint_tail(uint32_t tail_value, uint8_t* target, - uint32_t tail_length) { - switch (tail_length) { - case 5: - target[4] = (uint8_t)((tail_value >> 28) | 0x80); - case 4: - target[3] = (uint8_t)((tail_value >> 21) | 0x80); - case 3: - target[2] = (uint8_t)((tail_value >> 14) | 0x80); - case 2: - target[1] = (uint8_t)((tail_value >> 7) | 0x80); - case 1: - target[0] = (uint8_t)((tail_value) | 0x80); - } - target[tail_length - 1] &= 0x7f; -} diff --git a/src/core/transport/chttp2/varint.h b/src/core/transport/chttp2/varint.h deleted file mode 100644 index 7ab9d22ab5..0000000000 --- a/src/core/transport/chttp2/varint.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * - * Copyright 2015-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_TRANSPORT_CHTTP2_VARINT_H -#define GRPC_CORE_TRANSPORT_CHTTP2_VARINT_H - -#include - -/* Helpers for hpack varint encoding */ - -/* length of a value that needs varint tail encoding (it's bigger than can be - bitpacked into the opcode byte) - returned value includes the length of the - opcode byte */ -uint32_t grpc_chttp2_hpack_varint_length(uint32_t tail_value); - -void grpc_chttp2_hpack_write_varint_tail(uint32_t tail_value, uint8_t* target, - uint32_t tail_length); - -/* maximum value that can be bitpacked with the opcode if the opcode has a - prefix - of length prefix_bits */ -#define GRPC_CHTTP2_MAX_IN_PREFIX(prefix_bits) \ - ((uint32_t)((1 << (8 - (prefix_bits))) - 1)) - -/* length required to bitpack a value */ -#define GRPC_CHTTP2_VARINT_LENGTH(n, prefix_bits) \ - ((n) < GRPC_CHTTP2_MAX_IN_PREFIX(prefix_bits) \ - ? 1u \ - : grpc_chttp2_hpack_varint_length( \ - (n)-GRPC_CHTTP2_MAX_IN_PREFIX(prefix_bits))) - -#define GRPC_CHTTP2_WRITE_VARINT(n, prefix_bits, prefix_or, target, length) \ - do { \ - uint8_t* tgt = target; \ - if ((length) == 1u) { \ - (tgt)[0] = (uint8_t)((prefix_or) | (n)); \ - } else { \ - (tgt)[0] = \ - (prefix_or) | (uint8_t)GRPC_CHTTP2_MAX_IN_PREFIX(prefix_bits); \ - grpc_chttp2_hpack_write_varint_tail( \ - (n)-GRPC_CHTTP2_MAX_IN_PREFIX(prefix_bits), (tgt) + 1, (length)-1); \ - } \ - } while (0) - -#endif /* GRPC_CORE_TRANSPORT_CHTTP2_VARINT_H */ diff --git a/src/core/transport/chttp2/writing.c b/src/core/transport/chttp2/writing.c deleted file mode 100644 index 107725cbc7..0000000000 --- a/src/core/transport/chttp2/writing.c +++ /dev/null @@ -1,350 +0,0 @@ -/* - * - * Copyright 2015-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/transport/chttp2/internal.h" - -#include - -#include - -#include "src/core/profiling/timers.h" -#include "src/core/transport/chttp2/http2_errors.h" - -static void finalize_outbuf(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_writing *transport_writing); - -int grpc_chttp2_unlocking_check_writes( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, - grpc_chttp2_transport_writing *transport_writing, int is_parsing) { - grpc_chttp2_stream_global *stream_global; - grpc_chttp2_stream_writing *stream_writing; - - GPR_TIMER_BEGIN("grpc_chttp2_unlocking_check_writes", 0); - - /* simple writes are queued to qbuf, and flushed here */ - gpr_slice_buffer_swap(&transport_global->qbuf, &transport_writing->outbuf); - GPR_ASSERT(transport_global->qbuf.count == 0); - - grpc_chttp2_hpack_compressor_set_max_table_size( - &transport_writing->hpack_compressor, - transport_global->settings[GRPC_PEER_SETTINGS] - [GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE]); - - if (transport_global->dirtied_local_settings && - !transport_global->sent_local_settings && !is_parsing) { - gpr_slice_buffer_add( - &transport_writing->outbuf, - grpc_chttp2_settings_create( - transport_global->settings[GRPC_SENT_SETTINGS], - transport_global->settings[GRPC_LOCAL_SETTINGS], - transport_global->force_send_settings, GRPC_CHTTP2_NUM_SETTINGS)); - transport_global->force_send_settings = 0; - transport_global->dirtied_local_settings = 0; - transport_global->sent_local_settings = 1; - } - - GRPC_CHTTP2_FLOW_MOVE_TRANSPORT("write", transport_writing, outgoing_window, - transport_global, outgoing_window); - bool is_window_available = transport_writing->outgoing_window > 0; - grpc_chttp2_list_flush_writing_stalled_by_transport( - exec_ctx, transport_writing, is_window_available); - - /* for each grpc_chttp2_stream that's become writable, frame it's data - (according to available window sizes) and add to the output buffer */ - while (grpc_chttp2_list_pop_writable_stream( - transport_global, transport_writing, &stream_global, &stream_writing)) { - bool sent_initial_metadata = stream_writing->sent_initial_metadata; - bool become_writable = false; - - stream_writing->id = stream_global->id; - stream_writing->read_closed = stream_global->read_closed; - - GRPC_CHTTP2_FLOW_MOVE_STREAM("write", transport_writing, stream_writing, - outgoing_window, stream_global, - outgoing_window); - - if (!sent_initial_metadata && stream_global->send_initial_metadata) { - stream_writing->send_initial_metadata = - stream_global->send_initial_metadata; - stream_global->send_initial_metadata = NULL; - become_writable = true; - sent_initial_metadata = true; - } - if (sent_initial_metadata) { - if (stream_global->send_message != NULL) { - gpr_slice hdr = gpr_slice_malloc(5); - uint8_t *p = GPR_SLICE_START_PTR(hdr); - uint32_t len = stream_global->send_message->length; - GPR_ASSERT(stream_writing->send_message == NULL); - p[0] = (stream_global->send_message->flags & - GRPC_WRITE_INTERNAL_COMPRESS) != 0; - p[1] = (uint8_t)(len >> 24); - p[2] = (uint8_t)(len >> 16); - p[3] = (uint8_t)(len >> 8); - p[4] = (uint8_t)(len); - gpr_slice_buffer_add(&stream_writing->flow_controlled_buffer, hdr); - if (stream_global->send_message->length > 0) { - stream_writing->send_message = stream_global->send_message; - } else { - stream_writing->send_message = NULL; - } - stream_writing->stream_fetched = 0; - stream_global->send_message = NULL; - } - if ((stream_writing->send_message != NULL || - stream_writing->flow_controlled_buffer.length > 0) && - stream_writing->outgoing_window > 0) { - if (transport_writing->outgoing_window > 0) { - become_writable = true; - } else { - grpc_chttp2_list_add_stalled_by_transport(transport_writing, - stream_writing); - } - } - if (stream_global->send_trailing_metadata) { - stream_writing->send_trailing_metadata = - stream_global->send_trailing_metadata; - stream_global->send_trailing_metadata = NULL; - become_writable = true; - } - } - - if (!stream_global->read_closed && - stream_global->unannounced_incoming_window_for_writing > 1024) { - GRPC_CHTTP2_FLOW_MOVE_STREAM("write", transport_global, stream_writing, - announce_window, stream_global, - unannounced_incoming_window_for_writing); - become_writable = true; - } - - if (become_writable) { - grpc_chttp2_list_add_writing_stream(transport_writing, stream_writing); - } else { - GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2_writing"); - } - } - - /* if the grpc_chttp2_transport is ready to send a window update, do so here - also; 3/4 is a magic number that will likely get tuned soon */ - if (transport_global->announce_incoming_window > 0) { - uint32_t announced = (uint32_t)GPR_MIN( - transport_global->announce_incoming_window, UINT32_MAX); - GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("write", transport_global, - announce_incoming_window, announced); - gpr_slice_buffer_add(&transport_writing->outbuf, - grpc_chttp2_window_update_create(0, announced)); - } - - GPR_TIMER_END("grpc_chttp2_unlocking_check_writes", 0); - - return transport_writing->outbuf.count > 0 || - grpc_chttp2_list_have_writing_streams(transport_writing); -} - -void grpc_chttp2_perform_writes( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing, - grpc_endpoint *endpoint) { - GPR_ASSERT(transport_writing->outbuf.count > 0 || - grpc_chttp2_list_have_writing_streams(transport_writing)); - - finalize_outbuf(exec_ctx, transport_writing); - - GPR_ASSERT(endpoint); - - if (transport_writing->outbuf.count > 0) { - grpc_endpoint_write(exec_ctx, endpoint, &transport_writing->outbuf, - &transport_writing->done_cb); - } else { - grpc_exec_ctx_enqueue(exec_ctx, &transport_writing->done_cb, true, NULL); - } -} - -static void finalize_outbuf(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_writing *transport_writing) { - grpc_chttp2_stream_writing *stream_writing; - - GPR_TIMER_BEGIN("finalize_outbuf", 0); - - while ( - grpc_chttp2_list_pop_writing_stream(transport_writing, &stream_writing)) { - uint32_t max_outgoing = - (uint32_t)GPR_MIN(GRPC_CHTTP2_MAX_PAYLOAD_LENGTH, - GPR_MIN(stream_writing->outgoing_window, - transport_writing->outgoing_window)); - /* send initial metadata if it's available */ - if (stream_writing->send_initial_metadata != NULL) { - grpc_chttp2_encode_header( - &transport_writing->hpack_compressor, stream_writing->id, - stream_writing->send_initial_metadata, 0, &transport_writing->outbuf); - stream_writing->send_initial_metadata = NULL; - stream_writing->sent_initial_metadata = 1; - } - /* send any window updates */ - if (stream_writing->announce_window > 0 && - stream_writing->send_initial_metadata == NULL) { - uint32_t announce = stream_writing->announce_window; - gpr_slice_buffer_add( - &transport_writing->outbuf, - grpc_chttp2_window_update_create(stream_writing->id, - stream_writing->announce_window)); - GRPC_CHTTP2_FLOW_DEBIT_STREAM("write", transport_writing, stream_writing, - announce_window, announce); - stream_writing->announce_window = 0; - } - /* fetch any body bytes */ - while (!stream_writing->fetching && stream_writing->send_message && - stream_writing->flow_controlled_buffer.length < max_outgoing && - stream_writing->stream_fetched < - stream_writing->send_message->length) { - if (grpc_byte_stream_next(exec_ctx, stream_writing->send_message, - &stream_writing->fetching_slice, max_outgoing, - &stream_writing->finished_fetch)) { - stream_writing->stream_fetched += - GPR_SLICE_LENGTH(stream_writing->fetching_slice); - if (stream_writing->stream_fetched == - stream_writing->send_message->length) { - stream_writing->send_message = NULL; - } - gpr_slice_buffer_add(&stream_writing->flow_controlled_buffer, - stream_writing->fetching_slice); - } else { - stream_writing->fetching = 1; - } - } - /* send any body bytes */ - if (stream_writing->flow_controlled_buffer.length > 0) { - if (max_outgoing > 0) { - uint32_t send_bytes = (uint32_t)GPR_MIN( - max_outgoing, stream_writing->flow_controlled_buffer.length); - int is_last_data_frame = - stream_writing->send_message == NULL && - send_bytes == stream_writing->flow_controlled_buffer.length; - int is_last_frame = is_last_data_frame && - stream_writing->send_trailing_metadata != NULL && - grpc_metadata_batch_is_empty( - stream_writing->send_trailing_metadata); - grpc_chttp2_encode_data( - stream_writing->id, &stream_writing->flow_controlled_buffer, - send_bytes, is_last_frame, &transport_writing->outbuf); - GRPC_CHTTP2_FLOW_DEBIT_STREAM("write", transport_writing, - stream_writing, outgoing_window, - send_bytes); - GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("write", transport_writing, - outgoing_window, send_bytes); - if (is_last_frame) { - stream_writing->send_trailing_metadata = NULL; - stream_writing->sent_trailing_metadata = 1; - } - if (is_last_data_frame) { - GPR_ASSERT(stream_writing->send_message == NULL); - stream_writing->sent_message = 1; - } - } else if (transport_writing->outgoing_window == 0) { - grpc_chttp2_list_add_writing_stalled_by_transport(transport_writing, - stream_writing); - grpc_chttp2_list_add_written_stream(transport_writing, stream_writing); - } - } - /* send trailing metadata if it's available and we're ready for it */ - if (stream_writing->send_message == NULL && - stream_writing->flow_controlled_buffer.length == 0 && - stream_writing->send_trailing_metadata != NULL) { - if (grpc_metadata_batch_is_empty( - stream_writing->send_trailing_metadata)) { - grpc_chttp2_encode_data(stream_writing->id, - &stream_writing->flow_controlled_buffer, 0, 1, - &transport_writing->outbuf); - } else { - grpc_chttp2_encode_header(&transport_writing->hpack_compressor, - stream_writing->id, - stream_writing->send_trailing_metadata, 1, - &transport_writing->outbuf); - } - if (!transport_writing->is_client && !stream_writing->read_closed) { - gpr_slice_buffer_add(&transport_writing->outbuf, - grpc_chttp2_rst_stream_create( - stream_writing->id, GRPC_CHTTP2_NO_ERROR)); - } - stream_writing->send_trailing_metadata = NULL; - stream_writing->sent_trailing_metadata = 1; - } - /* if there's more to write, then loop, otherwise prepare to finish the - * write */ - if ((stream_writing->flow_controlled_buffer.length > 0 || - (stream_writing->send_message && !stream_writing->fetching)) && - stream_writing->outgoing_window > 0) { - if (transport_writing->outgoing_window > 0) { - grpc_chttp2_list_add_writing_stream(transport_writing, stream_writing); - } else { - grpc_chttp2_list_add_writing_stalled_by_transport(transport_writing, - stream_writing); - grpc_chttp2_list_add_written_stream(transport_writing, stream_writing); - } - } else { - grpc_chttp2_list_add_written_stream(transport_writing, stream_writing); - } - } - - GPR_TIMER_END("finalize_outbuf", 0); -} - -void grpc_chttp2_cleanup_writing( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, - grpc_chttp2_transport_writing *transport_writing) { - grpc_chttp2_stream_writing *stream_writing; - grpc_chttp2_stream_global *stream_global; - - while (grpc_chttp2_list_pop_written_stream( - transport_global, transport_writing, &stream_global, &stream_writing)) { - if (stream_writing->sent_initial_metadata) { - grpc_chttp2_complete_closure_step( - exec_ctx, &stream_global->send_initial_metadata_finished, 1); - } - if (stream_writing->sent_message) { - GPR_ASSERT(stream_writing->send_message == NULL); - grpc_chttp2_complete_closure_step( - exec_ctx, &stream_global->send_message_finished, 1); - stream_writing->sent_message = 0; - } - if (stream_writing->sent_trailing_metadata) { - grpc_chttp2_complete_closure_step( - exec_ctx, &stream_global->send_trailing_metadata_finished, 1); - } - if (stream_writing->sent_trailing_metadata) { - grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, - !transport_global->is_client, 1); - } - GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2_writing"); - } - gpr_slice_buffer_reset_and_unref(&transport_writing->outbuf); -} diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c deleted file mode 100644 index b45bf31997..0000000000 --- a/src/core/transport/chttp2_transport.c +++ /dev/null @@ -1,1785 +0,0 @@ -/* - * - * Copyright 2015-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/transport/chttp2_transport.h" - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "src/core/profiling/timers.h" -#include "src/core/support/string.h" -#include "src/core/transport/chttp2/http2_errors.h" -#include "src/core/transport/chttp2/internal.h" -#include "src/core/transport/chttp2/status_conversion.h" -#include "src/core/transport/chttp2/timeout_encoding.h" -#include "src/core/transport/static_metadata.h" -#include "src/core/transport/transport_impl.h" - -#define DEFAULT_WINDOW 65535 -#define DEFAULT_CONNECTION_WINDOW_TARGET (1024 * 1024) -#define MAX_WINDOW 0x7fffffffu - -#define MAX_CLIENT_STREAM_ID 0x7fffffffu - -int grpc_http_trace = 0; -int grpc_flowctl_trace = 0; - -#define TRANSPORT_FROM_WRITING(tw) \ - ((grpc_chttp2_transport *)((char *)(tw)-offsetof(grpc_chttp2_transport, \ - writing))) - -#define TRANSPORT_FROM_PARSING(tw) \ - ((grpc_chttp2_transport *)((char *)(tw)-offsetof(grpc_chttp2_transport, \ - parsing))) - -#define TRANSPORT_FROM_GLOBAL(tg) \ - ((grpc_chttp2_transport *)((char *)(tg)-offsetof(grpc_chttp2_transport, \ - global))) - -#define STREAM_FROM_GLOBAL(sg) \ - ((grpc_chttp2_stream *)((char *)(sg)-offsetof(grpc_chttp2_stream, global))) - -#define STREAM_FROM_PARSING(sg) \ - ((grpc_chttp2_stream *)((char *)(sg)-offsetof(grpc_chttp2_stream, parsing))) - -static const grpc_transport_vtable vtable; - -static void lock(grpc_chttp2_transport *t); -static void unlock(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t); - -/* forward declarations of various callbacks that we'll build closures around */ -static void writing_action(grpc_exec_ctx *exec_ctx, void *t, - bool iomgr_success_ignored); - -/** Set a transport level setting, and push it to our peer */ -static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id, - uint32_t value); - -/** Endpoint callback to process incoming data */ -static void recv_data(grpc_exec_ctx *exec_ctx, void *tp, bool success); - -/** Start disconnection chain */ -static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t); - -/** Perform a transport_op */ -static void perform_stream_op_locked( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global, grpc_transport_stream_op *op); - -/** Cancel a stream: coming from the transport API */ -static void cancel_from_api(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global, - grpc_status_code status); - -static void close_from_api(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global, - grpc_status_code status, - gpr_slice *optional_message); - -/** Add endpoint from this transport to pollset */ -static void add_to_pollset_locked(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t, - grpc_pollset *pollset); -static void add_to_pollset_set_locked(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t, - grpc_pollset_set *pollset_set); - -/** Start new streams that have been created if we can */ -static void maybe_start_some_streams( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global); - -static void connectivity_state_set( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, - grpc_connectivity_state state, const char *reason); - -static void check_read_ops(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_global *transport_global); - -static void incoming_byte_stream_update_flow_control( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global, size_t max_size_hint, - size_t have_already); - -static void fail_pending_writes(grpc_exec_ctx *exec_ctx, - grpc_chttp2_stream_global *stream_global); - -/******************************************************************************* - * CONSTRUCTION/DESTRUCTION/REFCOUNTING - */ - -static void destruct_transport(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t) { - size_t i; - - gpr_mu_lock(&t->mu); - - GPR_ASSERT(t->ep == NULL); - - gpr_slice_buffer_destroy(&t->global.qbuf); - - gpr_slice_buffer_destroy(&t->writing.outbuf); - grpc_chttp2_hpack_compressor_destroy(&t->writing.hpack_compressor); - - gpr_slice_buffer_destroy(&t->parsing.qbuf); - gpr_slice_buffer_destroy(&t->read_buffer); - grpc_chttp2_hpack_parser_destroy(&t->parsing.hpack_parser); - grpc_chttp2_goaway_parser_destroy(&t->parsing.goaway_parser); - - for (i = 0; i < STREAM_LIST_COUNT; i++) { - GPR_ASSERT(t->lists[i].head == NULL); - GPR_ASSERT(t->lists[i].tail == NULL); - } - - GPR_ASSERT(grpc_chttp2_stream_map_size(&t->parsing_stream_map) == 0); - GPR_ASSERT(grpc_chttp2_stream_map_size(&t->new_stream_map) == 0); - - grpc_chttp2_stream_map_destroy(&t->parsing_stream_map); - grpc_chttp2_stream_map_destroy(&t->new_stream_map); - grpc_connectivity_state_destroy(exec_ctx, &t->channel_callback.state_tracker); - - gpr_mu_unlock(&t->mu); - gpr_mu_destroy(&t->mu); - - /* callback remaining pings: they're not allowed to call into the transpot, - and maybe they hold resources that need to be freed */ - while (t->global.pings.next != &t->global.pings) { - grpc_chttp2_outstanding_ping *ping = t->global.pings.next; - grpc_exec_ctx_enqueue(exec_ctx, ping->on_recv, false, NULL); - ping->next->prev = ping->prev; - ping->prev->next = ping->next; - gpr_free(ping); - } - - gpr_free(t->peer_string); - gpr_free(t); -} - -#ifdef REFCOUNTING_DEBUG -#define REF_TRANSPORT(t, r) ref_transport(t, r, __FILE__, __LINE__) -#define UNREF_TRANSPORT(cl, t, r) unref_transport(cl, t, r, __FILE__, __LINE__) -static void unref_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, - const char *reason, const char *file, int line) { - gpr_log(GPR_DEBUG, "chttp2:unref:%p %d->%d %s [%s:%d]", t, t->refs.count, - t->refs.count - 1, reason, file, line); - if (!gpr_unref(&t->refs)) return; - destruct_transport(exec_ctx, t); -} - -static void ref_transport(grpc_chttp2_transport *t, const char *reason, - const char *file, int line) { - gpr_log(GPR_DEBUG, "chttp2: ref:%p %d->%d %s [%s:%d]", t, t->refs.count, - t->refs.count + 1, reason, file, line); - gpr_ref(&t->refs); -} -#else -#define REF_TRANSPORT(t, r) ref_transport(t) -#define UNREF_TRANSPORT(cl, t, r) unref_transport(cl, t) -static void unref_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) { - if (!gpr_unref(&t->refs)) return; - destruct_transport(exec_ctx, t); -} - -static void ref_transport(grpc_chttp2_transport *t) { gpr_ref(&t->refs); } -#endif - -static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, - const grpc_channel_args *channel_args, - grpc_endpoint *ep, uint8_t is_client) { - size_t i; - int j; - - GPR_ASSERT(strlen(GRPC_CHTTP2_CLIENT_CONNECT_STRING) == - GRPC_CHTTP2_CLIENT_CONNECT_STRLEN); - - memset(t, 0, sizeof(*t)); - - t->base.vtable = &vtable; - t->ep = ep; - /* one ref is for destroy, the other for when ep becomes NULL */ - gpr_ref_init(&t->refs, 2); - /* ref is dropped at transport close() */ - gpr_ref_init(&t->shutdown_ep_refs, 1); - gpr_mu_init(&t->mu); - t->peer_string = grpc_endpoint_get_peer(ep); - t->endpoint_reading = 1; - t->global.next_stream_id = is_client ? 1 : 2; - t->global.is_client = is_client; - t->writing.outgoing_window = DEFAULT_WINDOW; - t->parsing.incoming_window = DEFAULT_WINDOW; - t->global.stream_lookahead = DEFAULT_WINDOW; - t->global.connection_window_target = DEFAULT_CONNECTION_WINDOW_TARGET; - t->global.ping_counter = 1; - t->global.pings.next = t->global.pings.prev = &t->global.pings; - t->parsing.is_client = is_client; - t->parsing.deframe_state = - is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0; - t->writing.is_client = is_client; - grpc_connectivity_state_init( - &t->channel_callback.state_tracker, GRPC_CHANNEL_READY, - is_client ? "client_transport" : "server_transport"); - - gpr_slice_buffer_init(&t->global.qbuf); - - gpr_slice_buffer_init(&t->writing.outbuf); - grpc_chttp2_hpack_compressor_init(&t->writing.hpack_compressor); - grpc_closure_init(&t->writing_action, writing_action, t); - - gpr_slice_buffer_init(&t->parsing.qbuf); - grpc_chttp2_goaway_parser_init(&t->parsing.goaway_parser); - grpc_chttp2_hpack_parser_init(&t->parsing.hpack_parser); - - grpc_closure_init(&t->writing.done_cb, grpc_chttp2_terminate_writing, - &t->writing); - grpc_closure_init(&t->recv_data, recv_data, t); - gpr_slice_buffer_init(&t->read_buffer); - - if (is_client) { - gpr_slice_buffer_add( - &t->global.qbuf, - gpr_slice_from_copied_string(GRPC_CHTTP2_CLIENT_CONNECT_STRING)); - } - /* 8 is a random stab in the dark as to a good initial size: it's small enough - that it shouldn't waste memory for infrequently used connections, yet - large enough that the exponential growth should happen nicely when it's - needed. - TODO(ctiller): tune this */ - grpc_chttp2_stream_map_init(&t->parsing_stream_map, 8); - grpc_chttp2_stream_map_init(&t->new_stream_map, 8); - - /* copy in initial settings to all setting sets */ - for (i = 0; i < GRPC_CHTTP2_NUM_SETTINGS; i++) { - t->parsing.settings[i] = grpc_chttp2_settings_parameters[i].default_value; - for (j = 0; j < GRPC_NUM_SETTING_SETS; j++) { - t->global.settings[j][i] = - grpc_chttp2_settings_parameters[i].default_value; - } - } - t->global.dirtied_local_settings = 1; - /* Hack: it's common for implementations to assume 65536 bytes initial send - window -- this should by rights be 0 */ - t->global.force_send_settings = 1 << GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; - t->global.sent_local_settings = 0; - - /* configure http2 the way we like it */ - if (is_client) { - push_setting(t, GRPC_CHTTP2_SETTINGS_ENABLE_PUSH, 0); - push_setting(t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 0); - } - push_setting(t, GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, DEFAULT_WINDOW); - - if (channel_args) { - for (i = 0; i < channel_args->num_args; i++) { - if (0 == - strcmp(channel_args->args[i].key, GRPC_ARG_MAX_CONCURRENT_STREAMS)) { - if (is_client) { - gpr_log(GPR_ERROR, "%s: is ignored on the client", - GRPC_ARG_MAX_CONCURRENT_STREAMS); - } else if (channel_args->args[i].type != GRPC_ARG_INTEGER) { - gpr_log(GPR_ERROR, "%s: must be an integer", - GRPC_ARG_MAX_CONCURRENT_STREAMS); - } else { - push_setting(t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, - (uint32_t)channel_args->args[i].value.integer); - } - } else if (0 == strcmp(channel_args->args[i].key, - GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER)) { - if (channel_args->args[i].type != GRPC_ARG_INTEGER) { - gpr_log(GPR_ERROR, "%s: must be an integer", - GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER); - } else if ((t->global.next_stream_id & 1) != - (channel_args->args[i].value.integer & 1)) { - gpr_log(GPR_ERROR, "%s: low bit must be %d on %s", - GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER, - t->global.next_stream_id & 1, - is_client ? "client" : "server"); - } else { - t->global.next_stream_id = - (uint32_t)channel_args->args[i].value.integer; - } - } else if (0 == strcmp(channel_args->args[i].key, - GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES)) { - if (channel_args->args[i].type != GRPC_ARG_INTEGER) { - gpr_log(GPR_ERROR, "%s: must be an integer", - GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES); - } else if (channel_args->args[i].value.integer <= 5) { - gpr_log(GPR_ERROR, "%s: must be at least 5", - GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES); - } else { - t->global.stream_lookahead = - (uint32_t)channel_args->args[i].value.integer; - } - } else if (0 == strcmp(channel_args->args[i].key, - GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER)) { - if (channel_args->args[i].type != GRPC_ARG_INTEGER) { - gpr_log(GPR_ERROR, "%s: must be an integer", - GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER); - } else if (channel_args->args[i].value.integer < 0) { - gpr_log(GPR_ERROR, "%s: must be non-negative", - GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER); - } else { - push_setting(t, GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE, - (uint32_t)channel_args->args[i].value.integer); - } - } else if (0 == strcmp(channel_args->args[i].key, - GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER)) { - if (channel_args->args[i].type != GRPC_ARG_INTEGER) { - gpr_log(GPR_ERROR, "%s: must be an integer", - GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER); - } else if (channel_args->args[i].value.integer < 0) { - gpr_log(GPR_ERROR, "%s: must be non-negative", - GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER); - } else { - grpc_chttp2_hpack_compressor_set_max_usable_size( - &t->writing.hpack_compressor, - (uint32_t)channel_args->args[i].value.integer); - } - } - } - } -} - -static void destroy_transport(grpc_exec_ctx *exec_ctx, grpc_transport *gt) { - grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; - - lock(t); - t->destroying = 1; - drop_connection(exec_ctx, t); - unlock(exec_ctx, t); - - UNREF_TRANSPORT(exec_ctx, t, "destroy"); -} - -/** block grpc_endpoint_shutdown being called until a paired - allow_endpoint_shutdown is made */ -static void prevent_endpoint_shutdown(grpc_chttp2_transport *t) { - GPR_ASSERT(t->ep); - gpr_ref(&t->shutdown_ep_refs); -} - -static void allow_endpoint_shutdown_locked(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t) { - if (gpr_unref(&t->shutdown_ep_refs)) { - if (t->ep) { - grpc_endpoint_shutdown(exec_ctx, t->ep); - } - } -} - -static void allow_endpoint_shutdown_unlocked(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t) { - if (gpr_unref(&t->shutdown_ep_refs)) { - gpr_mu_lock(&t->mu); - if (t->ep) { - grpc_endpoint_shutdown(exec_ctx, t->ep); - } - gpr_mu_unlock(&t->mu); - } -} - -static void destroy_endpoint(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t) { - grpc_endpoint_destroy(exec_ctx, t->ep); - t->ep = NULL; - /* safe because we'll still have the ref for write */ - UNREF_TRANSPORT(exec_ctx, t, "disconnect"); -} - -static void close_transport_locked(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t) { - if (!t->closed) { - t->closed = 1; - connectivity_state_set(exec_ctx, &t->global, GRPC_CHANNEL_FATAL_FAILURE, - "close_transport"); - if (t->ep) { - allow_endpoint_shutdown_locked(exec_ctx, t); - } - - /* flush writable stream list to avoid dangling references */ - grpc_chttp2_stream_global *stream_global; - grpc_chttp2_stream_writing *stream_writing; - while (grpc_chttp2_list_pop_writable_stream( - &t->global, &t->writing, &stream_global, &stream_writing)) { - GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2_writing"); - } - } -} - -#ifdef GRPC_STREAM_REFCOUNT_DEBUG -void grpc_chttp2_stream_ref(grpc_chttp2_stream_global *stream_global, - const char *reason) { - grpc_stream_ref(STREAM_FROM_GLOBAL(stream_global)->refcount, reason); -} -void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx, - grpc_chttp2_stream_global *stream_global, - const char *reason) { - grpc_stream_unref(exec_ctx, STREAM_FROM_GLOBAL(stream_global)->refcount, - reason); -} -#else -void grpc_chttp2_stream_ref(grpc_chttp2_stream_global *stream_global) { - grpc_stream_ref(STREAM_FROM_GLOBAL(stream_global)->refcount); -} -void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx, - grpc_chttp2_stream_global *stream_global) { - grpc_stream_unref(exec_ctx, STREAM_FROM_GLOBAL(stream_global)->refcount); -} -#endif - -static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, - grpc_stream *gs, grpc_stream_refcount *refcount, - const void *server_data) { - grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; - grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs; - - memset(s, 0, sizeof(*s)); - - s->refcount = refcount; - GRPC_CHTTP2_STREAM_REF(&s->global, "chttp2"); - - grpc_chttp2_incoming_metadata_buffer_init(&s->parsing.metadata_buffer[0]); - grpc_chttp2_incoming_metadata_buffer_init(&s->parsing.metadata_buffer[1]); - grpc_chttp2_incoming_metadata_buffer_init( - &s->global.received_initial_metadata); - grpc_chttp2_incoming_metadata_buffer_init( - &s->global.received_trailing_metadata); - grpc_chttp2_data_parser_init(&s->parsing.data_parser); - gpr_slice_buffer_init(&s->writing.flow_controlled_buffer); - - REF_TRANSPORT(t, "stream"); - - lock(t); - grpc_chttp2_register_stream(t, s); - if (server_data) { - GPR_ASSERT(t->parsing_active); - s->global.id = (uint32_t)(uintptr_t)server_data; - s->parsing.id = s->global.id; - s->global.outgoing_window = - t->global.settings[GRPC_PEER_SETTINGS] - [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; - s->parsing.incoming_window = s->global.max_recv_bytes = - t->global.settings[GRPC_SENT_SETTINGS] - [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; - *t->accepting_stream = s; - grpc_chttp2_stream_map_add(&t->parsing_stream_map, s->global.id, s); - s->global.in_stream_map = 1; - } - unlock(exec_ctx, t); - - return 0; -} - -static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, - grpc_stream *gs) { - grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; - grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs; - int i; - grpc_byte_stream *bs; - - GPR_TIMER_BEGIN("destroy_stream", 0); - - gpr_mu_lock(&t->mu); - - GPR_ASSERT((s->global.write_closed && s->global.read_closed) || - s->global.id == 0); - GPR_ASSERT(!s->global.in_stream_map); - if (grpc_chttp2_unregister_stream(t, s) && t->global.sent_goaway) { - close_transport_locked(exec_ctx, t); - } - if (!t->parsing_active && s->global.id) { - GPR_ASSERT(grpc_chttp2_stream_map_find(&t->parsing_stream_map, - s->global.id) == NULL); - } - - grpc_chttp2_list_remove_unannounced_incoming_window_available(&t->global, - &s->global); - grpc_chttp2_list_remove_stalled_by_transport(&t->global, &s->global); - - gpr_mu_unlock(&t->mu); - - for (i = 0; i < STREAM_LIST_COUNT; i++) { - if (s->included[i]) { - gpr_log(GPR_ERROR, "%s stream %d still included in list %d", - t->global.is_client ? "client" : "server", s->global.id, i); - abort(); - } - } - - while ( - (bs = grpc_chttp2_incoming_frame_queue_pop(&s->global.incoming_frames))) { - grpc_byte_stream_destroy(exec_ctx, bs); - } - - GPR_ASSERT(s->global.send_initial_metadata_finished == NULL); - GPR_ASSERT(s->global.send_message_finished == NULL); - GPR_ASSERT(s->global.send_trailing_metadata_finished == NULL); - GPR_ASSERT(s->global.recv_initial_metadata_ready == NULL); - GPR_ASSERT(s->global.recv_message_ready == NULL); - GPR_ASSERT(s->global.recv_trailing_metadata_finished == NULL); - grpc_chttp2_data_parser_destroy(exec_ctx, &s->parsing.data_parser); - grpc_chttp2_incoming_metadata_buffer_destroy(&s->parsing.metadata_buffer[0]); - grpc_chttp2_incoming_metadata_buffer_destroy(&s->parsing.metadata_buffer[1]); - grpc_chttp2_incoming_metadata_buffer_destroy( - &s->global.received_initial_metadata); - grpc_chttp2_incoming_metadata_buffer_destroy( - &s->global.received_trailing_metadata); - gpr_slice_buffer_destroy(&s->writing.flow_controlled_buffer); - - UNREF_TRANSPORT(exec_ctx, t, "stream"); - - GPR_TIMER_END("destroy_stream", 0); -} - -grpc_chttp2_stream_parsing *grpc_chttp2_parsing_lookup_stream( - grpc_chttp2_transport_parsing *transport_parsing, uint32_t id) { - grpc_chttp2_transport *t = TRANSPORT_FROM_PARSING(transport_parsing); - grpc_chttp2_stream *s = - grpc_chttp2_stream_map_find(&t->parsing_stream_map, id); - return s ? &s->parsing : NULL; -} - -grpc_chttp2_stream_parsing *grpc_chttp2_parsing_accept_stream( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, - uint32_t id) { - grpc_chttp2_stream *accepting; - grpc_chttp2_transport *t = TRANSPORT_FROM_PARSING(transport_parsing); - GPR_ASSERT(t->accepting_stream == NULL); - t->accepting_stream = &accepting; - t->channel_callback.accept_stream(exec_ctx, - t->channel_callback.accept_stream_user_data, - &t->base, (void *)(uintptr_t)id); - t->accepting_stream = NULL; - return &accepting->parsing; -} - -/******************************************************************************* - * LOCK MANAGEMENT - */ - -/* We take a grpc_chttp2_transport-global lock in response to calls coming in - from above, - and in response to data being received from below. New data to be written - is always queued, as are callbacks to process data. During unlock() we - check our todo lists and initiate callbacks and flush writes. */ - -static void lock(grpc_chttp2_transport *t) { gpr_mu_lock(&t->mu); } - -static void unlock(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) { - GPR_TIMER_BEGIN("unlock", 0); - if (!t->writing_active && !t->closed && - grpc_chttp2_unlocking_check_writes(exec_ctx, &t->global, &t->writing, - t->parsing_active)) { - t->writing_active = 1; - REF_TRANSPORT(t, "writing"); - grpc_exec_ctx_enqueue(exec_ctx, &t->writing_action, true, NULL); - prevent_endpoint_shutdown(t); - } - check_read_ops(exec_ctx, &t->global); - - gpr_mu_unlock(&t->mu); - GPR_TIMER_END("unlock", 0); -} - -/******************************************************************************* - * OUTPUT PROCESSING - */ - -void grpc_chttp2_become_writable(grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global) { - if (!TRANSPORT_FROM_GLOBAL(transport_global)->closed && - grpc_chttp2_list_add_writable_stream(transport_global, stream_global)) { - GRPC_CHTTP2_STREAM_REF(stream_global, "chttp2_writing"); - } -} - -static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id, - uint32_t value) { - const grpc_chttp2_setting_parameters *sp = - &grpc_chttp2_settings_parameters[id]; - uint32_t use_value = GPR_CLAMP(value, sp->min_value, sp->max_value); - if (use_value != value) { - gpr_log(GPR_INFO, "Requested parameter %s clamped from %d to %d", sp->name, - value, use_value); - } - if (use_value != t->global.settings[GRPC_LOCAL_SETTINGS][id]) { - t->global.settings[GRPC_LOCAL_SETTINGS][id] = use_value; - t->global.dirtied_local_settings = 1; - } -} - -void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx, - void *transport_writing_ptr, bool success) { - grpc_chttp2_transport_writing *transport_writing = transport_writing_ptr; - grpc_chttp2_transport *t = TRANSPORT_FROM_WRITING(transport_writing); - grpc_chttp2_stream_global *stream_global; - - GPR_TIMER_BEGIN("grpc_chttp2_terminate_writing", 0); - - lock(t); - - allow_endpoint_shutdown_locked(exec_ctx, t); - - if (!success) { - drop_connection(exec_ctx, t); - } - - grpc_chttp2_cleanup_writing(exec_ctx, &t->global, &t->writing); - - while (grpc_chttp2_list_pop_closed_waiting_for_writing(&t->global, - &stream_global)) { - fail_pending_writes(exec_ctx, stream_global); - GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "finish_writes"); - } - - /* leave the writing flag up on shutdown to prevent further writes in unlock() - from starting */ - t->writing_active = 0; - if (t->ep && !t->endpoint_reading) { - destroy_endpoint(exec_ctx, t); - } - - unlock(exec_ctx, t); - - UNREF_TRANSPORT(exec_ctx, t, "writing"); - - GPR_TIMER_END("grpc_chttp2_terminate_writing", 0); -} - -static void writing_action(grpc_exec_ctx *exec_ctx, void *gt, - bool iomgr_success_ignored) { - grpc_chttp2_transport *t = gt; - GPR_TIMER_BEGIN("writing_action", 0); - grpc_chttp2_perform_writes(exec_ctx, &t->writing, t->ep); - GPR_TIMER_END("writing_action", 0); -} - -void grpc_chttp2_add_incoming_goaway( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, - uint32_t goaway_error, gpr_slice goaway_text) { - char *msg = gpr_dump_slice(goaway_text, GPR_DUMP_HEX | GPR_DUMP_ASCII); - gpr_log(GPR_DEBUG, "got goaway [%d]: %s", goaway_error, msg); - gpr_free(msg); - gpr_slice_unref(goaway_text); - transport_global->seen_goaway = 1; - connectivity_state_set(exec_ctx, transport_global, GRPC_CHANNEL_FATAL_FAILURE, - "got_goaway"); -} - -static void maybe_start_some_streams( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global) { - grpc_chttp2_stream_global *stream_global; - uint32_t stream_incoming_window; - /* start streams where we have free grpc_chttp2_stream ids and free - * concurrency */ - while (transport_global->next_stream_id <= MAX_CLIENT_STREAM_ID && - transport_global->concurrent_stream_count < - transport_global - ->settings[GRPC_PEER_SETTINGS] - [GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS] && - grpc_chttp2_list_pop_waiting_for_concurrency(transport_global, - &stream_global)) { - /* safe since we can't (legally) be parsing this stream yet */ - grpc_chttp2_stream_parsing *stream_parsing = - &STREAM_FROM_GLOBAL(stream_global)->parsing; - GRPC_CHTTP2_IF_TRACING(gpr_log( - GPR_DEBUG, "HTTP:%s: Allocating new grpc_chttp2_stream %p to id %d", - transport_global->is_client ? "CLI" : "SVR", stream_global, - transport_global->next_stream_id)); - - GPR_ASSERT(stream_global->id == 0); - stream_global->id = stream_parsing->id = transport_global->next_stream_id; - transport_global->next_stream_id += 2; - - if (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID) { - connectivity_state_set(exec_ctx, transport_global, - GRPC_CHANNEL_TRANSIENT_FAILURE, - "no_more_stream_ids"); - } - - stream_global->outgoing_window = - transport_global->settings[GRPC_PEER_SETTINGS] - [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; - stream_parsing->incoming_window = stream_incoming_window = - transport_global->settings[GRPC_SENT_SETTINGS] - [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; - stream_global->max_recv_bytes = - GPR_MAX(stream_incoming_window, stream_global->max_recv_bytes); - grpc_chttp2_stream_map_add( - &TRANSPORT_FROM_GLOBAL(transport_global)->new_stream_map, - stream_global->id, STREAM_FROM_GLOBAL(stream_global)); - stream_global->in_stream_map = 1; - transport_global->concurrent_stream_count++; - grpc_chttp2_become_writable(transport_global, stream_global); - } - /* cancel out streams that will never be started */ - while (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID && - grpc_chttp2_list_pop_waiting_for_concurrency(transport_global, - &stream_global)) { - cancel_from_api(exec_ctx, transport_global, stream_global, - GRPC_STATUS_UNAVAILABLE); - } -} - -static grpc_closure *add_closure_barrier(grpc_closure *closure) { - closure->final_data += 2; - return closure; -} - -void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx, - grpc_closure **pclosure, int success) { - grpc_closure *closure = *pclosure; - if (closure == NULL) { - return; - } - closure->final_data -= 2; - if (!success) { - closure->final_data |= 1; - } - if (closure->final_data < 2) { - grpc_exec_ctx_enqueue(exec_ctx, closure, closure->final_data == 0, NULL); - } - *pclosure = NULL; -} - -static int contains_non_ok_status( - grpc_chttp2_transport_global *transport_global, - grpc_metadata_batch *batch) { - grpc_linked_mdelem *l; - for (l = batch->list.head; l; l = l->next) { - if (l->md->key == GRPC_MDSTR_GRPC_STATUS && - l->md != GRPC_MDELEM_GRPC_STATUS_0) { - return 1; - } - } - return 0; -} - -static void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, bool success) {} - -static void perform_stream_op_locked( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global, grpc_transport_stream_op *op) { - grpc_closure *on_complete; - - GPR_TIMER_BEGIN("perform_stream_op_locked", 0); - - on_complete = op->on_complete; - if (on_complete == NULL) { - on_complete = grpc_closure_create(do_nothing, NULL); - } - /* use final_data as a barrier until enqueue time; the inital counter is - dropped at the end of this function */ - on_complete->final_data = 2; - - if (op->cancel_with_status != GRPC_STATUS_OK) { - cancel_from_api(exec_ctx, transport_global, stream_global, - op->cancel_with_status); - } - - if (op->close_with_status != GRPC_STATUS_OK) { - close_from_api(exec_ctx, transport_global, stream_global, - op->close_with_status, op->optional_close_message); - } - - if (op->send_initial_metadata != NULL) { - GPR_ASSERT(stream_global->send_initial_metadata_finished == NULL); - stream_global->send_initial_metadata_finished = - add_closure_barrier(on_complete); - stream_global->send_initial_metadata = op->send_initial_metadata; - if (contains_non_ok_status(transport_global, op->send_initial_metadata)) { - stream_global->seen_error = 1; - grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); - } - if (!stream_global->write_closed) { - if (transport_global->is_client) { - GPR_ASSERT(stream_global->id == 0); - grpc_chttp2_list_add_waiting_for_concurrency(transport_global, - stream_global); - maybe_start_some_streams(exec_ctx, transport_global); - } else { - GPR_ASSERT(stream_global->id != 0); - grpc_chttp2_become_writable(transport_global, stream_global); - } - } else { - grpc_chttp2_complete_closure_step( - exec_ctx, &stream_global->send_initial_metadata_finished, 0); - } - } - - if (op->send_message != NULL) { - GPR_ASSERT(stream_global->send_message_finished == NULL); - GPR_ASSERT(stream_global->send_message == NULL); - stream_global->send_message_finished = add_closure_barrier(on_complete); - if (stream_global->write_closed) { - grpc_chttp2_complete_closure_step( - exec_ctx, &stream_global->send_message_finished, 0); - } else { - stream_global->send_message = op->send_message; - if (stream_global->id != 0) { - grpc_chttp2_become_writable(transport_global, stream_global); - } - } - } - - if (op->send_trailing_metadata != NULL) { - GPR_ASSERT(stream_global->send_trailing_metadata_finished == NULL); - stream_global->send_trailing_metadata_finished = - add_closure_barrier(on_complete); - stream_global->send_trailing_metadata = op->send_trailing_metadata; - if (contains_non_ok_status(transport_global, op->send_trailing_metadata)) { - stream_global->seen_error = 1; - grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); - } - if (stream_global->write_closed) { - grpc_chttp2_complete_closure_step( - exec_ctx, &stream_global->send_trailing_metadata_finished, - grpc_metadata_batch_is_empty(op->send_trailing_metadata)); - } else if (stream_global->id != 0) { - /* TODO(ctiller): check if there's flow control for any outstanding - bytes before going writable */ - grpc_chttp2_become_writable(transport_global, stream_global); - } - } - - if (op->recv_initial_metadata != NULL) { - GPR_ASSERT(stream_global->recv_initial_metadata_ready == NULL); - stream_global->recv_initial_metadata_ready = - op->recv_initial_metadata_ready; - stream_global->recv_initial_metadata = op->recv_initial_metadata; - grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); - } - - if (op->recv_message != NULL) { - GPR_ASSERT(stream_global->recv_message_ready == NULL); - stream_global->recv_message_ready = op->recv_message_ready; - stream_global->recv_message = op->recv_message; - if (stream_global->id != 0 && - (stream_global->incoming_frames.head == NULL || - stream_global->incoming_frames.head->is_tail)) { - incoming_byte_stream_update_flow_control( - transport_global, stream_global, transport_global->stream_lookahead, - 0); - } - grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); - } - - if (op->recv_trailing_metadata != NULL) { - GPR_ASSERT(stream_global->recv_trailing_metadata_finished == NULL); - stream_global->recv_trailing_metadata_finished = - add_closure_barrier(on_complete); - stream_global->recv_trailing_metadata = op->recv_trailing_metadata; - grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); - } - - grpc_chttp2_complete_closure_step(exec_ctx, &on_complete, 1); - - GPR_TIMER_END("perform_stream_op_locked", 0); -} - -static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt, - grpc_stream *gs, grpc_transport_stream_op *op) { - grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; - grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs; - - lock(t); - perform_stream_op_locked(exec_ctx, &t->global, &s->global, op); - unlock(exec_ctx, t); -} - -static void send_ping_locked(grpc_chttp2_transport *t, grpc_closure *on_recv) { - grpc_chttp2_outstanding_ping *p = gpr_malloc(sizeof(*p)); - p->next = &t->global.pings; - p->prev = p->next->prev; - p->prev->next = p->next->prev = p; - p->id[0] = (uint8_t)((t->global.ping_counter >> 56) & 0xff); - p->id[1] = (uint8_t)((t->global.ping_counter >> 48) & 0xff); - p->id[2] = (uint8_t)((t->global.ping_counter >> 40) & 0xff); - p->id[3] = (uint8_t)((t->global.ping_counter >> 32) & 0xff); - p->id[4] = (uint8_t)((t->global.ping_counter >> 24) & 0xff); - p->id[5] = (uint8_t)((t->global.ping_counter >> 16) & 0xff); - p->id[6] = (uint8_t)((t->global.ping_counter >> 8) & 0xff); - p->id[7] = (uint8_t)(t->global.ping_counter & 0xff); - p->on_recv = on_recv; - gpr_slice_buffer_add(&t->global.qbuf, grpc_chttp2_ping_create(0, p->id)); -} - -void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_parsing *transport_parsing, - const uint8_t *opaque_8bytes) { - grpc_chttp2_outstanding_ping *ping; - grpc_chttp2_transport *t = TRANSPORT_FROM_PARSING(transport_parsing); - grpc_chttp2_transport_global *transport_global = &t->global; - lock(t); - for (ping = transport_global->pings.next; ping != &transport_global->pings; - ping = ping->next) { - if (0 == memcmp(opaque_8bytes, ping->id, 8)) { - grpc_exec_ctx_enqueue(exec_ctx, ping->on_recv, true, NULL); - ping->next->prev = ping->prev; - ping->prev->next = ping->next; - gpr_free(ping); - break; - } - } - unlock(exec_ctx, t); -} - -static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t, - grpc_transport_op *op) { - bool close_transport = false; - - grpc_exec_ctx_enqueue(exec_ctx, op->on_consumed, true, NULL); - - if (op->on_connectivity_state_change != NULL) { - grpc_connectivity_state_notify_on_state_change( - exec_ctx, &t->channel_callback.state_tracker, op->connectivity_state, - op->on_connectivity_state_change); - } - - if (op->send_goaway) { - t->global.sent_goaway = 1; - grpc_chttp2_goaway_append( - t->global.last_incoming_stream_id, - (uint32_t)grpc_chttp2_grpc_status_to_http2_error(op->goaway_status), - gpr_slice_ref(*op->goaway_message), &t->global.qbuf); - close_transport = !grpc_chttp2_has_streams(t); - } - - if (op->set_accept_stream) { - t->channel_callback.accept_stream = op->set_accept_stream_fn; - t->channel_callback.accept_stream_user_data = - op->set_accept_stream_user_data; - } - - if (op->bind_pollset) { - add_to_pollset_locked(exec_ctx, t, op->bind_pollset); - } - - if (op->bind_pollset_set) { - add_to_pollset_set_locked(exec_ctx, t, op->bind_pollset_set); - } - - if (op->send_ping) { - send_ping_locked(t, op->send_ping); - } - - if (op->disconnect) { - close_transport_locked(exec_ctx, t); - } - - if (close_transport) { - close_transport_locked(exec_ctx, t); - } -} - -static void perform_transport_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt, - grpc_transport_op *op) { - grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; - - lock(t); - - /* If there's a set_accept_stream ensure that we're not parsing - to avoid changing things out from underneath */ - if (t->parsing_active && op->set_accept_stream) { - GPR_ASSERT(t->post_parsing_op == NULL); - t->post_parsing_op = gpr_malloc(sizeof(*op)); - memcpy(t->post_parsing_op, op, sizeof(*op)); - } else { - perform_transport_op_locked(exec_ctx, t, op); - } - - unlock(exec_ctx, t); -} - -/******************************************************************************* - * INPUT PROCESSING - */ - -static void check_read_ops(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_global *transport_global) { - grpc_chttp2_stream_global *stream_global; - grpc_byte_stream *bs; - while ( - grpc_chttp2_list_pop_check_read_ops(transport_global, &stream_global)) { - if (stream_global->recv_initial_metadata_ready != NULL && - stream_global->published_initial_metadata) { - grpc_chttp2_incoming_metadata_buffer_publish( - &stream_global->received_initial_metadata, - stream_global->recv_initial_metadata); - grpc_exec_ctx_enqueue( - exec_ctx, stream_global->recv_initial_metadata_ready, true, NULL); - stream_global->recv_initial_metadata_ready = NULL; - } - if (stream_global->recv_message_ready != NULL) { - while (stream_global->seen_error && - (bs = grpc_chttp2_incoming_frame_queue_pop( - &stream_global->incoming_frames)) != NULL) { - grpc_byte_stream_destroy(exec_ctx, bs); - } - if (stream_global->incoming_frames.head != NULL) { - *stream_global->recv_message = grpc_chttp2_incoming_frame_queue_pop( - &stream_global->incoming_frames); - GPR_ASSERT(*stream_global->recv_message != NULL); - grpc_exec_ctx_enqueue(exec_ctx, stream_global->recv_message_ready, true, - NULL); - stream_global->recv_message_ready = NULL; - } else if (stream_global->published_trailing_metadata) { - *stream_global->recv_message = NULL; - grpc_exec_ctx_enqueue(exec_ctx, stream_global->recv_message_ready, true, - NULL); - stream_global->recv_message_ready = NULL; - } - } - if (stream_global->recv_trailing_metadata_finished != NULL && - stream_global->read_closed && stream_global->write_closed) { - while (stream_global->seen_error && - (bs = grpc_chttp2_incoming_frame_queue_pop( - &stream_global->incoming_frames)) != NULL) { - grpc_byte_stream_destroy(exec_ctx, bs); - } - if (stream_global->incoming_frames.head == NULL) { - grpc_chttp2_incoming_metadata_buffer_publish( - &stream_global->received_trailing_metadata, - stream_global->recv_trailing_metadata); - grpc_chttp2_complete_closure_step( - exec_ctx, &stream_global->recv_trailing_metadata_finished, 1); - } - } - } -} - -static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, - uint32_t id) { - size_t new_stream_count; - grpc_chttp2_stream *s = - grpc_chttp2_stream_map_delete(&t->parsing_stream_map, id); - if (!s) { - s = grpc_chttp2_stream_map_delete(&t->new_stream_map, id); - } - GPR_ASSERT(s); - s->global.in_stream_map = 0; - if (t->parsing.incoming_stream == &s->parsing) { - t->parsing.incoming_stream = NULL; - grpc_chttp2_parsing_become_skip_parser(exec_ctx, &t->parsing); - } - if (s->parsing.data_parser.parsing_frame != NULL) { - grpc_chttp2_incoming_byte_stream_finished( - exec_ctx, s->parsing.data_parser.parsing_frame, 0, 0); - s->parsing.data_parser.parsing_frame = NULL; - } - - if (grpc_chttp2_unregister_stream(t, s) && t->global.sent_goaway) { - close_transport_locked(exec_ctx, t); - } - if (grpc_chttp2_list_remove_writable_stream(&t->global, &s->global)) { - GRPC_CHTTP2_STREAM_UNREF(exec_ctx, &s->global, "chttp2_writing"); - } - - new_stream_count = grpc_chttp2_stream_map_size(&t->parsing_stream_map) + - grpc_chttp2_stream_map_size(&t->new_stream_map); - GPR_ASSERT(new_stream_count <= UINT32_MAX); - if (new_stream_count != t->global.concurrent_stream_count) { - t->global.concurrent_stream_count = (uint32_t)new_stream_count; - maybe_start_some_streams(exec_ctx, &t->global); - } -} - -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) { - if (stream_global->id != 0) { - gpr_slice_buffer_add( - &transport_global->qbuf, - grpc_chttp2_rst_stream_create( - stream_global->id, - (uint32_t)grpc_chttp2_grpc_status_to_http2_error(status))); - } - grpc_chttp2_fake_status(exec_ctx, transport_global, stream_global, status, - NULL); - grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, 1, - 1); -} - -void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global, - grpc_status_code status, gpr_slice *slice) { - if (status != GRPC_STATUS_OK) { - stream_global->seen_error = 1; - grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); - } - /* stream_global->recv_trailing_metadata_finished gives us a - last chance replacement: we've received trailing metadata, - but something more important has become available to signal - to the upper layers - drop what we've got, and then publish - what we want - which is safe because we haven't told anyone - about the metadata yet */ - if (!stream_global->published_trailing_metadata || - stream_global->recv_trailing_metadata_finished != NULL) { - char status_string[GPR_LTOA_MIN_BUFSIZE]; - gpr_ltoa(status, status_string); - grpc_chttp2_incoming_metadata_buffer_add( - &stream_global->received_trailing_metadata, - grpc_mdelem_from_metadata_strings( - GRPC_MDSTR_GRPC_STATUS, grpc_mdstr_from_string(status_string))); - if (slice) { - grpc_chttp2_incoming_metadata_buffer_add( - &stream_global->received_trailing_metadata, - grpc_mdelem_from_metadata_strings( - GRPC_MDSTR_GRPC_MESSAGE, - grpc_mdstr_from_slice(gpr_slice_ref(*slice)))); - } - stream_global->published_trailing_metadata = 1; - grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); - } - if (slice) { - gpr_slice_unref(*slice); - } -} - -static void fail_pending_writes(grpc_exec_ctx *exec_ctx, - grpc_chttp2_stream_global *stream_global) { - grpc_chttp2_complete_closure_step( - exec_ctx, &stream_global->send_initial_metadata_finished, 0); - grpc_chttp2_complete_closure_step( - exec_ctx, &stream_global->send_trailing_metadata_finished, 0); - grpc_chttp2_complete_closure_step(exec_ctx, - &stream_global->send_message_finished, 0); -} - -void grpc_chttp2_mark_stream_closed( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global, int close_reads, - int close_writes) { - if (stream_global->read_closed && stream_global->write_closed) { - /* already closed */ - return; - } - grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); - if (close_reads && !stream_global->read_closed) { - stream_global->read_closed = 1; - stream_global->published_initial_metadata = 1; - stream_global->published_trailing_metadata = 1; - } - if (close_writes && !stream_global->write_closed) { - stream_global->write_closed = 1; - if (TRANSPORT_FROM_GLOBAL(transport_global)->writing_active) { - GRPC_CHTTP2_STREAM_REF(stream_global, "finish_writes"); - grpc_chttp2_list_add_closed_waiting_for_writing(transport_global, - stream_global); - } else { - fail_pending_writes(exec_ctx, stream_global); - } - } - if (stream_global->read_closed && stream_global->write_closed) { - if (stream_global->id != 0 && - TRANSPORT_FROM_GLOBAL(transport_global)->parsing_active) { - grpc_chttp2_list_add_closed_waiting_for_parsing(transport_global, - stream_global); - } else { - if (stream_global->id != 0) { - remove_stream(exec_ctx, TRANSPORT_FROM_GLOBAL(transport_global), - stream_global->id); - } - GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2"); - } - } -} - -static void close_from_api(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global, - grpc_status_code status, - gpr_slice *optional_message) { - gpr_slice hdr; - gpr_slice status_hdr; - gpr_slice message_pfx; - uint8_t *p; - uint32_t len = 0; - - GPR_ASSERT(status >= 0 && (int)status < 100); - - GPR_ASSERT(stream_global->id != 0); - - /* Hand roll a header block. - This is unnecessarily ugly - at some point we should find a more elegant - solution. - It's complicated by the fact that our send machinery would be dead by the - time we got around to sending this, so instead we ignore HPACK compression - and just write the uncompressed bytes onto the wire. */ - status_hdr = gpr_slice_malloc(15 + (status >= 10)); - p = GPR_SLICE_START_PTR(status_hdr); - *p++ = 0x40; /* literal header */ - *p++ = 11; /* len(grpc-status) */ - *p++ = 'g'; - *p++ = 'r'; - *p++ = 'p'; - *p++ = 'c'; - *p++ = '-'; - *p++ = 's'; - *p++ = 't'; - *p++ = 'a'; - *p++ = 't'; - *p++ = 'u'; - *p++ = 's'; - if (status < 10) { - *p++ = 1; - *p++ = (uint8_t)('0' + status); - } else { - *p++ = 2; - *p++ = (uint8_t)('0' + (status / 10)); - *p++ = (uint8_t)('0' + (status % 10)); - } - GPR_ASSERT(p == GPR_SLICE_END_PTR(status_hdr)); - len += (uint32_t)GPR_SLICE_LENGTH(status_hdr); - - if (optional_message) { - GPR_ASSERT(GPR_SLICE_LENGTH(*optional_message) < 127); - message_pfx = gpr_slice_malloc(15); - p = GPR_SLICE_START_PTR(message_pfx); - *p++ = 0x40; - *p++ = 12; /* len(grpc-message) */ - *p++ = 'g'; - *p++ = 'r'; - *p++ = 'p'; - *p++ = 'c'; - *p++ = '-'; - *p++ = 'm'; - *p++ = 'e'; - *p++ = 's'; - *p++ = 's'; - *p++ = 'a'; - *p++ = 'g'; - *p++ = 'e'; - *p++ = (uint8_t)GPR_SLICE_LENGTH(*optional_message); - GPR_ASSERT(p == GPR_SLICE_END_PTR(message_pfx)); - len += (uint32_t)GPR_SLICE_LENGTH(message_pfx); - len += (uint32_t)GPR_SLICE_LENGTH(*optional_message); - } - - hdr = gpr_slice_malloc(9); - p = GPR_SLICE_START_PTR(hdr); - *p++ = (uint8_t)(len >> 16); - *p++ = (uint8_t)(len >> 8); - *p++ = (uint8_t)(len); - *p++ = GRPC_CHTTP2_FRAME_HEADER; - *p++ = GRPC_CHTTP2_DATA_FLAG_END_STREAM | GRPC_CHTTP2_DATA_FLAG_END_HEADERS; - *p++ = (uint8_t)(stream_global->id >> 24); - *p++ = (uint8_t)(stream_global->id >> 16); - *p++ = (uint8_t)(stream_global->id >> 8); - *p++ = (uint8_t)(stream_global->id); - GPR_ASSERT(p == GPR_SLICE_END_PTR(hdr)); - - gpr_slice_buffer_add(&transport_global->qbuf, hdr); - gpr_slice_buffer_add(&transport_global->qbuf, status_hdr); - if (optional_message) { - gpr_slice_buffer_add(&transport_global->qbuf, message_pfx); - gpr_slice_buffer_add(&transport_global->qbuf, - gpr_slice_ref(*optional_message)); - } - - gpr_slice_buffer_add( - &transport_global->qbuf, - grpc_chttp2_rst_stream_create(stream_global->id, GRPC_CHTTP2_NO_ERROR)); - - if (optional_message) { - gpr_slice_ref(*optional_message); - } - grpc_chttp2_fake_status(exec_ctx, transport_global, stream_global, status, - optional_message); - grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, 1, - 1); -} - -static void cancel_stream_cb(grpc_chttp2_transport_global *transport_global, - void *user_data, - grpc_chttp2_stream_global *stream_global) { - cancel_from_api(user_data, transport_global, stream_global, - GRPC_STATUS_UNAVAILABLE); -} - -static void end_all_the_calls(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t) { - grpc_chttp2_for_all_streams(&t->global, exec_ctx, cancel_stream_cb); -} - -static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) { - close_transport_locked(exec_ctx, t); - end_all_the_calls(exec_ctx, t); -} - -/** update window from a settings change */ -static void update_global_window(void *args, uint32_t id, void *stream) { - grpc_chttp2_transport *t = args; - grpc_chttp2_stream *s = stream; - grpc_chttp2_transport_global *transport_global = &t->global; - grpc_chttp2_stream_global *stream_global = &s->global; - int was_zero; - int is_zero; - int64_t initial_window_update = t->parsing.initial_window_update; - - was_zero = stream_global->outgoing_window <= 0; - GRPC_CHTTP2_FLOW_CREDIT_STREAM("settings", transport_global, stream_global, - outgoing_window, initial_window_update); - is_zero = stream_global->outgoing_window <= 0; - - if (was_zero && !is_zero) { - grpc_chttp2_become_writable(transport_global, stream_global); - } -} - -static void read_error_locked(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t) { - t->endpoint_reading = 0; - if (!t->writing_active && t->ep) { - destroy_endpoint(exec_ctx, t); - } -} - -/* tcp read callback */ -static void recv_data(grpc_exec_ctx *exec_ctx, void *tp, bool success) { - size_t i; - int keep_reading = 0; - grpc_chttp2_transport *t = tp; - grpc_chttp2_transport_global *transport_global = &t->global; - grpc_chttp2_transport_parsing *transport_parsing = &t->parsing; - grpc_chttp2_stream_global *stream_global; - - GPR_TIMER_BEGIN("recv_data", 0); - - lock(t); - i = 0; - GPR_ASSERT(!t->parsing_active); - if (!t->closed) { - t->parsing_active = 1; - /* merge stream lists */ - grpc_chttp2_stream_map_move_into(&t->new_stream_map, - &t->parsing_stream_map); - grpc_chttp2_prepare_to_read(transport_global, transport_parsing); - gpr_mu_unlock(&t->mu); - GPR_TIMER_BEGIN("recv_data.parse", 0); - for (; i < t->read_buffer.count && - grpc_chttp2_perform_read(exec_ctx, transport_parsing, - t->read_buffer.slices[i]); - i++) - ; - GPR_TIMER_END("recv_data.parse", 0); - gpr_mu_lock(&t->mu); - /* copy parsing qbuf to global qbuf */ - gpr_slice_buffer_move_into(&t->parsing.qbuf, &t->global.qbuf); - if (i != t->read_buffer.count) { - unlock(exec_ctx, t); - lock(t); - drop_connection(exec_ctx, t); - } - /* merge stream lists */ - grpc_chttp2_stream_map_move_into(&t->new_stream_map, - &t->parsing_stream_map); - transport_global->concurrent_stream_count = - (uint32_t)grpc_chttp2_stream_map_size(&t->parsing_stream_map); - if (transport_parsing->initial_window_update != 0) { - grpc_chttp2_stream_map_for_each(&t->parsing_stream_map, - update_global_window, t); - transport_parsing->initial_window_update = 0; - } - /* handle higher level things */ - grpc_chttp2_publish_reads(exec_ctx, transport_global, transport_parsing); - t->parsing_active = 0; - /* handle delayed transport ops (if there is one) */ - if (t->post_parsing_op) { - grpc_transport_op *op = t->post_parsing_op; - t->post_parsing_op = NULL; - perform_transport_op_locked(exec_ctx, t, op); - gpr_free(op); - } - /* if a stream is in the stream map, and gets cancelled, we need to ensure - * we are not parsing before continuing the cancellation to keep things in - * a sane state */ - while (grpc_chttp2_list_pop_closed_waiting_for_parsing(transport_global, - &stream_global)) { - GPR_ASSERT(stream_global->in_stream_map); - GPR_ASSERT(stream_global->write_closed); - GPR_ASSERT(stream_global->read_closed); - remove_stream(exec_ctx, t, stream_global->id); - GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2"); - } - } - if (!success || i != t->read_buffer.count || t->closed) { - drop_connection(exec_ctx, t); - read_error_locked(exec_ctx, t); - } else if (!t->closed) { - keep_reading = 1; - REF_TRANSPORT(t, "keep_reading"); - prevent_endpoint_shutdown(t); - } - gpr_slice_buffer_reset_and_unref(&t->read_buffer); - unlock(exec_ctx, t); - - if (keep_reading) { - grpc_endpoint_read(exec_ctx, t->ep, &t->read_buffer, &t->recv_data); - allow_endpoint_shutdown_unlocked(exec_ctx, t); - UNREF_TRANSPORT(exec_ctx, t, "keep_reading"); - } else { - UNREF_TRANSPORT(exec_ctx, t, "recv_data"); - } - - GPR_TIMER_END("recv_data", 0); -} - -/******************************************************************************* - * CALLBACK LOOP - */ - -static void connectivity_state_set( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, - grpc_connectivity_state state, const char *reason) { - GRPC_CHTTP2_IF_TRACING( - gpr_log(GPR_DEBUG, "set connectivity_state=%d", state)); - grpc_connectivity_state_set( - exec_ctx, - &TRANSPORT_FROM_GLOBAL(transport_global)->channel_callback.state_tracker, - state, reason); -} - -/******************************************************************************* - * POLLSET STUFF - */ - -static void add_to_pollset_locked(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t, - grpc_pollset *pollset) { - if (t->ep) { - grpc_endpoint_add_to_pollset(exec_ctx, t->ep, pollset); - } -} - -static void add_to_pollset_set_locked(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t, - grpc_pollset_set *pollset_set) { - if (t->ep) { - grpc_endpoint_add_to_pollset_set(exec_ctx, t->ep, pollset_set); - } -} - -static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_transport *gt, - grpc_stream *gs, grpc_pollset *pollset) { - grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; - lock(t); - add_to_pollset_locked(exec_ctx, t, pollset); - unlock(exec_ctx, t); -} - -/******************************************************************************* - * BYTE STREAM - */ - -static void incoming_byte_stream_update_flow_control( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global, size_t max_size_hint, - size_t have_already) { - uint32_t max_recv_bytes; - - /* clamp max recv hint to an allowable size */ - if (max_size_hint >= UINT32_MAX - transport_global->stream_lookahead) { - max_recv_bytes = UINT32_MAX - transport_global->stream_lookahead; - } else { - max_recv_bytes = (uint32_t)max_size_hint; - } - - /* account for bytes already received but unknown to higher layers */ - if (max_recv_bytes >= have_already) { - max_recv_bytes -= (uint32_t)have_already; - } else { - max_recv_bytes = 0; - } - - /* add some small lookahead to keep pipelines flowing */ - GPR_ASSERT(max_recv_bytes <= UINT32_MAX - transport_global->stream_lookahead); - max_recv_bytes += transport_global->stream_lookahead; - if (stream_global->max_recv_bytes < max_recv_bytes) { - uint32_t add_max_recv_bytes = - max_recv_bytes - stream_global->max_recv_bytes; - GRPC_CHTTP2_FLOW_CREDIT_STREAM("op", transport_global, stream_global, - max_recv_bytes, add_max_recv_bytes); - GRPC_CHTTP2_FLOW_CREDIT_STREAM("op", transport_global, stream_global, - unannounced_incoming_window_for_parse, - add_max_recv_bytes); - GRPC_CHTTP2_FLOW_CREDIT_STREAM("op", transport_global, stream_global, - unannounced_incoming_window_for_writing, - add_max_recv_bytes); - grpc_chttp2_list_add_unannounced_incoming_window_available(transport_global, - stream_global); - grpc_chttp2_become_writable(transport_global, stream_global); - } -} - -static int incoming_byte_stream_next(grpc_exec_ctx *exec_ctx, - grpc_byte_stream *byte_stream, - gpr_slice *slice, size_t max_size_hint, - grpc_closure *on_complete) { - grpc_chttp2_incoming_byte_stream *bs = - (grpc_chttp2_incoming_byte_stream *)byte_stream; - grpc_chttp2_transport_global *transport_global = &bs->transport->global; - grpc_chttp2_stream_global *stream_global = &bs->stream->global; - - lock(bs->transport); - if (bs->is_tail) { - incoming_byte_stream_update_flow_control(transport_global, stream_global, - max_size_hint, bs->slices.length); - } - if (bs->slices.count > 0) { - *slice = gpr_slice_buffer_take_first(&bs->slices); - unlock(exec_ctx, bs->transport); - return 1; - } else if (bs->failed) { - grpc_exec_ctx_enqueue(exec_ctx, on_complete, false, NULL); - unlock(exec_ctx, bs->transport); - return 0; - } else { - bs->on_next = on_complete; - bs->next = slice; - unlock(exec_ctx, bs->transport); - return 0; - } -} - -static void incoming_byte_stream_unref(grpc_chttp2_incoming_byte_stream *bs) { - if (gpr_unref(&bs->refs)) { - gpr_slice_buffer_destroy(&bs->slices); - gpr_free(bs); - } -} - -static void incoming_byte_stream_destroy(grpc_exec_ctx *exec_ctx, - grpc_byte_stream *byte_stream) { - incoming_byte_stream_unref((grpc_chttp2_incoming_byte_stream *)byte_stream); -} - -void grpc_chttp2_incoming_byte_stream_push(grpc_exec_ctx *exec_ctx, - grpc_chttp2_incoming_byte_stream *bs, - gpr_slice slice) { - gpr_mu_lock(&bs->transport->mu); - if (bs->on_next != NULL) { - *bs->next = slice; - grpc_exec_ctx_enqueue(exec_ctx, bs->on_next, true, NULL); - bs->on_next = NULL; - } else { - gpr_slice_buffer_add(&bs->slices, slice); - } - gpr_mu_unlock(&bs->transport->mu); -} - -void grpc_chttp2_incoming_byte_stream_finished( - grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs, int success, - int from_parsing_thread) { - if (!success) { - if (from_parsing_thread) { - gpr_mu_lock(&bs->transport->mu); - } - grpc_exec_ctx_enqueue(exec_ctx, bs->on_next, false, NULL); - bs->on_next = NULL; - bs->failed = 1; - if (from_parsing_thread) { - gpr_mu_unlock(&bs->transport->mu); - } - } else { -#ifndef NDEBUG - if (from_parsing_thread) { - gpr_mu_lock(&bs->transport->mu); - } - GPR_ASSERT(bs->on_next == NULL); - if (from_parsing_thread) { - gpr_mu_unlock(&bs->transport->mu); - } -#endif - } - incoming_byte_stream_unref(bs); -} - -grpc_chttp2_incoming_byte_stream *grpc_chttp2_incoming_byte_stream_create( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing, uint32_t frame_size, - uint32_t flags, grpc_chttp2_incoming_frame_queue *add_to_queue) { - grpc_chttp2_incoming_byte_stream *incoming_byte_stream = - gpr_malloc(sizeof(*incoming_byte_stream)); - incoming_byte_stream->base.length = frame_size; - incoming_byte_stream->base.flags = flags; - incoming_byte_stream->base.next = incoming_byte_stream_next; - incoming_byte_stream->base.destroy = incoming_byte_stream_destroy; - gpr_ref_init(&incoming_byte_stream->refs, 2); - incoming_byte_stream->next_message = NULL; - incoming_byte_stream->transport = TRANSPORT_FROM_PARSING(transport_parsing); - incoming_byte_stream->stream = STREAM_FROM_PARSING(stream_parsing); - gpr_slice_buffer_init(&incoming_byte_stream->slices); - incoming_byte_stream->on_next = NULL; - incoming_byte_stream->is_tail = 1; - incoming_byte_stream->failed = 0; - if (add_to_queue->head == NULL) { - add_to_queue->head = incoming_byte_stream; - } else { - add_to_queue->tail->is_tail = 0; - add_to_queue->tail->next_message = incoming_byte_stream; - } - add_to_queue->tail = incoming_byte_stream; - return incoming_byte_stream; -} - -/******************************************************************************* - * TRACING - */ - -static char *format_flowctl_context_var(const char *context, const char *var, - int64_t val, uint32_t id, - char **scope) { - char *underscore_pos; - char *result; - if (context == NULL) { - *scope = NULL; - gpr_asprintf(&result, "%s(%lld)", var, val); - return result; - } - underscore_pos = strchr(context, '_'); - *scope = gpr_strdup(context); - (*scope)[underscore_pos - context] = 0; - if (id != 0) { - char *tmp = *scope; - gpr_asprintf(scope, "%s[%d]", tmp, id); - gpr_free(tmp); - } - gpr_asprintf(&result, "%s.%s(%lld)", underscore_pos + 1, var, val); - return result; -} - -static int samestr(char *a, char *b) { - if (a == NULL) { - return b == NULL; - } - if (b == NULL) { - return 0; - } - return 0 == strcmp(a, b); -} - -void grpc_chttp2_flowctl_trace(const char *file, int line, const char *phase, - grpc_chttp2_flowctl_op op, const char *context1, - const char *var1, const char *context2, - const char *var2, int is_client, - uint32_t stream_id, int64_t val1, int64_t val2) { - char *scope1; - char *scope2; - char *label1 = - format_flowctl_context_var(context1, var1, val1, stream_id, &scope1); - char *label2 = - format_flowctl_context_var(context2, var2, val2, stream_id, &scope2); - char *clisvr = is_client ? "client" : "server"; - char *prefix; - - gpr_asprintf(&prefix, "FLOW % 8s: %s % 11s ", phase, clisvr, 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, - val1 + val2); - } - break; - case GRPC_CHTTP2_FLOWCTL_CREDIT: - GPR_ASSERT(val2 >= 0); - if (val2 != 0) { - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, - "%sCREDIT % 40s by % 40s giving %d", prefix, label1, label2, - val1 + val2); - } - break; - case GRPC_CHTTP2_FLOWCTL_DEBIT: - GPR_ASSERT(val2 >= 0); - if (val2 != 0) { - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, - "%sDEBIT % 40s by % 40s giving %d", prefix, label1, label2, - val1 - val2); - } - break; - } - - gpr_free(scope1); - gpr_free(scope2); - gpr_free(label1); - gpr_free(label2); - gpr_free(prefix); -} - -/******************************************************************************* - * INTEGRATION GLUE - */ - -static char *chttp2_get_peer(grpc_exec_ctx *exec_ctx, grpc_transport *t) { - return gpr_strdup(((grpc_chttp2_transport *)t)->peer_string); -} - -static const grpc_transport_vtable vtable = {sizeof(grpc_chttp2_stream), - "chttp2", - init_stream, - set_pollset, - perform_stream_op, - perform_transport_op, - destroy_stream, - destroy_transport, - chttp2_get_peer}; - -grpc_transport *grpc_create_chttp2_transport( - grpc_exec_ctx *exec_ctx, const grpc_channel_args *channel_args, - grpc_endpoint *ep, int is_client) { - grpc_chttp2_transport *t = gpr_malloc(sizeof(grpc_chttp2_transport)); - init_transport(exec_ctx, t, channel_args, ep, is_client != 0); - return &t->base; -} - -void grpc_chttp2_transport_start_reading(grpc_exec_ctx *exec_ctx, - grpc_transport *transport, - gpr_slice *slices, size_t nslices) { - grpc_chttp2_transport *t = (grpc_chttp2_transport *)transport; - REF_TRANSPORT(t, "recv_data"); /* matches unref inside recv_data */ - gpr_slice_buffer_addn(&t->read_buffer, slices, nslices); - recv_data(exec_ctx, t, 1); -} diff --git a/src/core/transport/chttp2_transport.h b/src/core/transport/chttp2_transport.h deleted file mode 100644 index 9a6cf0ed35..0000000000 --- a/src/core/transport/chttp2_transport.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * - * Copyright 2015-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_TRANSPORT_CHTTP2_TRANSPORT_H -#define GRPC_CORE_TRANSPORT_CHTTP2_TRANSPORT_H - -#include "src/core/iomgr/endpoint.h" -#include "src/core/transport/transport.h" - -extern int grpc_http_trace; -extern int grpc_flowctl_trace; - -grpc_transport *grpc_create_chttp2_transport( - grpc_exec_ctx *exec_ctx, const grpc_channel_args *channel_args, - grpc_endpoint *ep, int is_client); - -void grpc_chttp2_transport_start_reading(grpc_exec_ctx *exec_ctx, - grpc_transport *transport, - gpr_slice *slices, size_t nslices); - -#endif /* GRPC_CORE_TRANSPORT_CHTTP2_TRANSPORT_H */ diff --git a/src/core/transport/connectivity_state.c b/src/core/transport/connectivity_state.c deleted file mode 100644 index 87765b9799..0000000000 --- a/src/core/transport/connectivity_state.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * - * Copyright 2015-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/transport/connectivity_state.h" - -#include - -#include -#include -#include - -int grpc_connectivity_state_trace = 0; - -const char *grpc_connectivity_state_name(grpc_connectivity_state state) { - switch (state) { - case GRPC_CHANNEL_IDLE: - return "IDLE"; - case GRPC_CHANNEL_CONNECTING: - return "CONNECTING"; - case GRPC_CHANNEL_READY: - return "READY"; - case GRPC_CHANNEL_TRANSIENT_FAILURE: - return "TRANSIENT_FAILURE"; - case GRPC_CHANNEL_FATAL_FAILURE: - return "FATAL_FAILURE"; - } - GPR_UNREACHABLE_CODE(return "UNKNOWN"); -} - -void grpc_connectivity_state_init(grpc_connectivity_state_tracker *tracker, - grpc_connectivity_state init_state, - const char *name) { - tracker->current_state = init_state; - tracker->watchers = NULL; - tracker->name = gpr_strdup(name); -} - -void grpc_connectivity_state_destroy(grpc_exec_ctx *exec_ctx, - grpc_connectivity_state_tracker *tracker) { - int success; - grpc_connectivity_state_watcher *w; - while ((w = tracker->watchers)) { - tracker->watchers = w->next; - - if (GRPC_CHANNEL_FATAL_FAILURE != *w->current) { - *w->current = GRPC_CHANNEL_FATAL_FAILURE; - success = 1; - } else { - success = 0; - } - grpc_exec_ctx_enqueue(exec_ctx, w->notify, success, NULL); - gpr_free(w); - } - gpr_free(tracker->name); -} - -grpc_connectivity_state grpc_connectivity_state_check( - grpc_connectivity_state_tracker *tracker) { - if (grpc_connectivity_state_trace) { - gpr_log(GPR_DEBUG, "CONWATCH: %p %s: get %s", tracker, tracker->name, - grpc_connectivity_state_name(tracker->current_state)); - } - return tracker->current_state; -} - -int grpc_connectivity_state_notify_on_state_change( - grpc_exec_ctx *exec_ctx, grpc_connectivity_state_tracker *tracker, - grpc_connectivity_state *current, grpc_closure *notify) { - if (grpc_connectivity_state_trace) { - if (current == NULL) { - gpr_log(GPR_DEBUG, "CONWATCH: %p %s: unsubscribe notify=%p", tracker, - tracker->name, notify); - } else { - gpr_log(GPR_DEBUG, "CONWATCH: %p %s: from %s [cur=%s] notify=%p", tracker, - tracker->name, grpc_connectivity_state_name(*current), - grpc_connectivity_state_name(tracker->current_state), notify); - } - } - if (current == NULL) { - grpc_connectivity_state_watcher *w = tracker->watchers; - if (w != NULL && w->notify == notify) { - grpc_exec_ctx_enqueue(exec_ctx, notify, false, NULL); - tracker->watchers = w->next; - gpr_free(w); - return 0; - } - while (w != NULL) { - grpc_connectivity_state_watcher *rm_candidate = w->next; - if (rm_candidate != NULL && rm_candidate->notify == notify) { - grpc_exec_ctx_enqueue(exec_ctx, notify, false, NULL); - w->next = w->next->next; - gpr_free(rm_candidate); - return 0; - } - w = w->next; - } - return 0; - } else { - if (tracker->current_state != *current) { - *current = tracker->current_state; - grpc_exec_ctx_enqueue(exec_ctx, notify, true, NULL); - } else { - grpc_connectivity_state_watcher *w = gpr_malloc(sizeof(*w)); - w->current = current; - w->notify = notify; - w->next = tracker->watchers; - tracker->watchers = w; - } - return tracker->current_state == GRPC_CHANNEL_IDLE; - } -} - -void grpc_connectivity_state_set(grpc_exec_ctx *exec_ctx, - grpc_connectivity_state_tracker *tracker, - grpc_connectivity_state state, - const char *reason) { - grpc_connectivity_state_watcher *w; - if (grpc_connectivity_state_trace) { - gpr_log(GPR_DEBUG, "SET: %p %s: %s --> %s [%s]", tracker, 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) != NULL) { - *w->current = tracker->current_state; - tracker->watchers = w->next; - grpc_exec_ctx_enqueue(exec_ctx, w->notify, true, NULL); - gpr_free(w); - } -} diff --git a/src/core/transport/connectivity_state.h b/src/core/transport/connectivity_state.h deleted file mode 100644 index b4a3ce924d..0000000000 --- a/src/core/transport/connectivity_state.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * - * Copyright 2015-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_TRANSPORT_CONNECTIVITY_STATE_H -#define GRPC_CORE_TRANSPORT_CONNECTIVITY_STATE_H - -#include -#include "src/core/iomgr/exec_ctx.h" - -typedef struct grpc_connectivity_state_watcher { - /** we keep watchers in a linked list */ - struct grpc_connectivity_state_watcher *next; - /** closure to notify on change */ - grpc_closure *notify; - /** the current state as believed by the watcher */ - grpc_connectivity_state *current; -} grpc_connectivity_state_watcher; - -typedef struct { - /** current connectivity state */ - grpc_connectivity_state current_state; - /** all our watchers */ - grpc_connectivity_state_watcher *watchers; - /** a name to help debugging */ - char *name; -} grpc_connectivity_state_tracker; - -extern int grpc_connectivity_state_trace; - -const char *grpc_connectivity_state_name(grpc_connectivity_state state); - -void grpc_connectivity_state_init(grpc_connectivity_state_tracker *tracker, - grpc_connectivity_state init_state, - const char *name); -void grpc_connectivity_state_destroy(grpc_exec_ctx *exec_ctx, - grpc_connectivity_state_tracker *tracker); - -/** Set connectivity state; not thread safe; access must be serialized with an - * external lock */ -void grpc_connectivity_state_set(grpc_exec_ctx *exec_ctx, - grpc_connectivity_state_tracker *tracker, - grpc_connectivity_state state, - const char *reason); - -grpc_connectivity_state grpc_connectivity_state_check( - grpc_connectivity_state_tracker *tracker); - -/** Return 1 if the channel should start connecting, 0 otherwise. - If current==NULL cancel notify if it is already queued (success==0 in that - case) */ -int grpc_connectivity_state_notify_on_state_change( - grpc_exec_ctx *exec_ctx, grpc_connectivity_state_tracker *tracker, - grpc_connectivity_state *current, grpc_closure *notify); - -#endif /* GRPC_CORE_TRANSPORT_CONNECTIVITY_STATE_H */ diff --git a/src/core/transport/metadata.c b/src/core/transport/metadata.c deleted file mode 100644 index 7ed28feca8..0000000000 --- a/src/core/transport/metadata.c +++ /dev/null @@ -1,698 +0,0 @@ -/* - * - * Copyright 2015-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/transport/metadata.h" - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "src/core/iomgr/iomgr_internal.h" -#include "src/core/profiling/timers.h" -#include "src/core/support/murmur_hash.h" -#include "src/core/support/string.h" -#include "src/core/transport/chttp2/bin_encoder.h" -#include "src/core/transport/static_metadata.h" - -/* There are two kinds of mdelem and mdstr instances. - * Static instances are declared in static_metadata.{h,c} and - * are initialized by grpc_mdctx_global_init(). - * Dynamic instances are stored in hash tables on grpc_mdctx, and are backed - * by internal_string and internal_element structures. - * Internal helper functions here-in (is_mdstr_static, is_mdelem_static) are - * used to determine which kind of element a pointer refers to. - */ - -#define INITIAL_STRTAB_CAPACITY 4 -#define INITIAL_MDTAB_CAPACITY 4 - -#ifdef GRPC_METADATA_REFCOUNT_DEBUG -#define DEBUG_ARGS , const char *file, int line -#define FWD_DEBUG_ARGS , file, line -#define REF_MD_LOCKED(shard, s) ref_md_locked((shard), (s), __FILE__, __LINE__) -#else -#define DEBUG_ARGS -#define FWD_DEBUG_ARGS -#define REF_MD_LOCKED(shard, s) ref_md_locked((shard), (s)) -#endif - -#define TABLE_IDX(hash, log2_shards, capacity) \ - (((hash) >> (log2_shards)) % (capacity)) -#define SHARD_IDX(hash, log2_shards) ((hash) & ((1 << (log2_shards)) - 1)) - -typedef void (*destroy_user_data_func)(void *user_data); - -/* Shadow structure for grpc_mdstr for non-static values */ -typedef struct internal_string { - /* must be byte compatible with grpc_mdstr */ - gpr_slice slice; - uint32_t hash; - - /* private only data */ - gpr_atm refcnt; - - uint8_t has_base64_and_huffman_encoded; - gpr_slice_refcount refcount; - - gpr_slice base64_and_huffman; - - struct internal_string *bucket_next; -} internal_string; - -/* Shadow structure for grpc_mdelem for non-static elements */ -typedef struct internal_metadata { - /* must be byte compatible with grpc_mdelem */ - internal_string *key; - internal_string *value; - - /* private only data */ - gpr_atm refcnt; - - gpr_mu mu_user_data; - gpr_atm destroy_user_data; - gpr_atm user_data; - - struct internal_metadata *bucket_next; -} internal_metadata; - -typedef struct strtab_shard { - gpr_mu mu; - internal_string **strs; - size_t count; - size_t capacity; -} strtab_shard; - -typedef struct mdtab_shard { - gpr_mu mu; - internal_metadata **elems; - size_t count; - size_t capacity; - size_t free; -} mdtab_shard; - -#define LOG2_STRTAB_SHARD_COUNT 5 -#define LOG2_MDTAB_SHARD_COUNT 4 -#define STRTAB_SHARD_COUNT ((size_t)(1 << LOG2_STRTAB_SHARD_COUNT)) -#define MDTAB_SHARD_COUNT ((size_t)(1 << LOG2_MDTAB_SHARD_COUNT)) - -/* hash seed: decided at initialization time */ -static uint32_t g_hash_seed; -static int g_forced_hash_seed = 0; - -/* linearly probed hash tables for static element lookup */ -static grpc_mdstr *g_static_strtab[GRPC_STATIC_MDSTR_COUNT * 2]; -static grpc_mdelem *g_static_mdtab[GRPC_STATIC_MDELEM_COUNT * 2]; -static size_t g_static_strtab_maxprobe; -static size_t g_static_mdtab_maxprobe; - -static strtab_shard g_strtab_shard[STRTAB_SHARD_COUNT]; -static mdtab_shard g_mdtab_shard[MDTAB_SHARD_COUNT]; - -static void gc_mdtab(mdtab_shard *shard); - -void grpc_test_only_set_metadata_hash_seed(uint32_t seed) { - g_hash_seed = seed; - g_forced_hash_seed = 1; -} - -void grpc_mdctx_global_init(void) { - size_t i, j; - if (!g_forced_hash_seed) { - g_hash_seed = (uint32_t)gpr_now(GPR_CLOCK_REALTIME).tv_nsec; - } - g_static_strtab_maxprobe = 0; - g_static_mdtab_maxprobe = 0; - /* build static tables */ - memset(g_static_mdtab, 0, sizeof(g_static_mdtab)); - memset(g_static_strtab, 0, sizeof(g_static_strtab)); - for (i = 0; i < GRPC_STATIC_MDSTR_COUNT; i++) { - grpc_mdstr *elem = &grpc_static_mdstr_table[i]; - const char *str = grpc_static_metadata_strings[i]; - uint32_t hash = gpr_murmur_hash3(str, strlen(str), g_hash_seed); - *(gpr_slice *)&elem->slice = gpr_slice_from_static_string(str); - *(uint32_t *)&elem->hash = hash; - for (j = 0;; j++) { - size_t idx = (hash + j) % GPR_ARRAY_SIZE(g_static_strtab); - if (g_static_strtab[idx] == NULL) { - g_static_strtab[idx] = &grpc_static_mdstr_table[i]; - break; - } - } - if (j > g_static_strtab_maxprobe) { - g_static_strtab_maxprobe = j; - } - } - for (i = 0; i < GRPC_STATIC_MDELEM_COUNT; i++) { - grpc_mdelem *elem = &grpc_static_mdelem_table[i]; - grpc_mdstr *key = - &grpc_static_mdstr_table[grpc_static_metadata_elem_indices[2 * i + 0]]; - grpc_mdstr *value = - &grpc_static_mdstr_table[grpc_static_metadata_elem_indices[2 * i + 1]]; - uint32_t hash = GRPC_MDSTR_KV_HASH(key->hash, value->hash); - *(grpc_mdstr **)&elem->key = key; - *(grpc_mdstr **)&elem->value = value; - for (j = 0;; j++) { - size_t idx = (hash + j) % GPR_ARRAY_SIZE(g_static_mdtab); - if (g_static_mdtab[idx] == NULL) { - g_static_mdtab[idx] = elem; - break; - } - } - if (j > g_static_mdtab_maxprobe) { - g_static_mdtab_maxprobe = j; - } - } - /* initialize shards */ - for (i = 0; i < STRTAB_SHARD_COUNT; i++) { - strtab_shard *shard = &g_strtab_shard[i]; - gpr_mu_init(&shard->mu); - shard->count = 0; - shard->capacity = INITIAL_STRTAB_CAPACITY; - shard->strs = gpr_malloc(sizeof(*shard->strs) * shard->capacity); - memset(shard->strs, 0, sizeof(*shard->strs) * shard->capacity); - } - for (i = 0; i < MDTAB_SHARD_COUNT; i++) { - mdtab_shard *shard = &g_mdtab_shard[i]; - gpr_mu_init(&shard->mu); - shard->count = 0; - shard->free = 0; - shard->capacity = INITIAL_MDTAB_CAPACITY; - shard->elems = gpr_malloc(sizeof(*shard->elems) * shard->capacity); - memset(shard->elems, 0, sizeof(*shard->elems) * shard->capacity); - } -} - -void grpc_mdctx_global_shutdown(void) { - size_t i; - for (i = 0; i < MDTAB_SHARD_COUNT; i++) { - mdtab_shard *shard = &g_mdtab_shard[i]; - gpr_mu_destroy(&shard->mu); - gc_mdtab(shard); - /* TODO(ctiller): GPR_ASSERT(shard->count == 0); */ - if (shard->count != 0) { - gpr_log(GPR_DEBUG, "WARNING: %d metadata elements were leaked", - shard->count); - if (grpc_iomgr_abort_on_leaks()) { - abort(); - } - } - gpr_free(shard->elems); - } - for (i = 0; i < STRTAB_SHARD_COUNT; i++) { - strtab_shard *shard = &g_strtab_shard[i]; - 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", - shard->count); - if (grpc_iomgr_abort_on_leaks()) { - abort(); - } - } - gpr_free(shard->strs); - } -} - -static int is_mdstr_static(grpc_mdstr *s) { - return s >= &grpc_static_mdstr_table[0] && - s < &grpc_static_mdstr_table[GRPC_STATIC_MDSTR_COUNT]; -} - -static int is_mdelem_static(grpc_mdelem *e) { - return e >= &grpc_static_mdelem_table[0] && - e < &grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT]; -} - -static void ref_md_locked(mdtab_shard *shard, - internal_metadata *md DEBUG_ARGS) { -#ifdef GRPC_METADATA_REFCOUNT_DEBUG - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, - "ELM REF:%p:%d->%d: '%s' = '%s'", md, - gpr_atm_no_barrier_load(&md->refcnt), - gpr_atm_no_barrier_load(&md->refcnt) + 1, - grpc_mdstr_as_c_string((grpc_mdstr *)md->key), - grpc_mdstr_as_c_string((grpc_mdstr *)md->value)); -#endif - if (0 == gpr_atm_no_barrier_fetch_add(&md->refcnt, 2)) { - shard->free--; - } else { - GPR_ASSERT(1 != gpr_atm_no_barrier_fetch_add(&md->refcnt, -1)); - } -} - -static void grow_strtab(strtab_shard *shard) { - size_t capacity = shard->capacity * 2; - size_t i; - internal_string **strtab; - internal_string *s, *next; - - GPR_TIMER_BEGIN("grow_strtab", 0); - - strtab = gpr_malloc(sizeof(internal_string *) * capacity); - memset(strtab, 0, sizeof(internal_string *) * capacity); - - for (i = 0; i < shard->capacity; i++) { - for (s = shard->strs[i]; s; s = next) { - size_t idx = TABLE_IDX(s->hash, LOG2_STRTAB_SHARD_COUNT, capacity); - next = s->bucket_next; - s->bucket_next = strtab[idx]; - strtab[idx] = s; - } - } - - gpr_free(shard->strs); - shard->strs = strtab; - shard->capacity = capacity; - - GPR_TIMER_END("grow_strtab", 0); -} - -static void internal_destroy_string(strtab_shard *shard, internal_string *is) { - internal_string **prev_next; - internal_string *cur; - GPR_TIMER_BEGIN("internal_destroy_string", 0); - if (is->has_base64_and_huffman_encoded) { - gpr_slice_unref(is->base64_and_huffman); - } - for (prev_next = &shard->strs[TABLE_IDX(is->hash, LOG2_STRTAB_SHARD_COUNT, - shard->capacity)], - cur = *prev_next; - cur != is; prev_next = &cur->bucket_next, cur = cur->bucket_next) - ; - *prev_next = cur->bucket_next; - shard->count--; - gpr_free(is); - GPR_TIMER_END("internal_destroy_string", 0); -} - -static void slice_ref(void *p) { - internal_string *is = - (internal_string *)((char *)p - offsetof(internal_string, refcount)); - GRPC_MDSTR_REF((grpc_mdstr *)(is)); -} - -static void slice_unref(void *p) { - internal_string *is = - (internal_string *)((char *)p - offsetof(internal_string, refcount)); - GRPC_MDSTR_UNREF((grpc_mdstr *)(is)); -} - -grpc_mdstr *grpc_mdstr_from_string(const char *str) { - return grpc_mdstr_from_buffer((const uint8_t *)str, strlen(str)); -} - -grpc_mdstr *grpc_mdstr_from_slice(gpr_slice slice) { - grpc_mdstr *result = grpc_mdstr_from_buffer(GPR_SLICE_START_PTR(slice), - GPR_SLICE_LENGTH(slice)); - gpr_slice_unref(slice); - return result; -} - -grpc_mdstr *grpc_mdstr_from_buffer(const uint8_t *buf, size_t length) { - uint32_t hash = gpr_murmur_hash3(buf, length, g_hash_seed); - internal_string *s; - strtab_shard *shard = - &g_strtab_shard[SHARD_IDX(hash, LOG2_STRTAB_SHARD_COUNT)]; - size_t i; - size_t idx; - - GPR_TIMER_BEGIN("grpc_mdstr_from_buffer", 0); - - /* search for a static string */ - for (i = 0; i <= g_static_strtab_maxprobe; i++) { - grpc_mdstr *ss; - idx = (hash + i) % GPR_ARRAY_SIZE(g_static_strtab); - ss = g_static_strtab[idx]; - if (ss == NULL) break; - if (ss->hash == hash && GPR_SLICE_LENGTH(ss->slice) == length && - 0 == memcmp(buf, GPR_SLICE_START_PTR(ss->slice), length)) { - GPR_TIMER_END("grpc_mdstr_from_buffer", 0); - return ss; - } - } - - gpr_mu_lock(&shard->mu); - - /* search for an existing string */ - idx = TABLE_IDX(hash, LOG2_STRTAB_SHARD_COUNT, shard->capacity); - for (s = shard->strs[idx]; s; s = s->bucket_next) { - if (s->hash == hash && GPR_SLICE_LENGTH(s->slice) == length && - 0 == memcmp(buf, GPR_SLICE_START_PTR(s->slice), length)) { - GRPC_MDSTR_REF((grpc_mdstr *)s); - gpr_mu_unlock(&shard->mu); - GPR_TIMER_END("grpc_mdstr_from_buffer", 0); - return (grpc_mdstr *)s; - } - } - - /* not found: create a new string */ - if (length + 1 < GPR_SLICE_INLINED_SIZE) { - /* string data goes directly into the slice */ - s = gpr_malloc(sizeof(internal_string)); - gpr_atm_rel_store(&s->refcnt, 2); - s->slice.refcount = NULL; - memcpy(s->slice.data.inlined.bytes, buf, length); - s->slice.data.inlined.bytes[length] = 0; - s->slice.data.inlined.length = (uint8_t)length; - } else { - /* string data goes after the internal_string header, and we +1 for null - terminator */ - s = gpr_malloc(sizeof(internal_string) + length + 1); - gpr_atm_rel_store(&s->refcnt, 2); - s->refcount.ref = slice_ref; - s->refcount.unref = slice_unref; - s->slice.refcount = &s->refcount; - s->slice.data.refcounted.bytes = (uint8_t *)(s + 1); - s->slice.data.refcounted.length = length; - memcpy(s->slice.data.refcounted.bytes, buf, length); - /* add a null terminator for cheap c string conversion when desired */ - s->slice.data.refcounted.bytes[length] = 0; - } - s->has_base64_and_huffman_encoded = 0; - s->hash = hash; - s->bucket_next = shard->strs[idx]; - shard->strs[idx] = s; - - shard->count++; - - if (shard->count > shard->capacity * 2) { - grow_strtab(shard); - } - - gpr_mu_unlock(&shard->mu); - GPR_TIMER_END("grpc_mdstr_from_buffer", 0); - - return (grpc_mdstr *)s; -} - -static void gc_mdtab(mdtab_shard *shard) { - size_t i; - internal_metadata **prev_next; - internal_metadata *md, *next; - - GPR_TIMER_BEGIN("gc_mdtab", 0); - for (i = 0; i < shard->capacity; i++) { - prev_next = &shard->elems[i]; - for (md = shard->elems[i]; md; md = next) { - void *user_data = (void *)gpr_atm_no_barrier_load(&md->user_data); - next = md->bucket_next; - if (gpr_atm_acq_load(&md->refcnt) == 0) { - GRPC_MDSTR_UNREF((grpc_mdstr *)md->key); - GRPC_MDSTR_UNREF((grpc_mdstr *)md->value); - if (md->user_data) { - ((destroy_user_data_func)gpr_atm_no_barrier_load( - &md->destroy_user_data))(user_data); - } - gpr_free(md); - *prev_next = next; - shard->free--; - shard->count--; - } else { - prev_next = &md->bucket_next; - } - } - } - GPR_TIMER_END("gc_mdtab", 0); -} - -static void grow_mdtab(mdtab_shard *shard) { - size_t capacity = shard->capacity * 2; - size_t i; - internal_metadata **mdtab; - internal_metadata *md, *next; - uint32_t hash; - - GPR_TIMER_BEGIN("grow_mdtab", 0); - - mdtab = gpr_malloc(sizeof(internal_metadata *) * capacity); - memset(mdtab, 0, sizeof(internal_metadata *) * capacity); - - for (i = 0; i < shard->capacity; i++) { - for (md = shard->elems[i]; md; md = next) { - size_t idx; - hash = GRPC_MDSTR_KV_HASH(md->key->hash, md->value->hash); - next = md->bucket_next; - idx = TABLE_IDX(hash, LOG2_MDTAB_SHARD_COUNT, capacity); - md->bucket_next = mdtab[idx]; - mdtab[idx] = md; - } - } - - gpr_free(shard->elems); - shard->elems = mdtab; - shard->capacity = capacity; - - GPR_TIMER_END("grow_mdtab", 0); -} - -static void rehash_mdtab(mdtab_shard *shard) { - if (shard->free > shard->capacity / 4) { - gc_mdtab(shard); - } else { - grow_mdtab(shard); - } -} - -grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdstr *mkey, - grpc_mdstr *mvalue) { - internal_string *key = (internal_string *)mkey; - internal_string *value = (internal_string *)mvalue; - uint32_t hash = GRPC_MDSTR_KV_HASH(mkey->hash, mvalue->hash); - internal_metadata *md; - mdtab_shard *shard = &g_mdtab_shard[SHARD_IDX(hash, LOG2_MDTAB_SHARD_COUNT)]; - size_t i; - size_t idx; - - GPR_TIMER_BEGIN("grpc_mdelem_from_metadata_strings", 0); - - if (is_mdstr_static(mkey) && is_mdstr_static(mvalue)) { - for (i = 0; i <= g_static_mdtab_maxprobe; i++) { - grpc_mdelem *smd; - idx = (hash + i) % GPR_ARRAY_SIZE(g_static_mdtab); - smd = g_static_mdtab[idx]; - if (smd == NULL) break; - if (smd->key == mkey && smd->value == mvalue) { - GPR_TIMER_END("grpc_mdelem_from_metadata_strings", 0); - return smd; - } - } - } - - gpr_mu_lock(&shard->mu); - - idx = TABLE_IDX(hash, LOG2_MDTAB_SHARD_COUNT, shard->capacity); - /* search for an existing pair */ - for (md = shard->elems[idx]; md; md = md->bucket_next) { - if (md->key == key && md->value == value) { - REF_MD_LOCKED(shard, md); - GRPC_MDSTR_UNREF((grpc_mdstr *)key); - GRPC_MDSTR_UNREF((grpc_mdstr *)value); - gpr_mu_unlock(&shard->mu); - GPR_TIMER_END("grpc_mdelem_from_metadata_strings", 0); - return (grpc_mdelem *)md; - } - } - - /* not found: create a new pair */ - md = gpr_malloc(sizeof(internal_metadata)); - gpr_atm_rel_store(&md->refcnt, 2); - md->key = key; - md->value = value; - md->user_data = 0; - md->destroy_user_data = 0; - md->bucket_next = shard->elems[idx]; - shard->elems[idx] = md; - gpr_mu_init(&md->mu_user_data); -#ifdef GRPC_METADATA_REFCOUNT_DEBUG - gpr_log(GPR_DEBUG, "ELM NEW:%p:%d: '%s' = '%s'", md, - gpr_atm_no_barrier_load(&md->refcnt), - grpc_mdstr_as_c_string((grpc_mdstr *)md->key), - grpc_mdstr_as_c_string((grpc_mdstr *)md->value)); -#endif - shard->count++; - - if (shard->count > shard->capacity * 2) { - rehash_mdtab(shard); - } - - gpr_mu_unlock(&shard->mu); - - GPR_TIMER_END("grpc_mdelem_from_metadata_strings", 0); - - return (grpc_mdelem *)md; -} - -grpc_mdelem *grpc_mdelem_from_strings(const char *key, const char *value) { - return grpc_mdelem_from_metadata_strings(grpc_mdstr_from_string(key), - grpc_mdstr_from_string(value)); -} - -grpc_mdelem *grpc_mdelem_from_slices(gpr_slice key, gpr_slice value) { - return grpc_mdelem_from_metadata_strings(grpc_mdstr_from_slice(key), - grpc_mdstr_from_slice(value)); -} - -grpc_mdelem *grpc_mdelem_from_string_and_buffer(const char *key, - const uint8_t *value, - size_t value_length) { - return grpc_mdelem_from_metadata_strings( - grpc_mdstr_from_string(key), grpc_mdstr_from_buffer(value, value_length)); -} - -grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *gmd DEBUG_ARGS) { - internal_metadata *md = (internal_metadata *)gmd; - if (is_mdelem_static(gmd)) return gmd; -#ifdef GRPC_METADATA_REFCOUNT_DEBUG - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, - "ELM REF:%p:%d->%d: '%s' = '%s'", md, - gpr_atm_no_barrier_load(&md->refcnt), - gpr_atm_no_barrier_load(&md->refcnt) + 1, - grpc_mdstr_as_c_string((grpc_mdstr *)md->key), - grpc_mdstr_as_c_string((grpc_mdstr *)md->value)); -#endif - /* we can assume the ref count is >= 1 as the application is calling - this function - meaning that no adjustment to mdtab_free is necessary, - simplifying the logic here to be just an atomic increment */ - /* use C assert to have this removed in opt builds */ - assert(gpr_atm_no_barrier_load(&md->refcnt) >= 2); - gpr_atm_no_barrier_fetch_add(&md->refcnt, 1); - return gmd; -} - -void grpc_mdelem_unref(grpc_mdelem *gmd DEBUG_ARGS) { - internal_metadata *md = (internal_metadata *)gmd; - if (!md) return; - if (is_mdelem_static(gmd)) return; -#ifdef GRPC_METADATA_REFCOUNT_DEBUG - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, - "ELM UNREF:%p:%d->%d: '%s' = '%s'", md, - gpr_atm_no_barrier_load(&md->refcnt), - gpr_atm_no_barrier_load(&md->refcnt) - 1, - grpc_mdstr_as_c_string((grpc_mdstr *)md->key), - grpc_mdstr_as_c_string((grpc_mdstr *)md->value)); -#endif - if (2 == gpr_atm_full_fetch_add(&md->refcnt, -1)) { - uint32_t hash = GRPC_MDSTR_KV_HASH(md->key->hash, md->value->hash); - mdtab_shard *shard = - &g_mdtab_shard[SHARD_IDX(hash, LOG2_MDTAB_SHARD_COUNT)]; - GPR_TIMER_BEGIN("grpc_mdelem_unref.to_zero", 0); - gpr_mu_lock(&shard->mu); - if (1 == gpr_atm_no_barrier_load(&md->refcnt)) { - shard->free++; - gpr_atm_no_barrier_store(&md->refcnt, 0); - } - gpr_mu_unlock(&shard->mu); - GPR_TIMER_END("grpc_mdelem_unref.to_zero", 0); - } -} - -const char *grpc_mdstr_as_c_string(grpc_mdstr *s) { - return (const char *)GPR_SLICE_START_PTR(s->slice); -} - -grpc_mdstr *grpc_mdstr_ref(grpc_mdstr *gs DEBUG_ARGS) { - internal_string *s = (internal_string *)gs; - if (is_mdstr_static(gs)) return gs; - GPR_ASSERT(gpr_atm_full_fetch_add(&s->refcnt, 1) != 0); - return gs; -} - -void grpc_mdstr_unref(grpc_mdstr *gs DEBUG_ARGS) { - internal_string *s = (internal_string *)gs; - if (is_mdstr_static(gs)) return; - if (2 == gpr_atm_full_fetch_add(&s->refcnt, -1)) { - strtab_shard *shard = - &g_strtab_shard[SHARD_IDX(s->hash, LOG2_STRTAB_SHARD_COUNT)]; - gpr_mu_lock(&shard->mu); - if (1 == gpr_atm_no_barrier_load(&s->refcnt)) { - internal_destroy_string(shard, s); - } - gpr_mu_unlock(&shard->mu); - } -} - -void *grpc_mdelem_get_user_data(grpc_mdelem *md, void (*destroy_func)(void *)) { - internal_metadata *im = (internal_metadata *)md; - void *result; - if (is_mdelem_static(md)) { - return (void *)grpc_static_mdelem_user_data[md - grpc_static_mdelem_table]; - } - if (gpr_atm_acq_load(&im->destroy_user_data) == (gpr_atm)destroy_func) { - return (void *)gpr_atm_no_barrier_load(&im->user_data); - } else { - return NULL; - } - return result; -} - -void grpc_mdelem_set_user_data(grpc_mdelem *md, void (*destroy_func)(void *), - void *user_data) { - internal_metadata *im = (internal_metadata *)md; - GPR_ASSERT(!is_mdelem_static(md)); - GPR_ASSERT((user_data == NULL) == (destroy_func == NULL)); - gpr_mu_lock(&im->mu_user_data); - if (gpr_atm_no_barrier_load(&im->destroy_user_data)) { - /* user data can only be set once */ - gpr_mu_unlock(&im->mu_user_data); - if (destroy_func != NULL) { - destroy_func(user_data); - } - return; - } - gpr_atm_no_barrier_store(&im->user_data, (gpr_atm)user_data); - gpr_atm_rel_store(&im->destroy_user_data, (gpr_atm)destroy_func); - gpr_mu_unlock(&im->mu_user_data); -} - -gpr_slice grpc_mdstr_as_base64_encoded_and_huffman_compressed(grpc_mdstr *gs) { - internal_string *s = (internal_string *)gs; - gpr_slice slice; - strtab_shard *shard = - &g_strtab_shard[SHARD_IDX(s->hash, LOG2_STRTAB_SHARD_COUNT)]; - gpr_mu_lock(&shard->mu); - if (!s->has_base64_and_huffman_encoded) { - s->base64_and_huffman = - grpc_chttp2_base64_encode_and_huffman_compress(s->slice); - s->has_base64_and_huffman_encoded = 1; - } - slice = s->base64_and_huffman; - gpr_mu_unlock(&shard->mu); - return slice; -} diff --git a/src/core/transport/metadata.h b/src/core/transport/metadata.h deleted file mode 100644 index 5ab397848c..0000000000 --- a/src/core/transport/metadata.h +++ /dev/null @@ -1,156 +0,0 @@ -/* - * - * Copyright 2015-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_TRANSPORT_METADATA_H -#define GRPC_CORE_TRANSPORT_METADATA_H - -#include -#include - -/* This file provides a mechanism for tracking metadata through the grpc stack. - It's not intended for consumption outside of the library. - - Metadata is tracked in the context of a grpc_mdctx. For the time being there - is one of these per-channel, avoiding cross channel interference with memory - use and lock contention. - - The context tracks unique strings (grpc_mdstr) and pairs of strings - (grpc_mdelem). Any of these objects can be checked for equality by comparing - their pointers. These objects are reference counted. - - grpc_mdelem can additionally store a (non-NULL) user data pointer. This - pointer is intended to be used to cache semantic meaning of a metadata - element. For example, an OAuth token may cache the credentials it represents - and the time at which it expires in the mdelem user data. - - Combining this metadata cache and the hpack compression table allows us to - simply lookup complete preparsed objects quickly, incurring a few atomic - ops per metadata element on the fast path. - - grpc_mdelem instances MAY live longer than their refcount implies, and are - garbage collected periodically, meaning cached data can easily outlive a - single request. - - STATIC METADATA: in static_metadata.h we declare a set of static metadata. - These mdelems and mdstrs are available via pre-declared code generated macros - and are available to code anywhere between grpc_init() and grpc_shutdown(). - They are not refcounted, but can be passed to _ref and _unref functions - declared here - in which case those functions are effectively no-ops. */ - -/* Forward declarations */ -typedef struct grpc_mdstr grpc_mdstr; -typedef struct grpc_mdelem grpc_mdelem; - -/* if changing this, make identical changes in internal_string in metadata.c */ -struct grpc_mdstr { - const gpr_slice slice; - const uint32_t hash; - /* there is a private part to this in metadata.c */ -}; - -/* if changing this, make identical changes in internal_metadata in - metadata.c */ -struct grpc_mdelem { - grpc_mdstr *const key; - grpc_mdstr *const value; - /* there is a private part to this in metadata.c */ -}; - -void grpc_test_only_set_metadata_hash_seed(uint32_t seed); - -/* Constructors for grpc_mdstr instances; take a variety of data types that - clients may have handy */ -grpc_mdstr *grpc_mdstr_from_string(const char *str); -/* Unrefs the slice. */ -grpc_mdstr *grpc_mdstr_from_slice(gpr_slice slice); -grpc_mdstr *grpc_mdstr_from_buffer(const uint8_t *str, size_t length); - -/* Returns a borrowed slice from the mdstr with its contents base64 encoded - and huffman compressed */ -gpr_slice grpc_mdstr_as_base64_encoded_and_huffman_compressed(grpc_mdstr *str); - -/* Constructors for grpc_mdelem instances; take a variety of data types that - clients may have handy */ -grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdstr *key, - grpc_mdstr *value); -grpc_mdelem *grpc_mdelem_from_strings(const char *key, const char *value); -/* Unrefs the slices. */ -grpc_mdelem *grpc_mdelem_from_slices(gpr_slice key, gpr_slice value); -grpc_mdelem *grpc_mdelem_from_string_and_buffer(const char *key, - const uint8_t *value, - size_t value_length); - -/* Mutator and accessor for grpc_mdelem user data. The destructor function - is used as a type tag and is checked during user_data fetch. */ -void *grpc_mdelem_get_user_data(grpc_mdelem *md, - void (*if_destroy_func)(void *)); -void grpc_mdelem_set_user_data(grpc_mdelem *md, void (*destroy_func)(void *), - void *user_data); - -/* Reference counting */ -#ifdef GRPC_METADATA_REFCOUNT_DEBUG -#define GRPC_MDSTR_REF(s) grpc_mdstr_ref((s), __FILE__, __LINE__) -#define GRPC_MDSTR_UNREF(s) grpc_mdstr_unref((s), __FILE__, __LINE__) -#define GRPC_MDELEM_REF(s) grpc_mdelem_ref((s), __FILE__, __LINE__) -#define GRPC_MDELEM_UNREF(s) grpc_mdelem_unref((s), __FILE__, __LINE__) -grpc_mdstr *grpc_mdstr_ref(grpc_mdstr *s, const char *file, int line); -void grpc_mdstr_unref(grpc_mdstr *s, const char *file, int line); -grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *md, const char *file, int line); -void grpc_mdelem_unref(grpc_mdelem *md, const char *file, int line); -#else -#define GRPC_MDSTR_REF(s) grpc_mdstr_ref((s)) -#define GRPC_MDSTR_UNREF(s) grpc_mdstr_unref((s)) -#define GRPC_MDELEM_REF(s) grpc_mdelem_ref((s)) -#define GRPC_MDELEM_UNREF(s) grpc_mdelem_unref((s)) -grpc_mdstr *grpc_mdstr_ref(grpc_mdstr *s); -void grpc_mdstr_unref(grpc_mdstr *s); -grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *md); -void grpc_mdelem_unref(grpc_mdelem *md); -#endif - -/* Recover a char* from a grpc_mdstr. The returned string is null terminated. - Does not promise that the returned string has no embedded nulls however. */ -const char *grpc_mdstr_as_c_string(grpc_mdstr *s); - -#define GRPC_MDSTR_LENGTH(s) (GPR_SLICE_LENGTH(s->slice)) - -int grpc_mdstr_is_legal_header(grpc_mdstr *s); -int grpc_mdstr_is_legal_nonbin_header(grpc_mdstr *s); -int grpc_mdstr_is_bin_suffixed(grpc_mdstr *s); - -#define GRPC_MDSTR_KV_HASH(k_hash, v_hash) (GPR_ROTL((k_hash), 2) ^ (v_hash)) - -void grpc_mdctx_global_init(void); -void grpc_mdctx_global_shutdown(void); - -#endif /* GRPC_CORE_TRANSPORT_METADATA_H */ diff --git a/src/core/transport/metadata_batch.c b/src/core/transport/metadata_batch.c deleted file mode 100644 index 1266862f82..0000000000 --- a/src/core/transport/metadata_batch.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/transport/metadata_batch.h" - -#include - -#include -#include - -#include "src/core/profiling/timers.h" - -static void assert_valid_list(grpc_mdelem_list *list) { -#ifndef NDEBUG - grpc_linked_mdelem *l; - - GPR_ASSERT((list->head == NULL) == (list->tail == NULL)); - if (!list->head) return; - GPR_ASSERT(list->head->prev == NULL); - GPR_ASSERT(list->tail->next == NULL); - GPR_ASSERT((list->head == list->tail) == (list->head->next == NULL)); - - for (l = list->head; l; l = l->next) { - GPR_ASSERT(l->md); - GPR_ASSERT((l->prev == NULL) == (l == list->head)); - GPR_ASSERT((l->next == NULL) == (l == list->tail)); - if (l->next) GPR_ASSERT(l->next->prev == l); - if (l->prev) GPR_ASSERT(l->prev->next == l); - } -#endif /* NDEBUG */ -} - -#ifndef NDEBUG -void grpc_metadata_batch_assert_ok(grpc_metadata_batch *batch) { - assert_valid_list(&batch->list); -} -#endif /* NDEBUG */ - -void grpc_metadata_batch_init(grpc_metadata_batch *batch) { - batch->list.head = batch->list.tail = NULL; - batch->deadline = gpr_inf_future(GPR_CLOCK_REALTIME); -} - -void grpc_metadata_batch_destroy(grpc_metadata_batch *batch) { - grpc_linked_mdelem *l; - for (l = batch->list.head; l; l = l->next) { - GRPC_MDELEM_UNREF(l->md); - } -} - -void grpc_metadata_batch_add_head(grpc_metadata_batch *batch, - grpc_linked_mdelem *storage, - grpc_mdelem *elem_to_add) { - GPR_ASSERT(elem_to_add); - storage->md = elem_to_add; - grpc_metadata_batch_link_head(batch, storage); -} - -static void link_head(grpc_mdelem_list *list, grpc_linked_mdelem *storage) { - assert_valid_list(list); - GPR_ASSERT(storage->md); - storage->prev = NULL; - storage->next = list->head; - if (list->head != NULL) { - list->head->prev = storage; - } else { - list->tail = storage; - } - list->head = storage; - assert_valid_list(list); -} - -void grpc_metadata_batch_link_head(grpc_metadata_batch *batch, - grpc_linked_mdelem *storage) { - link_head(&batch->list, storage); -} - -void grpc_metadata_batch_add_tail(grpc_metadata_batch *batch, - grpc_linked_mdelem *storage, - grpc_mdelem *elem_to_add) { - GPR_ASSERT(elem_to_add); - storage->md = elem_to_add; - grpc_metadata_batch_link_tail(batch, storage); -} - -static void link_tail(grpc_mdelem_list *list, grpc_linked_mdelem *storage) { - assert_valid_list(list); - GPR_ASSERT(storage->md); - storage->prev = list->tail; - storage->next = NULL; - storage->reserved = NULL; - if (list->tail != NULL) { - list->tail->next = storage; - } else { - list->head = storage; - } - list->tail = storage; - assert_valid_list(list); -} - -void grpc_metadata_batch_link_tail(grpc_metadata_batch *batch, - grpc_linked_mdelem *storage) { - link_tail(&batch->list, storage); -} - -void grpc_metadata_batch_move(grpc_metadata_batch *dst, - grpc_metadata_batch *src) { - *dst = *src; - memset(src, 0, sizeof(grpc_metadata_batch)); -} - -void grpc_metadata_batch_filter(grpc_metadata_batch *batch, - grpc_mdelem *(*filter)(void *user_data, - grpc_mdelem *elem), - void *user_data) { - grpc_linked_mdelem *l; - grpc_linked_mdelem *next; - - GPR_TIMER_BEGIN("grpc_metadata_batch_filter", 0); - - assert_valid_list(&batch->list); - for (l = batch->list.head; l; l = next) { - grpc_mdelem *orig = l->md; - grpc_mdelem *filt = filter(user_data, orig); - next = l->next; - if (filt == NULL) { - if (l->prev) { - l->prev->next = l->next; - } - if (l->next) { - l->next->prev = l->prev; - } - if (batch->list.head == l) { - batch->list.head = l->next; - } - if (batch->list.tail == l) { - batch->list.tail = l->prev; - } - assert_valid_list(&batch->list); - GRPC_MDELEM_UNREF(l->md); - } else if (filt != orig) { - GRPC_MDELEM_UNREF(orig); - l->md = filt; - } - } - assert_valid_list(&batch->list); - - GPR_TIMER_END("grpc_metadata_batch_filter", 0); -} - -static grpc_mdelem *no_metadata_for_you(void *user_data, grpc_mdelem *elem) { - return NULL; -} - -void grpc_metadata_batch_clear(grpc_metadata_batch *batch) { - batch->deadline = gpr_inf_future(GPR_CLOCK_REALTIME); - grpc_metadata_batch_filter(batch, no_metadata_for_you, NULL); -} - -int grpc_metadata_batch_is_empty(grpc_metadata_batch *batch) { - return batch->list.head == NULL && - gpr_time_cmp(gpr_inf_future(batch->deadline.clock_type), - batch->deadline) == 0; -} diff --git a/src/core/transport/metadata_batch.h b/src/core/transport/metadata_batch.h deleted file mode 100644 index 9337b28328..0000000000 --- a/src/core/transport/metadata_batch.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * - * Copyright 2015-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_TRANSPORT_METADATA_BATCH_H -#define GRPC_CORE_TRANSPORT_METADATA_BATCH_H - -#include -#include -#include -#include -#include "src/core/transport/metadata.h" - -typedef struct grpc_linked_mdelem { - grpc_mdelem *md; - struct grpc_linked_mdelem *next; - struct grpc_linked_mdelem *prev; - void *reserved; -} grpc_linked_mdelem; - -typedef struct grpc_mdelem_list { - grpc_linked_mdelem *head; - grpc_linked_mdelem *tail; -} grpc_mdelem_list; - -typedef struct grpc_metadata_batch { - /** Metadata elements in this batch */ - grpc_mdelem_list list; - /** Used to calculate grpc-timeout at the point of sending, - or gpr_inf_future if this batch does not need to send a - grpc-timeout */ - gpr_timespec deadline; -} grpc_metadata_batch; - -void grpc_metadata_batch_init(grpc_metadata_batch *batch); -void grpc_metadata_batch_destroy(grpc_metadata_batch *batch); -void grpc_metadata_batch_clear(grpc_metadata_batch *batch); -int grpc_metadata_batch_is_empty(grpc_metadata_batch *batch); - -/** Moves the metadata information from \a src to \a dst. Upon return, \a src is - * zeroed. */ -void grpc_metadata_batch_move(grpc_metadata_batch *dst, - grpc_metadata_batch *src); - -/** Add \a storage to the beginning of \a batch. storage->md is - assumed to be valid. - \a storage is owned by the caller and must survive for the - lifetime of batch. This usually means it should be around - for the lifetime of the call. */ -void grpc_metadata_batch_link_head(grpc_metadata_batch *batch, - grpc_linked_mdelem *storage); -/** Add \a storage to the end of \a batch. storage->md is - assumed to be valid. - \a storage is owned by the caller and must survive for the - lifetime of batch. This usually means it should be around - for the lifetime of the call. */ -void grpc_metadata_batch_link_tail(grpc_metadata_batch *batch, - grpc_linked_mdelem *storage); - -/** Add \a elem_to_add as the first element in \a batch, using - \a storage as backing storage for the linked list element. - \a storage is owned by the caller and must survive for the - lifetime of batch. This usually means it should be around - for the lifetime of the call. - Takes ownership of \a elem_to_add */ -void grpc_metadata_batch_add_head(grpc_metadata_batch *batch, - grpc_linked_mdelem *storage, - grpc_mdelem *elem_to_add); -/** Add \a elem_to_add as the last element in \a batch, using - \a storage as backing storage for the linked list element. - \a storage is owned by the caller and must survive for the - lifetime of batch. This usually means it should be around - for the lifetime of the call. - Takes ownership of \a elem_to_add */ -void grpc_metadata_batch_add_tail(grpc_metadata_batch *batch, - grpc_linked_mdelem *storage, - grpc_mdelem *elem_to_add); - -/** For each element in \a batch, execute \a filter. - The return value from \a filter will be substituted for the - grpc_mdelem passed to \a filter. If \a filter returns NULL, - the element will be moved to the garbage list. */ -void grpc_metadata_batch_filter(grpc_metadata_batch *batch, - grpc_mdelem *(*filter)(void *user_data, - grpc_mdelem *elem), - void *user_data); - -#ifndef NDEBUG -void grpc_metadata_batch_assert_ok(grpc_metadata_batch *comd); -#else -#define grpc_metadata_batch_assert_ok(comd) \ - do { \ - } while (0) -#endif - -#endif /* GRPC_CORE_TRANSPORT_METADATA_BATCH_H */ diff --git a/src/core/transport/static_metadata.c b/src/core/transport/static_metadata.c deleted file mode 100644 index 30bbb89880..0000000000 --- a/src/core/transport/static_metadata.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * - * Copyright 2015-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. - * - */ - -/* - * WARNING: Auto-generated code. - * - * To make changes to this file, change - * tools/codegen/core/gen_static_metadata.py, - * and then re-run it. - * - * See metadata.h for an explanation of the interface here, and metadata.c for - * an - * explanation of what's going on. - */ - -#include "src/core/transport/static_metadata.h" - -grpc_mdstr grpc_static_mdstr_table[GRPC_STATIC_MDSTR_COUNT]; - -grpc_mdelem grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT]; -uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 4, 8, 6, 2, 4, 8, 6, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - -const uint8_t grpc_static_metadata_elem_indices[GRPC_STATIC_MDELEM_COUNT * 2] = - {11, 35, 10, 35, 12, 35, 12, 49, 13, 35, 14, 35, 15, 35, 16, 35, 17, 35, - 19, 35, 20, 35, 21, 35, 24, 35, 25, 35, 26, 35, 27, 35, 28, 35, 29, 35, - 30, 18, 30, 35, 31, 35, 32, 35, 36, 35, 37, 35, 38, 35, 39, 35, 42, 33, - 42, 34, 42, 48, 42, 53, 42, 54, 42, 55, 42, 56, 43, 33, 43, 48, 43, 53, - 46, 0, 46, 1, 46, 2, 50, 35, 57, 35, 58, 35, 59, 35, 60, 35, 61, 35, - 62, 35, 63, 35, 64, 35, 65, 35, 66, 40, 66, 68, 67, 78, 67, 79, 69, 35, - 70, 35, 71, 35, 72, 35, 73, 35, 74, 35, 75, 41, 75, 51, 75, 52, 76, 35, - 77, 35, 80, 3, 80, 4, 80, 5, 80, 6, 80, 7, 80, 8, 80, 9, 81, 35, - 82, 83, 84, 35, 85, 35, 86, 35, 87, 35, 88, 35}; - -const char *const grpc_static_metadata_strings[GRPC_STATIC_MDSTR_COUNT] = { - "0", - "1", - "2", - "200", - "204", - "206", - "304", - "400", - "404", - "500", - "accept", - "accept-charset", - "accept-encoding", - "accept-language", - "accept-ranges", - "access-control-allow-origin", - "age", - "allow", - "application/grpc", - ":authority", - "authorization", - "cache-control", - "census-bin", - "census-binary-bin", - "content-disposition", - "content-encoding", - "content-language", - "content-length", - "content-location", - "content-range", - "content-type", - "cookie", - "date", - "deflate", - "deflate,gzip", - "", - "etag", - "expect", - "expires", - "from", - "GET", - "grpc", - "grpc-accept-encoding", - "grpc-encoding", - "grpc-internal-encoding-request", - "grpc-message", - "grpc-status", - "grpc-timeout", - "gzip", - "gzip, deflate", - "host", - "http", - "https", - "identity", - "identity,deflate", - "identity,deflate,gzip", - "identity,gzip", - "if-match", - "if-modified-since", - "if-none-match", - "if-range", - "if-unmodified-since", - "last-modified", - "link", - "location", - "max-forwards", - ":method", - ":path", - "POST", - "proxy-authenticate", - "proxy-authorization", - "range", - "referer", - "refresh", - "retry-after", - ":scheme", - "server", - "set-cookie", - "/", - "/index.html", - ":status", - "strict-transport-security", - "te", - "trailers", - "transfer-encoding", - "user-agent", - "vary", - "via", - "www-authenticate"}; - -const uint8_t grpc_static_accept_encoding_metadata[8] = {0, 29, 26, 30, - 28, 32, 27, 31}; diff --git a/src/core/transport/static_metadata.h b/src/core/transport/static_metadata.h deleted file mode 100644 index 85442f8107..0000000000 --- a/src/core/transport/static_metadata.h +++ /dev/null @@ -1,408 +0,0 @@ -/* - * - * Copyright 2015-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. - * - */ - -/* - * WARNING: Auto-generated code. - * - * To make changes to this file, change - * tools/codegen/core/gen_static_metadata.py, - * and then re-run it. - * - * See metadata.h for an explanation of the interface here, and metadata.c for - * an - * explanation of what's going on. - */ - -#ifndef GRPC_CORE_TRANSPORT_STATIC_METADATA_H -#define GRPC_CORE_TRANSPORT_STATIC_METADATA_H - -#include "src/core/transport/metadata.h" - -#define GRPC_STATIC_MDSTR_COUNT 89 -extern grpc_mdstr grpc_static_mdstr_table[GRPC_STATIC_MDSTR_COUNT]; -/* "0" */ -#define GRPC_MDSTR_0 (&grpc_static_mdstr_table[0]) -/* "1" */ -#define GRPC_MDSTR_1 (&grpc_static_mdstr_table[1]) -/* "2" */ -#define GRPC_MDSTR_2 (&grpc_static_mdstr_table[2]) -/* "200" */ -#define GRPC_MDSTR_200 (&grpc_static_mdstr_table[3]) -/* "204" */ -#define GRPC_MDSTR_204 (&grpc_static_mdstr_table[4]) -/* "206" */ -#define GRPC_MDSTR_206 (&grpc_static_mdstr_table[5]) -/* "304" */ -#define GRPC_MDSTR_304 (&grpc_static_mdstr_table[6]) -/* "400" */ -#define GRPC_MDSTR_400 (&grpc_static_mdstr_table[7]) -/* "404" */ -#define GRPC_MDSTR_404 (&grpc_static_mdstr_table[8]) -/* "500" */ -#define GRPC_MDSTR_500 (&grpc_static_mdstr_table[9]) -/* "accept" */ -#define GRPC_MDSTR_ACCEPT (&grpc_static_mdstr_table[10]) -/* "accept-charset" */ -#define GRPC_MDSTR_ACCEPT_CHARSET (&grpc_static_mdstr_table[11]) -/* "accept-encoding" */ -#define GRPC_MDSTR_ACCEPT_ENCODING (&grpc_static_mdstr_table[12]) -/* "accept-language" */ -#define GRPC_MDSTR_ACCEPT_LANGUAGE (&grpc_static_mdstr_table[13]) -/* "accept-ranges" */ -#define GRPC_MDSTR_ACCEPT_RANGES (&grpc_static_mdstr_table[14]) -/* "access-control-allow-origin" */ -#define GRPC_MDSTR_ACCESS_CONTROL_ALLOW_ORIGIN (&grpc_static_mdstr_table[15]) -/* "age" */ -#define GRPC_MDSTR_AGE (&grpc_static_mdstr_table[16]) -/* "allow" */ -#define GRPC_MDSTR_ALLOW (&grpc_static_mdstr_table[17]) -/* "application/grpc" */ -#define GRPC_MDSTR_APPLICATION_SLASH_GRPC (&grpc_static_mdstr_table[18]) -/* ":authority" */ -#define GRPC_MDSTR_AUTHORITY (&grpc_static_mdstr_table[19]) -/* "authorization" */ -#define GRPC_MDSTR_AUTHORIZATION (&grpc_static_mdstr_table[20]) -/* "cache-control" */ -#define GRPC_MDSTR_CACHE_CONTROL (&grpc_static_mdstr_table[21]) -/* "census-bin" */ -#define GRPC_MDSTR_CENSUS_BIN (&grpc_static_mdstr_table[22]) -/* "census-binary-bin" */ -#define GRPC_MDSTR_CENSUS_BINARY_BIN (&grpc_static_mdstr_table[23]) -/* "content-disposition" */ -#define GRPC_MDSTR_CONTENT_DISPOSITION (&grpc_static_mdstr_table[24]) -/* "content-encoding" */ -#define GRPC_MDSTR_CONTENT_ENCODING (&grpc_static_mdstr_table[25]) -/* "content-language" */ -#define GRPC_MDSTR_CONTENT_LANGUAGE (&grpc_static_mdstr_table[26]) -/* "content-length" */ -#define GRPC_MDSTR_CONTENT_LENGTH (&grpc_static_mdstr_table[27]) -/* "content-location" */ -#define GRPC_MDSTR_CONTENT_LOCATION (&grpc_static_mdstr_table[28]) -/* "content-range" */ -#define GRPC_MDSTR_CONTENT_RANGE (&grpc_static_mdstr_table[29]) -/* "content-type" */ -#define GRPC_MDSTR_CONTENT_TYPE (&grpc_static_mdstr_table[30]) -/* "cookie" */ -#define GRPC_MDSTR_COOKIE (&grpc_static_mdstr_table[31]) -/* "date" */ -#define GRPC_MDSTR_DATE (&grpc_static_mdstr_table[32]) -/* "deflate" */ -#define GRPC_MDSTR_DEFLATE (&grpc_static_mdstr_table[33]) -/* "deflate,gzip" */ -#define GRPC_MDSTR_DEFLATE_COMMA_GZIP (&grpc_static_mdstr_table[34]) -/* "" */ -#define GRPC_MDSTR_EMPTY (&grpc_static_mdstr_table[35]) -/* "etag" */ -#define GRPC_MDSTR_ETAG (&grpc_static_mdstr_table[36]) -/* "expect" */ -#define GRPC_MDSTR_EXPECT (&grpc_static_mdstr_table[37]) -/* "expires" */ -#define GRPC_MDSTR_EXPIRES (&grpc_static_mdstr_table[38]) -/* "from" */ -#define GRPC_MDSTR_FROM (&grpc_static_mdstr_table[39]) -/* "GET" */ -#define GRPC_MDSTR_GET (&grpc_static_mdstr_table[40]) -/* "grpc" */ -#define GRPC_MDSTR_GRPC (&grpc_static_mdstr_table[41]) -/* "grpc-accept-encoding" */ -#define GRPC_MDSTR_GRPC_ACCEPT_ENCODING (&grpc_static_mdstr_table[42]) -/* "grpc-encoding" */ -#define GRPC_MDSTR_GRPC_ENCODING (&grpc_static_mdstr_table[43]) -/* "grpc-internal-encoding-request" */ -#define GRPC_MDSTR_GRPC_INTERNAL_ENCODING_REQUEST (&grpc_static_mdstr_table[44]) -/* "grpc-message" */ -#define GRPC_MDSTR_GRPC_MESSAGE (&grpc_static_mdstr_table[45]) -/* "grpc-status" */ -#define GRPC_MDSTR_GRPC_STATUS (&grpc_static_mdstr_table[46]) -/* "grpc-timeout" */ -#define GRPC_MDSTR_GRPC_TIMEOUT (&grpc_static_mdstr_table[47]) -/* "gzip" */ -#define GRPC_MDSTR_GZIP (&grpc_static_mdstr_table[48]) -/* "gzip, deflate" */ -#define GRPC_MDSTR_GZIP_COMMA_DEFLATE (&grpc_static_mdstr_table[49]) -/* "host" */ -#define GRPC_MDSTR_HOST (&grpc_static_mdstr_table[50]) -/* "http" */ -#define GRPC_MDSTR_HTTP (&grpc_static_mdstr_table[51]) -/* "https" */ -#define GRPC_MDSTR_HTTPS (&grpc_static_mdstr_table[52]) -/* "identity" */ -#define GRPC_MDSTR_IDENTITY (&grpc_static_mdstr_table[53]) -/* "identity,deflate" */ -#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE (&grpc_static_mdstr_table[54]) -/* "identity,deflate,gzip" */ -#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE_COMMA_GZIP \ - (&grpc_static_mdstr_table[55]) -/* "identity,gzip" */ -#define GRPC_MDSTR_IDENTITY_COMMA_GZIP (&grpc_static_mdstr_table[56]) -/* "if-match" */ -#define GRPC_MDSTR_IF_MATCH (&grpc_static_mdstr_table[57]) -/* "if-modified-since" */ -#define GRPC_MDSTR_IF_MODIFIED_SINCE (&grpc_static_mdstr_table[58]) -/* "if-none-match" */ -#define GRPC_MDSTR_IF_NONE_MATCH (&grpc_static_mdstr_table[59]) -/* "if-range" */ -#define GRPC_MDSTR_IF_RANGE (&grpc_static_mdstr_table[60]) -/* "if-unmodified-since" */ -#define GRPC_MDSTR_IF_UNMODIFIED_SINCE (&grpc_static_mdstr_table[61]) -/* "last-modified" */ -#define GRPC_MDSTR_LAST_MODIFIED (&grpc_static_mdstr_table[62]) -/* "link" */ -#define GRPC_MDSTR_LINK (&grpc_static_mdstr_table[63]) -/* "location" */ -#define GRPC_MDSTR_LOCATION (&grpc_static_mdstr_table[64]) -/* "max-forwards" */ -#define GRPC_MDSTR_MAX_FORWARDS (&grpc_static_mdstr_table[65]) -/* ":method" */ -#define GRPC_MDSTR_METHOD (&grpc_static_mdstr_table[66]) -/* ":path" */ -#define GRPC_MDSTR_PATH (&grpc_static_mdstr_table[67]) -/* "POST" */ -#define GRPC_MDSTR_POST (&grpc_static_mdstr_table[68]) -/* "proxy-authenticate" */ -#define GRPC_MDSTR_PROXY_AUTHENTICATE (&grpc_static_mdstr_table[69]) -/* "proxy-authorization" */ -#define GRPC_MDSTR_PROXY_AUTHORIZATION (&grpc_static_mdstr_table[70]) -/* "range" */ -#define GRPC_MDSTR_RANGE (&grpc_static_mdstr_table[71]) -/* "referer" */ -#define GRPC_MDSTR_REFERER (&grpc_static_mdstr_table[72]) -/* "refresh" */ -#define GRPC_MDSTR_REFRESH (&grpc_static_mdstr_table[73]) -/* "retry-after" */ -#define GRPC_MDSTR_RETRY_AFTER (&grpc_static_mdstr_table[74]) -/* ":scheme" */ -#define GRPC_MDSTR_SCHEME (&grpc_static_mdstr_table[75]) -/* "server" */ -#define GRPC_MDSTR_SERVER (&grpc_static_mdstr_table[76]) -/* "set-cookie" */ -#define GRPC_MDSTR_SET_COOKIE (&grpc_static_mdstr_table[77]) -/* "/" */ -#define GRPC_MDSTR_SLASH (&grpc_static_mdstr_table[78]) -/* "/index.html" */ -#define GRPC_MDSTR_SLASH_INDEX_DOT_HTML (&grpc_static_mdstr_table[79]) -/* ":status" */ -#define GRPC_MDSTR_STATUS (&grpc_static_mdstr_table[80]) -/* "strict-transport-security" */ -#define GRPC_MDSTR_STRICT_TRANSPORT_SECURITY (&grpc_static_mdstr_table[81]) -/* "te" */ -#define GRPC_MDSTR_TE (&grpc_static_mdstr_table[82]) -/* "trailers" */ -#define GRPC_MDSTR_TRAILERS (&grpc_static_mdstr_table[83]) -/* "transfer-encoding" */ -#define GRPC_MDSTR_TRANSFER_ENCODING (&grpc_static_mdstr_table[84]) -/* "user-agent" */ -#define GRPC_MDSTR_USER_AGENT (&grpc_static_mdstr_table[85]) -/* "vary" */ -#define GRPC_MDSTR_VARY (&grpc_static_mdstr_table[86]) -/* "via" */ -#define GRPC_MDSTR_VIA (&grpc_static_mdstr_table[87]) -/* "www-authenticate" */ -#define GRPC_MDSTR_WWW_AUTHENTICATE (&grpc_static_mdstr_table[88]) - -#define GRPC_STATIC_MDELEM_COUNT 78 -extern grpc_mdelem grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT]; -extern uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT]; -/* "accept-charset": "" */ -#define GRPC_MDELEM_ACCEPT_CHARSET_EMPTY (&grpc_static_mdelem_table[0]) -/* "accept": "" */ -#define GRPC_MDELEM_ACCEPT_EMPTY (&grpc_static_mdelem_table[1]) -/* "accept-encoding": "" */ -#define GRPC_MDELEM_ACCEPT_ENCODING_EMPTY (&grpc_static_mdelem_table[2]) -/* "accept-encoding": "gzip, deflate" */ -#define GRPC_MDELEM_ACCEPT_ENCODING_GZIP_COMMA_DEFLATE \ - (&grpc_static_mdelem_table[3]) -/* "accept-language": "" */ -#define GRPC_MDELEM_ACCEPT_LANGUAGE_EMPTY (&grpc_static_mdelem_table[4]) -/* "accept-ranges": "" */ -#define GRPC_MDELEM_ACCEPT_RANGES_EMPTY (&grpc_static_mdelem_table[5]) -/* "access-control-allow-origin": "" */ -#define GRPC_MDELEM_ACCESS_CONTROL_ALLOW_ORIGIN_EMPTY \ - (&grpc_static_mdelem_table[6]) -/* "age": "" */ -#define GRPC_MDELEM_AGE_EMPTY (&grpc_static_mdelem_table[7]) -/* "allow": "" */ -#define GRPC_MDELEM_ALLOW_EMPTY (&grpc_static_mdelem_table[8]) -/* ":authority": "" */ -#define GRPC_MDELEM_AUTHORITY_EMPTY (&grpc_static_mdelem_table[9]) -/* "authorization": "" */ -#define GRPC_MDELEM_AUTHORIZATION_EMPTY (&grpc_static_mdelem_table[10]) -/* "cache-control": "" */ -#define GRPC_MDELEM_CACHE_CONTROL_EMPTY (&grpc_static_mdelem_table[11]) -/* "content-disposition": "" */ -#define GRPC_MDELEM_CONTENT_DISPOSITION_EMPTY (&grpc_static_mdelem_table[12]) -/* "content-encoding": "" */ -#define GRPC_MDELEM_CONTENT_ENCODING_EMPTY (&grpc_static_mdelem_table[13]) -/* "content-language": "" */ -#define GRPC_MDELEM_CONTENT_LANGUAGE_EMPTY (&grpc_static_mdelem_table[14]) -/* "content-length": "" */ -#define GRPC_MDELEM_CONTENT_LENGTH_EMPTY (&grpc_static_mdelem_table[15]) -/* "content-location": "" */ -#define GRPC_MDELEM_CONTENT_LOCATION_EMPTY (&grpc_static_mdelem_table[16]) -/* "content-range": "" */ -#define GRPC_MDELEM_CONTENT_RANGE_EMPTY (&grpc_static_mdelem_table[17]) -/* "content-type": "application/grpc" */ -#define GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC \ - (&grpc_static_mdelem_table[18]) -/* "content-type": "" */ -#define GRPC_MDELEM_CONTENT_TYPE_EMPTY (&grpc_static_mdelem_table[19]) -/* "cookie": "" */ -#define GRPC_MDELEM_COOKIE_EMPTY (&grpc_static_mdelem_table[20]) -/* "date": "" */ -#define GRPC_MDELEM_DATE_EMPTY (&grpc_static_mdelem_table[21]) -/* "etag": "" */ -#define GRPC_MDELEM_ETAG_EMPTY (&grpc_static_mdelem_table[22]) -/* "expect": "" */ -#define GRPC_MDELEM_EXPECT_EMPTY (&grpc_static_mdelem_table[23]) -/* "expires": "" */ -#define GRPC_MDELEM_EXPIRES_EMPTY (&grpc_static_mdelem_table[24]) -/* "from": "" */ -#define GRPC_MDELEM_FROM_EMPTY (&grpc_static_mdelem_table[25]) -/* "grpc-accept-encoding": "deflate" */ -#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_DEFLATE (&grpc_static_mdelem_table[26]) -/* "grpc-accept-encoding": "deflate,gzip" */ -#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_DEFLATE_COMMA_GZIP \ - (&grpc_static_mdelem_table[27]) -/* "grpc-accept-encoding": "gzip" */ -#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_GZIP (&grpc_static_mdelem_table[28]) -/* "grpc-accept-encoding": "identity" */ -#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY \ - (&grpc_static_mdelem_table[29]) -/* "grpc-accept-encoding": "identity,deflate" */ -#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE \ - (&grpc_static_mdelem_table[30]) -/* "grpc-accept-encoding": "identity,deflate,gzip" */ -#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE_COMMA_GZIP \ - (&grpc_static_mdelem_table[31]) -/* "grpc-accept-encoding": "identity,gzip" */ -#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_GZIP \ - (&grpc_static_mdelem_table[32]) -/* "grpc-encoding": "deflate" */ -#define GRPC_MDELEM_GRPC_ENCODING_DEFLATE (&grpc_static_mdelem_table[33]) -/* "grpc-encoding": "gzip" */ -#define GRPC_MDELEM_GRPC_ENCODING_GZIP (&grpc_static_mdelem_table[34]) -/* "grpc-encoding": "identity" */ -#define GRPC_MDELEM_GRPC_ENCODING_IDENTITY (&grpc_static_mdelem_table[35]) -/* "grpc-status": "0" */ -#define GRPC_MDELEM_GRPC_STATUS_0 (&grpc_static_mdelem_table[36]) -/* "grpc-status": "1" */ -#define GRPC_MDELEM_GRPC_STATUS_1 (&grpc_static_mdelem_table[37]) -/* "grpc-status": "2" */ -#define GRPC_MDELEM_GRPC_STATUS_2 (&grpc_static_mdelem_table[38]) -/* "host": "" */ -#define GRPC_MDELEM_HOST_EMPTY (&grpc_static_mdelem_table[39]) -/* "if-match": "" */ -#define GRPC_MDELEM_IF_MATCH_EMPTY (&grpc_static_mdelem_table[40]) -/* "if-modified-since": "" */ -#define GRPC_MDELEM_IF_MODIFIED_SINCE_EMPTY (&grpc_static_mdelem_table[41]) -/* "if-none-match": "" */ -#define GRPC_MDELEM_IF_NONE_MATCH_EMPTY (&grpc_static_mdelem_table[42]) -/* "if-range": "" */ -#define GRPC_MDELEM_IF_RANGE_EMPTY (&grpc_static_mdelem_table[43]) -/* "if-unmodified-since": "" */ -#define GRPC_MDELEM_IF_UNMODIFIED_SINCE_EMPTY (&grpc_static_mdelem_table[44]) -/* "last-modified": "" */ -#define GRPC_MDELEM_LAST_MODIFIED_EMPTY (&grpc_static_mdelem_table[45]) -/* "link": "" */ -#define GRPC_MDELEM_LINK_EMPTY (&grpc_static_mdelem_table[46]) -/* "location": "" */ -#define GRPC_MDELEM_LOCATION_EMPTY (&grpc_static_mdelem_table[47]) -/* "max-forwards": "" */ -#define GRPC_MDELEM_MAX_FORWARDS_EMPTY (&grpc_static_mdelem_table[48]) -/* ":method": "GET" */ -#define GRPC_MDELEM_METHOD_GET (&grpc_static_mdelem_table[49]) -/* ":method": "POST" */ -#define GRPC_MDELEM_METHOD_POST (&grpc_static_mdelem_table[50]) -/* ":path": "/" */ -#define GRPC_MDELEM_PATH_SLASH (&grpc_static_mdelem_table[51]) -/* ":path": "/index.html" */ -#define GRPC_MDELEM_PATH_SLASH_INDEX_DOT_HTML (&grpc_static_mdelem_table[52]) -/* "proxy-authenticate": "" */ -#define GRPC_MDELEM_PROXY_AUTHENTICATE_EMPTY (&grpc_static_mdelem_table[53]) -/* "proxy-authorization": "" */ -#define GRPC_MDELEM_PROXY_AUTHORIZATION_EMPTY (&grpc_static_mdelem_table[54]) -/* "range": "" */ -#define GRPC_MDELEM_RANGE_EMPTY (&grpc_static_mdelem_table[55]) -/* "referer": "" */ -#define GRPC_MDELEM_REFERER_EMPTY (&grpc_static_mdelem_table[56]) -/* "refresh": "" */ -#define GRPC_MDELEM_REFRESH_EMPTY (&grpc_static_mdelem_table[57]) -/* "retry-after": "" */ -#define GRPC_MDELEM_RETRY_AFTER_EMPTY (&grpc_static_mdelem_table[58]) -/* ":scheme": "grpc" */ -#define GRPC_MDELEM_SCHEME_GRPC (&grpc_static_mdelem_table[59]) -/* ":scheme": "http" */ -#define GRPC_MDELEM_SCHEME_HTTP (&grpc_static_mdelem_table[60]) -/* ":scheme": "https" */ -#define GRPC_MDELEM_SCHEME_HTTPS (&grpc_static_mdelem_table[61]) -/* "server": "" */ -#define GRPC_MDELEM_SERVER_EMPTY (&grpc_static_mdelem_table[62]) -/* "set-cookie": "" */ -#define GRPC_MDELEM_SET_COOKIE_EMPTY (&grpc_static_mdelem_table[63]) -/* ":status": "200" */ -#define GRPC_MDELEM_STATUS_200 (&grpc_static_mdelem_table[64]) -/* ":status": "204" */ -#define GRPC_MDELEM_STATUS_204 (&grpc_static_mdelem_table[65]) -/* ":status": "206" */ -#define GRPC_MDELEM_STATUS_206 (&grpc_static_mdelem_table[66]) -/* ":status": "304" */ -#define GRPC_MDELEM_STATUS_304 (&grpc_static_mdelem_table[67]) -/* ":status": "400" */ -#define GRPC_MDELEM_STATUS_400 (&grpc_static_mdelem_table[68]) -/* ":status": "404" */ -#define GRPC_MDELEM_STATUS_404 (&grpc_static_mdelem_table[69]) -/* ":status": "500" */ -#define GRPC_MDELEM_STATUS_500 (&grpc_static_mdelem_table[70]) -/* "strict-transport-security": "" */ -#define GRPC_MDELEM_STRICT_TRANSPORT_SECURITY_EMPTY \ - (&grpc_static_mdelem_table[71]) -/* "te": "trailers" */ -#define GRPC_MDELEM_TE_TRAILERS (&grpc_static_mdelem_table[72]) -/* "transfer-encoding": "" */ -#define GRPC_MDELEM_TRANSFER_ENCODING_EMPTY (&grpc_static_mdelem_table[73]) -/* "user-agent": "" */ -#define GRPC_MDELEM_USER_AGENT_EMPTY (&grpc_static_mdelem_table[74]) -/* "vary": "" */ -#define GRPC_MDELEM_VARY_EMPTY (&grpc_static_mdelem_table[75]) -/* "via": "" */ -#define GRPC_MDELEM_VIA_EMPTY (&grpc_static_mdelem_table[76]) -/* "www-authenticate": "" */ -#define GRPC_MDELEM_WWW_AUTHENTICATE_EMPTY (&grpc_static_mdelem_table[77]) - -extern const uint8_t - grpc_static_metadata_elem_indices[GRPC_STATIC_MDELEM_COUNT * 2]; -extern const char *const grpc_static_metadata_strings[GRPC_STATIC_MDSTR_COUNT]; -extern const uint8_t grpc_static_accept_encoding_metadata[8]; -#define GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS(algs) \ - (&grpc_static_mdelem_table[grpc_static_accept_encoding_metadata[(algs)]]) -#endif /* GRPC_CORE_TRANSPORT_STATIC_METADATA_H */ diff --git a/src/core/transport/transport.c b/src/core/transport/transport.c deleted file mode 100644 index 3b555fa933..0000000000 --- a/src/core/transport/transport.c +++ /dev/null @@ -1,184 +0,0 @@ -/* - * - * Copyright 2015-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/transport/transport.h" -#include -#include -#include -#include "src/core/transport/transport_impl.h" - -#ifdef GRPC_STREAM_REFCOUNT_DEBUG -void grpc_stream_ref(grpc_stream_refcount *refcount, const char *reason) { - gpr_atm val = gpr_atm_no_barrier_load(&refcount->refs.count); - gpr_log(GPR_DEBUG, "%s %p:%p REF %d->%d %s", refcount->object_type, - refcount, refcount->destroy.cb_arg, val, val + 1, reason); -#else -void grpc_stream_ref(grpc_stream_refcount *refcount) { -#endif - gpr_ref_non_zero(&refcount->refs); -} - -#ifdef GRPC_STREAM_REFCOUNT_DEBUG -void grpc_stream_unref(grpc_exec_ctx *exec_ctx, grpc_stream_refcount *refcount, - const char *reason) { - gpr_atm val = gpr_atm_no_barrier_load(&refcount->refs.count); - gpr_log(GPR_DEBUG, "%s %p:%p UNREF %d->%d %s", refcount->object_type, - refcount, refcount->destroy.cb_arg, val, val - 1, reason); -#else -void grpc_stream_unref(grpc_exec_ctx *exec_ctx, - grpc_stream_refcount *refcount) { -#endif - if (gpr_unref(&refcount->refs)) { - grpc_exec_ctx_enqueue(exec_ctx, &refcount->destroy, true, NULL); - } -} - -#ifdef GRPC_STREAM_REFCOUNT_DEBUG -void grpc_stream_ref_init(grpc_stream_refcount *refcount, int initial_refs, - grpc_iomgr_cb_func cb, void *cb_arg, - const char *object_type) { - refcount->object_type = object_type; -#else -void grpc_stream_ref_init(grpc_stream_refcount *refcount, int initial_refs, - grpc_iomgr_cb_func cb, void *cb_arg) { -#endif - gpr_ref_init(&refcount->refs, initial_refs); - grpc_closure_init(&refcount->destroy, cb, cb_arg); -} - -size_t grpc_transport_stream_size(grpc_transport *transport) { - return transport->vtable->sizeof_stream; -} - -void grpc_transport_destroy(grpc_exec_ctx *exec_ctx, - grpc_transport *transport) { - transport->vtable->destroy(exec_ctx, transport); -} - -int grpc_transport_init_stream(grpc_exec_ctx *exec_ctx, - grpc_transport *transport, grpc_stream *stream, - grpc_stream_refcount *refcount, - const void *server_data) { - return transport->vtable->init_stream(exec_ctx, transport, stream, refcount, - server_data); -} - -void grpc_transport_perform_stream_op(grpc_exec_ctx *exec_ctx, - grpc_transport *transport, - grpc_stream *stream, - grpc_transport_stream_op *op) { - transport->vtable->perform_stream_op(exec_ctx, transport, stream, op); -} - -void grpc_transport_perform_op(grpc_exec_ctx *exec_ctx, - grpc_transport *transport, - grpc_transport_op *op) { - transport->vtable->perform_op(exec_ctx, transport, op); -} - -void grpc_transport_set_pollset(grpc_exec_ctx *exec_ctx, - grpc_transport *transport, grpc_stream *stream, - grpc_pollset *pollset) { - transport->vtable->set_pollset(exec_ctx, transport, stream, pollset); -} - -void grpc_transport_destroy_stream(grpc_exec_ctx *exec_ctx, - grpc_transport *transport, - grpc_stream *stream) { - transport->vtable->destroy_stream(exec_ctx, transport, stream); -} - -char *grpc_transport_get_peer(grpc_exec_ctx *exec_ctx, - grpc_transport *transport) { - return transport->vtable->get_peer(exec_ctx, transport); -} - -void grpc_transport_stream_op_finish_with_failure( - grpc_exec_ctx *exec_ctx, grpc_transport_stream_op *op) { - grpc_exec_ctx_enqueue(exec_ctx, op->recv_message_ready, false, NULL); - grpc_exec_ctx_enqueue(exec_ctx, op->recv_initial_metadata_ready, false, NULL); - grpc_exec_ctx_enqueue(exec_ctx, op->on_complete, false, NULL); -} - -void grpc_transport_stream_op_add_cancellation(grpc_transport_stream_op *op, - grpc_status_code status) { - GPR_ASSERT(status != GRPC_STATUS_OK); - if (op->cancel_with_status == GRPC_STATUS_OK) { - op->cancel_with_status = status; - } - if (op->close_with_status != GRPC_STATUS_OK) { - op->close_with_status = GRPC_STATUS_OK; - if (op->optional_close_message != NULL) { - gpr_slice_unref(*op->optional_close_message); - op->optional_close_message = NULL; - } - } -} - -typedef struct { - gpr_slice message; - grpc_closure *then_call; - grpc_closure closure; -} close_message_data; - -static void free_message(grpc_exec_ctx *exec_ctx, void *p, bool iomgr_success) { - close_message_data *cmd = p; - gpr_slice_unref(cmd->message); - if (cmd->then_call != NULL) { - cmd->then_call->cb(exec_ctx, cmd->then_call->cb_arg, iomgr_success); - } - gpr_free(cmd); -} - -void grpc_transport_stream_op_add_close(grpc_transport_stream_op *op, - grpc_status_code status, - gpr_slice *optional_message) { - close_message_data *cmd; - GPR_ASSERT(status != GRPC_STATUS_OK); - if (op->cancel_with_status != GRPC_STATUS_OK || - op->close_with_status != GRPC_STATUS_OK) { - if (optional_message) { - gpr_slice_unref(*optional_message); - } - return; - } - if (optional_message) { - cmd = gpr_malloc(sizeof(*cmd)); - cmd->message = *optional_message; - cmd->then_call = op->on_complete; - grpc_closure_init(&cmd->closure, free_message, cmd); - op->on_complete = &cmd->closure; - op->optional_close_message = &cmd->message; - } - op->close_with_status = status; -} diff --git a/src/core/transport/transport.h b/src/core/transport/transport.h deleted file mode 100644 index f43e56f23c..0000000000 --- a/src/core/transport/transport.h +++ /dev/null @@ -1,242 +0,0 @@ -/* - * - * Copyright 2015-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_TRANSPORT_TRANSPORT_H -#define GRPC_CORE_TRANSPORT_TRANSPORT_H - -#include - -#include "src/core/channel/context.h" -#include "src/core/iomgr/pollset.h" -#include "src/core/iomgr/pollset_set.h" -#include "src/core/transport/byte_stream.h" -#include "src/core/transport/metadata_batch.h" - -/* forward declarations */ -typedef struct grpc_transport grpc_transport; - -/* grpc_stream doesn't actually exist. It's used as a typesafe - opaque pointer for whatever data the transport wants to track - for a stream. */ -typedef struct grpc_stream grpc_stream; - -/*#define GRPC_STREAM_REFCOUNT_DEBUG*/ - -typedef struct grpc_stream_refcount { - gpr_refcount refs; - grpc_closure destroy; -#ifdef GRPC_STREAM_REFCOUNT_DEBUG - const char *object_type; -#endif -} grpc_stream_refcount; - -#ifdef GRPC_STREAM_REFCOUNT_DEBUG -void grpc_stream_ref_init(grpc_stream_refcount *refcount, int initial_refs, - grpc_iomgr_cb_func cb, void *cb_arg, - const char *object_type); -void grpc_stream_ref(grpc_stream_refcount *refcount, const char *reason); -void grpc_stream_unref(grpc_exec_ctx *exec_ctx, grpc_stream_refcount *refcount, - const char *reason); -#define GRPC_STREAM_REF_INIT(rc, ir, cb, cb_arg, objtype) \ - grpc_stream_ref_init(rc, ir, cb, cb_arg, objtype) -#else -void grpc_stream_ref_init(grpc_stream_refcount *refcount, int initial_refs, - grpc_iomgr_cb_func cb, void *cb_arg); -void grpc_stream_ref(grpc_stream_refcount *refcount); -void grpc_stream_unref(grpc_exec_ctx *exec_ctx, grpc_stream_refcount *refcount); -#define GRPC_STREAM_REF_INIT(rc, ir, cb, cb_arg, objtype) \ - grpc_stream_ref_init(rc, ir, cb, cb_arg) -#endif - -/* Transport stream op: a set of operations to perform on a transport - against a single stream */ -typedef struct grpc_transport_stream_op { - /** Send initial metadata to the peer, from the provided metadata batch. */ - grpc_metadata_batch *send_initial_metadata; - - /** Send trailing metadata to the peer, from the provided metadata batch. */ - grpc_metadata_batch *send_trailing_metadata; - - /** Send message data to the peer, from the provided byte stream. */ - grpc_byte_stream *send_message; - - /** Receive initial metadata from the stream, into provided metadata batch. */ - grpc_metadata_batch *recv_initial_metadata; - /** Should be enqueued when initial metadata is ready to be processed. */ - grpc_closure *recv_initial_metadata_ready; - - /** Receive message data from the stream, into provided byte stream. */ - grpc_byte_stream **recv_message; - /** Should be enqueued when one message is ready to be processed. */ - grpc_closure *recv_message_ready; - - /** Receive trailing metadata from the stream, into provided metadata batch. - */ - grpc_metadata_batch *recv_trailing_metadata; - - /** Should be enqueued when all requested operations (excluding recv_message - and recv_initial_metadata which have their own closures) in a given batch - have been completed. */ - grpc_closure *on_complete; - - /** If != GRPC_STATUS_OK, cancel this stream */ - grpc_status_code cancel_with_status; - - /** If != GRPC_STATUS_OK, send grpc-status, grpc-message, and close this - stream for both reading and writing */ - grpc_status_code close_with_status; - gpr_slice *optional_close_message; - - /* Indexes correspond to grpc_context_index enum values */ - grpc_call_context_element *context; -} grpc_transport_stream_op; - -/** Transport op: a set of operations to perform on a transport as a whole */ -typedef struct grpc_transport_op { - /** Called when processing of this op is done. */ - grpc_closure *on_consumed; - /** connectivity monitoring - set connectivity_state to NULL to unsubscribe */ - grpc_closure *on_connectivity_state_change; - grpc_connectivity_state *connectivity_state; - /** should the transport be disconnected */ - int disconnect; - /** should we send a goaway? - after a goaway is sent, once there are no more active calls on - the transport, the transport should disconnect */ - int send_goaway; - /** what should the goaway contain? */ - grpc_status_code goaway_status; - gpr_slice *goaway_message; - /** set the callback for accepting new streams; - this is a permanent callback, unlike the other one-shot closures. - If true, the callback is set to set_accept_stream_fn, with its - user_data argument set to set_accept_stream_user_data */ - bool set_accept_stream; - void (*set_accept_stream_fn)(grpc_exec_ctx *exec_ctx, void *user_data, - grpc_transport *transport, - const void *server_data); - void *set_accept_stream_user_data; - /** add this transport to a pollset */ - grpc_pollset *bind_pollset; - /** add this transport to a pollset_set */ - grpc_pollset_set *bind_pollset_set; - /** send a ping, call this back if not NULL */ - grpc_closure *send_ping; -} grpc_transport_op; - -/* Returns the amount of memory required to store a grpc_stream for this - transport */ -size_t grpc_transport_stream_size(grpc_transport *transport); - -/* Initialize transport data for a stream. - - Returns 0 on success, any other (transport-defined) value for failure. - - Arguments: - transport - the transport on which to create this stream - stream - a pointer to uninitialized memory to initialize - server_data - either NULL for a client initiated stream, or a pointer - supplied from the accept_stream callback function */ -int grpc_transport_init_stream(grpc_exec_ctx *exec_ctx, - grpc_transport *transport, grpc_stream *stream, - grpc_stream_refcount *refcount, - const void *server_data); - -void grpc_transport_set_pollset(grpc_exec_ctx *exec_ctx, - grpc_transport *transport, grpc_stream *stream, - grpc_pollset *pollset); - -/* Destroy transport data for a stream. - - Requires: a recv_batch with final_state == GRPC_STREAM_CLOSED has been - received by the up-layer. Must not be called in the same call stack as - recv_frame. - - Arguments: - transport - the transport on which to create this stream - stream - the grpc_stream to destroy (memory is still owned by the - caller, but any child memory must be cleaned up) */ -void grpc_transport_destroy_stream(grpc_exec_ctx *exec_ctx, - grpc_transport *transport, - grpc_stream *stream); - -void grpc_transport_stream_op_finish_with_failure(grpc_exec_ctx *exec_ctx, - grpc_transport_stream_op *op); - -void grpc_transport_stream_op_add_cancellation(grpc_transport_stream_op *op, - grpc_status_code status); - -void grpc_transport_stream_op_add_close(grpc_transport_stream_op *op, - grpc_status_code status, - gpr_slice *optional_message); - -char *grpc_transport_stream_op_string(grpc_transport_stream_op *op); - -/* Send a batch of operations on a transport - - Takes ownership of any objects contained in ops. - - Arguments: - transport - the transport on which to initiate the stream - stream - the stream on which to send the operations. This must be - non-NULL and previously initialized by the same transport. - op - a grpc_transport_stream_op specifying the op to perform */ -void grpc_transport_perform_stream_op(grpc_exec_ctx *exec_ctx, - grpc_transport *transport, - grpc_stream *stream, - grpc_transport_stream_op *op); - -void grpc_transport_perform_op(grpc_exec_ctx *exec_ctx, - grpc_transport *transport, - grpc_transport_op *op); - -/* Send a ping on a transport - - Calls cb with user data when a response is received. */ -void grpc_transport_ping(grpc_transport *transport, grpc_closure *cb); - -/* Advise peer of pending connection termination. */ -void grpc_transport_goaway(grpc_transport *transport, grpc_status_code status, - gpr_slice debug_data); - -/* Close a transport. Aborts all open streams. */ -void grpc_transport_close(grpc_transport *transport); - -/* Destroy the transport */ -void grpc_transport_destroy(grpc_exec_ctx *exec_ctx, grpc_transport *transport); - -/* Get the transports peer */ -char *grpc_transport_get_peer(grpc_exec_ctx *exec_ctx, - grpc_transport *transport); - -#endif /* GRPC_CORE_TRANSPORT_TRANSPORT_H */ diff --git a/src/core/transport/transport_impl.h b/src/core/transport/transport_impl.h deleted file mode 100644 index d9ecc4d2ba..0000000000 --- a/src/core/transport/transport_impl.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * - * Copyright 2015-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_TRANSPORT_TRANSPORT_IMPL_H -#define GRPC_CORE_TRANSPORT_TRANSPORT_IMPL_H - -#include "src/core/transport/transport.h" - -typedef struct grpc_transport_vtable { - /* Memory required for a single stream element - this is allocated by upper - layers and initialized by the transport */ - size_t sizeof_stream; /* = sizeof(transport stream) */ - - /* name of this transport implementation */ - const char *name; - - /* implementation of grpc_transport_init_stream */ - int (*init_stream)(grpc_exec_ctx *exec_ctx, grpc_transport *self, - grpc_stream *stream, grpc_stream_refcount *refcount, - const void *server_data); - - /* implementation of grpc_transport_set_pollset */ - void (*set_pollset)(grpc_exec_ctx *exec_ctx, grpc_transport *self, - grpc_stream *stream, grpc_pollset *pollset); - - /* implementation of grpc_transport_perform_stream_op */ - void (*perform_stream_op)(grpc_exec_ctx *exec_ctx, grpc_transport *self, - grpc_stream *stream, grpc_transport_stream_op *op); - - /* implementation of grpc_transport_perform_op */ - void (*perform_op)(grpc_exec_ctx *exec_ctx, grpc_transport *self, - grpc_transport_op *op); - - /* implementation of grpc_transport_destroy_stream */ - void (*destroy_stream)(grpc_exec_ctx *exec_ctx, grpc_transport *self, - grpc_stream *stream); - - /* implementation of grpc_transport_destroy */ - void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_transport *self); - - /* implementation of grpc_transport_get_peer */ - char *(*get_peer)(grpc_exec_ctx *exec_ctx, grpc_transport *self); -} grpc_transport_vtable; - -/* an instance of a grpc transport */ -struct grpc_transport { - /* pointer to a vtable defining operations on this transport */ - const grpc_transport_vtable *vtable; -}; - -#endif /* GRPC_CORE_TRANSPORT_TRANSPORT_IMPL_H */ diff --git a/src/core/transport/transport_op_string.c b/src/core/transport/transport_op_string.c deleted file mode 100644 index 8453412480..0000000000 --- a/src/core/transport/transport_op_string.c +++ /dev/null @@ -1,140 +0,0 @@ -/* - * - * Copyright 2015-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/channel/channel_stack.h" - -#include -#include -#include - -#include -#include -#include -#include "src/core/support/string.h" - -/* These routines are here to facilitate debugging - they produce string - representations of various transport data structures */ - -static void put_metadata(gpr_strvec *b, grpc_mdelem *md) { - gpr_strvec_add(b, gpr_strdup("key=")); - gpr_strvec_add(b, - gpr_dump_slice(md->key->slice, GPR_DUMP_HEX | GPR_DUMP_ASCII)); - - gpr_strvec_add(b, gpr_strdup(" value=")); - gpr_strvec_add( - b, gpr_dump_slice(md->value->slice, GPR_DUMP_HEX | GPR_DUMP_ASCII)); -} - -static void put_metadata_list(gpr_strvec *b, grpc_metadata_batch md) { - grpc_linked_mdelem *m; - for (m = md.list.head; m != NULL; m = m->next) { - if (m != md.list.head) gpr_strvec_add(b, gpr_strdup(", ")); - put_metadata(b, m->md); - } - if (gpr_time_cmp(md.deadline, gpr_inf_future(md.deadline.clock_type)) != 0) { - char *tmp; - gpr_asprintf(&tmp, " deadline=%lld.%09d", (long long)md.deadline.tv_sec, - (int)md.deadline.tv_nsec); - gpr_strvec_add(b, tmp); - } -} - -char *grpc_transport_stream_op_string(grpc_transport_stream_op *op) { - char *tmp; - char *out; - int first = 1; - - gpr_strvec b; - gpr_strvec_init(&b); - - if (op->send_initial_metadata != NULL) { - if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); - first = 0; - gpr_strvec_add(&b, gpr_strdup("SEND_INITIAL_METADATA{")); - put_metadata_list(&b, *op->send_initial_metadata); - gpr_strvec_add(&b, gpr_strdup("}")); - } - - if (op->send_message != NULL) { - if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); - first = 0; - gpr_asprintf(&tmp, "SEND_MESSAGE:flags=0x%08x:len=%d", - op->send_message->flags, op->send_message->length); - gpr_strvec_add(&b, tmp); - } - - if (op->send_trailing_metadata != NULL) { - if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); - first = 0; - gpr_strvec_add(&b, gpr_strdup("SEND_TRAILING_METADATA{")); - put_metadata_list(&b, *op->send_trailing_metadata); - gpr_strvec_add(&b, gpr_strdup("}")); - } - - if (op->recv_initial_metadata != NULL) { - if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); - first = 0; - gpr_strvec_add(&b, gpr_strdup("RECV_INITIAL_METADATA")); - } - - if (op->recv_message != NULL) { - if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); - first = 0; - gpr_strvec_add(&b, gpr_strdup("RECV_MESSAGE")); - } - - if (op->recv_trailing_metadata != NULL) { - if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); - first = 0; - gpr_strvec_add(&b, gpr_strdup("RECV_TRAILING_METADATA")); - } - - if (op->cancel_with_status != GRPC_STATUS_OK) { - if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); - first = 0; - gpr_asprintf(&tmp, "CANCEL:%d", op->cancel_with_status); - gpr_strvec_add(&b, tmp); - } - - out = gpr_strvec_flatten(&b, NULL); - gpr_strvec_destroy(&b); - - return out; -} - -void grpc_call_log_op(char *file, int line, gpr_log_severity severity, - grpc_call_element *elem, grpc_transport_stream_op *op) { - char *str = grpc_transport_stream_op_string(op); - gpr_log(file, line, severity, "OP[%s:%p]: %s", elem->filter->name, elem, str); - gpr_free(str); -} diff --git a/src/core/tsi/fake_transport_security.c b/src/core/tsi/fake_transport_security.c deleted file mode 100644 index c0106f7a33..0000000000 --- a/src/core/tsi/fake_transport_security.c +++ /dev/null @@ -1,527 +0,0 @@ -/* - * - * Copyright 2015-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/tsi/fake_transport_security.h" - -#include -#include - -#include -#include -#include -#include "src/core/tsi/transport_security.h" - -/* --- Constants. ---*/ -#define TSI_FAKE_FRAME_HEADER_SIZE 4 -#define TSI_FAKE_FRAME_INITIAL_ALLOCATED_SIZE 64 -#define TSI_FAKE_DEFAULT_FRAME_SIZE 16384 - -/* --- Structure definitions. ---*/ - -/* a frame is encoded like this: - | size | data | - where the size field value is the size of the size field plus the size of - the data encoded in little endian on 4 bytes. */ -typedef struct { - unsigned char *data; - size_t size; - size_t allocated_size; - size_t offset; - int needs_draining; -} tsi_fake_frame; - -typedef enum { - TSI_FAKE_CLIENT_INIT = 0, - TSI_FAKE_SERVER_INIT = 1, - TSI_FAKE_CLIENT_FINISHED = 2, - TSI_FAKE_SERVER_FINISHED = 3, - TSI_FAKE_HANDSHAKE_MESSAGE_MAX = 4 -} tsi_fake_handshake_message; - -typedef struct { - tsi_handshaker base; - int is_client; - tsi_fake_handshake_message next_message_to_send; - int needs_incoming_message; - tsi_fake_frame incoming; - tsi_fake_frame outgoing; - tsi_result result; -} tsi_fake_handshaker; - -typedef struct { - tsi_frame_protector base; - tsi_fake_frame protect_frame; - tsi_fake_frame unprotect_frame; - size_t max_frame_size; -} tsi_fake_frame_protector; - -/* --- Utils. ---*/ - -static const char *tsi_fake_handshake_message_strings[] = { - "CLIENT_INIT", "SERVER_INIT", "CLIENT_FINISHED", "SERVER_FINISHED"}; - -static const char *tsi_fake_handshake_message_to_string(int msg) { - if (msg < 0 || msg >= TSI_FAKE_HANDSHAKE_MESSAGE_MAX) { - gpr_log(GPR_ERROR, "Invalid message %d", msg); - return "UNKNOWN"; - } - return tsi_fake_handshake_message_strings[msg]; -} - -static tsi_result tsi_fake_handshake_message_from_string( - const char *msg_string, tsi_fake_handshake_message *msg) { - tsi_fake_handshake_message i; - for (i = 0; i < TSI_FAKE_HANDSHAKE_MESSAGE_MAX; i++) { - if (strncmp(msg_string, tsi_fake_handshake_message_strings[i], - strlen(tsi_fake_handshake_message_strings[i])) == 0) { - *msg = i; - return TSI_OK; - } - } - gpr_log(GPR_ERROR, "Invalid handshake message."); - return TSI_DATA_CORRUPTED; -} - -static uint32_t load32_little_endian(const unsigned char *buf) { - return ((uint32_t)(buf[0]) | (uint32_t)(buf[1] << 8) | - (uint32_t)(buf[2] << 16) | (uint32_t)(buf[3] << 24)); -} - -static void store32_little_endian(uint32_t value, unsigned char *buf) { - buf[3] = (unsigned char)((value >> 24) & 0xFF); - buf[2] = (unsigned char)((value >> 16) & 0xFF); - buf[1] = (unsigned char)((value >> 8) & 0xFF); - buf[0] = (unsigned char)((value)&0xFF); -} - -static void tsi_fake_frame_reset(tsi_fake_frame *frame, int needs_draining) { - frame->offset = 0; - frame->needs_draining = needs_draining; - if (!needs_draining) frame->size = 0; -} - -/* Returns 1 if successful, 0 otherwise. */ -static int tsi_fake_frame_ensure_size(tsi_fake_frame *frame) { - if (frame->data == NULL) { - frame->allocated_size = frame->size; - frame->data = malloc(frame->allocated_size); - if (frame->data == NULL) return 0; - } else if (frame->size > frame->allocated_size) { - unsigned char *new_data = realloc(frame->data, frame->size); - if (new_data == NULL) { - free(frame->data); - frame->data = NULL; - return 0; - } - frame->data = new_data; - frame->allocated_size = frame->size; - } - return 1; -} - -/* This method should not be called if frame->needs_framing is not 0. */ -static tsi_result fill_frame_from_bytes(const unsigned char *incoming_bytes, - size_t *incoming_bytes_size, - tsi_fake_frame *frame) { - size_t available_size = *incoming_bytes_size; - size_t to_read_size = 0; - const unsigned char *bytes_cursor = incoming_bytes; - - if (frame->needs_draining) return TSI_INTERNAL_ERROR; - if (frame->data == NULL) { - frame->allocated_size = TSI_FAKE_FRAME_INITIAL_ALLOCATED_SIZE; - frame->data = malloc(frame->allocated_size); - if (frame->data == NULL) return TSI_OUT_OF_RESOURCES; - } - - if (frame->offset < TSI_FAKE_FRAME_HEADER_SIZE) { - to_read_size = TSI_FAKE_FRAME_HEADER_SIZE - frame->offset; - if (to_read_size > available_size) { - /* Just fill what we can and exit. */ - memcpy(frame->data + frame->offset, bytes_cursor, available_size); - bytes_cursor += available_size; - frame->offset += available_size; - *incoming_bytes_size = (size_t)(bytes_cursor - incoming_bytes); - return TSI_INCOMPLETE_DATA; - } - memcpy(frame->data + frame->offset, bytes_cursor, to_read_size); - bytes_cursor += to_read_size; - frame->offset += to_read_size; - available_size -= to_read_size; - frame->size = load32_little_endian(frame->data); - if (!tsi_fake_frame_ensure_size(frame)) return TSI_OUT_OF_RESOURCES; - } - - to_read_size = frame->size - frame->offset; - if (to_read_size > available_size) { - memcpy(frame->data + frame->offset, bytes_cursor, available_size); - frame->offset += available_size; - bytes_cursor += available_size; - *incoming_bytes_size = (size_t)(bytes_cursor - incoming_bytes); - return TSI_INCOMPLETE_DATA; - } - memcpy(frame->data + frame->offset, bytes_cursor, to_read_size); - bytes_cursor += to_read_size; - *incoming_bytes_size = (size_t)(bytes_cursor - incoming_bytes); - tsi_fake_frame_reset(frame, 1 /* needs_draining */); - return TSI_OK; -} - -/* This method should not be called if frame->needs_framing is 0. */ -static tsi_result drain_frame_to_bytes(unsigned char *outgoing_bytes, - size_t *outgoing_bytes_size, - tsi_fake_frame *frame) { - size_t to_write_size = frame->size - frame->offset; - if (!frame->needs_draining) return TSI_INTERNAL_ERROR; - if (*outgoing_bytes_size < to_write_size) { - memcpy(outgoing_bytes, frame->data + frame->offset, *outgoing_bytes_size); - frame->offset += *outgoing_bytes_size; - return TSI_INCOMPLETE_DATA; - } - memcpy(outgoing_bytes, frame->data + frame->offset, to_write_size); - *outgoing_bytes_size = to_write_size; - tsi_fake_frame_reset(frame, 0 /* needs_draining */); - return TSI_OK; -} - -static tsi_result bytes_to_frame(unsigned char *bytes, size_t bytes_size, - tsi_fake_frame *frame) { - frame->offset = 0; - frame->size = bytes_size + TSI_FAKE_FRAME_HEADER_SIZE; - if (!tsi_fake_frame_ensure_size(frame)) return TSI_OUT_OF_RESOURCES; - store32_little_endian((uint32_t)frame->size, frame->data); - memcpy(frame->data + TSI_FAKE_FRAME_HEADER_SIZE, bytes, bytes_size); - tsi_fake_frame_reset(frame, 1 /* needs draining */); - return TSI_OK; -} - -static void tsi_fake_frame_destruct(tsi_fake_frame *frame) { - if (frame->data != NULL) free(frame->data); -} - -/* --- tsi_frame_protector methods implementation. ---*/ - -static tsi_result fake_protector_protect(tsi_frame_protector *self, - const unsigned char *unprotected_bytes, - size_t *unprotected_bytes_size, - unsigned char *protected_output_frames, - size_t *protected_output_frames_size) { - tsi_result result = TSI_OK; - tsi_fake_frame_protector *impl = (tsi_fake_frame_protector *)self; - unsigned char frame_header[TSI_FAKE_FRAME_HEADER_SIZE]; - tsi_fake_frame *frame = &impl->protect_frame; - size_t saved_output_size = *protected_output_frames_size; - size_t drained_size = 0; - size_t *num_bytes_written = protected_output_frames_size; - *num_bytes_written = 0; - - /* Try to drain first. */ - if (frame->needs_draining) { - drained_size = saved_output_size - *num_bytes_written; - result = - drain_frame_to_bytes(protected_output_frames, &drained_size, frame); - *num_bytes_written += drained_size; - protected_output_frames += drained_size; - if (result != TSI_OK) { - if (result == TSI_INCOMPLETE_DATA) { - *unprotected_bytes_size = 0; - result = TSI_OK; - } - return result; - } - } - - /* Now process the unprotected_bytes. */ - if (frame->needs_draining) return TSI_INTERNAL_ERROR; - if (frame->size == 0) { - /* New frame, create a header. */ - size_t written_in_frame_size = 0; - store32_little_endian((uint32_t)impl->max_frame_size, frame_header); - written_in_frame_size = TSI_FAKE_FRAME_HEADER_SIZE; - result = fill_frame_from_bytes(frame_header, &written_in_frame_size, frame); - if (result != TSI_INCOMPLETE_DATA) { - gpr_log(GPR_ERROR, "fill_frame_from_bytes returned %s", - tsi_result_to_string(result)); - return result; - } - } - result = - fill_frame_from_bytes(unprotected_bytes, unprotected_bytes_size, frame); - if (result != TSI_OK) { - if (result == TSI_INCOMPLETE_DATA) result = TSI_OK; - return result; - } - - /* Try to drain again. */ - if (!frame->needs_draining) return TSI_INTERNAL_ERROR; - if (frame->offset != 0) return TSI_INTERNAL_ERROR; - drained_size = saved_output_size - *num_bytes_written; - result = drain_frame_to_bytes(protected_output_frames, &drained_size, frame); - *num_bytes_written += drained_size; - if (result == TSI_INCOMPLETE_DATA) result = TSI_OK; - return result; -} - -static tsi_result fake_protector_protect_flush( - tsi_frame_protector *self, unsigned char *protected_output_frames, - size_t *protected_output_frames_size, size_t *still_pending_size) { - tsi_result result = TSI_OK; - tsi_fake_frame_protector *impl = (tsi_fake_frame_protector *)self; - tsi_fake_frame *frame = &impl->protect_frame; - if (!frame->needs_draining) { - /* Create a short frame. */ - frame->size = frame->offset; - frame->offset = 0; - frame->needs_draining = 1; - store32_little_endian((uint32_t)frame->size, - frame->data); /* Overwrite header. */ - } - result = drain_frame_to_bytes(protected_output_frames, - protected_output_frames_size, frame); - if (result == TSI_INCOMPLETE_DATA) result = TSI_OK; - *still_pending_size = frame->size - frame->offset; - return result; -} - -static tsi_result fake_protector_unprotect( - tsi_frame_protector *self, const unsigned char *protected_frames_bytes, - size_t *protected_frames_bytes_size, unsigned char *unprotected_bytes, - size_t *unprotected_bytes_size) { - tsi_result result = TSI_OK; - tsi_fake_frame_protector *impl = (tsi_fake_frame_protector *)self; - tsi_fake_frame *frame = &impl->unprotect_frame; - size_t saved_output_size = *unprotected_bytes_size; - size_t drained_size = 0; - size_t *num_bytes_written = unprotected_bytes_size; - *num_bytes_written = 0; - - /* Try to drain first. */ - if (frame->needs_draining) { - /* Go past the header if needed. */ - if (frame->offset == 0) frame->offset = TSI_FAKE_FRAME_HEADER_SIZE; - drained_size = saved_output_size - *num_bytes_written; - result = drain_frame_to_bytes(unprotected_bytes, &drained_size, frame); - unprotected_bytes += drained_size; - *num_bytes_written += drained_size; - if (result != TSI_OK) { - if (result == TSI_INCOMPLETE_DATA) { - *protected_frames_bytes_size = 0; - result = TSI_OK; - } - return result; - } - } - - /* Now process the protected_bytes. */ - if (frame->needs_draining) return TSI_INTERNAL_ERROR; - result = fill_frame_from_bytes(protected_frames_bytes, - protected_frames_bytes_size, frame); - if (result != TSI_OK) { - if (result == TSI_INCOMPLETE_DATA) result = TSI_OK; - return result; - } - - /* Try to drain again. */ - if (!frame->needs_draining) return TSI_INTERNAL_ERROR; - if (frame->offset != 0) return TSI_INTERNAL_ERROR; - frame->offset = TSI_FAKE_FRAME_HEADER_SIZE; /* Go past the header. */ - drained_size = saved_output_size - *num_bytes_written; - result = drain_frame_to_bytes(unprotected_bytes, &drained_size, frame); - *num_bytes_written += drained_size; - if (result == TSI_INCOMPLETE_DATA) result = TSI_OK; - return result; -} - -static void fake_protector_destroy(tsi_frame_protector *self) { - tsi_fake_frame_protector *impl = (tsi_fake_frame_protector *)self; - tsi_fake_frame_destruct(&impl->protect_frame); - tsi_fake_frame_destruct(&impl->unprotect_frame); - free(self); -} - -static const tsi_frame_protector_vtable frame_protector_vtable = { - fake_protector_protect, fake_protector_protect_flush, - fake_protector_unprotect, fake_protector_destroy, -}; - -/* --- tsi_handshaker methods implementation. ---*/ - -static tsi_result fake_handshaker_get_bytes_to_send_to_peer( - tsi_handshaker *self, unsigned char *bytes, size_t *bytes_size) { - tsi_fake_handshaker *impl = (tsi_fake_handshaker *)self; - tsi_result result = TSI_OK; - if (impl->needs_incoming_message || impl->result == TSI_OK) { - *bytes_size = 0; - return TSI_OK; - } - if (!impl->outgoing.needs_draining) { - tsi_fake_handshake_message next_message_to_send = - impl->next_message_to_send + 2; - const char *msg_string = - tsi_fake_handshake_message_to_string(impl->next_message_to_send); - result = bytes_to_frame((unsigned char *)msg_string, strlen(msg_string), - &impl->outgoing); - if (result != TSI_OK) return result; - if (next_message_to_send > TSI_FAKE_HANDSHAKE_MESSAGE_MAX) { - next_message_to_send = TSI_FAKE_HANDSHAKE_MESSAGE_MAX; - } - if (tsi_tracing_enabled) { - gpr_log(GPR_INFO, "%s prepared %s.", - impl->is_client ? "Client" : "Server", - tsi_fake_handshake_message_to_string(impl->next_message_to_send)); - } - impl->next_message_to_send = next_message_to_send; - } - result = drain_frame_to_bytes(bytes, bytes_size, &impl->outgoing); - if (result != TSI_OK) return result; - if (!impl->is_client && - impl->next_message_to_send == TSI_FAKE_HANDSHAKE_MESSAGE_MAX) { - /* We're done. */ - if (tsi_tracing_enabled) { - gpr_log(GPR_INFO, "Server is done."); - } - impl->result = TSI_OK; - } else { - impl->needs_incoming_message = 1; - } - return TSI_OK; -} - -static tsi_result fake_handshaker_process_bytes_from_peer( - tsi_handshaker *self, const unsigned char *bytes, size_t *bytes_size) { - tsi_result result = TSI_OK; - tsi_fake_handshaker *impl = (tsi_fake_handshaker *)self; - tsi_fake_handshake_message expected_msg = impl->next_message_to_send - 1; - tsi_fake_handshake_message received_msg; - - if (!impl->needs_incoming_message || impl->result == TSI_OK) { - *bytes_size = 0; - return TSI_OK; - } - result = fill_frame_from_bytes(bytes, bytes_size, &impl->incoming); - if (result != TSI_OK) return result; - - /* We now have a complete frame. */ - result = tsi_fake_handshake_message_from_string( - (const char *)impl->incoming.data + TSI_FAKE_FRAME_HEADER_SIZE, - &received_msg); - if (result != TSI_OK) { - impl->result = result; - return result; - } - if (received_msg != expected_msg) { - gpr_log(GPR_ERROR, "Invalid received message (%s instead of %s)", - tsi_fake_handshake_message_to_string(received_msg), - tsi_fake_handshake_message_to_string(expected_msg)); - } - if (tsi_tracing_enabled) { - gpr_log(GPR_INFO, "%s received %s.", impl->is_client ? "Client" : "Server", - tsi_fake_handshake_message_to_string(received_msg)); - } - tsi_fake_frame_reset(&impl->incoming, 0 /* needs_draining */); - impl->needs_incoming_message = 0; - if (impl->next_message_to_send == TSI_FAKE_HANDSHAKE_MESSAGE_MAX) { - /* We're done. */ - if (tsi_tracing_enabled) { - gpr_log(GPR_INFO, "%s is done.", impl->is_client ? "Client" : "Server"); - } - impl->result = TSI_OK; - } - return TSI_OK; -} - -static tsi_result fake_handshaker_get_result(tsi_handshaker *self) { - tsi_fake_handshaker *impl = (tsi_fake_handshaker *)self; - return impl->result; -} - -static tsi_result fake_handshaker_extract_peer(tsi_handshaker *self, - tsi_peer *peer) { - tsi_result result = tsi_construct_peer(1, peer); - if (result != TSI_OK) return result; - result = tsi_construct_string_peer_property_from_cstring( - TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_FAKE_CERTIFICATE_TYPE, - &peer->properties[0]); - if (result != TSI_OK) tsi_peer_destruct(peer); - return result; -} - -static tsi_result fake_handshaker_create_frame_protector( - tsi_handshaker *self, size_t *max_protected_frame_size, - tsi_frame_protector **protector) { - *protector = tsi_create_fake_protector(max_protected_frame_size); - if (*protector == NULL) return TSI_OUT_OF_RESOURCES; - return TSI_OK; -} - -static void fake_handshaker_destroy(tsi_handshaker *self) { - tsi_fake_handshaker *impl = (tsi_fake_handshaker *)self; - tsi_fake_frame_destruct(&impl->incoming); - tsi_fake_frame_destruct(&impl->outgoing); - free(self); -} - -static const tsi_handshaker_vtable handshaker_vtable = { - fake_handshaker_get_bytes_to_send_to_peer, - fake_handshaker_process_bytes_from_peer, - fake_handshaker_get_result, - fake_handshaker_extract_peer, - fake_handshaker_create_frame_protector, - fake_handshaker_destroy, -}; - -tsi_handshaker *tsi_create_fake_handshaker(int is_client) { - tsi_fake_handshaker *impl = calloc(1, sizeof(tsi_fake_handshaker)); - impl->base.vtable = &handshaker_vtable; - impl->is_client = is_client; - impl->result = TSI_HANDSHAKE_IN_PROGRESS; - if (is_client) { - impl->needs_incoming_message = 0; - impl->next_message_to_send = TSI_FAKE_CLIENT_INIT; - } else { - impl->needs_incoming_message = 1; - impl->next_message_to_send = TSI_FAKE_SERVER_INIT; - } - return &impl->base; -} - -tsi_frame_protector *tsi_create_fake_protector( - size_t *max_protected_frame_size) { - tsi_fake_frame_protector *impl = calloc(1, sizeof(tsi_fake_frame_protector)); - if (impl == NULL) return NULL; - impl->max_frame_size = (max_protected_frame_size == NULL) - ? TSI_FAKE_DEFAULT_FRAME_SIZE - : *max_protected_frame_size; - impl->base.vtable = &frame_protector_vtable; - return &impl->base; -} diff --git a/src/core/tsi/fake_transport_security.h b/src/core/tsi/fake_transport_security.h deleted file mode 100644 index 6b8e596290..0000000000 --- a/src/core/tsi/fake_transport_security.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * - * Copyright 2015-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_TSI_FAKE_TRANSPORT_SECURITY_H -#define GRPC_CORE_TSI_FAKE_TRANSPORT_SECURITY_H - -#include "src/core/tsi/transport_security_interface.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* Value for the TSI_CERTIFICATE_TYPE_PEER_PROPERTY property for FAKE certs. */ -#define TSI_FAKE_CERTIFICATE_TYPE "FAKE" - -/* Creates a fake handshaker that will create a fake frame protector. - - No cryptography is performed in these objects. They just simulate handshake - messages going back and forth for the handshaker and do some framing on - cleartext data for the protector. */ -tsi_handshaker *tsi_create_fake_handshaker(int is_client); - -/* Creates a protector directly without going through the handshake phase. */ -tsi_frame_protector *tsi_create_fake_protector( - size_t *max_protected_frame_size); - -#ifdef __cplusplus -} -#endif - -#endif /* GRPC_CORE_TSI_FAKE_TRANSPORT_SECURITY_H */ diff --git a/src/core/tsi/ssl_transport_security.c b/src/core/tsi/ssl_transport_security.c deleted file mode 100644 index 8df582609b..0000000000 --- a/src/core/tsi/ssl_transport_security.c +++ /dev/null @@ -1,1536 +0,0 @@ -/* - * - * Copyright 2015-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/tsi/ssl_transport_security.h" - -#include - -#include -#include - -/* TODO(jboeuf): refactor inet_ntop into a portability header. */ -#ifdef GPR_WINSOCK_SOCKET -#include -#else -#include -#endif - -#include -#include -#include -#include - -#include -#include /* For OPENSSL_free */ -#include -#include -#include -#include - -#include "src/core/tsi/ssl_types.h" -#include "src/core/tsi/transport_security.h" - -/* --- Constants. ---*/ - -#define TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND 16384 -#define TSI_SSL_MAX_PROTECTED_FRAME_SIZE_LOWER_BOUND 1024 - -/* Putting a macro like this and littering the source file with #if is really - bad practice. - TODO(jboeuf): refactor all the #if / #endif in a separate module. */ -#ifndef TSI_OPENSSL_ALPN_SUPPORT -#define TSI_OPENSSL_ALPN_SUPPORT 1 -#endif - -/* TODO(jboeuf): I have not found a way to get this number dynamically from the - SSL structure. This is what we would ultimately want though... */ -#define TSI_SSL_MAX_PROTECTION_OVERHEAD 100 - -/* --- Structure definitions. ---*/ - -struct tsi_ssl_handshaker_factory { - tsi_result (*create_handshaker)(tsi_ssl_handshaker_factory *self, - const char *server_name_indication, - tsi_handshaker **handshaker); - void (*destroy)(tsi_ssl_handshaker_factory *self); -}; - -typedef struct { - tsi_ssl_handshaker_factory base; - SSL_CTX *ssl_context; - unsigned char *alpn_protocol_list; - size_t alpn_protocol_list_length; -} tsi_ssl_client_handshaker_factory; - -typedef struct { - tsi_ssl_handshaker_factory base; - - /* Several contexts to support SNI. - The tsi_peer array contains the subject names of the server certificates - associated with the contexts at the same index. */ - SSL_CTX **ssl_contexts; - tsi_peer *ssl_context_x509_subject_names; - size_t ssl_context_count; - unsigned char *alpn_protocol_list; - size_t alpn_protocol_list_length; -} tsi_ssl_server_handshaker_factory; - -typedef struct { - tsi_handshaker base; - SSL *ssl; - BIO *into_ssl; - BIO *from_ssl; - tsi_result result; -} tsi_ssl_handshaker; - -typedef struct { - tsi_frame_protector base; - SSL *ssl; - BIO *into_ssl; - BIO *from_ssl; - unsigned char *buffer; - size_t buffer_size; - size_t buffer_offset; -} tsi_ssl_frame_protector; - -/* --- Library Initialization. ---*/ - -static gpr_once init_openssl_once = GPR_ONCE_INIT; -static gpr_mu *openssl_mutexes = NULL; - -static void openssl_locking_cb(int mode, int type, const char *file, int line) { - if (mode & CRYPTO_LOCK) { - gpr_mu_lock(&openssl_mutexes[type]); - } else { - gpr_mu_unlock(&openssl_mutexes[type]); - } -} - -static unsigned long openssl_thread_id_cb(void) { - return (unsigned long)gpr_thd_currentid(); -} - -static void init_openssl(void) { - int i; - int num_locks; - SSL_library_init(); - SSL_load_error_strings(); - OpenSSL_add_all_algorithms(); - num_locks = CRYPTO_num_locks(); - GPR_ASSERT(num_locks > 0); - openssl_mutexes = malloc((size_t)num_locks * sizeof(gpr_mu)); - GPR_ASSERT(openssl_mutexes != NULL); - for (i = 0; i < CRYPTO_num_locks(); i++) { - gpr_mu_init(&openssl_mutexes[i]); - } - CRYPTO_set_locking_callback(openssl_locking_cb); - CRYPTO_set_id_callback(openssl_thread_id_cb); -} - -/* --- Ssl utils. ---*/ - -static const char *ssl_error_string(int error) { - switch (error) { - case SSL_ERROR_NONE: - return "SSL_ERROR_NONE"; - case SSL_ERROR_ZERO_RETURN: - return "SSL_ERROR_ZERO_RETURN"; - case SSL_ERROR_WANT_READ: - return "SSL_ERROR_WANT_READ"; - case SSL_ERROR_WANT_WRITE: - return "SSL_ERROR_WANT_WRITE"; - case SSL_ERROR_WANT_CONNECT: - return "SSL_ERROR_WANT_CONNECT"; - case SSL_ERROR_WANT_ACCEPT: - return "SSL_ERROR_WANT_ACCEPT"; - case SSL_ERROR_WANT_X509_LOOKUP: - return "SSL_ERROR_WANT_X509_LOOKUP"; - case SSL_ERROR_SYSCALL: - return "SSL_ERROR_SYSCALL"; - case SSL_ERROR_SSL: - return "SSL_ERROR_SSL"; - default: - return "Unknown error"; - } -} - -/* TODO(jboeuf): Remove when we are past the debugging phase with this code. */ -static void ssl_log_where_info(const SSL *ssl, int where, int flag, - const char *msg) { - if ((where & flag) && tsi_tracing_enabled) { - gpr_log(GPR_INFO, "%20.20s - %30.30s - %5.10s", msg, - SSL_state_string_long(ssl), SSL_state_string(ssl)); - } -} - -/* Used for debugging. TODO(jboeuf): Remove when code is mature enough. */ -static void ssl_info_callback(const SSL *ssl, int where, int ret) { - if (ret == 0) { - gpr_log(GPR_ERROR, "ssl_info_callback: error occured.\n"); - return; - } - - ssl_log_where_info(ssl, where, SSL_CB_LOOP, "LOOP"); - ssl_log_where_info(ssl, where, SSL_CB_HANDSHAKE_START, "HANDSHAKE START"); - ssl_log_where_info(ssl, where, SSL_CB_HANDSHAKE_DONE, "HANDSHAKE DONE"); -} - -/* Returns 1 if name looks like an IP address, 0 otherwise. - This is a very rough heuristic, and only handles IPv6 in hexadecimal form. */ -static int looks_like_ip_address(const char *name) { - size_t i; - size_t dot_count = 0; - size_t num_size = 0; - for (i = 0; i < strlen(name); i++) { - if (name[i] == ':') { - /* IPv6 Address in hexadecimal form, : is not allowed in DNS names. */ - return 1; - } - if (name[i] >= '0' && name[i] <= '9') { - if (num_size > 3) return 0; - num_size++; - } else if (name[i] == '.') { - if (dot_count > 3 || num_size == 0) return 0; - dot_count++; - num_size = 0; - } else { - return 0; - } - } - if (dot_count < 3 || num_size == 0) return 0; - return 1; -} - -/* Gets the subject CN from an X509 cert. */ -static tsi_result ssl_get_x509_common_name(X509 *cert, unsigned char **utf8, - size_t *utf8_size) { - int common_name_index = -1; - X509_NAME_ENTRY *common_name_entry = NULL; - ASN1_STRING *common_name_asn1 = NULL; - X509_NAME *subject_name = X509_get_subject_name(cert); - int utf8_returned_size = 0; - if (subject_name == NULL) { - gpr_log(GPR_ERROR, "Could not get subject name from certificate."); - return TSI_NOT_FOUND; - } - common_name_index = - X509_NAME_get_index_by_NID(subject_name, NID_commonName, -1); - if (common_name_index == -1) { - gpr_log(GPR_ERROR, - "Could not get common name of subject from certificate."); - return TSI_NOT_FOUND; - } - common_name_entry = X509_NAME_get_entry(subject_name, common_name_index); - if (common_name_entry == NULL) { - gpr_log(GPR_ERROR, "Could not get common name entry from certificate."); - return TSI_INTERNAL_ERROR; - } - common_name_asn1 = X509_NAME_ENTRY_get_data(common_name_entry); - if (common_name_asn1 == NULL) { - gpr_log(GPR_ERROR, - "Could not get common name entry asn1 from certificate."); - return TSI_INTERNAL_ERROR; - } - utf8_returned_size = ASN1_STRING_to_UTF8(utf8, common_name_asn1); - if (utf8_returned_size < 0) { - gpr_log(GPR_ERROR, "Could not extract utf8 from asn1 string."); - return TSI_OUT_OF_RESOURCES; - } - *utf8_size = (size_t)utf8_returned_size; - return TSI_OK; -} - -/* Gets the subject CN of an X509 cert as a tsi_peer_property. */ -static tsi_result peer_property_from_x509_common_name( - X509 *cert, tsi_peer_property *property) { - unsigned char *common_name; - size_t common_name_size; - tsi_result result = - ssl_get_x509_common_name(cert, &common_name, &common_name_size); - if (result != TSI_OK) { - if (result == TSI_NOT_FOUND) { - common_name = NULL; - common_name_size = 0; - } else { - return result; - } - } - result = tsi_construct_string_peer_property( - TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY, - common_name == NULL ? "" : (const char *)common_name, common_name_size, - property); - OPENSSL_free(common_name); - return result; -} - -/* Gets the X509 cert in PEM format as a tsi_peer_property. */ -static tsi_result add_pem_certificate(X509 *cert, tsi_peer_property *property) { - BIO *bio = BIO_new(BIO_s_mem()); - if (!PEM_write_bio_X509(bio, cert)) { - BIO_free(bio); - return TSI_INTERNAL_ERROR; - } - char *contents; - long len = BIO_get_mem_data(bio, &contents); - if (len <= 0) { - BIO_free(bio); - return TSI_INTERNAL_ERROR; - } - tsi_result result = tsi_construct_string_peer_property( - TSI_X509_PEM_CERT_PROPERTY, (const char *)contents, (size_t)len, - property); - BIO_free(bio); - return result; -} - -/* Gets the subject SANs from an X509 cert as a tsi_peer_property. */ -static tsi_result add_subject_alt_names_properties_to_peer( - tsi_peer *peer, GENERAL_NAMES *subject_alt_names, - size_t subject_alt_name_count) { - size_t i; - tsi_result result = TSI_OK; - - /* Reset for DNS entries filtering. */ - peer->property_count -= subject_alt_name_count; - - for (i = 0; i < subject_alt_name_count; i++) { - GENERAL_NAME *subject_alt_name = - sk_GENERAL_NAME_value(subject_alt_names, TSI_SIZE_AS_SIZE(i)); - /* Filter out the non-dns entries names. */ - if (subject_alt_name->type == GEN_DNS) { - unsigned char *name = NULL; - int name_size; - name_size = ASN1_STRING_to_UTF8(&name, subject_alt_name->d.dNSName); - if (name_size < 0) { - gpr_log(GPR_ERROR, "Could not get utf8 from asn1 string."); - result = TSI_INTERNAL_ERROR; - break; - } - result = tsi_construct_string_peer_property( - TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, (const char *)name, - (size_t)name_size, &peer->properties[peer->property_count++]); - OPENSSL_free(name); - } else if (subject_alt_name->type == GEN_IPADD) { - char ntop_buf[INET6_ADDRSTRLEN]; - int af; - - if (subject_alt_name->d.iPAddress->length == 4) { - af = AF_INET; - } else if (subject_alt_name->d.iPAddress->length == 16) { - af = AF_INET6; - } else { - gpr_log(GPR_ERROR, "SAN IP Address contained invalid IP"); - result = TSI_INTERNAL_ERROR; - break; - } - const char *name = inet_ntop(af, subject_alt_name->d.iPAddress->data, - ntop_buf, INET6_ADDRSTRLEN); - if (name == NULL) { - gpr_log(GPR_ERROR, "Could not get IP string from asn1 octet."); - result = TSI_INTERNAL_ERROR; - break; - } - - result = tsi_construct_string_peer_property_from_cstring( - TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, name, - &peer->properties[peer->property_count++]); - } - if (result != TSI_OK) break; - } - return result; -} - -/* Gets information about the peer's X509 cert as a tsi_peer object. */ -static tsi_result peer_from_x509(X509 *cert, int include_certificate_type, - tsi_peer *peer) { - /* TODO(jboeuf): Maybe add more properties. */ - GENERAL_NAMES *subject_alt_names = - X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0); - int subject_alt_name_count = (subject_alt_names != NULL) - ? (int)sk_GENERAL_NAME_num(subject_alt_names) - : 0; - size_t property_count; - tsi_result result; - GPR_ASSERT(subject_alt_name_count >= 0); - property_count = (include_certificate_type ? (size_t)1 : 0) + - 2 /* common name, certificate */ + - (size_t)subject_alt_name_count; - result = tsi_construct_peer(property_count, peer); - if (result != TSI_OK) return result; - do { - if (include_certificate_type) { - result = tsi_construct_string_peer_property_from_cstring( - TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE, - &peer->properties[0]); - if (result != TSI_OK) break; - } - result = peer_property_from_x509_common_name( - cert, &peer->properties[include_certificate_type ? 1 : 0]); - if (result != TSI_OK) break; - - result = add_pem_certificate( - cert, &peer->properties[include_certificate_type ? 2 : 1]); - if (result != TSI_OK) break; - - if (subject_alt_name_count != 0) { - result = add_subject_alt_names_properties_to_peer( - peer, subject_alt_names, (size_t)subject_alt_name_count); - if (result != TSI_OK) break; - } - } while (0); - - if (subject_alt_names != NULL) { - sk_GENERAL_NAME_pop_free(subject_alt_names, GENERAL_NAME_free); - } - if (result != TSI_OK) tsi_peer_destruct(peer); - return result; -} - -/* Logs the SSL error stack. */ -static void log_ssl_error_stack(void) { - unsigned long err; - while ((err = ERR_get_error()) != 0) { - char details[256]; - ERR_error_string_n((uint32_t)err, details, sizeof(details)); - gpr_log(GPR_ERROR, "%s", details); - } -} - -/* Performs an SSL_read and handle errors. */ -static tsi_result do_ssl_read(SSL *ssl, unsigned char *unprotected_bytes, - size_t *unprotected_bytes_size) { - int read_from_ssl; - GPR_ASSERT(*unprotected_bytes_size <= INT_MAX); - read_from_ssl = - SSL_read(ssl, unprotected_bytes, (int)*unprotected_bytes_size); - if (read_from_ssl == 0) { - gpr_log(GPR_ERROR, "SSL_read returned 0 unexpectedly."); - return TSI_INTERNAL_ERROR; - } - if (read_from_ssl < 0) { - read_from_ssl = SSL_get_error(ssl, read_from_ssl); - switch (read_from_ssl) { - case SSL_ERROR_WANT_READ: - /* We need more data to finish the frame. */ - *unprotected_bytes_size = 0; - return TSI_OK; - case SSL_ERROR_WANT_WRITE: - gpr_log( - GPR_ERROR, - "Peer tried to renegotiate SSL connection. This is unsupported."); - return TSI_UNIMPLEMENTED; - case SSL_ERROR_SSL: - gpr_log(GPR_ERROR, "Corruption detected."); - log_ssl_error_stack(); - return TSI_DATA_CORRUPTED; - default: - gpr_log(GPR_ERROR, "SSL_read failed with error %s.", - ssl_error_string(read_from_ssl)); - return TSI_PROTOCOL_FAILURE; - } - } - *unprotected_bytes_size = (size_t)read_from_ssl; - return TSI_OK; -} - -/* Performs an SSL_write and handle errors. */ -static tsi_result do_ssl_write(SSL *ssl, unsigned char *unprotected_bytes, - size_t unprotected_bytes_size) { - int ssl_write_result; - GPR_ASSERT(unprotected_bytes_size <= INT_MAX); - ssl_write_result = - SSL_write(ssl, unprotected_bytes, (int)unprotected_bytes_size); - if (ssl_write_result < 0) { - ssl_write_result = SSL_get_error(ssl, ssl_write_result); - if (ssl_write_result == SSL_ERROR_WANT_READ) { - gpr_log(GPR_ERROR, - "Peer tried to renegotiate SSL connection. This is unsupported."); - return TSI_UNIMPLEMENTED; - } else { - gpr_log(GPR_ERROR, "SSL_write failed with error %s.", - ssl_error_string(ssl_write_result)); - return TSI_INTERNAL_ERROR; - } - } - return TSI_OK; -} - -/* Loads an in-memory PEM certificate chain into the SSL context. */ -static tsi_result ssl_ctx_use_certificate_chain( - SSL_CTX *context, const unsigned char *pem_cert_chain, - size_t pem_cert_chain_size) { - tsi_result result = TSI_OK; - X509 *certificate = NULL; - BIO *pem; - GPR_ASSERT(pem_cert_chain_size <= INT_MAX); - pem = BIO_new_mem_buf((void *)pem_cert_chain, (int)pem_cert_chain_size); - if (pem == NULL) return TSI_OUT_OF_RESOURCES; - - do { - certificate = PEM_read_bio_X509_AUX(pem, NULL, NULL, ""); - if (certificate == NULL) { - result = TSI_INVALID_ARGUMENT; - break; - } - if (!SSL_CTX_use_certificate(context, certificate)) { - result = TSI_INVALID_ARGUMENT; - break; - } - while (1) { - X509 *certificate_authority = PEM_read_bio_X509(pem, NULL, NULL, ""); - if (certificate_authority == NULL) { - ERR_clear_error(); - break; /* Done reading. */ - } - if (!SSL_CTX_add_extra_chain_cert(context, certificate_authority)) { - X509_free(certificate_authority); - result = TSI_INVALID_ARGUMENT; - break; - } - /* We don't need to free certificate_authority as its ownership has been - transfered to the context. That is not the case for certificate though. - */ - } - } while (0); - - if (certificate != NULL) X509_free(certificate); - BIO_free(pem); - return result; -} - -/* Loads an in-memory PEM private key into the SSL context. */ -static tsi_result ssl_ctx_use_private_key(SSL_CTX *context, - const unsigned char *pem_key, - size_t pem_key_size) { - tsi_result result = TSI_OK; - EVP_PKEY *private_key = NULL; - BIO *pem; - GPR_ASSERT(pem_key_size <= INT_MAX); - pem = BIO_new_mem_buf((void *)pem_key, (int)pem_key_size); - if (pem == NULL) return TSI_OUT_OF_RESOURCES; - do { - private_key = PEM_read_bio_PrivateKey(pem, NULL, NULL, ""); - if (private_key == NULL) { - result = TSI_INVALID_ARGUMENT; - break; - } - if (!SSL_CTX_use_PrivateKey(context, private_key)) { - result = TSI_INVALID_ARGUMENT; - break; - } - } while (0); - if (private_key != NULL) EVP_PKEY_free(private_key); - BIO_free(pem); - return result; -} - -/* Loads in-memory PEM verification certs into the SSL context and optionally - returns the verification cert names (root_names can be NULL). */ -static tsi_result ssl_ctx_load_verification_certs( - SSL_CTX *context, const unsigned char *pem_roots, size_t pem_roots_size, - STACK_OF(X509_NAME) * *root_names) { - tsi_result result = TSI_OK; - size_t num_roots = 0; - X509 *root = NULL; - X509_NAME *root_name = NULL; - BIO *pem; - X509_STORE *root_store; - GPR_ASSERT(pem_roots_size <= INT_MAX); - pem = BIO_new_mem_buf((void *)pem_roots, (int)pem_roots_size); - root_store = SSL_CTX_get_cert_store(context); - if (root_store == NULL) return TSI_INVALID_ARGUMENT; - if (pem == NULL) return TSI_OUT_OF_RESOURCES; - if (root_names != NULL) { - *root_names = sk_X509_NAME_new_null(); - if (*root_names == NULL) return TSI_OUT_OF_RESOURCES; - } - - while (1) { - root = PEM_read_bio_X509_AUX(pem, NULL, NULL, ""); - if (root == NULL) { - ERR_clear_error(); - break; /* We're at the end of stream. */ - } - if (root_names != NULL) { - root_name = X509_get_subject_name(root); - if (root_name == NULL) { - gpr_log(GPR_ERROR, "Could not get name from root certificate."); - result = TSI_INVALID_ARGUMENT; - break; - } - root_name = X509_NAME_dup(root_name); - if (root_name == NULL) { - result = TSI_OUT_OF_RESOURCES; - break; - } - sk_X509_NAME_push(*root_names, root_name); - root_name = NULL; - } - if (!X509_STORE_add_cert(root_store, root)) { - gpr_log(GPR_ERROR, "Could not add root certificate to ssl context."); - result = TSI_INTERNAL_ERROR; - break; - } - X509_free(root); - num_roots++; - } - - if (num_roots == 0) { - gpr_log(GPR_ERROR, "Could not load any root certificate."); - result = TSI_INVALID_ARGUMENT; - } - - if (result != TSI_OK) { - if (root != NULL) X509_free(root); - if (root_names != NULL) { - sk_X509_NAME_pop_free(*root_names, X509_NAME_free); - *root_names = NULL; - if (root_name != NULL) X509_NAME_free(root_name); - } - } - BIO_free(pem); - return result; -} - -/* Populates the SSL context with a private key and a cert chain, and sets the - cipher list and the ephemeral ECDH key. */ -static tsi_result populate_ssl_context( - SSL_CTX *context, const unsigned char *pem_private_key, - size_t pem_private_key_size, const unsigned char *pem_certificate_chain, - size_t pem_certificate_chain_size, const char *cipher_list) { - tsi_result result = TSI_OK; - if (pem_certificate_chain != NULL) { - result = ssl_ctx_use_certificate_chain(context, pem_certificate_chain, - pem_certificate_chain_size); - if (result != TSI_OK) { - gpr_log(GPR_ERROR, "Invalid cert chain file."); - return result; - } - } - if (pem_private_key != NULL) { - result = - ssl_ctx_use_private_key(context, pem_private_key, pem_private_key_size); - if (result != TSI_OK || !SSL_CTX_check_private_key(context)) { - gpr_log(GPR_ERROR, "Invalid private key."); - return result != TSI_OK ? result : TSI_INVALID_ARGUMENT; - } - } - if ((cipher_list != NULL) && !SSL_CTX_set_cipher_list(context, cipher_list)) { - gpr_log(GPR_ERROR, "Invalid cipher list: %s.", cipher_list); - return TSI_INVALID_ARGUMENT; - } - { - EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); - if (!SSL_CTX_set_tmp_ecdh(context, ecdh)) { - gpr_log(GPR_ERROR, "Could not set ephemeral ECDH key."); - EC_KEY_free(ecdh); - return TSI_INTERNAL_ERROR; - } - SSL_CTX_set_options(context, SSL_OP_SINGLE_ECDH_USE); - EC_KEY_free(ecdh); - } - return TSI_OK; -} - -/* Extracts the CN and the SANs from an X509 cert as a peer object. */ -static tsi_result extract_x509_subject_names_from_pem_cert( - const unsigned char *pem_cert, size_t pem_cert_size, tsi_peer *peer) { - tsi_result result = TSI_OK; - X509 *cert = NULL; - BIO *pem; - GPR_ASSERT(pem_cert_size <= INT_MAX); - pem = BIO_new_mem_buf((void *)pem_cert, (int)pem_cert_size); - if (pem == NULL) return TSI_OUT_OF_RESOURCES; - - cert = PEM_read_bio_X509(pem, NULL, NULL, ""); - if (cert == NULL) { - gpr_log(GPR_ERROR, "Invalid certificate"); - result = TSI_INVALID_ARGUMENT; - } else { - result = peer_from_x509(cert, 0, peer); - } - if (cert != NULL) X509_free(cert); - BIO_free(pem); - return result; -} - -/* Builds the alpn protocol name list according to rfc 7301. */ -static tsi_result build_alpn_protocol_name_list( - const unsigned char **alpn_protocols, - const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols, - unsigned char **protocol_name_list, size_t *protocol_name_list_length) { - uint16_t i; - unsigned char *current; - *protocol_name_list = NULL; - *protocol_name_list_length = 0; - if (num_alpn_protocols == 0) return TSI_INVALID_ARGUMENT; - for (i = 0; i < num_alpn_protocols; i++) { - if (alpn_protocols_lengths[i] == 0) { - gpr_log(GPR_ERROR, "Invalid 0-length protocol name."); - return TSI_INVALID_ARGUMENT; - } - *protocol_name_list_length += (size_t)alpn_protocols_lengths[i] + 1; - } - *protocol_name_list = malloc(*protocol_name_list_length); - if (*protocol_name_list == NULL) return TSI_OUT_OF_RESOURCES; - current = *protocol_name_list; - for (i = 0; i < num_alpn_protocols; i++) { - *(current++) = alpn_protocols_lengths[i]; - memcpy(current, alpn_protocols[i], alpn_protocols_lengths[i]); - current += alpn_protocols_lengths[i]; - } - /* Safety check. */ - if ((current < *protocol_name_list) || - ((uintptr_t)(current - *protocol_name_list) != - *protocol_name_list_length)) { - return TSI_INTERNAL_ERROR; - } - return TSI_OK; -} - -/* --- tsi_frame_protector methods implementation. ---*/ - -static tsi_result ssl_protector_protect(tsi_frame_protector *self, - const unsigned char *unprotected_bytes, - size_t *unprotected_bytes_size, - unsigned char *protected_output_frames, - size_t *protected_output_frames_size) { - tsi_ssl_frame_protector *impl = (tsi_ssl_frame_protector *)self; - int read_from_ssl; - size_t available; - tsi_result result = TSI_OK; - - /* First see if we have some pending data in the SSL BIO. */ - int pending_in_ssl = (int)BIO_pending(impl->from_ssl); - if (pending_in_ssl > 0) { - *unprotected_bytes_size = 0; - GPR_ASSERT(*protected_output_frames_size <= INT_MAX); - read_from_ssl = BIO_read(impl->from_ssl, protected_output_frames, - (int)*protected_output_frames_size); - if (read_from_ssl < 0) { - gpr_log(GPR_ERROR, - "Could not read from BIO even though some data is pending"); - return TSI_INTERNAL_ERROR; - } - *protected_output_frames_size = (size_t)read_from_ssl; - return TSI_OK; - } - - /* Now see if we can send a complete frame. */ - available = impl->buffer_size - impl->buffer_offset; - if (available > *unprotected_bytes_size) { - /* If we cannot, just copy the data in our internal buffer. */ - memcpy(impl->buffer + impl->buffer_offset, unprotected_bytes, - *unprotected_bytes_size); - impl->buffer_offset += *unprotected_bytes_size; - *protected_output_frames_size = 0; - return TSI_OK; - } - - /* If we can, prepare the buffer, send it to SSL_write and read. */ - memcpy(impl->buffer + impl->buffer_offset, unprotected_bytes, available); - result = do_ssl_write(impl->ssl, impl->buffer, impl->buffer_size); - if (result != TSI_OK) return result; - - GPR_ASSERT(*protected_output_frames_size <= INT_MAX); - read_from_ssl = BIO_read(impl->from_ssl, protected_output_frames, - (int)*protected_output_frames_size); - if (read_from_ssl < 0) { - gpr_log(GPR_ERROR, "Could not read from BIO after SSL_write."); - return TSI_INTERNAL_ERROR; - } - *protected_output_frames_size = (size_t)read_from_ssl; - *unprotected_bytes_size = available; - impl->buffer_offset = 0; - return TSI_OK; -} - -static tsi_result ssl_protector_protect_flush( - tsi_frame_protector *self, unsigned char *protected_output_frames, - size_t *protected_output_frames_size, size_t *still_pending_size) { - tsi_result result = TSI_OK; - tsi_ssl_frame_protector *impl = (tsi_ssl_frame_protector *)self; - int read_from_ssl = 0; - int pending; - - if (impl->buffer_offset != 0) { - result = do_ssl_write(impl->ssl, impl->buffer, impl->buffer_offset); - if (result != TSI_OK) return result; - impl->buffer_offset = 0; - } - - pending = (int)BIO_pending(impl->from_ssl); - GPR_ASSERT(pending >= 0); - *still_pending_size = (size_t)pending; - if (*still_pending_size == 0) return TSI_OK; - - GPR_ASSERT(*protected_output_frames_size <= INT_MAX); - read_from_ssl = BIO_read(impl->from_ssl, protected_output_frames, - (int)*protected_output_frames_size); - if (read_from_ssl <= 0) { - gpr_log(GPR_ERROR, "Could not read from BIO after SSL_write."); - return TSI_INTERNAL_ERROR; - } - *protected_output_frames_size = (size_t)read_from_ssl; - pending = (int)BIO_pending(impl->from_ssl); - GPR_ASSERT(pending >= 0); - *still_pending_size = (size_t)pending; - return TSI_OK; -} - -static tsi_result ssl_protector_unprotect( - tsi_frame_protector *self, const unsigned char *protected_frames_bytes, - size_t *protected_frames_bytes_size, unsigned char *unprotected_bytes, - size_t *unprotected_bytes_size) { - tsi_result result = TSI_OK; - int written_into_ssl = 0; - size_t output_bytes_size = *unprotected_bytes_size; - size_t output_bytes_offset = 0; - tsi_ssl_frame_protector *impl = (tsi_ssl_frame_protector *)self; - - /* First, try to read remaining data from ssl. */ - result = do_ssl_read(impl->ssl, unprotected_bytes, unprotected_bytes_size); - if (result != TSI_OK) return result; - if (*unprotected_bytes_size == output_bytes_size) { - /* We have read everything we could and cannot process any more input. */ - *protected_frames_bytes_size = 0; - return TSI_OK; - } - output_bytes_offset = *unprotected_bytes_size; - unprotected_bytes += output_bytes_offset; - *unprotected_bytes_size = output_bytes_size - output_bytes_offset; - - /* Then, try to write some data to ssl. */ - GPR_ASSERT(*protected_frames_bytes_size <= INT_MAX); - written_into_ssl = BIO_write(impl->into_ssl, protected_frames_bytes, - (int)*protected_frames_bytes_size); - if (written_into_ssl < 0) { - gpr_log(GPR_ERROR, "Sending protected frame to ssl failed with %d", - written_into_ssl); - return TSI_INTERNAL_ERROR; - } - *protected_frames_bytes_size = (size_t)written_into_ssl; - - /* Now try to read some data again. */ - result = do_ssl_read(impl->ssl, unprotected_bytes, unprotected_bytes_size); - if (result == TSI_OK) { - /* Don't forget to output the total number of bytes read. */ - *unprotected_bytes_size += output_bytes_offset; - } - return result; -} - -static void ssl_protector_destroy(tsi_frame_protector *self) { - tsi_ssl_frame_protector *impl = (tsi_ssl_frame_protector *)self; - if (impl->buffer != NULL) free(impl->buffer); - if (impl->ssl != NULL) SSL_free(impl->ssl); - free(self); -} - -static const tsi_frame_protector_vtable frame_protector_vtable = { - ssl_protector_protect, ssl_protector_protect_flush, ssl_protector_unprotect, - ssl_protector_destroy, -}; - -/* --- tsi_handshaker methods implementation. ---*/ - -static tsi_result ssl_handshaker_get_bytes_to_send_to_peer(tsi_handshaker *self, - unsigned char *bytes, - size_t *bytes_size) { - tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self; - int bytes_read_from_ssl = 0; - if (bytes == NULL || bytes_size == NULL || *bytes_size == 0 || - *bytes_size > INT_MAX) { - return TSI_INVALID_ARGUMENT; - } - GPR_ASSERT(*bytes_size <= INT_MAX); - bytes_read_from_ssl = BIO_read(impl->from_ssl, bytes, (int)*bytes_size); - if (bytes_read_from_ssl < 0) { - *bytes_size = 0; - if (!BIO_should_retry(impl->from_ssl)) { - impl->result = TSI_INTERNAL_ERROR; - return impl->result; - } else { - return TSI_OK; - } - } - *bytes_size = (size_t)bytes_read_from_ssl; - return BIO_pending(impl->from_ssl) == 0 ? TSI_OK : TSI_INCOMPLETE_DATA; -} - -static tsi_result ssl_handshaker_get_result(tsi_handshaker *self) { - tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self; - if ((impl->result == TSI_HANDSHAKE_IN_PROGRESS) && - SSL_is_init_finished(impl->ssl)) { - impl->result = TSI_OK; - } - return impl->result; -} - -static tsi_result ssl_handshaker_process_bytes_from_peer( - tsi_handshaker *self, const unsigned char *bytes, size_t *bytes_size) { - tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self; - int bytes_written_into_ssl_size = 0; - if (bytes == NULL || bytes_size == 0 || *bytes_size > INT_MAX) { - return TSI_INVALID_ARGUMENT; - } - GPR_ASSERT(*bytes_size <= INT_MAX); - bytes_written_into_ssl_size = - BIO_write(impl->into_ssl, bytes, (int)*bytes_size); - if (bytes_written_into_ssl_size < 0) { - gpr_log(GPR_ERROR, "Could not write to memory BIO."); - impl->result = TSI_INTERNAL_ERROR; - return impl->result; - } - *bytes_size = (size_t)bytes_written_into_ssl_size; - - if (!tsi_handshaker_is_in_progress(self)) { - impl->result = TSI_OK; - return impl->result; - } else { - /* Get ready to get some bytes from SSL. */ - int ssl_result = SSL_do_handshake(impl->ssl); - ssl_result = SSL_get_error(impl->ssl, ssl_result); - switch (ssl_result) { - case SSL_ERROR_WANT_READ: - if (BIO_pending(impl->from_ssl) == 0) { - /* We need more data. */ - return TSI_INCOMPLETE_DATA; - } else { - return TSI_OK; - } - case SSL_ERROR_NONE: - return TSI_OK; - default: { - char err_str[256]; - ERR_error_string_n(ERR_get_error(), err_str, sizeof(err_str)); - gpr_log(GPR_ERROR, "Handshake failed with fatal error %s: %s.", - ssl_error_string(ssl_result), err_str); - impl->result = TSI_PROTOCOL_FAILURE; - return impl->result; - } - } - } -} - -static tsi_result ssl_handshaker_extract_peer(tsi_handshaker *self, - tsi_peer *peer) { - tsi_result result = TSI_OK; - const unsigned char *alpn_selected = NULL; - unsigned int alpn_selected_len; - tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self; - X509 *peer_cert = SSL_get_peer_certificate(impl->ssl); - if (peer_cert != NULL) { - result = peer_from_x509(peer_cert, 1, peer); - X509_free(peer_cert); - if (result != TSI_OK) return result; - } -#if TSI_OPENSSL_ALPN_SUPPORT - SSL_get0_alpn_selected(impl->ssl, &alpn_selected, &alpn_selected_len); -#endif /* TSI_OPENSSL_ALPN_SUPPORT */ - if (alpn_selected == NULL) { - /* Try npn. */ - SSL_get0_next_proto_negotiated(impl->ssl, &alpn_selected, - &alpn_selected_len); - } - if (alpn_selected != NULL) { - size_t i; - tsi_peer_property *new_properties = - calloc(1, sizeof(tsi_peer_property) * (peer->property_count + 1)); - if (new_properties == NULL) return TSI_OUT_OF_RESOURCES; - for (i = 0; i < peer->property_count; i++) { - new_properties[i] = peer->properties[i]; - } - result = tsi_construct_string_peer_property( - TSI_SSL_ALPN_SELECTED_PROTOCOL, (const char *)alpn_selected, - alpn_selected_len, &new_properties[peer->property_count]); - if (result != TSI_OK) { - free(new_properties); - return result; - } - if (peer->properties != NULL) free(peer->properties); - peer->property_count++; - peer->properties = new_properties; - } - return result; -} - -static tsi_result ssl_handshaker_create_frame_protector( - tsi_handshaker *self, size_t *max_output_protected_frame_size, - tsi_frame_protector **protector) { - size_t actual_max_output_protected_frame_size = - TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND; - tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self; - tsi_ssl_frame_protector *protector_impl = - calloc(1, sizeof(tsi_ssl_frame_protector)); - if (protector_impl == NULL) { - return TSI_OUT_OF_RESOURCES; - } - - if (max_output_protected_frame_size != NULL) { - if (*max_output_protected_frame_size > - TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND) { - *max_output_protected_frame_size = - TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND; - } else if (*max_output_protected_frame_size < - TSI_SSL_MAX_PROTECTED_FRAME_SIZE_LOWER_BOUND) { - *max_output_protected_frame_size = - TSI_SSL_MAX_PROTECTED_FRAME_SIZE_LOWER_BOUND; - } - actual_max_output_protected_frame_size = *max_output_protected_frame_size; - } - protector_impl->buffer_size = - actual_max_output_protected_frame_size - TSI_SSL_MAX_PROTECTION_OVERHEAD; - protector_impl->buffer = malloc(protector_impl->buffer_size); - if (protector_impl->buffer == NULL) { - gpr_log(GPR_ERROR, - "Could not allocated buffer for tsi_ssl_frame_protector."); - free(protector_impl); - return TSI_INTERNAL_ERROR; - } - - /* Transfer ownership of ssl to the frame protector. It is OK as the caller - * cannot call anything else but destroy on the handshaker after this call. */ - protector_impl->ssl = impl->ssl; - impl->ssl = NULL; - protector_impl->into_ssl = impl->into_ssl; - protector_impl->from_ssl = impl->from_ssl; - - protector_impl->base.vtable = &frame_protector_vtable; - *protector = &protector_impl->base; - return TSI_OK; -} - -static void ssl_handshaker_destroy(tsi_handshaker *self) { - tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self; - SSL_free(impl->ssl); /* The BIO objects are owned by ssl */ - free(impl); -} - -static const tsi_handshaker_vtable handshaker_vtable = { - ssl_handshaker_get_bytes_to_send_to_peer, - ssl_handshaker_process_bytes_from_peer, - ssl_handshaker_get_result, - ssl_handshaker_extract_peer, - ssl_handshaker_create_frame_protector, - ssl_handshaker_destroy, -}; - -/* --- tsi_ssl_handshaker_factory common methods. --- */ - -tsi_result tsi_ssl_handshaker_factory_create_handshaker( - tsi_ssl_handshaker_factory *self, const char *server_name_indication, - tsi_handshaker **handshaker) { - if (self == NULL || handshaker == NULL) return TSI_INVALID_ARGUMENT; - return self->create_handshaker(self, server_name_indication, handshaker); -} - -void tsi_ssl_handshaker_factory_destroy(tsi_ssl_handshaker_factory *self) { - if (self == NULL) return; - self->destroy(self); -} - -static tsi_result create_tsi_ssl_handshaker(SSL_CTX *ctx, int is_client, - const char *server_name_indication, - tsi_handshaker **handshaker) { - SSL *ssl = SSL_new(ctx); - BIO *into_ssl = NULL; - BIO *from_ssl = NULL; - tsi_ssl_handshaker *impl = NULL; - *handshaker = NULL; - if (ctx == NULL) { - gpr_log(GPR_ERROR, "SSL Context is null. Should never happen."); - return TSI_INTERNAL_ERROR; - } - if (ssl == NULL) { - return TSI_OUT_OF_RESOURCES; - } - SSL_set_info_callback(ssl, ssl_info_callback); - - into_ssl = BIO_new(BIO_s_mem()); - from_ssl = BIO_new(BIO_s_mem()); - if (into_ssl == NULL || from_ssl == NULL) { - gpr_log(GPR_ERROR, "BIO_new failed."); - SSL_free(ssl); - if (into_ssl != NULL) BIO_free(into_ssl); - if (from_ssl != NULL) BIO_free(into_ssl); - return TSI_OUT_OF_RESOURCES; - } - SSL_set_bio(ssl, into_ssl, from_ssl); - if (is_client) { - int ssl_result; - SSL_set_connect_state(ssl); - if (server_name_indication != NULL) { - if (!SSL_set_tlsext_host_name(ssl, server_name_indication)) { - gpr_log(GPR_ERROR, "Invalid server name indication %s.", - server_name_indication); - SSL_free(ssl); - return TSI_INTERNAL_ERROR; - } - } - ssl_result = SSL_do_handshake(ssl); - ssl_result = SSL_get_error(ssl, ssl_result); - if (ssl_result != SSL_ERROR_WANT_READ) { - gpr_log(GPR_ERROR, - "Unexpected error received from first SSL_do_handshake call: %s", - ssl_error_string(ssl_result)); - SSL_free(ssl); - return TSI_INTERNAL_ERROR; - } - } else { - SSL_set_accept_state(ssl); - } - - impl = calloc(1, sizeof(tsi_ssl_handshaker)); - if (impl == NULL) { - SSL_free(ssl); - return TSI_OUT_OF_RESOURCES; - } - impl->ssl = ssl; - impl->into_ssl = into_ssl; - impl->from_ssl = from_ssl; - impl->result = TSI_HANDSHAKE_IN_PROGRESS; - impl->base.vtable = &handshaker_vtable; - *handshaker = &impl->base; - return TSI_OK; -} - -static int select_protocol_list(const unsigned char **out, - unsigned char *outlen, - const unsigned char *client_list, - size_t client_list_len, - const unsigned char *server_list, - size_t server_list_len) { - const unsigned char *client_current = client_list; - while ((unsigned int)(client_current - client_list) < client_list_len) { - unsigned char client_current_len = *(client_current++); - const unsigned char *server_current = server_list; - while ((server_current >= server_list) && - (uintptr_t)(server_current - server_list) < server_list_len) { - unsigned char server_current_len = *(server_current++); - if ((client_current_len == server_current_len) && - !memcmp(client_current, server_current, server_current_len)) { - *out = server_current; - *outlen = server_current_len; - return SSL_TLSEXT_ERR_OK; - } - server_current += server_current_len; - } - client_current += client_current_len; - } - return SSL_TLSEXT_ERR_NOACK; -} - -/* --- tsi_ssl__client_handshaker_factory methods implementation. --- */ - -static tsi_result ssl_client_handshaker_factory_create_handshaker( - tsi_ssl_handshaker_factory *self, const char *server_name_indication, - tsi_handshaker **handshaker) { - tsi_ssl_client_handshaker_factory *impl = - (tsi_ssl_client_handshaker_factory *)self; - return create_tsi_ssl_handshaker(impl->ssl_context, 1, server_name_indication, - handshaker); -} - -static void ssl_client_handshaker_factory_destroy( - tsi_ssl_handshaker_factory *self) { - tsi_ssl_client_handshaker_factory *impl = - (tsi_ssl_client_handshaker_factory *)self; - if (impl->ssl_context != NULL) SSL_CTX_free(impl->ssl_context); - if (impl->alpn_protocol_list != NULL) free(impl->alpn_protocol_list); - free(impl); -} - -static int client_handshaker_factory_npn_callback(SSL *ssl, unsigned char **out, - unsigned char *outlen, - const unsigned char *in, - unsigned int inlen, - void *arg) { - tsi_ssl_client_handshaker_factory *factory = - (tsi_ssl_client_handshaker_factory *)arg; - return select_protocol_list((const unsigned char **)out, outlen, - factory->alpn_protocol_list, - factory->alpn_protocol_list_length, in, inlen); -} - -/* --- tsi_ssl_server_handshaker_factory methods implementation. --- */ - -static tsi_result ssl_server_handshaker_factory_create_handshaker( - tsi_ssl_handshaker_factory *self, const char *server_name_indication, - tsi_handshaker **handshaker) { - tsi_ssl_server_handshaker_factory *impl = - (tsi_ssl_server_handshaker_factory *)self; - if (impl->ssl_context_count == 0 || server_name_indication != NULL) { - return TSI_INVALID_ARGUMENT; - } - /* Create the handshaker with the first context. We will switch if needed - because of SNI in ssl_server_handshaker_factory_servername_callback. */ - return create_tsi_ssl_handshaker(impl->ssl_contexts[0], 0, NULL, handshaker); -} - -static void ssl_server_handshaker_factory_destroy( - tsi_ssl_handshaker_factory *self) { - tsi_ssl_server_handshaker_factory *impl = - (tsi_ssl_server_handshaker_factory *)self; - size_t i; - for (i = 0; i < impl->ssl_context_count; i++) { - if (impl->ssl_contexts[i] != NULL) { - SSL_CTX_free(impl->ssl_contexts[i]); - tsi_peer_destruct(&impl->ssl_context_x509_subject_names[i]); - } - } - if (impl->ssl_contexts != NULL) free(impl->ssl_contexts); - if (impl->ssl_context_x509_subject_names != NULL) { - free(impl->ssl_context_x509_subject_names); - } - if (impl->alpn_protocol_list != NULL) free(impl->alpn_protocol_list); - free(impl); -} - -static int does_entry_match_name(const char *entry, size_t entry_length, - const char *name) { - const char *dot; - const char *name_subdomain = NULL; - size_t name_length = strlen(name); - size_t name_subdomain_length; - if (entry_length == 0) return 0; - - /* Take care of '.' terminations. */ - if (name[name_length - 1] == '.') { - name_length--; - } - if (entry[entry_length - 1] == '.') { - entry_length--; - if (entry_length == 0) return 0; - } - - if ((name_length == entry_length) && - strncmp(name, entry, entry_length) == 0) { - return 1; /* Perfect match. */ - } - if (entry[0] != '*') return 0; - - /* Wildchar subdomain matching. */ - if (entry_length < 3 || entry[1] != '.') { /* At least *.x */ - gpr_log(GPR_ERROR, "Invalid wildchar entry."); - return 0; - } - name_subdomain = strchr(name, '.'); - if (name_subdomain == NULL) return 0; - name_subdomain_length = strlen(name_subdomain); - if (name_subdomain_length < 2) return 0; - name_subdomain++; /* Starts after the dot. */ - name_subdomain_length--; - entry += 2; /* Remove *. */ - entry_length -= 2; - dot = strchr(name_subdomain, '.'); - if ((dot == NULL) || (dot == &name_subdomain[name_subdomain_length - 1])) { - gpr_log(GPR_ERROR, "Invalid toplevel subdomain: %s", name_subdomain); - return 0; - } - if (name_subdomain[name_subdomain_length - 1] == '.') { - name_subdomain_length--; - } - return ((entry_length > 0) && (name_subdomain_length == entry_length) && - strncmp(entry, name_subdomain, entry_length) == 0); -} - -static int ssl_server_handshaker_factory_servername_callback(SSL *ssl, int *ap, - void *arg) { - tsi_ssl_server_handshaker_factory *impl = - (tsi_ssl_server_handshaker_factory *)arg; - size_t i = 0; - const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); - if (servername == NULL || strlen(servername) == 0) { - return SSL_TLSEXT_ERR_NOACK; - } - - for (i = 0; i < impl->ssl_context_count; i++) { - if (tsi_ssl_peer_matches_name(&impl->ssl_context_x509_subject_names[i], - servername)) { - SSL_set_SSL_CTX(ssl, impl->ssl_contexts[i]); - return SSL_TLSEXT_ERR_OK; - } - } - gpr_log(GPR_ERROR, "No match found for server name: %s.", servername); - return SSL_TLSEXT_ERR_ALERT_WARNING; -} - -#if TSI_OPENSSL_ALPN_SUPPORT -static int server_handshaker_factory_alpn_callback( - SSL *ssl, const unsigned char **out, unsigned char *outlen, - const unsigned char *in, unsigned int inlen, void *arg) { - tsi_ssl_server_handshaker_factory *factory = - (tsi_ssl_server_handshaker_factory *)arg; - return select_protocol_list(out, outlen, in, inlen, - factory->alpn_protocol_list, - factory->alpn_protocol_list_length); -} -#endif /* TSI_OPENSSL_ALPN_SUPPORT */ - -static int server_handshaker_factory_npn_advertised_callback( - SSL *ssl, const unsigned char **out, unsigned int *outlen, void *arg) { - tsi_ssl_server_handshaker_factory *factory = - (tsi_ssl_server_handshaker_factory *)arg; - *out = factory->alpn_protocol_list; - GPR_ASSERT(factory->alpn_protocol_list_length <= UINT_MAX); - *outlen = (unsigned int)factory->alpn_protocol_list_length; - return SSL_TLSEXT_ERR_OK; -} - -/* --- tsi_ssl_handshaker_factory constructors. --- */ - -tsi_result tsi_create_ssl_client_handshaker_factory( - const unsigned char *pem_private_key, size_t pem_private_key_size, - const unsigned char *pem_cert_chain, size_t pem_cert_chain_size, - const unsigned char *pem_root_certs, size_t pem_root_certs_size, - const char *cipher_list, const unsigned char **alpn_protocols, - const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols, - tsi_ssl_handshaker_factory **factory) { - SSL_CTX *ssl_context = NULL; - tsi_ssl_client_handshaker_factory *impl = NULL; - tsi_result result = TSI_OK; - - gpr_once_init(&init_openssl_once, init_openssl); - - if (factory == NULL) return TSI_INVALID_ARGUMENT; - *factory = NULL; - if (pem_root_certs == NULL) return TSI_INVALID_ARGUMENT; - - ssl_context = SSL_CTX_new(TLSv1_2_method()); - if (ssl_context == NULL) { - gpr_log(GPR_ERROR, "Could not create ssl context."); - return TSI_INVALID_ARGUMENT; - } - - impl = calloc(1, sizeof(tsi_ssl_client_handshaker_factory)); - if (impl == NULL) { - SSL_CTX_free(ssl_context); - return TSI_OUT_OF_RESOURCES; - } - impl->ssl_context = ssl_context; - - do { - result = - populate_ssl_context(ssl_context, pem_private_key, pem_private_key_size, - pem_cert_chain, pem_cert_chain_size, cipher_list); - if (result != TSI_OK) break; - result = ssl_ctx_load_verification_certs(ssl_context, pem_root_certs, - pem_root_certs_size, NULL); - if (result != TSI_OK) { - gpr_log(GPR_ERROR, "Cannot load server root certificates."); - break; - } - - if (num_alpn_protocols != 0) { - result = build_alpn_protocol_name_list( - alpn_protocols, alpn_protocols_lengths, num_alpn_protocols, - &impl->alpn_protocol_list, &impl->alpn_protocol_list_length); - if (result != TSI_OK) { - gpr_log(GPR_ERROR, "Building alpn list failed with error %s.", - tsi_result_to_string(result)); - break; - } -#if TSI_OPENSSL_ALPN_SUPPORT - GPR_ASSERT(impl->alpn_protocol_list_length < UINT_MAX); - if (SSL_CTX_set_alpn_protos( - ssl_context, impl->alpn_protocol_list, - (unsigned int)impl->alpn_protocol_list_length)) { - gpr_log(GPR_ERROR, "Could not set alpn protocol list to context."); - result = TSI_INVALID_ARGUMENT; - break; - } -#endif /* TSI_OPENSSL_ALPN_SUPPORT */ - SSL_CTX_set_next_proto_select_cb( - ssl_context, client_handshaker_factory_npn_callback, impl); - } - } while (0); - if (result != TSI_OK) { - ssl_client_handshaker_factory_destroy(&impl->base); - return result; - } - SSL_CTX_set_verify(ssl_context, SSL_VERIFY_PEER, NULL); - /* TODO(jboeuf): Add revocation verification. */ - - impl->base.create_handshaker = - ssl_client_handshaker_factory_create_handshaker; - impl->base.destroy = ssl_client_handshaker_factory_destroy; - *factory = &impl->base; - return TSI_OK; -} - -tsi_result tsi_create_ssl_server_handshaker_factory( - const unsigned char **pem_private_keys, - const size_t *pem_private_keys_sizes, const unsigned char **pem_cert_chains, - const size_t *pem_cert_chains_sizes, size_t key_cert_pair_count, - const unsigned char *pem_client_root_certs, - size_t pem_client_root_certs_size, int force_client_auth, - const char *cipher_list, const unsigned char **alpn_protocols, - const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols, - tsi_ssl_handshaker_factory **factory) { - tsi_ssl_server_handshaker_factory *impl = NULL; - tsi_result result = TSI_OK; - size_t i = 0; - - gpr_once_init(&init_openssl_once, init_openssl); - - if (factory == NULL) return TSI_INVALID_ARGUMENT; - *factory = NULL; - if (key_cert_pair_count == 0 || pem_private_keys == NULL || - pem_cert_chains == NULL) { - return TSI_INVALID_ARGUMENT; - } - - impl = calloc(1, sizeof(tsi_ssl_server_handshaker_factory)); - if (impl == NULL) return TSI_OUT_OF_RESOURCES; - impl->base.create_handshaker = - ssl_server_handshaker_factory_create_handshaker; - impl->base.destroy = ssl_server_handshaker_factory_destroy; - impl->ssl_contexts = calloc(key_cert_pair_count, sizeof(SSL_CTX *)); - impl->ssl_context_x509_subject_names = - calloc(key_cert_pair_count, sizeof(tsi_peer)); - if (impl->ssl_contexts == NULL || - impl->ssl_context_x509_subject_names == NULL) { - tsi_ssl_handshaker_factory_destroy(&impl->base); - return TSI_OUT_OF_RESOURCES; - } - impl->ssl_context_count = key_cert_pair_count; - - if (num_alpn_protocols > 0) { - result = build_alpn_protocol_name_list( - alpn_protocols, alpn_protocols_lengths, num_alpn_protocols, - &impl->alpn_protocol_list, &impl->alpn_protocol_list_length); - if (result != TSI_OK) { - tsi_ssl_handshaker_factory_destroy(&impl->base); - return result; - } - } - - for (i = 0; i < key_cert_pair_count; i++) { - do { - impl->ssl_contexts[i] = SSL_CTX_new(TLSv1_2_method()); - if (impl->ssl_contexts[i] == NULL) { - gpr_log(GPR_ERROR, "Could not create ssl context."); - result = TSI_OUT_OF_RESOURCES; - break; - } - result = populate_ssl_context( - impl->ssl_contexts[i], pem_private_keys[i], pem_private_keys_sizes[i], - pem_cert_chains[i], pem_cert_chains_sizes[i], cipher_list); - if (result != TSI_OK) break; - - if (pem_client_root_certs != NULL) { - int flags = SSL_VERIFY_PEER; - STACK_OF(X509_NAME) *root_names = NULL; - result = ssl_ctx_load_verification_certs( - impl->ssl_contexts[i], pem_client_root_certs, - pem_client_root_certs_size, &root_names); - if (result != TSI_OK) { - gpr_log(GPR_ERROR, "Invalid verification certs."); - break; - } - SSL_CTX_set_client_CA_list(impl->ssl_contexts[i], root_names); - if (force_client_auth) flags |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; - SSL_CTX_set_verify(impl->ssl_contexts[i], flags, NULL); - /* TODO(jboeuf): Add revocation verification. */ - } - - result = extract_x509_subject_names_from_pem_cert( - pem_cert_chains[i], pem_cert_chains_sizes[i], - &impl->ssl_context_x509_subject_names[i]); - if (result != TSI_OK) break; - - SSL_CTX_set_tlsext_servername_callback( - impl->ssl_contexts[i], - ssl_server_handshaker_factory_servername_callback); - SSL_CTX_set_tlsext_servername_arg(impl->ssl_contexts[i], impl); -#if TSI_OPENSSL_ALPN_SUPPORT - SSL_CTX_set_alpn_select_cb(impl->ssl_contexts[i], - server_handshaker_factory_alpn_callback, impl); -#endif /* TSI_OPENSSL_ALPN_SUPPORT */ - SSL_CTX_set_next_protos_advertised_cb( - impl->ssl_contexts[i], - server_handshaker_factory_npn_advertised_callback, impl); - } while (0); - - if (result != TSI_OK) { - tsi_ssl_handshaker_factory_destroy(&impl->base); - return result; - } - } - *factory = &impl->base; - return TSI_OK; -} - -/* --- tsi_ssl utils. --- */ - -int tsi_ssl_peer_matches_name(const tsi_peer *peer, const char *name) { - size_t i = 0; - size_t san_count = 0; - const tsi_peer_property *cn_property = NULL; - int like_ip = looks_like_ip_address(name); - - /* Check the SAN first. */ - for (i = 0; i < peer->property_count; i++) { - const tsi_peer_property *property = &peer->properties[i]; - if (property->name == NULL) continue; - if (strcmp(property->name, - TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) { - san_count++; - - if (!like_ip && does_entry_match_name(property->value.data, - property->value.length, name)) { - return 1; - } else if (like_ip && - strncmp(name, property->value.data, property->value.length) == - 0 && - strlen(name) == property->value.length) { - /* IP Addresses are exact matches only. */ - return 1; - } - } else if (strcmp(property->name, - TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY) == 0) { - cn_property = property; - } - } - - /* If there's no SAN, try the CN, but only if its not like an IP Address */ - if (san_count == 0 && cn_property != NULL && !like_ip) { - if (does_entry_match_name(cn_property->value.data, - cn_property->value.length, name)) { - return 1; - } - } - - return 0; /* Not found. */ -} diff --git a/src/core/tsi/ssl_transport_security.h b/src/core/tsi/ssl_transport_security.h deleted file mode 100644 index 612f5c64cc..0000000000 --- a/src/core/tsi/ssl_transport_security.h +++ /dev/null @@ -1,174 +0,0 @@ -/* - * - * Copyright 2015-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_TSI_SSL_TRANSPORT_SECURITY_H -#define GRPC_CORE_TSI_SSL_TRANSPORT_SECURITY_H - -#include "src/core/tsi/transport_security_interface.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* Value for the TSI_CERTIFICATE_TYPE_PEER_PROPERTY property for X509 certs. */ -#define TSI_X509_CERTIFICATE_TYPE "X509" - -/* This property is of type TSI_PEER_PROPERTY_STRING. */ -#define TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY "x509_subject_common_name" -#define TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY \ - "x509_subject_alternative_name" - -#define TSI_X509_PEM_CERT_PROPERTY "x509_pem_cert" - -#define TSI_SSL_ALPN_SELECTED_PROTOCOL "ssl_alpn_selected_protocol" - -/* --- tsi_ssl_handshaker_factory object --- - - This object creates tsi_handshaker objects implemented in terms of the - TLS 1.2 specificiation. */ - -typedef struct tsi_ssl_handshaker_factory tsi_ssl_handshaker_factory; - -/* Creates a client handshaker factory. - - pem_private_key is the buffer containing the PEM encoding of the client's - private key. This parameter can be NULL if the client does not have a - private key. - - pem_private_key_size is the size of the associated buffer. - - pem_cert_chain is the buffer containing the PEM encoding of the client's - certificate chain. This parameter can be NULL if the client does not have - a certificate chain. - - pem_cert_chain_size is the size of the associated buffer. - - pem_roots_cert is the buffer containing the PEM encoding of the server - root certificates. This parameter cannot be NULL. - - pem_roots_cert_size is the size of the associated buffer. - - cipher_suites contains an optional list of the ciphers that the client - supports. The format of this string is described in: - https://www.openssl.org/docs/apps/ciphers.html. - This parameter can be set to NULL to use the default set of ciphers. - TODO(jboeuf): Revisit the format of this parameter. - - alpn_protocols is an array containing the protocol names that the - handshakers created with this factory support. This parameter can be NULL. - - alpn_protocols_lengths is an array containing the lengths of the alpn - protocols specified in alpn_protocols. This parameter can be NULL. - - num_alpn_protocols is the number of alpn protocols and associated lengths - specified. If this parameter is 0, the other alpn parameters must be NULL. - - factory is the address of the factory pointer to be created. - - - This method returns TSI_OK on success or TSI_INVALID_PARAMETER in the case - where a parameter is invalid. */ -tsi_result tsi_create_ssl_client_handshaker_factory( - const unsigned char *pem_private_key, size_t pem_private_key_size, - const unsigned char *pem_cert_chain, size_t pem_cert_chain_size, - const unsigned char *pem_root_certs, size_t pem_root_certs_size, - const char *cipher_suites, const unsigned char **alpn_protocols, - const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols, - tsi_ssl_handshaker_factory **factory); - -/* Creates a server handshaker factory. - - version indicates which version of the specification to use. - - pem_private_keys is an array containing the PEM encoding of the server's - private keys. This parameter cannot be NULL. The size of the array is - given by the key_cert_pair_count parameter. - - pem_private_keys_sizes is the array containing the sizes of the associated - buffers. - - pem_cert_chains is an array containing the PEM encoding of the server's - cert chains. This parameter cannot be NULL. The size of the array is - given by the key_cert_pair_count parameter. - - pem_cert_chains_sizes is the array containing the sizes of the associated - buffers. - - key_cert_pair_count indicates the number of items in the private_key_files - and cert_chain_files parameters. - - pem_client_roots is the buffer containing the PEM encoding of the client - root certificates. This parameter may be NULL in which case the server will - not authenticate the client. If not NULL, the force_client_auth parameter - specifies if the server will accept only authenticated clients or both - authenticated and non-authenticated clients. - - pem_client_root_certs_size is the size of the associated buffer. - - force_client_auth, if set to non-zero will force the client to authenticate - with an SSL cert. Note that this option is ignored if pem_client_root_certs - is NULL or pem_client_roots_certs_size is 0 - - cipher_suites contains an optional list of the ciphers that the server - supports. The format of this string is described in: - https://www.openssl.org/docs/apps/ciphers.html. - This parameter can be set to NULL to use the default set of ciphers. - TODO(jboeuf): Revisit the format of this parameter. - - alpn_protocols is an array containing the protocol names that the - handshakers created with this factory support. This parameter can be NULL. - - alpn_protocols_lengths is an array containing the lengths of the alpn - protocols specified in alpn_protocols. This parameter can be NULL. - - num_alpn_protocols is the number of alpn protocols and associated lengths - specified. If this parameter is 0, the other alpn parameters must be NULL. - - factory is the address of the factory pointer to be created. - - - This method returns TSI_OK on success or TSI_INVALID_PARAMETER in the case - where a parameter is invalid. */ -tsi_result tsi_create_ssl_server_handshaker_factory( - const unsigned char **pem_private_keys, - const size_t *pem_private_keys_sizes, const unsigned char **pem_cert_chains, - const size_t *pem_cert_chains_sizes, size_t key_cert_pair_count, - const unsigned char *pem_client_root_certs, - size_t pem_client_root_certs_size, int force_client_auth, - const char *cipher_suites, const unsigned char **alpn_protocols, - const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols, - tsi_ssl_handshaker_factory **factory); - -/* Creates a handshaker. - - self is the factory from which the handshaker will be created. - - server_name_indication indicates the name of the server the client is - trying to connect to which will be relayed to the server using the SNI - extension. - This parameter must be NULL for a server handshaker factory. - - handhshaker is the address of the handshaker pointer to be created. - - - This method returns TSI_OK on success or TSI_INVALID_PARAMETER in the case - where a parameter is invalid. */ -tsi_result tsi_ssl_handshaker_factory_create_handshaker( - tsi_ssl_handshaker_factory *self, const char *server_name_indication, - tsi_handshaker **handshaker); - -/* Destroys the handshaker factory. WARNING: it is unsafe to destroy a factory - while handshakers created with this factory are still in use. */ -void tsi_ssl_handshaker_factory_destroy(tsi_ssl_handshaker_factory *self); - -/* Util that checks that an ssl peer matches a specific name. - Still TODO(jboeuf): - - handle mixed case. - - handle %encoded chars. - - handle public suffix wildchar more strictly (e.g. *.co.uk) */ -int tsi_ssl_peer_matches_name(const tsi_peer *peer, const char *name); - -#ifdef __cplusplus -} -#endif - -#endif /* GRPC_CORE_TSI_SSL_TRANSPORT_SECURITY_H */ diff --git a/src/core/tsi/ssl_types.h b/src/core/tsi/ssl_types.h deleted file mode 100644 index 6ea85fe6d4..0000000000 --- a/src/core/tsi/ssl_types.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * - * Copyright 2015-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_TSI_SSL_TYPES_H -#define GRPC_CORE_TSI_SSL_TYPES_H - -/* A collection of macros to cast between various integer types that are - * used differently between BoringSSL and OpenSSL: - * TSI_INT_AS_SIZE(x): convert 'int x' to a length parameter for an OpenSSL - * function - * TSI_SIZE_AS_SIZE(x): convert 'size_t x' to a length parameter for an OpenSSL - * function - */ - -#include - -#ifdef OPENSSL_IS_BORINGSSL -#define TSI_INT_AS_SIZE(x) ((size_t)(x)) -#define TSI_SIZE_AS_SIZE(x) (x) -#else -#define TSI_INT_AS_SIZE(x) (x) -#define TSI_SIZE_AS_SIZE(x) ((int)(x)) -#endif - -#endif /* GRPC_CORE_TSI_SSL_TYPES_H */ diff --git a/src/core/tsi/test_creds/README b/src/core/tsi/test_creds/README deleted file mode 100644 index eb8482d648..0000000000 --- a/src/core/tsi/test_creds/README +++ /dev/null @@ -1,62 +0,0 @@ -The test credentials (CONFIRMEDTESTKEY) have been generated with the following -commands: - -Bad credentials (badclient.* / badserver.*): -============================================ - -These are self-signed certificates: - -$ openssl req -x509 -newkey rsa:1024 -keyout badserver.key -out badserver.pem \ - -days 3650 -nodes - -When prompted for certificate information, everything is default except the -common name which is set to badserver.test.google.com. - - -Valid test credentials: -======================= - -The ca is self-signed: ----------------------- - -$ openssl req -x509 -new -newkey rsa:1024 -nodes -out ca.pem -config ca-openssl.cnf -days 3650 -extensions v3_req -When prompted for certificate information, everything is default. - -client is issued by CA: ------------------------ - -$ openssl genrsa -out client.key.rsa 1024 -$ openssl pkcs8 -topk8 -in client.key.rsa -out client.key -nocrypt -$ rm client.key.rsa -$ openssl req -new -key client.key -out client.csr - -When prompted for certificate information, everything is default except the -common name which is set to testclient. - -$ openssl ca -in client.csr -out client.pem - -server0 is issued by CA: ------------------------- - -$ openssl genrsa -out server0.key.rsa 1024 -$ openssl pkcs8 -topk8 -in server0.key.rsa -out server0.key -nocrypt -$ rm server0.key.rsa -$ openssl req -new -key server0.key -out server0.csr - -When prompted for certificate information, everything is default except the -common name which is set to *.test.google.com.au. - -$ openssl ca -in server0.csr -out server0.pem - -server1 is issued by CA with a special config for subject alternative names: ----------------------------------------------------------------------------- - -$ openssl genrsa -out server1.key.rsa 1024 -$ openssl pkcs8 -topk8 -in server1.key.rsa -out server1.key -nocrypt -$ rm server1.key.rsa -$ openssl req -new -key server1.key -out server1.csr -config server1-openssl.cnf - -When prompted for certificate information, everything is default except the -common name which is set to *.test.google.com. - -$ openssl ca -in server1.csr -out server1.pem diff --git a/src/core/tsi/test_creds/badclient.key b/src/core/tsi/test_creds/badclient.key deleted file mode 100644 index 5832685122..0000000000 --- a/src/core/tsi/test_creds/badclient.key +++ /dev/null @@ -1,16 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALJfYnFn4nkj52WF -E5W2qUxCfjsEFyuXYYKS/07UPWsv3gpZhtjXgdeGL+dpwEBC0IRDBfGnkMp6YY5S -O7rnEz0X3r/fvgYy+dEl2jnaA6zgc7RzMGl9U11d56gP9FiDC2190mvP/hpq2xLZ -CTbIximpmaoQyxuuH1bbYunesIG/AgMBAAECgYAdqJCEzMIyZE7oaW0tOpcB0BiP -FYoIvH4BKRH8eHvR476mt+YdDhBP1scGUmYeCT4Ej+RgHv2LPTgVYwT9eciP2+E/ -CBCNRel0Sw9JepwW0r+jWJtDY1pp6YXAgNRGX2UflvUsT+o9lZvagf9moLTMyGvU -uLFnsyfLim1B4vXvWQJBANouZllXGZoSrZLtR3VgV4tzRQvJxu84kLeIk64Ov47X -pHVBMTRBfzPEhbBodjr1m5OLaVLqkFcXftzRCrbWoKsCQQDRSoLLXOiLrtJ3DLJC -rX7Y8wrHZrqk5bMdZLGa/UX8RanhVw3+Xp+urd1711umeNJfzu/MCk4a1KkG/CU0 -rqs9AkA4cSx1DD1JSG+yxMNpsAS1xJomFIrsM9vsPt7FdndDwrF+y+CovhDkGYDk -RAHh+svGfZg/pQK2JRPimAmHhzqFAkEAu6Ya70s2FUeB3Mu9aJs2CD6hg3dQEVkB -53DI7TX48d9kGW58VX1xnqS02LyWqAPcW5qm1kLHFLdndaPNmBaj4QJBAJugl367 -9d9t/QLTSuULLaoYv2vJT3s1y9HN89EoaDDEkPVfQu6GVEXgIBtim1sI/VPSzI8H -aXvaTUwblFWSM70= ------END PRIVATE KEY----- diff --git a/src/core/tsi/test_creds/badclient.pem b/src/core/tsi/test_creds/badclient.pem deleted file mode 100644 index 1785970221..0000000000 --- a/src/core/tsi/test_creds/badclient.pem +++ /dev/null @@ -1,17 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICoDCCAgmgAwIBAgIJANIz2/zoRiapMA0GCSqGSIb3DQEBBQUAMGkxCzAJBgNV -BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX -aWRnaXRzIFB0eSBMdGQxIjAgBgNVBAMMGWJhZGNsaWVudC50ZXN0Lmdvb2dsZS5j -b20wHhcNMTQwNzI4MjAwODI1WhcNMjQwNzI1MjAwODI1WjBpMQswCQYDVQQGEwJB -VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 -cyBQdHkgTHRkMSIwIAYDVQQDDBliYWRjbGllbnQudGVzdC5nb29nbGUuY29tMIGf -MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyX2JxZ+J5I+dlhROVtqlMQn47BBcr -l2GCkv9O1D1rL94KWYbY14HXhi/nacBAQtCEQwXxp5DKemGOUju65xM9F96/374G -MvnRJdo52gOs4HO0czBpfVNdXeeoD/RYgwttfdJrz/4aatsS2Qk2yMYpqZmqEMsb -rh9W22Lp3rCBvwIDAQABo1AwTjAdBgNVHQ4EFgQU523AJMR8Ds9V8fhf7gu1i0MM -UqAwHwYDVR0jBBgwFoAU523AJMR8Ds9V8fhf7gu1i0MMUqAwDAYDVR0TBAUwAwEB -/zANBgkqhkiG9w0BAQUFAAOBgQCI/tvSBYH1iyfLaCTBKwpdj36+MkR9EeJJmImx -X+bjhKWXwsBX4PDMWvdusr++QGUYtyoya+hfYMXRhXua39mD54xgloQNuu9REDwX -Ffto+aOw3BcYducz6ofxicFK/Y2VeXDurSMpRv5TfGf2Qr6eOOdaRhj6ed7BibHk -X1VGZA== ------END CERTIFICATE----- diff --git a/src/core/tsi/test_creds/badserver.key b/src/core/tsi/test_creds/badserver.key deleted file mode 100644 index abfbde10ff..0000000000 --- a/src/core/tsi/test_creds/badserver.key +++ /dev/null @@ -1,16 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKeZ1e1y29cmBKaW -oIUwJ5neOJUjx+eD/3nRPe+dvLXEd9+db0fG5RYRR0S3mF1Ywuj4PIxlTW2YprUS -oGSw+tcqWNIzxv94HjwYFkkvER3AblXcDBh0P2zAkzg+nf9AcAsMh0QpDTyrXtMl -gqryjq1/vkhFofKMMbY+aXJdG6OBAgMBAAECgYAAgaB51S0A22aMMkxN2rVj6530 -JWWHN4jgD1fGj41wZyWNkWYyq1Ep3ed/N6bIMWp1VbqpGe0/9YQba/D8HOTFHGRt -72YXnP1e/ds8cxU4x4j1vvqSPtXpMmkiXfXijOvCl9mrMH2xjghFAt6/1Nb9xo1m -VdcOB8OdSuOIw6CI+QJBAN5FZUbS+bRXDWII/FaAih1DBpwCxhYEN+TXPJBxSen6 -kOzGt5g+mB6YqRMZ/qshshwPq7bsgFGfJ2lIdS2t3GsCQQDBCKifV5AAkOdOUrkK -HvoX3qnVmyIA8CyvWLcIWpfZ76QAYh0q0StedKdOMXaB1jTeSJ2KU1nlss7UD1Yw -VbrDAkAwjMHpbW3jiVw//Kx5jIwehiRscWKpLnSzBJyTBFvbwsJjJai2lX2OuVO8 -+2GYKb0Iyhd81j3VFkl6grwtpRtPAkB7+n+yt555fpfRKjhGU9b09cHGu7h/OcK5 -bBVCfE0DYHLI/DsXgPiF1g6Onh4rDdUu3xyv9xDKAqnscV099hHZAkEAvcFBfXZs -tk18N+bUcvXTdZjzZbfLCHlJmwPIspZ8G/6Pn63deg4GVYoCvTwGruah+8y734Ph -7PskfPgUQlB7Ag== ------END PRIVATE KEY----- diff --git a/src/core/tsi/test_creds/badserver.pem b/src/core/tsi/test_creds/badserver.pem deleted file mode 100644 index 983c979f31..0000000000 --- a/src/core/tsi/test_creds/badserver.pem +++ /dev/null @@ -1,17 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICoDCCAgmgAwIBAgIJAPdqwqsKNy81MA0GCSqGSIb3DQEBBQUAMGkxCzAJBgNV -BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX -aWRnaXRzIFB0eSBMdGQxIjAgBgNVBAMMGWJhZHNlcnZlci50ZXN0Lmdvb2dsZS5j -b20wHhcNMTQwNzI4MjAwODU0WhcNMjQwNzI1MjAwODU0WjBpMQswCQYDVQQGEwJB -VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 -cyBQdHkgTHRkMSIwIAYDVQQDDBliYWRzZXJ2ZXIudGVzdC5nb29nbGUuY29tMIGf -MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCnmdXtctvXJgSmlqCFMCeZ3jiVI8fn -g/950T3vnby1xHffnW9HxuUWEUdEt5hdWMLo+DyMZU1tmKa1EqBksPrXKljSM8b/ -eB48GBZJLxEdwG5V3AwYdD9swJM4Pp3/QHALDIdEKQ08q17TJYKq8o6tf75IRaHy -jDG2PmlyXRujgQIDAQABo1AwTjAdBgNVHQ4EFgQU3u/qvHr9knMBeZyAD7mAA/ec -8cUwHwYDVR0jBBgwFoAU3u/qvHr9knMBeZyAD7mAA/ec8cUwDAYDVR0TBAUwAwEB -/zANBgkqhkiG9w0BAQUFAAOBgQA/FmR1SGLguxCCfhp4CYCbrAePSyPWDi48gTwj -vVZf/OMxdVu/H8sBYFf27BjbrEugAw16DElFtgTZ83pLb2BvkUgb6vBUK5sEkgmh -z88zBsgDp8aCf4STDOLFZMBh/E9ZKkm1zogbEmlTjFp/ceSpa2gNv7OuN4WiorOh -Wvw40g== ------END CERTIFICATE----- diff --git a/src/core/tsi/test_creds/ca-openssl.cnf b/src/core/tsi/test_creds/ca-openssl.cnf deleted file mode 100644 index e97b945e4b..0000000000 --- a/src/core/tsi/test_creds/ca-openssl.cnf +++ /dev/null @@ -1,17 +0,0 @@ -[req] -distinguished_name = req_distinguished_name -req_extensions = v3_req - -[req_distinguished_name] -countryName = Country Name (2 letter code) -countryName_default = AU -stateOrProvinceName = State or Province Name (full name) -stateOrProvinceName_default = Some-State -organizationName = Organization Name (eg, company) -organizationName_default = Internet Widgits Pty Ltd -commonName = Common Name (eg, YOUR name) -commonName_default = testca - -[v3_req] -basicConstraints = CA:true -keyUsage = critical, keyCertSign diff --git a/src/core/tsi/test_creds/ca.key b/src/core/tsi/test_creds/ca.key deleted file mode 100644 index 03c4f950e3..0000000000 --- a/src/core/tsi/test_creds/ca.key +++ /dev/null @@ -1,16 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAMBA3wVeTGHZR1Ry -e/i+J8a2cu5gXwFV6TnObzGM7bLFCO5i9v4mLo4iFzPsHmWDUxKS3Y8iXbu0eYBl -LoNY0lSvxDx33O+DuwMmVN+DzSD+Eod9zfvwOWHsazYCZT2PhNxnVWIuJXViY4JA -HUGodjx+QAi6yCAurUZGvYXGgZSBAgMBAAECgYAxRi8i9BlFlufGSBVoGmydbJOm -bwLKl9dP3o33ODSP9hok5y6A0w5plWk3AJSF1hPLleK9VcSKYGYnt0clmPVHF35g -bx2rVK8dOT0mn7rz9Zr70jcSz1ETA2QonHZ+Y+niLmcic9At6hRtWiewblUmyFQm -GwggIzi7LOyEUHrEcQJBAOXxyQvnLvtKzXiqcsW/K6rExqVJVk+KF0fzzVyMzTJx -HRBxUVgvGdEJT7j+7P2kcTyafve0BBzDSPIaDyiJ+Y0CQQDWCb7jASFSbu5M3Zcd -Gkr4ZKN1XO3VLQX10b22bQYdF45hrTN2tnzRvVUR4q86VVnXmiGiTqmLkXcA2WWf -pHfFAkAhv9olUBo6MeF0i3frBEMRfm41hk0PwZHnMqZ6pgPcGnQMnMU2rzsXzkkQ -OwJnvAIOxhJKovZTjmofdqmw5odlAkBYVUdRWjsNUTjJwj3GRf6gyq/nFMYWz3EB -RWFdM1ttkDYzu45ctO2IhfHg4sPceDMO1s6AtKQmNI9/azkUjITdAkApNa9yFRzc -TBaDNPd5KVd58LVIzoPQ6i7uMHteLXJUWqSroji6S3s4gKMFJ/dO+ZXIlgQgfJJJ -ZDL4cdrdkeoM ------END PRIVATE KEY----- diff --git a/src/core/tsi/test_creds/ca.pem b/src/core/tsi/test_creds/ca.pem deleted file mode 100644 index 6c8511a73c..0000000000 --- a/src/core/tsi/test_creds/ca.pem +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICSjCCAbOgAwIBAgIJAJHGGR4dGioHMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV -BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX -aWRnaXRzIFB0eSBMdGQxDzANBgNVBAMTBnRlc3RjYTAeFw0xNDExMTEyMjMxMjla -Fw0yNDExMDgyMjMxMjlaMFYxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0 -YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDzANBgNVBAMT -BnRlc3RjYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwEDfBV5MYdlHVHJ7 -+L4nxrZy7mBfAVXpOc5vMYztssUI7mL2/iYujiIXM+weZYNTEpLdjyJdu7R5gGUu -g1jSVK/EPHfc74O7AyZU34PNIP4Sh33N+/A5YexrNgJlPY+E3GdVYi4ldWJjgkAd -Qah2PH5ACLrIIC6tRka9hcaBlIECAwEAAaMgMB4wDAYDVR0TBAUwAwEB/zAOBgNV -HQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADgYEAHzC7jdYlzAVmddi/gdAeKPau -sPBG/C2HCWqHzpCUHcKuvMzDVkY/MP2o6JIW2DBbY64bO/FceExhjcykgaYtCH/m -oIU63+CFOTtR7otyQAWHqXa7q4SbCDlG7DyRFxqG0txPtGvy12lgldA2+RgcigQG -Dfcog5wrJytaQ6UA0wE= ------END CERTIFICATE----- diff --git a/src/core/tsi/test_creds/client.key b/src/core/tsi/test_creds/client.key deleted file mode 100644 index f48d0735d9..0000000000 --- a/src/core/tsi/test_creds/client.key +++ /dev/null @@ -1,16 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIICeQIBADANBgkqhkiG9w0BAQEFAASCAmMwggJfAgEAAoGBAOxUR9uhvhbeVUIM -s5WbH0px0mehl2+6sZpNjzvE2KimZpHzMJHukVH0Ffkvhs0b8+S5Ut9VNUAqd3IM -JCCAEGtRNoQhM1t9Yr2zAckSvbRacp+FL/Cj9eDmyo00KsVGaeefA4Dh4OW+ZhkT -NKcldXqkSuj1sEf244JZYuqZp6/tAgMBAAECgYEAi2NSVqpZMafE5YYUTcMGe6QS -k2jtpsqYgggI2RnLJ/2tNZwYI5pwP8QVSbnMaiF4gokD5hGdrNDfTnb2v+yIwYEH -0w8+oG7Z81KodsiZSIDJfTGsAZhVNwOz9y0VD8BBZZ1/274Zh52AUKLjZS/ZwIbS -W2ywya855dPnH/wj+0ECQQD9X8D920kByTNHhBG18biAEZ4pxs9f0OAG8333eVcI -w2lJDLsYDZrCB2ocgA3lUdozlzPC7YDYw8reg0tkiRY5AkEA7sdNzOeQsQRn7++5 -0bP9DtT/iON1gbfxRzCfCfXdoOtfQWIzTePWtURt9X/5D9NofI0Rg5W2oGy/MLe5 -/sXHVQJBAIup5XrJDkQywNZyAUU2ecn2bCWBFjwtqd+LBmuMciI9fOKsZtEKZrz/ -U0lkeMRoSwvXE8wmGLjjrAbdfohrXFkCQQDZEx/LtIl6JINJQiswVe0tWr6k+ASP -1WXoTm+HYpoF/XUvv9LccNF1IazFj34hwRQwhx7w/V52Ieb+p0jUMYGxAkEAjDhd -9pBO1fKXWiXzi9ZKfoyTNcUq3eBSVKwPG2nItg5ycXengjT5sgcWDnciIzW7BIVI -JiqOszq9GWESErAatg== ------END PRIVATE KEY----- diff --git a/src/core/tsi/test_creds/client.pem b/src/core/tsi/test_creds/client.pem deleted file mode 100644 index e332091019..0000000000 --- a/src/core/tsi/test_creds/client.pem +++ /dev/null @@ -1,14 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICHzCCAYgCAQEwDQYJKoZIhvcNAQEFBQAwVjELMAkGA1UEBhMCQVUxEzARBgNV -BAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0 -ZDEPMA0GA1UEAwwGdGVzdGNhMB4XDTE0MDcxNzIzNTYwMloXDTI0MDcxNDIzNTYw -MlowWjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM -GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDETMBEGA1UEAwwKdGVzdGNsaWVudDCB -nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA7FRH26G+Ft5VQgyzlZsfSnHSZ6GX -b7qxmk2PO8TYqKZmkfMwke6RUfQV+S+GzRvz5LlS31U1QCp3cgwkIIAQa1E2hCEz -W31ivbMByRK9tFpyn4Uv8KP14ObKjTQqxUZp558DgOHg5b5mGRM0pyV1eqRK6PWw -R/bjglli6pmnr+0CAwEAATANBgkqhkiG9w0BAQUFAAOBgQAStSm5PM7ubROiKK6/ -T2FkKlhiTOx+Ryenm3Eio59emq+jXl+1nhPySX5G2PQzSR5vd1dIhwgZSR4Gyttk -tRZ57k/NI1brUW8joiEOMJA/Mr7H7asx7wIRYDE91Fs8GkKWd5LhoPAQj+qdG35C -OO+svdkmqH0KZo320ZUqdl2ooQ== ------END CERTIFICATE----- diff --git a/src/core/tsi/test_creds/server0.key b/src/core/tsi/test_creds/server0.key deleted file mode 100644 index add153c9ae..0000000000 --- a/src/core/tsi/test_creds/server0.key +++ /dev/null @@ -1,16 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANOmffupIGC8YDau -rOF4eKnHwPszgpkkhWzKsVxhNDBxCVYx4TEjG0XWIO0iyRXupZbUC+7N/8HnEVNa -8F1jYhng14Iiq99cNQbbnuHHhIztmpocrJTxmnhGzoAnRa1Tb+GnAuRoIHRA/V2c -VUE9tbikQugFx/SPgXAw6tfWB+YvAgMBAAECgYEAoEq9qzUBgoHoVEGiSPiWWe8g -5p6yUA1qx2QTQyWTAwT4z0DjjfVKmG99bFsl8+hTnJFnoCp/gnjflEOROwkjp5kG -m0drqOPx1jeipJjpXYTBu49h+WpZ1PF+KhVtxsIm3OOCvh67iWaKyyOVb5Og8aiR -jl6dn/TdG/dlGD8AfUECQQDuNMle6p0oU8amC6O9wIMBroxx2nFstzE6O35PLEzG -/tj0kxxn9Jp2TS9mGaLCzSuXmpjlF4+NOWiBPkrLC2TfAkEA43Xg7uEUkaJAz2/W -m1lIBTLt+4rIQY/2emh33bDcA+rv8rwwrMMIv17/xPx7bs49YqGG5xufD+Rwl6TL -qFXYsQJAPrOwagax1aKvwJeBw3oAQhoTKAkLIEXcdGqipe6QSzVcIIz0xjxxyEAr -AOIwoLxnBCISqwMXq2H4K0UdZPMb2wJAdhdYLY1L6YRMk6XjzImg25oidisKZweA -FvMv8DgHMj2CUAqmVrt3SivfLH1M9C09L3zfFhOAFHcsgX58gav4MQJBANSBnrHj -tIq4l8z79CPUIuu3QyeEh+XwY8s5qE5CNTck0U59lzp9NvENHbkx3KO896TTerko -+8bXHMLkJkHPXms= ------END PRIVATE KEY----- diff --git a/src/core/tsi/test_creds/server0.pem b/src/core/tsi/test_creds/server0.pem deleted file mode 100644 index ade75d8563..0000000000 --- a/src/core/tsi/test_creds/server0.pem +++ /dev/null @@ -1,14 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICHDCCAYUCAQQwDQYJKoZIhvcNAQEFBQAwVjELMAkGA1UEBhMCQVUxEzARBgNV -BAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0 -ZDEPMA0GA1UEAwwGdGVzdGNhMB4XDTE0MDcyMjE3NTk0OVoXDTI0MDcxOTE3NTk0 -OVowVzELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxFDASBgNVBAoM -C0dvb2dsZSBJbmMuMR0wGwYDVQQDDBQqLnRlc3QuZ29vZ2xlLmNvbS5hdTCBnzAN -BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA06Z9+6kgYLxgNq6s4Xh4qcfA+zOCmSSF -bMqxXGE0MHEJVjHhMSMbRdYg7SLJFe6lltQL7s3/wecRU1rwXWNiGeDXgiKr31w1 -Btue4ceEjO2amhyslPGaeEbOgCdFrVNv4acC5GggdED9XZxVQT21uKRC6AXH9I+B -cDDq19YH5i8CAwEAATANBgkqhkiG9w0BAQUFAAOBgQBtfR5qXG9TTI8YcYh7sA4V -GeNoplp0x6p7OG0NLvbJqAkUnkvjIkk1m1R2AUHhbkxzx6G75JIOoNJcWrCzywBA -BIsaTdmnNysf/s1hQJuD3IHiVb+7Ji0jhttnJlYcMid4o0tJO/a2E9YUxR+9cg0i -obb+Ql3qsvKdWBC1dDLDLw== ------END CERTIFICATE----- diff --git a/src/core/tsi/test_creds/server1-openssl.cnf b/src/core/tsi/test_creds/server1-openssl.cnf deleted file mode 100644 index 8a02108289..0000000000 --- a/src/core/tsi/test_creds/server1-openssl.cnf +++ /dev/null @@ -1,26 +0,0 @@ -[req] -distinguished_name = req_distinguished_name -req_extensions = v3_req - -[req_distinguished_name] -countryName = Country Name (2 letter code) -countryName_default = US -stateOrProvinceName = State or Province Name (full name) -stateOrProvinceName_default = Illinois -localityName = Locality Name (eg, city) -localityName_default = Chicago -organizationName = Organization Name (eg, company) -organizationName_default = Example, Co. -commonName = Common Name (eg, YOUR name) -commonName_max = 64 - -[v3_req] -basicConstraints = CA:FALSE -keyUsage = nonRepudiation, digitalSignature, keyEncipherment -subjectAltName = @alt_names - -[alt_names] -DNS.1 = *.test.google.fr -DNS.2 = waterzooi.test.google.be -DNS.3 = *.test.youtube.com -IP.1 = "192.168.1.3" diff --git a/src/core/tsi/test_creds/server1.key b/src/core/tsi/test_creds/server1.key deleted file mode 100644 index 143a5b8765..0000000000 --- a/src/core/tsi/test_creds/server1.key +++ /dev/null @@ -1,16 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAOHDFScoLCVJpYDD -M4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1BgzkWF+slf -3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd9N8YwbBY -AckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAECgYAn7qGnM2vbjJNBm0VZCkOkTIWm -V10okw7EPJrdL2mkre9NasghNXbE1y5zDshx5Nt3KsazKOxTT8d0Jwh/3KbaN+YY -tTCbKGW0pXDRBhwUHRcuRzScjli8Rih5UOCiZkhefUTcRb6xIhZJuQy71tjaSy0p -dHZRmYyBYO2YEQ8xoQJBAPrJPhMBkzmEYFtyIEqAxQ/o/A6E+E4w8i+KM7nQCK7q -K4JXzyXVAjLfyBZWHGM2uro/fjqPggGD6QH1qXCkI4MCQQDmdKeb2TrKRh5BY1LR -81aJGKcJ2XbcDu6wMZK4oqWbTX2KiYn9GB0woM6nSr/Y6iy1u145YzYxEV/iMwff -DJULAkB8B2MnyzOg0pNFJqBJuH29bKCcHa8gHJzqXhNO5lAlEbMK95p/P2Wi+4Hd -aiEIAF1BF326QJcvYKmwSmrORp85AkAlSNxRJ50OWrfMZnBgzVjDx3xG6KsFQVk2 -ol6VhqL6dFgKUORFUWBvnKSyhjJxurlPEahV6oo6+A+mPhFY8eUvAkAZQyTdupP3 -XEFQKctGz+9+gKkemDp7LBBMEMBXrGTLPhpEfcjv/7KPdnFHYmhYeBTBnuVmTVWe -F98XJ7tIFfJq ------END PRIVATE KEY----- diff --git a/src/core/tsi/test_creds/server1.pem b/src/core/tsi/test_creds/server1.pem deleted file mode 100644 index f3d43fcc5b..0000000000 --- a/src/core/tsi/test_creds/server1.pem +++ /dev/null @@ -1,16 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICnDCCAgWgAwIBAgIBBzANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJBVTET -MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ -dHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2EwHhcNMTUxMTA0MDIyMDI0WhcNMjUxMTAx -MDIyMDI0WjBlMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV -BAcTB0NoaWNhZ28xFTATBgNVBAoTDEV4YW1wbGUsIENvLjEaMBgGA1UEAxQRKi50 -ZXN0Lmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOHDFSco -LCVJpYDDM4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1Bg -zkWF+slf3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd -9N8YwbBYAckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAGjazBpMAkGA1UdEwQCMAAw -CwYDVR0PBAQDAgXgME8GA1UdEQRIMEaCECoudGVzdC5nb29nbGUuZnKCGHdhdGVy -em9vaS50ZXN0Lmdvb2dsZS5iZYISKi50ZXN0LnlvdXR1YmUuY29thwTAqAEDMA0G -CSqGSIb3DQEBCwUAA4GBAJFXVifQNub1LUP4JlnX5lXNlo8FxZ2a12AFQs+bzoJ6 -hM044EDjqyxUqSbVePK0ni3w1fHQB5rY9yYC5f8G7aqqTY1QOhoUk8ZTSTRpnkTh -y4jjdvTZeLDVBlueZUTDRmy2feY5aZIU18vFDK08dTG0A87pppuv1LNIR3loveU8 ------END CERTIFICATE----- diff --git a/src/core/tsi/transport_security.c b/src/core/tsi/transport_security.c deleted file mode 100644 index db219a50a6..0000000000 --- a/src/core/tsi/transport_security.c +++ /dev/null @@ -1,284 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/tsi/transport_security.h" - -#include -#include - -/* --- Tracing. --- */ - -int tsi_tracing_enabled = 0; - -/* --- Utils. --- */ - -char *tsi_strdup(const char *src) { - char *dst; - size_t len; - if (!src) return NULL; - len = strlen(src) + 1; - dst = malloc(len); - if (!dst) return NULL; - memcpy(dst, src, len); - return dst; -} - -/* --- tsi_result common implementation. --- */ - -const char *tsi_result_to_string(tsi_result result) { - switch (result) { - case TSI_OK: - return "TSI_OK"; - case TSI_UNKNOWN_ERROR: - return "TSI_UNKNOWN_ERROR"; - case TSI_INVALID_ARGUMENT: - return "TSI_INVALID_ARGUMENT"; - case TSI_PERMISSION_DENIED: - return "TSI_PERMISSION_DENIED"; - case TSI_INCOMPLETE_DATA: - return "TSI_INCOMPLETE_DATA"; - case TSI_FAILED_PRECONDITION: - return "TSI_FAILED_PRECONDITION"; - case TSI_UNIMPLEMENTED: - return "TSI_UNIMPLEMENTED"; - case TSI_INTERNAL_ERROR: - return "TSI_INTERNAL_ERROR"; - case TSI_DATA_CORRUPTED: - return "TSI_DATA_CORRUPTED"; - case TSI_NOT_FOUND: - return "TSI_NOT_FOUND"; - case TSI_PROTOCOL_FAILURE: - return "TSI_PROTOCOL_FAILURE"; - case TSI_HANDSHAKE_IN_PROGRESS: - return "TSI_HANDSHAKE_IN_PROGRESS"; - case TSI_OUT_OF_RESOURCES: - return "TSI_OUT_OF_RESOURCES"; - default: - return "UNKNOWN"; - } -} - -/* --- tsi_frame_protector common implementation. --- - - Calls specific implementation after state/input validation. */ - -tsi_result tsi_frame_protector_protect(tsi_frame_protector *self, - const unsigned char *unprotected_bytes, - size_t *unprotected_bytes_size, - unsigned char *protected_output_frames, - size_t *protected_output_frames_size) { - if (self == NULL || unprotected_bytes == NULL || - unprotected_bytes_size == NULL || protected_output_frames == NULL || - protected_output_frames_size == NULL) { - return TSI_INVALID_ARGUMENT; - } - return self->vtable->protect(self, unprotected_bytes, unprotected_bytes_size, - protected_output_frames, - protected_output_frames_size); -} - -tsi_result tsi_frame_protector_protect_flush( - tsi_frame_protector *self, unsigned char *protected_output_frames, - size_t *protected_output_frames_size, size_t *still_pending_size) { - if (self == NULL || protected_output_frames == NULL || - protected_output_frames == NULL || still_pending_size == NULL) { - return TSI_INVALID_ARGUMENT; - } - return self->vtable->protect_flush(self, protected_output_frames, - protected_output_frames_size, - still_pending_size); -} - -tsi_result tsi_frame_protector_unprotect( - tsi_frame_protector *self, const unsigned char *protected_frames_bytes, - size_t *protected_frames_bytes_size, unsigned char *unprotected_bytes, - size_t *unprotected_bytes_size) { - if (self == NULL || protected_frames_bytes == NULL || - protected_frames_bytes_size == NULL || unprotected_bytes == NULL || - unprotected_bytes_size == NULL) { - return TSI_INVALID_ARGUMENT; - } - return self->vtable->unprotect(self, protected_frames_bytes, - protected_frames_bytes_size, unprotected_bytes, - unprotected_bytes_size); -} - -void tsi_frame_protector_destroy(tsi_frame_protector *self) { - if (self == NULL) return; - self->vtable->destroy(self); -} - -/* --- tsi_handshaker common implementation. --- - - Calls specific implementation after state/input validation. */ - -tsi_result tsi_handshaker_get_bytes_to_send_to_peer(tsi_handshaker *self, - unsigned char *bytes, - size_t *bytes_size) { - if (self == NULL || bytes == NULL || bytes_size == NULL) { - return TSI_INVALID_ARGUMENT; - } - if (self->frame_protector_created) return TSI_FAILED_PRECONDITION; - return self->vtable->get_bytes_to_send_to_peer(self, bytes, bytes_size); -} - -tsi_result tsi_handshaker_process_bytes_from_peer(tsi_handshaker *self, - const unsigned char *bytes, - size_t *bytes_size) { - if (self == NULL || bytes == NULL || bytes_size == NULL) { - return TSI_INVALID_ARGUMENT; - } - if (self->frame_protector_created) return TSI_FAILED_PRECONDITION; - return self->vtable->process_bytes_from_peer(self, bytes, bytes_size); -} - -tsi_result tsi_handshaker_get_result(tsi_handshaker *self) { - if (self == NULL) return TSI_INVALID_ARGUMENT; - if (self->frame_protector_created) return TSI_FAILED_PRECONDITION; - return self->vtable->get_result(self); -} - -tsi_result tsi_handshaker_extract_peer(tsi_handshaker *self, tsi_peer *peer) { - if (self == NULL || peer == NULL) return TSI_INVALID_ARGUMENT; - memset(peer, 0, sizeof(tsi_peer)); - if (self->frame_protector_created) return TSI_FAILED_PRECONDITION; - if (tsi_handshaker_get_result(self) != TSI_OK) { - return TSI_FAILED_PRECONDITION; - } - return self->vtable->extract_peer(self, peer); -} - -tsi_result tsi_handshaker_create_frame_protector( - tsi_handshaker *self, size_t *max_protected_frame_size, - tsi_frame_protector **protector) { - tsi_result result; - if (self == NULL || protector == NULL) return TSI_INVALID_ARGUMENT; - if (self->frame_protector_created) return TSI_FAILED_PRECONDITION; - if (tsi_handshaker_get_result(self) != TSI_OK) { - return TSI_FAILED_PRECONDITION; - } - result = self->vtable->create_frame_protector(self, max_protected_frame_size, - protector); - if (result == TSI_OK) { - self->frame_protector_created = 1; - } - return result; -} - -void tsi_handshaker_destroy(tsi_handshaker *self) { - if (self == NULL) return; - self->vtable->destroy(self); -} - -/* --- tsi_peer implementation. --- */ - -tsi_peer_property tsi_init_peer_property(void) { - tsi_peer_property property; - memset(&property, 0, sizeof(tsi_peer_property)); - return property; -} - -static void tsi_peer_destroy_list_property(tsi_peer_property *children, - size_t child_count) { - size_t i; - for (i = 0; i < child_count; i++) { - tsi_peer_property_destruct(&children[i]); - } - free(children); -} - -void tsi_peer_property_destruct(tsi_peer_property *property) { - if (property->name != NULL) { - free(property->name); - } - if (property->value.data != NULL) { - free(property->value.data); - } - *property = tsi_init_peer_property(); /* Reset everything to 0. */ -} - -void tsi_peer_destruct(tsi_peer *self) { - if (self == NULL) return; - if (self->properties != NULL) { - tsi_peer_destroy_list_property(self->properties, self->property_count); - self->properties = NULL; - } - self->property_count = 0; -} - -tsi_result tsi_construct_allocated_string_peer_property( - const char *name, size_t value_length, tsi_peer_property *property) { - *property = tsi_init_peer_property(); - if (name != NULL) { - property->name = tsi_strdup(name); - if (property->name == NULL) return TSI_OUT_OF_RESOURCES; - } - if (value_length > 0) { - property->value.data = calloc(1, value_length); - if (property->value.data == NULL) { - tsi_peer_property_destruct(property); - return TSI_OUT_OF_RESOURCES; - } - property->value.length = value_length; - } - return TSI_OK; -} - -tsi_result tsi_construct_string_peer_property_from_cstring( - const char *name, const char *value, tsi_peer_property *property) { - return tsi_construct_string_peer_property(name, value, strlen(value), - property); -} - -tsi_result tsi_construct_string_peer_property(const char *name, - const char *value, - size_t value_length, - tsi_peer_property *property) { - tsi_result result = tsi_construct_allocated_string_peer_property( - name, value_length, property); - if (result != TSI_OK) return result; - if (value_length > 0) { - memcpy(property->value.data, value, value_length); - } - return TSI_OK; -} - -tsi_result tsi_construct_peer(size_t property_count, tsi_peer *peer) { - memset(peer, 0, sizeof(tsi_peer)); - if (property_count > 0) { - peer->properties = calloc(property_count, sizeof(tsi_peer_property)); - if (peer->properties == NULL) return TSI_OUT_OF_RESOURCES; - peer->property_count = property_count; - } - return TSI_OK; -} diff --git a/src/core/tsi/transport_security.h b/src/core/tsi/transport_security.h deleted file mode 100644 index ecc037193b..0000000000 --- a/src/core/tsi/transport_security.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * - * Copyright 2015-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_TSI_TRANSPORT_SECURITY_H -#define GRPC_CORE_TSI_TRANSPORT_SECURITY_H - -#include "src/core/tsi/transport_security_interface.h" - -#ifdef __cplusplus -extern "C" { -#endif - -extern int tsi_tracing_enabled; - -/* Base for tsi_frame_protector implementations. - See transport_security_interface.h for documentation. */ -typedef struct { - tsi_result (*protect)(tsi_frame_protector *self, - const unsigned char *unprotected_bytes, - size_t *unprotected_bytes_size, - unsigned char *protected_output_frames, - size_t *protected_output_frames_size); - tsi_result (*protect_flush)(tsi_frame_protector *self, - unsigned char *protected_output_frames, - size_t *protected_output_frames_size, - size_t *still_pending_size); - tsi_result (*unprotect)(tsi_frame_protector *self, - const unsigned char *protected_frames_bytes, - size_t *protected_frames_bytes_size, - unsigned char *unprotected_bytes, - size_t *unprotected_bytes_size); - void (*destroy)(tsi_frame_protector *self); -} tsi_frame_protector_vtable; - -struct tsi_frame_protector { - const tsi_frame_protector_vtable *vtable; -}; - -/* Base for tsi_handshaker implementations. - See transport_security_interface.h for documentation. */ -typedef struct { - tsi_result (*get_bytes_to_send_to_peer)(tsi_handshaker *self, - unsigned char *bytes, - size_t *bytes_size); - tsi_result (*process_bytes_from_peer)(tsi_handshaker *self, - const unsigned char *bytes, - size_t *bytes_size); - tsi_result (*get_result)(tsi_handshaker *self); - tsi_result (*extract_peer)(tsi_handshaker *self, tsi_peer *peer); - tsi_result (*create_frame_protector)(tsi_handshaker *self, - size_t *max_protected_frame_size, - tsi_frame_protector **protector); - void (*destroy)(tsi_handshaker *self); -} tsi_handshaker_vtable; - -struct tsi_handshaker { - const tsi_handshaker_vtable *vtable; - int frame_protector_created; -}; - -/* Peer and property construction/destruction functions. */ -tsi_result tsi_construct_peer(size_t property_count, tsi_peer *peer); -tsi_peer_property tsi_init_peer_property(void); -void tsi_peer_property_destruct(tsi_peer_property *property); -tsi_result tsi_construct_string_peer_property(const char *name, - const char *value, - size_t value_length, - tsi_peer_property *property); -tsi_result tsi_construct_allocated_string_peer_property( - const char *name, size_t value_length, tsi_peer_property *property); -tsi_result tsi_construct_string_peer_property_from_cstring( - const char *name, const char *value, tsi_peer_property *property); - -/* Utils. */ -char *tsi_strdup(const char *src); /* Sadly, no strdup in C89. */ - -#ifdef __cplusplus -} -#endif - -#endif /* GRPC_CORE_TSI_TRANSPORT_SECURITY_H */ diff --git a/src/core/tsi/transport_security_interface.h b/src/core/tsi/transport_security_interface.h deleted file mode 100644 index 08501802f5..0000000000 --- a/src/core/tsi/transport_security_interface.h +++ /dev/null @@ -1,344 +0,0 @@ -/* - * - * Copyright 2015-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_TSI_TRANSPORT_SECURITY_INTERFACE_H -#define GRPC_CORE_TSI_TRANSPORT_SECURITY_INTERFACE_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* --- tsi result --- */ - -typedef enum { - TSI_OK = 0, - TSI_UNKNOWN_ERROR = 1, - TSI_INVALID_ARGUMENT = 2, - TSI_PERMISSION_DENIED = 3, - TSI_INCOMPLETE_DATA = 4, - TSI_FAILED_PRECONDITION = 5, - TSI_UNIMPLEMENTED = 6, - TSI_INTERNAL_ERROR = 7, - TSI_DATA_CORRUPTED = 8, - TSI_NOT_FOUND = 9, - TSI_PROTOCOL_FAILURE = 10, - TSI_HANDSHAKE_IN_PROGRESS = 11, - TSI_OUT_OF_RESOURCES = 12 -} tsi_result; - -const char *tsi_result_to_string(tsi_result result); - -/* --- tsi tracing --- */ - -/* Set this early to avoid races */ -extern int tsi_tracing_enabled; - -/* --- tsi_frame_protector object --- - - This object protects and unprotects buffers once the handshake is done. - Implementations of this object must be thread compatible. */ - -typedef struct tsi_frame_protector tsi_frame_protector; - -/* Outputs protected frames. - - unprotected_bytes is an input only parameter and points to the data - to be protected. - - unprotected_bytes_size is an input/output parameter used by the caller to - specify how many bytes are available in unprotected_bytes. The output - value is the number of bytes consumed during the call. - - protected_output_frames points to a buffer allocated by the caller that - will be written. - - protected_output_frames_size is an input/output parameter used by the - caller to specify how many bytes are available in protected_output_frames. - As an output, this value indicates the number of bytes written. - - This method returns TSI_OK in case of success or a specific error code in - case of failure. Note that even if all the input unprotected bytes are - consumed, they may not have been processed into the returned protected - output frames. The caller should call the protect_flush method - to make sure that there are no more protected bytes buffered in the - protector. - - A typical way to call this method would be: - - ------------------------------------------------------------------------ - unsigned char protected_buffer[4096]; - size_t protected_buffer_size = sizeof(protected_buffer); - tsi_result result = TSI_OK; - while (message_size > 0) { - size_t protected_buffer_size_to_send = protected_buffer_size; - size_t processed_message_size = message_size; - result = tsi_frame_protector_protect(protector, - message_bytes, - &processed_message_size, - protected_buffer, - &protected_buffer_size_to_send); - if (result != TSI_OK) break; - send_bytes_to_peer(protected_buffer, protected_buffer_size_to_send); - message_bytes += processed_message_size; - message_size -= processed_message_size; - - // Don't forget to flush. - if (message_size == 0) { - size_t still_pending_size; - do { - protected_buffer_size_to_send = protected_buffer_size; - result = tsi_frame_protector_protect_flush( - protector, protected_buffer, - &protected_buffer_size_to_send, &still_pending_size); - if (result != TSI_OK) break; - send_bytes_to_peer(protected_buffer, protected_buffer_size_to_send); - } while (still_pending_size > 0); - } - } - - if (result != TSI_OK) HandleError(result); - ------------------------------------------------------------------------ */ -tsi_result tsi_frame_protector_protect(tsi_frame_protector *self, - const unsigned char *unprotected_bytes, - size_t *unprotected_bytes_size, - unsigned char *protected_output_frames, - size_t *protected_output_frames_size); - -/* Indicates that we need to flush the bytes buffered in the protector and get - the resulting frame. - - protected_output_frames points to a buffer allocated by the caller that - will be written. - - protected_output_frames_size is an input/output parameter used by the - caller to specify how many bytes are available in protected_output_frames. - - still_pending_bytes is an output parameter indicating the number of bytes - that still need to be flushed from the protector.*/ -tsi_result tsi_frame_protector_protect_flush( - tsi_frame_protector *self, unsigned char *protected_output_frames, - size_t *protected_output_frames_size, size_t *still_pending_size); - -/* Outputs unprotected bytes. - - protected_frames_bytes is an input only parameter and points to the - protected frames to be unprotected. - - protected_frames_bytes_size is an input/output only parameter used by the - caller to specify how many bytes are available in protected_bytes. The - output value is the number of bytes consumed during the call. - Implementations will buffer up to a frame of protected data. - - unprotected_bytes points to a buffer allocated by the caller that will be - written. - - unprotected_bytes_size is an input/output parameter used by the caller to - specify how many bytes are available in unprotected_bytes. This - value is expected to be at most max_protected_frame_size minus overhead - which means that max_protected_frame_size is a safe bet. The output value - is the number of bytes actually written. - If *unprotected_bytes_size is unchanged, there may be more data remaining - to unprotect, and the caller should call this function again. - - - This method returns TSI_OK in case of success. Success includes cases where - there is not enough data to output a frame in which case - unprotected_bytes_size will be set to 0 and cases where the internal buffer - needs to be read before new protected data can be processed in which case - protected_frames_size will be set to 0. */ -tsi_result tsi_frame_protector_unprotect( - tsi_frame_protector *self, const unsigned char *protected_frames_bytes, - size_t *protected_frames_bytes_size, unsigned char *unprotected_bytes, - size_t *unprotected_bytes_size); - -/* Destroys the tsi_frame_protector object. */ -void tsi_frame_protector_destroy(tsi_frame_protector *self); - -/* --- tsi_peer objects --- - - tsi_peer objects are a set of properties. The peer owns the properties. */ - -/* This property is of type TSI_PEER_PROPERTY_STRING. */ -#define TSI_CERTIFICATE_TYPE_PEER_PROPERTY "certificate_type" - -/* Property values may contain NULL characters just like C++ strings. - The length field gives the length of the string. */ -typedef struct tsi_peer_property { - char *name; - struct { - char *data; - size_t length; - } value; -} tsi_peer_property; - -typedef struct { - tsi_peer_property *properties; - size_t property_count; -} tsi_peer; - -/* Destructs the tsi_peer object. */ -void tsi_peer_destruct(tsi_peer *self); - -/* --- tsi_handshaker objects ---- - - Implementations of this object must be thread compatible. - - A typical usage of this object would be: - - ------------------------------------------------------------------------ - tsi_result result = TSI_OK; - unsigned char buf[4096]; - size_t buf_offset; - size_t buf_size; - while (1) { - // See if we need to send some bytes to the peer. - do { - size_t buf_size_to_send = sizeof(buf); - result = tsi_handshaker_get_bytes_to_send_to_peer(handshaker, buf, - &buf_size_to_send); - if (buf_size_to_send > 0) send_bytes_to_peer(buf, buf_size_to_send); - } while (result == TSI_INCOMPLETE_DATA); - if (result != TSI_OK) return result; - if (!tsi_handshaker_is_in_progress(handshaker)) break; - - do { - // Read bytes from the peer. - buf_size = sizeof(buf); - buf_offset = 0; - read_bytes_from_peer(buf, &buf_size); - if (buf_size == 0) break; - - // Process the bytes from the peer. We have to be careful as these bytes - // may contain non-handshake data (protected data). If this is the case, - // we will exit from the loop with buf_size > 0. - size_t consumed_by_handshaker = buf_size; - result = tsi_handshaker_process_bytes_from_peer( - handshaker, buf, &consumed_by_handshaker); - buf_size -= consumed_by_handshaker; - buf_offset += consumed_by_handshaker; - } while (result == TSI_INCOMPLETE_DATA); - - if (result != TSI_OK) return result; - if (!tsi_handshaker_is_in_progress(handshaker)) break; - } - - // Check the Peer. - tsi_peer peer; - do { - result = tsi_handshaker_extract_peer(handshaker, &peer); - if (result != TSI_OK) break; - result = check_peer(&peer); - } while (0); - tsi_peer_destruct(&peer); - if (result != TSI_OK) return result; - - // Create the protector. - tsi_frame_protector* protector = NULL; - result = tsi_handshaker_create_frame_protector(handshaker, NULL, - &protector); - if (result != TSI_OK) return result; - - // Do not forget to unprotect outstanding data if any. - if (buf_size > 0) { - result = tsi_frame_protector_unprotect(protector, buf + buf_offset, - buf_size, ..., ...); - .... - } - ... - ------------------------------------------------------------------------ */ -typedef struct tsi_handshaker tsi_handshaker; - -/* Gets bytes that need to be sent to the peer. - - bytes is the buffer that will be written with the data to be sent to the - peer. - - bytes_size is an input/output parameter specifying the capacity of the - bytes parameter as input and the number of bytes written as output. - Returns TSI_OK if all the data to send to the peer has been written or if - nothing has to be sent to the peer (in which base bytes_size outputs to 0), - otherwise returns TSI_INCOMPLETE_DATA which indicates that this method - needs to be called again to get all the bytes to send to the peer (there - was more data to write than the specified bytes_size). In case of a fatal - error in the handshake, another specific error code is returned. */ -tsi_result tsi_handshaker_get_bytes_to_send_to_peer(tsi_handshaker *self, - unsigned char *bytes, - size_t *bytes_size); - -/* Processes bytes received from the peer. - - bytes is the buffer containing the data. - - bytes_size is an input/output parameter specifying the size of the data as - input and the number of bytes consumed as output. - Return TSI_OK if the handshake has all the data it needs to process, - otherwise return TSI_INCOMPLETE_DATA which indicates that this method - needs to be called again to complete the data needed for processing. In - case of a fatal error in the handshake, another specific error code is - returned. */ -tsi_result tsi_handshaker_process_bytes_from_peer(tsi_handshaker *self, - const unsigned char *bytes, - size_t *bytes_size); - -/* Gets the result of the handshaker. - Returns TSI_OK if the hanshake completed successfully and there has been no - errors. Returns TSI_HANDSHAKE_IN_PROGRESS if the handshaker is not done yet - but no error has been encountered so far. Otherwise the handshaker failed - with the returned error. */ -tsi_result tsi_handshaker_get_result(tsi_handshaker *self); - -/* Returns 1 if the handshake is in progress, 0 otherwise. */ -#define tsi_handshaker_is_in_progress(h) \ - (tsi_handshaker_get_result((h)) == TSI_HANDSHAKE_IN_PROGRESS) - -/* This method may return TSI_FAILED_PRECONDITION if - tsi_handshaker_is_in_progress returns 1, it returns TSI_OK otherwise - assuming the handshaker is not in a fatal error state. - The caller is responsible for destructing the peer. */ -tsi_result tsi_handshaker_extract_peer(tsi_handshaker *self, tsi_peer *peer); - -/* This method creates a tsi_frame_protector object after the handshake phase - is done. After this method has been called successfully, the only method - that can be called on this object is Destroy. - - max_output_protected_frame_size is an input/output parameter specifying the - desired max output protected frame size as input and outputing the actual - max output frame size as the output. Passing NULL is OK and will result in - the implementation choosing the default maximum protected frame size. Note - that this size only applies to outgoing frames (generated with - tsi_frame_protector_protect) and not incoming frames (input of - tsi_frame_protector_unprotect). - - protector is an output parameter pointing to the newly created - tsi_frame_protector object. - This method may return TSI_FAILED_PRECONDITION if - tsi_handshaker_is_in_progress returns 1, it returns TSI_OK otherwise assuming - the handshaker is not in a fatal error state. - The caller is responsible for destroying the protector. */ -tsi_result tsi_handshaker_create_frame_protector( - tsi_handshaker *self, size_t *max_output_protected_frame_size, - tsi_frame_protector **protector); - -/* This method releases the tsi_handshaker object. After this method is called, - no other method can be called on the object. */ -void tsi_handshaker_destroy(tsi_handshaker *self); - -#ifdef __cplusplus -} -#endif - -#endif /* GRPC_CORE_TSI_TRANSPORT_SECURITY_INTERFACE_H */ diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py index 27cd8d60bc..a5bc18af5e 100644 --- a/src/python/grpcio/grpc_core_dependencies.py +++ b/src/python/grpcio/grpc_core_dependencies.py @@ -30,211 +30,211 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_core_dependencies.py.template`!!! CORE_SOURCE_FILES = [ - 'src/core/profiling/basic_timers.c', - 'src/core/profiling/stap_timers.c', - 'src/core/support/alloc.c', - 'src/core/support/avl.c', - 'src/core/support/backoff.c', - 'src/core/support/cmdline.c', - 'src/core/support/cpu_iphone.c', - 'src/core/support/cpu_linux.c', - 'src/core/support/cpu_posix.c', - 'src/core/support/cpu_windows.c', - 'src/core/support/env_linux.c', - 'src/core/support/env_posix.c', - 'src/core/support/env_win32.c', - 'src/core/support/histogram.c', - 'src/core/support/host_port.c', - 'src/core/support/load_file.c', - 'src/core/support/log.c', - 'src/core/support/log_android.c', - 'src/core/support/log_linux.c', - 'src/core/support/log_posix.c', - 'src/core/support/log_win32.c', - 'src/core/support/murmur_hash.c', - 'src/core/support/slice.c', - 'src/core/support/slice_buffer.c', - 'src/core/support/stack_lockfree.c', - 'src/core/support/string.c', - 'src/core/support/string_posix.c', - 'src/core/support/string_win32.c', - 'src/core/support/subprocess_posix.c', - 'src/core/support/subprocess_windows.c', - 'src/core/support/sync.c', - 'src/core/support/sync_posix.c', - 'src/core/support/sync_win32.c', - 'src/core/support/thd.c', - 'src/core/support/thd_posix.c', - 'src/core/support/thd_win32.c', - 'src/core/support/time.c', - 'src/core/support/time_posix.c', - 'src/core/support/time_precise.c', - 'src/core/support/time_win32.c', - 'src/core/support/tls_pthread.c', - 'src/core/support/tmpfile_posix.c', - 'src/core/support/tmpfile_win32.c', - 'src/core/support/wrap_memcpy.c', - 'src/core/census/grpc_context.c', - 'src/core/census/grpc_filter.c', - 'src/core/census/grpc_plugin.c', - 'src/core/channel/channel_args.c', - 'src/core/channel/channel_stack.c', - 'src/core/channel/channel_stack_builder.c', - 'src/core/channel/client_channel.c', - 'src/core/channel/compress_filter.c', - 'src/core/channel/connected_channel.c', - 'src/core/channel/http_client_filter.c', - 'src/core/channel/http_server_filter.c', - 'src/core/channel/subchannel_call_holder.c', - 'src/core/client_config/client_config.c', - 'src/core/client_config/connector.c', - 'src/core/client_config/default_initial_connect_string.c', - 'src/core/client_config/initial_connect_string.c', - 'src/core/client_config/lb_policies/load_balancer_api.c', - 'src/core/client_config/lb_policies/pick_first.c', - 'src/core/client_config/lb_policies/round_robin.c', - 'src/core/client_config/lb_policy.c', - 'src/core/client_config/lb_policy_factory.c', - 'src/core/client_config/lb_policy_registry.c', - 'src/core/client_config/resolver.c', - 'src/core/client_config/resolver_factory.c', - 'src/core/client_config/resolver_registry.c', - 'src/core/client_config/resolvers/dns_resolver.c', - 'src/core/client_config/resolvers/sockaddr_resolver.c', - 'src/core/client_config/subchannel.c', - 'src/core/client_config/subchannel_factory.c', - 'src/core/client_config/subchannel_index.c', - 'src/core/client_config/uri_parser.c', - 'src/core/compression/compression_algorithm.c', - 'src/core/compression/message_compress.c', - 'src/core/debug/trace.c', - 'src/core/http/format_request.c', - 'src/core/http/httpcli.c', - 'src/core/http/parser.c', - 'src/core/iomgr/closure.c', - 'src/core/iomgr/endpoint.c', - 'src/core/iomgr/endpoint_pair_posix.c', - 'src/core/iomgr/endpoint_pair_windows.c', - 'src/core/iomgr/exec_ctx.c', - 'src/core/iomgr/executor.c', - 'src/core/iomgr/fd_posix.c', - 'src/core/iomgr/iocp_windows.c', - 'src/core/iomgr/iomgr.c', - 'src/core/iomgr/iomgr_posix.c', - 'src/core/iomgr/iomgr_windows.c', - 'src/core/iomgr/pollset_multipoller_with_epoll.c', - 'src/core/iomgr/pollset_multipoller_with_poll_posix.c', - 'src/core/iomgr/pollset_posix.c', - 'src/core/iomgr/pollset_set_posix.c', - 'src/core/iomgr/pollset_set_windows.c', - 'src/core/iomgr/pollset_windows.c', - 'src/core/iomgr/resolve_address_posix.c', - 'src/core/iomgr/resolve_address_windows.c', - 'src/core/iomgr/sockaddr_utils.c', - 'src/core/iomgr/socket_utils_common_posix.c', - 'src/core/iomgr/socket_utils_linux.c', - 'src/core/iomgr/socket_utils_posix.c', - 'src/core/iomgr/socket_windows.c', - 'src/core/iomgr/tcp_client_posix.c', - 'src/core/iomgr/tcp_client_windows.c', - 'src/core/iomgr/tcp_posix.c', - 'src/core/iomgr/tcp_server_posix.c', - 'src/core/iomgr/tcp_server_windows.c', - 'src/core/iomgr/tcp_windows.c', - 'src/core/iomgr/time_averaged_stats.c', - 'src/core/iomgr/timer.c', - 'src/core/iomgr/timer_heap.c', - 'src/core/iomgr/udp_server.c', - 'src/core/iomgr/unix_sockets_posix.c', - 'src/core/iomgr/unix_sockets_posix_noop.c', - 'src/core/iomgr/wakeup_fd_eventfd.c', - 'src/core/iomgr/wakeup_fd_nospecial.c', - 'src/core/iomgr/wakeup_fd_pipe.c', - 'src/core/iomgr/wakeup_fd_posix.c', - 'src/core/iomgr/workqueue_posix.c', - 'src/core/iomgr/workqueue_windows.c', - 'src/core/json/json.c', - 'src/core/json/json_reader.c', - 'src/core/json/json_string.c', - 'src/core/json/json_writer.c', - 'src/core/proto/grpc/lb/v0/load_balancer.pb.c', - 'src/core/surface/alarm.c', - 'src/core/surface/api_trace.c', - 'src/core/surface/byte_buffer.c', - 'src/core/surface/byte_buffer_reader.c', - '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/channel_init.c', - 'src/core/surface/channel_ping.c', - 'src/core/surface/channel_stack_type.c', - 'src/core/surface/completion_queue.c', - 'src/core/surface/event_string.c', - 'src/core/surface/init.c', - 'src/core/surface/lame_client.c', - 'src/core/surface/metadata_array.c', - 'src/core/surface/server.c', - 'src/core/surface/server_chttp2.c', - 'src/core/surface/validate_metadata.c', - 'src/core/surface/version.c', - 'src/core/transport/byte_stream.c', - 'src/core/transport/chttp2/alpn.c', - 'src/core/transport/chttp2/bin_encoder.c', - 'src/core/transport/chttp2/frame_data.c', - 'src/core/transport/chttp2/frame_goaway.c', - 'src/core/transport/chttp2/frame_ping.c', - 'src/core/transport/chttp2/frame_rst_stream.c', - 'src/core/transport/chttp2/frame_settings.c', - 'src/core/transport/chttp2/frame_window_update.c', - 'src/core/transport/chttp2/hpack_encoder.c', - 'src/core/transport/chttp2/hpack_parser.c', - 'src/core/transport/chttp2/hpack_table.c', - 'src/core/transport/chttp2/huffsyms.c', - 'src/core/transport/chttp2/incoming_metadata.c', - 'src/core/transport/chttp2/parsing.c', - 'src/core/transport/chttp2/status_conversion.c', - 'src/core/transport/chttp2/stream_lists.c', - 'src/core/transport/chttp2/stream_map.c', - 'src/core/transport/chttp2/timeout_encoding.c', - 'src/core/transport/chttp2/varint.c', - 'src/core/transport/chttp2/writing.c', - 'src/core/transport/chttp2_transport.c', - 'src/core/transport/connectivity_state.c', - 'src/core/transport/metadata.c', - 'src/core/transport/metadata_batch.c', - 'src/core/transport/static_metadata.c', - 'src/core/transport/transport.c', - 'src/core/transport/transport_op_string.c', - 'src/core/http/httpcli_security_connector.c', - 'src/core/security/b64.c', - 'src/core/security/client_auth_filter.c', - 'src/core/security/credentials.c', - 'src/core/security/credentials_metadata.c', - 'src/core/security/credentials_posix.c', - 'src/core/security/credentials_win32.c', - 'src/core/security/google_default_credentials.c', - 'src/core/security/handshake.c', - 'src/core/security/json_token.c', - 'src/core/security/jwt_verifier.c', - 'src/core/security/secure_endpoint.c', - 'src/core/security/security_connector.c', - 'src/core/security/security_context.c', - 'src/core/security/server_auth_filter.c', - 'src/core/security/server_secure_chttp2.c', - 'src/core/surface/init_secure.c', - 'src/core/surface/secure_channel_create.c', - 'src/core/tsi/fake_transport_security.c', - 'src/core/tsi/ssl_transport_security.c', - 'src/core/tsi/transport_security.c', - 'src/core/census/context.c', - 'src/core/census/initialize.c', - 'src/core/census/mlog.c', - 'src/core/census/operation.c', - 'src/core/census/placeholders.c', - 'src/core/census/tracing.c', + 'src/core/lib/profiling/basic_timers.c', + 'src/core/lib/profiling/stap_timers.c', + 'src/core/lib/support/alloc.c', + 'src/core/lib/support/avl.c', + 'src/core/lib/support/backoff.c', + 'src/core/lib/support/cmdline.c', + 'src/core/lib/support/cpu_iphone.c', + 'src/core/lib/support/cpu_linux.c', + 'src/core/lib/support/cpu_posix.c', + 'src/core/lib/support/cpu_windows.c', + 'src/core/lib/support/env_linux.c', + 'src/core/lib/support/env_posix.c', + 'src/core/lib/support/env_win32.c', + 'src/core/lib/support/histogram.c', + 'src/core/lib/support/host_port.c', + 'src/core/lib/support/load_file.c', + 'src/core/lib/support/log.c', + 'src/core/lib/support/log_android.c', + 'src/core/lib/support/log_linux.c', + 'src/core/lib/support/log_posix.c', + 'src/core/lib/support/log_win32.c', + 'src/core/lib/support/murmur_hash.c', + 'src/core/lib/support/slice.c', + 'src/core/lib/support/slice_buffer.c', + 'src/core/lib/support/stack_lockfree.c', + 'src/core/lib/support/string.c', + 'src/core/lib/support/string_posix.c', + 'src/core/lib/support/string_win32.c', + 'src/core/lib/support/subprocess_posix.c', + 'src/core/lib/support/subprocess_windows.c', + 'src/core/lib/support/sync.c', + 'src/core/lib/support/sync_posix.c', + 'src/core/lib/support/sync_win32.c', + 'src/core/lib/support/thd.c', + 'src/core/lib/support/thd_posix.c', + 'src/core/lib/support/thd_win32.c', + 'src/core/lib/support/time.c', + 'src/core/lib/support/time_posix.c', + 'src/core/lib/support/time_precise.c', + 'src/core/lib/support/time_win32.c', + 'src/core/lib/support/tls_pthread.c', + 'src/core/lib/support/tmpfile_posix.c', + 'src/core/lib/support/tmpfile_win32.c', + 'src/core/lib/support/wrap_memcpy.c', + 'src/core/lib/census/grpc_context.c', + 'src/core/lib/census/grpc_filter.c', + 'src/core/lib/census/grpc_plugin.c', + 'src/core/lib/channel/channel_args.c', + 'src/core/lib/channel/channel_stack.c', + 'src/core/lib/channel/channel_stack_builder.c', + 'src/core/lib/channel/client_channel.c', + 'src/core/lib/channel/compress_filter.c', + 'src/core/lib/channel/connected_channel.c', + 'src/core/lib/channel/http_client_filter.c', + 'src/core/lib/channel/http_server_filter.c', + 'src/core/lib/channel/subchannel_call_holder.c', + 'src/core/lib/client_config/client_config.c', + 'src/core/lib/client_config/connector.c', + 'src/core/lib/client_config/default_initial_connect_string.c', + 'src/core/lib/client_config/initial_connect_string.c', + 'src/core/lib/client_config/lb_policies/load_balancer_api.c', + 'src/core/lib/client_config/lb_policies/pick_first.c', + 'src/core/lib/client_config/lb_policies/round_robin.c', + 'src/core/lib/client_config/lb_policy.c', + 'src/core/lib/client_config/lb_policy_factory.c', + 'src/core/lib/client_config/lb_policy_registry.c', + 'src/core/lib/client_config/resolver.c', + 'src/core/lib/client_config/resolver_factory.c', + 'src/core/lib/client_config/resolver_registry.c', + 'src/core/lib/client_config/resolvers/dns_resolver.c', + 'src/core/lib/client_config/resolvers/sockaddr_resolver.c', + 'src/core/lib/client_config/subchannel.c', + 'src/core/lib/client_config/subchannel_factory.c', + 'src/core/lib/client_config/subchannel_index.c', + 'src/core/lib/client_config/uri_parser.c', + 'src/core/lib/compression/compression_algorithm.c', + 'src/core/lib/compression/message_compress.c', + 'src/core/lib/debug/trace.c', + 'src/core/lib/http/format_request.c', + 'src/core/lib/http/httpcli.c', + 'src/core/lib/http/parser.c', + 'src/core/lib/iomgr/closure.c', + 'src/core/lib/iomgr/endpoint.c', + 'src/core/lib/iomgr/endpoint_pair_posix.c', + 'src/core/lib/iomgr/endpoint_pair_windows.c', + 'src/core/lib/iomgr/exec_ctx.c', + 'src/core/lib/iomgr/executor.c', + 'src/core/lib/iomgr/fd_posix.c', + 'src/core/lib/iomgr/iocp_windows.c', + 'src/core/lib/iomgr/iomgr.c', + 'src/core/lib/iomgr/iomgr_posix.c', + 'src/core/lib/iomgr/iomgr_windows.c', + 'src/core/lib/iomgr/pollset_multipoller_with_epoll.c', + 'src/core/lib/iomgr/pollset_multipoller_with_poll_posix.c', + 'src/core/lib/iomgr/pollset_posix.c', + 'src/core/lib/iomgr/pollset_set_posix.c', + 'src/core/lib/iomgr/pollset_set_windows.c', + 'src/core/lib/iomgr/pollset_windows.c', + 'src/core/lib/iomgr/resolve_address_posix.c', + 'src/core/lib/iomgr/resolve_address_windows.c', + 'src/core/lib/iomgr/sockaddr_utils.c', + 'src/core/lib/iomgr/socket_utils_common_posix.c', + 'src/core/lib/iomgr/socket_utils_linux.c', + 'src/core/lib/iomgr/socket_utils_posix.c', + 'src/core/lib/iomgr/socket_windows.c', + 'src/core/lib/iomgr/tcp_client_posix.c', + 'src/core/lib/iomgr/tcp_client_windows.c', + 'src/core/lib/iomgr/tcp_posix.c', + 'src/core/lib/iomgr/tcp_server_posix.c', + 'src/core/lib/iomgr/tcp_server_windows.c', + 'src/core/lib/iomgr/tcp_windows.c', + 'src/core/lib/iomgr/time_averaged_stats.c', + 'src/core/lib/iomgr/timer.c', + 'src/core/lib/iomgr/timer_heap.c', + 'src/core/lib/iomgr/udp_server.c', + 'src/core/lib/iomgr/unix_sockets_posix.c', + 'src/core/lib/iomgr/unix_sockets_posix_noop.c', + 'src/core/lib/iomgr/wakeup_fd_eventfd.c', + 'src/core/lib/iomgr/wakeup_fd_nospecial.c', + 'src/core/lib/iomgr/wakeup_fd_pipe.c', + 'src/core/lib/iomgr/wakeup_fd_posix.c', + 'src/core/lib/iomgr/workqueue_posix.c', + 'src/core/lib/iomgr/workqueue_windows.c', + 'src/core/lib/json/json.c', + 'src/core/lib/json/json_reader.c', + 'src/core/lib/json/json_string.c', + 'src/core/lib/json/json_writer.c', + 'src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c', + 'src/core/lib/surface/alarm.c', + 'src/core/lib/surface/api_trace.c', + 'src/core/lib/surface/byte_buffer.c', + 'src/core/lib/surface/byte_buffer_reader.c', + 'src/core/lib/surface/call.c', + 'src/core/lib/surface/call_details.c', + 'src/core/lib/surface/call_log_batch.c', + 'src/core/lib/surface/channel.c', + 'src/core/lib/surface/channel_connectivity.c', + 'src/core/lib/surface/channel_create.c', + 'src/core/lib/surface/channel_init.c', + 'src/core/lib/surface/channel_ping.c', + 'src/core/lib/surface/channel_stack_type.c', + 'src/core/lib/surface/completion_queue.c', + 'src/core/lib/surface/event_string.c', + 'src/core/lib/surface/init.c', + 'src/core/lib/surface/lame_client.c', + 'src/core/lib/surface/metadata_array.c', + 'src/core/lib/surface/server.c', + 'src/core/lib/surface/server_chttp2.c', + 'src/core/lib/surface/validate_metadata.c', + 'src/core/lib/surface/version.c', + 'src/core/lib/transport/byte_stream.c', + 'src/core/lib/transport/chttp2/alpn.c', + 'src/core/lib/transport/chttp2/bin_encoder.c', + 'src/core/lib/transport/chttp2/frame_data.c', + 'src/core/lib/transport/chttp2/frame_goaway.c', + 'src/core/lib/transport/chttp2/frame_ping.c', + 'src/core/lib/transport/chttp2/frame_rst_stream.c', + 'src/core/lib/transport/chttp2/frame_settings.c', + 'src/core/lib/transport/chttp2/frame_window_update.c', + 'src/core/lib/transport/chttp2/hpack_encoder.c', + 'src/core/lib/transport/chttp2/hpack_parser.c', + 'src/core/lib/transport/chttp2/hpack_table.c', + 'src/core/lib/transport/chttp2/huffsyms.c', + 'src/core/lib/transport/chttp2/incoming_metadata.c', + 'src/core/lib/transport/chttp2/parsing.c', + 'src/core/lib/transport/chttp2/status_conversion.c', + 'src/core/lib/transport/chttp2/stream_lists.c', + 'src/core/lib/transport/chttp2/stream_map.c', + 'src/core/lib/transport/chttp2/timeout_encoding.c', + 'src/core/lib/transport/chttp2/varint.c', + 'src/core/lib/transport/chttp2/writing.c', + 'src/core/lib/transport/chttp2_transport.c', + 'src/core/lib/transport/connectivity_state.c', + 'src/core/lib/transport/metadata.c', + 'src/core/lib/transport/metadata_batch.c', + 'src/core/lib/transport/static_metadata.c', + 'src/core/lib/transport/transport.c', + 'src/core/lib/transport/transport_op_string.c', + 'src/core/lib/http/httpcli_security_connector.c', + 'src/core/lib/security/b64.c', + 'src/core/lib/security/client_auth_filter.c', + 'src/core/lib/security/credentials.c', + 'src/core/lib/security/credentials_metadata.c', + 'src/core/lib/security/credentials_posix.c', + 'src/core/lib/security/credentials_win32.c', + 'src/core/lib/security/google_default_credentials.c', + 'src/core/lib/security/handshake.c', + 'src/core/lib/security/json_token.c', + 'src/core/lib/security/jwt_verifier.c', + 'src/core/lib/security/secure_endpoint.c', + 'src/core/lib/security/security_connector.c', + 'src/core/lib/security/security_context.c', + 'src/core/lib/security/server_auth_filter.c', + 'src/core/lib/security/server_secure_chttp2.c', + 'src/core/lib/surface/init_secure.c', + 'src/core/lib/surface/secure_channel_create.c', + 'src/core/lib/tsi/fake_transport_security.c', + 'src/core/lib/tsi/ssl_transport_security.c', + 'src/core/lib/tsi/transport_security.c', + 'src/core/lib/census/context.c', + 'src/core/lib/census/initialize.c', + 'src/core/lib/census/mlog.c', + 'src/core/lib/census/operation.c', + 'src/core/lib/census/placeholders.c', + 'src/core/lib/census/tracing.c', 'third_party/nanopb/pb_common.c', 'third_party/nanopb/pb_decode.c', 'third_party/nanopb/pb_encode.c', diff --git a/templates/src/core/lib/surface/version.c.template b/templates/src/core/lib/surface/version.c.template new file mode 100644 index 0000000000..f2b3cfdc58 --- /dev/null +++ b/templates/src/core/lib/surface/version.c.template @@ -0,0 +1,41 @@ +%YAML 1.2 +--- | + /* + * + * Copyright 2015-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. + * + */ + + /* This file is autogenerated from: + templates/src/core/surface/version.c.template */ + + #include + + const char *grpc_version_string(void) { return "${settings.core_version}"; } diff --git a/templates/src/core/surface/version.c.template b/templates/src/core/surface/version.c.template deleted file mode 100644 index f2b3cfdc58..0000000000 --- a/templates/src/core/surface/version.c.template +++ /dev/null @@ -1,41 +0,0 @@ -%YAML 1.2 ---- | - /* - * - * Copyright 2015-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. - * - */ - - /* This file is autogenerated from: - templates/src/core/surface/version.c.template */ - - #include - - const char *grpc_version_string(void) { return "${settings.core_version}"; } diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index 5044ed2c93..7f91115cec 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -773,308 +773,308 @@ include/grpc/impl/codegen/grpc_types.h \ include/grpc/impl/codegen/propagation_bits.h \ include/grpc/impl/codegen/status.h \ include/grpc/census.h \ -src/core/census/grpc_filter.h \ -src/core/census/grpc_plugin.h \ -src/core/channel/channel_args.h \ -src/core/channel/channel_stack.h \ -src/core/channel/channel_stack_builder.h \ -src/core/channel/client_channel.h \ -src/core/channel/compress_filter.h \ -src/core/channel/connected_channel.h \ -src/core/channel/context.h \ -src/core/channel/http_client_filter.h \ -src/core/channel/http_server_filter.h \ -src/core/channel/subchannel_call_holder.h \ -src/core/client_config/client_config.h \ -src/core/client_config/connector.h \ -src/core/client_config/initial_connect_string.h \ -src/core/client_config/lb_policies/load_balancer_api.h \ -src/core/client_config/lb_policies/pick_first.h \ -src/core/client_config/lb_policies/round_robin.h \ -src/core/client_config/lb_policy.h \ -src/core/client_config/lb_policy_factory.h \ -src/core/client_config/lb_policy_registry.h \ -src/core/client_config/resolver.h \ -src/core/client_config/resolver_factory.h \ -src/core/client_config/resolver_registry.h \ -src/core/client_config/resolvers/dns_resolver.h \ -src/core/client_config/resolvers/sockaddr_resolver.h \ -src/core/client_config/subchannel.h \ -src/core/client_config/subchannel_factory.h \ -src/core/client_config/subchannel_index.h \ -src/core/client_config/uri_parser.h \ -src/core/compression/algorithm_metadata.h \ -src/core/compression/message_compress.h \ -src/core/debug/trace.h \ -src/core/http/format_request.h \ -src/core/http/httpcli.h \ -src/core/http/parser.h \ -src/core/iomgr/closure.h \ -src/core/iomgr/endpoint.h \ -src/core/iomgr/endpoint_pair.h \ -src/core/iomgr/exec_ctx.h \ -src/core/iomgr/executor.h \ -src/core/iomgr/fd_posix.h \ -src/core/iomgr/iocp_windows.h \ -src/core/iomgr/iomgr.h \ -src/core/iomgr/iomgr_internal.h \ -src/core/iomgr/iomgr_posix.h \ -src/core/iomgr/pollset.h \ -src/core/iomgr/pollset_posix.h \ -src/core/iomgr/pollset_set.h \ -src/core/iomgr/pollset_set_posix.h \ -src/core/iomgr/pollset_set_windows.h \ -src/core/iomgr/pollset_windows.h \ -src/core/iomgr/resolve_address.h \ -src/core/iomgr/sockaddr.h \ -src/core/iomgr/sockaddr_posix.h \ -src/core/iomgr/sockaddr_utils.h \ -src/core/iomgr/sockaddr_win32.h \ -src/core/iomgr/socket_utils_posix.h \ -src/core/iomgr/socket_windows.h \ -src/core/iomgr/tcp_client.h \ -src/core/iomgr/tcp_posix.h \ -src/core/iomgr/tcp_server.h \ -src/core/iomgr/tcp_windows.h \ -src/core/iomgr/time_averaged_stats.h \ -src/core/iomgr/timer.h \ -src/core/iomgr/timer_heap.h \ -src/core/iomgr/udp_server.h \ -src/core/iomgr/unix_sockets_posix.h \ -src/core/iomgr/wakeup_fd_pipe.h \ -src/core/iomgr/wakeup_fd_posix.h \ -src/core/iomgr/workqueue.h \ -src/core/iomgr/workqueue_posix.h \ -src/core/iomgr/workqueue_windows.h \ -src/core/json/json.h \ -src/core/json/json_common.h \ -src/core/json/json_reader.h \ -src/core/json/json_writer.h \ -src/core/proto/grpc/lb/v0/load_balancer.pb.h \ -src/core/statistics/census_interface.h \ -src/core/statistics/census_rpc_stats.h \ -src/core/surface/api_trace.h \ -src/core/surface/call.h \ -src/core/surface/call_test_only.h \ -src/core/surface/channel.h \ -src/core/surface/channel_init.h \ -src/core/surface/channel_stack_type.h \ -src/core/surface/completion_queue.h \ -src/core/surface/event_string.h \ -src/core/surface/init.h \ -src/core/surface/lame_client.h \ -src/core/surface/server.h \ -src/core/surface/surface_trace.h \ -src/core/transport/byte_stream.h \ -src/core/transport/chttp2/alpn.h \ -src/core/transport/chttp2/bin_encoder.h \ -src/core/transport/chttp2/frame.h \ -src/core/transport/chttp2/frame_data.h \ -src/core/transport/chttp2/frame_goaway.h \ -src/core/transport/chttp2/frame_ping.h \ -src/core/transport/chttp2/frame_rst_stream.h \ -src/core/transport/chttp2/frame_settings.h \ -src/core/transport/chttp2/frame_window_update.h \ -src/core/transport/chttp2/hpack_encoder.h \ -src/core/transport/chttp2/hpack_parser.h \ -src/core/transport/chttp2/hpack_table.h \ -src/core/transport/chttp2/http2_errors.h \ -src/core/transport/chttp2/huffsyms.h \ -src/core/transport/chttp2/incoming_metadata.h \ -src/core/transport/chttp2/internal.h \ -src/core/transport/chttp2/status_conversion.h \ -src/core/transport/chttp2/stream_map.h \ -src/core/transport/chttp2/timeout_encoding.h \ -src/core/transport/chttp2/varint.h \ -src/core/transport/chttp2_transport.h \ -src/core/transport/connectivity_state.h \ -src/core/transport/metadata.h \ -src/core/transport/metadata_batch.h \ -src/core/transport/static_metadata.h \ -src/core/transport/transport.h \ -src/core/transport/transport_impl.h \ -src/core/security/auth_filters.h \ -src/core/security/b64.h \ -src/core/security/credentials.h \ -src/core/security/handshake.h \ -src/core/security/json_token.h \ -src/core/security/jwt_verifier.h \ -src/core/security/secure_endpoint.h \ -src/core/security/security_connector.h \ -src/core/security/security_context.h \ -src/core/tsi/fake_transport_security.h \ -src/core/tsi/ssl_transport_security.h \ -src/core/tsi/ssl_types.h \ -src/core/tsi/transport_security.h \ -src/core/tsi/transport_security_interface.h \ -src/core/census/aggregation.h \ -src/core/census/mlog.h \ -src/core/census/rpc_metric_id.h \ +src/core/lib/census/grpc_filter.h \ +src/core/lib/census/grpc_plugin.h \ +src/core/lib/channel/channel_args.h \ +src/core/lib/channel/channel_stack.h \ +src/core/lib/channel/channel_stack_builder.h \ +src/core/lib/channel/client_channel.h \ +src/core/lib/channel/compress_filter.h \ +src/core/lib/channel/connected_channel.h \ +src/core/lib/channel/context.h \ +src/core/lib/channel/http_client_filter.h \ +src/core/lib/channel/http_server_filter.h \ +src/core/lib/channel/subchannel_call_holder.h \ +src/core/lib/client_config/client_config.h \ +src/core/lib/client_config/connector.h \ +src/core/lib/client_config/initial_connect_string.h \ +src/core/lib/client_config/lb_policies/load_balancer_api.h \ +src/core/lib/client_config/lb_policies/pick_first.h \ +src/core/lib/client_config/lb_policies/round_robin.h \ +src/core/lib/client_config/lb_policy.h \ +src/core/lib/client_config/lb_policy_factory.h \ +src/core/lib/client_config/lb_policy_registry.h \ +src/core/lib/client_config/resolver.h \ +src/core/lib/client_config/resolver_factory.h \ +src/core/lib/client_config/resolver_registry.h \ +src/core/lib/client_config/resolvers/dns_resolver.h \ +src/core/lib/client_config/resolvers/sockaddr_resolver.h \ +src/core/lib/client_config/subchannel.h \ +src/core/lib/client_config/subchannel_factory.h \ +src/core/lib/client_config/subchannel_index.h \ +src/core/lib/client_config/uri_parser.h \ +src/core/lib/compression/algorithm_metadata.h \ +src/core/lib/compression/message_compress.h \ +src/core/lib/debug/trace.h \ +src/core/lib/http/format_request.h \ +src/core/lib/http/httpcli.h \ +src/core/lib/http/parser.h \ +src/core/lib/iomgr/closure.h \ +src/core/lib/iomgr/endpoint.h \ +src/core/lib/iomgr/endpoint_pair.h \ +src/core/lib/iomgr/exec_ctx.h \ +src/core/lib/iomgr/executor.h \ +src/core/lib/iomgr/fd_posix.h \ +src/core/lib/iomgr/iocp_windows.h \ +src/core/lib/iomgr/iomgr.h \ +src/core/lib/iomgr/iomgr_internal.h \ +src/core/lib/iomgr/iomgr_posix.h \ +src/core/lib/iomgr/pollset.h \ +src/core/lib/iomgr/pollset_posix.h \ +src/core/lib/iomgr/pollset_set.h \ +src/core/lib/iomgr/pollset_set_posix.h \ +src/core/lib/iomgr/pollset_set_windows.h \ +src/core/lib/iomgr/pollset_windows.h \ +src/core/lib/iomgr/resolve_address.h \ +src/core/lib/iomgr/sockaddr.h \ +src/core/lib/iomgr/sockaddr_posix.h \ +src/core/lib/iomgr/sockaddr_utils.h \ +src/core/lib/iomgr/sockaddr_win32.h \ +src/core/lib/iomgr/socket_utils_posix.h \ +src/core/lib/iomgr/socket_windows.h \ +src/core/lib/iomgr/tcp_client.h \ +src/core/lib/iomgr/tcp_posix.h \ +src/core/lib/iomgr/tcp_server.h \ +src/core/lib/iomgr/tcp_windows.h \ +src/core/lib/iomgr/time_averaged_stats.h \ +src/core/lib/iomgr/timer.h \ +src/core/lib/iomgr/timer_heap.h \ +src/core/lib/iomgr/udp_server.h \ +src/core/lib/iomgr/unix_sockets_posix.h \ +src/core/lib/iomgr/wakeup_fd_pipe.h \ +src/core/lib/iomgr/wakeup_fd_posix.h \ +src/core/lib/iomgr/workqueue.h \ +src/core/lib/iomgr/workqueue_posix.h \ +src/core/lib/iomgr/workqueue_windows.h \ +src/core/lib/json/json.h \ +src/core/lib/json/json_common.h \ +src/core/lib/json/json_reader.h \ +src/core/lib/json/json_writer.h \ +src/core/lib/proto/grpc/lb/v0/load_balancer.pb.h \ +src/core/lib/statistics/census_interface.h \ +src/core/lib/statistics/census_rpc_stats.h \ +src/core/lib/surface/api_trace.h \ +src/core/lib/surface/call.h \ +src/core/lib/surface/call_test_only.h \ +src/core/lib/surface/channel.h \ +src/core/lib/surface/channel_init.h \ +src/core/lib/surface/channel_stack_type.h \ +src/core/lib/surface/completion_queue.h \ +src/core/lib/surface/event_string.h \ +src/core/lib/surface/init.h \ +src/core/lib/surface/lame_client.h \ +src/core/lib/surface/server.h \ +src/core/lib/surface/surface_trace.h \ +src/core/lib/transport/byte_stream.h \ +src/core/lib/transport/chttp2/alpn.h \ +src/core/lib/transport/chttp2/bin_encoder.h \ +src/core/lib/transport/chttp2/frame.h \ +src/core/lib/transport/chttp2/frame_data.h \ +src/core/lib/transport/chttp2/frame_goaway.h \ +src/core/lib/transport/chttp2/frame_ping.h \ +src/core/lib/transport/chttp2/frame_rst_stream.h \ +src/core/lib/transport/chttp2/frame_settings.h \ +src/core/lib/transport/chttp2/frame_window_update.h \ +src/core/lib/transport/chttp2/hpack_encoder.h \ +src/core/lib/transport/chttp2/hpack_parser.h \ +src/core/lib/transport/chttp2/hpack_table.h \ +src/core/lib/transport/chttp2/http2_errors.h \ +src/core/lib/transport/chttp2/huffsyms.h \ +src/core/lib/transport/chttp2/incoming_metadata.h \ +src/core/lib/transport/chttp2/internal.h \ +src/core/lib/transport/chttp2/status_conversion.h \ +src/core/lib/transport/chttp2/stream_map.h \ +src/core/lib/transport/chttp2/timeout_encoding.h \ +src/core/lib/transport/chttp2/varint.h \ +src/core/lib/transport/chttp2_transport.h \ +src/core/lib/transport/connectivity_state.h \ +src/core/lib/transport/metadata.h \ +src/core/lib/transport/metadata_batch.h \ +src/core/lib/transport/static_metadata.h \ +src/core/lib/transport/transport.h \ +src/core/lib/transport/transport_impl.h \ +src/core/lib/security/auth_filters.h \ +src/core/lib/security/b64.h \ +src/core/lib/security/credentials.h \ +src/core/lib/security/handshake.h \ +src/core/lib/security/json_token.h \ +src/core/lib/security/jwt_verifier.h \ +src/core/lib/security/secure_endpoint.h \ +src/core/lib/security/security_connector.h \ +src/core/lib/security/security_context.h \ +src/core/lib/tsi/fake_transport_security.h \ +src/core/lib/tsi/ssl_transport_security.h \ +src/core/lib/tsi/ssl_types.h \ +src/core/lib/tsi/transport_security.h \ +src/core/lib/tsi/transport_security_interface.h \ +src/core/lib/census/aggregation.h \ +src/core/lib/census/mlog.h \ +src/core/lib/census/rpc_metric_id.h \ third_party/nanopb/pb.h \ third_party/nanopb/pb_common.h \ third_party/nanopb/pb_decode.h \ third_party/nanopb/pb_encode.h \ -src/core/census/grpc_context.c \ -src/core/census/grpc_filter.c \ -src/core/census/grpc_plugin.c \ -src/core/channel/channel_args.c \ -src/core/channel/channel_stack.c \ -src/core/channel/channel_stack_builder.c \ -src/core/channel/client_channel.c \ -src/core/channel/compress_filter.c \ -src/core/channel/connected_channel.c \ -src/core/channel/http_client_filter.c \ -src/core/channel/http_server_filter.c \ -src/core/channel/subchannel_call_holder.c \ -src/core/client_config/client_config.c \ -src/core/client_config/connector.c \ -src/core/client_config/default_initial_connect_string.c \ -src/core/client_config/initial_connect_string.c \ -src/core/client_config/lb_policies/load_balancer_api.c \ -src/core/client_config/lb_policies/pick_first.c \ -src/core/client_config/lb_policies/round_robin.c \ -src/core/client_config/lb_policy.c \ -src/core/client_config/lb_policy_factory.c \ -src/core/client_config/lb_policy_registry.c \ -src/core/client_config/resolver.c \ -src/core/client_config/resolver_factory.c \ -src/core/client_config/resolver_registry.c \ -src/core/client_config/resolvers/dns_resolver.c \ -src/core/client_config/resolvers/sockaddr_resolver.c \ -src/core/client_config/subchannel.c \ -src/core/client_config/subchannel_factory.c \ -src/core/client_config/subchannel_index.c \ -src/core/client_config/uri_parser.c \ -src/core/compression/compression_algorithm.c \ -src/core/compression/message_compress.c \ -src/core/debug/trace.c \ -src/core/http/format_request.c \ -src/core/http/httpcli.c \ -src/core/http/parser.c \ -src/core/iomgr/closure.c \ -src/core/iomgr/endpoint.c \ -src/core/iomgr/endpoint_pair_posix.c \ -src/core/iomgr/endpoint_pair_windows.c \ -src/core/iomgr/exec_ctx.c \ -src/core/iomgr/executor.c \ -src/core/iomgr/fd_posix.c \ -src/core/iomgr/iocp_windows.c \ -src/core/iomgr/iomgr.c \ -src/core/iomgr/iomgr_posix.c \ -src/core/iomgr/iomgr_windows.c \ -src/core/iomgr/pollset_multipoller_with_epoll.c \ -src/core/iomgr/pollset_multipoller_with_poll_posix.c \ -src/core/iomgr/pollset_posix.c \ -src/core/iomgr/pollset_set_posix.c \ -src/core/iomgr/pollset_set_windows.c \ -src/core/iomgr/pollset_windows.c \ -src/core/iomgr/resolve_address_posix.c \ -src/core/iomgr/resolve_address_windows.c \ -src/core/iomgr/sockaddr_utils.c \ -src/core/iomgr/socket_utils_common_posix.c \ -src/core/iomgr/socket_utils_linux.c \ -src/core/iomgr/socket_utils_posix.c \ -src/core/iomgr/socket_windows.c \ -src/core/iomgr/tcp_client_posix.c \ -src/core/iomgr/tcp_client_windows.c \ -src/core/iomgr/tcp_posix.c \ -src/core/iomgr/tcp_server_posix.c \ -src/core/iomgr/tcp_server_windows.c \ -src/core/iomgr/tcp_windows.c \ -src/core/iomgr/time_averaged_stats.c \ -src/core/iomgr/timer.c \ -src/core/iomgr/timer_heap.c \ -src/core/iomgr/udp_server.c \ -src/core/iomgr/unix_sockets_posix.c \ -src/core/iomgr/unix_sockets_posix_noop.c \ -src/core/iomgr/wakeup_fd_eventfd.c \ -src/core/iomgr/wakeup_fd_nospecial.c \ -src/core/iomgr/wakeup_fd_pipe.c \ -src/core/iomgr/wakeup_fd_posix.c \ -src/core/iomgr/workqueue_posix.c \ -src/core/iomgr/workqueue_windows.c \ -src/core/json/json.c \ -src/core/json/json_reader.c \ -src/core/json/json_string.c \ -src/core/json/json_writer.c \ -src/core/proto/grpc/lb/v0/load_balancer.pb.c \ -src/core/surface/alarm.c \ -src/core/surface/api_trace.c \ -src/core/surface/byte_buffer.c \ -src/core/surface/byte_buffer_reader.c \ -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/channel_init.c \ -src/core/surface/channel_ping.c \ -src/core/surface/channel_stack_type.c \ -src/core/surface/completion_queue.c \ -src/core/surface/event_string.c \ -src/core/surface/init.c \ -src/core/surface/lame_client.c \ -src/core/surface/metadata_array.c \ -src/core/surface/server.c \ -src/core/surface/server_chttp2.c \ -src/core/surface/validate_metadata.c \ -src/core/surface/version.c \ -src/core/transport/byte_stream.c \ -src/core/transport/chttp2/alpn.c \ -src/core/transport/chttp2/bin_encoder.c \ -src/core/transport/chttp2/frame_data.c \ -src/core/transport/chttp2/frame_goaway.c \ -src/core/transport/chttp2/frame_ping.c \ -src/core/transport/chttp2/frame_rst_stream.c \ -src/core/transport/chttp2/frame_settings.c \ -src/core/transport/chttp2/frame_window_update.c \ -src/core/transport/chttp2/hpack_encoder.c \ -src/core/transport/chttp2/hpack_parser.c \ -src/core/transport/chttp2/hpack_table.c \ -src/core/transport/chttp2/huffsyms.c \ -src/core/transport/chttp2/incoming_metadata.c \ -src/core/transport/chttp2/parsing.c \ -src/core/transport/chttp2/status_conversion.c \ -src/core/transport/chttp2/stream_lists.c \ -src/core/transport/chttp2/stream_map.c \ -src/core/transport/chttp2/timeout_encoding.c \ -src/core/transport/chttp2/varint.c \ -src/core/transport/chttp2/writing.c \ -src/core/transport/chttp2_transport.c \ -src/core/transport/connectivity_state.c \ -src/core/transport/metadata.c \ -src/core/transport/metadata_batch.c \ -src/core/transport/static_metadata.c \ -src/core/transport/transport.c \ -src/core/transport/transport_op_string.c \ -src/core/http/httpcli_security_connector.c \ -src/core/security/b64.c \ -src/core/security/client_auth_filter.c \ -src/core/security/credentials.c \ -src/core/security/credentials_metadata.c \ -src/core/security/credentials_posix.c \ -src/core/security/credentials_win32.c \ -src/core/security/google_default_credentials.c \ -src/core/security/handshake.c \ -src/core/security/json_token.c \ -src/core/security/jwt_verifier.c \ -src/core/security/secure_endpoint.c \ -src/core/security/security_connector.c \ -src/core/security/security_context.c \ -src/core/security/server_auth_filter.c \ -src/core/security/server_secure_chttp2.c \ -src/core/surface/init_secure.c \ -src/core/surface/secure_channel_create.c \ -src/core/tsi/fake_transport_security.c \ -src/core/tsi/ssl_transport_security.c \ -src/core/tsi/transport_security.c \ -src/core/census/context.c \ -src/core/census/initialize.c \ -src/core/census/mlog.c \ -src/core/census/operation.c \ -src/core/census/placeholders.c \ -src/core/census/tracing.c \ +src/core/lib/census/grpc_context.c \ +src/core/lib/census/grpc_filter.c \ +src/core/lib/census/grpc_plugin.c \ +src/core/lib/channel/channel_args.c \ +src/core/lib/channel/channel_stack.c \ +src/core/lib/channel/channel_stack_builder.c \ +src/core/lib/channel/client_channel.c \ +src/core/lib/channel/compress_filter.c \ +src/core/lib/channel/connected_channel.c \ +src/core/lib/channel/http_client_filter.c \ +src/core/lib/channel/http_server_filter.c \ +src/core/lib/channel/subchannel_call_holder.c \ +src/core/lib/client_config/client_config.c \ +src/core/lib/client_config/connector.c \ +src/core/lib/client_config/default_initial_connect_string.c \ +src/core/lib/client_config/initial_connect_string.c \ +src/core/lib/client_config/lb_policies/load_balancer_api.c \ +src/core/lib/client_config/lb_policies/pick_first.c \ +src/core/lib/client_config/lb_policies/round_robin.c \ +src/core/lib/client_config/lb_policy.c \ +src/core/lib/client_config/lb_policy_factory.c \ +src/core/lib/client_config/lb_policy_registry.c \ +src/core/lib/client_config/resolver.c \ +src/core/lib/client_config/resolver_factory.c \ +src/core/lib/client_config/resolver_registry.c \ +src/core/lib/client_config/resolvers/dns_resolver.c \ +src/core/lib/client_config/resolvers/sockaddr_resolver.c \ +src/core/lib/client_config/subchannel.c \ +src/core/lib/client_config/subchannel_factory.c \ +src/core/lib/client_config/subchannel_index.c \ +src/core/lib/client_config/uri_parser.c \ +src/core/lib/compression/compression_algorithm.c \ +src/core/lib/compression/message_compress.c \ +src/core/lib/debug/trace.c \ +src/core/lib/http/format_request.c \ +src/core/lib/http/httpcli.c \ +src/core/lib/http/parser.c \ +src/core/lib/iomgr/closure.c \ +src/core/lib/iomgr/endpoint.c \ +src/core/lib/iomgr/endpoint_pair_posix.c \ +src/core/lib/iomgr/endpoint_pair_windows.c \ +src/core/lib/iomgr/exec_ctx.c \ +src/core/lib/iomgr/executor.c \ +src/core/lib/iomgr/fd_posix.c \ +src/core/lib/iomgr/iocp_windows.c \ +src/core/lib/iomgr/iomgr.c \ +src/core/lib/iomgr/iomgr_posix.c \ +src/core/lib/iomgr/iomgr_windows.c \ +src/core/lib/iomgr/pollset_multipoller_with_epoll.c \ +src/core/lib/iomgr/pollset_multipoller_with_poll_posix.c \ +src/core/lib/iomgr/pollset_posix.c \ +src/core/lib/iomgr/pollset_set_posix.c \ +src/core/lib/iomgr/pollset_set_windows.c \ +src/core/lib/iomgr/pollset_windows.c \ +src/core/lib/iomgr/resolve_address_posix.c \ +src/core/lib/iomgr/resolve_address_windows.c \ +src/core/lib/iomgr/sockaddr_utils.c \ +src/core/lib/iomgr/socket_utils_common_posix.c \ +src/core/lib/iomgr/socket_utils_linux.c \ +src/core/lib/iomgr/socket_utils_posix.c \ +src/core/lib/iomgr/socket_windows.c \ +src/core/lib/iomgr/tcp_client_posix.c \ +src/core/lib/iomgr/tcp_client_windows.c \ +src/core/lib/iomgr/tcp_posix.c \ +src/core/lib/iomgr/tcp_server_posix.c \ +src/core/lib/iomgr/tcp_server_windows.c \ +src/core/lib/iomgr/tcp_windows.c \ +src/core/lib/iomgr/time_averaged_stats.c \ +src/core/lib/iomgr/timer.c \ +src/core/lib/iomgr/timer_heap.c \ +src/core/lib/iomgr/udp_server.c \ +src/core/lib/iomgr/unix_sockets_posix.c \ +src/core/lib/iomgr/unix_sockets_posix_noop.c \ +src/core/lib/iomgr/wakeup_fd_eventfd.c \ +src/core/lib/iomgr/wakeup_fd_nospecial.c \ +src/core/lib/iomgr/wakeup_fd_pipe.c \ +src/core/lib/iomgr/wakeup_fd_posix.c \ +src/core/lib/iomgr/workqueue_posix.c \ +src/core/lib/iomgr/workqueue_windows.c \ +src/core/lib/json/json.c \ +src/core/lib/json/json_reader.c \ +src/core/lib/json/json_string.c \ +src/core/lib/json/json_writer.c \ +src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c \ +src/core/lib/surface/alarm.c \ +src/core/lib/surface/api_trace.c \ +src/core/lib/surface/byte_buffer.c \ +src/core/lib/surface/byte_buffer_reader.c \ +src/core/lib/surface/call.c \ +src/core/lib/surface/call_details.c \ +src/core/lib/surface/call_log_batch.c \ +src/core/lib/surface/channel.c \ +src/core/lib/surface/channel_connectivity.c \ +src/core/lib/surface/channel_create.c \ +src/core/lib/surface/channel_init.c \ +src/core/lib/surface/channel_ping.c \ +src/core/lib/surface/channel_stack_type.c \ +src/core/lib/surface/completion_queue.c \ +src/core/lib/surface/event_string.c \ +src/core/lib/surface/init.c \ +src/core/lib/surface/lame_client.c \ +src/core/lib/surface/metadata_array.c \ +src/core/lib/surface/server.c \ +src/core/lib/surface/server_chttp2.c \ +src/core/lib/surface/validate_metadata.c \ +src/core/lib/surface/version.c \ +src/core/lib/transport/byte_stream.c \ +src/core/lib/transport/chttp2/alpn.c \ +src/core/lib/transport/chttp2/bin_encoder.c \ +src/core/lib/transport/chttp2/frame_data.c \ +src/core/lib/transport/chttp2/frame_goaway.c \ +src/core/lib/transport/chttp2/frame_ping.c \ +src/core/lib/transport/chttp2/frame_rst_stream.c \ +src/core/lib/transport/chttp2/frame_settings.c \ +src/core/lib/transport/chttp2/frame_window_update.c \ +src/core/lib/transport/chttp2/hpack_encoder.c \ +src/core/lib/transport/chttp2/hpack_parser.c \ +src/core/lib/transport/chttp2/hpack_table.c \ +src/core/lib/transport/chttp2/huffsyms.c \ +src/core/lib/transport/chttp2/incoming_metadata.c \ +src/core/lib/transport/chttp2/parsing.c \ +src/core/lib/transport/chttp2/status_conversion.c \ +src/core/lib/transport/chttp2/stream_lists.c \ +src/core/lib/transport/chttp2/stream_map.c \ +src/core/lib/transport/chttp2/timeout_encoding.c \ +src/core/lib/transport/chttp2/varint.c \ +src/core/lib/transport/chttp2/writing.c \ +src/core/lib/transport/chttp2_transport.c \ +src/core/lib/transport/connectivity_state.c \ +src/core/lib/transport/metadata.c \ +src/core/lib/transport/metadata_batch.c \ +src/core/lib/transport/static_metadata.c \ +src/core/lib/transport/transport.c \ +src/core/lib/transport/transport_op_string.c \ +src/core/lib/http/httpcli_security_connector.c \ +src/core/lib/security/b64.c \ +src/core/lib/security/client_auth_filter.c \ +src/core/lib/security/credentials.c \ +src/core/lib/security/credentials_metadata.c \ +src/core/lib/security/credentials_posix.c \ +src/core/lib/security/credentials_win32.c \ +src/core/lib/security/google_default_credentials.c \ +src/core/lib/security/handshake.c \ +src/core/lib/security/json_token.c \ +src/core/lib/security/jwt_verifier.c \ +src/core/lib/security/secure_endpoint.c \ +src/core/lib/security/security_connector.c \ +src/core/lib/security/security_context.c \ +src/core/lib/security/server_auth_filter.c \ +src/core/lib/security/server_secure_chttp2.c \ +src/core/lib/surface/init_secure.c \ +src/core/lib/surface/secure_channel_create.c \ +src/core/lib/tsi/fake_transport_security.c \ +src/core/lib/tsi/ssl_transport_security.c \ +src/core/lib/tsi/transport_security.c \ +src/core/lib/census/context.c \ +src/core/lib/census/initialize.c \ +src/core/lib/census/mlog.c \ +src/core/lib/census/operation.c \ +src/core/lib/census/placeholders.c \ +src/core/lib/census/tracing.c \ third_party/nanopb/pb_common.c \ third_party/nanopb/pb_decode.c \ third_party/nanopb/pb_encode.c \ @@ -1120,62 +1120,62 @@ include/grpc/impl/codegen/sync_generic.h \ include/grpc/impl/codegen/sync_posix.h \ include/grpc/impl/codegen/sync_win32.h \ include/grpc/impl/codegen/time.h \ -src/core/profiling/timers.h \ -src/core/support/backoff.h \ -src/core/support/block_annotate.h \ -src/core/support/env.h \ -src/core/support/load_file.h \ -src/core/support/murmur_hash.h \ -src/core/support/stack_lockfree.h \ -src/core/support/string.h \ -src/core/support/string_win32.h \ -src/core/support/thd_internal.h \ -src/core/support/time_precise.h \ -src/core/support/tmpfile.h \ -src/core/profiling/basic_timers.c \ -src/core/profiling/stap_timers.c \ -src/core/support/alloc.c \ -src/core/support/avl.c \ -src/core/support/backoff.c \ -src/core/support/cmdline.c \ -src/core/support/cpu_iphone.c \ -src/core/support/cpu_linux.c \ -src/core/support/cpu_posix.c \ -src/core/support/cpu_windows.c \ -src/core/support/env_linux.c \ -src/core/support/env_posix.c \ -src/core/support/env_win32.c \ -src/core/support/histogram.c \ -src/core/support/host_port.c \ -src/core/support/load_file.c \ -src/core/support/log.c \ -src/core/support/log_android.c \ -src/core/support/log_linux.c \ -src/core/support/log_posix.c \ -src/core/support/log_win32.c \ -src/core/support/murmur_hash.c \ -src/core/support/slice.c \ -src/core/support/slice_buffer.c \ -src/core/support/stack_lockfree.c \ -src/core/support/string.c \ -src/core/support/string_posix.c \ -src/core/support/string_win32.c \ -src/core/support/subprocess_posix.c \ -src/core/support/subprocess_windows.c \ -src/core/support/sync.c \ -src/core/support/sync_posix.c \ -src/core/support/sync_win32.c \ -src/core/support/thd.c \ -src/core/support/thd_posix.c \ -src/core/support/thd_win32.c \ -src/core/support/time.c \ -src/core/support/time_posix.c \ -src/core/support/time_precise.c \ -src/core/support/time_win32.c \ -src/core/support/tls_pthread.c \ -src/core/support/tmpfile_posix.c \ -src/core/support/tmpfile_win32.c \ -src/core/support/wrap_memcpy.c +src/core/lib/profiling/timers.h \ +src/core/lib/support/backoff.h \ +src/core/lib/support/block_annotate.h \ +src/core/lib/support/env.h \ +src/core/lib/support/load_file.h \ +src/core/lib/support/murmur_hash.h \ +src/core/lib/support/stack_lockfree.h \ +src/core/lib/support/string.h \ +src/core/lib/support/string_win32.h \ +src/core/lib/support/thd_internal.h \ +src/core/lib/support/time_precise.h \ +src/core/lib/support/tmpfile.h \ +src/core/lib/profiling/basic_timers.c \ +src/core/lib/profiling/stap_timers.c \ +src/core/lib/support/alloc.c \ +src/core/lib/support/avl.c \ +src/core/lib/support/backoff.c \ +src/core/lib/support/cmdline.c \ +src/core/lib/support/cpu_iphone.c \ +src/core/lib/support/cpu_linux.c \ +src/core/lib/support/cpu_posix.c \ +src/core/lib/support/cpu_windows.c \ +src/core/lib/support/env_linux.c \ +src/core/lib/support/env_posix.c \ +src/core/lib/support/env_win32.c \ +src/core/lib/support/histogram.c \ +src/core/lib/support/host_port.c \ +src/core/lib/support/load_file.c \ +src/core/lib/support/log.c \ +src/core/lib/support/log_android.c \ +src/core/lib/support/log_linux.c \ +src/core/lib/support/log_posix.c \ +src/core/lib/support/log_win32.c \ +src/core/lib/support/murmur_hash.c \ +src/core/lib/support/slice.c \ +src/core/lib/support/slice_buffer.c \ +src/core/lib/support/stack_lockfree.c \ +src/core/lib/support/string.c \ +src/core/lib/support/string_posix.c \ +src/core/lib/support/string_win32.c \ +src/core/lib/support/subprocess_posix.c \ +src/core/lib/support/subprocess_windows.c \ +src/core/lib/support/sync.c \ +src/core/lib/support/sync_posix.c \ +src/core/lib/support/sync_win32.c \ +src/core/lib/support/thd.c \ +src/core/lib/support/thd_posix.c \ +src/core/lib/support/thd_win32.c \ +src/core/lib/support/time.c \ +src/core/lib/support/time_posix.c \ +src/core/lib/support/time_precise.c \ +src/core/lib/support/time_win32.c \ +src/core/lib/support/tls_pthread.c \ +src/core/lib/support/tmpfile_posix.c \ +src/core/lib/support/tmpfile_win32.c \ +src/core/lib/support/wrap_memcpy.c # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json index 06dc6d0ff8..8653cf7017 100644 --- a/tools/run_tests/sources_and_headers.json +++ b/tools/run_tests/sources_and_headers.json @@ -3772,18 +3772,18 @@ "include/grpc/support/tls_msvc.h", "include/grpc/support/tls_pthread.h", "include/grpc/support/useful.h", - "src/core/profiling/timers.h", - "src/core/support/backoff.h", - "src/core/support/block_annotate.h", - "src/core/support/env.h", - "src/core/support/load_file.h", - "src/core/support/murmur_hash.h", - "src/core/support/stack_lockfree.h", - "src/core/support/string.h", - "src/core/support/string_win32.h", - "src/core/support/thd_internal.h", - "src/core/support/time_precise.h", - "src/core/support/tmpfile.h" + "src/core/lib/profiling/timers.h", + "src/core/lib/support/backoff.h", + "src/core/lib/support/block_annotate.h", + "src/core/lib/support/env.h", + "src/core/lib/support/load_file.h", + "src/core/lib/support/murmur_hash.h", + "src/core/lib/support/stack_lockfree.h", + "src/core/lib/support/string.h", + "src/core/lib/support/string_win32.h", + "src/core/lib/support/thd_internal.h", + "src/core/lib/support/time_precise.h", + "src/core/lib/support/tmpfile.h" ], "language": "c", "name": "gpr", @@ -3830,62 +3830,62 @@ "include/grpc/support/tls_msvc.h", "include/grpc/support/tls_pthread.h", "include/grpc/support/useful.h", - "src/core/profiling/basic_timers.c", - "src/core/profiling/stap_timers.c", - "src/core/profiling/timers.h", - "src/core/support/alloc.c", - "src/core/support/avl.c", - "src/core/support/backoff.c", - "src/core/support/backoff.h", - "src/core/support/block_annotate.h", - "src/core/support/cmdline.c", - "src/core/support/cpu_iphone.c", - "src/core/support/cpu_linux.c", - "src/core/support/cpu_posix.c", - "src/core/support/cpu_windows.c", - "src/core/support/env.h", - "src/core/support/env_linux.c", - "src/core/support/env_posix.c", - "src/core/support/env_win32.c", - "src/core/support/histogram.c", - "src/core/support/host_port.c", - "src/core/support/load_file.c", - "src/core/support/load_file.h", - "src/core/support/log.c", - "src/core/support/log_android.c", - "src/core/support/log_linux.c", - "src/core/support/log_posix.c", - "src/core/support/log_win32.c", - "src/core/support/murmur_hash.c", - "src/core/support/murmur_hash.h", - "src/core/support/slice.c", - "src/core/support/slice_buffer.c", - "src/core/support/stack_lockfree.c", - "src/core/support/stack_lockfree.h", - "src/core/support/string.c", - "src/core/support/string.h", - "src/core/support/string_posix.c", - "src/core/support/string_win32.c", - "src/core/support/string_win32.h", - "src/core/support/subprocess_posix.c", - "src/core/support/subprocess_windows.c", - "src/core/support/sync.c", - "src/core/support/sync_posix.c", - "src/core/support/sync_win32.c", - "src/core/support/thd.c", - "src/core/support/thd_internal.h", - "src/core/support/thd_posix.c", - "src/core/support/thd_win32.c", - "src/core/support/time.c", - "src/core/support/time_posix.c", - "src/core/support/time_precise.c", - "src/core/support/time_precise.h", - "src/core/support/time_win32.c", - "src/core/support/tls_pthread.c", - "src/core/support/tmpfile.h", - "src/core/support/tmpfile_posix.c", - "src/core/support/tmpfile_win32.c", - "src/core/support/wrap_memcpy.c" + "src/core/lib/profiling/basic_timers.c", + "src/core/lib/profiling/stap_timers.c", + "src/core/lib/profiling/timers.h", + "src/core/lib/support/alloc.c", + "src/core/lib/support/avl.c", + "src/core/lib/support/backoff.c", + "src/core/lib/support/backoff.h", + "src/core/lib/support/block_annotate.h", + "src/core/lib/support/cmdline.c", + "src/core/lib/support/cpu_iphone.c", + "src/core/lib/support/cpu_linux.c", + "src/core/lib/support/cpu_posix.c", + "src/core/lib/support/cpu_windows.c", + "src/core/lib/support/env.h", + "src/core/lib/support/env_linux.c", + "src/core/lib/support/env_posix.c", + "src/core/lib/support/env_win32.c", + "src/core/lib/support/histogram.c", + "src/core/lib/support/host_port.c", + "src/core/lib/support/load_file.c", + "src/core/lib/support/load_file.h", + "src/core/lib/support/log.c", + "src/core/lib/support/log_android.c", + "src/core/lib/support/log_linux.c", + "src/core/lib/support/log_posix.c", + "src/core/lib/support/log_win32.c", + "src/core/lib/support/murmur_hash.c", + "src/core/lib/support/murmur_hash.h", + "src/core/lib/support/slice.c", + "src/core/lib/support/slice_buffer.c", + "src/core/lib/support/stack_lockfree.c", + "src/core/lib/support/stack_lockfree.h", + "src/core/lib/support/string.c", + "src/core/lib/support/string.h", + "src/core/lib/support/string_posix.c", + "src/core/lib/support/string_win32.c", + "src/core/lib/support/string_win32.h", + "src/core/lib/support/subprocess_posix.c", + "src/core/lib/support/subprocess_windows.c", + "src/core/lib/support/sync.c", + "src/core/lib/support/sync_posix.c", + "src/core/lib/support/sync_win32.c", + "src/core/lib/support/thd.c", + "src/core/lib/support/thd_internal.h", + "src/core/lib/support/thd_posix.c", + "src/core/lib/support/thd_win32.c", + "src/core/lib/support/time.c", + "src/core/lib/support/time_posix.c", + "src/core/lib/support/time_precise.c", + "src/core/lib/support/time_precise.h", + "src/core/lib/support/time_win32.c", + "src/core/lib/support/tls_pthread.c", + "src/core/lib/support/tmpfile.h", + "src/core/lib/support/tmpfile_posix.c", + "src/core/lib/support/tmpfile_win32.c", + "src/core/lib/support/wrap_memcpy.c" ], "third_party": false, "type": "lib" @@ -3924,143 +3924,143 @@ "include/grpc/impl/codegen/propagation_bits.h", "include/grpc/impl/codegen/status.h", "include/grpc/status.h", - "src/core/census/aggregation.h", - "src/core/census/grpc_filter.h", - "src/core/census/grpc_plugin.h", - "src/core/census/mlog.h", - "src/core/census/rpc_metric_id.h", - "src/core/channel/channel_args.h", - "src/core/channel/channel_stack.h", - "src/core/channel/channel_stack_builder.h", - "src/core/channel/client_channel.h", - "src/core/channel/compress_filter.h", - "src/core/channel/connected_channel.h", - "src/core/channel/context.h", - "src/core/channel/http_client_filter.h", - "src/core/channel/http_server_filter.h", - "src/core/channel/subchannel_call_holder.h", - "src/core/client_config/client_config.h", - "src/core/client_config/connector.h", - "src/core/client_config/initial_connect_string.h", - "src/core/client_config/lb_policies/load_balancer_api.h", - "src/core/client_config/lb_policies/pick_first.h", - "src/core/client_config/lb_policies/round_robin.h", - "src/core/client_config/lb_policy.h", - "src/core/client_config/lb_policy_factory.h", - "src/core/client_config/lb_policy_registry.h", - "src/core/client_config/resolver.h", - "src/core/client_config/resolver_factory.h", - "src/core/client_config/resolver_registry.h", - "src/core/client_config/resolvers/dns_resolver.h", - "src/core/client_config/resolvers/sockaddr_resolver.h", - "src/core/client_config/subchannel.h", - "src/core/client_config/subchannel_factory.h", - "src/core/client_config/subchannel_index.h", - "src/core/client_config/uri_parser.h", - "src/core/compression/algorithm_metadata.h", - "src/core/compression/message_compress.h", - "src/core/debug/trace.h", - "src/core/http/format_request.h", - "src/core/http/httpcli.h", - "src/core/http/parser.h", - "src/core/iomgr/closure.h", - "src/core/iomgr/endpoint.h", - "src/core/iomgr/endpoint_pair.h", - "src/core/iomgr/exec_ctx.h", - "src/core/iomgr/executor.h", - "src/core/iomgr/fd_posix.h", - "src/core/iomgr/iocp_windows.h", - "src/core/iomgr/iomgr.h", - "src/core/iomgr/iomgr_internal.h", - "src/core/iomgr/iomgr_posix.h", - "src/core/iomgr/pollset.h", - "src/core/iomgr/pollset_posix.h", - "src/core/iomgr/pollset_set.h", - "src/core/iomgr/pollset_set_posix.h", - "src/core/iomgr/pollset_set_windows.h", - "src/core/iomgr/pollset_windows.h", - "src/core/iomgr/resolve_address.h", - "src/core/iomgr/sockaddr.h", - "src/core/iomgr/sockaddr_posix.h", - "src/core/iomgr/sockaddr_utils.h", - "src/core/iomgr/sockaddr_win32.h", - "src/core/iomgr/socket_utils_posix.h", - "src/core/iomgr/socket_windows.h", - "src/core/iomgr/tcp_client.h", - "src/core/iomgr/tcp_posix.h", - "src/core/iomgr/tcp_server.h", - "src/core/iomgr/tcp_windows.h", - "src/core/iomgr/time_averaged_stats.h", - "src/core/iomgr/timer.h", - "src/core/iomgr/timer_heap.h", - "src/core/iomgr/udp_server.h", - "src/core/iomgr/unix_sockets_posix.h", - "src/core/iomgr/wakeup_fd_pipe.h", - "src/core/iomgr/wakeup_fd_posix.h", - "src/core/iomgr/workqueue.h", - "src/core/iomgr/workqueue_posix.h", - "src/core/iomgr/workqueue_windows.h", - "src/core/json/json.h", - "src/core/json/json_common.h", - "src/core/json/json_reader.h", - "src/core/json/json_writer.h", - "src/core/proto/grpc/lb/v0/load_balancer.pb.h", - "src/core/security/auth_filters.h", - "src/core/security/b64.h", - "src/core/security/credentials.h", - "src/core/security/handshake.h", - "src/core/security/json_token.h", - "src/core/security/jwt_verifier.h", - "src/core/security/secure_endpoint.h", - "src/core/security/security_connector.h", - "src/core/security/security_context.h", - "src/core/statistics/census_interface.h", - "src/core/statistics/census_rpc_stats.h", - "src/core/surface/api_trace.h", - "src/core/surface/call.h", - "src/core/surface/call_test_only.h", - "src/core/surface/channel.h", - "src/core/surface/channel_init.h", - "src/core/surface/channel_stack_type.h", - "src/core/surface/completion_queue.h", - "src/core/surface/event_string.h", - "src/core/surface/init.h", - "src/core/surface/lame_client.h", - "src/core/surface/server.h", - "src/core/surface/surface_trace.h", - "src/core/transport/byte_stream.h", - "src/core/transport/chttp2/alpn.h", - "src/core/transport/chttp2/bin_encoder.h", - "src/core/transport/chttp2/frame.h", - "src/core/transport/chttp2/frame_data.h", - "src/core/transport/chttp2/frame_goaway.h", - "src/core/transport/chttp2/frame_ping.h", - "src/core/transport/chttp2/frame_rst_stream.h", - "src/core/transport/chttp2/frame_settings.h", - "src/core/transport/chttp2/frame_window_update.h", - "src/core/transport/chttp2/hpack_encoder.h", - "src/core/transport/chttp2/hpack_parser.h", - "src/core/transport/chttp2/hpack_table.h", - "src/core/transport/chttp2/http2_errors.h", - "src/core/transport/chttp2/huffsyms.h", - "src/core/transport/chttp2/incoming_metadata.h", - "src/core/transport/chttp2/internal.h", - "src/core/transport/chttp2/status_conversion.h", - "src/core/transport/chttp2/stream_map.h", - "src/core/transport/chttp2/timeout_encoding.h", - "src/core/transport/chttp2/varint.h", - "src/core/transport/chttp2_transport.h", - "src/core/transport/connectivity_state.h", - "src/core/transport/metadata.h", - "src/core/transport/metadata_batch.h", - "src/core/transport/static_metadata.h", - "src/core/transport/transport.h", - "src/core/transport/transport_impl.h", - "src/core/tsi/fake_transport_security.h", - "src/core/tsi/ssl_transport_security.h", - "src/core/tsi/ssl_types.h", - "src/core/tsi/transport_security.h", - "src/core/tsi/transport_security_interface.h", + "src/core/lib/census/aggregation.h", + "src/core/lib/census/grpc_filter.h", + "src/core/lib/census/grpc_plugin.h", + "src/core/lib/census/mlog.h", + "src/core/lib/census/rpc_metric_id.h", + "src/core/lib/channel/channel_args.h", + "src/core/lib/channel/channel_stack.h", + "src/core/lib/channel/channel_stack_builder.h", + "src/core/lib/channel/client_channel.h", + "src/core/lib/channel/compress_filter.h", + "src/core/lib/channel/connected_channel.h", + "src/core/lib/channel/context.h", + "src/core/lib/channel/http_client_filter.h", + "src/core/lib/channel/http_server_filter.h", + "src/core/lib/channel/subchannel_call_holder.h", + "src/core/lib/client_config/client_config.h", + "src/core/lib/client_config/connector.h", + "src/core/lib/client_config/initial_connect_string.h", + "src/core/lib/client_config/lb_policies/load_balancer_api.h", + "src/core/lib/client_config/lb_policies/pick_first.h", + "src/core/lib/client_config/lb_policies/round_robin.h", + "src/core/lib/client_config/lb_policy.h", + "src/core/lib/client_config/lb_policy_factory.h", + "src/core/lib/client_config/lb_policy_registry.h", + "src/core/lib/client_config/resolver.h", + "src/core/lib/client_config/resolver_factory.h", + "src/core/lib/client_config/resolver_registry.h", + "src/core/lib/client_config/resolvers/dns_resolver.h", + "src/core/lib/client_config/resolvers/sockaddr_resolver.h", + "src/core/lib/client_config/subchannel.h", + "src/core/lib/client_config/subchannel_factory.h", + "src/core/lib/client_config/subchannel_index.h", + "src/core/lib/client_config/uri_parser.h", + "src/core/lib/compression/algorithm_metadata.h", + "src/core/lib/compression/message_compress.h", + "src/core/lib/debug/trace.h", + "src/core/lib/http/format_request.h", + "src/core/lib/http/httpcli.h", + "src/core/lib/http/parser.h", + "src/core/lib/iomgr/closure.h", + "src/core/lib/iomgr/endpoint.h", + "src/core/lib/iomgr/endpoint_pair.h", + "src/core/lib/iomgr/exec_ctx.h", + "src/core/lib/iomgr/executor.h", + "src/core/lib/iomgr/fd_posix.h", + "src/core/lib/iomgr/iocp_windows.h", + "src/core/lib/iomgr/iomgr.h", + "src/core/lib/iomgr/iomgr_internal.h", + "src/core/lib/iomgr/iomgr_posix.h", + "src/core/lib/iomgr/pollset.h", + "src/core/lib/iomgr/pollset_posix.h", + "src/core/lib/iomgr/pollset_set.h", + "src/core/lib/iomgr/pollset_set_posix.h", + "src/core/lib/iomgr/pollset_set_windows.h", + "src/core/lib/iomgr/pollset_windows.h", + "src/core/lib/iomgr/resolve_address.h", + "src/core/lib/iomgr/sockaddr.h", + "src/core/lib/iomgr/sockaddr_posix.h", + "src/core/lib/iomgr/sockaddr_utils.h", + "src/core/lib/iomgr/sockaddr_win32.h", + "src/core/lib/iomgr/socket_utils_posix.h", + "src/core/lib/iomgr/socket_windows.h", + "src/core/lib/iomgr/tcp_client.h", + "src/core/lib/iomgr/tcp_posix.h", + "src/core/lib/iomgr/tcp_server.h", + "src/core/lib/iomgr/tcp_windows.h", + "src/core/lib/iomgr/time_averaged_stats.h", + "src/core/lib/iomgr/timer.h", + "src/core/lib/iomgr/timer_heap.h", + "src/core/lib/iomgr/udp_server.h", + "src/core/lib/iomgr/unix_sockets_posix.h", + "src/core/lib/iomgr/wakeup_fd_pipe.h", + "src/core/lib/iomgr/wakeup_fd_posix.h", + "src/core/lib/iomgr/workqueue.h", + "src/core/lib/iomgr/workqueue_posix.h", + "src/core/lib/iomgr/workqueue_windows.h", + "src/core/lib/json/json.h", + "src/core/lib/json/json_common.h", + "src/core/lib/json/json_reader.h", + "src/core/lib/json/json_writer.h", + "src/core/lib/proto/grpc/lb/v0/load_balancer.pb.h", + "src/core/lib/security/auth_filters.h", + "src/core/lib/security/b64.h", + "src/core/lib/security/credentials.h", + "src/core/lib/security/handshake.h", + "src/core/lib/security/json_token.h", + "src/core/lib/security/jwt_verifier.h", + "src/core/lib/security/secure_endpoint.h", + "src/core/lib/security/security_connector.h", + "src/core/lib/security/security_context.h", + "src/core/lib/statistics/census_interface.h", + "src/core/lib/statistics/census_rpc_stats.h", + "src/core/lib/surface/api_trace.h", + "src/core/lib/surface/call.h", + "src/core/lib/surface/call_test_only.h", + "src/core/lib/surface/channel.h", + "src/core/lib/surface/channel_init.h", + "src/core/lib/surface/channel_stack_type.h", + "src/core/lib/surface/completion_queue.h", + "src/core/lib/surface/event_string.h", + "src/core/lib/surface/init.h", + "src/core/lib/surface/lame_client.h", + "src/core/lib/surface/server.h", + "src/core/lib/surface/surface_trace.h", + "src/core/lib/transport/byte_stream.h", + "src/core/lib/transport/chttp2/alpn.h", + "src/core/lib/transport/chttp2/bin_encoder.h", + "src/core/lib/transport/chttp2/frame.h", + "src/core/lib/transport/chttp2/frame_data.h", + "src/core/lib/transport/chttp2/frame_goaway.h", + "src/core/lib/transport/chttp2/frame_ping.h", + "src/core/lib/transport/chttp2/frame_rst_stream.h", + "src/core/lib/transport/chttp2/frame_settings.h", + "src/core/lib/transport/chttp2/frame_window_update.h", + "src/core/lib/transport/chttp2/hpack_encoder.h", + "src/core/lib/transport/chttp2/hpack_parser.h", + "src/core/lib/transport/chttp2/hpack_table.h", + "src/core/lib/transport/chttp2/http2_errors.h", + "src/core/lib/transport/chttp2/huffsyms.h", + "src/core/lib/transport/chttp2/incoming_metadata.h", + "src/core/lib/transport/chttp2/internal.h", + "src/core/lib/transport/chttp2/status_conversion.h", + "src/core/lib/transport/chttp2/stream_map.h", + "src/core/lib/transport/chttp2/timeout_encoding.h", + "src/core/lib/transport/chttp2/varint.h", + "src/core/lib/transport/chttp2_transport.h", + "src/core/lib/transport/connectivity_state.h", + "src/core/lib/transport/metadata.h", + "src/core/lib/transport/metadata_batch.h", + "src/core/lib/transport/static_metadata.h", + "src/core/lib/transport/transport.h", + "src/core/lib/transport/transport_impl.h", + "src/core/lib/tsi/fake_transport_security.h", + "src/core/lib/tsi/ssl_transport_security.h", + "src/core/lib/tsi/ssl_types.h", + "src/core/lib/tsi/transport_security.h", + "src/core/lib/tsi/transport_security_interface.h", "third_party/nanopb/pb.h", "third_party/nanopb/pb_common.h", "third_party/nanopb/pb_decode.h", @@ -4082,304 +4082,304 @@ "include/grpc/impl/codegen/propagation_bits.h", "include/grpc/impl/codegen/status.h", "include/grpc/status.h", - "src/core/census/aggregation.h", - "src/core/census/context.c", - "src/core/census/grpc_context.c", - "src/core/census/grpc_filter.c", - "src/core/census/grpc_filter.h", - "src/core/census/grpc_plugin.c", - "src/core/census/grpc_plugin.h", - "src/core/census/initialize.c", - "src/core/census/mlog.c", - "src/core/census/mlog.h", - "src/core/census/operation.c", - "src/core/census/placeholders.c", - "src/core/census/rpc_metric_id.h", - "src/core/census/tracing.c", - "src/core/channel/channel_args.c", - "src/core/channel/channel_args.h", - "src/core/channel/channel_stack.c", - "src/core/channel/channel_stack.h", - "src/core/channel/channel_stack_builder.c", - "src/core/channel/channel_stack_builder.h", - "src/core/channel/client_channel.c", - "src/core/channel/client_channel.h", - "src/core/channel/compress_filter.c", - "src/core/channel/compress_filter.h", - "src/core/channel/connected_channel.c", - "src/core/channel/connected_channel.h", - "src/core/channel/context.h", - "src/core/channel/http_client_filter.c", - "src/core/channel/http_client_filter.h", - "src/core/channel/http_server_filter.c", - "src/core/channel/http_server_filter.h", - "src/core/channel/subchannel_call_holder.c", - "src/core/channel/subchannel_call_holder.h", - "src/core/client_config/client_config.c", - "src/core/client_config/client_config.h", - "src/core/client_config/connector.c", - "src/core/client_config/connector.h", - "src/core/client_config/default_initial_connect_string.c", - "src/core/client_config/initial_connect_string.c", - "src/core/client_config/initial_connect_string.h", - "src/core/client_config/lb_policies/load_balancer_api.c", - "src/core/client_config/lb_policies/load_balancer_api.h", - "src/core/client_config/lb_policies/pick_first.c", - "src/core/client_config/lb_policies/pick_first.h", - "src/core/client_config/lb_policies/round_robin.c", - "src/core/client_config/lb_policies/round_robin.h", - "src/core/client_config/lb_policy.c", - "src/core/client_config/lb_policy.h", - "src/core/client_config/lb_policy_factory.c", - "src/core/client_config/lb_policy_factory.h", - "src/core/client_config/lb_policy_registry.c", - "src/core/client_config/lb_policy_registry.h", - "src/core/client_config/resolver.c", - "src/core/client_config/resolver.h", - "src/core/client_config/resolver_factory.c", - "src/core/client_config/resolver_factory.h", - "src/core/client_config/resolver_registry.c", - "src/core/client_config/resolver_registry.h", - "src/core/client_config/resolvers/dns_resolver.c", - "src/core/client_config/resolvers/dns_resolver.h", - "src/core/client_config/resolvers/sockaddr_resolver.c", - "src/core/client_config/resolvers/sockaddr_resolver.h", - "src/core/client_config/subchannel.c", - "src/core/client_config/subchannel.h", - "src/core/client_config/subchannel_factory.c", - "src/core/client_config/subchannel_factory.h", - "src/core/client_config/subchannel_index.c", - "src/core/client_config/subchannel_index.h", - "src/core/client_config/uri_parser.c", - "src/core/client_config/uri_parser.h", - "src/core/compression/algorithm_metadata.h", - "src/core/compression/compression_algorithm.c", - "src/core/compression/message_compress.c", - "src/core/compression/message_compress.h", - "src/core/debug/trace.c", - "src/core/debug/trace.h", - "src/core/http/format_request.c", - "src/core/http/format_request.h", - "src/core/http/httpcli.c", - "src/core/http/httpcli.h", - "src/core/http/httpcli_security_connector.c", - "src/core/http/parser.c", - "src/core/http/parser.h", - "src/core/iomgr/closure.c", - "src/core/iomgr/closure.h", - "src/core/iomgr/endpoint.c", - "src/core/iomgr/endpoint.h", - "src/core/iomgr/endpoint_pair.h", - "src/core/iomgr/endpoint_pair_posix.c", - "src/core/iomgr/endpoint_pair_windows.c", - "src/core/iomgr/exec_ctx.c", - "src/core/iomgr/exec_ctx.h", - "src/core/iomgr/executor.c", - "src/core/iomgr/executor.h", - "src/core/iomgr/fd_posix.c", - "src/core/iomgr/fd_posix.h", - "src/core/iomgr/iocp_windows.c", - "src/core/iomgr/iocp_windows.h", - "src/core/iomgr/iomgr.c", - "src/core/iomgr/iomgr.h", - "src/core/iomgr/iomgr_internal.h", - "src/core/iomgr/iomgr_posix.c", - "src/core/iomgr/iomgr_posix.h", - "src/core/iomgr/iomgr_windows.c", - "src/core/iomgr/pollset.h", - "src/core/iomgr/pollset_multipoller_with_epoll.c", - "src/core/iomgr/pollset_multipoller_with_poll_posix.c", - "src/core/iomgr/pollset_posix.c", - "src/core/iomgr/pollset_posix.h", - "src/core/iomgr/pollset_set.h", - "src/core/iomgr/pollset_set_posix.c", - "src/core/iomgr/pollset_set_posix.h", - "src/core/iomgr/pollset_set_windows.c", - "src/core/iomgr/pollset_set_windows.h", - "src/core/iomgr/pollset_windows.c", - "src/core/iomgr/pollset_windows.h", - "src/core/iomgr/resolve_address.h", - "src/core/iomgr/resolve_address_posix.c", - "src/core/iomgr/resolve_address_windows.c", - "src/core/iomgr/sockaddr.h", - "src/core/iomgr/sockaddr_posix.h", - "src/core/iomgr/sockaddr_utils.c", - "src/core/iomgr/sockaddr_utils.h", - "src/core/iomgr/sockaddr_win32.h", - "src/core/iomgr/socket_utils_common_posix.c", - "src/core/iomgr/socket_utils_linux.c", - "src/core/iomgr/socket_utils_posix.c", - "src/core/iomgr/socket_utils_posix.h", - "src/core/iomgr/socket_windows.c", - "src/core/iomgr/socket_windows.h", - "src/core/iomgr/tcp_client.h", - "src/core/iomgr/tcp_client_posix.c", - "src/core/iomgr/tcp_client_windows.c", - "src/core/iomgr/tcp_posix.c", - "src/core/iomgr/tcp_posix.h", - "src/core/iomgr/tcp_server.h", - "src/core/iomgr/tcp_server_posix.c", - "src/core/iomgr/tcp_server_windows.c", - "src/core/iomgr/tcp_windows.c", - "src/core/iomgr/tcp_windows.h", - "src/core/iomgr/time_averaged_stats.c", - "src/core/iomgr/time_averaged_stats.h", - "src/core/iomgr/timer.c", - "src/core/iomgr/timer.h", - "src/core/iomgr/timer_heap.c", - "src/core/iomgr/timer_heap.h", - "src/core/iomgr/udp_server.c", - "src/core/iomgr/udp_server.h", - "src/core/iomgr/unix_sockets_posix.c", - "src/core/iomgr/unix_sockets_posix.h", - "src/core/iomgr/unix_sockets_posix_noop.c", - "src/core/iomgr/wakeup_fd_eventfd.c", - "src/core/iomgr/wakeup_fd_nospecial.c", - "src/core/iomgr/wakeup_fd_pipe.c", - "src/core/iomgr/wakeup_fd_pipe.h", - "src/core/iomgr/wakeup_fd_posix.c", - "src/core/iomgr/wakeup_fd_posix.h", - "src/core/iomgr/workqueue.h", - "src/core/iomgr/workqueue_posix.c", - "src/core/iomgr/workqueue_posix.h", - "src/core/iomgr/workqueue_windows.c", - "src/core/iomgr/workqueue_windows.h", - "src/core/json/json.c", - "src/core/json/json.h", - "src/core/json/json_common.h", - "src/core/json/json_reader.c", - "src/core/json/json_reader.h", - "src/core/json/json_string.c", - "src/core/json/json_writer.c", - "src/core/json/json_writer.h", - "src/core/proto/grpc/lb/v0/load_balancer.pb.c", - "src/core/proto/grpc/lb/v0/load_balancer.pb.h", - "src/core/security/auth_filters.h", - "src/core/security/b64.c", - "src/core/security/b64.h", - "src/core/security/client_auth_filter.c", - "src/core/security/credentials.c", - "src/core/security/credentials.h", - "src/core/security/credentials_metadata.c", - "src/core/security/credentials_posix.c", - "src/core/security/credentials_win32.c", - "src/core/security/google_default_credentials.c", - "src/core/security/handshake.c", - "src/core/security/handshake.h", - "src/core/security/json_token.c", - "src/core/security/json_token.h", - "src/core/security/jwt_verifier.c", - "src/core/security/jwt_verifier.h", - "src/core/security/secure_endpoint.c", - "src/core/security/secure_endpoint.h", - "src/core/security/security_connector.c", - "src/core/security/security_connector.h", - "src/core/security/security_context.c", - "src/core/security/security_context.h", - "src/core/security/server_auth_filter.c", - "src/core/security/server_secure_chttp2.c", - "src/core/statistics/census_interface.h", - "src/core/statistics/census_rpc_stats.h", - "src/core/surface/alarm.c", - "src/core/surface/api_trace.c", - "src/core/surface/api_trace.h", - "src/core/surface/byte_buffer.c", - "src/core/surface/byte_buffer_reader.c", - "src/core/surface/call.c", - "src/core/surface/call.h", - "src/core/surface/call_details.c", - "src/core/surface/call_log_batch.c", - "src/core/surface/call_test_only.h", - "src/core/surface/channel.c", - "src/core/surface/channel.h", - "src/core/surface/channel_connectivity.c", - "src/core/surface/channel_create.c", - "src/core/surface/channel_init.c", - "src/core/surface/channel_init.h", - "src/core/surface/channel_ping.c", - "src/core/surface/channel_stack_type.c", - "src/core/surface/channel_stack_type.h", - "src/core/surface/completion_queue.c", - "src/core/surface/completion_queue.h", - "src/core/surface/event_string.c", - "src/core/surface/event_string.h", - "src/core/surface/init.c", - "src/core/surface/init.h", - "src/core/surface/init_secure.c", - "src/core/surface/lame_client.c", - "src/core/surface/lame_client.h", - "src/core/surface/metadata_array.c", - "src/core/surface/secure_channel_create.c", - "src/core/surface/server.c", - "src/core/surface/server.h", - "src/core/surface/server_chttp2.c", - "src/core/surface/surface_trace.h", - "src/core/surface/validate_metadata.c", - "src/core/surface/version.c", - "src/core/transport/byte_stream.c", - "src/core/transport/byte_stream.h", - "src/core/transport/chttp2/alpn.c", - "src/core/transport/chttp2/alpn.h", - "src/core/transport/chttp2/bin_encoder.c", - "src/core/transport/chttp2/bin_encoder.h", - "src/core/transport/chttp2/frame.h", - "src/core/transport/chttp2/frame_data.c", - "src/core/transport/chttp2/frame_data.h", - "src/core/transport/chttp2/frame_goaway.c", - "src/core/transport/chttp2/frame_goaway.h", - "src/core/transport/chttp2/frame_ping.c", - "src/core/transport/chttp2/frame_ping.h", - "src/core/transport/chttp2/frame_rst_stream.c", - "src/core/transport/chttp2/frame_rst_stream.h", - "src/core/transport/chttp2/frame_settings.c", - "src/core/transport/chttp2/frame_settings.h", - "src/core/transport/chttp2/frame_window_update.c", - "src/core/transport/chttp2/frame_window_update.h", - "src/core/transport/chttp2/hpack_encoder.c", - "src/core/transport/chttp2/hpack_encoder.h", - "src/core/transport/chttp2/hpack_parser.c", - "src/core/transport/chttp2/hpack_parser.h", - "src/core/transport/chttp2/hpack_table.c", - "src/core/transport/chttp2/hpack_table.h", - "src/core/transport/chttp2/http2_errors.h", - "src/core/transport/chttp2/huffsyms.c", - "src/core/transport/chttp2/huffsyms.h", - "src/core/transport/chttp2/incoming_metadata.c", - "src/core/transport/chttp2/incoming_metadata.h", - "src/core/transport/chttp2/internal.h", - "src/core/transport/chttp2/parsing.c", - "src/core/transport/chttp2/status_conversion.c", - "src/core/transport/chttp2/status_conversion.h", - "src/core/transport/chttp2/stream_lists.c", - "src/core/transport/chttp2/stream_map.c", - "src/core/transport/chttp2/stream_map.h", - "src/core/transport/chttp2/timeout_encoding.c", - "src/core/transport/chttp2/timeout_encoding.h", - "src/core/transport/chttp2/varint.c", - "src/core/transport/chttp2/varint.h", - "src/core/transport/chttp2/writing.c", - "src/core/transport/chttp2_transport.c", - "src/core/transport/chttp2_transport.h", - "src/core/transport/connectivity_state.c", - "src/core/transport/connectivity_state.h", - "src/core/transport/metadata.c", - "src/core/transport/metadata.h", - "src/core/transport/metadata_batch.c", - "src/core/transport/metadata_batch.h", - "src/core/transport/static_metadata.c", - "src/core/transport/static_metadata.h", - "src/core/transport/transport.c", - "src/core/transport/transport.h", - "src/core/transport/transport_impl.h", - "src/core/transport/transport_op_string.c", - "src/core/tsi/fake_transport_security.c", - "src/core/tsi/fake_transport_security.h", - "src/core/tsi/ssl_transport_security.c", - "src/core/tsi/ssl_transport_security.h", - "src/core/tsi/ssl_types.h", - "src/core/tsi/transport_security.c", - "src/core/tsi/transport_security.h", - "src/core/tsi/transport_security_interface.h" + "src/core/lib/census/aggregation.h", + "src/core/lib/census/context.c", + "src/core/lib/census/grpc_context.c", + "src/core/lib/census/grpc_filter.c", + "src/core/lib/census/grpc_filter.h", + "src/core/lib/census/grpc_plugin.c", + "src/core/lib/census/grpc_plugin.h", + "src/core/lib/census/initialize.c", + "src/core/lib/census/mlog.c", + "src/core/lib/census/mlog.h", + "src/core/lib/census/operation.c", + "src/core/lib/census/placeholders.c", + "src/core/lib/census/rpc_metric_id.h", + "src/core/lib/census/tracing.c", + "src/core/lib/channel/channel_args.c", + "src/core/lib/channel/channel_args.h", + "src/core/lib/channel/channel_stack.c", + "src/core/lib/channel/channel_stack.h", + "src/core/lib/channel/channel_stack_builder.c", + "src/core/lib/channel/channel_stack_builder.h", + "src/core/lib/channel/client_channel.c", + "src/core/lib/channel/client_channel.h", + "src/core/lib/channel/compress_filter.c", + "src/core/lib/channel/compress_filter.h", + "src/core/lib/channel/connected_channel.c", + "src/core/lib/channel/connected_channel.h", + "src/core/lib/channel/context.h", + "src/core/lib/channel/http_client_filter.c", + "src/core/lib/channel/http_client_filter.h", + "src/core/lib/channel/http_server_filter.c", + "src/core/lib/channel/http_server_filter.h", + "src/core/lib/channel/subchannel_call_holder.c", + "src/core/lib/channel/subchannel_call_holder.h", + "src/core/lib/client_config/client_config.c", + "src/core/lib/client_config/client_config.h", + "src/core/lib/client_config/connector.c", + "src/core/lib/client_config/connector.h", + "src/core/lib/client_config/default_initial_connect_string.c", + "src/core/lib/client_config/initial_connect_string.c", + "src/core/lib/client_config/initial_connect_string.h", + "src/core/lib/client_config/lb_policies/load_balancer_api.c", + "src/core/lib/client_config/lb_policies/load_balancer_api.h", + "src/core/lib/client_config/lb_policies/pick_first.c", + "src/core/lib/client_config/lb_policies/pick_first.h", + "src/core/lib/client_config/lb_policies/round_robin.c", + "src/core/lib/client_config/lb_policies/round_robin.h", + "src/core/lib/client_config/lb_policy.c", + "src/core/lib/client_config/lb_policy.h", + "src/core/lib/client_config/lb_policy_factory.c", + "src/core/lib/client_config/lb_policy_factory.h", + "src/core/lib/client_config/lb_policy_registry.c", + "src/core/lib/client_config/lb_policy_registry.h", + "src/core/lib/client_config/resolver.c", + "src/core/lib/client_config/resolver.h", + "src/core/lib/client_config/resolver_factory.c", + "src/core/lib/client_config/resolver_factory.h", + "src/core/lib/client_config/resolver_registry.c", + "src/core/lib/client_config/resolver_registry.h", + "src/core/lib/client_config/resolvers/dns_resolver.c", + "src/core/lib/client_config/resolvers/dns_resolver.h", + "src/core/lib/client_config/resolvers/sockaddr_resolver.c", + "src/core/lib/client_config/resolvers/sockaddr_resolver.h", + "src/core/lib/client_config/subchannel.c", + "src/core/lib/client_config/subchannel.h", + "src/core/lib/client_config/subchannel_factory.c", + "src/core/lib/client_config/subchannel_factory.h", + "src/core/lib/client_config/subchannel_index.c", + "src/core/lib/client_config/subchannel_index.h", + "src/core/lib/client_config/uri_parser.c", + "src/core/lib/client_config/uri_parser.h", + "src/core/lib/compression/algorithm_metadata.h", + "src/core/lib/compression/compression_algorithm.c", + "src/core/lib/compression/message_compress.c", + "src/core/lib/compression/message_compress.h", + "src/core/lib/debug/trace.c", + "src/core/lib/debug/trace.h", + "src/core/lib/http/format_request.c", + "src/core/lib/http/format_request.h", + "src/core/lib/http/httpcli.c", + "src/core/lib/http/httpcli.h", + "src/core/lib/http/httpcli_security_connector.c", + "src/core/lib/http/parser.c", + "src/core/lib/http/parser.h", + "src/core/lib/iomgr/closure.c", + "src/core/lib/iomgr/closure.h", + "src/core/lib/iomgr/endpoint.c", + "src/core/lib/iomgr/endpoint.h", + "src/core/lib/iomgr/endpoint_pair.h", + "src/core/lib/iomgr/endpoint_pair_posix.c", + "src/core/lib/iomgr/endpoint_pair_windows.c", + "src/core/lib/iomgr/exec_ctx.c", + "src/core/lib/iomgr/exec_ctx.h", + "src/core/lib/iomgr/executor.c", + "src/core/lib/iomgr/executor.h", + "src/core/lib/iomgr/fd_posix.c", + "src/core/lib/iomgr/fd_posix.h", + "src/core/lib/iomgr/iocp_windows.c", + "src/core/lib/iomgr/iocp_windows.h", + "src/core/lib/iomgr/iomgr.c", + "src/core/lib/iomgr/iomgr.h", + "src/core/lib/iomgr/iomgr_internal.h", + "src/core/lib/iomgr/iomgr_posix.c", + "src/core/lib/iomgr/iomgr_posix.h", + "src/core/lib/iomgr/iomgr_windows.c", + "src/core/lib/iomgr/pollset.h", + "src/core/lib/iomgr/pollset_multipoller_with_epoll.c", + "src/core/lib/iomgr/pollset_multipoller_with_poll_posix.c", + "src/core/lib/iomgr/pollset_posix.c", + "src/core/lib/iomgr/pollset_posix.h", + "src/core/lib/iomgr/pollset_set.h", + "src/core/lib/iomgr/pollset_set_posix.c", + "src/core/lib/iomgr/pollset_set_posix.h", + "src/core/lib/iomgr/pollset_set_windows.c", + "src/core/lib/iomgr/pollset_set_windows.h", + "src/core/lib/iomgr/pollset_windows.c", + "src/core/lib/iomgr/pollset_windows.h", + "src/core/lib/iomgr/resolve_address.h", + "src/core/lib/iomgr/resolve_address_posix.c", + "src/core/lib/iomgr/resolve_address_windows.c", + "src/core/lib/iomgr/sockaddr.h", + "src/core/lib/iomgr/sockaddr_posix.h", + "src/core/lib/iomgr/sockaddr_utils.c", + "src/core/lib/iomgr/sockaddr_utils.h", + "src/core/lib/iomgr/sockaddr_win32.h", + "src/core/lib/iomgr/socket_utils_common_posix.c", + "src/core/lib/iomgr/socket_utils_linux.c", + "src/core/lib/iomgr/socket_utils_posix.c", + "src/core/lib/iomgr/socket_utils_posix.h", + "src/core/lib/iomgr/socket_windows.c", + "src/core/lib/iomgr/socket_windows.h", + "src/core/lib/iomgr/tcp_client.h", + "src/core/lib/iomgr/tcp_client_posix.c", + "src/core/lib/iomgr/tcp_client_windows.c", + "src/core/lib/iomgr/tcp_posix.c", + "src/core/lib/iomgr/tcp_posix.h", + "src/core/lib/iomgr/tcp_server.h", + "src/core/lib/iomgr/tcp_server_posix.c", + "src/core/lib/iomgr/tcp_server_windows.c", + "src/core/lib/iomgr/tcp_windows.c", + "src/core/lib/iomgr/tcp_windows.h", + "src/core/lib/iomgr/time_averaged_stats.c", + "src/core/lib/iomgr/time_averaged_stats.h", + "src/core/lib/iomgr/timer.c", + "src/core/lib/iomgr/timer.h", + "src/core/lib/iomgr/timer_heap.c", + "src/core/lib/iomgr/timer_heap.h", + "src/core/lib/iomgr/udp_server.c", + "src/core/lib/iomgr/udp_server.h", + "src/core/lib/iomgr/unix_sockets_posix.c", + "src/core/lib/iomgr/unix_sockets_posix.h", + "src/core/lib/iomgr/unix_sockets_posix_noop.c", + "src/core/lib/iomgr/wakeup_fd_eventfd.c", + "src/core/lib/iomgr/wakeup_fd_nospecial.c", + "src/core/lib/iomgr/wakeup_fd_pipe.c", + "src/core/lib/iomgr/wakeup_fd_pipe.h", + "src/core/lib/iomgr/wakeup_fd_posix.c", + "src/core/lib/iomgr/wakeup_fd_posix.h", + "src/core/lib/iomgr/workqueue.h", + "src/core/lib/iomgr/workqueue_posix.c", + "src/core/lib/iomgr/workqueue_posix.h", + "src/core/lib/iomgr/workqueue_windows.c", + "src/core/lib/iomgr/workqueue_windows.h", + "src/core/lib/json/json.c", + "src/core/lib/json/json.h", + "src/core/lib/json/json_common.h", + "src/core/lib/json/json_reader.c", + "src/core/lib/json/json_reader.h", + "src/core/lib/json/json_string.c", + "src/core/lib/json/json_writer.c", + "src/core/lib/json/json_writer.h", + "src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c", + "src/core/lib/proto/grpc/lb/v0/load_balancer.pb.h", + "src/core/lib/security/auth_filters.h", + "src/core/lib/security/b64.c", + "src/core/lib/security/b64.h", + "src/core/lib/security/client_auth_filter.c", + "src/core/lib/security/credentials.c", + "src/core/lib/security/credentials.h", + "src/core/lib/security/credentials_metadata.c", + "src/core/lib/security/credentials_posix.c", + "src/core/lib/security/credentials_win32.c", + "src/core/lib/security/google_default_credentials.c", + "src/core/lib/security/handshake.c", + "src/core/lib/security/handshake.h", + "src/core/lib/security/json_token.c", + "src/core/lib/security/json_token.h", + "src/core/lib/security/jwt_verifier.c", + "src/core/lib/security/jwt_verifier.h", + "src/core/lib/security/secure_endpoint.c", + "src/core/lib/security/secure_endpoint.h", + "src/core/lib/security/security_connector.c", + "src/core/lib/security/security_connector.h", + "src/core/lib/security/security_context.c", + "src/core/lib/security/security_context.h", + "src/core/lib/security/server_auth_filter.c", + "src/core/lib/security/server_secure_chttp2.c", + "src/core/lib/statistics/census_interface.h", + "src/core/lib/statistics/census_rpc_stats.h", + "src/core/lib/surface/alarm.c", + "src/core/lib/surface/api_trace.c", + "src/core/lib/surface/api_trace.h", + "src/core/lib/surface/byte_buffer.c", + "src/core/lib/surface/byte_buffer_reader.c", + "src/core/lib/surface/call.c", + "src/core/lib/surface/call.h", + "src/core/lib/surface/call_details.c", + "src/core/lib/surface/call_log_batch.c", + "src/core/lib/surface/call_test_only.h", + "src/core/lib/surface/channel.c", + "src/core/lib/surface/channel.h", + "src/core/lib/surface/channel_connectivity.c", + "src/core/lib/surface/channel_create.c", + "src/core/lib/surface/channel_init.c", + "src/core/lib/surface/channel_init.h", + "src/core/lib/surface/channel_ping.c", + "src/core/lib/surface/channel_stack_type.c", + "src/core/lib/surface/channel_stack_type.h", + "src/core/lib/surface/completion_queue.c", + "src/core/lib/surface/completion_queue.h", + "src/core/lib/surface/event_string.c", + "src/core/lib/surface/event_string.h", + "src/core/lib/surface/init.c", + "src/core/lib/surface/init.h", + "src/core/lib/surface/init_secure.c", + "src/core/lib/surface/lame_client.c", + "src/core/lib/surface/lame_client.h", + "src/core/lib/surface/metadata_array.c", + "src/core/lib/surface/secure_channel_create.c", + "src/core/lib/surface/server.c", + "src/core/lib/surface/server.h", + "src/core/lib/surface/server_chttp2.c", + "src/core/lib/surface/surface_trace.h", + "src/core/lib/surface/validate_metadata.c", + "src/core/lib/surface/version.c", + "src/core/lib/transport/byte_stream.c", + "src/core/lib/transport/byte_stream.h", + "src/core/lib/transport/chttp2/alpn.c", + "src/core/lib/transport/chttp2/alpn.h", + "src/core/lib/transport/chttp2/bin_encoder.c", + "src/core/lib/transport/chttp2/bin_encoder.h", + "src/core/lib/transport/chttp2/frame.h", + "src/core/lib/transport/chttp2/frame_data.c", + "src/core/lib/transport/chttp2/frame_data.h", + "src/core/lib/transport/chttp2/frame_goaway.c", + "src/core/lib/transport/chttp2/frame_goaway.h", + "src/core/lib/transport/chttp2/frame_ping.c", + "src/core/lib/transport/chttp2/frame_ping.h", + "src/core/lib/transport/chttp2/frame_rst_stream.c", + "src/core/lib/transport/chttp2/frame_rst_stream.h", + "src/core/lib/transport/chttp2/frame_settings.c", + "src/core/lib/transport/chttp2/frame_settings.h", + "src/core/lib/transport/chttp2/frame_window_update.c", + "src/core/lib/transport/chttp2/frame_window_update.h", + "src/core/lib/transport/chttp2/hpack_encoder.c", + "src/core/lib/transport/chttp2/hpack_encoder.h", + "src/core/lib/transport/chttp2/hpack_parser.c", + "src/core/lib/transport/chttp2/hpack_parser.h", + "src/core/lib/transport/chttp2/hpack_table.c", + "src/core/lib/transport/chttp2/hpack_table.h", + "src/core/lib/transport/chttp2/http2_errors.h", + "src/core/lib/transport/chttp2/huffsyms.c", + "src/core/lib/transport/chttp2/huffsyms.h", + "src/core/lib/transport/chttp2/incoming_metadata.c", + "src/core/lib/transport/chttp2/incoming_metadata.h", + "src/core/lib/transport/chttp2/internal.h", + "src/core/lib/transport/chttp2/parsing.c", + "src/core/lib/transport/chttp2/status_conversion.c", + "src/core/lib/transport/chttp2/status_conversion.h", + "src/core/lib/transport/chttp2/stream_lists.c", + "src/core/lib/transport/chttp2/stream_map.c", + "src/core/lib/transport/chttp2/stream_map.h", + "src/core/lib/transport/chttp2/timeout_encoding.c", + "src/core/lib/transport/chttp2/timeout_encoding.h", + "src/core/lib/transport/chttp2/varint.c", + "src/core/lib/transport/chttp2/varint.h", + "src/core/lib/transport/chttp2/writing.c", + "src/core/lib/transport/chttp2_transport.c", + "src/core/lib/transport/chttp2_transport.h", + "src/core/lib/transport/connectivity_state.c", + "src/core/lib/transport/connectivity_state.h", + "src/core/lib/transport/metadata.c", + "src/core/lib/transport/metadata.h", + "src/core/lib/transport/metadata_batch.c", + "src/core/lib/transport/metadata_batch.h", + "src/core/lib/transport/static_metadata.c", + "src/core/lib/transport/static_metadata.h", + "src/core/lib/transport/transport.c", + "src/core/lib/transport/transport.h", + "src/core/lib/transport/transport_impl.h", + "src/core/lib/transport/transport_op_string.c", + "src/core/lib/tsi/fake_transport_security.c", + "src/core/lib/tsi/fake_transport_security.h", + "src/core/lib/tsi/ssl_transport_security.c", + "src/core/lib/tsi/ssl_transport_security.h", + "src/core/lib/tsi/ssl_types.h", + "src/core/lib/tsi/transport_security.c", + "src/core/lib/tsi/transport_security.h", + "src/core/lib/tsi/transport_security_interface.h" ], "third_party": false, "type": "lib" @@ -4552,129 +4552,129 @@ "include/grpc/impl/codegen/propagation_bits.h", "include/grpc/impl/codegen/status.h", "include/grpc/status.h", - "src/core/census/aggregation.h", - "src/core/census/grpc_filter.h", - "src/core/census/grpc_plugin.h", - "src/core/census/mlog.h", - "src/core/census/rpc_metric_id.h", - "src/core/channel/channel_args.h", - "src/core/channel/channel_stack.h", - "src/core/channel/channel_stack_builder.h", - "src/core/channel/client_channel.h", - "src/core/channel/compress_filter.h", - "src/core/channel/connected_channel.h", - "src/core/channel/context.h", - "src/core/channel/http_client_filter.h", - "src/core/channel/http_server_filter.h", - "src/core/channel/subchannel_call_holder.h", - "src/core/client_config/client_config.h", - "src/core/client_config/connector.h", - "src/core/client_config/initial_connect_string.h", - "src/core/client_config/lb_policies/load_balancer_api.h", - "src/core/client_config/lb_policies/pick_first.h", - "src/core/client_config/lb_policies/round_robin.h", - "src/core/client_config/lb_policy.h", - "src/core/client_config/lb_policy_factory.h", - "src/core/client_config/lb_policy_registry.h", - "src/core/client_config/resolver.h", - "src/core/client_config/resolver_factory.h", - "src/core/client_config/resolver_registry.h", - "src/core/client_config/resolvers/dns_resolver.h", - "src/core/client_config/resolvers/sockaddr_resolver.h", - "src/core/client_config/subchannel.h", - "src/core/client_config/subchannel_factory.h", - "src/core/client_config/subchannel_index.h", - "src/core/client_config/uri_parser.h", - "src/core/compression/algorithm_metadata.h", - "src/core/compression/message_compress.h", - "src/core/debug/trace.h", - "src/core/http/format_request.h", - "src/core/http/httpcli.h", - "src/core/http/parser.h", - "src/core/iomgr/closure.h", - "src/core/iomgr/endpoint.h", - "src/core/iomgr/endpoint_pair.h", - "src/core/iomgr/exec_ctx.h", - "src/core/iomgr/executor.h", - "src/core/iomgr/fd_posix.h", - "src/core/iomgr/iocp_windows.h", - "src/core/iomgr/iomgr.h", - "src/core/iomgr/iomgr_internal.h", - "src/core/iomgr/iomgr_posix.h", - "src/core/iomgr/pollset.h", - "src/core/iomgr/pollset_posix.h", - "src/core/iomgr/pollset_set.h", - "src/core/iomgr/pollset_set_posix.h", - "src/core/iomgr/pollset_set_windows.h", - "src/core/iomgr/pollset_windows.h", - "src/core/iomgr/resolve_address.h", - "src/core/iomgr/sockaddr.h", - "src/core/iomgr/sockaddr_posix.h", - "src/core/iomgr/sockaddr_utils.h", - "src/core/iomgr/sockaddr_win32.h", - "src/core/iomgr/socket_utils_posix.h", - "src/core/iomgr/socket_windows.h", - "src/core/iomgr/tcp_client.h", - "src/core/iomgr/tcp_posix.h", - "src/core/iomgr/tcp_server.h", - "src/core/iomgr/tcp_windows.h", - "src/core/iomgr/time_averaged_stats.h", - "src/core/iomgr/timer.h", - "src/core/iomgr/timer_heap.h", - "src/core/iomgr/udp_server.h", - "src/core/iomgr/unix_sockets_posix.h", - "src/core/iomgr/wakeup_fd_pipe.h", - "src/core/iomgr/wakeup_fd_posix.h", - "src/core/iomgr/workqueue.h", - "src/core/iomgr/workqueue_posix.h", - "src/core/iomgr/workqueue_windows.h", - "src/core/json/json.h", - "src/core/json/json_common.h", - "src/core/json/json_reader.h", - "src/core/json/json_writer.h", - "src/core/proto/grpc/lb/v0/load_balancer.pb.h", - "src/core/statistics/census_interface.h", - "src/core/statistics/census_rpc_stats.h", - "src/core/surface/api_trace.h", - "src/core/surface/call.h", - "src/core/surface/call_test_only.h", - "src/core/surface/channel.h", - "src/core/surface/channel_init.h", - "src/core/surface/channel_stack_type.h", - "src/core/surface/completion_queue.h", - "src/core/surface/event_string.h", - "src/core/surface/init.h", - "src/core/surface/lame_client.h", - "src/core/surface/server.h", - "src/core/surface/surface_trace.h", - "src/core/transport/byte_stream.h", - "src/core/transport/chttp2/alpn.h", - "src/core/transport/chttp2/bin_encoder.h", - "src/core/transport/chttp2/frame.h", - "src/core/transport/chttp2/frame_data.h", - "src/core/transport/chttp2/frame_goaway.h", - "src/core/transport/chttp2/frame_ping.h", - "src/core/transport/chttp2/frame_rst_stream.h", - "src/core/transport/chttp2/frame_settings.h", - "src/core/transport/chttp2/frame_window_update.h", - "src/core/transport/chttp2/hpack_encoder.h", - "src/core/transport/chttp2/hpack_parser.h", - "src/core/transport/chttp2/hpack_table.h", - "src/core/transport/chttp2/http2_errors.h", - "src/core/transport/chttp2/huffsyms.h", - "src/core/transport/chttp2/incoming_metadata.h", - "src/core/transport/chttp2/internal.h", - "src/core/transport/chttp2/status_conversion.h", - "src/core/transport/chttp2/stream_map.h", - "src/core/transport/chttp2/timeout_encoding.h", - "src/core/transport/chttp2/varint.h", - "src/core/transport/chttp2_transport.h", - "src/core/transport/connectivity_state.h", - "src/core/transport/metadata.h", - "src/core/transport/metadata_batch.h", - "src/core/transport/static_metadata.h", - "src/core/transport/transport.h", - "src/core/transport/transport_impl.h", + "src/core/lib/census/aggregation.h", + "src/core/lib/census/grpc_filter.h", + "src/core/lib/census/grpc_plugin.h", + "src/core/lib/census/mlog.h", + "src/core/lib/census/rpc_metric_id.h", + "src/core/lib/channel/channel_args.h", + "src/core/lib/channel/channel_stack.h", + "src/core/lib/channel/channel_stack_builder.h", + "src/core/lib/channel/client_channel.h", + "src/core/lib/channel/compress_filter.h", + "src/core/lib/channel/connected_channel.h", + "src/core/lib/channel/context.h", + "src/core/lib/channel/http_client_filter.h", + "src/core/lib/channel/http_server_filter.h", + "src/core/lib/channel/subchannel_call_holder.h", + "src/core/lib/client_config/client_config.h", + "src/core/lib/client_config/connector.h", + "src/core/lib/client_config/initial_connect_string.h", + "src/core/lib/client_config/lb_policies/load_balancer_api.h", + "src/core/lib/client_config/lb_policies/pick_first.h", + "src/core/lib/client_config/lb_policies/round_robin.h", + "src/core/lib/client_config/lb_policy.h", + "src/core/lib/client_config/lb_policy_factory.h", + "src/core/lib/client_config/lb_policy_registry.h", + "src/core/lib/client_config/resolver.h", + "src/core/lib/client_config/resolver_factory.h", + "src/core/lib/client_config/resolver_registry.h", + "src/core/lib/client_config/resolvers/dns_resolver.h", + "src/core/lib/client_config/resolvers/sockaddr_resolver.h", + "src/core/lib/client_config/subchannel.h", + "src/core/lib/client_config/subchannel_factory.h", + "src/core/lib/client_config/subchannel_index.h", + "src/core/lib/client_config/uri_parser.h", + "src/core/lib/compression/algorithm_metadata.h", + "src/core/lib/compression/message_compress.h", + "src/core/lib/debug/trace.h", + "src/core/lib/http/format_request.h", + "src/core/lib/http/httpcli.h", + "src/core/lib/http/parser.h", + "src/core/lib/iomgr/closure.h", + "src/core/lib/iomgr/endpoint.h", + "src/core/lib/iomgr/endpoint_pair.h", + "src/core/lib/iomgr/exec_ctx.h", + "src/core/lib/iomgr/executor.h", + "src/core/lib/iomgr/fd_posix.h", + "src/core/lib/iomgr/iocp_windows.h", + "src/core/lib/iomgr/iomgr.h", + "src/core/lib/iomgr/iomgr_internal.h", + "src/core/lib/iomgr/iomgr_posix.h", + "src/core/lib/iomgr/pollset.h", + "src/core/lib/iomgr/pollset_posix.h", + "src/core/lib/iomgr/pollset_set.h", + "src/core/lib/iomgr/pollset_set_posix.h", + "src/core/lib/iomgr/pollset_set_windows.h", + "src/core/lib/iomgr/pollset_windows.h", + "src/core/lib/iomgr/resolve_address.h", + "src/core/lib/iomgr/sockaddr.h", + "src/core/lib/iomgr/sockaddr_posix.h", + "src/core/lib/iomgr/sockaddr_utils.h", + "src/core/lib/iomgr/sockaddr_win32.h", + "src/core/lib/iomgr/socket_utils_posix.h", + "src/core/lib/iomgr/socket_windows.h", + "src/core/lib/iomgr/tcp_client.h", + "src/core/lib/iomgr/tcp_posix.h", + "src/core/lib/iomgr/tcp_server.h", + "src/core/lib/iomgr/tcp_windows.h", + "src/core/lib/iomgr/time_averaged_stats.h", + "src/core/lib/iomgr/timer.h", + "src/core/lib/iomgr/timer_heap.h", + "src/core/lib/iomgr/udp_server.h", + "src/core/lib/iomgr/unix_sockets_posix.h", + "src/core/lib/iomgr/wakeup_fd_pipe.h", + "src/core/lib/iomgr/wakeup_fd_posix.h", + "src/core/lib/iomgr/workqueue.h", + "src/core/lib/iomgr/workqueue_posix.h", + "src/core/lib/iomgr/workqueue_windows.h", + "src/core/lib/json/json.h", + "src/core/lib/json/json_common.h", + "src/core/lib/json/json_reader.h", + "src/core/lib/json/json_writer.h", + "src/core/lib/proto/grpc/lb/v0/load_balancer.pb.h", + "src/core/lib/statistics/census_interface.h", + "src/core/lib/statistics/census_rpc_stats.h", + "src/core/lib/surface/api_trace.h", + "src/core/lib/surface/call.h", + "src/core/lib/surface/call_test_only.h", + "src/core/lib/surface/channel.h", + "src/core/lib/surface/channel_init.h", + "src/core/lib/surface/channel_stack_type.h", + "src/core/lib/surface/completion_queue.h", + "src/core/lib/surface/event_string.h", + "src/core/lib/surface/init.h", + "src/core/lib/surface/lame_client.h", + "src/core/lib/surface/server.h", + "src/core/lib/surface/surface_trace.h", + "src/core/lib/transport/byte_stream.h", + "src/core/lib/transport/chttp2/alpn.h", + "src/core/lib/transport/chttp2/bin_encoder.h", + "src/core/lib/transport/chttp2/frame.h", + "src/core/lib/transport/chttp2/frame_data.h", + "src/core/lib/transport/chttp2/frame_goaway.h", + "src/core/lib/transport/chttp2/frame_ping.h", + "src/core/lib/transport/chttp2/frame_rst_stream.h", + "src/core/lib/transport/chttp2/frame_settings.h", + "src/core/lib/transport/chttp2/frame_window_update.h", + "src/core/lib/transport/chttp2/hpack_encoder.h", + "src/core/lib/transport/chttp2/hpack_parser.h", + "src/core/lib/transport/chttp2/hpack_table.h", + "src/core/lib/transport/chttp2/http2_errors.h", + "src/core/lib/transport/chttp2/huffsyms.h", + "src/core/lib/transport/chttp2/incoming_metadata.h", + "src/core/lib/transport/chttp2/internal.h", + "src/core/lib/transport/chttp2/status_conversion.h", + "src/core/lib/transport/chttp2/stream_map.h", + "src/core/lib/transport/chttp2/timeout_encoding.h", + "src/core/lib/transport/chttp2/varint.h", + "src/core/lib/transport/chttp2_transport.h", + "src/core/lib/transport/connectivity_state.h", + "src/core/lib/transport/metadata.h", + "src/core/lib/transport/metadata_batch.h", + "src/core/lib/transport/static_metadata.h", + "src/core/lib/transport/transport.h", + "src/core/lib/transport/transport_impl.h", "third_party/nanopb/pb.h", "third_party/nanopb/pb_common.h", "third_party/nanopb/pb_decode.h", @@ -4695,270 +4695,270 @@ "include/grpc/impl/codegen/propagation_bits.h", "include/grpc/impl/codegen/status.h", "include/grpc/status.h", - "src/core/census/aggregation.h", - "src/core/census/context.c", - "src/core/census/grpc_context.c", - "src/core/census/grpc_filter.c", - "src/core/census/grpc_filter.h", - "src/core/census/grpc_plugin.c", - "src/core/census/grpc_plugin.h", - "src/core/census/initialize.c", - "src/core/census/mlog.c", - "src/core/census/mlog.h", - "src/core/census/operation.c", - "src/core/census/placeholders.c", - "src/core/census/rpc_metric_id.h", - "src/core/census/tracing.c", - "src/core/channel/channel_args.c", - "src/core/channel/channel_args.h", - "src/core/channel/channel_stack.c", - "src/core/channel/channel_stack.h", - "src/core/channel/channel_stack_builder.c", - "src/core/channel/channel_stack_builder.h", - "src/core/channel/client_channel.c", - "src/core/channel/client_channel.h", - "src/core/channel/compress_filter.c", - "src/core/channel/compress_filter.h", - "src/core/channel/connected_channel.c", - "src/core/channel/connected_channel.h", - "src/core/channel/context.h", - "src/core/channel/http_client_filter.c", - "src/core/channel/http_client_filter.h", - "src/core/channel/http_server_filter.c", - "src/core/channel/http_server_filter.h", - "src/core/channel/subchannel_call_holder.c", - "src/core/channel/subchannel_call_holder.h", - "src/core/client_config/client_config.c", - "src/core/client_config/client_config.h", - "src/core/client_config/connector.c", - "src/core/client_config/connector.h", - "src/core/client_config/default_initial_connect_string.c", - "src/core/client_config/initial_connect_string.c", - "src/core/client_config/initial_connect_string.h", - "src/core/client_config/lb_policies/load_balancer_api.c", - "src/core/client_config/lb_policies/load_balancer_api.h", - "src/core/client_config/lb_policies/pick_first.c", - "src/core/client_config/lb_policies/pick_first.h", - "src/core/client_config/lb_policies/round_robin.c", - "src/core/client_config/lb_policies/round_robin.h", - "src/core/client_config/lb_policy.c", - "src/core/client_config/lb_policy.h", - "src/core/client_config/lb_policy_factory.c", - "src/core/client_config/lb_policy_factory.h", - "src/core/client_config/lb_policy_registry.c", - "src/core/client_config/lb_policy_registry.h", - "src/core/client_config/resolver.c", - "src/core/client_config/resolver.h", - "src/core/client_config/resolver_factory.c", - "src/core/client_config/resolver_factory.h", - "src/core/client_config/resolver_registry.c", - "src/core/client_config/resolver_registry.h", - "src/core/client_config/resolvers/dns_resolver.c", - "src/core/client_config/resolvers/dns_resolver.h", - "src/core/client_config/resolvers/sockaddr_resolver.c", - "src/core/client_config/resolvers/sockaddr_resolver.h", - "src/core/client_config/subchannel.c", - "src/core/client_config/subchannel.h", - "src/core/client_config/subchannel_factory.c", - "src/core/client_config/subchannel_factory.h", - "src/core/client_config/subchannel_index.c", - "src/core/client_config/subchannel_index.h", - "src/core/client_config/uri_parser.c", - "src/core/client_config/uri_parser.h", - "src/core/compression/algorithm_metadata.h", - "src/core/compression/compression_algorithm.c", - "src/core/compression/message_compress.c", - "src/core/compression/message_compress.h", - "src/core/debug/trace.c", - "src/core/debug/trace.h", - "src/core/http/format_request.c", - "src/core/http/format_request.h", - "src/core/http/httpcli.c", - "src/core/http/httpcli.h", - "src/core/http/parser.c", - "src/core/http/parser.h", - "src/core/iomgr/closure.c", - "src/core/iomgr/closure.h", - "src/core/iomgr/endpoint.c", - "src/core/iomgr/endpoint.h", - "src/core/iomgr/endpoint_pair.h", - "src/core/iomgr/endpoint_pair_posix.c", - "src/core/iomgr/endpoint_pair_windows.c", - "src/core/iomgr/exec_ctx.c", - "src/core/iomgr/exec_ctx.h", - "src/core/iomgr/executor.c", - "src/core/iomgr/executor.h", - "src/core/iomgr/fd_posix.c", - "src/core/iomgr/fd_posix.h", - "src/core/iomgr/iocp_windows.c", - "src/core/iomgr/iocp_windows.h", - "src/core/iomgr/iomgr.c", - "src/core/iomgr/iomgr.h", - "src/core/iomgr/iomgr_internal.h", - "src/core/iomgr/iomgr_posix.c", - "src/core/iomgr/iomgr_posix.h", - "src/core/iomgr/iomgr_windows.c", - "src/core/iomgr/pollset.h", - "src/core/iomgr/pollset_multipoller_with_epoll.c", - "src/core/iomgr/pollset_multipoller_with_poll_posix.c", - "src/core/iomgr/pollset_posix.c", - "src/core/iomgr/pollset_posix.h", - "src/core/iomgr/pollset_set.h", - "src/core/iomgr/pollset_set_posix.c", - "src/core/iomgr/pollset_set_posix.h", - "src/core/iomgr/pollset_set_windows.c", - "src/core/iomgr/pollset_set_windows.h", - "src/core/iomgr/pollset_windows.c", - "src/core/iomgr/pollset_windows.h", - "src/core/iomgr/resolve_address.h", - "src/core/iomgr/resolve_address_posix.c", - "src/core/iomgr/resolve_address_windows.c", - "src/core/iomgr/sockaddr.h", - "src/core/iomgr/sockaddr_posix.h", - "src/core/iomgr/sockaddr_utils.c", - "src/core/iomgr/sockaddr_utils.h", - "src/core/iomgr/sockaddr_win32.h", - "src/core/iomgr/socket_utils_common_posix.c", - "src/core/iomgr/socket_utils_linux.c", - "src/core/iomgr/socket_utils_posix.c", - "src/core/iomgr/socket_utils_posix.h", - "src/core/iomgr/socket_windows.c", - "src/core/iomgr/socket_windows.h", - "src/core/iomgr/tcp_client.h", - "src/core/iomgr/tcp_client_posix.c", - "src/core/iomgr/tcp_client_windows.c", - "src/core/iomgr/tcp_posix.c", - "src/core/iomgr/tcp_posix.h", - "src/core/iomgr/tcp_server.h", - "src/core/iomgr/tcp_server_posix.c", - "src/core/iomgr/tcp_server_windows.c", - "src/core/iomgr/tcp_windows.c", - "src/core/iomgr/tcp_windows.h", - "src/core/iomgr/time_averaged_stats.c", - "src/core/iomgr/time_averaged_stats.h", - "src/core/iomgr/timer.c", - "src/core/iomgr/timer.h", - "src/core/iomgr/timer_heap.c", - "src/core/iomgr/timer_heap.h", - "src/core/iomgr/udp_server.c", - "src/core/iomgr/udp_server.h", - "src/core/iomgr/unix_sockets_posix.c", - "src/core/iomgr/unix_sockets_posix.h", - "src/core/iomgr/unix_sockets_posix_noop.c", - "src/core/iomgr/wakeup_fd_eventfd.c", - "src/core/iomgr/wakeup_fd_nospecial.c", - "src/core/iomgr/wakeup_fd_pipe.c", - "src/core/iomgr/wakeup_fd_pipe.h", - "src/core/iomgr/wakeup_fd_posix.c", - "src/core/iomgr/wakeup_fd_posix.h", - "src/core/iomgr/workqueue.h", - "src/core/iomgr/workqueue_posix.c", - "src/core/iomgr/workqueue_posix.h", - "src/core/iomgr/workqueue_windows.c", - "src/core/iomgr/workqueue_windows.h", - "src/core/json/json.c", - "src/core/json/json.h", - "src/core/json/json_common.h", - "src/core/json/json_reader.c", - "src/core/json/json_reader.h", - "src/core/json/json_string.c", - "src/core/json/json_writer.c", - "src/core/json/json_writer.h", - "src/core/proto/grpc/lb/v0/load_balancer.pb.c", - "src/core/proto/grpc/lb/v0/load_balancer.pb.h", - "src/core/statistics/census_interface.h", - "src/core/statistics/census_rpc_stats.h", - "src/core/surface/alarm.c", - "src/core/surface/api_trace.c", - "src/core/surface/api_trace.h", - "src/core/surface/byte_buffer.c", - "src/core/surface/byte_buffer_reader.c", - "src/core/surface/call.c", - "src/core/surface/call.h", - "src/core/surface/call_details.c", - "src/core/surface/call_log_batch.c", - "src/core/surface/call_test_only.h", - "src/core/surface/channel.c", - "src/core/surface/channel.h", - "src/core/surface/channel_connectivity.c", - "src/core/surface/channel_create.c", - "src/core/surface/channel_init.c", - "src/core/surface/channel_init.h", - "src/core/surface/channel_ping.c", - "src/core/surface/channel_stack_type.c", - "src/core/surface/channel_stack_type.h", - "src/core/surface/completion_queue.c", - "src/core/surface/completion_queue.h", - "src/core/surface/event_string.c", - "src/core/surface/event_string.h", - "src/core/surface/init.c", - "src/core/surface/init.h", - "src/core/surface/init_unsecure.c", - "src/core/surface/lame_client.c", - "src/core/surface/lame_client.h", - "src/core/surface/metadata_array.c", - "src/core/surface/server.c", - "src/core/surface/server.h", - "src/core/surface/server_chttp2.c", - "src/core/surface/surface_trace.h", - "src/core/surface/validate_metadata.c", - "src/core/surface/version.c", - "src/core/transport/byte_stream.c", - "src/core/transport/byte_stream.h", - "src/core/transport/chttp2/alpn.c", - "src/core/transport/chttp2/alpn.h", - "src/core/transport/chttp2/bin_encoder.c", - "src/core/transport/chttp2/bin_encoder.h", - "src/core/transport/chttp2/frame.h", - "src/core/transport/chttp2/frame_data.c", - "src/core/transport/chttp2/frame_data.h", - "src/core/transport/chttp2/frame_goaway.c", - "src/core/transport/chttp2/frame_goaway.h", - "src/core/transport/chttp2/frame_ping.c", - "src/core/transport/chttp2/frame_ping.h", - "src/core/transport/chttp2/frame_rst_stream.c", - "src/core/transport/chttp2/frame_rst_stream.h", - "src/core/transport/chttp2/frame_settings.c", - "src/core/transport/chttp2/frame_settings.h", - "src/core/transport/chttp2/frame_window_update.c", - "src/core/transport/chttp2/frame_window_update.h", - "src/core/transport/chttp2/hpack_encoder.c", - "src/core/transport/chttp2/hpack_encoder.h", - "src/core/transport/chttp2/hpack_parser.c", - "src/core/transport/chttp2/hpack_parser.h", - "src/core/transport/chttp2/hpack_table.c", - "src/core/transport/chttp2/hpack_table.h", - "src/core/transport/chttp2/http2_errors.h", - "src/core/transport/chttp2/huffsyms.c", - "src/core/transport/chttp2/huffsyms.h", - "src/core/transport/chttp2/incoming_metadata.c", - "src/core/transport/chttp2/incoming_metadata.h", - "src/core/transport/chttp2/internal.h", - "src/core/transport/chttp2/parsing.c", - "src/core/transport/chttp2/status_conversion.c", - "src/core/transport/chttp2/status_conversion.h", - "src/core/transport/chttp2/stream_lists.c", - "src/core/transport/chttp2/stream_map.c", - "src/core/transport/chttp2/stream_map.h", - "src/core/transport/chttp2/timeout_encoding.c", - "src/core/transport/chttp2/timeout_encoding.h", - "src/core/transport/chttp2/varint.c", - "src/core/transport/chttp2/varint.h", - "src/core/transport/chttp2/writing.c", - "src/core/transport/chttp2_transport.c", - "src/core/transport/chttp2_transport.h", - "src/core/transport/connectivity_state.c", - "src/core/transport/connectivity_state.h", - "src/core/transport/metadata.c", - "src/core/transport/metadata.h", - "src/core/transport/metadata_batch.c", - "src/core/transport/metadata_batch.h", - "src/core/transport/static_metadata.c", - "src/core/transport/static_metadata.h", - "src/core/transport/transport.c", - "src/core/transport/transport.h", - "src/core/transport/transport_impl.h", - "src/core/transport/transport_op_string.c" + "src/core/lib/census/aggregation.h", + "src/core/lib/census/context.c", + "src/core/lib/census/grpc_context.c", + "src/core/lib/census/grpc_filter.c", + "src/core/lib/census/grpc_filter.h", + "src/core/lib/census/grpc_plugin.c", + "src/core/lib/census/grpc_plugin.h", + "src/core/lib/census/initialize.c", + "src/core/lib/census/mlog.c", + "src/core/lib/census/mlog.h", + "src/core/lib/census/operation.c", + "src/core/lib/census/placeholders.c", + "src/core/lib/census/rpc_metric_id.h", + "src/core/lib/census/tracing.c", + "src/core/lib/channel/channel_args.c", + "src/core/lib/channel/channel_args.h", + "src/core/lib/channel/channel_stack.c", + "src/core/lib/channel/channel_stack.h", + "src/core/lib/channel/channel_stack_builder.c", + "src/core/lib/channel/channel_stack_builder.h", + "src/core/lib/channel/client_channel.c", + "src/core/lib/channel/client_channel.h", + "src/core/lib/channel/compress_filter.c", + "src/core/lib/channel/compress_filter.h", + "src/core/lib/channel/connected_channel.c", + "src/core/lib/channel/connected_channel.h", + "src/core/lib/channel/context.h", + "src/core/lib/channel/http_client_filter.c", + "src/core/lib/channel/http_client_filter.h", + "src/core/lib/channel/http_server_filter.c", + "src/core/lib/channel/http_server_filter.h", + "src/core/lib/channel/subchannel_call_holder.c", + "src/core/lib/channel/subchannel_call_holder.h", + "src/core/lib/client_config/client_config.c", + "src/core/lib/client_config/client_config.h", + "src/core/lib/client_config/connector.c", + "src/core/lib/client_config/connector.h", + "src/core/lib/client_config/default_initial_connect_string.c", + "src/core/lib/client_config/initial_connect_string.c", + "src/core/lib/client_config/initial_connect_string.h", + "src/core/lib/client_config/lb_policies/load_balancer_api.c", + "src/core/lib/client_config/lb_policies/load_balancer_api.h", + "src/core/lib/client_config/lb_policies/pick_first.c", + "src/core/lib/client_config/lb_policies/pick_first.h", + "src/core/lib/client_config/lb_policies/round_robin.c", + "src/core/lib/client_config/lb_policies/round_robin.h", + "src/core/lib/client_config/lb_policy.c", + "src/core/lib/client_config/lb_policy.h", + "src/core/lib/client_config/lb_policy_factory.c", + "src/core/lib/client_config/lb_policy_factory.h", + "src/core/lib/client_config/lb_policy_registry.c", + "src/core/lib/client_config/lb_policy_registry.h", + "src/core/lib/client_config/resolver.c", + "src/core/lib/client_config/resolver.h", + "src/core/lib/client_config/resolver_factory.c", + "src/core/lib/client_config/resolver_factory.h", + "src/core/lib/client_config/resolver_registry.c", + "src/core/lib/client_config/resolver_registry.h", + "src/core/lib/client_config/resolvers/dns_resolver.c", + "src/core/lib/client_config/resolvers/dns_resolver.h", + "src/core/lib/client_config/resolvers/sockaddr_resolver.c", + "src/core/lib/client_config/resolvers/sockaddr_resolver.h", + "src/core/lib/client_config/subchannel.c", + "src/core/lib/client_config/subchannel.h", + "src/core/lib/client_config/subchannel_factory.c", + "src/core/lib/client_config/subchannel_factory.h", + "src/core/lib/client_config/subchannel_index.c", + "src/core/lib/client_config/subchannel_index.h", + "src/core/lib/client_config/uri_parser.c", + "src/core/lib/client_config/uri_parser.h", + "src/core/lib/compression/algorithm_metadata.h", + "src/core/lib/compression/compression_algorithm.c", + "src/core/lib/compression/message_compress.c", + "src/core/lib/compression/message_compress.h", + "src/core/lib/debug/trace.c", + "src/core/lib/debug/trace.h", + "src/core/lib/http/format_request.c", + "src/core/lib/http/format_request.h", + "src/core/lib/http/httpcli.c", + "src/core/lib/http/httpcli.h", + "src/core/lib/http/parser.c", + "src/core/lib/http/parser.h", + "src/core/lib/iomgr/closure.c", + "src/core/lib/iomgr/closure.h", + "src/core/lib/iomgr/endpoint.c", + "src/core/lib/iomgr/endpoint.h", + "src/core/lib/iomgr/endpoint_pair.h", + "src/core/lib/iomgr/endpoint_pair_posix.c", + "src/core/lib/iomgr/endpoint_pair_windows.c", + "src/core/lib/iomgr/exec_ctx.c", + "src/core/lib/iomgr/exec_ctx.h", + "src/core/lib/iomgr/executor.c", + "src/core/lib/iomgr/executor.h", + "src/core/lib/iomgr/fd_posix.c", + "src/core/lib/iomgr/fd_posix.h", + "src/core/lib/iomgr/iocp_windows.c", + "src/core/lib/iomgr/iocp_windows.h", + "src/core/lib/iomgr/iomgr.c", + "src/core/lib/iomgr/iomgr.h", + "src/core/lib/iomgr/iomgr_internal.h", + "src/core/lib/iomgr/iomgr_posix.c", + "src/core/lib/iomgr/iomgr_posix.h", + "src/core/lib/iomgr/iomgr_windows.c", + "src/core/lib/iomgr/pollset.h", + "src/core/lib/iomgr/pollset_multipoller_with_epoll.c", + "src/core/lib/iomgr/pollset_multipoller_with_poll_posix.c", + "src/core/lib/iomgr/pollset_posix.c", + "src/core/lib/iomgr/pollset_posix.h", + "src/core/lib/iomgr/pollset_set.h", + "src/core/lib/iomgr/pollset_set_posix.c", + "src/core/lib/iomgr/pollset_set_posix.h", + "src/core/lib/iomgr/pollset_set_windows.c", + "src/core/lib/iomgr/pollset_set_windows.h", + "src/core/lib/iomgr/pollset_windows.c", + "src/core/lib/iomgr/pollset_windows.h", + "src/core/lib/iomgr/resolve_address.h", + "src/core/lib/iomgr/resolve_address_posix.c", + "src/core/lib/iomgr/resolve_address_windows.c", + "src/core/lib/iomgr/sockaddr.h", + "src/core/lib/iomgr/sockaddr_posix.h", + "src/core/lib/iomgr/sockaddr_utils.c", + "src/core/lib/iomgr/sockaddr_utils.h", + "src/core/lib/iomgr/sockaddr_win32.h", + "src/core/lib/iomgr/socket_utils_common_posix.c", + "src/core/lib/iomgr/socket_utils_linux.c", + "src/core/lib/iomgr/socket_utils_posix.c", + "src/core/lib/iomgr/socket_utils_posix.h", + "src/core/lib/iomgr/socket_windows.c", + "src/core/lib/iomgr/socket_windows.h", + "src/core/lib/iomgr/tcp_client.h", + "src/core/lib/iomgr/tcp_client_posix.c", + "src/core/lib/iomgr/tcp_client_windows.c", + "src/core/lib/iomgr/tcp_posix.c", + "src/core/lib/iomgr/tcp_posix.h", + "src/core/lib/iomgr/tcp_server.h", + "src/core/lib/iomgr/tcp_server_posix.c", + "src/core/lib/iomgr/tcp_server_windows.c", + "src/core/lib/iomgr/tcp_windows.c", + "src/core/lib/iomgr/tcp_windows.h", + "src/core/lib/iomgr/time_averaged_stats.c", + "src/core/lib/iomgr/time_averaged_stats.h", + "src/core/lib/iomgr/timer.c", + "src/core/lib/iomgr/timer.h", + "src/core/lib/iomgr/timer_heap.c", + "src/core/lib/iomgr/timer_heap.h", + "src/core/lib/iomgr/udp_server.c", + "src/core/lib/iomgr/udp_server.h", + "src/core/lib/iomgr/unix_sockets_posix.c", + "src/core/lib/iomgr/unix_sockets_posix.h", + "src/core/lib/iomgr/unix_sockets_posix_noop.c", + "src/core/lib/iomgr/wakeup_fd_eventfd.c", + "src/core/lib/iomgr/wakeup_fd_nospecial.c", + "src/core/lib/iomgr/wakeup_fd_pipe.c", + "src/core/lib/iomgr/wakeup_fd_pipe.h", + "src/core/lib/iomgr/wakeup_fd_posix.c", + "src/core/lib/iomgr/wakeup_fd_posix.h", + "src/core/lib/iomgr/workqueue.h", + "src/core/lib/iomgr/workqueue_posix.c", + "src/core/lib/iomgr/workqueue_posix.h", + "src/core/lib/iomgr/workqueue_windows.c", + "src/core/lib/iomgr/workqueue_windows.h", + "src/core/lib/json/json.c", + "src/core/lib/json/json.h", + "src/core/lib/json/json_common.h", + "src/core/lib/json/json_reader.c", + "src/core/lib/json/json_reader.h", + "src/core/lib/json/json_string.c", + "src/core/lib/json/json_writer.c", + "src/core/lib/json/json_writer.h", + "src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c", + "src/core/lib/proto/grpc/lb/v0/load_balancer.pb.h", + "src/core/lib/statistics/census_interface.h", + "src/core/lib/statistics/census_rpc_stats.h", + "src/core/lib/surface/alarm.c", + "src/core/lib/surface/api_trace.c", + "src/core/lib/surface/api_trace.h", + "src/core/lib/surface/byte_buffer.c", + "src/core/lib/surface/byte_buffer_reader.c", + "src/core/lib/surface/call.c", + "src/core/lib/surface/call.h", + "src/core/lib/surface/call_details.c", + "src/core/lib/surface/call_log_batch.c", + "src/core/lib/surface/call_test_only.h", + "src/core/lib/surface/channel.c", + "src/core/lib/surface/channel.h", + "src/core/lib/surface/channel_connectivity.c", + "src/core/lib/surface/channel_create.c", + "src/core/lib/surface/channel_init.c", + "src/core/lib/surface/channel_init.h", + "src/core/lib/surface/channel_ping.c", + "src/core/lib/surface/channel_stack_type.c", + "src/core/lib/surface/channel_stack_type.h", + "src/core/lib/surface/completion_queue.c", + "src/core/lib/surface/completion_queue.h", + "src/core/lib/surface/event_string.c", + "src/core/lib/surface/event_string.h", + "src/core/lib/surface/init.c", + "src/core/lib/surface/init.h", + "src/core/lib/surface/init_unsecure.c", + "src/core/lib/surface/lame_client.c", + "src/core/lib/surface/lame_client.h", + "src/core/lib/surface/metadata_array.c", + "src/core/lib/surface/server.c", + "src/core/lib/surface/server.h", + "src/core/lib/surface/server_chttp2.c", + "src/core/lib/surface/surface_trace.h", + "src/core/lib/surface/validate_metadata.c", + "src/core/lib/surface/version.c", + "src/core/lib/transport/byte_stream.c", + "src/core/lib/transport/byte_stream.h", + "src/core/lib/transport/chttp2/alpn.c", + "src/core/lib/transport/chttp2/alpn.h", + "src/core/lib/transport/chttp2/bin_encoder.c", + "src/core/lib/transport/chttp2/bin_encoder.h", + "src/core/lib/transport/chttp2/frame.h", + "src/core/lib/transport/chttp2/frame_data.c", + "src/core/lib/transport/chttp2/frame_data.h", + "src/core/lib/transport/chttp2/frame_goaway.c", + "src/core/lib/transport/chttp2/frame_goaway.h", + "src/core/lib/transport/chttp2/frame_ping.c", + "src/core/lib/transport/chttp2/frame_ping.h", + "src/core/lib/transport/chttp2/frame_rst_stream.c", + "src/core/lib/transport/chttp2/frame_rst_stream.h", + "src/core/lib/transport/chttp2/frame_settings.c", + "src/core/lib/transport/chttp2/frame_settings.h", + "src/core/lib/transport/chttp2/frame_window_update.c", + "src/core/lib/transport/chttp2/frame_window_update.h", + "src/core/lib/transport/chttp2/hpack_encoder.c", + "src/core/lib/transport/chttp2/hpack_encoder.h", + "src/core/lib/transport/chttp2/hpack_parser.c", + "src/core/lib/transport/chttp2/hpack_parser.h", + "src/core/lib/transport/chttp2/hpack_table.c", + "src/core/lib/transport/chttp2/hpack_table.h", + "src/core/lib/transport/chttp2/http2_errors.h", + "src/core/lib/transport/chttp2/huffsyms.c", + "src/core/lib/transport/chttp2/huffsyms.h", + "src/core/lib/transport/chttp2/incoming_metadata.c", + "src/core/lib/transport/chttp2/incoming_metadata.h", + "src/core/lib/transport/chttp2/internal.h", + "src/core/lib/transport/chttp2/parsing.c", + "src/core/lib/transport/chttp2/status_conversion.c", + "src/core/lib/transport/chttp2/status_conversion.h", + "src/core/lib/transport/chttp2/stream_lists.c", + "src/core/lib/transport/chttp2/stream_map.c", + "src/core/lib/transport/chttp2/stream_map.h", + "src/core/lib/transport/chttp2/timeout_encoding.c", + "src/core/lib/transport/chttp2/timeout_encoding.h", + "src/core/lib/transport/chttp2/varint.c", + "src/core/lib/transport/chttp2/varint.h", + "src/core/lib/transport/chttp2/writing.c", + "src/core/lib/transport/chttp2_transport.c", + "src/core/lib/transport/chttp2_transport.h", + "src/core/lib/transport/connectivity_state.c", + "src/core/lib/transport/connectivity_state.h", + "src/core/lib/transport/metadata.c", + "src/core/lib/transport/metadata.h", + "src/core/lib/transport/metadata_batch.c", + "src/core/lib/transport/metadata_batch.h", + "src/core/lib/transport/static_metadata.c", + "src/core/lib/transport/static_metadata.h", + "src/core/lib/transport/transport.c", + "src/core/lib/transport/transport.h", + "src/core/lib/transport/transport_impl.h", + "src/core/lib/transport/transport_op_string.c" ], "third_party": false, "type": "lib" @@ -4970,14 +4970,14 @@ ], "headers": [ "include/grpc/grpc_zookeeper.h", - "src/core/client_config/resolvers/zookeeper_resolver.h" + "src/core/lib/client_config/resolvers/zookeeper_resolver.h" ], "language": "c", "name": "grpc_zookeeper", "src": [ "include/grpc/grpc_zookeeper.h", - "src/core/client_config/resolvers/zookeeper_resolver.c", - "src/core/client_config/resolvers/zookeeper_resolver.h" + "src/core/lib/client_config/resolvers/zookeeper_resolver.c", + "src/core/lib/client_config/resolvers/zookeeper_resolver.h" ], "third_party": false, "type": "lib" diff --git a/vsprojects/vcxproj/gpr/gpr.vcxproj b/vsprojects/vcxproj/gpr/gpr.vcxproj index 9281fa3995..cdb128e48e 100644 --- a/vsprojects/vcxproj/gpr/gpr.vcxproj +++ b/vsprojects/vcxproj/gpr/gpr.vcxproj @@ -191,107 +191,107 @@ - - - - - - - - - - - - + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/vsprojects/vcxproj/gpr/gpr.vcxproj.filters b/vsprojects/vcxproj/gpr/gpr.vcxproj.filters index b85060f385..8af6fdd44c 100644 --- a/vsprojects/vcxproj/gpr/gpr.vcxproj.filters +++ b/vsprojects/vcxproj/gpr/gpr.vcxproj.filters @@ -1,137 +1,137 @@ - - src\core\profiling + + src\core\lib\profiling - - src\core\profiling + + src\core\lib\profiling - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support @@ -263,41 +263,41 @@ - - src\core\profiling + + src\core\lib\profiling - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support - - src\core\support + + src\core\lib\support @@ -323,11 +323,14 @@ {c5e1baa7-de77-beb1-9675-942261648f79} - - {93b7086c-8c8a-6bbf-fb14-1f166bf0146a} + + {52037bcb-5719-a548-224d-834fbe569045} - - {bb116f2a-ea2a-c233-82da-0c54e3cbfec1} + + {ba38d79d-d5de-a89e-9ca2-c5235a03ca7f} + + + {a4812158-7fba-959e-4e09-50167fe38df8} diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj index ebc3674360..b09abb28c4 100644 --- a/vsprojects/vcxproj/grpc/grpc.vcxproj +++ b/vsprojects/vcxproj/grpc/grpc.vcxproj @@ -282,470 +282,470 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters index e5bff0e4f3..81136ebb93 100644 --- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters +++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters @@ -1,488 +1,488 @@ - - src\core\census + + src\core\lib\census - - src\core\census + + src\core\lib\census - - src\core\census + + src\core\lib\census - - src\core\channel + + src\core\lib\channel - - src\core\channel + + src\core\lib\channel - - src\core\channel + + src\core\lib\channel - - src\core\channel + + src\core\lib\channel - - src\core\channel + + src\core\lib\channel - - src\core\channel + + src\core\lib\channel - - src\core\channel + + src\core\lib\channel - - src\core\channel + + src\core\lib\channel - - src\core\channel + + src\core\lib\channel - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config\lb_policies + + src\core\lib\client_config\lb_policies - - src\core\client_config\lb_policies + + src\core\lib\client_config\lb_policies - - src\core\client_config\lb_policies + + src\core\lib\client_config\lb_policies - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config\resolvers + + src\core\lib\client_config\resolvers - - src\core\client_config\resolvers + + src\core\lib\client_config\resolvers - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\compression + + src\core\lib\compression - - src\core\compression + + src\core\lib\compression - - src\core\debug + + src\core\lib\debug - - src\core\http + + src\core\lib\http - - src\core\http + + src\core\lib\http - - src\core\http + + src\core\lib\http - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\json + + src\core\lib\json - - src\core\json + + src\core\lib\json - - src\core\json + + src\core\lib\json - - src\core\json + + src\core\lib\json - - src\core\proto\grpc\lb\v0 + + src\core\lib\proto\grpc\lb\v0 - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\transport + + src\core\lib\transport - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport + + src\core\lib\transport - - src\core\transport + + src\core\lib\transport - - src\core\transport + + src\core\lib\transport - - src\core\transport + + src\core\lib\transport - - src\core\transport + + src\core\lib\transport - - src\core\transport + + src\core\lib\transport - - src\core\transport + + src\core\lib\transport - - src\core\http + + src\core\lib\http - - src\core\security + + src\core\lib\security - - src\core\security + + src\core\lib\security - - src\core\security + + src\core\lib\security - - src\core\security + + src\core\lib\security - - src\core\security + + src\core\lib\security - - src\core\security + + src\core\lib\security - - src\core\security + + src\core\lib\security - - src\core\security + + src\core\lib\security - - src\core\security + + src\core\lib\security - - src\core\security + + src\core\lib\security - - src\core\security + + src\core\lib\security - - src\core\security + + src\core\lib\security - - src\core\security + + src\core\lib\security - - src\core\security + + src\core\lib\security - - src\core\security + + src\core\lib\security - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\tsi + + src\core\lib\tsi - - src\core\tsi + + src\core\lib\tsi - - src\core\tsi + + src\core\lib\tsi - - src\core\census + + src\core\lib\census - - src\core\census + + src\core\lib\census - - src\core\census + + src\core\lib\census - - src\core\census + + src\core\lib\census - - src\core\census + + src\core\lib\census - - src\core\census + + src\core\lib\census third_party\nanopb @@ -536,416 +536,416 @@ - - src\core\census + + src\core\lib\census - - src\core\census + + src\core\lib\census - - src\core\channel + + src\core\lib\channel - - src\core\channel + + src\core\lib\channel - - src\core\channel + + src\core\lib\channel - - src\core\channel + + src\core\lib\channel - - src\core\channel + + src\core\lib\channel - - src\core\channel + + src\core\lib\channel - - src\core\channel + + src\core\lib\channel - - src\core\channel + + src\core\lib\channel - - src\core\channel + + src\core\lib\channel - - src\core\channel + + src\core\lib\channel - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config\lb_policies + + src\core\lib\client_config\lb_policies - - src\core\client_config\lb_policies + + src\core\lib\client_config\lb_policies - - src\core\client_config\lb_policies + + src\core\lib\client_config\lb_policies - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config\resolvers + + src\core\lib\client_config\resolvers - - src\core\client_config\resolvers + + src\core\lib\client_config\resolvers - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\compression + + src\core\lib\compression - - src\core\compression + + src\core\lib\compression - - src\core\debug + + src\core\lib\debug - - src\core\http + + src\core\lib\http - - src\core\http + + src\core\lib\http - - src\core\http + + src\core\lib\http - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\json + + src\core\lib\json - - src\core\json + + src\core\lib\json - - src\core\json + + src\core\lib\json - - src\core\json + + src\core\lib\json - - src\core\proto\grpc\lb\v0 + + src\core\lib\proto\grpc\lb\v0 - - src\core\statistics + + src\core\lib\statistics - - src\core\statistics + + src\core\lib\statistics - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\transport + + src\core\lib\transport - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport + + src\core\lib\transport - - src\core\transport + + src\core\lib\transport - - src\core\transport + + src\core\lib\transport - - src\core\transport + + src\core\lib\transport - - src\core\transport + + src\core\lib\transport - - src\core\transport + + src\core\lib\transport - - src\core\transport + + src\core\lib\transport - - src\core\security + + src\core\lib\security - - src\core\security + + src\core\lib\security - - src\core\security + + src\core\lib\security - - src\core\security + + src\core\lib\security - - src\core\security + + src\core\lib\security - - src\core\security + + src\core\lib\security - - src\core\security + + src\core\lib\security - - src\core\security + + src\core\lib\security - - src\core\security + + src\core\lib\security - - src\core\tsi + + src\core\lib\tsi - - src\core\tsi + + src\core\lib\tsi - - src\core\tsi + + src\core\lib\tsi - - src\core\tsi + + src\core\lib\tsi - - src\core\tsi + + src\core\lib\tsi - - src\core\census + + src\core\lib\census - - src\core\census + + src\core\lib\census - - src\core\census + + src\core\lib\census third_party\nanopb @@ -980,65 +980,68 @@ {ea745680-21ea-9c5e-679b-64dc40562d08} - - {fb3aefc2-8205-b0bf-525f-ab5e339f7f76} + + {5b2ded3f-84a5-f6b4-2060-286c7d1dc945} - - {d897b6c3-c555-234e-a589-b4f008063615} + + {f4108884-98c3-ac2e-c669-83cd41343975} - - {e71e6928-b1e3-0616-0961-1505370458ab} + + {1931b044-90f3-cd68-b5f8-23be77ca8efc} - - {a3eca4d5-f760-61a6-7251-556b828c8b44} + + {2f3260de-be57-d18d-6882-61d115baa159} - - {6d97b8d9-2c15-927a-892a-709d073c02ab} + + {118d2bb5-086f-54f3-11de-26d7d7f73f9d} - - {263cb913-dfe6-42a4-096b-cac231f76305} + + {b9d8db6c-2c68-1c90-fe5e-37da90f47ae6} - - {1da7ef8a-a06d-5499-b3de-19fee4a4214d} + + {dadf7fe9-3f15-d431-e4f6-f987b090536c} - - {404fdb9e-a69c-81d4-035b-465c826115a9} + + {19122742-9b92-5b67-9fb9-e552ac62ca5d} - - {1baf3894-af37-e647-bdbc-95dc17ed0073} + + {dab8f03a-73de-8cfa-88fb-6e04402efb54} - - {e665cc0e-b994-d7c5-cc18-2007392019f0} + + {5468ba38-b8a3-85b1-216f-48a2364e18df} - - {1ff04466-0905-8a5d-d6f4-7ff2df4c13b5} + + {cb2b0073-f2a7-5c63-d182-8874b24bdf36} - - {7c7ad0b3-bf85-5bd3-e0c8-4f5468a8e2e6} + + {b4b19f9a-1575-8a21-0bca-537746f858b7} - - {3d533dad-8100-e8a3-b7c3-1fc13a4d60da} + + {cbc8ce67-4a97-d533-8dc3-f949c63e2771} - - {0ffcf868-7617-5fed-b6ce-2162d9d09148} + + {933530ae-447b-ea8d-3531-98f0556960b0} - - {1d850ac6-e639-4eab-5338-4ba40272fcc9} + + {c33f944f-37d4-42fd-abc3-61f0d4400462} - - {0ef49896-2313-4a3f-1ce2-716fa0e5c6ca} + + {c4661d64-349f-01c1-1ba8-0602f9047595} - - {aeb18e82-5d25-0aad-8b02-a0a3470073ce} + + {4dc3c48b-e931-ed47-ffa2-b4ea3a7956ec} - - {168fa1b1-1c18-eb55-9a4d-746bc58df2c1} + + {a21971fb-304f-da08-b1b2-7bd8df8ac373} - - {b8b623c3-a168-a2b1-0d5f-b70a1f1cd8d2} + + {e9d0d3fc-c100-f3e6-89b8-649f241155bf} - - {0b0f9ab1-efa4-7f03-e446-6fb9b5227e84} + + {a47fedfc-b6c6-d588-14fc-6645d736bcd6} + + + {95ad2811-c8d0-7a42-2a73-baf03fcbf699} {aaab30a4-2a15-732e-c141-3fbc0f0f5a7a} diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj index 4f2336aab2..0512501cfc 100644 --- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj +++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj @@ -272,416 +272,416 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters index e31ece741d..5309b18729 100644 --- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters +++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters @@ -1,428 +1,428 @@ - - src\core\surface + + src\core\lib\surface - - src\core\census + + src\core\lib\census - - src\core\census + + src\core\lib\census - - src\core\census + + src\core\lib\census - - src\core\channel + + src\core\lib\channel - - src\core\channel + + src\core\lib\channel - - src\core\channel + + src\core\lib\channel - - src\core\channel + + src\core\lib\channel - - src\core\channel + + src\core\lib\channel - - src\core\channel + + src\core\lib\channel - - src\core\channel + + src\core\lib\channel - - src\core\channel + + src\core\lib\channel - - src\core\channel + + src\core\lib\channel - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config\lb_policies + + src\core\lib\client_config\lb_policies - - src\core\client_config\lb_policies + + src\core\lib\client_config\lb_policies - - src\core\client_config\lb_policies + + src\core\lib\client_config\lb_policies - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config\resolvers + + src\core\lib\client_config\resolvers - - src\core\client_config\resolvers + + src\core\lib\client_config\resolvers - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\compression + + src\core\lib\compression - - src\core\compression + + src\core\lib\compression - - src\core\debug + + src\core\lib\debug - - src\core\http + + src\core\lib\http - - src\core\http + + src\core\lib\http - - src\core\http + + src\core\lib\http - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\json + + src\core\lib\json - - src\core\json + + src\core\lib\json - - src\core\json + + src\core\lib\json - - src\core\json + + src\core\lib\json - - src\core\proto\grpc\lb\v0 + + src\core\lib\proto\grpc\lb\v0 - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\transport + + src\core\lib\transport - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport + + src\core\lib\transport - - src\core\transport + + src\core\lib\transport - - src\core\transport + + src\core\lib\transport - - src\core\transport + + src\core\lib\transport - - src\core\transport + + src\core\lib\transport - - src\core\transport + + src\core\lib\transport - - src\core\transport + + src\core\lib\transport - - src\core\census + + src\core\lib\census - - src\core\census + + src\core\lib\census - - src\core\census + + src\core\lib\census - - src\core\census + + src\core\lib\census - - src\core\census + + src\core\lib\census - - src\core\census + + src\core\lib\census third_party\nanopb @@ -473,374 +473,374 @@ - - src\core\census + + src\core\lib\census - - src\core\census + + src\core\lib\census - - src\core\channel + + src\core\lib\channel - - src\core\channel + + src\core\lib\channel - - src\core\channel + + src\core\lib\channel - - src\core\channel + + src\core\lib\channel - - src\core\channel + + src\core\lib\channel - - src\core\channel + + src\core\lib\channel - - src\core\channel + + src\core\lib\channel - - src\core\channel + + src\core\lib\channel - - src\core\channel + + src\core\lib\channel - - src\core\channel + + src\core\lib\channel - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config\lb_policies + + src\core\lib\client_config\lb_policies - - src\core\client_config\lb_policies + + src\core\lib\client_config\lb_policies - - src\core\client_config\lb_policies + + src\core\lib\client_config\lb_policies - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config\resolvers + + src\core\lib\client_config\resolvers - - src\core\client_config\resolvers + + src\core\lib\client_config\resolvers - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\client_config + + src\core\lib\client_config - - src\core\compression + + src\core\lib\compression - - src\core\compression + + src\core\lib\compression - - src\core\debug + + src\core\lib\debug - - src\core\http + + src\core\lib\http - - src\core\http + + src\core\lib\http - - src\core\http + + src\core\lib\http - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\iomgr + + src\core\lib\iomgr - - src\core\json + + src\core\lib\json - - src\core\json + + src\core\lib\json - - src\core\json + + src\core\lib\json - - src\core\json + + src\core\lib\json - - src\core\proto\grpc\lb\v0 + + src\core\lib\proto\grpc\lb\v0 - - src\core\statistics + + src\core\lib\statistics - - src\core\statistics + + src\core\lib\statistics - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\surface + + src\core\lib\surface - - src\core\transport + + src\core\lib\transport - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport\chttp2 + + src\core\lib\transport\chttp2 - - src\core\transport + + src\core\lib\transport - - src\core\transport + + src\core\lib\transport - - src\core\transport + + src\core\lib\transport - - src\core\transport + + src\core\lib\transport - - src\core\transport + + src\core\lib\transport - - src\core\transport + + src\core\lib\transport - - src\core\transport + + src\core\lib\transport - - src\core\census + + src\core\lib\census - - src\core\census + + src\core\lib\census - - src\core\census + + src\core\lib\census third_party\nanopb @@ -875,59 +875,62 @@ {88491077-386b-2039-d14c-0c40136b5f7a} - - {a7596ee2-afee-3a82-7e6e-bd8b8f904e04} + + {8bd5b461-bff8-6aa8-b5a6-85da2834eb8a} - - {cc102c4b-66ff-cf4c-2288-d76327e1a183} + + {19582d5a-dab7-9dc1-c7e9-cc147fd52e5f} - - {02bd7340-02ee-4337-ffa5-0b6ecc7cf60c} + + {fb964f3d-a59c-a7ba-fee5-6072dbb94a7b} - - {308af086-46c7-fa66-9021-19b1c3d4a6bd} + + {29ca2974-89e4-1a74-3e4d-0d63e2f77566} - - {dd617c24-6f07-fdff-80d5-c8610d6f815e} + + {6c7e36d4-6117-e0cd-c886-b9eb3c994927} - - {2e3aca1d-223d-10a1-b282-7f9fc68ee6f5} + + {2d959ef9-9703-dc92-a56f-9fe136dadfb9} - - {6d8d5774-7291-554d-fafa-583463cd3fd9} + + {b88002e9-185e-4e64-49f5-2d8989ce87f6} - - {46faed8e-5cd4-98b0-05ed-ff2ac7bc2d46} + + {7f23789d-f18a-2a2d-60fe-a87dc656f539} - - {a9df8b24-ecea-ff6d-8999-d8fa54cd70bf} + + {748c8078-2027-8641-f485-1d4c66466e79} - - {443ffc61-1bea-2477-6e54-1ddf8c139264} + + {bb1a1cf2-6824-08f0-a9bd-3fafcaf13042} - - {7f4bb22a-65ba-0f8f-6387-66b1f6677a80} + + {681cdaeb-c47f-8853-d985-bf13c2873947} - - {9c2bd164-c317-8a13-564d-3b28b0fd79cf} + + {4bfbd6c6-f6a8-c6b3-5186-b788f4e11e23} - - {2bad8e10-4fc5-d8b3-e026-4abbd0c25cda} + + {60f3ab7d-ea44-348f-671e-77fdebbd18bb} - - {4475c8ed-e01b-8906-47d0-8a504189c0d5} + + {bcd33510-32e7-c2fb-e11d-a3655f97bc84} - - {e084164c-a069-00e3-db35-4e0b1cd6f0b7} + + {bb9b8c80-9eff-5ab6-5b29-c2d54f0fc192} - - {6cd0127e-c24b-d43c-38f5-198db8d4322a} + + {d0ab6d54-ae25-fc49-3656-91d9db57366a} - - {6687ff98-e36e-c0b1-2756-1bc79edec406} + + {506dc3b3-d884-2b59-0dfa-57ed6affa2d3} - - {5fcd6206-f774-9ae6-4b85-305d6a723843} + + {6c3394d1-27e9-003e-19ed-8116d210f7cc} + + + {212a6997-9b9c-3b47-d953-aaff34d608b1} {025c051e-8eba-125b-67f9-173f95176eb2} -- cgit v1.2.3