Line data Source code
1 : /*
2 : *
3 : * Copyright 2015, 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 :
34 : #include <grpc/grpc.h>
35 :
36 : #include <string.h>
37 :
38 : #include "src/core/channel/channel_args.h"
39 : #include "src/core/channel/http_server_filter.h"
40 : #include "src/core/iomgr/endpoint.h"
41 : #include "src/core/iomgr/resolve_address.h"
42 : #include "src/core/iomgr/tcp_server.h"
43 : #include "src/core/security/auth_filters.h"
44 : #include "src/core/security/credentials.h"
45 : #include "src/core/security/security_connector.h"
46 : #include "src/core/security/security_context.h"
47 : #include "src/core/surface/api_trace.h"
48 : #include "src/core/surface/server.h"
49 : #include "src/core/transport/chttp2_transport.h"
50 : #include <grpc/support/alloc.h>
51 : #include <grpc/support/log.h>
52 : #include <grpc/support/sync.h>
53 : #include <grpc/support/useful.h>
54 :
55 : typedef struct tcp_endpoint_list {
56 : grpc_endpoint *tcp_endpoint;
57 : struct tcp_endpoint_list *next;
58 : } tcp_endpoint_list;
59 :
60 : typedef struct grpc_server_secure_state {
61 : grpc_server *server;
62 : grpc_tcp_server *tcp;
63 : grpc_security_connector *sc;
64 : grpc_server_credentials *creds;
65 : tcp_endpoint_list *handshaking_tcp_endpoints;
66 : int is_shutdown;
67 : gpr_mu mu;
68 : gpr_refcount refcount;
69 : grpc_closure destroy_closure;
70 : grpc_closure *destroy_callback;
71 : } grpc_server_secure_state;
72 :
73 451 : static void state_ref(grpc_server_secure_state *state) {
74 451 : gpr_ref(&state->refcount);
75 451 : }
76 :
77 974 : static void state_unref(grpc_server_secure_state *state) {
78 974 : if (gpr_unref(&state->refcount)) {
79 : /* ensure all threads have unlocked */
80 523 : gpr_mu_lock(&state->mu);
81 523 : gpr_mu_unlock(&state->mu);
82 : /* clean up */
83 523 : GRPC_SECURITY_CONNECTOR_UNREF(state->sc, "server");
84 523 : grpc_server_credentials_unref(state->creds);
85 523 : gpr_free(state);
86 : }
87 974 : }
88 :
89 440 : static void setup_transport(grpc_exec_ctx *exec_ctx, void *statep,
90 : grpc_transport *transport, grpc_mdctx *mdctx) {
91 : static grpc_channel_filter const *extra_filters[] = {
92 : &grpc_server_auth_filter, &grpc_http_server_filter};
93 440 : grpc_server_secure_state *state = statep;
94 : grpc_channel_args *args_copy;
95 : grpc_arg args_to_add[2];
96 440 : args_to_add[0] = grpc_server_credentials_to_arg(state->creds);
97 440 : args_to_add[1] =
98 440 : grpc_auth_context_to_arg(state->sc->auth_context);
99 440 : args_copy = grpc_channel_args_copy_and_add(
100 : grpc_server_get_channel_args(state->server), args_to_add,
101 : GPR_ARRAY_SIZE(args_to_add));
102 440 : grpc_server_setup_transport(exec_ctx, state->server, transport, extra_filters,
103 : GPR_ARRAY_SIZE(extra_filters), mdctx, args_copy);
104 440 : grpc_channel_args_destroy(args_copy);
105 440 : }
106 :
107 462 : static int remove_tcp_from_list_locked(grpc_server_secure_state *state,
108 : grpc_endpoint *tcp) {
109 462 : tcp_endpoint_list *node = state->handshaking_tcp_endpoints;
110 462 : tcp_endpoint_list *tmp = NULL;
111 462 : if (node && node->tcp_endpoint == tcp) {
112 451 : state->handshaking_tcp_endpoints = state->handshaking_tcp_endpoints->next;
113 451 : gpr_free(node);
114 451 : return 0;
115 : }
116 22 : while (node) {
117 0 : if (node->next->tcp_endpoint == tcp) {
118 0 : tmp = node->next;
119 0 : node->next = node->next->next;
120 0 : gpr_free(tmp);
121 0 : return 0;
122 : }
123 0 : node = node->next;
124 : }
125 11 : return -1;
126 : }
127 :
128 451 : static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *statep,
129 : grpc_security_status status,
130 : grpc_endpoint *wrapped_endpoint,
131 : grpc_endpoint *secure_endpoint) {
132 451 : grpc_server_secure_state *state = statep;
133 : grpc_transport *transport;
134 : grpc_mdctx *mdctx;
135 451 : if (status == GRPC_SECURITY_OK) {
136 440 : gpr_mu_lock(&state->mu);
137 440 : remove_tcp_from_list_locked(state, wrapped_endpoint);
138 440 : if (!state->is_shutdown) {
139 440 : mdctx = grpc_mdctx_create();
140 440 : transport = grpc_create_chttp2_transport(
141 : exec_ctx, grpc_server_get_channel_args(state->server),
142 : secure_endpoint, mdctx, 0);
143 440 : setup_transport(exec_ctx, state, transport, mdctx);
144 440 : grpc_chttp2_transport_start_reading(exec_ctx, transport, NULL, 0);
145 : } else {
146 : /* We need to consume this here, because the server may already have gone
147 : * away. */
148 0 : grpc_endpoint_destroy(exec_ctx, secure_endpoint);
149 : }
150 440 : gpr_mu_unlock(&state->mu);
151 : } else {
152 11 : gpr_mu_lock(&state->mu);
153 11 : remove_tcp_from_list_locked(state, wrapped_endpoint);
154 11 : gpr_mu_unlock(&state->mu);
155 11 : gpr_log(GPR_ERROR, "Secure transport failed with error %d", status);
156 : }
157 451 : state_unref(state);
158 451 : }
159 :
160 451 : static void on_accept(grpc_exec_ctx *exec_ctx, void *statep,
161 : grpc_endpoint *tcp) {
162 451 : grpc_server_secure_state *state = statep;
163 : tcp_endpoint_list *node;
164 451 : state_ref(state);
165 451 : node = gpr_malloc(sizeof(tcp_endpoint_list));
166 451 : node->tcp_endpoint = tcp;
167 451 : gpr_mu_lock(&state->mu);
168 451 : node->next = state->handshaking_tcp_endpoints;
169 451 : state->handshaking_tcp_endpoints = node;
170 451 : gpr_mu_unlock(&state->mu);
171 451 : grpc_security_connector_do_handshake(exec_ctx, state->sc, tcp,
172 : on_secure_handshake_done, state);
173 451 : }
174 :
175 : /* Server callback: start listening on our ports */
176 523 : static void start(grpc_exec_ctx *exec_ctx, grpc_server *server, void *statep,
177 : grpc_pollset **pollsets, size_t pollset_count) {
178 523 : grpc_server_secure_state *state = statep;
179 523 : grpc_tcp_server_start(exec_ctx, state->tcp, pollsets, pollset_count,
180 : on_accept, state);
181 523 : }
182 :
183 523 : static void destroy_done(grpc_exec_ctx *exec_ctx, void *statep, int success) {
184 523 : grpc_server_secure_state *state = statep;
185 523 : state->destroy_callback->cb(exec_ctx, state->destroy_callback->cb_arg,
186 : success);
187 523 : gpr_mu_lock(&state->mu);
188 1057 : while (state->handshaking_tcp_endpoints != NULL) {
189 11 : grpc_endpoint_shutdown(exec_ctx,
190 11 : state->handshaking_tcp_endpoints->tcp_endpoint);
191 11 : remove_tcp_from_list_locked(state,
192 11 : state->handshaking_tcp_endpoints->tcp_endpoint);
193 : }
194 523 : gpr_mu_unlock(&state->mu);
195 523 : state_unref(state);
196 523 : }
197 :
198 : /* Server callback: destroy the tcp listener (so we don't generate further
199 : callbacks) */
200 523 : static void destroy(grpc_exec_ctx *exec_ctx, grpc_server *server, void *statep,
201 : grpc_closure *callback) {
202 523 : grpc_server_secure_state *state = statep;
203 : grpc_tcp_server *tcp;
204 523 : gpr_mu_lock(&state->mu);
205 523 : state->is_shutdown = 1;
206 523 : state->destroy_callback = callback;
207 523 : tcp = state->tcp;
208 523 : gpr_mu_unlock(&state->mu);
209 523 : grpc_closure_init(&state->destroy_closure, destroy_done, state);
210 523 : grpc_tcp_server_destroy(exec_ctx, tcp, &state->destroy_closure);
211 523 : }
212 :
213 523 : int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
214 : grpc_server_credentials *creds) {
215 523 : grpc_resolved_addresses *resolved = NULL;
216 523 : grpc_tcp_server *tcp = NULL;
217 523 : grpc_server_secure_state *state = NULL;
218 : size_t i;
219 523 : unsigned count = 0;
220 523 : int port_num = -1;
221 : int port_temp;
222 523 : grpc_security_status status = GRPC_SECURITY_ERROR;
223 523 : grpc_security_connector *sc = NULL;
224 523 : grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
225 :
226 523 : GRPC_API_TRACE(
227 : "grpc_server_add_secure_http2_port("
228 : "server=%p, addr=%s, creds=%p)",
229 : 3, (server, addr, creds));
230 :
231 : /* create security context */
232 523 : if (creds == NULL) goto error;
233 523 : status = grpc_server_credentials_create_security_connector(creds, &sc);
234 523 : if (status != GRPC_SECURITY_OK) {
235 0 : gpr_log(GPR_ERROR,
236 : "Unable to create secure server with credentials of type %s.",
237 : creds->type);
238 0 : goto error;
239 : }
240 :
241 : /* resolve address */
242 523 : resolved = grpc_blocking_resolve_address(addr, "https");
243 523 : if (!resolved) {
244 0 : goto error;
245 : }
246 :
247 523 : tcp = grpc_tcp_server_create();
248 523 : if (!tcp) {
249 0 : goto error;
250 : }
251 :
252 1046 : for (i = 0; i < resolved->naddrs; i++) {
253 1046 : port_temp = grpc_tcp_server_add_port(
254 523 : tcp, (struct sockaddr *)&resolved->addrs[i].addr,
255 523 : resolved->addrs[i].len);
256 523 : if (port_temp >= 0) {
257 523 : if (port_num == -1) {
258 523 : port_num = port_temp;
259 : } else {
260 0 : GPR_ASSERT(port_num == port_temp);
261 : }
262 523 : count++;
263 : }
264 : }
265 523 : if (count == 0) {
266 0 : gpr_log(GPR_ERROR, "No address added out of total %d resolved",
267 : resolved->naddrs);
268 0 : goto error;
269 : }
270 523 : if (count != resolved->naddrs) {
271 0 : gpr_log(GPR_ERROR, "Only %d addresses added out of total %d resolved",
272 : count, resolved->naddrs);
273 : /* if it's an error, don't we want to goto error; here ? */
274 : }
275 523 : grpc_resolved_addresses_destroy(resolved);
276 :
277 523 : state = gpr_malloc(sizeof(*state));
278 523 : memset(state, 0, sizeof(*state));
279 523 : state->server = server;
280 523 : state->tcp = tcp;
281 523 : state->sc = sc;
282 523 : state->creds = grpc_server_credentials_ref(creds);
283 :
284 523 : state->handshaking_tcp_endpoints = NULL;
285 523 : state->is_shutdown = 0;
286 523 : gpr_mu_init(&state->mu);
287 523 : gpr_ref_init(&state->refcount, 1);
288 :
289 : /* Register with the server only upon success */
290 523 : grpc_server_add_listener(&exec_ctx, server, state, start, destroy);
291 :
292 523 : grpc_exec_ctx_finish(&exec_ctx);
293 523 : return port_num;
294 :
295 : /* Error path: cleanup and return */
296 : error:
297 0 : if (sc) {
298 0 : GRPC_SECURITY_CONNECTOR_UNREF(sc, "server");
299 : }
300 0 : if (resolved) {
301 0 : grpc_resolved_addresses_destroy(resolved);
302 : }
303 0 : if (tcp) {
304 0 : grpc_tcp_server_destroy(&exec_ctx, tcp, NULL);
305 : }
306 0 : if (state) {
307 0 : gpr_free(state);
308 : }
309 0 : grpc_exec_ctx_finish(&exec_ctx);
310 0 : return 0;
311 : }
|