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 "src/core/iomgr/sockaddr.h"
35 : #include "src/core/transport/metadata.h"
36 :
37 : #include <assert.h>
38 : #include <stddef.h>
39 : #include <string.h>
40 :
41 : #include <grpc/support/alloc.h>
42 : #include <grpc/support/atm.h>
43 : #include <grpc/support/log.h>
44 : #include "src/core/support/murmur_hash.h"
45 : #include "src/core/transport/chttp2/bin_encoder.h"
46 : #include <grpc/support/time.h>
47 :
48 : #define INITIAL_STRTAB_CAPACITY 4
49 : #define INITIAL_MDTAB_CAPACITY 4
50 :
51 : #ifdef GRPC_METADATA_REFCOUNT_DEBUG
52 : #define DEBUG_ARGS , const char *file, int line
53 : #define FWD_DEBUG_ARGS , file, line
54 : #define INTERNAL_STRING_REF(s) internal_string_ref((s), __FILE__, __LINE__)
55 : #define INTERNAL_STRING_UNREF(s) internal_string_unref((s), __FILE__, __LINE__)
56 : #define REF_MD_LOCKED(s) ref_md_locked((s), __FILE__, __LINE__)
57 : #else
58 : #define DEBUG_ARGS
59 : #define FWD_DEBUG_ARGS
60 : #define INTERNAL_STRING_REF(s) internal_string_ref((s))
61 : #define INTERNAL_STRING_UNREF(s) internal_string_unref((s))
62 : #define REF_MD_LOCKED(s) ref_md_locked((s))
63 : #endif
64 :
65 : typedef struct internal_string {
66 : /* must be byte compatible with grpc_mdstr */
67 : gpr_slice slice;
68 : gpr_uint32 hash;
69 :
70 : /* private only data */
71 : gpr_uint32 refs;
72 : gpr_uint8 has_base64_and_huffman_encoded;
73 : gpr_slice_refcount refcount;
74 :
75 : gpr_slice base64_and_huffman;
76 :
77 : grpc_mdctx *context;
78 :
79 : struct internal_string *bucket_next;
80 : } internal_string;
81 :
82 : typedef struct internal_metadata {
83 : /* must be byte compatible with grpc_mdelem */
84 : internal_string *key;
85 : internal_string *value;
86 :
87 : gpr_atm refcnt;
88 :
89 : /* private only data */
90 : gpr_mu mu_user_data;
91 : void *user_data;
92 : void (*destroy_user_data)(void *user_data);
93 :
94 : grpc_mdctx *context;
95 : struct internal_metadata *bucket_next;
96 : } internal_metadata;
97 :
98 : struct grpc_mdctx {
99 : gpr_uint32 hash_seed;
100 : int refs;
101 :
102 : gpr_mu mu;
103 :
104 : internal_string **strtab;
105 : size_t strtab_count;
106 : size_t strtab_capacity;
107 :
108 : internal_metadata **mdtab;
109 : size_t mdtab_count;
110 : size_t mdtab_free;
111 : size_t mdtab_capacity;
112 : };
113 :
114 : static void internal_string_ref(internal_string *s DEBUG_ARGS);
115 : static void internal_string_unref(internal_string *s DEBUG_ARGS);
116 : static void discard_metadata(grpc_mdctx *ctx);
117 : static void gc_mdtab(grpc_mdctx *ctx);
118 : static void metadata_context_destroy_locked(grpc_mdctx *ctx);
119 :
120 23593136 : static void lock(grpc_mdctx *ctx) { gpr_mu_lock(&ctx->mu); }
121 :
122 23654471 : static void unlock(grpc_mdctx *ctx) {
123 : /* If the context has been orphaned we'd like to delete it soon. We check
124 : conditions in unlock as it signals the end of mutations on a context.
125 :
126 : We need to ensure all grpc_mdelem and grpc_mdstr elements have been deleted
127 : first. This is equivalent to saying that both tables have zero counts,
128 : which is equivalent to saying that strtab_count is zero (as mdelem's MUST
129 : reference an mdstr for their key and value slots).
130 :
131 : To encourage that to happen, we start discarding zero reference count
132 : mdelems on every unlock (instead of the usual 'I'm too loaded' trigger
133 : case), since otherwise we can be stuck waiting for a garbage collection
134 : that will never happen. */
135 23654471 : if (ctx->refs == 0) {
136 : /* uncomment if you're having trouble diagnosing an mdelem leak to make
137 : things clearer (slows down destruction a lot, however) */
138 : #ifdef GRPC_METADATA_REFCOUNT_DEBUG
139 : gc_mdtab(ctx);
140 : #endif
141 4476 : if (ctx->mdtab_count && ctx->mdtab_count == ctx->mdtab_free) {
142 4251 : discard_metadata(ctx);
143 : }
144 4476 : if (ctx->strtab_count == 0) {
145 4258 : metadata_context_destroy_locked(ctx);
146 23674751 : return;
147 : }
148 : }
149 23650213 : gpr_mu_unlock(&ctx->mu);
150 : }
151 :
152 667228 : static void ref_md_locked(internal_metadata *md DEBUG_ARGS) {
153 : #ifdef GRPC_METADATA_REFCOUNT_DEBUG
154 : gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
155 : "ELM REF:%p:%d->%d: '%s' = '%s'", md,
156 : gpr_atm_no_barrier_load(&md->refcnt),
157 : gpr_atm_no_barrier_load(&md->refcnt) + 1,
158 : grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
159 : grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
160 : #endif
161 667228 : if (0 == gpr_atm_no_barrier_fetch_add(&md->refcnt, 1)) {
162 108993 : md->context->mdtab_free--;
163 : }
164 667228 : }
165 :
166 4258 : grpc_mdctx *grpc_mdctx_create_with_seed(gpr_uint32 seed) {
167 4258 : grpc_mdctx *ctx = gpr_malloc(sizeof(grpc_mdctx));
168 :
169 4258 : ctx->refs = 1;
170 4258 : ctx->hash_seed = seed;
171 4258 : gpr_mu_init(&ctx->mu);
172 4258 : ctx->strtab = gpr_malloc(sizeof(internal_string *) * INITIAL_STRTAB_CAPACITY);
173 4258 : memset(ctx->strtab, 0, sizeof(grpc_mdstr *) * INITIAL_STRTAB_CAPACITY);
174 4258 : ctx->strtab_count = 0;
175 4258 : ctx->strtab_capacity = INITIAL_STRTAB_CAPACITY;
176 4258 : ctx->mdtab = gpr_malloc(sizeof(internal_metadata *) * INITIAL_MDTAB_CAPACITY);
177 4258 : memset(ctx->mdtab, 0, sizeof(grpc_mdelem *) * INITIAL_MDTAB_CAPACITY);
178 4258 : ctx->mdtab_count = 0;
179 4258 : ctx->mdtab_capacity = INITIAL_MDTAB_CAPACITY;
180 4258 : ctx->mdtab_free = 0;
181 :
182 4258 : return ctx;
183 : }
184 :
185 4244 : grpc_mdctx *grpc_mdctx_create(void) {
186 : /* This seed is used to prevent remote connections from controlling hash table
187 : * collisions. It needs to be somewhat unpredictable to a remote connection.
188 : */
189 4244 : return grpc_mdctx_create_with_seed(
190 4244 : (gpr_uint32)gpr_now(GPR_CLOCK_REALTIME).tv_nsec);
191 : }
192 :
193 4251 : static void discard_metadata(grpc_mdctx *ctx) {
194 : size_t i;
195 : internal_metadata *next, *cur;
196 :
197 263403 : for (i = 0; i < ctx->mdtab_capacity; i++) {
198 259152 : cur = ctx->mdtab[i];
199 828426 : while (cur) {
200 310122 : GPR_ASSERT(gpr_atm_acq_load(&cur->refcnt) == 0);
201 310121 : next = cur->bucket_next;
202 310121 : INTERNAL_STRING_UNREF(cur->key);
203 310118 : INTERNAL_STRING_UNREF(cur->value);
204 310118 : if (cur->user_data) {
205 8487 : cur->destroy_user_data(cur->user_data);
206 : }
207 310118 : gpr_mu_destroy(&cur->mu_user_data);
208 310119 : gpr_free(cur);
209 310122 : cur = next;
210 310122 : ctx->mdtab_free--;
211 310122 : ctx->mdtab_count--;
212 : }
213 259152 : ctx->mdtab[i] = NULL;
214 : }
215 4251 : }
216 :
217 4258 : static void metadata_context_destroy_locked(grpc_mdctx *ctx) {
218 4258 : GPR_ASSERT(ctx->strtab_count == 0);
219 4258 : GPR_ASSERT(ctx->mdtab_count == 0);
220 4258 : GPR_ASSERT(ctx->mdtab_free == 0);
221 4258 : gpr_free(ctx->strtab);
222 4258 : gpr_free(ctx->mdtab);
223 4258 : gpr_mu_unlock(&ctx->mu);
224 4258 : gpr_mu_destroy(&ctx->mu);
225 4258 : gpr_free(ctx);
226 4258 : }
227 :
228 8715 : void grpc_mdctx_ref(grpc_mdctx *ctx) {
229 8715 : lock(ctx);
230 8715 : GPR_ASSERT(ctx->refs > 0);
231 8715 : ctx->refs++;
232 8715 : unlock(ctx);
233 8715 : }
234 :
235 12973 : void grpc_mdctx_unref(grpc_mdctx *ctx) {
236 12973 : lock(ctx);
237 12973 : GPR_ASSERT(ctx->refs > 0);
238 12973 : ctx->refs--;
239 12973 : unlock(ctx);
240 12973 : }
241 :
242 16148 : static void grow_strtab(grpc_mdctx *ctx) {
243 16148 : size_t capacity = ctx->strtab_capacity * 2;
244 : size_t i;
245 16148 : internal_string **strtab = gpr_malloc(sizeof(internal_string *) * capacity);
246 : internal_string *s, *next;
247 16146 : memset(strtab, 0, sizeof(internal_string *) * capacity);
248 :
249 266304 : for (i = 0; i < ctx->strtab_capacity; i++) {
250 766229 : for (s = ctx->strtab[i]; s; s = next) {
251 516071 : next = s->bucket_next;
252 516071 : s->bucket_next = strtab[s->hash % capacity];
253 516071 : strtab[s->hash % capacity] = s;
254 : }
255 : }
256 :
257 16146 : gpr_free(ctx->strtab);
258 16147 : ctx->strtab = strtab;
259 16147 : ctx->strtab_capacity = capacity;
260 16147 : }
261 :
262 2549240 : static void internal_destroy_string(internal_string *is) {
263 : internal_string **prev_next;
264 : internal_string *cur;
265 2549240 : grpc_mdctx *ctx = is->context;
266 2549240 : if (is->has_base64_and_huffman_encoded) {
267 111 : gpr_slice_unref(is->base64_and_huffman);
268 : }
269 9486150 : for (prev_next = &ctx->strtab[is->hash % ctx->strtab_capacity],
270 2549245 : cur = *prev_next;
271 1838415 : cur != is; prev_next = &cur->bucket_next, cur = cur->bucket_next)
272 : ;
273 2549245 : *prev_next = cur->bucket_next;
274 2549245 : ctx->strtab_count--;
275 2549245 : gpr_free(is);
276 2549250 : }
277 :
278 5313097 : static void internal_string_ref(internal_string *s DEBUG_ARGS) {
279 : #ifdef GRPC_METADATA_REFCOUNT_DEBUG
280 : gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "STR REF:%p:%d->%d: '%s'", s,
281 : s->refs, s->refs + 1, grpc_mdstr_as_c_string((grpc_mdstr *)s));
282 : #endif
283 5313097 : ++s->refs;
284 5313097 : }
285 :
286 7861825 : static void internal_string_unref(internal_string *s DEBUG_ARGS) {
287 : #ifdef GRPC_METADATA_REFCOUNT_DEBUG
288 : gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "STR UNREF:%p:%d->%d: '%s'", s,
289 : s->refs, s->refs - 1, grpc_mdstr_as_c_string((grpc_mdstr *)s));
290 : #endif
291 7861825 : GPR_ASSERT(s->refs > 0);
292 7861825 : if (0 == --s->refs) {
293 2549240 : internal_destroy_string(s);
294 : }
295 7861833 : }
296 :
297 81468 : static void slice_ref(void *p) {
298 81468 : internal_string *is =
299 : (internal_string *)((char *)p - offsetof(internal_string, refcount));
300 81468 : grpc_mdctx *ctx = is->context;
301 81468 : lock(ctx);
302 81468 : INTERNAL_STRING_REF(is);
303 81468 : unlock(ctx);
304 81468 : }
305 :
306 81468 : static void slice_unref(void *p) {
307 81468 : internal_string *is =
308 : (internal_string *)((char *)p - offsetof(internal_string, refcount));
309 81468 : grpc_mdctx *ctx = is->context;
310 81468 : lock(ctx);
311 81468 : INTERNAL_STRING_UNREF(is);
312 81468 : unlock(ctx);
313 81468 : }
314 :
315 4510064 : grpc_mdstr *grpc_mdstr_from_string(grpc_mdctx *ctx, const char *str) {
316 4510064 : return grpc_mdstr_from_buffer(ctx, (const gpr_uint8 *)str, strlen(str));
317 : }
318 :
319 292 : grpc_mdstr *grpc_mdstr_from_slice(grpc_mdctx *ctx, gpr_slice slice) {
320 428 : grpc_mdstr *result = grpc_mdstr_from_buffer(ctx, GPR_SLICE_START_PTR(slice),
321 428 : GPR_SLICE_LENGTH(slice));
322 292 : gpr_slice_unref(slice);
323 292 : return result;
324 : }
325 :
326 4768397 : grpc_mdstr *grpc_mdstr_from_buffer(grpc_mdctx *ctx, const gpr_uint8 *buf,
327 : size_t length) {
328 4768397 : gpr_uint32 hash = gpr_murmur_hash3(buf, length, ctx->hash_seed);
329 : internal_string *s;
330 :
331 4768535 : lock(ctx);
332 :
333 : /* search for an existing string */
334 9175412 : for (s = ctx->strtab[hash % ctx->strtab_capacity]; s; s = s->bucket_next) {
335 8846204 : if (s->hash == hash && GPR_SLICE_LENGTH(s->slice) == length &&
336 2220044 : 0 == memcmp(buf, GPR_SLICE_START_PTR(s->slice), length)) {
337 2219967 : INTERNAL_STRING_REF(s);
338 2220012 : unlock(ctx);
339 2220040 : return (grpc_mdstr *)s;
340 : }
341 : }
342 :
343 : /* not found: create a new string */
344 2549252 : if (length + 1 < GPR_SLICE_INLINED_SIZE) {
345 : /* string data goes directly into the slice */
346 2392874 : s = gpr_malloc(sizeof(internal_string));
347 2392795 : s->refs = 1;
348 2392795 : s->slice.refcount = NULL;
349 2392795 : memcpy(s->slice.data.inlined.bytes, buf, length);
350 2392795 : s->slice.data.inlined.bytes[length] = 0;
351 2392795 : s->slice.data.inlined.length = (gpr_uint8)length;
352 : } else {
353 : /* string data goes after the internal_string header, and we +1 for null
354 : terminator */
355 156378 : s = gpr_malloc(sizeof(internal_string) + length + 1);
356 156372 : s->refs = 1;
357 156372 : s->refcount.ref = slice_ref;
358 156372 : s->refcount.unref = slice_unref;
359 156372 : s->slice.refcount = &s->refcount;
360 156372 : s->slice.data.refcounted.bytes = (gpr_uint8 *)(s + 1);
361 156372 : s->slice.data.refcounted.length = length;
362 156372 : memcpy(s->slice.data.refcounted.bytes, buf, length);
363 : /* add a null terminator for cheap c string conversion when desired */
364 156372 : s->slice.data.refcounted.bytes[length] = 0;
365 : }
366 2549167 : s->has_base64_and_huffman_encoded = 0;
367 2549167 : s->hash = hash;
368 2549167 : s->context = ctx;
369 2549167 : s->bucket_next = ctx->strtab[hash % ctx->strtab_capacity];
370 2549167 : ctx->strtab[hash % ctx->strtab_capacity] = s;
371 :
372 2549167 : ctx->strtab_count++;
373 :
374 2549167 : if (ctx->strtab_count > ctx->strtab_capacity * 2) {
375 16148 : grow_strtab(ctx);
376 : }
377 :
378 2549166 : unlock(ctx);
379 :
380 2549234 : return (grpc_mdstr *)s;
381 : }
382 :
383 10440 : static void gc_mdtab(grpc_mdctx *ctx) {
384 : size_t i;
385 : internal_metadata **prev_next;
386 : internal_metadata *md, *next;
387 :
388 1257292 : for (i = 0; i < ctx->mdtab_capacity; i++) {
389 1246852 : prev_next = &ctx->mdtab[i];
390 3750996 : for (md = ctx->mdtab[i]; md; md = next) {
391 2504144 : next = md->bucket_next;
392 2504144 : if (gpr_atm_acq_load(&md->refcnt) == 0) {
393 1120471 : INTERNAL_STRING_UNREF(md->key);
394 1120471 : INTERNAL_STRING_UNREF(md->value);
395 1120471 : if (md->user_data) {
396 0 : md->destroy_user_data(md->user_data);
397 : }
398 1120471 : gpr_free(md);
399 1120471 : *prev_next = next;
400 1120471 : ctx->mdtab_free--;
401 1120471 : ctx->mdtab_count--;
402 : } else {
403 1383673 : prev_next = &md->bucket_next;
404 : }
405 : }
406 : }
407 :
408 10440 : GPR_ASSERT(ctx->mdtab_free == 0);
409 10440 : }
410 :
411 15721 : static void grow_mdtab(grpc_mdctx *ctx) {
412 15721 : size_t capacity = ctx->mdtab_capacity * 2;
413 : size_t i;
414 15721 : internal_metadata **mdtab =
415 15721 : gpr_malloc(sizeof(internal_metadata *) * capacity);
416 : internal_metadata *md, *next;
417 : gpr_uint32 hash;
418 15721 : memset(mdtab, 0, sizeof(internal_metadata *) * capacity);
419 :
420 257652 : for (i = 0; i < ctx->mdtab_capacity; i++) {
421 741202 : for (md = ctx->mdtab[i]; md; md = next) {
422 499271 : hash = GRPC_MDSTR_KV_HASH(md->key->hash, md->value->hash);
423 499271 : next = md->bucket_next;
424 499271 : md->bucket_next = mdtab[hash % capacity];
425 499271 : mdtab[hash % capacity] = md;
426 : }
427 : }
428 :
429 15721 : gpr_free(ctx->mdtab);
430 15721 : ctx->mdtab = mdtab;
431 15721 : ctx->mdtab_capacity = capacity;
432 15721 : }
433 :
434 26161 : static void rehash_mdtab(grpc_mdctx *ctx) {
435 26161 : if (ctx->mdtab_free > ctx->mdtab_capacity / 4) {
436 10440 : gc_mdtab(ctx);
437 : } else {
438 15721 : grow_mdtab(ctx);
439 : }
440 26161 : }
441 :
442 2097770 : grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdctx *ctx,
443 : grpc_mdstr *mkey,
444 : grpc_mdstr *mvalue) {
445 2097770 : internal_string *key = (internal_string *)mkey;
446 2097770 : internal_string *value = (internal_string *)mvalue;
447 2097770 : gpr_uint32 hash = GRPC_MDSTR_KV_HASH(mkey->hash, mvalue->hash);
448 : internal_metadata *md;
449 :
450 2097770 : GPR_ASSERT(key->context == ctx);
451 2097770 : GPR_ASSERT(value->context == ctx);
452 :
453 2097770 : lock(ctx);
454 :
455 : /* search for an existing pair */
456 4657977 : for (md = ctx->mdtab[hash % ctx->mdtab_capacity]; md; md = md->bucket_next) {
457 3227407 : if (md->key == key && md->value == value) {
458 667225 : REF_MD_LOCKED(md);
459 667228 : INTERNAL_STRING_UNREF(key);
460 667228 : INTERNAL_STRING_UNREF(value);
461 667228 : unlock(ctx);
462 667227 : return (grpc_mdelem *)md;
463 : }
464 : }
465 :
466 : /* not found: create a new pair */
467 1430570 : md = gpr_malloc(sizeof(internal_metadata));
468 1430437 : gpr_atm_rel_store(&md->refcnt, 1);
469 1430437 : md->context = ctx;
470 1430437 : md->key = key;
471 1430437 : md->value = value;
472 1430437 : md->user_data = NULL;
473 1430437 : md->destroy_user_data = NULL;
474 1430437 : md->bucket_next = ctx->mdtab[hash % ctx->mdtab_capacity];
475 1430437 : gpr_mu_init(&md->mu_user_data);
476 : #ifdef GRPC_METADATA_REFCOUNT_DEBUG
477 : gpr_log(GPR_DEBUG, "ELM NEW:%p:%d: '%s' = '%s'", md,
478 : gpr_atm_no_barrier_load(&md->refcnt),
479 : grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
480 : grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
481 : #endif
482 1430419 : ctx->mdtab[hash % ctx->mdtab_capacity] = md;
483 1430419 : ctx->mdtab_count++;
484 :
485 1430419 : if (ctx->mdtab_count > ctx->mdtab_capacity * 2) {
486 26161 : rehash_mdtab(ctx);
487 : }
488 :
489 1430419 : unlock(ctx);
490 :
491 1430531 : return (grpc_mdelem *)md;
492 : }
493 :
494 1710904 : grpc_mdelem *grpc_mdelem_from_strings(grpc_mdctx *ctx, const char *key,
495 : const char *value) {
496 1710904 : return grpc_mdelem_from_metadata_strings(ctx,
497 : grpc_mdstr_from_string(ctx, key),
498 : grpc_mdstr_from_string(ctx, value));
499 : }
500 :
501 146 : grpc_mdelem *grpc_mdelem_from_slices(grpc_mdctx *ctx, gpr_slice key,
502 : gpr_slice value) {
503 146 : return grpc_mdelem_from_metadata_strings(ctx, grpc_mdstr_from_slice(ctx, key),
504 : grpc_mdstr_from_slice(ctx, value));
505 : }
506 :
507 1193 : grpc_mdelem *grpc_mdelem_from_string_and_buffer(grpc_mdctx *ctx,
508 : const char *key,
509 : const gpr_uint8 *value,
510 : size_t value_length) {
511 1193 : return grpc_mdelem_from_metadata_strings(
512 : ctx, grpc_mdstr_from_string(ctx, key),
513 : grpc_mdstr_from_buffer(ctx, value, value_length));
514 : }
515 :
516 37522670 : grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *gmd DEBUG_ARGS) {
517 37522670 : internal_metadata *md = (internal_metadata *)gmd;
518 : #ifdef GRPC_METADATA_REFCOUNT_DEBUG
519 : gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
520 : "ELM REF:%p:%d->%d: '%s' = '%s'", md,
521 : gpr_atm_no_barrier_load(&md->refcnt),
522 : gpr_atm_no_barrier_load(&md->refcnt) + 1,
523 : grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
524 : grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
525 : #endif
526 : /* we can assume the ref count is >= 1 as the application is calling
527 : this function - meaning that no adjustment to mdtab_free is necessary,
528 : simplifying the logic here to be just an atomic increment */
529 : /* use C assert to have this removed in opt builds */
530 37522670 : assert(gpr_atm_no_barrier_load(&md->refcnt) >= 1);
531 37522670 : gpr_atm_no_barrier_fetch_add(&md->refcnt, 1);
532 37522670 : return gmd;
533 : }
534 :
535 3105108 : void grpc_mdelem_unref(grpc_mdelem *gmd DEBUG_ARGS) {
536 3105108 : internal_metadata *md = (internal_metadata *)gmd;
537 3105108 : grpc_mdctx *ctx = md->context;
538 3105108 : lock(ctx);
539 : #ifdef GRPC_METADATA_REFCOUNT_DEBUG
540 : gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
541 : "ELM UNREF:%p:%d->%d: '%s' = '%s'", md,
542 : gpr_atm_no_barrier_load(&md->refcnt),
543 : gpr_atm_no_barrier_load(&md->refcnt) - 1,
544 : grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
545 : grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
546 : #endif
547 3105705 : assert(gpr_atm_no_barrier_load(&md->refcnt) >= 1);
548 3105705 : if (1 == gpr_atm_full_fetch_add(&md->refcnt, -1)) {
549 1435829 : ctx->mdtab_free++;
550 : }
551 3105705 : unlock(ctx);
552 3105735 : }
553 :
554 2628793 : const char *grpc_mdstr_as_c_string(grpc_mdstr *s) {
555 2628793 : return (const char *)GPR_SLICE_START_PTR(s->slice);
556 : }
557 :
558 3011145 : grpc_mdstr *grpc_mdstr_ref(grpc_mdstr *gs DEBUG_ARGS) {
559 3011145 : internal_string *s = (internal_string *)gs;
560 3011145 : grpc_mdctx *ctx = s->context;
561 3011145 : lock(ctx);
562 3011944 : internal_string_ref(s FWD_DEBUG_ARGS);
563 3011810 : unlock(ctx);
564 3011955 : return gs;
565 : }
566 :
567 3583029 : void grpc_mdstr_unref(grpc_mdstr *gs DEBUG_ARGS) {
568 3583029 : internal_string *s = (internal_string *)gs;
569 3583029 : grpc_mdctx *ctx = s->context;
570 3583029 : lock(ctx);
571 3585393 : internal_string_unref(s FWD_DEBUG_ARGS);
572 3585387 : unlock(ctx);
573 3585434 : }
574 :
575 2 : size_t grpc_mdctx_get_mdtab_capacity_test_only(grpc_mdctx *ctx) {
576 2 : return ctx->mdtab_capacity;
577 : }
578 :
579 4 : size_t grpc_mdctx_get_mdtab_count_test_only(grpc_mdctx *ctx) {
580 4 : return ctx->mdtab_count;
581 : }
582 :
583 4 : size_t grpc_mdctx_get_mdtab_free_test_only(grpc_mdctx *ctx) {
584 4 : return ctx->mdtab_free;
585 : }
586 :
587 4120129 : void *grpc_mdelem_get_user_data(grpc_mdelem *md,
588 : void (*if_destroy_func)(void *)) {
589 4120129 : internal_metadata *im = (internal_metadata *)md;
590 : void *result;
591 4120129 : gpr_mu_lock(&im->mu_user_data);
592 4126131 : result = im->destroy_user_data == if_destroy_func ? im->user_data : NULL;
593 4126131 : gpr_mu_unlock(&im->mu_user_data);
594 4125457 : return result;
595 : }
596 :
597 8487 : void grpc_mdelem_set_user_data(grpc_mdelem *md, void (*destroy_func)(void *),
598 : void *user_data) {
599 8487 : internal_metadata *im = (internal_metadata *)md;
600 8487 : GPR_ASSERT((user_data == NULL) == (destroy_func == NULL));
601 8487 : gpr_mu_lock(&im->mu_user_data);
602 8487 : if (im->destroy_user_data) {
603 : /* user data can only be set once */
604 0 : gpr_mu_unlock(&im->mu_user_data);
605 0 : if (destroy_func != NULL) {
606 0 : destroy_func(user_data);
607 : }
608 8487 : return;
609 : }
610 8487 : im->destroy_user_data = destroy_func;
611 8487 : im->user_data = user_data;
612 8487 : gpr_mu_unlock(&im->mu_user_data);
613 : }
614 :
615 111 : gpr_slice grpc_mdstr_as_base64_encoded_and_huffman_compressed(grpc_mdstr *gs) {
616 111 : internal_string *s = (internal_string *)gs;
617 : gpr_slice slice;
618 111 : grpc_mdctx *ctx = s->context;
619 111 : lock(ctx);
620 111 : if (!s->has_base64_and_huffman_encoded) {
621 111 : s->base64_and_huffman =
622 : grpc_chttp2_base64_encode_and_huffman_compress(s->slice);
623 111 : s->has_base64_and_huffman_encoded = 1;
624 : }
625 111 : slice = s->base64_and_huffman;
626 111 : unlock(ctx);
627 111 : return slice;
628 : }
629 :
630 6916392 : void grpc_mdctx_lock(grpc_mdctx *ctx) { lock(ctx); }
631 :
632 36644842 : void grpc_mdctx_locked_mdelem_unref(grpc_mdctx *ctx,
633 : grpc_mdelem *gmd DEBUG_ARGS) {
634 36644842 : internal_metadata *md = (internal_metadata *)gmd;
635 36644842 : grpc_mdctx *elem_ctx = md->context;
636 36644842 : GPR_ASSERT(ctx == elem_ctx);
637 : #ifdef GRPC_METADATA_REFCOUNT_DEBUG
638 : gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
639 : "ELM UNREF:%p:%d->%d: '%s' = '%s'", md,
640 : gpr_atm_no_barrier_load(&md->refcnt),
641 : gpr_atm_no_barrier_load(&md->refcnt) - 1,
642 : grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
643 : grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
644 : #endif
645 36644842 : assert(gpr_atm_no_barrier_load(&md->refcnt) >= 1);
646 36644842 : if (1 == gpr_atm_full_fetch_add(&md->refcnt, -1)) {
647 103751 : ctx->mdtab_free++;
648 : }
649 36644842 : }
650 :
651 6927909 : void grpc_mdctx_unlock(grpc_mdctx *ctx) { unlock(ctx); }
652 :
653 2276 : static int conforms_to(grpc_mdstr *s, const gpr_uint8 *legal_bits) {
654 2276 : const gpr_uint8 *p = GPR_SLICE_START_PTR(s->slice);
655 2276 : const gpr_uint8 *e = GPR_SLICE_END_PTR(s->slice);
656 1735672 : for (; p != e; p++) {
657 1733396 : int idx = *p;
658 1733396 : int byte = idx / 8;
659 1733396 : int bit = idx % 8;
660 1733396 : if ((legal_bits[byte] & (1 << bit)) == 0) return 0;
661 : }
662 2276 : return 1;
663 : }
664 :
665 1193 : int grpc_mdstr_is_legal_header(grpc_mdstr *s) {
666 : static const gpr_uint8 legal_header_bits[256 / 8] = {
667 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xff, 0x03, 0x00, 0x00, 0x00,
668 : 0x80, 0xfe, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
669 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
670 1193 : return conforms_to(s, legal_header_bits);
671 : }
672 :
673 1083 : int grpc_mdstr_is_legal_nonbin_header(grpc_mdstr *s) {
674 : static const gpr_uint8 legal_header_bits[256 / 8] = {
675 : 0x00, 0x00, 0x00, 0x00, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff,
676 : 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
677 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
678 1083 : return conforms_to(s, legal_header_bits);
679 : }
680 :
681 1193 : int grpc_mdstr_is_bin_suffixed(grpc_mdstr *s) {
682 : /* TODO(ctiller): consider caching this */
683 1905 : return grpc_is_binary_header((const char *)GPR_SLICE_START_PTR(s->slice),
684 1905 : GPR_SLICE_LENGTH(s->slice));
685 : }
|