| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224 | /* * * Copyright 2016 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *     http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */#include <string.h>#include <grpc/grpc.h>#include <grpc/grpc_security.h>#include <grpc/support/alloc.h>#include <grpc/support/log.h>#include <grpc/support/string_util.h>#include "src/core/ext/filters/client_channel/lb_policy_factory.h"#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"#include "src/core/lib/channel/channel_args.h"#include "src/core/lib/iomgr/executor.h"#include "src/core/lib/iomgr/resolve_address.h"#include "src/core/lib/iomgr/tcp_client.h"#include "src/core/lib/iomgr/timer.h"#include "src/core/lib/iomgr/timer_manager.h"#include "src/core/lib/slice/slice_internal.h"#include "src/core/lib/support/env.h"#include "src/core/lib/surface/server.h"#include "src/core/lib/transport/metadata.h"#include "test/core/end2end/data/ssl_test_data.h"#include "test/core/util/passthru_endpoint.h"////////////////////////////////////////////////////////////////////////////////// loggingbool squelch = true;bool leak_check = true;static void dont_log(gpr_log_func_args *args) {}////////////////////////////////////////////////////////////////////////////////// global statestatic gpr_timespec g_now;static grpc_server *g_server;static grpc_channel *g_channel;static grpc_resource_quota *g_resource_quota;extern gpr_timespec (*gpr_now_impl)(gpr_clock_type clock_type);static gpr_timespec now_impl(gpr_clock_type clock_type) {  GPR_ASSERT(clock_type != GPR_TIMESPAN);  return g_now;}////////////////////////////////////////////////////////////////////////////////// input_stream: allows easy access to input bytes, and allows reading a little//               past the end (avoiding needing to check everywhere)typedef struct {  const uint8_t *cur;  const uint8_t *end;} input_stream;static uint8_t next_byte(input_stream *inp) {  if (inp->cur == inp->end) {    return 0;  }  return *inp->cur++;}static void end(input_stream *inp) { inp->cur = inp->end; }static char *read_string(input_stream *inp, bool *special) {  char *str = NULL;  size_t cap = 0;  size_t sz = 0;  char c;  do {    if (cap == sz) {      cap = GPR_MAX(3 * cap / 2, cap + 8);      str = gpr_realloc(str, cap);    }    c = (char)next_byte(inp);    str[sz++] = c;  } while (c != 0 && c != 1);  if (special != NULL) {    *special = (c == 1);  }  if (c == 1) {    str[sz - 1] = 0;  }  return str;}static void read_buffer(input_stream *inp, char **buffer, size_t *length,                        bool *special) {  *length = next_byte(inp);  if (*length == 255) {    if (special != NULL) *special = true;    *length = next_byte(inp);  } else {    if (special != NULL) *special = false;  }  *buffer = gpr_malloc(*length);  for (size_t i = 0; i < *length; i++) {    (*buffer)[i] = (char)next_byte(inp);  }}static grpc_slice maybe_intern(grpc_slice s, bool intern) {  grpc_slice r = intern ? grpc_slice_intern(s) : grpc_slice_ref(s);  grpc_slice_unref(s);  return r;}static grpc_slice read_string_like_slice(input_stream *inp) {  bool special;  char *s = read_string(inp, &special);  grpc_slice r = maybe_intern(grpc_slice_from_copied_string(s), special);  gpr_free(s);  return r;}static grpc_slice read_buffer_like_slice(input_stream *inp) {  char *buffer;  size_t length;  bool special;  read_buffer(inp, &buffer, &length, &special);  grpc_slice r =      maybe_intern(grpc_slice_from_copied_buffer(buffer, length), special);  gpr_free(buffer);  return r;}static uint32_t read_uint22(input_stream *inp) {  uint8_t b = next_byte(inp);  uint32_t x = b & 0x7f;  if (b & 0x80) {    x <<= 7;    b = next_byte(inp);    x |= b & 0x7f;    if (b & 0x80) {      x <<= 8;      x |= next_byte(inp);    }  }  return x;}static uint32_t read_uint32(input_stream *inp) {  uint8_t b = next_byte(inp);  uint32_t x = b & 0x7f;  if (b & 0x80) {    x <<= 7;    b = next_byte(inp);    x |= b & 0x7f;    if (b & 0x80) {      x <<= 7;      b = next_byte(inp);      x |= b & 0x7f;      if (b & 0x80) {        x <<= 7;        b = next_byte(inp);        x |= b & 0x7f;        if (b & 0x80) {          x = (x << 4) | (next_byte(inp) & 0x0f);        }      }    }  }  return x;}static grpc_byte_buffer *read_message(input_stream *inp) {  grpc_slice slice = grpc_slice_malloc(read_uint22(inp));  memset(GRPC_SLICE_START_PTR(slice), 0, GRPC_SLICE_LENGTH(slice));  grpc_byte_buffer *out = grpc_raw_byte_buffer_create(&slice, 1);  grpc_slice_unref(slice);  return out;}static int read_int(input_stream *inp) { return (int)read_uint32(inp); }static grpc_channel_args *read_args(input_stream *inp) {  size_t n = next_byte(inp);  grpc_arg *args = gpr_malloc(sizeof(*args) * n);  for (size_t i = 0; i < n; i++) {    switch (next_byte(inp)) {      case 1:        args[i].type = GRPC_ARG_STRING;        args[i].key = read_string(inp, NULL);        args[i].value.string = read_string(inp, NULL);        break;      case 2:        args[i].type = GRPC_ARG_INTEGER;        args[i].key = read_string(inp, NULL);        args[i].value.integer = read_int(inp);        break;      case 3:        args[i].type = GRPC_ARG_POINTER;        args[i].key = gpr_strdup(GRPC_ARG_RESOURCE_QUOTA);        args[i].value.pointer.vtable = grpc_resource_quota_arg_vtable();        args[i].value.pointer.p = g_resource_quota;        grpc_resource_quota_ref(g_resource_quota);        break;      default:        end(inp);        n = i;        break;    }  }  grpc_channel_args *a = gpr_malloc(sizeof(*a));  a->args = args;  a->num_args = n;  return a;}typedef struct cred_artifact_ctx {  int num_release;  char *release[3];} cred_artifact_ctx;#define CRED_ARTIFACT_CTX_INIT \  {                            \    0, { 0 }                   \  }static void cred_artifact_ctx_finish(cred_artifact_ctx *ctx) {  for (int i = 0; i < ctx->num_release; i++) {    gpr_free(ctx->release[i]);  }}static const char *read_cred_artifact(cred_artifact_ctx *ctx, input_stream *inp,                                      const char **builtins,                                      size_t num_builtins) {  uint8_t b = next_byte(inp);  if (b == 0) return NULL;  if (b == 1) return ctx->release[ctx->num_release++] = read_string(inp, NULL);  if (b >= num_builtins + 1) {    end(inp);    return NULL;  }  return builtins[b - 1];}static grpc_channel_credentials *read_ssl_channel_creds(input_stream *inp) {  cred_artifact_ctx ctx = CRED_ARTIFACT_CTX_INIT;  static const char *builtin_root_certs[] = {test_root_cert};  static const char *builtin_private_keys[] = {      test_server1_key, test_self_signed_client_key, test_signed_client_key};  static const char *builtin_cert_chains[] = {      test_server1_cert, test_self_signed_client_cert, test_signed_client_cert};  const char *root_certs = read_cred_artifact(      &ctx, inp, builtin_root_certs, GPR_ARRAY_SIZE(builtin_root_certs));  const char *private_key = read_cred_artifact(      &ctx, inp, builtin_private_keys, GPR_ARRAY_SIZE(builtin_private_keys));  const char *certs = read_cred_artifact(&ctx, inp, builtin_cert_chains,                                         GPR_ARRAY_SIZE(builtin_cert_chains));  grpc_ssl_pem_key_cert_pair key_cert_pair = {private_key, certs};  grpc_channel_credentials *creds = grpc_ssl_credentials_create(      root_certs, private_key != NULL && certs != NULL ? &key_cert_pair : NULL,      NULL);  cred_artifact_ctx_finish(&ctx);  return creds;}static grpc_call_credentials *read_call_creds(input_stream *inp) {  switch (next_byte(inp)) {    default:      end(inp);      return NULL;    case 0:      return NULL;    case 1: {      grpc_call_credentials *c1 = read_call_creds(inp);      grpc_call_credentials *c2 = read_call_creds(inp);      if (c1 != NULL && c2 != NULL) {        grpc_call_credentials *out =            grpc_composite_call_credentials_create(c1, c2, NULL);        grpc_call_credentials_release(c1);        grpc_call_credentials_release(c2);        return out;      } else if (c1 != NULL) {        return c1;      } else if (c2 != NULL) {        return c2;      } else {        return NULL;      }      GPR_UNREACHABLE_CODE(return NULL);    }    case 2: {      cred_artifact_ctx ctx = CRED_ARTIFACT_CTX_INIT;      const char *access_token = read_cred_artifact(&ctx, inp, NULL, 0);      grpc_call_credentials *out =          access_token == NULL ? NULL : grpc_access_token_credentials_create(                                            access_token, NULL);      cred_artifact_ctx_finish(&ctx);      return out;    }    case 3: {      cred_artifact_ctx ctx = CRED_ARTIFACT_CTX_INIT;      const char *auth_token = read_cred_artifact(&ctx, inp, NULL, 0);      const char *auth_selector = read_cred_artifact(&ctx, inp, NULL, 0);      grpc_call_credentials *out = auth_token == NULL || auth_selector == NULL                                       ? NULL                                       : grpc_google_iam_credentials_create(                                             auth_token, auth_selector, NULL);      cred_artifact_ctx_finish(&ctx);      return out;    }      /* TODO(ctiller): more cred types here */  }}static grpc_channel_credentials *read_channel_creds(input_stream *inp) {  switch (next_byte(inp)) {    case 0:      return read_ssl_channel_creds(inp);      break;    case 1: {      grpc_channel_credentials *c1 = read_channel_creds(inp);      grpc_call_credentials *c2 = read_call_creds(inp);      if (c1 != NULL && c2 != NULL) {        grpc_channel_credentials *out =            grpc_composite_channel_credentials_create(c1, c2, NULL);        grpc_channel_credentials_release(c1);        grpc_call_credentials_release(c2);        return out;      } else if (c1) {        return c1;      } else if (c2) {        grpc_call_credentials_release(c2);        return NULL;      } else {        return NULL;      }      GPR_UNREACHABLE_CODE(return NULL);    }    case 2:      return NULL;    default:      end(inp);      return NULL;  }}static bool is_eof(input_stream *inp) { return inp->cur == inp->end; }////////////////////////////////////////////////////////////////////////////////// dns resolutiontypedef struct addr_req {  grpc_timer timer;  char *addr;  grpc_closure *on_done;  grpc_resolved_addresses **addrs;  grpc_lb_addresses **lb_addrs;} addr_req;static void finish_resolve(grpc_exec_ctx *exec_ctx, void *arg,                           grpc_error *error) {  addr_req *r = arg;  if (error == GRPC_ERROR_NONE && 0 == strcmp(r->addr, "server")) {    if (r->addrs != NULL) {      grpc_resolved_addresses *addrs = gpr_malloc(sizeof(*addrs));      addrs->naddrs = 1;      addrs->addrs = gpr_malloc(sizeof(*addrs->addrs));      addrs->addrs[0].len = 0;      *r->addrs = addrs;    } else if (r->lb_addrs != NULL) {      grpc_lb_addresses *lb_addrs = grpc_lb_addresses_create(1, NULL);      grpc_lb_addresses_set_address(lb_addrs, 0, NULL, 0, NULL, NULL, NULL);      *r->lb_addrs = lb_addrs;    }    GRPC_CLOSURE_SCHED(exec_ctx, r->on_done, GRPC_ERROR_NONE);  } else {    GRPC_CLOSURE_SCHED(exec_ctx, r->on_done,                       GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(                           "Resolution failed", &error, 1));  }  gpr_free(r->addr);  gpr_free(r);}void my_resolve_address(grpc_exec_ctx *exec_ctx, const char *addr,                        const char *default_port,                        grpc_pollset_set *interested_parties,                        grpc_closure *on_done,                        grpc_resolved_addresses **addresses) {  addr_req *r = gpr_malloc(sizeof(*r));  r->addr = gpr_strdup(addr);  r->on_done = on_done;  r->addrs = addresses;  r->lb_addrs = NULL;  grpc_timer_init(      exec_ctx, &r->timer, gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),                                        gpr_time_from_seconds(1, GPR_TIMESPAN)),      GRPC_CLOSURE_CREATE(finish_resolve, r, grpc_schedule_on_exec_ctx),      gpr_now(GPR_CLOCK_MONOTONIC));}grpc_ares_request *my_dns_lookup_ares(    grpc_exec_ctx *exec_ctx, const char *dns_server, const char *addr,    const char *default_port, grpc_pollset_set *interested_parties,    grpc_closure *on_done, grpc_lb_addresses **lb_addrs, bool check_grpclb,    char **service_config_json) {  addr_req *r = gpr_malloc(sizeof(*r));  r->addr = gpr_strdup(addr);  r->on_done = on_done;  r->addrs = NULL;  r->lb_addrs = lb_addrs;  grpc_timer_init(      exec_ctx, &r->timer, gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),                                        gpr_time_from_seconds(1, GPR_TIMESPAN)),      GRPC_CLOSURE_CREATE(finish_resolve, r, grpc_schedule_on_exec_ctx),      gpr_now(GPR_CLOCK_MONOTONIC));  return NULL;}////////////////////////////////////////////////////////////////////////////////// client connection// defined in tcp_client_posix.cextern void (*grpc_tcp_client_connect_impl)(    grpc_exec_ctx *exec_ctx, grpc_closure *closure, grpc_endpoint **ep,    grpc_pollset_set *interested_parties, const grpc_channel_args *channel_args,    const grpc_resolved_address *addr, gpr_timespec deadline);static void sched_connect(grpc_exec_ctx *exec_ctx, grpc_closure *closure,                          grpc_endpoint **ep, gpr_timespec deadline);typedef struct {  grpc_timer timer;  grpc_closure *closure;  grpc_endpoint **ep;  gpr_timespec deadline;} future_connect;static void do_connect(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {  future_connect *fc = arg;  if (error != GRPC_ERROR_NONE) {    *fc->ep = NULL;    GRPC_CLOSURE_SCHED(exec_ctx, fc->closure, GRPC_ERROR_REF(error));  } else if (g_server != NULL) {    grpc_endpoint *client;    grpc_endpoint *server;    grpc_passthru_endpoint_create(&client, &server, g_resource_quota, NULL);    *fc->ep = client;    grpc_transport *transport =        grpc_create_chttp2_transport(exec_ctx, NULL, server, 0);    grpc_server_setup_transport(exec_ctx, g_server, transport, NULL, NULL);    grpc_chttp2_transport_start_reading(exec_ctx, transport, NULL);    GRPC_CLOSURE_SCHED(exec_ctx, fc->closure, GRPC_ERROR_NONE);  } else {    sched_connect(exec_ctx, fc->closure, fc->ep, fc->deadline);  }  gpr_free(fc);}static void sched_connect(grpc_exec_ctx *exec_ctx, grpc_closure *closure,                          grpc_endpoint **ep, gpr_timespec deadline) {  if (gpr_time_cmp(deadline, gpr_now(deadline.clock_type)) < 0) {    *ep = NULL;    GRPC_CLOSURE_SCHED(exec_ctx, closure, GRPC_ERROR_CREATE_FROM_STATIC_STRING(                                              "Connect deadline exceeded"));    return;  }  future_connect *fc = gpr_malloc(sizeof(*fc));  fc->closure = closure;  fc->ep = ep;  fc->deadline = deadline;  grpc_timer_init(      exec_ctx, &fc->timer, gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),                                         gpr_time_from_millis(1, GPR_TIMESPAN)),      GRPC_CLOSURE_CREATE(do_connect, fc, grpc_schedule_on_exec_ctx),      gpr_now(GPR_CLOCK_MONOTONIC));}static void my_tcp_client_connect(grpc_exec_ctx *exec_ctx,                                  grpc_closure *closure, grpc_endpoint **ep,                                  grpc_pollset_set *interested_parties,                                  const grpc_channel_args *channel_args,                                  const grpc_resolved_address *addr,                                  gpr_timespec deadline) {  sched_connect(exec_ctx, closure, ep, deadline);}////////////////////////////////////////////////////////////////////////////////// test drivertypedef struct validator {  void (*validate)(void *arg, bool success);  void *arg;} validator;static validator *create_validator(void (*validate)(void *arg, bool success),                                   void *arg) {  validator *v = gpr_malloc(sizeof(*v));  v->validate = validate;  v->arg = arg;  return v;}static void assert_success_and_decrement(void *counter, bool success) {  GPR_ASSERT(success);  --*(int *)counter;}static void decrement(void *counter, bool success) { --*(int *)counter; }typedef struct connectivity_watch {  int *counter;  gpr_timespec deadline;} connectivity_watch;static connectivity_watch *make_connectivity_watch(gpr_timespec s,                                                   int *counter) {  connectivity_watch *o = gpr_malloc(sizeof(*o));  o->deadline = s;  o->counter = counter;  return o;}static void validate_connectivity_watch(void *p, bool success) {  connectivity_watch *w = p;  if (!success) {    GPR_ASSERT(gpr_time_cmp(gpr_now(w->deadline.clock_type), w->deadline) >= 0);  }  --*w->counter;  gpr_free(w);}static void free_non_null(void *p) {  GPR_ASSERT(p != NULL);  gpr_free(p);}typedef enum { ROOT, CLIENT, SERVER, PENDING_SERVER } call_state_type;#define DONE_FLAG_CALL_CLOSED ((uint64_t)(1 << 0))typedef struct call_state {  call_state_type type;  grpc_call *call;  grpc_byte_buffer *recv_message;  grpc_status_code status;  grpc_metadata_array recv_initial_metadata;  grpc_metadata_array recv_trailing_metadata;  grpc_slice recv_status_details;  int cancelled;  int pending_ops;  grpc_call_details call_details;  grpc_byte_buffer *send_message;  // starts at 0, individual flags from DONE_FLAG_xxx are set  // as different operations are completed  uint64_t done_flags;  // array of pointers to free later  size_t num_to_free;  size_t cap_to_free;  void **to_free;  // array of slices to unref  size_t num_slices_to_unref;  size_t cap_slices_to_unref;  grpc_slice **slices_to_unref;  struct call_state *next;  struct call_state *prev;} call_state;static call_state *g_active_call;static call_state *new_call(call_state *sibling, call_state_type type) {  call_state *c = gpr_malloc(sizeof(*c));  memset(c, 0, sizeof(*c));  if (sibling != NULL) {    c->next = sibling;    c->prev = sibling->prev;    c->next->prev = c->prev->next = c;  } else {    c->next = c->prev = c;  }  c->type = type;  return c;}static call_state *maybe_delete_call_state(call_state *call) {  call_state *next = call->next;  if (call->call != NULL) return next;  if (call->pending_ops != 0) return next;  if (call == g_active_call) {    g_active_call = call->next;    GPR_ASSERT(call != g_active_call);  }  call->prev->next = call->next;  call->next->prev = call->prev;  grpc_metadata_array_destroy(&call->recv_initial_metadata);  grpc_metadata_array_destroy(&call->recv_trailing_metadata);  grpc_slice_unref(call->recv_status_details);  grpc_call_details_destroy(&call->call_details);  for (size_t i = 0; i < call->num_slices_to_unref; i++) {    grpc_slice_unref(*call->slices_to_unref[i]);    gpr_free(call->slices_to_unref[i]);  }  for (size_t i = 0; i < call->num_to_free; i++) {    gpr_free(call->to_free[i]);  }  gpr_free(call->to_free);  gpr_free(call->slices_to_unref);  gpr_free(call);  return next;}static void add_to_free(call_state *call, void *p) {  if (call->num_to_free == call->cap_to_free) {    call->cap_to_free = GPR_MAX(8, 2 * call->cap_to_free);    call->to_free =        gpr_realloc(call->to_free, sizeof(*call->to_free) * call->cap_to_free);  }  call->to_free[call->num_to_free++] = p;}static grpc_slice *add_slice_to_unref(call_state *call, grpc_slice s) {  if (call->num_slices_to_unref == call->cap_slices_to_unref) {    call->cap_slices_to_unref = GPR_MAX(8, 2 * call->cap_slices_to_unref);    call->slices_to_unref =        gpr_realloc(call->slices_to_unref,                    sizeof(*call->slices_to_unref) * call->cap_slices_to_unref);  }  call->slices_to_unref[call->num_slices_to_unref] =      gpr_malloc(sizeof(grpc_slice));  *call->slices_to_unref[call->num_slices_to_unref++] = s;  return call->slices_to_unref[call->num_slices_to_unref - 1];}static void read_metadata(input_stream *inp, size_t *count,                          grpc_metadata **metadata, call_state *cs) {  *count = next_byte(inp);  if (*count) {    *metadata = gpr_malloc(*count * sizeof(**metadata));    memset(*metadata, 0, *count * sizeof(**metadata));    for (size_t i = 0; i < *count; i++) {      (*metadata)[i].key = read_string_like_slice(inp);      (*metadata)[i].value = read_buffer_like_slice(inp);      (*metadata)[i].flags = read_uint32(inp);      add_slice_to_unref(cs, (*metadata)[i].key);      add_slice_to_unref(cs, (*metadata)[i].value);    }  } else {    *metadata = gpr_malloc(1);  }  add_to_free(cs, *metadata);}static call_state *destroy_call(call_state *call) {  grpc_call_unref(call->call);  call->call = NULL;  return maybe_delete_call_state(call);}static void finished_request_call(void *csp, bool success) {  call_state *cs = csp;  GPR_ASSERT(cs->pending_ops > 0);  --cs->pending_ops;  if (success) {    GPR_ASSERT(cs->call != NULL);    cs->type = SERVER;  } else {    maybe_delete_call_state(cs);  }}typedef struct {  call_state *cs;  uint8_t has_ops;} batch_info;static void finished_batch(void *p, bool success) {  batch_info *bi = p;  --bi->cs->pending_ops;  if ((bi->has_ops & (1u << GRPC_OP_RECV_MESSAGE)) &&      (bi->cs->done_flags & DONE_FLAG_CALL_CLOSED)) {    GPR_ASSERT(bi->cs->recv_message == NULL);  }  if ((bi->has_ops & (1u << GRPC_OP_RECV_MESSAGE) &&       bi->cs->recv_message != NULL)) {    grpc_byte_buffer_destroy(bi->cs->recv_message);    bi->cs->recv_message = NULL;  }  if ((bi->has_ops & (1u << GRPC_OP_SEND_MESSAGE))) {    grpc_byte_buffer_destroy(bi->cs->send_message);    bi->cs->send_message = NULL;  }  if ((bi->has_ops & (1u << GRPC_OP_RECV_STATUS_ON_CLIENT)) ||      (bi->has_ops & (1u << GRPC_OP_RECV_CLOSE_ON_SERVER))) {    bi->cs->done_flags |= DONE_FLAG_CALL_CLOSED;  }  maybe_delete_call_state(bi->cs);  gpr_free(bi);}static validator *make_finished_batch_validator(call_state *cs,                                                uint8_t has_ops) {  batch_info *bi = gpr_malloc(sizeof(*bi));  bi->cs = cs;  bi->has_ops = has_ops;  return create_validator(finished_batch, bi);}int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {  grpc_test_only_set_slice_hash_seed(0);  char *grpc_trace_fuzzer = gpr_getenv("GRPC_TRACE_FUZZER");  if (squelch && grpc_trace_fuzzer == NULL) gpr_set_log_function(dont_log);  gpr_free(grpc_trace_fuzzer);  input_stream inp = {data, data + size};  grpc_tcp_client_connect_impl = my_tcp_client_connect;  gpr_now_impl = now_impl;  grpc_init();  grpc_timer_manager_set_threading(false);  {    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;    grpc_executor_set_threading(&exec_ctx, false);    grpc_exec_ctx_finish(&exec_ctx);  }  grpc_resolve_address = my_resolve_address;  grpc_dns_lookup_ares = my_dns_lookup_ares;  GPR_ASSERT(g_channel == NULL);  GPR_ASSERT(g_server == NULL);  bool server_shutdown = false;  int pending_server_shutdowns = 0;  int pending_channel_watches = 0;  int pending_pings = 0;  g_active_call = new_call(NULL, ROOT);  g_resource_quota = grpc_resource_quota_create("api_fuzzer");  grpc_completion_queue *cq = grpc_completion_queue_create_for_next(NULL);  while (!is_eof(&inp) || g_channel != NULL || g_server != NULL ||         pending_channel_watches > 0 || pending_pings > 0 ||         g_active_call->type != ROOT || g_active_call->next != g_active_call) {    if (is_eof(&inp)) {      if (g_channel != NULL) {        grpc_channel_destroy(g_channel);        g_channel = NULL;      }      if (g_server != NULL) {        if (!server_shutdown) {          grpc_server_shutdown_and_notify(              g_server, cq, create_validator(assert_success_and_decrement,                                             &pending_server_shutdowns));          server_shutdown = true;          pending_server_shutdowns++;        } else if (pending_server_shutdowns == 0) {          grpc_server_destroy(g_server);          g_server = NULL;        }      }      call_state *s = g_active_call;      do {        if (s->type != PENDING_SERVER && s->call != NULL) {          s = destroy_call(s);        } else {          s = s->next;        }      } while (s != g_active_call);      g_now = gpr_time_add(g_now, gpr_time_from_seconds(1, GPR_TIMESPAN));    }    grpc_timer_manager_tick();    switch (next_byte(&inp)) {      // terminate on bad bytes      default:        end(&inp);        break;      // tickle completion queue      case 0: {        grpc_event ev = grpc_completion_queue_next(            cq, gpr_inf_past(GPR_CLOCK_REALTIME), NULL);        switch (ev.type) {          case GRPC_OP_COMPLETE: {            validator *v = ev.tag;            v->validate(v->arg, ev.success);            gpr_free(v);            break;          }          case GRPC_QUEUE_TIMEOUT:            break;          case GRPC_QUEUE_SHUTDOWN:            abort();            break;        }        break;      }      // increment global time      case 1: {        g_now = gpr_time_add(            g_now, gpr_time_from_micros(read_uint32(&inp), GPR_TIMESPAN));        break;      }      // create an insecure channel      case 2: {        if (g_channel == NULL) {          char *target = read_string(&inp, NULL);          char *target_uri;          gpr_asprintf(&target_uri, "dns:%s", target);          grpc_channel_args *args = read_args(&inp);          g_channel = grpc_insecure_channel_create(target_uri, args, NULL);          GPR_ASSERT(g_channel != NULL);          {            grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;            grpc_channel_args_destroy(&exec_ctx, args);            grpc_exec_ctx_finish(&exec_ctx);          }          gpr_free(target_uri);          gpr_free(target);        } else {          end(&inp);        }        break;      }      // destroy a channel      case 3: {        if (g_channel != NULL) {          grpc_channel_destroy(g_channel);          g_channel = NULL;        } else {          end(&inp);        }        break;      }      // bring up a server      case 4: {        if (g_server == NULL) {          grpc_channel_args *args = read_args(&inp);          g_server = grpc_server_create(args, NULL);          GPR_ASSERT(g_server != NULL);          {            grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;            grpc_channel_args_destroy(&exec_ctx, args);            grpc_exec_ctx_finish(&exec_ctx);          }          grpc_server_register_completion_queue(g_server, cq, NULL);          grpc_server_start(g_server);          server_shutdown = false;          GPR_ASSERT(pending_server_shutdowns == 0);        } else {          end(&inp);        }        break;      }      // begin server shutdown      case 5: {        if (g_server != NULL) {          grpc_server_shutdown_and_notify(              g_server, cq, create_validator(assert_success_and_decrement,                                             &pending_server_shutdowns));          pending_server_shutdowns++;          server_shutdown = true;        } else {          end(&inp);        }        break;      }      // cancel all calls if shutdown      case 6: {        if (g_server != NULL && server_shutdown) {          grpc_server_cancel_all_calls(g_server);        } else {          end(&inp);        }        break;      }      // destroy server      case 7: {        if (g_server != NULL && server_shutdown &&            pending_server_shutdowns == 0) {          grpc_server_destroy(g_server);          g_server = NULL;        } else {          end(&inp);        }        break;      }      // check connectivity      case 8: {        if (g_channel != NULL) {          uint8_t try_to_connect = next_byte(&inp);          if (try_to_connect == 0 || try_to_connect == 1) {            grpc_channel_check_connectivity_state(g_channel, try_to_connect);          } else {            end(&inp);          }        } else {          end(&inp);        }        break;      }      // watch connectivity      case 9: {        if (g_channel != NULL) {          grpc_connectivity_state st =              grpc_channel_check_connectivity_state(g_channel, 0);          if (st != GRPC_CHANNEL_SHUTDOWN) {            gpr_timespec deadline = gpr_time_add(                gpr_now(GPR_CLOCK_REALTIME),                gpr_time_from_micros(read_uint32(&inp), GPR_TIMESPAN));            grpc_channel_watch_connectivity_state(                g_channel, st, deadline, cq,                create_validator(validate_connectivity_watch,                                 make_connectivity_watch(                                     deadline, &pending_channel_watches)));            pending_channel_watches++;          }        } else {          end(&inp);        }        break;      }      // create a call      case 10: {        bool ok = true;        if (g_channel == NULL) ok = false;        grpc_call *parent_call = NULL;        if (g_active_call->type != ROOT) {          if (g_active_call->call == NULL || g_active_call->type == CLIENT) {            end(&inp);            break;          }          parent_call = g_active_call->call;        }        uint32_t propagation_mask = read_uint32(&inp);        grpc_slice method = read_string_like_slice(&inp);        if (GRPC_SLICE_LENGTH(method) == 0) {          ok = false;        }        grpc_slice host = read_string_like_slice(&inp);        gpr_timespec deadline =            gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),                         gpr_time_from_micros(read_uint32(&inp), GPR_TIMESPAN));        if (ok) {          call_state *cs = new_call(g_active_call, CLIENT);          cs->call =              grpc_channel_create_call(g_channel, parent_call, propagation_mask,                                       cq, method, &host, deadline, NULL);        } else {          end(&inp);        }        grpc_slice_unref(method);        grpc_slice_unref(host);        break;      }      // switch the 'current' call      case 11: {        g_active_call = g_active_call->next;        break;      }      // queue some ops on a call      case 12: {        if (g_active_call->type == PENDING_SERVER ||            g_active_call->type == ROOT || g_active_call->call == NULL) {          end(&inp);          break;        }        size_t num_ops = next_byte(&inp);        if (num_ops > 6) {          end(&inp);          break;        }        grpc_op *ops = gpr_malloc(sizeof(grpc_op) * num_ops);        if (num_ops > 0) memset(ops, 0, sizeof(grpc_op) * num_ops);        bool ok = true;        size_t i;        grpc_op *op;        uint8_t has_ops = 0;        for (i = 0; i < num_ops; i++) {          op = &ops[i];          switch (next_byte(&inp)) {            default:              /* invalid value */              op->op = (grpc_op_type)-1;              ok = false;              break;            case GRPC_OP_SEND_INITIAL_METADATA:              op->op = GRPC_OP_SEND_INITIAL_METADATA;              has_ops |= 1 << GRPC_OP_SEND_INITIAL_METADATA;              read_metadata(&inp, &op->data.send_initial_metadata.count,                            &op->data.send_initial_metadata.metadata,                            g_active_call);              break;            case GRPC_OP_SEND_MESSAGE:              op->op = GRPC_OP_SEND_MESSAGE;              if (g_active_call->send_message != NULL) {                ok = false;              } else {                has_ops |= 1 << GRPC_OP_SEND_MESSAGE;                g_active_call->send_message =                    op->data.send_message.send_message = read_message(&inp);              }              break;            case GRPC_OP_SEND_CLOSE_FROM_CLIENT:              op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;              has_ops |= 1 << GRPC_OP_SEND_CLOSE_FROM_CLIENT;              break;            case GRPC_OP_SEND_STATUS_FROM_SERVER:              op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;              has_ops |= 1 << GRPC_OP_SEND_STATUS_FROM_SERVER;              read_metadata(                  &inp,                  &op->data.send_status_from_server.trailing_metadata_count,                  &op->data.send_status_from_server.trailing_metadata,                  g_active_call);              op->data.send_status_from_server.status = next_byte(&inp);              op->data.send_status_from_server.status_details =                  add_slice_to_unref(g_active_call,                                     read_buffer_like_slice(&inp));              break;            case GRPC_OP_RECV_INITIAL_METADATA:              op->op = GRPC_OP_RECV_INITIAL_METADATA;              has_ops |= 1 << GRPC_OP_RECV_INITIAL_METADATA;              op->data.recv_initial_metadata.recv_initial_metadata =                  &g_active_call->recv_initial_metadata;              break;            case GRPC_OP_RECV_MESSAGE:              op->op = GRPC_OP_RECV_MESSAGE;              has_ops |= 1 << GRPC_OP_RECV_MESSAGE;              op->data.recv_message.recv_message = &g_active_call->recv_message;              break;            case GRPC_OP_RECV_STATUS_ON_CLIENT:              op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;              op->data.recv_status_on_client.status = &g_active_call->status;              op->data.recv_status_on_client.trailing_metadata =                  &g_active_call->recv_trailing_metadata;              op->data.recv_status_on_client.status_details =                  &g_active_call->recv_status_details;              break;            case GRPC_OP_RECV_CLOSE_ON_SERVER:              op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;              has_ops |= 1 << GRPC_OP_RECV_CLOSE_ON_SERVER;              op->data.recv_close_on_server.cancelled =                  &g_active_call->cancelled;              break;          }          op->reserved = NULL;          op->flags = read_uint32(&inp);        }        if (ok) {          validator *v = make_finished_batch_validator(g_active_call, has_ops);          g_active_call->pending_ops++;          grpc_call_error error =              grpc_call_start_batch(g_active_call->call, ops, num_ops, v, NULL);          if (error != GRPC_CALL_OK) {            v->validate(v->arg, false);            gpr_free(v);          }        } else {          end(&inp);        }        if (!ok && (has_ops & (1 << GRPC_OP_SEND_MESSAGE))) {          grpc_byte_buffer_destroy(g_active_call->send_message);          g_active_call->send_message = NULL;        }        gpr_free(ops);        break;      }      // cancel current call      case 13: {        if (g_active_call->type != ROOT && g_active_call->call != NULL) {          grpc_call_cancel(g_active_call->call, NULL);        } else {          end(&inp);        }        break;      }      // get a calls peer      case 14: {        if (g_active_call->type != ROOT && g_active_call->call != NULL) {          free_non_null(grpc_call_get_peer(g_active_call->call));        } else {          end(&inp);        }        break;      }      // get a channels target      case 15: {        if (g_channel != NULL) {          free_non_null(grpc_channel_get_target(g_channel));        } else {          end(&inp);        }        break;      }      // send a ping on a channel      case 16: {        if (g_channel != NULL) {          pending_pings++;          grpc_channel_ping(g_channel, cq,                            create_validator(decrement, &pending_pings), NULL);        } else {          end(&inp);        }        break;      }      // enable a tracer      case 17: {        char *tracer = read_string(&inp, NULL);        grpc_tracer_set_enabled(tracer, 1);        gpr_free(tracer);        break;      }      // disable a tracer      case 18: {        char *tracer = read_string(&inp, NULL);        grpc_tracer_set_enabled(tracer, 0);        gpr_free(tracer);        break;      }      // request a server call      case 19: {        if (g_server == NULL) {          end(&inp);          break;        }        call_state *cs = new_call(g_active_call, PENDING_SERVER);        cs->pending_ops++;        validator *v = create_validator(finished_request_call, cs);        grpc_call_error error =            grpc_server_request_call(g_server, &cs->call, &cs->call_details,                                     &cs->recv_initial_metadata, cq, cq, v);        if (error != GRPC_CALL_OK) {          v->validate(v->arg, false);          gpr_free(v);        }        break;      }      // destroy a call      case 20: {        if (g_active_call->type != ROOT &&            g_active_call->type != PENDING_SERVER &&            g_active_call->call != NULL) {          destroy_call(g_active_call);        } else {          end(&inp);        }        break;      }      // resize the buffer pool      case 21: {        grpc_resource_quota_resize(g_resource_quota, read_uint22(&inp));        break;      }      // create a secure channel      case 22: {        if (g_channel == NULL) {          char *target = read_string(&inp, NULL);          char *target_uri;          gpr_asprintf(&target_uri, "dns:%s", target);          grpc_channel_args *args = read_args(&inp);          grpc_channel_credentials *creds = read_channel_creds(&inp);          g_channel = grpc_secure_channel_create(creds, target_uri, args, NULL);          GPR_ASSERT(g_channel != NULL);          {            grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;            grpc_channel_args_destroy(&exec_ctx, args);            grpc_exec_ctx_finish(&exec_ctx);          }          gpr_free(target_uri);          gpr_free(target);          grpc_channel_credentials_release(creds);        } else {          end(&inp);        }        break;      }    }  }  GPR_ASSERT(g_channel == NULL);  GPR_ASSERT(g_server == NULL);  GPR_ASSERT(g_active_call->type == ROOT);  GPR_ASSERT(g_active_call->next == g_active_call);  gpr_free(g_active_call);  grpc_completion_queue_shutdown(cq);  GPR_ASSERT(      grpc_completion_queue_next(cq, gpr_inf_past(GPR_CLOCK_REALTIME), NULL)          .type == GRPC_QUEUE_SHUTDOWN);  grpc_completion_queue_destroy(cq);  grpc_resource_quota_unref(g_resource_quota);  grpc_shutdown();  return 0;}
 |