Beispiel #1
0
void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
                             grpc_endpoint **ep,
                             grpc_pollset_set *interested_parties,
                             const struct sockaddr *addr, size_t addr_len,
                             gpr_timespec deadline) {
  int fd;
  grpc_dualstack_mode dsmode;
  int err;
  async_connect *ac;
  struct sockaddr_in6 addr6_v4mapped;
  struct sockaddr_in addr4_copy;
  grpc_fd *fdobj;
  char *name;
  char *addr_str;

  *ep = NULL;

  /* Use dualstack sockets where available. */
  if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
    addr = (const struct sockaddr *)&addr6_v4mapped;
    addr_len = sizeof(addr6_v4mapped);
  }

  fd = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode);
  if (fd < 0) {
    gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno));
  }
  if (dsmode == GRPC_DSMODE_IPV4) {
    /* If we got an AF_INET socket, map the address back to IPv4. */
    GPR_ASSERT(grpc_sockaddr_is_v4mapped(addr, &addr4_copy));
    addr = (struct sockaddr *)&addr4_copy;
    addr_len = sizeof(addr4_copy);
  }
  if (!prepare_socket(addr, fd)) {
    grpc_exec_ctx_enqueue(exec_ctx, closure, 0);
    return;
  }

  do {
    GPR_ASSERT(addr_len < ~(socklen_t)0);
    err = connect(fd, addr, (socklen_t)addr_len);
  } while (err < 0 && errno == EINTR);

  addr_str = grpc_sockaddr_to_uri(addr);
  gpr_asprintf(&name, "tcp-client:%s", addr_str);

  fdobj = grpc_fd_create(fd, name);

  if (err >= 0) {
    *ep = grpc_tcp_create(fdobj, GRPC_TCP_DEFAULT_READ_SLICE_SIZE, addr_str);
    grpc_exec_ctx_enqueue(exec_ctx, closure, 1);
    goto done;
  }

  if (errno != EWOULDBLOCK && errno != EINPROGRESS) {
    gpr_log(GPR_ERROR, "connect error to '%s': %s", addr_str, strerror(errno));
    grpc_fd_orphan(exec_ctx, fdobj, NULL, "tcp_client_connect_error");
    grpc_exec_ctx_enqueue(exec_ctx, closure, 0);
    goto done;
  }

  grpc_pollset_set_add_fd(exec_ctx, interested_parties, fdobj);

  ac = gpr_malloc(sizeof(async_connect));
  ac->closure = closure;
  ac->ep = ep;
  ac->fd = fdobj;
  ac->interested_parties = interested_parties;
  ac->addr_str = addr_str;
  addr_str = NULL;
  gpr_mu_init(&ac->mu);
  ac->refs = 2;
  ac->write_closure.cb = on_writable;
  ac->write_closure.cb_arg = ac;

  if (grpc_tcp_trace) {
    gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: asynchronously connecting",
            ac->addr_str);
  }

  gpr_mu_lock(&ac->mu);
  grpc_alarm_init(exec_ctx, &ac->alarm,
                  gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
                  tc_on_alarm, ac, gpr_now(GPR_CLOCK_MONOTONIC));
  grpc_fd_notify_on_write(exec_ctx, ac->fd, &ac->write_closure);
  gpr_mu_unlock(&ac->mu);

done:
  gpr_free(name);
  gpr_free(addr_str);
}
Beispiel #2
0
static void tcp_add_to_pollset_set(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
                                   grpc_pollset_set *pollset_set) {
  grpc_tcp *tcp = (grpc_tcp *)ep;
  grpc_pollset_set_add_fd(exec_ctx, pollset_set, tcp->em_fd);
}
Beispiel #3
0
/* Pollset_set with an empty pollset */
void pollset_set_test_empty_pollset() {
  /* We construct the following structure for this test:
   *
   *        +---> PS0 (EMPTY)
   *        |
   *        +---> FD0
   *        |
   * PSS0---+
   *        |          +---> FD1
   *        |          |
   *        +---> PS1--+
   *                   |
   *                   +---> FD2
   */
  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
  grpc_pollset_worker *worker;
  gpr_timespec deadline;

  test_fd tfds[3];
  test_pollset pollsets[2];
  test_pollset_set pollset_set;
  const int num_fds = GPR_ARRAY_SIZE(tfds);
  const int num_ps = GPR_ARRAY_SIZE(pollsets);
  const int num_pss = 1;

  init_test_fds(&exec_ctx, tfds, num_fds);
  init_test_pollsets(pollsets, num_ps);
  init_test_pollset_sets(&pollset_set, num_pss);

  /* Construct the structure */
  grpc_pollset_set_add_fd(&exec_ctx, pollset_set.pss, tfds[0].fd);
  grpc_pollset_add_fd(&exec_ctx, pollsets[1].ps, tfds[1].fd);
  grpc_pollset_add_fd(&exec_ctx, pollsets[1].ps, tfds[2].fd);

  grpc_pollset_set_add_pollset(&exec_ctx, pollset_set.pss, pollsets[0].ps);
  grpc_pollset_set_add_pollset(&exec_ctx, pollset_set.pss, pollsets[1].ps);

  /* Test. Make all FDs readable and make sure that can be observed by doing
   * grpc_pollset_work on the empty pollset 'PS0' */
  make_test_fds_readable(tfds, num_fds);

  gpr_mu_lock(pollsets[0].mu);
  deadline = grpc_timeout_milliseconds_to_deadline(2);
  GPR_ASSERT(GRPC_ERROR_NONE ==
             grpc_pollset_work(&exec_ctx, pollsets[0].ps, &worker,
                               gpr_now(GPR_CLOCK_MONOTONIC), deadline));
  gpr_mu_unlock(pollsets[0].mu);
  grpc_exec_ctx_flush(&exec_ctx);

  verify_readable_and_reset(&exec_ctx, tfds, num_fds);
  grpc_exec_ctx_flush(&exec_ctx);

  /* Tear down */
  grpc_pollset_set_del_fd(&exec_ctx, pollset_set.pss, tfds[0].fd);
  grpc_pollset_set_del_pollset(&exec_ctx, pollset_set.pss, pollsets[0].ps);
  grpc_pollset_set_del_pollset(&exec_ctx, pollset_set.pss, pollsets[1].ps);
  grpc_exec_ctx_flush(&exec_ctx);

  cleanup_test_fds(&exec_ctx, tfds, num_fds);
  cleanup_test_pollsets(&exec_ctx, pollsets, num_ps);
  cleanup_test_pollset_sets(&exec_ctx, &pollset_set, num_pss);
  grpc_exec_ctx_finish(&exec_ctx);
}
Beispiel #4
0
static void 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) {
  int fd;
  grpc_dualstack_mode dsmode;
  int err;
  async_connect *ac;
  grpc_resolved_address addr6_v4mapped;
  grpc_resolved_address addr4_copy;
  grpc_fd *fdobj;
  char *name;
  char *addr_str;
  grpc_error *error;

  *ep = NULL;

  /* Use dualstack sockets where available. */
  if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
    addr = &addr6_v4mapped;
  }

  error = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode, &fd);
  if (error != GRPC_ERROR_NONE) {
    grpc_closure_sched(exec_ctx, closure, error);
    return;
  }
  if (dsmode == GRPC_DSMODE_IPV4) {
    /* If we got an AF_INET socket, map the address back to IPv4. */
    GPR_ASSERT(grpc_sockaddr_is_v4mapped(addr, &addr4_copy));
    addr = &addr4_copy;
  }
  if ((error = prepare_socket(addr, fd, channel_args)) != GRPC_ERROR_NONE) {
    grpc_closure_sched(exec_ctx, closure, error);
    return;
  }

  do {
    GPR_ASSERT(addr->len < ~(socklen_t)0);
    err =
        connect(fd, (const struct sockaddr *)addr->addr, (socklen_t)addr->len);
  } while (err < 0 && errno == EINTR);

  addr_str = grpc_sockaddr_to_uri(addr);
  gpr_asprintf(&name, "tcp-client:%s", addr_str);

  fdobj = grpc_fd_create(fd, name);

  if (err >= 0) {
    *ep =
        grpc_tcp_client_create_from_fd(exec_ctx, fdobj, channel_args, addr_str);
    grpc_closure_sched(exec_ctx, closure, GRPC_ERROR_NONE);
    goto done;
  }

  if (errno != EWOULDBLOCK && errno != EINPROGRESS) {
    grpc_fd_orphan(exec_ctx, fdobj, NULL, NULL, "tcp_client_connect_error");
    grpc_closure_sched(exec_ctx, closure, GRPC_OS_ERROR(errno, "connect"));
    goto done;
  }

  grpc_pollset_set_add_fd(exec_ctx, interested_parties, fdobj);

  ac = gpr_malloc(sizeof(async_connect));
  ac->closure = closure;
  ac->ep = ep;
  ac->fd = fdobj;
  ac->interested_parties = interested_parties;
  ac->addr_str = addr_str;
  addr_str = NULL;
  gpr_mu_init(&ac->mu);
  ac->refs = 2;
  grpc_closure_init(&ac->write_closure, on_writable, ac,
                    grpc_schedule_on_exec_ctx);
  ac->channel_args = grpc_channel_args_copy(channel_args);

  if (grpc_tcp_trace) {
    gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: asynchronously connecting",
            ac->addr_str);
  }

  gpr_mu_lock(&ac->mu);
  grpc_closure_init(&ac->on_alarm, tc_on_alarm, ac, grpc_schedule_on_exec_ctx);
  grpc_timer_init(exec_ctx, &ac->alarm,
                  gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
                  &ac->on_alarm, gpr_now(GPR_CLOCK_MONOTONIC));
  grpc_fd_notify_on_write(exec_ctx, ac->fd, &ac->write_closure);
  gpr_mu_unlock(&ac->mu);

done:
  gpr_free(name);
  gpr_free(addr_str);
}
Beispiel #5
0
/* Test some typical scenarios in pollset_set */
static void pollset_set_test_basic() {
  /* We construct the following structure for this test:
   *
   *        +---> FD0 (Added before PSS1, PS1 and PS2 are added to PSS0)
   *        |
   *        +---> FD5 (Added after PSS1, PS1 and PS2 are added to PSS0)
   *        |
   *        |
   *        |           +---> FD1 (Added before PSS1 is added to PSS0)
   *        |           |
   *        |           +---> FD6 (Added after PSS1 is added to PSS0)
   *        |           |
   *        +---> PSS1--+           +--> FD2 (Added before PS0 is added to PSS1)
   *        |           |           |
   *        |           +---> PS0---+
   *        |                       |
   * PSS0---+                       +--> FD7 (Added after PS0 is added to PSS1)
   *        |
   *        |
   *        |           +---> FD3 (Added before PS1 is added to PSS0)
   *        |           |
   *        +---> PS1---+
   *        |           |
   *        |           +---> FD8 (Added after PS1 added to PSS0)
   *        |
   *        |
   *        |           +---> FD4 (Added before PS2 is added to PSS0)
   *        |           |
   *        +---> PS2---+
   *                    |
   *                    +---> FD9 (Added after PS2 is added to PSS0)
   */
  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
  grpc_pollset_worker *worker;
  gpr_timespec deadline;

  test_fd tfds[10];
  test_pollset pollsets[3];
  test_pollset_set pollset_sets[2];
  const int num_fds = GPR_ARRAY_SIZE(tfds);
  const int num_ps = GPR_ARRAY_SIZE(pollsets);
  const int num_pss = GPR_ARRAY_SIZE(pollset_sets);

  init_test_fds(&exec_ctx, tfds, num_fds);
  init_test_pollsets(pollsets, num_ps);
  init_test_pollset_sets(pollset_sets, num_pss);

  /* Construct the pollset_set/pollset/fd tree (see diagram above) */

  grpc_pollset_set_add_fd(&exec_ctx, pollset_sets[0].pss, tfds[0].fd);
  grpc_pollset_set_add_fd(&exec_ctx, pollset_sets[1].pss, tfds[1].fd);

  grpc_pollset_add_fd(&exec_ctx, pollsets[0].ps, tfds[2].fd);
  grpc_pollset_add_fd(&exec_ctx, pollsets[1].ps, tfds[3].fd);
  grpc_pollset_add_fd(&exec_ctx, pollsets[2].ps, tfds[4].fd);

  grpc_pollset_set_add_pollset_set(&exec_ctx, pollset_sets[0].pss,
                                   pollset_sets[1].pss);

  grpc_pollset_set_add_pollset(&exec_ctx, pollset_sets[1].pss, pollsets[0].ps);
  grpc_pollset_set_add_pollset(&exec_ctx, pollset_sets[0].pss, pollsets[1].ps);
  grpc_pollset_set_add_pollset(&exec_ctx, pollset_sets[0].pss, pollsets[2].ps);

  grpc_pollset_set_add_fd(&exec_ctx, pollset_sets[0].pss, tfds[5].fd);
  grpc_pollset_set_add_fd(&exec_ctx, pollset_sets[1].pss, tfds[6].fd);

  grpc_pollset_add_fd(&exec_ctx, pollsets[0].ps, tfds[7].fd);
  grpc_pollset_add_fd(&exec_ctx, pollsets[1].ps, tfds[8].fd);
  grpc_pollset_add_fd(&exec_ctx, pollsets[2].ps, tfds[9].fd);

  grpc_exec_ctx_flush(&exec_ctx);

  /* Test that if any FD in the above structure is readable, it is observable by
   * doing grpc_pollset_work on any pollset
   *
   *   For every pollset, do the following:
   *     - (Ensure that all FDs are in reset state)
   *     - Make all FDs readable
   *     - Call grpc_pollset_work() on the pollset
   *     - Flush the exec_ctx
   *     - Verify that on_readable call back was called for all FDs (and
   *       reset the FDs)
   * */
  for (int i = 0; i < num_ps; i++) {
    make_test_fds_readable(tfds, num_fds);

    gpr_mu_lock(pollsets[i].mu);
    deadline = grpc_timeout_milliseconds_to_deadline(2);
    GPR_ASSERT(GRPC_ERROR_NONE ==
               grpc_pollset_work(&exec_ctx, pollsets[i].ps, &worker,
                                 gpr_now(GPR_CLOCK_MONOTONIC), deadline));
    gpr_mu_unlock(pollsets[i].mu);

    grpc_exec_ctx_flush(&exec_ctx);

    verify_readable_and_reset(&exec_ctx, tfds, num_fds);
    grpc_exec_ctx_flush(&exec_ctx);
  }

  /* Test tear down */
  grpc_pollset_set_del_fd(&exec_ctx, pollset_sets[0].pss, tfds[0].fd);
  grpc_pollset_set_del_fd(&exec_ctx, pollset_sets[0].pss, tfds[5].fd);
  grpc_pollset_set_del_fd(&exec_ctx, pollset_sets[1].pss, tfds[1].fd);
  grpc_pollset_set_del_fd(&exec_ctx, pollset_sets[1].pss, tfds[6].fd);
  grpc_exec_ctx_flush(&exec_ctx);

  grpc_pollset_set_del_pollset(&exec_ctx, pollset_sets[1].pss, pollsets[0].ps);
  grpc_pollset_set_del_pollset(&exec_ctx, pollset_sets[0].pss, pollsets[1].ps);
  grpc_pollset_set_del_pollset(&exec_ctx, pollset_sets[0].pss, pollsets[2].ps);

  grpc_pollset_set_del_pollset_set(&exec_ctx, pollset_sets[0].pss,
                                   pollset_sets[1].pss);
  grpc_exec_ctx_flush(&exec_ctx);

  cleanup_test_fds(&exec_ctx, tfds, num_fds);
  cleanup_test_pollsets(&exec_ctx, pollsets, num_ps);
  cleanup_test_pollset_sets(&exec_ctx, pollset_sets, num_pss);
  grpc_exec_ctx_finish(&exec_ctx);
}