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 grpc_server_secure_state {
56 : grpc_server *server;
57 : grpc_tcp_server *tcp;
58 : grpc_security_connector *sc;
59 : grpc_server_credentials *creds;
60 : int is_shutdown;
61 : gpr_mu mu;
62 : gpr_refcount refcount;
63 : grpc_closure destroy_closure;
64 : grpc_closure *destroy_callback;
65 : } grpc_server_secure_state;
66 :
67 578 : static void state_ref(grpc_server_secure_state *state) {
68 595 : gpr_ref(&state->refcount);
69 578 : }
70 :
71 1299 : static void state_unref(grpc_server_secure_state *state) {
72 1299 : if (gpr_unref(&state->refcount)) {
73 : /* ensure all threads have unlocked */
74 704 : gpr_mu_lock(&state->mu);
75 704 : gpr_mu_unlock(&state->mu);
76 : /* clean up */
77 704 : GRPC_SECURITY_CONNECTOR_UNREF(state->sc, "server");
78 704 : grpc_server_credentials_unref(state->creds);
79 704 : gpr_free(state);
80 : }
81 1299 : }
82 :
83 590 : static void setup_transport(grpc_exec_ctx *exec_ctx, void *statep,
84 : grpc_transport *transport) {
85 : static grpc_channel_filter const *extra_filters[] = {
86 : &grpc_server_auth_filter, &grpc_http_server_filter};
87 573 : grpc_server_secure_state *state = statep;
88 : grpc_channel_args *args_copy;
89 : grpc_arg args_to_add[2];
90 590 : args_to_add[0] = grpc_server_credentials_to_arg(state->creds);
91 590 : args_to_add[1] = grpc_auth_context_to_arg(state->sc->auth_context);
92 590 : args_copy = grpc_channel_args_copy_and_add(
93 : grpc_server_get_channel_args(state->server), args_to_add,
94 : GPR_ARRAY_SIZE(args_to_add));
95 590 : grpc_server_setup_transport(exec_ctx, state->server, transport, extra_filters,
96 : GPR_ARRAY_SIZE(extra_filters), args_copy);
97 590 : grpc_channel_args_destroy(args_copy);
98 590 : }
99 :
100 595 : static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *statep,
101 : grpc_security_status status,
102 : grpc_endpoint *secure_endpoint) {
103 578 : grpc_server_secure_state *state = statep;
104 : grpc_transport *transport;
105 595 : if (status == GRPC_SECURITY_OK) {
106 590 : if (secure_endpoint) {
107 590 : gpr_mu_lock(&state->mu);
108 590 : if (!state->is_shutdown) {
109 590 : transport = grpc_create_chttp2_transport(
110 : exec_ctx, grpc_server_get_channel_args(state->server),
111 : secure_endpoint, 0);
112 590 : setup_transport(exec_ctx, state, transport);
113 590 : grpc_chttp2_transport_start_reading(exec_ctx, transport, NULL, 0);
114 : } else {
115 : /* We need to consume this here, because the server may already have
116 : * gone away. */
117 0 : grpc_endpoint_destroy(exec_ctx, secure_endpoint);
118 : }
119 590 : gpr_mu_unlock(&state->mu);
120 : }
121 : } else {
122 5 : gpr_log(GPR_ERROR, "Secure transport failed with error %d", status);
123 : }
124 595 : state_unref(state);
125 595 : }
126 :
127 595 : static void on_accept(grpc_exec_ctx *exec_ctx, void *statep,
128 : grpc_endpoint *tcp) {
129 578 : grpc_server_secure_state *state = statep;
130 578 : state_ref(state);
131 595 : grpc_security_connector_do_handshake(exec_ctx, state->sc, tcp,
132 : on_secure_handshake_done, state);
133 595 : }
134 :
135 : /* Server callback: start listening on our ports */
136 704 : static void start(grpc_exec_ctx *exec_ctx, grpc_server *server, void *statep,
137 : grpc_pollset **pollsets, size_t pollset_count) {
138 702 : grpc_server_secure_state *state = statep;
139 704 : grpc_tcp_server_start(exec_ctx, state->tcp, pollsets, pollset_count,
140 : on_accept, state);
141 704 : }
142 :
143 704 : static void destroy_done(grpc_exec_ctx *exec_ctx, void *statep, int success) {
144 702 : grpc_server_secure_state *state = statep;
145 704 : state->destroy_callback->cb(exec_ctx, state->destroy_callback->cb_arg,
146 : success);
147 704 : grpc_security_connector_shutdown(exec_ctx, state->sc);
148 704 : state_unref(state);
149 704 : }
150 :
151 : /* Server callback: destroy the tcp listener (so we don't generate further
152 : callbacks) */
153 704 : static void destroy(grpc_exec_ctx *exec_ctx, grpc_server *server, void *statep,
154 : grpc_closure *callback) {
155 702 : grpc_server_secure_state *state = statep;
156 : grpc_tcp_server *tcp;
157 704 : gpr_mu_lock(&state->mu);
158 704 : state->is_shutdown = 1;
159 704 : state->destroy_callback = callback;
160 704 : tcp = state->tcp;
161 704 : gpr_mu_unlock(&state->mu);
162 704 : grpc_closure_init(&state->destroy_closure, destroy_done, state);
163 704 : grpc_tcp_server_destroy(exec_ctx, tcp, &state->destroy_closure);
164 704 : }
165 :
166 705 : int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
167 : grpc_server_credentials *creds) {
168 702 : grpc_resolved_addresses *resolved = NULL;
169 702 : grpc_tcp_server *tcp = NULL;
170 702 : grpc_server_secure_state *state = NULL;
171 : size_t i;
172 702 : unsigned count = 0;
173 702 : int port_num = -1;
174 : int port_temp;
175 702 : grpc_security_status status = GRPC_SECURITY_ERROR;
176 705 : grpc_security_connector *sc = NULL;
177 705 : grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
178 :
179 705 : GRPC_API_TRACE(
180 : "grpc_server_add_secure_http2_port("
181 : "server=%p, addr=%s, creds=%p)",
182 : 3, (server, addr, creds));
183 :
184 : /* create security context */
185 705 : if (creds == NULL) goto error;
186 705 : status = grpc_server_credentials_create_security_connector(creds, &sc);
187 705 : if (status != GRPC_SECURITY_OK) {
188 0 : gpr_log(GPR_ERROR,
189 : "Unable to create secure server with credentials of type %s.",
190 : creds->type);
191 0 : goto error;
192 : }
193 705 : sc->channel_args = grpc_server_get_channel_args(server);
194 :
195 : /* resolve address */
196 705 : resolved = grpc_blocking_resolve_address(addr, "https");
197 705 : if (!resolved) {
198 0 : goto error;
199 : }
200 :
201 705 : tcp = grpc_tcp_server_create();
202 705 : if (!tcp) {
203 0 : goto error;
204 : }
205 :
206 2061 : for (i = 0; i < resolved->naddrs; i++) {
207 : grpc_tcp_listener *listener;
208 2718 : listener = grpc_tcp_server_add_port(
209 1359 : tcp, (struct sockaddr *)&resolved->addrs[i].addr,
210 1359 : resolved->addrs[i].len);
211 1359 : port_temp = grpc_tcp_listener_get_port(listener);
212 1359 : if (port_temp >= 0) {
213 1359 : if (port_num == -1) {
214 702 : port_num = port_temp;
215 : } else {
216 654 : GPR_ASSERT(port_num == port_temp);
217 : }
218 1359 : count++;
219 : }
220 : }
221 705 : if (count == 0) {
222 0 : gpr_log(GPR_ERROR, "No address added out of total %d resolved",
223 : resolved->naddrs);
224 0 : goto error;
225 : }
226 705 : if (count != resolved->naddrs) {
227 0 : gpr_log(GPR_ERROR, "Only %d addresses added out of total %d resolved",
228 : count, resolved->naddrs);
229 : /* if it's an error, don't we want to goto error; here ? */
230 : }
231 705 : grpc_resolved_addresses_destroy(resolved);
232 :
233 705 : state = gpr_malloc(sizeof(*state));
234 705 : memset(state, 0, sizeof(*state));
235 705 : state->server = server;
236 705 : state->tcp = tcp;
237 705 : state->sc = sc;
238 705 : state->creds = grpc_server_credentials_ref(creds);
239 :
240 705 : state->is_shutdown = 0;
241 705 : gpr_mu_init(&state->mu);
242 705 : gpr_ref_init(&state->refcount, 1);
243 :
244 : /* Register with the server only upon success */
245 705 : grpc_server_add_listener(&exec_ctx, server, state, start, destroy);
246 :
247 705 : grpc_exec_ctx_finish(&exec_ctx);
248 705 : return port_num;
249 :
250 : /* Error path: cleanup and return */
251 : error:
252 0 : if (sc) {
253 0 : GRPC_SECURITY_CONNECTOR_UNREF(sc, "server");
254 : }
255 0 : if (resolved) {
256 0 : grpc_resolved_addresses_destroy(resolved);
257 : }
258 0 : if (tcp) {
259 0 : grpc_tcp_server_destroy(&exec_ctx, tcp, NULL);
260 : }
261 0 : if (state) {
262 0 : gpr_free(state);
263 : }
264 0 : grpc_exec_ctx_finish(&exec_ctx);
265 0 : return 0;
266 : }
|