Mark D. Roth | 74e03a2 | 2016-07-13 10:12:17 -0700 | [diff] [blame] | 1 | /* |
| 2 | * |
| 3 | * Copyright 2016, Google Inc. |
| 4 | * All rights reserved. |
| 5 | * |
| 6 | * Redistribution and use in source and binary forms, with or without |
| 7 | * modification, are permitted provided that the following conditions are |
| 8 | * met: |
| 9 | * |
| 10 | * * Redistributions of source code must retain the above copyright |
| 11 | * notice, this list of conditions and the following disclaimer. |
| 12 | * * Redistributions in binary form must reproduce the above |
| 13 | * copyright notice, this list of conditions and the following disclaimer |
| 14 | * in the documentation and/or other materials provided with the |
| 15 | * distribution. |
| 16 | * * Neither the name of Google Inc. nor the names of its |
| 17 | * contributors may be used to endorse or promote products derived from |
| 18 | * this software without specific prior written permission. |
| 19 | * |
| 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 31 | * |
| 32 | */ |
| 33 | |
Mark D. Roth | 7c2a58c | 2016-07-14 11:53:47 -0700 | [diff] [blame] | 34 | #include <string.h> |
| 35 | |
David Garcia Quintas | 6b11462 | 2016-07-27 14:49:53 -0700 | [diff] [blame] | 36 | #include <grpc/support/alloc.h> |
David Garcia Quintas | c79b065 | 2016-07-27 21:11:58 -0700 | [diff] [blame] | 37 | #include <grpc/support/log.h> |
Mark D. Roth | 7c2a58c | 2016-07-14 11:53:47 -0700 | [diff] [blame] | 38 | |
Mark D. Roth | 45015dc | 2016-07-15 08:48:25 -0700 | [diff] [blame] | 39 | #include "src/core/lib/channel/channel_args.h" |
Mark D. Roth | 74e03a2 | 2016-07-13 10:12:17 -0700 | [diff] [blame] | 40 | #include "src/core/lib/channel/handshaker.h" |
Mark D. Roth | b16c1e3 | 2016-11-14 12:08:13 -0800 | [diff] [blame] | 41 | #include "src/core/lib/iomgr/timer.h" |
Mark D. Roth | 74e03a2 | 2016-07-13 10:12:17 -0700 | [diff] [blame] | 42 | |
Mark D. Roth | c05539f | 2016-07-14 09:12:51 -0700 | [diff] [blame] | 43 | // |
| 44 | // grpc_handshaker |
| 45 | // |
| 46 | |
Mark D. Roth | 27588bb | 2016-11-11 15:03:39 -0800 | [diff] [blame] | 47 | void grpc_handshaker_init(const grpc_handshaker_vtable* vtable, |
Mark D. Roth | 7c2a58c | 2016-07-14 11:53:47 -0700 | [diff] [blame] | 48 | grpc_handshaker* handshaker) { |
Mark D. Roth | 74e03a2 | 2016-07-13 10:12:17 -0700 | [diff] [blame] | 49 | handshaker->vtable = vtable; |
| 50 | } |
| 51 | |
Mark D. Roth | 887e218 | 2016-12-07 08:19:34 -0800 | [diff] [blame] | 52 | void grpc_handshaker_destroy(grpc_exec_ctx* exec_ctx, |
| 53 | grpc_handshaker* handshaker) { |
Mark D. Roth | 74e03a2 | 2016-07-13 10:12:17 -0700 | [diff] [blame] | 54 | handshaker->vtable->destroy(exec_ctx, handshaker); |
| 55 | } |
| 56 | |
Mark D. Roth | 887e218 | 2016-12-07 08:19:34 -0800 | [diff] [blame] | 57 | void grpc_handshaker_shutdown(grpc_exec_ctx* exec_ctx, |
| 58 | grpc_handshaker* handshaker) { |
Mark D. Roth | c05539f | 2016-07-14 09:12:51 -0700 | [diff] [blame] | 59 | handshaker->vtable->shutdown(exec_ctx, handshaker); |
| 60 | } |
| 61 | |
Mark D. Roth | 887e218 | 2016-12-07 08:19:34 -0800 | [diff] [blame] | 62 | void grpc_handshaker_do_handshake(grpc_exec_ctx* exec_ctx, |
| 63 | grpc_handshaker* handshaker, |
| 64 | grpc_tcp_server_acceptor* acceptor, |
| 65 | grpc_closure* on_handshake_done, |
| 66 | grpc_handshaker_args* args) { |
Mark D. Roth | b16c1e3 | 2016-11-14 12:08:13 -0800 | [diff] [blame] | 67 | handshaker->vtable->do_handshake(exec_ctx, handshaker, acceptor, |
Mark D. Roth | 27588bb | 2016-11-11 15:03:39 -0800 | [diff] [blame] | 68 | on_handshake_done, args); |
Mark D. Roth | c05539f | 2016-07-14 09:12:51 -0700 | [diff] [blame] | 69 | } |
| 70 | |
| 71 | // |
| 72 | // grpc_handshake_manager |
| 73 | // |
| 74 | |
Mark D. Roth | b16c1e3 | 2016-11-14 12:08:13 -0800 | [diff] [blame] | 75 | struct grpc_handshake_manager { |
| 76 | gpr_mu mu; |
| 77 | gpr_refcount refs; |
Mark D. Roth | f6a046e | 2016-12-02 13:15:42 -0800 | [diff] [blame] | 78 | bool shutdown; |
Mark D. Roth | b16c1e3 | 2016-11-14 12:08:13 -0800 | [diff] [blame] | 79 | // An array of handshakers added via grpc_handshake_manager_add(). |
| 80 | size_t count; |
| 81 | grpc_handshaker** handshakers; |
| 82 | // The index of the handshaker to invoke next and closure to invoke it. |
Mark D. Roth | c05539f | 2016-07-14 09:12:51 -0700 | [diff] [blame] | 83 | size_t index; |
Mark D. Roth | 4b5cdb7 | 2016-11-14 11:37:36 -0800 | [diff] [blame] | 84 | grpc_closure call_next_handshaker; |
Mark D. Roth | 5682a52 | 2016-07-20 09:54:41 -0700 | [diff] [blame] | 85 | // The acceptor to call the handshakers with. |
Mark D. Roth | ac8df65 | 2016-07-21 07:25:24 -0700 | [diff] [blame] | 86 | grpc_tcp_server_acceptor* acceptor; |
Mark D. Roth | b16c1e3 | 2016-11-14 12:08:13 -0800 | [diff] [blame] | 87 | // Deadline timer across all handshakers. |
| 88 | grpc_timer deadline_timer; |
Mark D. Roth | 45015dc | 2016-07-15 08:48:25 -0700 | [diff] [blame] | 89 | // The final callback and user_data to invoke after the last handshaker. |
Mark D. Roth | 4b5cdb7 | 2016-11-14 11:37:36 -0800 | [diff] [blame] | 90 | grpc_closure on_handshake_done; |
Mark D. Roth | 27588bb | 2016-11-11 15:03:39 -0800 | [diff] [blame] | 91 | void* user_data; |
Mark D. Roth | f9b56b9 | 2016-11-16 14:58:05 -0800 | [diff] [blame] | 92 | // Handshaker args. |
| 93 | grpc_handshaker_args args; |
Mark D. Roth | c05539f | 2016-07-14 09:12:51 -0700 | [diff] [blame] | 94 | }; |
| 95 | |
Mark D. Roth | c05539f | 2016-07-14 09:12:51 -0700 | [diff] [blame] | 96 | grpc_handshake_manager* grpc_handshake_manager_create() { |
| 97 | grpc_handshake_manager* mgr = gpr_malloc(sizeof(grpc_handshake_manager)); |
| 98 | memset(mgr, 0, sizeof(*mgr)); |
Mark D. Roth | b16c1e3 | 2016-11-14 12:08:13 -0800 | [diff] [blame] | 99 | gpr_mu_init(&mgr->mu); |
| 100 | gpr_ref_init(&mgr->refs, 1); |
Mark D. Roth | c05539f | 2016-07-14 09:12:51 -0700 | [diff] [blame] | 101 | return mgr; |
| 102 | } |
| 103 | |
Mark D. Roth | ac8df65 | 2016-07-21 07:25:24 -0700 | [diff] [blame] | 104 | static bool is_power_of_2(size_t n) { return (n & (n - 1)) == 0; } |
Mark D. Roth | 0b84add | 2016-07-20 10:08:48 -0700 | [diff] [blame] | 105 | |
Mark D. Roth | 39377e9 | 2016-07-25 11:21:09 -0700 | [diff] [blame] | 106 | void grpc_handshake_manager_add(grpc_handshake_manager* mgr, |
| 107 | grpc_handshaker* handshaker) { |
Mark D. Roth | b16c1e3 | 2016-11-14 12:08:13 -0800 | [diff] [blame] | 108 | gpr_mu_lock(&mgr->mu); |
Mark D. Roth | 0b84add | 2016-07-20 10:08:48 -0700 | [diff] [blame] | 109 | // To avoid allocating memory for each handshaker we add, we double |
| 110 | // the number of elements every time we need more. |
| 111 | size_t realloc_count = 0; |
| 112 | if (mgr->count == 0) { |
| 113 | realloc_count = 2; |
| 114 | } else if (mgr->count >= 2 && is_power_of_2(mgr->count)) { |
| 115 | realloc_count = mgr->count * 2; |
| 116 | } |
| 117 | if (realloc_count > 0) { |
Mark D. Roth | ac8df65 | 2016-07-21 07:25:24 -0700 | [diff] [blame] | 118 | mgr->handshakers = |
| 119 | gpr_realloc(mgr->handshakers, realloc_count * sizeof(grpc_handshaker*)); |
Mark D. Roth | 0b84add | 2016-07-20 10:08:48 -0700 | [diff] [blame] | 120 | } |
Mark D. Roth | c05539f | 2016-07-14 09:12:51 -0700 | [diff] [blame] | 121 | mgr->handshakers[mgr->count++] = handshaker; |
Mark D. Roth | b16c1e3 | 2016-11-14 12:08:13 -0800 | [diff] [blame] | 122 | gpr_mu_unlock(&mgr->mu); |
| 123 | } |
| 124 | |
| 125 | static void grpc_handshake_manager_unref(grpc_exec_ctx* exec_ctx, |
| 126 | grpc_handshake_manager* mgr) { |
| 127 | if (gpr_unref(&mgr->refs)) { |
| 128 | for (size_t i = 0; i < mgr->count; ++i) { |
| 129 | grpc_handshaker_destroy(exec_ctx, mgr->handshakers[i]); |
| 130 | } |
| 131 | gpr_free(mgr->handshakers); |
| 132 | gpr_mu_destroy(&mgr->mu); |
| 133 | gpr_free(mgr); |
| 134 | } |
Mark D. Roth | c05539f | 2016-07-14 09:12:51 -0700 | [diff] [blame] | 135 | } |
| 136 | |
Mark D. Roth | 1d3b2cc | 2016-07-14 09:18:12 -0700 | [diff] [blame] | 137 | void grpc_handshake_manager_destroy(grpc_exec_ctx* exec_ctx, |
| 138 | grpc_handshake_manager* mgr) { |
Mark D. Roth | b16c1e3 | 2016-11-14 12:08:13 -0800 | [diff] [blame] | 139 | grpc_handshake_manager_unref(exec_ctx, mgr); |
Mark D. Roth | c05539f | 2016-07-14 09:12:51 -0700 | [diff] [blame] | 140 | } |
| 141 | |
Mark D. Roth | 1d3b2cc | 2016-07-14 09:18:12 -0700 | [diff] [blame] | 142 | void grpc_handshake_manager_shutdown(grpc_exec_ctx* exec_ctx, |
| 143 | grpc_handshake_manager* mgr) { |
Mark D. Roth | b16c1e3 | 2016-11-14 12:08:13 -0800 | [diff] [blame] | 144 | gpr_mu_lock(&mgr->mu); |
Mark D. Roth | a9bd943 | 2016-11-30 09:38:55 -0800 | [diff] [blame] | 145 | // Shutdown the handshaker that's currently in progress, if any. |
Mark D. Roth | f6a046e | 2016-12-02 13:15:42 -0800 | [diff] [blame] | 146 | if (!mgr->shutdown && mgr->index > 0) { |
| 147 | mgr->shutdown = true; |
Mark D. Roth | 30f698f | 2016-11-29 14:02:32 -0800 | [diff] [blame] | 148 | grpc_handshaker_shutdown(exec_ctx, mgr->handshakers[mgr->index - 1]); |
Mark D. Roth | c05539f | 2016-07-14 09:12:51 -0700 | [diff] [blame] | 149 | } |
Mark D. Roth | b16c1e3 | 2016-11-14 12:08:13 -0800 | [diff] [blame] | 150 | gpr_mu_unlock(&mgr->mu); |
| 151 | } |
| 152 | |
Mark D. Roth | b16c1e3 | 2016-11-14 12:08:13 -0800 | [diff] [blame] | 153 | // Helper function to call either the next handshaker or the |
| 154 | // on_handshake_done callback. |
Mark D. Roth | a9bd943 | 2016-11-30 09:38:55 -0800 | [diff] [blame] | 155 | // Returns true if we've scheduled the on_handshake_done callback. |
| 156 | static bool call_next_handshaker_locked(grpc_exec_ctx* exec_ctx, |
Mark D. Roth | 2ea37e9 | 2016-11-14 12:31:22 -0800 | [diff] [blame] | 157 | grpc_handshake_manager* mgr, |
Mark D. Roth | 2ea37e9 | 2016-11-14 12:31:22 -0800 | [diff] [blame] | 158 | grpc_error* error) { |
Mark D. Roth | b16c1e3 | 2016-11-14 12:08:13 -0800 | [diff] [blame] | 159 | GPR_ASSERT(mgr->index <= mgr->count); |
Mark D. Roth | cc527cf | 2016-12-06 10:43:12 -0800 | [diff] [blame] | 160 | // If we got an error or we've been shut down or we're exiting early or |
| 161 | // we've finished the last handshaker, invoke the on_handshake_done |
| 162 | // callback. Otherwise, call the next handshaker. |
| 163 | if (error != GRPC_ERROR_NONE || mgr->shutdown || mgr->args.exit_early || |
| 164 | mgr->index == mgr->count) { |
Mark D. Roth | b16c1e3 | 2016-11-14 12:08:13 -0800 | [diff] [blame] | 165 | // Cancel deadline timer, since we're invoking the on_handshake_done |
| 166 | // callback now. |
| 167 | grpc_timer_cancel(exec_ctx, &mgr->deadline_timer); |
Mark D. Roth | 4475694 | 2016-11-29 12:43:55 -0800 | [diff] [blame] | 168 | grpc_exec_ctx_sched(exec_ctx, &mgr->on_handshake_done, error, NULL); |
Mark D. Roth | f6a046e | 2016-12-02 13:15:42 -0800 | [diff] [blame] | 169 | mgr->shutdown = true; |
| 170 | } else { |
| 171 | grpc_handshaker_do_handshake(exec_ctx, mgr->handshakers[mgr->index], |
| 172 | mgr->acceptor, &mgr->call_next_handshaker, |
| 173 | &mgr->args); |
Mark D. Roth | c05539f | 2016-07-14 09:12:51 -0700 | [diff] [blame] | 174 | } |
Mark D. Roth | b16c1e3 | 2016-11-14 12:08:13 -0800 | [diff] [blame] | 175 | ++mgr->index; |
Mark D. Roth | f6a046e | 2016-12-02 13:15:42 -0800 | [diff] [blame] | 176 | return mgr->shutdown; |
Mark D. Roth | c05539f | 2016-07-14 09:12:51 -0700 | [diff] [blame] | 177 | } |
| 178 | |
| 179 | // A function used as the handshaker-done callback when chaining |
| 180 | // handshakers together. |
Mark D. Roth | 27588bb | 2016-11-11 15:03:39 -0800 | [diff] [blame] | 181 | static void call_next_handshaker(grpc_exec_ctx* exec_ctx, void* arg, |
| 182 | grpc_error* error) { |
Mark D. Roth | 4475694 | 2016-11-29 12:43:55 -0800 | [diff] [blame] | 183 | grpc_handshake_manager* mgr = arg; |
Mark D. Roth | b16c1e3 | 2016-11-14 12:08:13 -0800 | [diff] [blame] | 184 | gpr_mu_lock(&mgr->mu); |
Mark D. Roth | a9bd943 | 2016-11-30 09:38:55 -0800 | [diff] [blame] | 185 | bool done = call_next_handshaker_locked(exec_ctx, mgr, GRPC_ERROR_REF(error)); |
Mark D. Roth | b16c1e3 | 2016-11-14 12:08:13 -0800 | [diff] [blame] | 186 | gpr_mu_unlock(&mgr->mu); |
Mark D. Roth | a9bd943 | 2016-11-30 09:38:55 -0800 | [diff] [blame] | 187 | // If we're invoked the final callback, we won't be coming back |
| 188 | // to this function, so we can release our reference to the |
| 189 | // handshake manager. |
| 190 | if (done) { |
| 191 | grpc_handshake_manager_unref(exec_ctx, mgr); |
| 192 | } |
Mark D. Roth | b16c1e3 | 2016-11-14 12:08:13 -0800 | [diff] [blame] | 193 | } |
| 194 | |
| 195 | // Callback invoked when deadline is exceeded. |
| 196 | static void on_timeout(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) { |
| 197 | grpc_handshake_manager* mgr = arg; |
| 198 | if (error == GRPC_ERROR_NONE) { // Timer fired, rather than being cancelled. |
| 199 | grpc_handshake_manager_shutdown(exec_ctx, mgr); |
Mark D. Roth | a228e5f | 2016-07-22 09:02:15 -0700 | [diff] [blame] | 200 | } |
Mark D. Roth | b16c1e3 | 2016-11-14 12:08:13 -0800 | [diff] [blame] | 201 | grpc_handshake_manager_unref(exec_ctx, mgr); |
Mark D. Roth | c05539f | 2016-07-14 09:12:51 -0700 | [diff] [blame] | 202 | } |
| 203 | |
Mark D. Roth | b3ce178 | 2016-07-20 09:25:25 -0700 | [diff] [blame] | 204 | void grpc_handshake_manager_do_handshake( |
| 205 | grpc_exec_ctx* exec_ctx, grpc_handshake_manager* mgr, |
Mark D. Roth | 27588bb | 2016-11-11 15:03:39 -0800 | [diff] [blame] | 206 | grpc_endpoint* endpoint, const grpc_channel_args* channel_args, |
Mark D. Roth | ac8df65 | 2016-07-21 07:25:24 -0700 | [diff] [blame] | 207 | gpr_timespec deadline, grpc_tcp_server_acceptor* acceptor, |
Mark D. Roth | 27588bb | 2016-11-11 15:03:39 -0800 | [diff] [blame] | 208 | grpc_iomgr_cb_func on_handshake_done, void* user_data) { |
Mark D. Roth | 30f698f | 2016-11-29 14:02:32 -0800 | [diff] [blame] | 209 | gpr_mu_lock(&mgr->mu); |
| 210 | GPR_ASSERT(mgr->index == 0); |
Mark D. Roth | f6a046e | 2016-12-02 13:15:42 -0800 | [diff] [blame] | 211 | GPR_ASSERT(!mgr->shutdown); |
Mark D. Roth | 27588bb | 2016-11-11 15:03:39 -0800 | [diff] [blame] | 212 | // Construct handshaker args. These will be passed through all |
Mark D. Roth | b16c1e3 | 2016-11-14 12:08:13 -0800 | [diff] [blame] | 213 | // handshakers and eventually be freed by the on_handshake_done callback. |
Mark D. Roth | f9b56b9 | 2016-11-16 14:58:05 -0800 | [diff] [blame] | 214 | mgr->args.endpoint = endpoint; |
| 215 | mgr->args.args = grpc_channel_args_copy(channel_args); |
Mark D. Roth | 4475694 | 2016-11-29 12:43:55 -0800 | [diff] [blame] | 216 | mgr->args.user_data = user_data; |
Mark D. Roth | f9b56b9 | 2016-11-16 14:58:05 -0800 | [diff] [blame] | 217 | mgr->args.read_buffer = gpr_malloc(sizeof(*mgr->args.read_buffer)); |
| 218 | grpc_slice_buffer_init(mgr->args.read_buffer); |
Mark D. Roth | b16c1e3 | 2016-11-14 12:08:13 -0800 | [diff] [blame] | 219 | // Initialize state needed for calling handshakers. |
Mark D. Roth | b16c1e3 | 2016-11-14 12:08:13 -0800 | [diff] [blame] | 220 | mgr->acceptor = acceptor; |
Mark D. Roth | 4475694 | 2016-11-29 12:43:55 -0800 | [diff] [blame] | 221 | grpc_closure_init(&mgr->call_next_handshaker, call_next_handshaker, mgr); |
Mark D. Roth | f9b56b9 | 2016-11-16 14:58:05 -0800 | [diff] [blame] | 222 | grpc_closure_init(&mgr->on_handshake_done, on_handshake_done, &mgr->args); |
Mark D. Roth | b16c1e3 | 2016-11-14 12:08:13 -0800 | [diff] [blame] | 223 | // Start deadline timer, which owns a ref. |
| 224 | gpr_ref(&mgr->refs); |
| 225 | grpc_timer_init(exec_ctx, &mgr->deadline_timer, |
| 226 | gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC), |
| 227 | on_timeout, mgr, gpr_now(GPR_CLOCK_MONOTONIC)); |
| 228 | // Start first handshaker, which also owns a ref. |
| 229 | gpr_ref(&mgr->refs); |
Mark D. Roth | a9bd943 | 2016-11-30 09:38:55 -0800 | [diff] [blame] | 230 | bool done = call_next_handshaker_locked(exec_ctx, mgr, GRPC_ERROR_NONE); |
Mark D. Roth | b16c1e3 | 2016-11-14 12:08:13 -0800 | [diff] [blame] | 231 | gpr_mu_unlock(&mgr->mu); |
Mark D. Roth | a9bd943 | 2016-11-30 09:38:55 -0800 | [diff] [blame] | 232 | if (done) { |
| 233 | grpc_handshake_manager_unref(exec_ctx, mgr); |
| 234 | } |
Mark D. Roth | 74e03a2 | 2016-07-13 10:12:17 -0700 | [diff] [blame] | 235 | } |