|  | @@ -42,6 +42,7 @@
 | 
	
		
			
				|  |  |  #include "src/core/lib/iomgr/tcp_windows.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/iomgr/timer.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/slice/slice_internal.h"
 | 
	
		
			
				|  |  | +#include "src/core/lib/slice/slice_string_helpers.h"
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #if defined(__MSYS__) && defined(GPR_ARCH_64)
 | 
	
		
			
				|  |  |  /* Nasty workaround for nasty bug when using the 64 bits msys compiler
 | 
	
	
		
			
				|  | @@ -112,7 +113,10 @@ typedef struct grpc_tcp {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    grpc_closure* read_cb;
 | 
	
		
			
				|  |  |    grpc_closure* write_cb;
 | 
	
		
			
				|  |  | -  grpc_slice read_slice;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  /* garbage after the last read */
 | 
	
		
			
				|  |  | +  grpc_slice_buffer last_read_buffer;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    grpc_slice_buffer* write_slices;
 | 
	
		
			
				|  |  |    grpc_slice_buffer* read_slices;
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -131,6 +135,7 @@ static void tcp_free(grpc_tcp* tcp) {
 | 
	
		
			
				|  |  |    grpc_winsocket_destroy(tcp->socket);
 | 
	
		
			
				|  |  |    gpr_mu_destroy(&tcp->mu);
 | 
	
		
			
				|  |  |    gpr_free(tcp->peer_string);
 | 
	
		
			
				|  |  | +  grpc_slice_buffer_destroy_internal(&tcp->last_read_buffer);
 | 
	
		
			
				|  |  |    grpc_resource_user_unref(tcp->resource_user);
 | 
	
		
			
				|  |  |    if (tcp->shutting_down) GRPC_ERROR_UNREF(tcp->shutdown_error);
 | 
	
		
			
				|  |  |    gpr_free(tcp);
 | 
	
	
		
			
				|  | @@ -179,9 +184,12 @@ static void on_read(void* tcpp, grpc_error* error) {
 | 
	
		
			
				|  |  |    grpc_tcp* tcp = (grpc_tcp*)tcpp;
 | 
	
		
			
				|  |  |    grpc_closure* cb = tcp->read_cb;
 | 
	
		
			
				|  |  |    grpc_winsocket* socket = tcp->socket;
 | 
	
		
			
				|  |  | -  grpc_slice sub;
 | 
	
		
			
				|  |  |    grpc_winsocket_callback_info* info = &socket->read_info;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  if (grpc_tcp_trace.enabled()) {
 | 
	
		
			
				|  |  | +    gpr_log(GPR_INFO, "TCP:%p on_read", tcp);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    GRPC_ERROR_REF(error);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    if (error == GRPC_ERROR_NONE) {
 | 
	
	
		
			
				|  | @@ -189,13 +197,35 @@ static void on_read(void* tcpp, grpc_error* error) {
 | 
	
		
			
				|  |  |        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(tcp->read_slice);
 | 
	
		
			
				|  |  | +      grpc_slice_buffer_reset_and_unref_internal(tcp->read_slices);
 | 
	
		
			
				|  |  |      } 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);
 | 
	
		
			
				|  |  | +        GPR_ASSERT((size_t)info->bytes_transfered <= tcp->read_slices->length);
 | 
	
		
			
				|  |  | +        if (static_cast<size_t>(info->bytes_transfered) !=
 | 
	
		
			
				|  |  | +            tcp->read_slices->length) {
 | 
	
		
			
				|  |  | +          grpc_slice_buffer_trim_end(
 | 
	
		
			
				|  |  | +              tcp->read_slices,
 | 
	
		
			
				|  |  | +              tcp->read_slices->length -
 | 
	
		
			
				|  |  | +                  static_cast<size_t>(info->bytes_transfered),
 | 
	
		
			
				|  |  | +              &tcp->last_read_buffer);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        GPR_ASSERT((size_t)info->bytes_transfered == tcp->read_slices->length);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        if (grpc_tcp_trace.enabled()) {
 | 
	
		
			
				|  |  | +          size_t i;
 | 
	
		
			
				|  |  | +          for (i = 0; i < tcp->read_slices->count; i++) {
 | 
	
		
			
				|  |  | +            char* dump = grpc_dump_slice(tcp->read_slices->slices[i],
 | 
	
		
			
				|  |  | +                                         GPR_DUMP_HEX | GPR_DUMP_ASCII);
 | 
	
		
			
				|  |  | +            gpr_log(GPR_INFO, "READ %p (peer=%s): %s", tcp, tcp->peer_string,
 | 
	
		
			
				|  |  | +                    dump);
 | 
	
		
			
				|  |  | +            gpr_free(dump);
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |        } else {
 | 
	
		
			
				|  |  | -        grpc_slice_unref_internal(tcp->read_slice);
 | 
	
		
			
				|  |  | +        if (grpc_tcp_trace.enabled()) {
 | 
	
		
			
				|  |  | +          gpr_log(GPR_INFO, "TCP:%p unref read_slice", tcp);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        grpc_slice_buffer_reset_and_unref_internal(tcp->read_slices);
 | 
	
		
			
				|  |  |          error = tcp->shutting_down
 | 
	
		
			
				|  |  |                      ? GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
 | 
	
		
			
				|  |  |                            "TCP stream shutting down", &tcp->shutdown_error, 1)
 | 
	
	
		
			
				|  | @@ -209,6 +239,8 @@ static void on_read(void* tcpp, grpc_error* error) {
 | 
	
		
			
				|  |  |    GRPC_CLOSURE_SCHED(cb, error);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#define DEFAULT_TARGET_READ_SIZE 8192
 | 
	
		
			
				|  |  | +#define MAX_WSABUF_COUNT 16
 | 
	
		
			
				|  |  |  static void win_read(grpc_endpoint* ep, grpc_slice_buffer* read_slices,
 | 
	
		
			
				|  |  |                       grpc_closure* cb) {
 | 
	
		
			
				|  |  |    grpc_tcp* tcp = (grpc_tcp*)ep;
 | 
	
	
		
			
				|  | @@ -217,7 +249,12 @@ static void win_read(grpc_endpoint* ep, grpc_slice_buffer* read_slices,
 | 
	
		
			
				|  |  |    int status;
 | 
	
		
			
				|  |  |    DWORD bytes_read = 0;
 | 
	
		
			
				|  |  |    DWORD flags = 0;
 | 
	
		
			
				|  |  | -  WSABUF buffer;
 | 
	
		
			
				|  |  | +  WSABUF buffers[MAX_WSABUF_COUNT];
 | 
	
		
			
				|  |  | +  size_t i;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (grpc_tcp_trace.enabled()) {
 | 
	
		
			
				|  |  | +    gpr_log(GPR_INFO, "TCP:%p win_read", tcp);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    if (tcp->shutting_down) {
 | 
	
		
			
				|  |  |      GRPC_CLOSURE_SCHED(
 | 
	
	
		
			
				|  | @@ -229,18 +266,27 @@ static void win_read(grpc_endpoint* ep, grpc_slice_buffer* read_slices,
 | 
	
		
			
				|  |  |    tcp->read_cb = cb;
 | 
	
		
			
				|  |  |    tcp->read_slices = read_slices;
 | 
	
		
			
				|  |  |    grpc_slice_buffer_reset_and_unref_internal(read_slices);
 | 
	
		
			
				|  |  | +  grpc_slice_buffer_swap(read_slices, &tcp->last_read_buffer);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  tcp->read_slice = GRPC_SLICE_MALLOC(8192);
 | 
	
		
			
				|  |  | +  if (tcp->read_slices->length < DEFAULT_TARGET_READ_SIZE / 2 &&
 | 
	
		
			
				|  |  | +      tcp->read_slices->count < MAX_WSABUF_COUNT) {
 | 
	
		
			
				|  |  | +    // TODO(jtattermusch): slice should be allocated using resource quota
 | 
	
		
			
				|  |  | +    grpc_slice_buffer_add(tcp->read_slices,
 | 
	
		
			
				|  |  | +                          GRPC_SLICE_MALLOC(DEFAULT_TARGET_READ_SIZE));
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  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);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(tcp->read_slices->count <= MAX_WSABUF_COUNT);
 | 
	
		
			
				|  |  | +  for (i = 0; i < tcp->read_slices->count; i++) {
 | 
	
		
			
				|  |  | +    buffers[i].len = (ULONG)GRPC_SLICE_LENGTH(
 | 
	
		
			
				|  |  | +        tcp->read_slices->slices[i]);  // we know slice size fits in 32bit.
 | 
	
		
			
				|  |  | +    buffers[i].buf = (char*)GRPC_SLICE_START_PTR(tcp->read_slices->slices[i]);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    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);
 | 
	
		
			
				|  |  | +  status = WSARecv(tcp->socket->socket, buffers, (DWORD)tcp->read_slices->count,
 | 
	
		
			
				|  |  | +                   &bytes_read, &flags, NULL, NULL);
 | 
	
		
			
				|  |  |    info->wsa_error = status == 0 ? 0 : WSAGetLastError();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /* Did we get data immediately ? Yay. */
 | 
	
	
		
			
				|  | @@ -252,8 +298,8 @@ static void win_read(grpc_endpoint* ep, grpc_slice_buffer* read_slices,
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /* 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);
 | 
	
		
			
				|  |  | +  status = WSARecv(tcp->socket->socket, buffers, (DWORD)tcp->read_slices->count,
 | 
	
		
			
				|  |  | +                   &bytes_read, &flags, &info->overlapped, NULL);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    if (status != 0) {
 | 
	
		
			
				|  |  |      int wsa_error = WSAGetLastError();
 | 
	
	
		
			
				|  | @@ -275,6 +321,10 @@ static void on_write(void* tcpp, grpc_error* error) {
 | 
	
		
			
				|  |  |    grpc_winsocket_callback_info* info = &handle->write_info;
 | 
	
		
			
				|  |  |    grpc_closure* cb;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  if (grpc_tcp_trace.enabled()) {
 | 
	
		
			
				|  |  | +    gpr_log(GPR_INFO, "TCP:%p on_write", tcp);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    GRPC_ERROR_REF(error);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    gpr_mu_lock(&tcp->mu);
 | 
	
	
		
			
				|  | @@ -303,11 +353,21 @@ static void win_write(grpc_endpoint* ep, grpc_slice_buffer* slices,
 | 
	
		
			
				|  |  |    unsigned i;
 | 
	
		
			
				|  |  |    DWORD bytes_sent;
 | 
	
		
			
				|  |  |    int status;
 | 
	
		
			
				|  |  | -  WSABUF local_buffers[16];
 | 
	
		
			
				|  |  | +  WSABUF local_buffers[MAX_WSABUF_COUNT];
 | 
	
		
			
				|  |  |    WSABUF* allocated = NULL;
 | 
	
		
			
				|  |  |    WSABUF* buffers = local_buffers;
 | 
	
		
			
				|  |  |    size_t len;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  if (grpc_tcp_trace.enabled()) {
 | 
	
		
			
				|  |  | +    size_t i;
 | 
	
		
			
				|  |  | +    for (i = 0; i < slices->count; i++) {
 | 
	
		
			
				|  |  | +      char* data =
 | 
	
		
			
				|  |  | +          grpc_dump_slice(slices->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII);
 | 
	
		
			
				|  |  | +      gpr_log(GPR_INFO, "WRITE %p (peer=%s): %s", tcp, tcp->peer_string, data);
 | 
	
		
			
				|  |  | +      gpr_free(data);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    if (tcp->shutting_down) {
 | 
	
		
			
				|  |  |      GRPC_CLOSURE_SCHED(
 | 
	
		
			
				|  |  |          cb, GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
 | 
	
	
		
			
				|  | @@ -412,6 +472,7 @@ static void win_shutdown(grpc_endpoint* ep, grpc_error* why) {
 | 
	
		
			
				|  |  |  static void win_destroy(grpc_endpoint* ep) {
 | 
	
		
			
				|  |  |    grpc_network_status_unregister_endpoint(ep);
 | 
	
		
			
				|  |  |    grpc_tcp* tcp = (grpc_tcp*)ep;
 | 
	
		
			
				|  |  | +  grpc_slice_buffer_reset_and_unref_internal(&tcp->last_read_buffer);
 | 
	
		
			
				|  |  |    TCP_UNREF(tcp, "destroy");
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -460,6 +521,7 @@ grpc_endpoint* grpc_tcp_create(grpc_winsocket* socket,
 | 
	
		
			
				|  |  |    GRPC_CLOSURE_INIT(&tcp->on_read, on_read, tcp, grpc_schedule_on_exec_ctx);
 | 
	
		
			
				|  |  |    GRPC_CLOSURE_INIT(&tcp->on_write, on_write, tcp, grpc_schedule_on_exec_ctx);
 | 
	
		
			
				|  |  |    tcp->peer_string = gpr_strdup(peer_string);
 | 
	
		
			
				|  |  | +  grpc_slice_buffer_init(&tcp->last_read_buffer);
 | 
	
		
			
				|  |  |    tcp->resource_user = grpc_resource_user_create(resource_quota, peer_string);
 | 
	
		
			
				|  |  |    /* Tell network status tracking code about the new endpoint */
 | 
	
		
			
				|  |  |    grpc_network_status_register_endpoint(&tcp->base);
 |