/* Bind to "::" to get a port number not used by any address. */
static grpc_error *get_unused_port(int *port) {
  grpc_resolved_address wild;
  grpc_sockaddr_make_wildcard6(0, &wild);
  grpc_dualstack_mode dsmode;
  int fd;
  grpc_error *err =
      grpc_create_dualstack_socket(&wild, SOCK_STREAM, 0, &dsmode, &fd);
  if (err != GRPC_ERROR_NONE) {
    return err;
  }
  if (dsmode == GRPC_DSMODE_IPV4) {
    grpc_sockaddr_make_wildcard4(0, &wild);
  }
  if (bind(fd, (const struct sockaddr *)wild.addr, (socklen_t)wild.len) != 0) {
    err = GRPC_OS_ERROR(errno, "bind");
    close(fd);
    return err;
  }
  if (getsockname(fd, (struct sockaddr *)wild.addr, (socklen_t *)&wild.len) !=
      0) {
    err = GRPC_OS_ERROR(errno, "getsockname");
    close(fd);
    return err;
  }
  close(fd);
  *port = grpc_sockaddr_get_port(&wild);
  return *port <= 0 ? GRPC_ERROR_CREATE_FROM_STATIC_STRING("Bad port")
                    : GRPC_ERROR_NONE;
}
Example #2
0
/* Prepare a recently-created socket for listening. */
static grpc_error *prepare_socket(int fd, const struct sockaddr *addr,
                                  size_t addr_len, bool so_reuseport,
                                  int *port) {
  struct sockaddr_storage sockname_temp;
  socklen_t sockname_len;
  grpc_error *err = GRPC_ERROR_NONE;

  GPR_ASSERT(fd >= 0);

  if (so_reuseport) {
    err = grpc_set_socket_reuse_port(fd, 1);
    if (err != GRPC_ERROR_NONE) goto error;
  }

  err = grpc_set_socket_nonblocking(fd, 1);
  if (err != GRPC_ERROR_NONE) goto error;
  err = grpc_set_socket_cloexec(fd, 1);
  if (err != GRPC_ERROR_NONE) goto error;
  if (!grpc_is_unix_socket(addr)) {
    err = grpc_set_socket_low_latency(fd, 1);
    if (err != GRPC_ERROR_NONE) goto error;
    err = grpc_set_socket_reuse_addr(fd, 1);
    if (err != GRPC_ERROR_NONE) goto error;
  }
  err = grpc_set_socket_no_sigpipe_if_possible(fd);
  if (err != GRPC_ERROR_NONE) goto error;

  GPR_ASSERT(addr_len < ~(socklen_t)0);
  if (bind(fd, addr, (socklen_t)addr_len) < 0) {
    err = GRPC_OS_ERROR(errno, "bind");
    goto error;
  }

  if (listen(fd, get_max_accept_queue_size()) < 0) {
    err = GRPC_OS_ERROR(errno, "listen");
    goto error;
  }

  sockname_len = sizeof(sockname_temp);
  if (getsockname(fd, (struct sockaddr *)&sockname_temp, &sockname_len) < 0) {
    err = GRPC_OS_ERROR(errno, "getsockname");
    goto error;
  }

  *port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
  return GRPC_ERROR_NONE;

error:
  GPR_ASSERT(err != GRPC_ERROR_NONE);
  if (fd >= 0) {
    close(fd);
  }
  grpc_error *ret = grpc_error_set_int(
      GRPC_ERROR_CREATE_REFERENCING("Unable to configure socket", &err, 1),
      GRPC_ERROR_INT_FD, fd);
  GRPC_ERROR_UNREF(err);
  return ret;
}
Example #3
0
static grpc_error *tcp_connect(grpc_exec_ctx *exec_ctx, const test_addr *remote,
                               on_connect_result *result) {
  gpr_timespec deadline = grpc_timeout_seconds_to_deadline(10);
  int clifd;
  int nconnects_before;
  const struct sockaddr *remote_addr =
      (const struct sockaddr *)remote->addr.addr;

  gpr_log(GPR_INFO, "Connecting to %s", remote->str);
  gpr_mu_lock(g_mu);
  nconnects_before = g_nconnects;
  on_connect_result_init(&g_result);
  clifd = socket(remote_addr->sa_family, SOCK_STREAM, 0);
  if (clifd < 0) {
    gpr_mu_unlock(g_mu);
    return GRPC_OS_ERROR(errno, "Failed to create socket");
  }
  gpr_log(GPR_DEBUG, "start connect to %s", remote->str);
  if (connect(clifd, remote_addr, (socklen_t)remote->addr.len) != 0) {
    gpr_mu_unlock(g_mu);
    close(clifd);
    return GRPC_OS_ERROR(errno, "connect");
  }
  gpr_log(GPR_DEBUG, "wait");
  while (g_nconnects == nconnects_before &&
         gpr_time_cmp(deadline, gpr_now(deadline.clock_type)) > 0) {
    grpc_pollset_worker *worker = NULL;
    grpc_error *err;
    if ((err = grpc_pollset_work(exec_ctx, g_pollset, &worker,
                                 gpr_now(GPR_CLOCK_MONOTONIC), deadline)) !=
        GRPC_ERROR_NONE) {
      gpr_mu_unlock(g_mu);
      close(clifd);
      return err;
    }
    gpr_mu_unlock(g_mu);
    grpc_exec_ctx_finish(exec_ctx);
    gpr_mu_lock(g_mu);
  }
  gpr_log(GPR_DEBUG, "wait done");
  if (g_nconnects != nconnects_before + 1) {
    gpr_mu_unlock(g_mu);
    close(clifd);
    return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Didn't connect");
  }
  close(clifd);
  *result = g_result;

  gpr_mu_unlock(g_mu);
  gpr_log(GPR_INFO, "Result (%d, %d) fd %d", result->port_index,
          result->fd_index, result->server_fd);
  grpc_tcp_server_unref(exec_ctx, result->server);
  return GRPC_ERROR_NONE;
}
Example #4
0
/* disable nagle */
grpc_error *grpc_set_socket_low_latency(int fd, int low_latency) {
  int val = (low_latency != 0);
  int newval;
  socklen_t intlen = sizeof(newval);
  if (0 != setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val))) {
    return GRPC_OS_ERROR(errno, "setsockopt(TCP_NODELAY)");
  }
  if (0 != getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &newval, &intlen)) {
    return GRPC_OS_ERROR(errno, "getsockopt(TCP_NODELAY)");
  }
  if ((newval != 0) != val) {
    return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed to set TCP_NODELAY");
  }
  return GRPC_ERROR_NONE;
}
Example #5
0
grpc_error *grpc_load_file(const char *filename, int add_null_terminator,
                           grpc_slice *output) {
  unsigned char *contents = NULL;
  size_t contents_size = 0;
  grpc_slice result = grpc_empty_slice();
  FILE *file;
  size_t bytes_read = 0;
  grpc_error *error = GRPC_ERROR_NONE;

  GRPC_SCHEDULING_START_BLOCKING_REGION;
  file = fopen(filename, "rb");
  if (file == NULL) {
    error = GRPC_OS_ERROR(errno, "fopen");
    goto end;
  }
  fseek(file, 0, SEEK_END);
  /* Converting to size_t on the assumption that it will not fail */
  contents_size = (size_t)ftell(file);
  fseek(file, 0, SEEK_SET);
  contents = (unsigned char *)gpr_malloc(contents_size +
                                         (add_null_terminator ? 1 : 0));
  bytes_read = fread(contents, 1, contents_size, file);
  if (bytes_read < contents_size) {
    error = GRPC_OS_ERROR(errno, "fread");
    GPR_ASSERT(ferror(file));
    goto end;
  }
  if (add_null_terminator) {
    contents[contents_size++] = 0;
  }
  result = grpc_slice_new(contents, contents_size, gpr_free);

end:
  *output = result;
  if (file != NULL) fclose(file);
  if (error != GRPC_ERROR_NONE) {
    grpc_error *error_out =
        grpc_error_set_str(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
                               "Failed to load file", &error, 1),
                           GRPC_ERROR_STR_FILENAME,
                           grpc_slice_from_copied_string(
                               filename));  // TODO(ncteisen), always static?
    GRPC_ERROR_UNREF(error);
    error = error_out;
  }
  GRPC_SCHEDULING_END_BLOCKING_REGION;
  return error;
}
Example #6
0
/* set a socket to reuse old addresses */
grpc_error *grpc_set_socket_reuse_addr(int fd, int reuse) {
  int val = (reuse != 0);
  int newval;
  socklen_t intlen = sizeof(newval);
  if (0 != setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val))) {
    return GRPC_OS_ERROR(errno, "setsockopt(SO_REUSEADDR)");
  }
  if (0 != getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &newval, &intlen)) {
    return GRPC_OS_ERROR(errno, "getsockopt(SO_REUSEADDR)");
  }
  if ((newval != 0) != val) {
    return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed to set SO_REUSEADDR");
  }

  return GRPC_ERROR_NONE;
}
Example #7
0
static grpc_error *pollset_epoll(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
                                 pollable *p, gpr_timespec now,
                                 gpr_timespec deadline) {
  int timeout = poll_deadline_to_millis_timeout(deadline, now);

  if (GRPC_TRACER_ON(grpc_polling_trace)) {
    gpr_log(GPR_DEBUG, "PS:%p poll %p for %dms", pollset, p, timeout);
  }

  if (timeout != 0) {
    GRPC_SCHEDULING_START_BLOCKING_REGION;
  }
  int r;
  do {
    r = epoll_wait(p->epfd, pollset->events, MAX_EPOLL_EVENTS, timeout);
  } while (r < 0 && errno == EINTR);
  if (timeout != 0) {
    GRPC_SCHEDULING_END_BLOCKING_REGION;
  }

  if (r < 0) return GRPC_OS_ERROR(errno, "epoll_wait");

  if (GRPC_TRACER_ON(grpc_polling_trace)) {
    gpr_log(GPR_DEBUG, "PS:%p poll %p got %d events", pollset, p, r);
  }

  pollset->event_cursor = 0;
  pollset->event_count = r;

  return GRPC_ERROR_NONE;
}
Example #8
0
grpc_error *grpc_set_socket_no_sigpipe_if_possible(int fd) {
#ifdef GRPC_HAVE_SO_NOSIGPIPE
  int val = 1;
  int newval;
  socklen_t intlen = sizeof(newval);
  if (0 != setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(val))) {
    return GRPC_OS_ERROR(errno, "setsockopt(SO_NOSIGPIPE)");
  }
  if (0 != getsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &newval, &intlen)) {
    return GRPC_OS_ERROR(errno, "getsockopt(SO_NOSIGPIPE)");
  }
  if ((newval != 0) != (val != 0)) {
    return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed to set SO_NOSIGPIPE");
  }
#endif
  return GRPC_ERROR_NONE;
}
Example #9
0
/* set a socket to close on exec */
grpc_error *grpc_set_socket_cloexec(int fd, int close_on_exec) {
  int oldflags = fcntl(fd, F_GETFD, 0);
  if (oldflags < 0) {
    return GRPC_OS_ERROR(errno, "fcntl");
  }

  if (close_on_exec) {
    oldflags |= FD_CLOEXEC;
  } else {
    oldflags &= ~FD_CLOEXEC;
  }

  if (fcntl(fd, F_SETFD, oldflags) != 0) {
    return GRPC_OS_ERROR(errno, "fcntl");
  }

  return GRPC_ERROR_NONE;
}
Example #10
0
/* set a socket to non blocking mode */
grpc_error *grpc_set_socket_nonblocking(int fd, int non_blocking) {
  int oldflags = fcntl(fd, F_GETFL, 0);
  if (oldflags < 0) {
    return GRPC_OS_ERROR(errno, "fcntl");
  }

  if (non_blocking) {
    oldflags |= O_NONBLOCK;
  } else {
    oldflags &= ~O_NONBLOCK;
  }

  if (fcntl(fd, F_SETFL, oldflags) != 0) {
    return GRPC_OS_ERROR(errno, "fcntl");
  }

  return GRPC_ERROR_NONE;
}
Example #11
0
static grpc_error *error_for_fd(int fd, const grpc_resolved_address *addr) {
  if (fd >= 0) return GRPC_ERROR_NONE;
  char *addr_str;
  grpc_sockaddr_to_string(&addr_str, addr, 0);
  grpc_error *err = grpc_error_set_str(GRPC_OS_ERROR(errno, "socket"),
                                       GRPC_ERROR_STR_TARGET_ADDRESS,
                                       grpc_slice_from_copied_string(addr_str));
  gpr_free(addr_str);
  return err;
}
Example #12
0
grpc_error *grpc_set_socket_ip_pktinfo_if_possible(int fd) {
#ifdef GRPC_HAVE_IP_PKTINFO
  int get_local_ip = 1;
  if (0 != setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &get_local_ip,
                      sizeof(get_local_ip))) {
    return GRPC_OS_ERROR(errno, "setsockopt(IP_PKTINFO)");
  }
#endif
  return GRPC_ERROR_NONE;
}
Example #13
0
/* set a socket to reuse old addresses */
grpc_error *grpc_set_socket_reuse_port(int fd, int reuse) {
#ifndef SO_REUSEPORT
  return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
      "SO_REUSEPORT unavailable on compiling system");
#else
  int val = (reuse != 0);
  int newval;
  socklen_t intlen = sizeof(newval);
  if (0 != setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val))) {
    return GRPC_OS_ERROR(errno, "setsockopt(SO_REUSEPORT)");
  }
  if (0 != getsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &newval, &intlen)) {
    return GRPC_OS_ERROR(errno, "getsockopt(SO_REUSEPORT)");
  }
  if ((newval != 0) != val) {
    return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed to set SO_REUSEPORT");
  }

  return GRPC_ERROR_NONE;
#endif
}
Example #14
0
/* ensure that p->epfd, p->wakeup are initialized; p->po.mu must be held */
static grpc_error *pollable_materialize(pollable *p) {
  if (p->epfd == -1) {
    int new_epfd = epoll_create1(EPOLL_CLOEXEC);
    if (new_epfd < 0) {
      return GRPC_OS_ERROR(errno, "epoll_create1");
    }
    grpc_error *err = grpc_wakeup_fd_init(&p->wakeup);
    if (err != GRPC_ERROR_NONE) {
      close(new_epfd);
      return err;
    }
    struct epoll_event ev = {.events = (uint32_t)(EPOLLIN | EPOLLET),
                             .data.ptr = (void *)(1 | (intptr_t)&p->wakeup)};
    if (epoll_ctl(new_epfd, EPOLL_CTL_ADD, p->wakeup.read_fd, &ev) != 0) {
      err = GRPC_OS_ERROR(errno, "epoll_ctl");
      close(new_epfd);
      grpc_wakeup_fd_destroy(&p->wakeup);
      return err;
    }

    p->epfd = new_epfd;
  }
  return GRPC_ERROR_NONE;
}
Example #15
0
static grpc_error* pipe_init(grpc_wakeup_fd* fd_info) {
  int pipefd[2];
  int r = pipe(pipefd);
  if (0 != r) {
    gpr_log(GPR_ERROR, "pipe creation failed (%d): %s", errno, strerror(errno));
    return GRPC_OS_ERROR(errno, "pipe");
  }
  grpc_error* err;
  err = grpc_set_socket_nonblocking(pipefd[0], 1);
  if (err != GRPC_ERROR_NONE) return err;
  err = grpc_set_socket_nonblocking(pipefd[1], 1);
  if (err != GRPC_ERROR_NONE) return err;
  fd_info->read_fd = pipefd[0];
  fd_info->write_fd = pipefd[1];
  return GRPC_ERROR_NONE;
}
Example #16
0
/* pollable must be materialized */
static grpc_error *pollable_add_fd(pollable *p, grpc_fd *fd) {
  grpc_error *error = GRPC_ERROR_NONE;
  static const char *err_desc = "pollable_add_fd";
  const int epfd = p->epfd;
  GPR_ASSERT(epfd != -1);

  if (GRPC_TRACER_ON(grpc_polling_trace)) {
    gpr_log(GPR_DEBUG, "add fd %p to pollable %p", fd, p);
  }

  gpr_mu_lock(&fd->orphaned_mu);
  if (fd->orphaned) {
    gpr_mu_unlock(&fd->orphaned_mu);
    return GRPC_ERROR_NONE;
  }
  struct epoll_event ev_fd = {
      .events = (uint32_t)(EPOLLET | EPOLLIN | EPOLLOUT | EPOLLEXCLUSIVE),
      .data.ptr = fd};
  if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd->fd, &ev_fd) != 0) {
    switch (errno) {
      case EEXIST:
        break;
      default:
        append_error(&error, GRPC_OS_ERROR(errno, "epoll_ctl"), err_desc);
    }
  }
  gpr_mu_unlock(&fd->orphaned_mu);

  return error;
}

/*******************************************************************************
 * Pollset Definitions
 */

GPR_TLS_DECL(g_current_thread_pollset);
GPR_TLS_DECL(g_current_thread_worker);

/* Global state management */
static grpc_error *pollset_global_init(void) {
  gpr_tls_init(&g_current_thread_pollset);
  gpr_tls_init(&g_current_thread_worker);
  pollable_init(&g_empty_pollable, PO_EMPTY_POLLABLE);
  return GRPC_ERROR_NONE;
}
Example #17
0
static grpc_error* pipe_consume(grpc_wakeup_fd* fd_info) {
  char buf[128];
  ssize_t r;

  for (;;) {
    r = read(fd_info->read_fd, buf, sizeof(buf));
    if (r > 0) continue;
    if (r == 0) return GRPC_ERROR_NONE;
    switch (errno) {
      case EAGAIN:
        return GRPC_ERROR_NONE;
      case EINTR:
        continue;
      default:
        return GRPC_OS_ERROR(errno, "read");
    }
  }
}
Example #18
0
grpc_error *grpc_set_socket_rcvbuf(int fd, int buffer_size_bytes) {
  return 0 == setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &buffer_size_bytes,
                         sizeof(buffer_size_bytes))
             ? GRPC_ERROR_NONE
             : GRPC_OS_ERROR(errno, "setsockopt(SO_RCVBUF)");
}
grpc_error *grpc_tcp_server_add_all_local_addrs(grpc_tcp_server *s,
                                                unsigned port_index,
                                                int requested_port,
                                                int *out_port) {
  struct ifaddrs *ifa = NULL;
  struct ifaddrs *ifa_it;
  unsigned fd_index = 0;
  grpc_tcp_listener *sp = NULL;
  grpc_error *err = GRPC_ERROR_NONE;
  if (requested_port == 0) {
    /* Note: There could be a race where some local addrs can listen on the
       selected port and some can't. The sane way to handle this would be to
       retry by recreating the whole grpc_tcp_server. Backing out individual
       listeners and orphaning the FDs looks like too much trouble. */
    if ((err = get_unused_port(&requested_port)) != GRPC_ERROR_NONE) {
      return err;
    } else if (requested_port <= 0) {
      return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Bad get_unused_port()");
    }
    gpr_log(GPR_DEBUG, "Picked unused port %d", requested_port);
  }
  if (getifaddrs(&ifa) != 0 || ifa == NULL) {
    return GRPC_OS_ERROR(errno, "getifaddrs");
  }
  for (ifa_it = ifa; ifa_it != NULL; ifa_it = ifa_it->ifa_next) {
    grpc_resolved_address addr;
    char *addr_str = NULL;
    grpc_dualstack_mode dsmode;
    grpc_tcp_listener *new_sp = NULL;
    const char *ifa_name = (ifa_it->ifa_name ? ifa_it->ifa_name : "<unknown>");
    if (ifa_it->ifa_addr == NULL) {
      continue;
    } else if (ifa_it->ifa_addr->sa_family == AF_INET) {
      addr.len = sizeof(struct sockaddr_in);
    } else if (ifa_it->ifa_addr->sa_family == AF_INET6) {
      addr.len = sizeof(struct sockaddr_in6);
    } else {
      continue;
    }
    memcpy(addr.addr, ifa_it->ifa_addr, addr.len);
    if (!grpc_sockaddr_set_port(&addr, requested_port)) {
      /* Should never happen, because we check sa_family above. */
      err = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed to set port");
      break;
    }
    if (grpc_sockaddr_to_string(&addr_str, &addr, 0) < 0) {
      addr_str = gpr_strdup("<error>");
    }
    gpr_log(GPR_DEBUG,
            "Adding local addr from interface %s flags 0x%x to server: %s",
            ifa_name, ifa_it->ifa_flags, addr_str);
    /* We could have multiple interfaces with the same address (e.g., bonding),
       so look for duplicates. */
    if (find_listener_with_addr(s, &addr) != NULL) {
      gpr_log(GPR_DEBUG, "Skipping duplicate addr %s on interface %s", addr_str,
              ifa_name);
      gpr_free(addr_str);
      continue;
    }
    if ((err = grpc_tcp_server_add_addr(s, &addr, port_index, fd_index, &dsmode,
                                        &new_sp)) != GRPC_ERROR_NONE) {
      char *err_str = NULL;
      grpc_error *root_err;
      if (gpr_asprintf(&err_str, "Failed to add listener: %s", addr_str) < 0) {
        err_str = gpr_strdup("Failed to add listener");
      }
      root_err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(err_str);
      gpr_free(err_str);
      gpr_free(addr_str);
      err = grpc_error_add_child(root_err, err);
      break;
    } else {
      GPR_ASSERT(requested_port == new_sp->port);
      ++fd_index;
      if (sp != NULL) {
        new_sp->is_sibling = 1;
        sp->sibling = new_sp;
      }
      sp = new_sp;
    }
    gpr_free(addr_str);
  }
  freeifaddrs(ifa);
  if (err != GRPC_ERROR_NONE) {
    return err;
  } else if (sp == NULL) {
    return GRPC_ERROR_CREATE_FROM_STATIC_STRING("No local addresses");
  } else {
    *out_port = sp->port;
    return GRPC_ERROR_NONE;
  }
}
Example #20
0
static bool tcp_flush(grpc_tcp *tcp, grpc_error **error) {
  struct msghdr msg;
  struct iovec iov[MAX_WRITE_IOVEC];
  msg_iovlen_type iov_size;
  ssize_t sent_length;
  size_t sending_length;
  size_t trailing;
  size_t unwind_slice_idx;
  size_t unwind_byte_idx;

  for (;;) {
    sending_length = 0;
    unwind_slice_idx = tcp->outgoing_slice_idx;
    unwind_byte_idx = tcp->outgoing_byte_idx;
    for (iov_size = 0; tcp->outgoing_slice_idx != tcp->outgoing_buffer->count &&
                       iov_size != MAX_WRITE_IOVEC;
         iov_size++) {
      iov[iov_size].iov_base =
          GRPC_SLICE_START_PTR(
              tcp->outgoing_buffer->slices[tcp->outgoing_slice_idx]) +
          tcp->outgoing_byte_idx;
      iov[iov_size].iov_len =
          GRPC_SLICE_LENGTH(
              tcp->outgoing_buffer->slices[tcp->outgoing_slice_idx]) -
          tcp->outgoing_byte_idx;
      sending_length += iov[iov_size].iov_len;
      tcp->outgoing_slice_idx++;
      tcp->outgoing_byte_idx = 0;
    }
    GPR_ASSERT(iov_size > 0);

    msg.msg_name = NULL;
    msg.msg_namelen = 0;
    msg.msg_iov = iov;
    msg.msg_iovlen = iov_size;
    msg.msg_control = NULL;
    msg.msg_controllen = 0;
    msg.msg_flags = 0;

    GPR_TIMER_BEGIN("sendmsg", 1);
    do {
      /* TODO(klempner): Cork if this is a partial write */
      sent_length = sendmsg(tcp->fd, &msg, SENDMSG_FLAGS);
    } while (sent_length < 0 && errno == EINTR);
    GPR_TIMER_END("sendmsg", 0);

    if (sent_length < 0) {
      if (errno == EAGAIN) {
        tcp->outgoing_slice_idx = unwind_slice_idx;
        tcp->outgoing_byte_idx = unwind_byte_idx;
        return false;
      } else if (errno == EPIPE) {
        *error = grpc_error_set_int(GRPC_OS_ERROR(errno, "sendmsg"),
                                    GRPC_ERROR_INT_GRPC_STATUS,
                                    GRPC_STATUS_UNAVAILABLE);
        return true;
      } else {
        *error = tcp_annotate_error(GRPC_OS_ERROR(errno, "sendmsg"), tcp);
        return true;
      }
    }

    GPR_ASSERT(tcp->outgoing_byte_idx == 0);
    trailing = sending_length - (size_t)sent_length;
    while (trailing > 0) {
      size_t slice_length;

      tcp->outgoing_slice_idx--;
      slice_length = GRPC_SLICE_LENGTH(
          tcp->outgoing_buffer->slices[tcp->outgoing_slice_idx]);
      if (slice_length > trailing) {
        tcp->outgoing_byte_idx = slice_length - trailing;
        break;
      } else {
        trailing -= slice_length;
      }
    }

    if (tcp->outgoing_slice_idx == tcp->outgoing_buffer->count) {
      *error = GRPC_ERROR_NONE;
      return true;
    }
  };
}
Example #21
0
static void tcp_do_read(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
  struct msghdr msg;
  struct iovec iov[MAX_READ_IOVEC];
  ssize_t read_bytes;
  size_t i;

  GPR_ASSERT(!tcp->finished_edge);
  GPR_ASSERT(tcp->iov_size <= MAX_READ_IOVEC);
  GPR_ASSERT(tcp->incoming_buffer->count <= MAX_READ_IOVEC);
  GPR_TIMER_BEGIN("tcp_continue_read", 0);

  for (i = 0; i < tcp->incoming_buffer->count; i++) {
    iov[i].iov_base = GRPC_SLICE_START_PTR(tcp->incoming_buffer->slices[i]);
    iov[i].iov_len = GRPC_SLICE_LENGTH(tcp->incoming_buffer->slices[i]);
  }

  msg.msg_name = NULL;
  msg.msg_namelen = 0;
  msg.msg_iov = iov;
  msg.msg_iovlen = tcp->iov_size;
  msg.msg_control = NULL;
  msg.msg_controllen = 0;
  msg.msg_flags = 0;

  GPR_TIMER_BEGIN("recvmsg", 0);
  do {
    read_bytes = recvmsg(tcp->fd, &msg, 0);
  } while (read_bytes < 0 && errno == EINTR);
  GPR_TIMER_END("recvmsg", read_bytes >= 0);

  if (read_bytes < 0) {
    /* NB: After calling call_read_cb a parallel call of the read handler may
     * be running. */
    if (errno == EAGAIN) {
      if (tcp->iov_size > 1) {
        tcp->iov_size /= 2;
      }
      /* We've consumed the edge, request a new one */
      grpc_fd_notify_on_read(exec_ctx, tcp->em_fd, &tcp->read_closure);
    } else {
      grpc_slice_buffer_reset_and_unref(tcp->incoming_buffer);
      call_read_cb(exec_ctx, tcp,
                   tcp_annotate_error(GRPC_OS_ERROR(errno, "recvmsg"), tcp));
      TCP_UNREF(exec_ctx, tcp, "read");
    }
  } else if (read_bytes == 0) {
    /* 0 read size ==> end of stream */
    grpc_slice_buffer_reset_and_unref(tcp->incoming_buffer);
    call_read_cb(exec_ctx, tcp,
                 tcp_annotate_error(GRPC_ERROR_CREATE("Socket closed"), tcp));
    TCP_UNREF(exec_ctx, tcp, "read");
  } else {
    GPR_ASSERT((size_t)read_bytes <= tcp->incoming_buffer->length);
    if ((size_t)read_bytes < tcp->incoming_buffer->length) {
      grpc_slice_buffer_trim_end(
          tcp->incoming_buffer,
          tcp->incoming_buffer->length - (size_t)read_bytes,
          &tcp->last_read_buffer);
    } else if (tcp->iov_size < MAX_READ_IOVEC) {
      ++tcp->iov_size;
    }
    GPR_ASSERT((size_t)read_bytes == tcp->incoming_buffer->length);
    call_read_cb(exec_ctx, tcp, GRPC_ERROR_NONE);
    TCP_UNREF(exec_ctx, tcp, "read");
  }

  GPR_TIMER_END("tcp_continue_read", 0);
}
Example #22
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 #23
0
static void on_writable(grpc_exec_ctx *exec_ctx, void *acp, grpc_error *error) {
  async_connect *ac = acp;
  int so_error = 0;
  socklen_t so_error_size;
  int err;
  int done;
  grpc_endpoint **ep = ac->ep;
  grpc_closure *closure = ac->closure;
  grpc_fd *fd;

  GRPC_ERROR_REF(error);

  if (grpc_tcp_trace) {
    const char *str = grpc_error_string(error);
    gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: on_writable: error=%s",
            ac->addr_str, str);
  }

  gpr_mu_lock(&ac->mu);
  GPR_ASSERT(ac->fd);
  fd = ac->fd;
  ac->fd = NULL;
  gpr_mu_unlock(&ac->mu);

  grpc_timer_cancel(exec_ctx, &ac->alarm);

  gpr_mu_lock(&ac->mu);
  if (error != GRPC_ERROR_NONE) {
    error =
        grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR,
                           grpc_slice_from_static_string("Timeout occurred"));
    goto finish;
  }

  do {
    so_error_size = sizeof(so_error);
    err = getsockopt(grpc_fd_wrapped_fd(fd), SOL_SOCKET, SO_ERROR, &so_error,
                     &so_error_size);
  } while (err < 0 && errno == EINTR);
  if (err < 0) {
    error = GRPC_OS_ERROR(errno, "getsockopt");
    goto finish;
  }

  switch (so_error) {
    case 0:
      grpc_pollset_set_del_fd(exec_ctx, ac->interested_parties, fd);
      *ep = grpc_tcp_client_create_from_fd(exec_ctx, fd, ac->channel_args,
                                           ac->addr_str);
      fd = NULL;
      break;
    case ENOBUFS:
      /* We will get one of these errors if we have run out of
         memory in the kernel for the data structures allocated
         when you connect a socket.  If this happens it is very
         likely that if we wait a little bit then try again the
         connection will work (since other programs or this
         program will close their network connections and free up
         memory).  This does _not_ indicate that there is anything
         wrong with the server we are connecting to, this is a
         local problem.

         If you are looking at this code, then chances are that
         your program or another program on the same computer
         opened too many network connections.  The "easy" fix:
         don't do that! */
      gpr_log(GPR_ERROR, "kernel out of buffers");
      gpr_mu_unlock(&ac->mu);
      grpc_fd_notify_on_write(exec_ctx, fd, &ac->write_closure);
      return;
    case ECONNREFUSED:
      /* This error shouldn't happen for anything other than connect(). */
      error = GRPC_OS_ERROR(so_error, "connect");
      break;
    default:
      /* We don't really know which syscall triggered the problem here,
         so punt by reporting getsockopt(). */
      error = GRPC_OS_ERROR(so_error, "getsockopt(SO_ERROR)");
      break;
  }

finish:
  if (fd != NULL) {
    grpc_pollset_set_del_fd(exec_ctx, ac->interested_parties, fd);
    grpc_fd_orphan(exec_ctx, fd, NULL, NULL, "tcp_client_orphan");
    fd = NULL;
  }
  done = (--ac->refs == 0);
  gpr_mu_unlock(&ac->mu);
  if (error != GRPC_ERROR_NONE) {
    char *error_descr;
    grpc_slice str;
    bool ret = grpc_error_get_str(error, GRPC_ERROR_STR_DESCRIPTION, &str);
    GPR_ASSERT(ret);
    char *desc = grpc_slice_to_c_string(str);
    gpr_asprintf(&error_descr, "Failed to connect to remote host: %s", desc);
    error = grpc_error_set_str(error, GRPC_ERROR_STR_DESCRIPTION,
                               grpc_slice_from_copied_string(error_descr));
    gpr_free(error_descr);
    gpr_free(desc);
    error = grpc_error_set_str(error, GRPC_ERROR_STR_TARGET_ADDRESS,
                               grpc_slice_from_copied_string(ac->addr_str));
  }
  if (done) {
    gpr_mu_destroy(&ac->mu);
    gpr_free(ac->addr_str);
    grpc_channel_args_destroy(exec_ctx, ac->channel_args);
    gpr_free(ac);
  }
  grpc_closure_sched(exec_ctx, closure, error);
}