Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 1 | /* |
| 2 | * |
Jan Tattermusch | 7897ae9 | 2017-06-07 22:57:36 +0200 | [diff] [blame] | 3 | * Copyright 2015 gRPC authors. |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 4 | * |
Jan Tattermusch | 7897ae9 | 2017-06-07 22:57:36 +0200 | [diff] [blame] | 5 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | * you may not use this file except in compliance with the License. |
| 7 | * You may obtain a copy of the License at |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 8 | * |
Jan Tattermusch | 7897ae9 | 2017-06-07 22:57:36 +0200 | [diff] [blame] | 9 | * http://www.apache.org/licenses/LICENSE-2.0 |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 10 | * |
Jan Tattermusch | 7897ae9 | 2017-06-07 22:57:36 +0200 | [diff] [blame] | 11 | * Unless required by applicable law or agreed to in writing, software |
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | * See the License for the specific language governing permissions and |
| 15 | * limitations under the License. |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 16 | * |
| 17 | */ |
| 18 | |
| 19 | #include "src/core/ext/transport/chttp2/server/chttp2_server.h" |
| 20 | |
| 21 | #include <grpc/grpc.h> |
| 22 | |
Yash Tibrewal | fcd26bc | 2017-09-25 15:08:28 -0700 | [diff] [blame] | 23 | #include <inttypes.h> |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 24 | #include <string.h> |
| 25 | |
| 26 | #include <grpc/support/alloc.h> |
| 27 | #include <grpc/support/log.h> |
| 28 | #include <grpc/support/string_util.h> |
| 29 | #include <grpc/support/sync.h> |
| 30 | #include <grpc/support/useful.h> |
| 31 | |
Craig Tiller | e3593d9 | 2017-04-03 14:51:02 -0700 | [diff] [blame] | 32 | #include "src/core/ext/filters/http/server/http_server_filter.h" |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 33 | #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h" |
| 34 | #include "src/core/lib/channel/channel_args.h" |
| 35 | #include "src/core/lib/channel/handshaker.h" |
Mark D. Roth | 1f0f23c | 2017-01-06 13:07:19 -0800 | [diff] [blame] | 36 | #include "src/core/lib/channel/handshaker_registry.h" |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 37 | #include "src/core/lib/iomgr/endpoint.h" |
| 38 | #include "src/core/lib/iomgr/resolve_address.h" |
| 39 | #include "src/core/lib/iomgr/tcp_server.h" |
Craig Tiller | 6822a7a | 2016-12-06 19:28:52 -0800 | [diff] [blame] | 40 | #include "src/core/lib/slice/slice_internal.h" |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 41 | #include "src/core/lib/surface/api_trace.h" |
| 42 | #include "src/core/lib/surface/server.h" |
| 43 | |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 44 | typedef struct { |
| 45 | grpc_server *server; |
| 46 | grpc_tcp_server *tcp_server; |
| 47 | grpc_channel_args *args; |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 48 | gpr_mu mu; |
| 49 | bool shutdown; |
| 50 | grpc_closure tcp_server_shutdown_complete; |
| 51 | grpc_closure *server_destroy_listener_done; |
yang-g | 6da1e85 | 2017-02-16 10:34:06 -0800 | [diff] [blame] | 52 | grpc_handshake_manager *pending_handshake_mgrs; |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 53 | } server_state; |
| 54 | |
| 55 | typedef struct { |
Yash Tibrewal | a495220 | 2017-09-13 10:53:28 -0700 | [diff] [blame] | 56 | server_state *svr_state; |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 57 | grpc_pollset *accepting_pollset; |
| 58 | grpc_tcp_server_acceptor *acceptor; |
| 59 | grpc_handshake_manager *handshake_mgr; |
| 60 | } server_connection_state; |
| 61 | |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 62 | static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg, |
| 63 | grpc_error *error) { |
Yash Tibrewal | ca3c1c0 | 2017-09-07 22:47:16 -0700 | [diff] [blame] | 64 | grpc_handshaker_args *args = (grpc_handshaker_args *)arg; |
| 65 | server_connection_state *connection_state = |
| 66 | (server_connection_state *)args->user_data; |
Yash Tibrewal | a495220 | 2017-09-13 10:53:28 -0700 | [diff] [blame] | 67 | gpr_mu_lock(&connection_state->svr_state->mu); |
| 68 | if (error != GRPC_ERROR_NONE || connection_state->svr_state->shutdown) { |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 69 | const char *error_str = grpc_error_string(error); |
David Garcia Quintas | c3fc834 | 2017-04-21 15:01:18 -0700 | [diff] [blame] | 70 | gpr_log(GPR_DEBUG, "Handshaking failed: %s", error_str); |
Craig Tiller | 7c70b6c | 2017-01-23 07:48:42 -0800 | [diff] [blame] | 71 | |
Mark D. Roth | 0ee1dbb | 2016-12-09 09:57:20 -0800 | [diff] [blame] | 72 | if (error == GRPC_ERROR_NONE && args->endpoint != NULL) { |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 73 | // We were shut down after handshaking completed successfully, so |
| 74 | // destroy the endpoint here. |
| 75 | // TODO(ctiller): It is currently necessary to shutdown endpoints |
| 76 | // before destroying them, even if we know that there are no |
| 77 | // pending read/write callbacks. This should be fixed, at which |
| 78 | // point this can be removed. |
Craig Tiller | cda759d | 2017-01-27 11:37:37 -0800 | [diff] [blame] | 79 | grpc_endpoint_shutdown(exec_ctx, args->endpoint, GRPC_ERROR_NONE); |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 80 | grpc_endpoint_destroy(exec_ctx, args->endpoint); |
Craig Tiller | 397bff3 | 2016-12-06 15:05:59 -0800 | [diff] [blame] | 81 | grpc_channel_args_destroy(exec_ctx, args->args); |
Craig Tiller | 6822a7a | 2016-12-06 19:28:52 -0800 | [diff] [blame] | 82 | grpc_slice_buffer_destroy_internal(exec_ctx, args->read_buffer); |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 83 | gpr_free(args->read_buffer); |
| 84 | } |
| 85 | } else { |
Mark D. Roth | 3059828 | 2016-12-07 07:13:58 -0800 | [diff] [blame] | 86 | // If the handshaking succeeded but there is no endpoint, then the |
| 87 | // handshaker may have handed off the connection to some external |
| 88 | // code, so we can just clean up here without creating a transport. |
Mark D. Roth | cc527cf | 2016-12-06 10:43:12 -0800 | [diff] [blame] | 89 | if (args->endpoint != NULL) { |
| 90 | grpc_transport *transport = |
| 91 | grpc_create_chttp2_transport(exec_ctx, args->args, args->endpoint, 0); |
| 92 | grpc_server_setup_transport( |
Yash Tibrewal | a495220 | 2017-09-13 10:53:28 -0700 | [diff] [blame] | 93 | exec_ctx, connection_state->svr_state->server, transport, |
Mark D. Roth | cc527cf | 2016-12-06 10:43:12 -0800 | [diff] [blame] | 94 | connection_state->accepting_pollset, args->args); |
| 95 | grpc_chttp2_transport_start_reading(exec_ctx, transport, |
| 96 | args->read_buffer); |
Craig Tiller | 1a7c57b | 2016-12-12 06:38:13 -0800 | [diff] [blame] | 97 | grpc_channel_args_destroy(exec_ctx, args->args); |
Mark D. Roth | cc527cf | 2016-12-06 10:43:12 -0800 | [diff] [blame] | 98 | } |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 99 | } |
yang-g | 6da1e85 | 2017-02-16 10:34:06 -0800 | [diff] [blame] | 100 | grpc_handshake_manager_pending_list_remove( |
Yash Tibrewal | a495220 | 2017-09-13 10:53:28 -0700 | [diff] [blame] | 101 | &connection_state->svr_state->pending_handshake_mgrs, |
yang-g | 6da1e85 | 2017-02-16 10:34:06 -0800 | [diff] [blame] | 102 | connection_state->handshake_mgr); |
Yash Tibrewal | a495220 | 2017-09-13 10:53:28 -0700 | [diff] [blame] | 103 | gpr_mu_unlock(&connection_state->svr_state->mu); |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 104 | grpc_handshake_manager_destroy(exec_ctx, connection_state->handshake_mgr); |
Yash Tibrewal | a495220 | 2017-09-13 10:53:28 -0700 | [diff] [blame] | 105 | grpc_tcp_server_unref(exec_ctx, connection_state->svr_state->tcp_server); |
Mark D. Roth | eed3815 | 2016-12-08 13:59:13 -0800 | [diff] [blame] | 106 | gpr_free(connection_state->acceptor); |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 107 | gpr_free(connection_state); |
| 108 | } |
| 109 | |
| 110 | static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, grpc_endpoint *tcp, |
| 111 | grpc_pollset *accepting_pollset, |
| 112 | grpc_tcp_server_acceptor *acceptor) { |
Yash Tibrewal | ca3c1c0 | 2017-09-07 22:47:16 -0700 | [diff] [blame] | 113 | server_state *state = (server_state *)arg; |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 114 | gpr_mu_lock(&state->mu); |
| 115 | if (state->shutdown) { |
| 116 | gpr_mu_unlock(&state->mu); |
Makarand Dharmapurikar | 9c156da | 2017-05-18 10:32:13 -0700 | [diff] [blame] | 117 | grpc_endpoint_shutdown(exec_ctx, tcp, GRPC_ERROR_NONE); |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 118 | grpc_endpoint_destroy(exec_ctx, tcp); |
Mark D. Roth | 96ba68d | 2016-12-09 17:21:26 +0000 | [diff] [blame] | 119 | gpr_free(acceptor); |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 120 | return; |
| 121 | } |
| 122 | grpc_handshake_manager *handshake_mgr = grpc_handshake_manager_create(); |
yang-g | 6da1e85 | 2017-02-16 10:34:06 -0800 | [diff] [blame] | 123 | grpc_handshake_manager_pending_list_add(&state->pending_handshake_mgrs, |
| 124 | handshake_mgr); |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 125 | gpr_mu_unlock(&state->mu); |
| 126 | grpc_tcp_server_ref(state->tcp_server); |
| 127 | server_connection_state *connection_state = |
Yash Tibrewal | bc130da | 2017-09-12 22:44:08 -0700 | [diff] [blame] | 128 | (server_connection_state *)gpr_malloc(sizeof(*connection_state)); |
Yash Tibrewal | a495220 | 2017-09-13 10:53:28 -0700 | [diff] [blame] | 129 | connection_state->svr_state = state; |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 130 | connection_state->accepting_pollset = accepting_pollset; |
| 131 | connection_state->acceptor = acceptor; |
| 132 | connection_state->handshake_mgr = handshake_mgr; |
Mark D. Roth | 1f0f23c | 2017-01-06 13:07:19 -0800 | [diff] [blame] | 133 | grpc_handshakers_add(exec_ctx, HANDSHAKER_SERVER, state->args, |
| 134 | connection_state->handshake_mgr); |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 135 | // TODO(roth): We should really get this timeout value from channel |
| 136 | // args instead of hard-coding it. |
Craig Tiller | dc3998e | 2017-05-12 09:55:30 -0700 | [diff] [blame] | 137 | const grpc_millis deadline = |
| 138 | grpc_exec_ctx_now(exec_ctx) + 120 * GPR_MS_PER_SEC; |
Craig Tiller | 73122ba | 2016-12-05 08:16:58 -0800 | [diff] [blame] | 139 | grpc_handshake_manager_do_handshake(exec_ctx, connection_state->handshake_mgr, |
| 140 | tcp, state->args, deadline, acceptor, |
| 141 | on_handshake_done, connection_state); |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 142 | } |
| 143 | |
| 144 | /* Server callback: start listening on our ports */ |
| 145 | static void server_start_listener(grpc_exec_ctx *exec_ctx, grpc_server *server, |
| 146 | void *arg, grpc_pollset **pollsets, |
| 147 | size_t pollset_count) { |
Yash Tibrewal | ca3c1c0 | 2017-09-07 22:47:16 -0700 | [diff] [blame] | 148 | server_state *state = (server_state *)arg; |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 149 | gpr_mu_lock(&state->mu); |
| 150 | state->shutdown = false; |
| 151 | gpr_mu_unlock(&state->mu); |
| 152 | grpc_tcp_server_start(exec_ctx, state->tcp_server, pollsets, pollset_count, |
| 153 | on_accept, state); |
| 154 | } |
| 155 | |
| 156 | static void tcp_server_shutdown_complete(grpc_exec_ctx *exec_ctx, void *arg, |
| 157 | grpc_error *error) { |
Yash Tibrewal | ca3c1c0 | 2017-09-07 22:47:16 -0700 | [diff] [blame] | 158 | server_state *state = (server_state *)arg; |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 159 | /* ensure all threads have unlocked */ |
| 160 | gpr_mu_lock(&state->mu); |
| 161 | grpc_closure *destroy_done = state->server_destroy_listener_done; |
| 162 | GPR_ASSERT(state->shutdown); |
yang-g | 6da1e85 | 2017-02-16 10:34:06 -0800 | [diff] [blame] | 163 | grpc_handshake_manager_pending_list_shutdown_all( |
| 164 | exec_ctx, state->pending_handshake_mgrs, GRPC_ERROR_REF(error)); |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 165 | gpr_mu_unlock(&state->mu); |
| 166 | // Flush queued work before destroying handshaker factory, since that |
| 167 | // may do a synchronous unref. |
| 168 | grpc_exec_ctx_flush(exec_ctx); |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 169 | if (destroy_done != NULL) { |
| 170 | destroy_done->cb(exec_ctx, destroy_done->cb_arg, GRPC_ERROR_REF(error)); |
| 171 | grpc_exec_ctx_flush(exec_ctx); |
| 172 | } |
Craig Tiller | 397bff3 | 2016-12-06 15:05:59 -0800 | [diff] [blame] | 173 | grpc_channel_args_destroy(exec_ctx, state->args); |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 174 | gpr_mu_destroy(&state->mu); |
| 175 | gpr_free(state); |
| 176 | } |
| 177 | |
| 178 | /* Server callback: destroy the tcp listener (so we don't generate further |
| 179 | callbacks) */ |
| 180 | static void server_destroy_listener(grpc_exec_ctx *exec_ctx, |
| 181 | grpc_server *server, void *arg, |
| 182 | grpc_closure *destroy_done) { |
Yash Tibrewal | ca3c1c0 | 2017-09-07 22:47:16 -0700 | [diff] [blame] | 183 | server_state *state = (server_state *)arg; |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 184 | gpr_mu_lock(&state->mu); |
| 185 | state->shutdown = true; |
| 186 | state->server_destroy_listener_done = destroy_done; |
| 187 | grpc_tcp_server *tcp_server = state->tcp_server; |
| 188 | gpr_mu_unlock(&state->mu); |
| 189 | grpc_tcp_server_shutdown_listeners(exec_ctx, tcp_server); |
| 190 | grpc_tcp_server_unref(exec_ctx, tcp_server); |
| 191 | } |
| 192 | |
Mark D. Roth | 1f0f23c | 2017-01-06 13:07:19 -0800 | [diff] [blame] | 193 | grpc_error *grpc_chttp2_server_add_port(grpc_exec_ctx *exec_ctx, |
| 194 | grpc_server *server, const char *addr, |
| 195 | grpc_channel_args *args, |
| 196 | int *port_num) { |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 197 | grpc_resolved_addresses *resolved = NULL; |
| 198 | grpc_tcp_server *tcp_server = NULL; |
| 199 | size_t i; |
| 200 | size_t count = 0; |
| 201 | int port_temp; |
| 202 | grpc_error *err = GRPC_ERROR_NONE; |
| 203 | server_state *state = NULL; |
Mark D. Roth | a0bcfbb | 2016-12-02 12:10:25 -0800 | [diff] [blame] | 204 | grpc_error **errors = NULL; |
Yash Tibrewal | 533d118 | 2017-09-18 10:48:22 -0700 | [diff] [blame] | 205 | size_t naddrs = 0; |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 206 | |
| 207 | *port_num = -1; |
| 208 | |
| 209 | /* resolve address */ |
| 210 | err = grpc_blocking_resolve_address(addr, "https", &resolved); |
| 211 | if (err != GRPC_ERROR_NONE) { |
| 212 | goto error; |
| 213 | } |
Yash Tibrewal | ca3c1c0 | 2017-09-07 22:47:16 -0700 | [diff] [blame] | 214 | state = (server_state *)gpr_zalloc(sizeof(*state)); |
ncteisen | 274bbbe | 2017-06-08 14:57:11 -0700 | [diff] [blame] | 215 | GRPC_CLOSURE_INIT(&state->tcp_server_shutdown_complete, |
Craig Tiller | 91031da | 2016-12-28 15:44:25 -0800 | [diff] [blame] | 216 | tcp_server_shutdown_complete, state, |
| 217 | grpc_schedule_on_exec_ctx); |
Craig Tiller | 73122ba | 2016-12-05 08:16:58 -0800 | [diff] [blame] | 218 | err = grpc_tcp_server_create(exec_ctx, &state->tcp_server_shutdown_complete, |
| 219 | args, &tcp_server); |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 220 | if (err != GRPC_ERROR_NONE) { |
| 221 | goto error; |
| 222 | } |
| 223 | |
| 224 | state->server = server; |
| 225 | state->tcp_server = tcp_server; |
| 226 | state->args = args; |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 227 | state->shutdown = true; |
| 228 | gpr_mu_init(&state->mu); |
| 229 | |
Yash Tibrewal | 533d118 | 2017-09-18 10:48:22 -0700 | [diff] [blame] | 230 | naddrs = resolved->naddrs; |
Yash Tibrewal | ca3c1c0 | 2017-09-07 22:47:16 -0700 | [diff] [blame] | 231 | errors = (grpc_error **)gpr_malloc(sizeof(*errors) * naddrs); |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 232 | for (i = 0; i < naddrs; i++) { |
| 233 | errors[i] = |
| 234 | grpc_tcp_server_add_port(tcp_server, &resolved->addrs[i], &port_temp); |
| 235 | if (errors[i] == GRPC_ERROR_NONE) { |
| 236 | if (*port_num == -1) { |
| 237 | *port_num = port_temp; |
| 238 | } else { |
| 239 | GPR_ASSERT(*port_num == port_temp); |
| 240 | } |
| 241 | count++; |
| 242 | } |
| 243 | } |
| 244 | if (count == 0) { |
| 245 | char *msg; |
| 246 | gpr_asprintf(&msg, "No address added out of total %" PRIuPTR " resolved", |
| 247 | naddrs); |
ncteisen | 4b36a3d | 2017-03-13 19:08:06 -0700 | [diff] [blame] | 248 | err = GRPC_ERROR_CREATE_REFERENCING_FROM_COPIED_STRING(msg, errors, naddrs); |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 249 | gpr_free(msg); |
| 250 | goto error; |
| 251 | } else if (count != naddrs) { |
| 252 | char *msg; |
| 253 | gpr_asprintf(&msg, "Only %" PRIuPTR |
| 254 | " addresses added out of total %" PRIuPTR " resolved", |
| 255 | count, naddrs); |
ncteisen | 4b36a3d | 2017-03-13 19:08:06 -0700 | [diff] [blame] | 256 | err = GRPC_ERROR_CREATE_REFERENCING_FROM_COPIED_STRING(msg, errors, naddrs); |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 257 | gpr_free(msg); |
| 258 | |
| 259 | const char *warning_message = grpc_error_string(err); |
| 260 | gpr_log(GPR_INFO, "WARNING: %s", warning_message); |
Craig Tiller | 7c70b6c | 2017-01-23 07:48:42 -0800 | [diff] [blame] | 261 | |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 262 | /* we managed to bind some addresses: continue */ |
| 263 | } |
| 264 | grpc_resolved_addresses_destroy(resolved); |
| 265 | |
| 266 | /* Register with the server only upon success */ |
| 267 | grpc_server_add_listener(exec_ctx, server, state, server_start_listener, |
| 268 | server_destroy_listener); |
| 269 | goto done; |
| 270 | |
| 271 | /* Error path: cleanup and return */ |
| 272 | error: |
| 273 | GPR_ASSERT(err != GRPC_ERROR_NONE); |
| 274 | if (resolved) { |
| 275 | grpc_resolved_addresses_destroy(resolved); |
| 276 | } |
| 277 | if (tcp_server) { |
| 278 | grpc_tcp_server_unref(exec_ctx, tcp_server); |
Mark D. Roth | 0f4bbba | 2016-12-02 22:16:03 +0000 | [diff] [blame] | 279 | } else { |
Craig Tiller | 397bff3 | 2016-12-06 15:05:59 -0800 | [diff] [blame] | 280 | grpc_channel_args_destroy(exec_ctx, args); |
Mark D. Roth | 0f4bbba | 2016-12-02 22:16:03 +0000 | [diff] [blame] | 281 | gpr_free(state); |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 282 | } |
Mark D. Roth | 7140382 | 2016-12-02 10:51:39 -0800 | [diff] [blame] | 283 | *port_num = 0; |
| 284 | |
| 285 | done: |
| 286 | if (errors != NULL) { |
| 287 | for (i = 0; i < naddrs; i++) { |
| 288 | GRPC_ERROR_UNREF(errors[i]); |
| 289 | } |
| 290 | gpr_free(errors); |
| 291 | } |
| 292 | return err; |
| 293 | } |