예제 #1
0
/* Asynchronous callback from the IOCP, or the background thread. */
static void on_read(grpc_exec_ctx *exec_ctx, void *tcpp, grpc_error *error) {
  grpc_tcp *tcp = tcpp;
  grpc_closure *cb = tcp->read_cb;
  grpc_winsocket *socket = tcp->socket;
  grpc_slice sub;
  grpc_winsocket_callback_info *info = &socket->read_info;

  GRPC_ERROR_REF(error);

  if (error == GRPC_ERROR_NONE) {
    if (info->wsa_error != 0 && !tcp->shutting_down) {
      char *utf8_message = gpr_format_message(info->wsa_error);
      error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(utf8_message);
      gpr_free(utf8_message);
      grpc_slice_unref_internal(exec_ctx, tcp->read_slice);
    } else {
      if (info->bytes_transfered != 0 && !tcp->shutting_down) {
        sub = grpc_slice_sub_no_ref(tcp->read_slice, 0, info->bytes_transfered);
        grpc_slice_buffer_add(tcp->read_slices, sub);
      } else {
        grpc_slice_unref_internal(exec_ctx, tcp->read_slice);
        error = tcp->shutting_down
                    ? GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
                          "TCP stream shutting down", &tcp->shutdown_error, 1)
                    : GRPC_ERROR_CREATE_FROM_STATIC_STRING("End of TCP stream");
      }
    }
  }

  tcp->read_cb = NULL;
  TCP_UNREF(exec_ctx, tcp, "read");
  GRPC_CLOSURE_SCHED(exec_ctx, cb, error);
}
예제 #2
0
static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx, void *arg,
                                           grpc_error *error) {
  security_handshaker *h = arg;
  gpr_mu_lock(&h->mu);
  if (error != GRPC_ERROR_NONE || h->shutdown) {
    security_handshake_failed_locked(
        exec_ctx, h, GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
                         "Handshake write failed", &error, 1));
    gpr_mu_unlock(&h->mu);
    security_handshaker_unref(exec_ctx, h);
    return;
  }
  // We may be done.
  if (h->handshaker_result == NULL) {
    grpc_endpoint_read(exec_ctx, h->args->endpoint, h->args->read_buffer,
                       &h->on_handshake_data_received_from_peer);
  } else {
    error = check_peer_locked(exec_ctx, h);
    if (error != GRPC_ERROR_NONE) {
      security_handshake_failed_locked(exec_ctx, h, error);
      gpr_mu_unlock(&h->mu);
      security_handshaker_unref(exec_ctx, h);
      return;
    }
  }
  gpr_mu_unlock(&h->mu);
}
예제 #3
0
static void win_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
                     grpc_slice_buffer *read_slices, grpc_closure *cb) {
  grpc_tcp *tcp = (grpc_tcp *)ep;
  grpc_winsocket *handle = tcp->socket;
  grpc_winsocket_callback_info *info = &handle->read_info;
  int status;
  DWORD bytes_read = 0;
  DWORD flags = 0;
  WSABUF buffer;

  if (tcp->shutting_down) {
    GRPC_CLOSURE_SCHED(
        exec_ctx, cb,
        GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
            "TCP socket is shutting down", &tcp->shutdown_error, 1));
    return;
  }

  tcp->read_cb = cb;
  tcp->read_slices = read_slices;
  grpc_slice_buffer_reset_and_unref_internal(exec_ctx, read_slices);

  tcp->read_slice = GRPC_SLICE_MALLOC(8192);

  buffer.len = (ULONG)GRPC_SLICE_LENGTH(
      tcp->read_slice);  // we know slice size fits in 32bit.
  buffer.buf = (char *)GRPC_SLICE_START_PTR(tcp->read_slice);

  TCP_REF(tcp, "read");

  /* First let's try a synchronous, non-blocking read. */
  status =
      WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags, NULL, NULL);
  info->wsa_error = status == 0 ? 0 : WSAGetLastError();

  /* Did we get data immediately ? Yay. */
  if (info->wsa_error != WSAEWOULDBLOCK) {
    info->bytes_transfered = bytes_read;
    GRPC_CLOSURE_SCHED(exec_ctx, &tcp->on_read, GRPC_ERROR_NONE);
    return;
  }

  /* Otherwise, let's retry, by queuing a read. */
  memset(&tcp->socket->read_info.overlapped, 0, sizeof(OVERLAPPED));
  status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags,
                   &info->overlapped, NULL);

  if (status != 0) {
    int wsa_error = WSAGetLastError();
    if (wsa_error != WSA_IO_PENDING) {
      info->wsa_error = wsa_error;
      GRPC_CLOSURE_SCHED(exec_ctx, &tcp->on_read,
                         GRPC_WSA_ERROR(info->wsa_error, "WSARecv"));
      return;
    }
  }

  grpc_socket_notify_on_read(exec_ctx, tcp->socket, &tcp->on_read);
}
예제 #4
0
static void recv_im_ready(grpc_exec_ctx *exec_ctx, void *arg,
                          grpc_error *error) {
  grpc_call_element *elem = arg;
  call_data *calld = elem->call_data;
  grpc_closure_sched(
      exec_ctx, calld->recv_im_ready,
      grpc_error_set_int(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
                             "Failure that's not preventable.", &error, 1),
                         GRPC_ERROR_INT_GRPC_STATUS,
                         GRPC_STATUS_PERMISSION_DENIED));
}
예제 #5
0
static void me_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
                        grpc_error *why) {
  half *m = (half *)ep;
  gpr_mu_lock(&m->parent->mu);
  m->parent->shutdown = true;
  if (m->on_read) {
    GRPC_CLOSURE_SCHED(
        exec_ctx, m->on_read,
        GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING("Shutdown", &why, 1));
    m->on_read = NULL;
  }
  m = other_half(m);
  if (m->on_read) {
    GRPC_CLOSURE_SCHED(
        exec_ctx, m->on_read,
        GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING("Shutdown", &why, 1));
    m->on_read = NULL;
  }
  gpr_mu_unlock(&m->parent->mu);
  grpc_resource_user_shutdown(exec_ctx, m->resource_user);
  GRPC_ERROR_UNREF(why);
}
예제 #6
0
파일: load_file.c 프로젝트: endobson/grpc
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;
}
예제 #7
0
static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx,
                                                 void *arg, grpc_error *error) {
  security_handshaker *h = arg;
  gpr_mu_lock(&h->mu);
  if (error != GRPC_ERROR_NONE || h->shutdown) {
    security_handshake_failed_locked(
        exec_ctx, h, GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
                         "Handshake read failed", &error, 1));
    gpr_mu_unlock(&h->mu);
    security_handshaker_unref(exec_ctx, h);
    return;
  }
  // Copy all slices received.
  size_t i;
  size_t bytes_received_size = 0;
  for (i = 0; i < h->args->read_buffer->count; i++) {
    bytes_received_size += GRPC_SLICE_LENGTH(h->args->read_buffer->slices[i]);
  }
  if (bytes_received_size > h->handshake_buffer_size) {
    h->handshake_buffer = gpr_realloc(h->handshake_buffer, bytes_received_size);
    h->handshake_buffer_size = bytes_received_size;
  }
  size_t offset = 0;
  for (i = 0; i < h->args->read_buffer->count; i++) {
    size_t slice_size = GPR_SLICE_LENGTH(h->args->read_buffer->slices[i]);
    memcpy(h->handshake_buffer + offset,
           GRPC_SLICE_START_PTR(h->args->read_buffer->slices[i]), slice_size);
    offset += slice_size;
  }
  // Call TSI handshaker.
  error = do_handshaker_next_locked(exec_ctx, h, h->handshake_buffer,
                                    bytes_received_size);

  if (error != GRPC_ERROR_NONE) {
    security_handshake_failed_locked(exec_ctx, h, error);
    gpr_mu_unlock(&h->mu);
    security_handshaker_unref(exec_ctx, h);
  } else {
    gpr_mu_unlock(&h->mu);
  }
}
예제 #8
0
/* Initiates a write. */
static void win_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
                      grpc_slice_buffer *slices, grpc_closure *cb) {
  grpc_tcp *tcp = (grpc_tcp *)ep;
  grpc_winsocket *socket = tcp->socket;
  grpc_winsocket_callback_info *info = &socket->write_info;
  unsigned i;
  DWORD bytes_sent;
  int status;
  WSABUF local_buffers[16];
  WSABUF *allocated = NULL;
  WSABUF *buffers = local_buffers;
  size_t len;

  if (tcp->shutting_down) {
    GRPC_CLOSURE_SCHED(
        exec_ctx, cb,
        GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
            "TCP socket is shutting down", &tcp->shutdown_error, 1));
    return;
  }

  tcp->write_cb = cb;
  tcp->write_slices = slices;
  GPR_ASSERT(tcp->write_slices->count <= UINT_MAX);
  if (tcp->write_slices->count > GPR_ARRAY_SIZE(local_buffers)) {
    buffers = (WSABUF *)gpr_malloc(sizeof(WSABUF) * tcp->write_slices->count);
    allocated = buffers;
  }

  for (i = 0; i < tcp->write_slices->count; i++) {
    len = GRPC_SLICE_LENGTH(tcp->write_slices->slices[i]);
    GPR_ASSERT(len <= ULONG_MAX);
    buffers[i].len = (ULONG)len;
    buffers[i].buf = (char *)GRPC_SLICE_START_PTR(tcp->write_slices->slices[i]);
  }

  /* First, let's try a synchronous, non-blocking write. */
  status = WSASend(socket->socket, buffers, (DWORD)tcp->write_slices->count,
                   &bytes_sent, 0, NULL, NULL);
  info->wsa_error = status == 0 ? 0 : WSAGetLastError();

  /* We would kind of expect to get a WSAEWOULDBLOCK here, especially on a busy
     connection that has its send queue filled up. But if we don't, then we can
     avoid doing an async write operation at all. */
  if (info->wsa_error != WSAEWOULDBLOCK) {
    grpc_error *error = status == 0
                            ? GRPC_ERROR_NONE
                            : GRPC_WSA_ERROR(info->wsa_error, "WSASend");
    GRPC_CLOSURE_SCHED(exec_ctx, cb, error);
    if (allocated) gpr_free(allocated);
    return;
  }

  TCP_REF(tcp, "write");

  /* If we got a WSAEWOULDBLOCK earlier, then we need to re-do the same
     operation, this time asynchronously. */
  memset(&socket->write_info.overlapped, 0, sizeof(OVERLAPPED));
  status = WSASend(socket->socket, buffers, (DWORD)tcp->write_slices->count,
                   &bytes_sent, 0, &socket->write_info.overlapped, NULL);
  if (allocated) gpr_free(allocated);

  if (status != 0) {
    int wsa_error = WSAGetLastError();
    if (wsa_error != WSA_IO_PENDING) {
      TCP_UNREF(exec_ctx, tcp, "write");
      GRPC_CLOSURE_SCHED(exec_ctx, cb, GRPC_WSA_ERROR(wsa_error, "WSASend"));
      return;
    }
  }

  /* As all is now setup, we can now ask for the IOCP notification. It may
     trigger the callback immediately however, but no matter. */
  grpc_socket_notify_on_write(exec_ctx, socket, &tcp->on_write);
}
예제 #9
0
grpc_error *grpc_tcp_server_add_port(grpc_tcp_server *s,
                                     const grpc_resolved_address *addr,
                                     int *port) {
  // This function is mostly copied from tcp_server_windows.c
  grpc_tcp_listener *sp = NULL;
  uv_tcp_t *handle;
  grpc_resolved_address addr6_v4mapped;
  grpc_resolved_address wildcard;
  grpc_resolved_address *allocated_addr = NULL;
  grpc_resolved_address sockname_temp;
  unsigned port_index = 0;
  int status;
  grpc_error *error = GRPC_ERROR_NONE;

  if (s->tail != NULL) {
    port_index = s->tail->port_index + 1;
  }

  /* Check if this is a wildcard port, and if so, try to keep the port the same
     as some previously created listener. */
  if (grpc_sockaddr_get_port(addr) == 0) {
    for (sp = s->head; sp; sp = sp->next) {
      sockname_temp.len = sizeof(struct sockaddr_storage);
      if (0 == uv_tcp_getsockname(sp->handle,
                                  (struct sockaddr *)&sockname_temp.addr,
                                  (int *)&sockname_temp.len)) {
        *port = grpc_sockaddr_get_port(&sockname_temp);
        if (*port > 0) {
          allocated_addr = gpr_malloc(sizeof(grpc_resolved_address));
          memcpy(allocated_addr, addr, sizeof(grpc_resolved_address));
          grpc_sockaddr_set_port(allocated_addr, *port);
          addr = allocated_addr;
          break;
        }
      }
    }
  }

  if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
    addr = &addr6_v4mapped;
  }

  /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */
  if (grpc_sockaddr_is_wildcard(addr, port)) {
    grpc_sockaddr_make_wildcard6(*port, &wildcard);

    addr = &wildcard;
  }

  handle = gpr_malloc(sizeof(uv_tcp_t));
  status = uv_tcp_init(uv_default_loop(), handle);
  if (status == 0) {
    error = add_socket_to_server(s, handle, addr, port_index, &sp);
  } else {
    error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
        "Failed to initialize UV tcp handle");
    error =
        grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR,
                           grpc_slice_from_static_string(uv_strerror(status)));
  }

  gpr_free(allocated_addr);

  if (error != GRPC_ERROR_NONE) {
    grpc_error *error_out = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
        "Failed to add port to server", &error, 1);
    GRPC_ERROR_UNREF(error);
    error = error_out;
    *port = -1;
  } else {
    GPR_ASSERT(sp != NULL);
    *port = sp->port;
  }
  return error;
}
예제 #10
0
static void on_read(grpc_exec_ctx *exec_ctx, void *user_data,
                    grpc_error *error) {
  unsigned i;
  uint8_t keep_looping = 0;
  tsi_result result = TSI_OK;
  secure_endpoint *ep = (secure_endpoint *)user_data;
  uint8_t *cur = GRPC_SLICE_START_PTR(ep->read_staging_buffer);
  uint8_t *end = GRPC_SLICE_END_PTR(ep->read_staging_buffer);

  if (error != GRPC_ERROR_NONE) {
    grpc_slice_buffer_reset_and_unref_internal(exec_ctx, ep->read_buffer);
    call_read_cb(exec_ctx, ep, GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
                                   "Secure read failed", &error, 1));
    return;
  }

  if (ep->zero_copy_protector != NULL) {
    // Use zero-copy grpc protector to unprotect.
    result = tsi_zero_copy_grpc_protector_unprotect(
        exec_ctx, ep->zero_copy_protector, &ep->source_buffer, ep->read_buffer);
  } else {
    // Use frame protector to unprotect.
    /* TODO(yangg) check error, maybe bail out early */
    for (i = 0; i < ep->source_buffer.count; i++) {
      grpc_slice encrypted = ep->source_buffer.slices[i];
      uint8_t *message_bytes = GRPC_SLICE_START_PTR(encrypted);
      size_t message_size = GRPC_SLICE_LENGTH(encrypted);

      while (message_size > 0 || keep_looping) {
        size_t unprotected_buffer_size_written = (size_t)(end - cur);
        size_t processed_message_size = message_size;
        gpr_mu_lock(&ep->protector_mu);
        result = tsi_frame_protector_unprotect(
            ep->protector, message_bytes, &processed_message_size, cur,
            &unprotected_buffer_size_written);
        gpr_mu_unlock(&ep->protector_mu);
        if (result != TSI_OK) {
          gpr_log(GPR_ERROR, "Decryption error: %s",
                  tsi_result_to_string(result));
          break;
        }
        message_bytes += processed_message_size;
        message_size -= processed_message_size;
        cur += unprotected_buffer_size_written;

        if (cur == end) {
          flush_read_staging_buffer(ep, &cur, &end);
          /* Force to enter the loop again to extract buffered bytes in
             protector. The bytes could be buffered because of running out of
             staging_buffer. If this happens at the end of all slices, doing
             another unprotect avoids leaving data in the protector. */
          keep_looping = 1;
        } else if (unprotected_buffer_size_written > 0) {
          keep_looping = 1;
        } else {
          keep_looping = 0;
        }
      }
      if (result != TSI_OK) break;
    }

    if (cur != GRPC_SLICE_START_PTR(ep->read_staging_buffer)) {
      grpc_slice_buffer_add(
          ep->read_buffer,
          grpc_slice_split_head(
              &ep->read_staging_buffer,
              (size_t)(cur - GRPC_SLICE_START_PTR(ep->read_staging_buffer))));
    }
  }

  /* TODO(yangg) experiment with moving this block after read_cb to see if it
     helps latency */
  grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &ep->source_buffer);

  if (result != TSI_OK) {
    grpc_slice_buffer_reset_and_unref_internal(exec_ctx, ep->read_buffer);
    call_read_cb(
        exec_ctx, ep,
        grpc_set_tsi_error_result(
            GRPC_ERROR_CREATE_FROM_STATIC_STRING("Unwrap failed"), result));
    return;
  }

  call_read_cb(exec_ctx, ep, GRPC_ERROR_NONE);
}