Example #1
0
/* Cleaning up a list with pending timers. */
void destruction_test(void) {
  grpc_timer timers[5];
  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;

  grpc_timer_list_init(gpr_time_0(GPR_CLOCK_REALTIME));
  memset(cb_called, 0, sizeof(cb_called));

  grpc_timer_init(&exec_ctx, &timers[0], tfm(100), cb, (void *)(intptr_t)0,
                  gpr_time_0(GPR_CLOCK_REALTIME));
  grpc_timer_init(&exec_ctx, &timers[1], tfm(3), cb, (void *)(intptr_t)1,
                  gpr_time_0(GPR_CLOCK_REALTIME));
  grpc_timer_init(&exec_ctx, &timers[2], tfm(100), cb, (void *)(intptr_t)2,
                  gpr_time_0(GPR_CLOCK_REALTIME));
  grpc_timer_init(&exec_ctx, &timers[3], tfm(3), cb, (void *)(intptr_t)3,
                  gpr_time_0(GPR_CLOCK_REALTIME));
  grpc_timer_init(&exec_ctx, &timers[4], tfm(1), cb, (void *)(intptr_t)4,
                  gpr_time_0(GPR_CLOCK_REALTIME));
  GPR_ASSERT(1 == grpc_timer_check(&exec_ctx, tfm(2), NULL));
  grpc_exec_ctx_finish(&exec_ctx);
  GPR_ASSERT(1 == cb_called[4][1]);
  grpc_timer_cancel(&exec_ctx, &timers[0]);
  grpc_timer_cancel(&exec_ctx, &timers[3]);
  grpc_exec_ctx_finish(&exec_ctx);
  GPR_ASSERT(1 == cb_called[0][0]);
  GPR_ASSERT(1 == cb_called[3][0]);

  grpc_timer_list_shutdown(&exec_ctx);
  grpc_exec_ctx_finish(&exec_ctx);
  GPR_ASSERT(1 == cb_called[1][0]);
  GPR_ASSERT(1 == cb_called[2][0]);
}
Example #2
0
static void dns_on_resolved(grpc_exec_ctx *exec_ctx, void *arg,
                            grpc_resolved_addresses *addresses) {
    dns_resolver *r = arg;
    grpc_client_config *config = NULL;
    grpc_subchannel **subchannels;
    grpc_subchannel_args args;
    grpc_lb_policy *lb_policy;
    size_t i;
    gpr_mu_lock(&r->mu);
    GPR_ASSERT(r->resolving);
    r->resolving = 0;
    if (addresses != NULL) {
        grpc_lb_policy_args lb_policy_args;
        config = grpc_client_config_create();
        subchannels = gpr_malloc(sizeof(grpc_subchannel *) * addresses->naddrs);
        size_t naddrs = 0;
        for (i = 0; i < addresses->naddrs; i++) {
            memset(&args, 0, sizeof(args));
            args.addr = (struct sockaddr *)(addresses->addrs[i].addr);
            args.addr_len = (size_t)addresses->addrs[i].len;
            grpc_subchannel *subchannel = grpc_subchannel_factory_create_subchannel(
                                              exec_ctx, r->subchannel_factory, &args);
            if (subchannel != NULL) {
                subchannels[naddrs++] = subchannel;
            }
        }
        memset(&lb_policy_args, 0, sizeof(lb_policy_args));
        lb_policy_args.subchannels = subchannels;
        lb_policy_args.num_subchannels = naddrs;
        lb_policy = grpc_lb_policy_create(r->lb_policy_name, &lb_policy_args);
        if (lb_policy != NULL) {
            grpc_client_config_set_lb_policy(config, lb_policy);
            GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "construction");
        }
        grpc_resolved_addresses_destroy(addresses);
        gpr_free(subchannels);
    } else {
        int retry_seconds = 15;
        gpr_log(GPR_DEBUG, "dns resolution failed: retrying in %d seconds",
                retry_seconds);
        GPR_ASSERT(!r->have_retry_timer);
        r->have_retry_timer = true;
        gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
        GRPC_RESOLVER_REF(&r->base, "retry-timer");
        grpc_timer_init(
            exec_ctx, &r->retry_timer,
            gpr_time_add(now, gpr_time_from_seconds(retry_seconds, GPR_TIMESPAN)),
            dns_on_retry_timer, r, now);
    }
    if (r->resolved_config) {
        grpc_client_config_unref(exec_ctx, r->resolved_config);
    }
    r->resolved_config = config;
    r->resolved_version++;
    dns_maybe_finish_next_locked(exec_ctx, r);
    gpr_mu_unlock(&r->mu);

    GRPC_RESOLVER_UNREF(exec_ctx, &r->base, "dns-resolving");
}
Example #3
0
static void watcher_timer_init(grpc_exec_ctx *exec_ctx, void *arg,
                               grpc_error *error_ignored) {
  watcher_timer_init_arg *wa = (watcher_timer_init_arg *)arg;

  grpc_timer_init(exec_ctx, &wa->w->alarm,
                  gpr_convert_clock_type(wa->deadline, GPR_CLOCK_MONOTONIC),
                  &wa->w->on_timeout, gpr_now(GPR_CLOCK_MONOTONIC));
  gpr_free(wa);
}
Example #4
0
void my_resolve_address(grpc_exec_ctx *exec_ctx, const char *addr,
                        const char *default_port, grpc_resolve_cb cb,
                        void *arg) {
  addr_req *r = gpr_malloc(sizeof(*r));
  r->addr = gpr_strdup(addr);
  r->cb = cb;
  r->arg = arg;
  grpc_timer_init(exec_ctx, &r->timer,
                  gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
                               gpr_time_from_seconds(1, GPR_TIMESPAN)),
                  finish_resolve, r, gpr_now(GPR_CLOCK_MONOTONIC));
}
Example #5
0
static void set_deadline_alarm(grpc_exec_ctx *exec_ctx, grpc_call *call,
                               gpr_timespec deadline) {
  if (call->have_alarm) {
    gpr_log(GPR_ERROR, "Attempt to set deadline alarm twice");
    assert(0);
    return;
  }
  GRPC_CALL_INTERNAL_REF(call, "alarm");
  call->have_alarm = 1;
  call->send_deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC);
  grpc_timer_init(exec_ctx, &call->alarm, call->send_deadline, call_alarm, call,
                  gpr_now(GPR_CLOCK_MONOTONIC));
}
Example #6
0
void grpc_alarm_set(grpc_alarm *alarm, grpc_completion_queue *cq,
                    gpr_timespec deadline, void *tag, void *reserved) {
  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;

  GRPC_CQ_INTERNAL_REF(cq, "alarm");
  alarm->cq = cq;
  alarm->tag = tag;

  GPR_ASSERT(grpc_cq_begin_op(cq, tag));
  grpc_timer_init(&exec_ctx, &alarm->alarm,
                  gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
                  &alarm->on_alarm, gpr_now(GPR_CLOCK_MONOTONIC));
  grpc_exec_ctx_finish(&exec_ctx);
}
Example #7
0
static void dns_on_resolved(grpc_exec_ctx *exec_ctx, void *arg,
                            grpc_error *error) {
  dns_resolver *r = arg;
  grpc_channel_args *result = NULL;
  gpr_mu_lock(&r->mu);
  GPR_ASSERT(r->resolving);
  r->resolving = false;
  if (r->addresses != NULL) {
    grpc_lb_addresses *addresses = grpc_lb_addresses_create(
        r->addresses->naddrs, NULL /* user_data_vtable */);
    for (size_t i = 0; i < r->addresses->naddrs; ++i) {
      grpc_lb_addresses_set_address(
          addresses, i, &r->addresses->addrs[i].addr,
          r->addresses->addrs[i].len, false /* is_balancer */,
          NULL /* balancer_name */, NULL /* user_data */);
    }
    grpc_arg new_arg = grpc_lb_addresses_create_channel_arg(addresses);
    result = grpc_channel_args_copy_and_add(r->channel_args, &new_arg, 1);
    grpc_resolved_addresses_destroy(r->addresses);
    grpc_lb_addresses_destroy(addresses);
  } else {
    gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
    gpr_timespec next_try = gpr_backoff_step(&r->backoff_state, now);
    gpr_timespec timeout = gpr_time_sub(next_try, now);
    const char *msg = grpc_error_string(error);
    gpr_log(GPR_DEBUG, "dns resolution failed: %s", msg);
    grpc_error_free_string(msg);
    GPR_ASSERT(!r->have_retry_timer);
    r->have_retry_timer = true;
    GRPC_RESOLVER_REF(&r->base, "retry-timer");
    if (gpr_time_cmp(timeout, gpr_time_0(timeout.clock_type)) > 0) {
      gpr_log(GPR_DEBUG, "retrying in %" PRId64 ".%09d seconds", timeout.tv_sec,
              timeout.tv_nsec);
    } else {
      gpr_log(GPR_DEBUG, "retrying immediately");
    }
    grpc_timer_init(exec_ctx, &r->retry_timer, next_try, dns_on_retry_timer, r,
                    now);
  }
  if (r->resolved_result != NULL) {
    grpc_channel_args_destroy(r->resolved_result);
  }
  r->resolved_result = result;
  r->resolved_version++;
  dns_maybe_finish_next_locked(exec_ctx, r);
  gpr_mu_unlock(&r->mu);

  GRPC_RESOLVER_UNREF(exec_ctx, &r->base, "dns-resolving");
}
Example #8
0
// Starts the deadline timer.
static void start_timer_if_needed(grpc_exec_ctx* exec_ctx,
                                  grpc_call_element* elem,
                                  gpr_timespec deadline) {
  grpc_deadline_state* deadline_state = elem->call_data;
  deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC);
  if (gpr_time_cmp(deadline, gpr_inf_future(GPR_CLOCK_MONOTONIC)) != 0) {
    // Take a reference to the call stack, to be owned by the timer.
    GRPC_CALL_STACK_REF(deadline_state->call_stack, "deadline_timer");
    gpr_mu_lock(&deadline_state->timer_mu);
    deadline_state->timer_pending = true;
    grpc_timer_init(exec_ctx, &deadline_state->timer, deadline, timer_callback,
                    elem, gpr_now(GPR_CLOCK_MONOTONIC));
    gpr_mu_unlock(&deadline_state->timer_mu);
  }
}
Example #9
0
grpc_alarm *grpc_alarm_create(grpc_completion_queue *cq, gpr_timespec deadline,
                              void *tag) {
    grpc_alarm *alarm = gpr_malloc(sizeof(grpc_alarm));
    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;

    GRPC_CQ_INTERNAL_REF(cq, "alarm");
    alarm->cq = cq;
    alarm->tag = tag;

    grpc_timer_init(&exec_ctx, &alarm->alarm, deadline, alarm_cb, alarm,
                    gpr_now(GPR_CLOCK_MONOTONIC));
    grpc_cq_begin_op(cq, tag);
    grpc_exec_ctx_finish(&exec_ctx);
    return alarm;
}
Example #10
0
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_exec_ctx_enqueue(exec_ctx, closure, false, NULL);
    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)),
                  do_connect, fc, gpr_now(GPR_CLOCK_MONOTONIC));
}
Example #11
0
void grpc_do_security_handshake(
    grpc_exec_ctx *exec_ctx, tsi_handshaker *handshaker,
    grpc_security_connector *connector, bool is_client_side,
    grpc_endpoint *nonsecure_endpoint, gpr_slice_buffer *read_buffer,
    gpr_timespec deadline, grpc_security_handshake_done_cb cb,
    void *user_data) {
    grpc_security_connector_handshake_list *handshake_node;
    grpc_security_handshake *h = gpr_malloc(sizeof(grpc_security_handshake));
    memset(h, 0, sizeof(grpc_security_handshake));
    h->handshaker = handshaker;
    h->connector = GRPC_SECURITY_CONNECTOR_REF(connector, "handshake");
    h->is_client_side = is_client_side;
    h->handshake_buffer_size = GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE;
    h->handshake_buffer = gpr_malloc(h->handshake_buffer_size);
    h->wrapped_endpoint = nonsecure_endpoint;
    h->user_data = user_data;
    h->cb = cb;
    gpr_ref_init(&h->refs, 2); /* timer and handshake proper each get a ref */
    grpc_closure_init(&h->on_handshake_data_sent_to_peer,
                      on_handshake_data_sent_to_peer, h);
    grpc_closure_init(&h->on_handshake_data_received_from_peer,
                      on_handshake_data_received_from_peer, h);
    gpr_slice_buffer_init(&h->left_overs);
    gpr_slice_buffer_init(&h->outgoing);
    gpr_slice_buffer_init(&h->incoming);
    if (read_buffer != NULL) {
        gpr_slice_buffer_move_into(read_buffer, &h->incoming);
        gpr_free(read_buffer);
    }
    if (!is_client_side) {
        grpc_server_security_connector *server_connector =
            (grpc_server_security_connector *)connector;
        handshake_node = gpr_malloc(sizeof(grpc_security_connector_handshake_list));
        handshake_node->handshake = h;
        gpr_mu_lock(&server_connector->mu);
        handshake_node->next = server_connector->handshaking_handshakes;
        server_connector->handshaking_handshakes = handshake_node;
        gpr_mu_unlock(&server_connector->mu);
    }
    send_handshake_bytes_to_peer(exec_ctx, h);
    grpc_timer_init(exec_ctx, &h->timer,
                    gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
                    on_timeout, h, gpr_now(GPR_CLOCK_MONOTONIC));
}
Example #12
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 *resolved_addr,
                                    gpr_timespec deadline) {
  grpc_uv_tcp_connect *connect;
  grpc_resource_quota *resource_quota = grpc_resource_quota_create(NULL);
  (void)channel_args;
  (void)interested_parties;

  if (channel_args != NULL) {
    for (size_t i = 0; i < channel_args->num_args; i++) {
      if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) {
        grpc_resource_quota_unref_internal(exec_ctx, resource_quota);
        resource_quota = grpc_resource_quota_ref_internal(
            channel_args->args[i].value.pointer.p);
      }
    }
  }

  connect = gpr_malloc(sizeof(grpc_uv_tcp_connect));
  memset(connect, 0, sizeof(grpc_uv_tcp_connect));
  connect->closure = closure;
  connect->endpoint = ep;
  connect->tcp_handle = gpr_malloc(sizeof(uv_tcp_t));
  connect->addr_name = grpc_sockaddr_to_uri(resolved_addr);
  connect->resource_quota = resource_quota;
  uv_tcp_init(uv_default_loop(), connect->tcp_handle);
  connect->connect_req.data = connect;
  // TODO(murgatroid99): figure out what the return value here means
  uv_tcp_connect(&connect->connect_req, connect->tcp_handle,
                 (const struct sockaddr *)resolved_addr->addr,
                 uv_tc_on_connect);
  grpc_closure_init(&connect->on_alarm, uv_tc_on_alarm, connect,
                    grpc_schedule_on_exec_ctx);
  grpc_timer_init(exec_ctx, &connect->alarm,
                  gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
                  &connect->on_alarm, gpr_now(GPR_CLOCK_MONOTONIC));
}
Example #13
0
/* Tries to issue one async connection, then schedules both an IOCP
   notification request for the connection, and one timeout alert. */
void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *on_done,
                             grpc_endpoint **endpoint,
                             grpc_pollset_set *interested_parties,
                             const struct sockaddr *addr, size_t addr_len,
                             gpr_timespec deadline) {
  SOCKET sock = INVALID_SOCKET;
  BOOL success;
  int status;
  struct sockaddr_in6 addr6_v4mapped;
  struct sockaddr_in6 local_address;
  async_connect *ac;
  grpc_winsocket *socket = NULL;
  LPFN_CONNECTEX ConnectEx;
  GUID guid = WSAID_CONNECTEX;
  DWORD ioctl_num_bytes;
  const char *message = NULL;
  char *utf8_message;
  grpc_winsocket_callback_info *info;

  *endpoint = 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);
  }

  sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
                   WSA_FLAG_OVERLAPPED);
  if (sock == INVALID_SOCKET) {
    message = "Unable to create socket: %s";
    goto failure;
  }

  if (!grpc_tcp_prepare_socket(sock)) {
    message = "Unable to set socket options: %s";
    goto failure;
  }

  /* Grab the function pointer for ConnectEx for that specific socket.
     It may change depending on the interface. */
  status =
      WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
               &ConnectEx, sizeof(ConnectEx), &ioctl_num_bytes, NULL, NULL);

  if (status != 0) {
    message = "Unable to retrieve ConnectEx pointer: %s";
    goto failure;
  }

  grpc_sockaddr_make_wildcard6(0, &local_address);

  status = bind(sock, (struct sockaddr *)&local_address, sizeof(local_address));
  if (status != 0) {
    message = "Unable to bind socket: %s";
    goto failure;
  }

  socket = grpc_winsocket_create(sock, "client");
  info = &socket->write_info;
  success =
      ConnectEx(sock, addr, (int)addr_len, NULL, 0, NULL, &info->overlapped);

  /* It wouldn't be unusual to get a success immediately. But we'll still get
     an IOCP notification, so let's ignore it. */
  if (!success) {
    int error = WSAGetLastError();
    if (error != ERROR_IO_PENDING) {
      message = "ConnectEx failed: %s";
      goto failure;
    }
  }

  ac = gpr_malloc(sizeof(async_connect));
  ac->on_done = on_done;
  ac->socket = socket;
  gpr_mu_init(&ac->mu);
  ac->refs = 2;
  ac->addr_name = grpc_sockaddr_to_uri(addr);
  ac->endpoint = endpoint;
  grpc_closure_init(&ac->on_connect, on_connect, ac);

  grpc_timer_init(exec_ctx, &ac->alarm, deadline, on_alarm, ac,
                  gpr_now(GPR_CLOCK_MONOTONIC));
  grpc_socket_notify_on_write(exec_ctx, socket, &ac->on_connect);
  return;

failure:
  utf8_message = gpr_format_message(WSAGetLastError());
  gpr_log(GPR_ERROR, message, utf8_message);
  gpr_free(utf8_message);
  if (socket != NULL) {
    grpc_winsocket_destroy(socket);
  } else if (sock != INVALID_SOCKET) {
    closesocket(sock);
  }
  grpc_exec_ctx_enqueue(exec_ctx, on_done, 0);
}
Example #14
0
static void add_test(void) {
  gpr_timespec start = gpr_now(GPR_CLOCK_REALTIME);
  int i;
  grpc_timer timers[20];
  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;

  grpc_timer_list_init(start);
  memset(cb_called, 0, sizeof(cb_called));

  /* 10 ms timers.  will expire in the current epoch */
  for (i = 0; i < 10; i++) {
    grpc_timer_init(&exec_ctx, &timers[i],
                    gpr_time_add(start, gpr_time_from_millis(10, GPR_TIMESPAN)),
                    cb, (void *)(intptr_t)i, start);
  }

  /* 1010 ms timers.  will expire in the next epoch */
  for (i = 10; i < 20; i++) {
    grpc_timer_init(
        &exec_ctx, &timers[i],
        gpr_time_add(start, gpr_time_from_millis(1010, GPR_TIMESPAN)), cb,
        (void *)(intptr_t)i, start);
  }

  /* collect timers.  Only the first batch should be ready. */
  GPR_ASSERT(10 == grpc_timer_check(&exec_ctx,
                                    gpr_time_add(start, gpr_time_from_millis(
                                                            500, GPR_TIMESPAN)),
                                    NULL));
  grpc_exec_ctx_finish(&exec_ctx);
  for (i = 0; i < 20; i++) {
    GPR_ASSERT(cb_called[i][1] == (i < 10));
    GPR_ASSERT(cb_called[i][0] == 0);
  }

  GPR_ASSERT(0 == grpc_timer_check(&exec_ctx,
                                   gpr_time_add(start, gpr_time_from_millis(
                                                           600, GPR_TIMESPAN)),
                                   NULL));
  grpc_exec_ctx_finish(&exec_ctx);
  for (i = 0; i < 30; i++) {
    GPR_ASSERT(cb_called[i][1] == (i < 10));
    GPR_ASSERT(cb_called[i][0] == 0);
  }

  /* collect the rest of the timers */
  GPR_ASSERT(10 == grpc_timer_check(
                       &exec_ctx, gpr_time_add(start, gpr_time_from_millis(
                                                          1500, GPR_TIMESPAN)),
                       NULL));
  grpc_exec_ctx_finish(&exec_ctx);
  for (i = 0; i < 30; i++) {
    GPR_ASSERT(cb_called[i][1] == (i < 20));
    GPR_ASSERT(cb_called[i][0] == 0);
  }

  GPR_ASSERT(0 == grpc_timer_check(&exec_ctx,
                                   gpr_time_add(start, gpr_time_from_millis(
                                                           1600, GPR_TIMESPAN)),
                                   NULL));
  for (i = 0; i < 30; i++) {
    GPR_ASSERT(cb_called[i][1] == (i < 20));
    GPR_ASSERT(cb_called[i][0] == 0);
  }

  grpc_timer_list_shutdown(&exec_ctx);
  grpc_exec_ctx_finish(&exec_ctx);
}
Example #15
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);
}
Example #16
0
/* Tries to issue one async connection, then schedules both an IOCP
   notification request for the connection, and one timeout alert. */
void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *on_done,
                             grpc_endpoint **endpoint,
                             grpc_pollset_set *interested_parties,
                             const grpc_channel_args *channel_args,
                             const grpc_resolved_address *addr,
                             gpr_timespec deadline) {
  SOCKET sock = INVALID_SOCKET;
  BOOL success;
  int status;
  grpc_resolved_address addr6_v4mapped;
  grpc_resolved_address local_address;
  async_connect *ac;
  grpc_winsocket *socket = NULL;
  LPFN_CONNECTEX ConnectEx;
  GUID guid = WSAID_CONNECTEX;
  DWORD ioctl_num_bytes;
  grpc_winsocket_callback_info *info;
  grpc_error *error = GRPC_ERROR_NONE;

  grpc_resource_quota *resource_quota = grpc_resource_quota_create(NULL);
  if (channel_args != NULL) {
    for (size_t i = 0; i < channel_args->num_args; i++) {
      if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) {
        grpc_resource_quota_internal_unref(exec_ctx, resource_quota);
        resource_quota = grpc_resource_quota_internal_ref(
            channel_args->args[i].value.pointer.p);
      }
    }
  }

  *endpoint = NULL;

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

  sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
                   WSA_FLAG_OVERLAPPED);
  if (sock == INVALID_SOCKET) {
    error = GRPC_WSA_ERROR(WSAGetLastError(), "WSASocket");
    goto failure;
  }

  error = grpc_tcp_prepare_socket(sock);
  if (error != GRPC_ERROR_NONE) {
    goto failure;
  }

  /* Grab the function pointer for ConnectEx for that specific socket.
     It may change depending on the interface. */
  status =
      WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
               &ConnectEx, sizeof(ConnectEx), &ioctl_num_bytes, NULL, NULL);

  if (status != 0) {
    error = GRPC_WSA_ERROR(WSAGetLastError(),
                           "WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER)");
    goto failure;
  }

  grpc_sockaddr_make_wildcard6(0, &local_address);

  status = bind(sock, (struct sockaddr *)&local_address.addr,
                (int)local_address.len);
  if (status != 0) {
    error = GRPC_WSA_ERROR(WSAGetLastError(), "bind");
    goto failure;
  }

  socket = grpc_winsocket_create(sock, "client");
  info = &socket->write_info;
  success = ConnectEx(sock, (struct sockaddr *)&addr->addr, (int)addr->len,
                      NULL, 0, NULL, &info->overlapped);

  /* It wouldn't be unusual to get a success immediately. But we'll still get
     an IOCP notification, so let's ignore it. */
  if (!success) {
    int last_error = WSAGetLastError();
    if (last_error != ERROR_IO_PENDING) {
      error = GRPC_WSA_ERROR(last_error, "ConnectEx");
      goto failure;
    }
  }

  ac = gpr_malloc(sizeof(async_connect));
  ac->on_done = on_done;
  ac->socket = socket;
  gpr_mu_init(&ac->mu);
  ac->refs = 2;
  ac->addr_name = grpc_sockaddr_to_uri(addr);
  ac->endpoint = endpoint;
  ac->resource_quota = resource_quota;
  grpc_closure_init(&ac->on_connect, on_connect, ac);

  grpc_timer_init(exec_ctx, &ac->alarm, deadline, on_alarm, ac,
                  gpr_now(GPR_CLOCK_MONOTONIC));
  grpc_socket_notify_on_write(exec_ctx, socket, &ac->on_connect);
  return;

failure:
  GPR_ASSERT(error != GRPC_ERROR_NONE);
  char *target_uri = grpc_sockaddr_to_uri(addr);
  grpc_error *final_error = grpc_error_set_str(
      GRPC_ERROR_CREATE_REFERENCING("Failed to connect", &error, 1),
      GRPC_ERROR_STR_TARGET_ADDRESS, target_uri);
  GRPC_ERROR_UNREF(error);
  if (socket != NULL) {
    grpc_winsocket_destroy(socket);
  } else if (sock != INVALID_SOCKET) {
    closesocket(sock);
  }
  grpc_resource_quota_internal_unref(exec_ctx, resource_quota);
  grpc_exec_ctx_sched(exec_ctx, on_done, final_error, NULL);
}