From 8b78c28451e8cfe869630bb69c0b7425293d5903 Mon Sep 17 00:00:00 2001 From: Julien Boeuf Date: Fri, 14 Aug 2015 13:39:19 -0700 Subject: First draft at addressing #1799 for grpc_security. - Will make all the changes everywhere once we reach consensus. --- include/grpc/grpc.h | 9 ++++----- include/grpc/grpc_security.h | 25 +++++++++++++++---------- 2 files changed, 19 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h index 2d53325b77..fd007090ba 100644 --- a/include/grpc/grpc.h +++ b/include/grpc/grpc.h @@ -206,8 +206,7 @@ typedef struct grpc_metadata { /** The following fields are reserved for grpc internal use. There is no need to initialize them, and they will be set to garbage - during - calls to grpc. */ + during calls to grpc. */ struct { void *obfuscated[4]; } internal_data; @@ -378,11 +377,11 @@ typedef struct grpc_op { /** Registers a plugin to be initialized and destroyed with the library. - The \a init and \a destroy functions will be invoked as part of - \a grpc_init() and \a grpc_shutdown(), respectively. + The \a init and \a destroy functions will be invoked as part of + \a grpc_init() and \a grpc_shutdown(), respectively. Note that these functions can be invoked an arbitrary number of times (and hence so will \a init and \a destroy). - It is safe to pass NULL to either argument. Plugins are destroyed in + It is safe to pass NULL to either argument. Plugins are destroyed in the reverse order they were initialized. */ void grpc_register_plugin(void (*init)(void), void (*destroy)(void)); diff --git a/include/grpc/grpc_security.h b/include/grpc/grpc_security.h index 640c1fda98..81d17712ec 100644 --- a/include/grpc/grpc_security.h +++ b/include/grpc/grpc_security.h @@ -89,16 +89,18 @@ typedef struct { key and certificate chain. This parameter can be NULL if the client does not have such a key/cert pair. */ grpc_credentials *grpc_ssl_credentials_create( - const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair); + const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair, + void *reserved); /* Creates a composite credentials object. */ grpc_credentials *grpc_composite_credentials_create(grpc_credentials *creds1, - grpc_credentials *creds2); + grpc_credentials *creds2, + void *reserved); /* Creates a compute engine credentials object. WARNING: Do NOT use this credentials to connect to a non-google service as this could result in an oauth2 token leak. */ -grpc_credentials *grpc_compute_engine_credentials_create(void); +grpc_credentials *grpc_compute_engine_credentials_create(void *reserved); extern const gpr_timespec grpc_max_auth_token_lifetime; @@ -112,7 +114,8 @@ extern const gpr_timespec grpc_max_auth_token_lifetime; account credentials. It should not exceed grpc_max_auth_token_lifetime or will be cropped to this value. */ grpc_credentials *grpc_service_account_credentials_create( - const char *json_key, const char *scope, gpr_timespec token_lifetime); + const char *json_key, const char *scope, gpr_timespec token_lifetime, + void *reserved); /* Creates a JWT credentials object. May return NULL if the input is invalid. - json_key is the JSON key string containing the client's private key. @@ -120,7 +123,7 @@ grpc_credentials *grpc_service_account_credentials_create( this credentials. It should not exceed grpc_max_auth_token_lifetime or will be cropped to this value. */ grpc_credentials *grpc_service_account_jwt_access_credentials_create( - const char *json_key, gpr_timespec token_lifetime); + const char *json_key, gpr_timespec token_lifetime, void *reserved); /* Creates an Oauth2 Refresh Token credentials object. May return NULL if the input is invalid. @@ -129,16 +132,17 @@ grpc_credentials *grpc_service_account_jwt_access_credentials_create( - json_refresh_token is the JSON string containing the refresh token itself along with a client_id and client_secret. */ grpc_credentials *grpc_refresh_token_credentials_create( - const char *json_refresh_token); + const char *json_refresh_token, void *reserved); /* Creates an Oauth2 Access Token credentials with an access token that was aquired by an out of band mechanism. */ grpc_credentials *grpc_access_token_credentials_create( - const char *access_token); + const char *access_token, void *reserved); /* Creates an IAM credentials object. */ grpc_credentials *grpc_iam_credentials_create(const char *authorization_token, - const char *authority_selector); + const char *authority_selector, + void *reserved); /* --- Secure channel creation. --- */ @@ -154,7 +158,8 @@ grpc_credentials *grpc_iam_credentials_create(const char *authorization_token, /* Creates a secure channel using the passed-in credentials. */ grpc_channel *grpc_secure_channel_create(grpc_credentials *creds, const char *target, - const grpc_channel_args *args); + const grpc_channel_args *args, + void *reserved); /* --- grpc_server_credentials object. --- @@ -180,7 +185,7 @@ void grpc_server_credentials_release(grpc_server_credentials *creds); NULL. */ grpc_server_credentials *grpc_ssl_server_credentials_create( const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs, - size_t num_key_cert_pairs, int force_client_auth); + size_t num_key_cert_pairs, int force_client_auth, void *reserved); /* --- Server-side secure ports. --- */ -- cgit v1.2.3 From 592e7f2dd0c059468de6377e8d6bc0d61fe2dd2c Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 21 Aug 2015 10:45:48 -0700 Subject: Refactor Endpoint API - Allow reads to complete immediately - Unify read/write signatures - Simplify memory management to allow future optimization work --- include/grpc/support/slice_buffer.h | 2 + src/core/httpcli/httpcli.c | 95 +++--- src/core/iomgr/endpoint.c | 17 +- src/core/iomgr/endpoint.h | 51 ++- src/core/iomgr/tcp_posix.c | 520 ++++++++++------------------- src/core/security/secure_endpoint.c | 188 ++++++----- src/core/security/secure_transport_setup.c | 119 ++++--- src/core/support/slice_buffer.c | 22 ++ src/core/transport/chttp2/internal.h | 10 +- src/core/transport/chttp2/writing.c | 21 +- src/core/transport/chttp2_transport.c | 125 +++---- test/core/bad_client/bad_client.c | 17 +- test/core/iomgr/endpoint_tests.c | 204 ++++++----- test/core/iomgr/tcp_posix_test.c | 147 ++++---- test/core/security/secure_endpoint_test.c | 55 +-- 15 files changed, 734 insertions(+), 859 deletions(-) (limited to 'include') diff --git a/include/grpc/support/slice_buffer.h b/include/grpc/support/slice_buffer.h index ec048e8c91..04db003ac5 100644 --- a/include/grpc/support/slice_buffer.h +++ b/include/grpc/support/slice_buffer.h @@ -86,6 +86,8 @@ void gpr_slice_buffer_reset_and_unref(gpr_slice_buffer *sb); void gpr_slice_buffer_swap(gpr_slice_buffer *a, gpr_slice_buffer *b); /* move all of the elements of src into dst */ void gpr_slice_buffer_move_into(gpr_slice_buffer *src, gpr_slice_buffer *dst); +/* remove n bytes from the end of a slice buffer */ +void gpr_slice_buffer_trim_end(gpr_slice_buffer *src, size_t n); #ifdef __cplusplus } diff --git a/src/core/httpcli/httpcli.c b/src/core/httpcli/httpcli.c index 9012070e8e..1e38479eb1 100644 --- a/src/core/httpcli/httpcli.c +++ b/src/core/httpcli/httpcli.c @@ -61,6 +61,10 @@ typedef struct { grpc_httpcli_context *context; grpc_pollset *pollset; grpc_iomgr_object iomgr_obj; + gpr_slice_buffer incoming; + gpr_slice_buffer outgoing; + grpc_iomgr_closure on_read; + grpc_iomgr_closure done_write; } internal_request; static grpc_httpcli_get_override g_get_override = NULL; @@ -99,73 +103,70 @@ static void finish(internal_request *req, int success) { gpr_slice_unref(req->request_text); gpr_free(req->host); grpc_iomgr_unregister_object(&req->iomgr_obj); + gpr_slice_buffer_destroy(&req->incoming); + gpr_slice_buffer_destroy(&req->outgoing); gpr_free(req); } -static void on_read(void *user_data, gpr_slice *slices, size_t nslices, - grpc_endpoint_cb_status status) { +static void on_read(void *user_data, int success); + +static void do_read(internal_request *req) { + switch (grpc_endpoint_read(req->ep, &req->incoming, &req->on_read)) { + case GRPC_ENDPOINT_DONE: + on_read(req, 1); + break; + case GRPC_ENDPOINT_PENDING: + break; + case GRPC_ENDPOINT_ERROR: + on_read(req, 0); + break; + } +} + +static void on_read(void *user_data, int success) { internal_request *req = user_data; size_t i; - for (i = 0; i < nslices; i++) { - if (GPR_SLICE_LENGTH(slices[i])) { + for (i = 0; i < req->incoming.count; i++) { + if (GPR_SLICE_LENGTH(req->incoming.slices[i])) { req->have_read_byte = 1; - if (!grpc_httpcli_parser_parse(&req->parser, slices[i])) { + if (!grpc_httpcli_parser_parse(&req->parser, req->incoming.slices[i])) { finish(req, 0); - goto done; + return; } } } - switch (status) { - case GRPC_ENDPOINT_CB_OK: - grpc_endpoint_notify_on_read(req->ep, on_read, req); - break; - case GRPC_ENDPOINT_CB_EOF: - case GRPC_ENDPOINT_CB_ERROR: - case GRPC_ENDPOINT_CB_SHUTDOWN: - if (!req->have_read_byte) { - next_address(req); - } else { - finish(req, grpc_httpcli_parser_eof(&req->parser)); - } - break; - } - -done: - for (i = 0; i < nslices; i++) { - gpr_slice_unref(slices[i]); + if (success) { + do_read(req); + } else if (!req->have_read_byte) { + next_address(req); + } else { + finish(req, grpc_httpcli_parser_eof(&req->parser)); } } -static void on_written(internal_request *req) { - grpc_endpoint_notify_on_read(req->ep, on_read, req); -} +static void on_written(internal_request *req) { do_read(req); } -static void done_write(void *arg, grpc_endpoint_cb_status status) { +static void done_write(void *arg, int success) { internal_request *req = arg; - switch (status) { - case GRPC_ENDPOINT_CB_OK: - on_written(req); - break; - case GRPC_ENDPOINT_CB_EOF: - case GRPC_ENDPOINT_CB_SHUTDOWN: - case GRPC_ENDPOINT_CB_ERROR: - next_address(req); - break; + if (success) { + on_written(req); + } else { + next_address(req); } } static void start_write(internal_request *req) { gpr_slice_ref(req->request_text); - switch ( - grpc_endpoint_write(req->ep, &req->request_text, 1, done_write, req)) { - case GRPC_ENDPOINT_WRITE_DONE: + gpr_slice_buffer_add(&req->outgoing, req->request_text); + switch (grpc_endpoint_write(req->ep, &req->outgoing, &req->done_write)) { + case GRPC_ENDPOINT_DONE: on_written(req); break; - case GRPC_ENDPOINT_WRITE_PENDING: + case GRPC_ENDPOINT_PENDING: break; - case GRPC_ENDPOINT_WRITE_ERROR: + case GRPC_ENDPOINT_ERROR: finish(req, 0); break; } @@ -237,6 +238,10 @@ void grpc_httpcli_get(grpc_httpcli_context *context, grpc_pollset *pollset, request->handshaker ? request->handshaker : &grpc_httpcli_plaintext; req->context = context; req->pollset = pollset; + grpc_iomgr_closure_init(&req->on_read, on_read, req); + grpc_iomgr_closure_init(&req->done_write, done_write, req); + gpr_slice_buffer_init(&req->incoming); + gpr_slice_buffer_init(&req->outgoing); gpr_asprintf(&name, "HTTP:GET:%s:%s", request->host, request->path); grpc_iomgr_register_object(&req->iomgr_obj, name); gpr_free(name); @@ -270,7 +275,11 @@ void grpc_httpcli_post(grpc_httpcli_context *context, grpc_pollset *pollset, request->handshaker ? request->handshaker : &grpc_httpcli_plaintext; req->context = context; req->pollset = pollset; - gpr_asprintf(&name, "HTTP:GET:%s:%s", request->host, request->path); + grpc_iomgr_closure_init(&req->on_read, on_read, req); + grpc_iomgr_closure_init(&req->done_write, done_write, req); + gpr_slice_buffer_init(&req->incoming); + gpr_slice_buffer_init(&req->outgoing); + gpr_asprintf(&name, "HTTP:POST:%s:%s", request->host, request->path); grpc_iomgr_register_object(&req->iomgr_obj, name); gpr_free(name); req->host = gpr_strdup(request->host); diff --git a/src/core/iomgr/endpoint.c b/src/core/iomgr/endpoint.c index 8ee14bce9b..a7878e31dd 100644 --- a/src/core/iomgr/endpoint.c +++ b/src/core/iomgr/endpoint.c @@ -33,17 +33,16 @@ #include "src/core/iomgr/endpoint.h" -void grpc_endpoint_notify_on_read(grpc_endpoint *ep, grpc_endpoint_read_cb cb, - void *user_data) { - ep->vtable->notify_on_read(ep, cb, user_data); +grpc_endpoint_op_status grpc_endpoint_read(grpc_endpoint *ep, + gpr_slice_buffer *slices, + grpc_iomgr_closure *cb) { + return ep->vtable->read(ep, slices, cb); } -grpc_endpoint_write_status grpc_endpoint_write(grpc_endpoint *ep, - gpr_slice *slices, - size_t nslices, - grpc_endpoint_write_cb cb, - void *user_data) { - return ep->vtable->write(ep, slices, nslices, cb, user_data); +grpc_endpoint_op_status grpc_endpoint_write(grpc_endpoint *ep, + gpr_slice_buffer *slices, + grpc_iomgr_closure *cb) { + return ep->vtable->write(ep, slices, cb); } void grpc_endpoint_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset) { diff --git a/src/core/iomgr/endpoint.h b/src/core/iomgr/endpoint.h index ea92a500e8..38f1e46d67 100644 --- a/src/core/iomgr/endpoint.h +++ b/src/core/iomgr/endpoint.h @@ -37,6 +37,7 @@ #include "src/core/iomgr/pollset.h" #include "src/core/iomgr/pollset_set.h" #include +#include #include /* An endpoint caps a streaming channel between two communicating processes. @@ -45,31 +46,17 @@ typedef struct grpc_endpoint grpc_endpoint; typedef struct grpc_endpoint_vtable grpc_endpoint_vtable; -typedef enum grpc_endpoint_cb_status { - GRPC_ENDPOINT_CB_OK = 0, /* Call completed successfully */ - GRPC_ENDPOINT_CB_EOF, /* Call completed successfully, end of file reached */ - GRPC_ENDPOINT_CB_SHUTDOWN, /* Call interrupted by shutdown */ - GRPC_ENDPOINT_CB_ERROR /* Call interrupted by socket error */ -} grpc_endpoint_cb_status; - -typedef enum grpc_endpoint_write_status { - GRPC_ENDPOINT_WRITE_DONE, /* completed immediately, cb won't be called */ - GRPC_ENDPOINT_WRITE_PENDING, /* cb will be called when completed */ - GRPC_ENDPOINT_WRITE_ERROR /* write errored out, cb won't be called */ -} grpc_endpoint_write_status; - -typedef void (*grpc_endpoint_read_cb)(void *user_data, gpr_slice *slices, - size_t nslices, - grpc_endpoint_cb_status error); -typedef void (*grpc_endpoint_write_cb)(void *user_data, - grpc_endpoint_cb_status error); +typedef enum grpc_endpoint_op_status { + GRPC_ENDPOINT_DONE, /* completed immediately, cb won't be called */ + GRPC_ENDPOINT_PENDING, /* cb will be called when completed */ + GRPC_ENDPOINT_ERROR /* write errored out, cb won't be called */ +} grpc_endpoint_op_status; struct grpc_endpoint_vtable { - void (*notify_on_read)(grpc_endpoint *ep, grpc_endpoint_read_cb cb, - void *user_data); - grpc_endpoint_write_status (*write)(grpc_endpoint *ep, gpr_slice *slices, - size_t nslices, grpc_endpoint_write_cb cb, - void *user_data); + grpc_endpoint_op_status (*read)(grpc_endpoint *ep, gpr_slice_buffer *slices, + grpc_iomgr_closure *cb); + grpc_endpoint_op_status (*write)(grpc_endpoint *ep, gpr_slice_buffer *slices, + grpc_iomgr_closure *cb); void (*add_to_pollset)(grpc_endpoint *ep, grpc_pollset *pollset); void (*add_to_pollset_set)(grpc_endpoint *ep, grpc_pollset_set *pollset); void (*shutdown)(grpc_endpoint *ep); @@ -77,9 +64,13 @@ struct grpc_endpoint_vtable { char *(*get_peer)(grpc_endpoint *ep); }; -/* When data is available on the connection, calls the callback with slices. */ -void grpc_endpoint_notify_on_read(grpc_endpoint *ep, grpc_endpoint_read_cb cb, - void *user_data); +/* When data is available on the connection, calls the callback with slices. + Callback success indicates that the endpoint can accept more reads, failure + indicates the endpoint is closed. + Valid slices may be placed into \a slices even on callback success == 0. */ +grpc_endpoint_op_status grpc_endpoint_read( + grpc_endpoint *ep, gpr_slice_buffer *slices, + grpc_iomgr_closure *cb) GRPC_MUST_USE_RESULT; char *grpc_endpoint_get_peer(grpc_endpoint *ep); @@ -89,11 +80,9 @@ char *grpc_endpoint_get_peer(grpc_endpoint *ep); returns GRPC_ENDPOINT_WRITE_DONE. Otherwise it returns GRPC_ENDPOINT_WRITE_PENDING and calls cb when the connection is ready for more data. */ -grpc_endpoint_write_status grpc_endpoint_write(grpc_endpoint *ep, - gpr_slice *slices, - size_t nslices, - grpc_endpoint_write_cb cb, - void *user_data); +grpc_endpoint_op_status grpc_endpoint_write( + grpc_endpoint *ep, gpr_slice_buffer *slices, + grpc_iomgr_closure *cb) GRPC_MUST_USE_RESULT; /* Causes any pending read/write callbacks to run immediately with GRPC_ENDPOINT_CB_SHUTDOWN status */ diff --git a/src/core/iomgr/tcp_posix.c b/src/core/iomgr/tcp_posix.c index 360e6ebd8c..36ba3a7606 100644 --- a/src/core/iomgr/tcp_posix.c +++ b/src/core/iomgr/tcp_posix.c @@ -61,209 +61,8 @@ #define SENDMSG_FLAGS 0 #endif -/* Holds a slice array and associated state. */ -typedef struct grpc_tcp_slice_state { - gpr_slice *slices; /* Array of slices */ - size_t nslices; /* Size of slices array. */ - ssize_t first_slice; /* First valid slice in array */ - ssize_t last_slice; /* Last valid slice in array */ - gpr_slice working_slice; /* pointer to original final slice */ - int working_slice_valid; /* True if there is a working slice */ - int memory_owned; /* True if slices array is owned */ -} grpc_tcp_slice_state; - int grpc_tcp_trace = 0; -static void slice_state_init(grpc_tcp_slice_state *state, gpr_slice *slices, - size_t nslices, size_t valid_slices) { - state->slices = slices; - state->nslices = nslices; - if (valid_slices == 0) { - state->first_slice = -1; - } else { - state->first_slice = 0; - } - state->last_slice = valid_slices - 1; - state->working_slice_valid = 0; - state->memory_owned = 0; -} - -/* Returns true if there is still available data */ -static int slice_state_has_available(grpc_tcp_slice_state *state) { - return state->first_slice != -1 && state->last_slice >= state->first_slice; -} - -static ssize_t slice_state_slices_allocated(grpc_tcp_slice_state *state) { - if (state->first_slice == -1) { - return 0; - } else { - return state->last_slice - state->first_slice + 1; - } -} - -static void slice_state_realloc(grpc_tcp_slice_state *state, size_t new_size) { - /* TODO(klempner): use realloc instead when first_slice is 0 */ - /* TODO(klempner): Avoid a realloc in cases where it is unnecessary */ - gpr_slice *slices = state->slices; - size_t original_size = slice_state_slices_allocated(state); - size_t i; - gpr_slice *new_slices = gpr_malloc(sizeof(gpr_slice) * new_size); - - for (i = 0; i < original_size; ++i) { - new_slices[i] = slices[i + state->first_slice]; - } - - state->slices = new_slices; - state->last_slice = original_size - 1; - if (original_size > 0) { - state->first_slice = 0; - } else { - state->first_slice = -1; - } - state->nslices = new_size; - - if (state->memory_owned) { - gpr_free(slices); - } - state->memory_owned = 1; -} - -static void slice_state_remove_prefix(grpc_tcp_slice_state *state, - size_t prefix_bytes) { - gpr_slice *current_slice = &state->slices[state->first_slice]; - size_t current_slice_size; - - while (slice_state_has_available(state)) { - current_slice_size = GPR_SLICE_LENGTH(*current_slice); - if (current_slice_size > prefix_bytes) { - /* TODO(klempner): Get rid of the extra refcount created here by adding a - native "trim the first N bytes" operation to splice */ - /* TODO(klempner): This really shouldn't be modifying the current slice - unless we own the slices array. */ - gpr_slice tail; - tail = gpr_slice_split_tail(current_slice, prefix_bytes); - gpr_slice_unref(*current_slice); - *current_slice = tail; - return; - } else { - gpr_slice_unref(*current_slice); - ++state->first_slice; - ++current_slice; - prefix_bytes -= current_slice_size; - } - } -} - -static void slice_state_destroy(grpc_tcp_slice_state *state) { - while (slice_state_has_available(state)) { - gpr_slice_unref(state->slices[state->first_slice]); - ++state->first_slice; - } - - if (state->memory_owned) { - gpr_free(state->slices); - state->memory_owned = 0; - } -} - -void slice_state_transfer_ownership(grpc_tcp_slice_state *state, - gpr_slice **slices, size_t *nslices) { - *slices = state->slices + state->first_slice; - *nslices = state->last_slice - state->first_slice + 1; - - state->first_slice = -1; - state->last_slice = -1; -} - -/* Fills iov with the first min(iov_size, available) slices, returns number - filled */ -static size_t slice_state_to_iovec(grpc_tcp_slice_state *state, - struct iovec *iov, size_t iov_size) { - size_t nslices = state->last_slice - state->first_slice + 1; - gpr_slice *slices = state->slices + state->first_slice; - size_t i; - if (nslices < iov_size) { - iov_size = nslices; - } - - for (i = 0; i < iov_size; ++i) { - iov[i].iov_base = GPR_SLICE_START_PTR(slices[i]); - iov[i].iov_len = GPR_SLICE_LENGTH(slices[i]); - } - return iov_size; -} - -/* Makes n blocks available at the end of state, writes them into iov, and - returns the number of bytes allocated */ -static size_t slice_state_append_blocks_into_iovec(grpc_tcp_slice_state *state, - struct iovec *iov, size_t n, - size_t slice_size) { - size_t target_size; - size_t i; - size_t allocated_bytes; - ssize_t allocated_slices = slice_state_slices_allocated(state); - - if (n - state->working_slice_valid >= state->nslices - state->last_slice) { - /* Need to grow the slice array */ - target_size = state->nslices; - do { - target_size = target_size * 2; - } while (target_size < allocated_slices + n - state->working_slice_valid); - /* TODO(klempner): If this ever needs to support both prefix removal and - append, we should be smarter about the growth logic here */ - slice_state_realloc(state, target_size); - } - - i = 0; - allocated_bytes = 0; - - if (state->working_slice_valid) { - iov[0].iov_base = GPR_SLICE_END_PTR(state->slices[state->last_slice]); - iov[0].iov_len = GPR_SLICE_LENGTH(state->working_slice) - - GPR_SLICE_LENGTH(state->slices[state->last_slice]); - allocated_bytes += iov[0].iov_len; - ++i; - state->slices[state->last_slice] = state->working_slice; - state->working_slice_valid = 0; - } - - for (; i < n; ++i) { - ++state->last_slice; - state->slices[state->last_slice] = gpr_slice_malloc(slice_size); - iov[i].iov_base = GPR_SLICE_START_PTR(state->slices[state->last_slice]); - iov[i].iov_len = slice_size; - allocated_bytes += slice_size; - } - if (state->first_slice == -1) { - state->first_slice = 0; - } - return allocated_bytes; -} - -/* Remove the last n bytes from state */ -/* TODO(klempner): Consider having this defer actual deletion until later */ -static void slice_state_remove_last(grpc_tcp_slice_state *state, size_t bytes) { - while (bytes > 0 && slice_state_has_available(state)) { - if (GPR_SLICE_LENGTH(state->slices[state->last_slice]) > bytes) { - state->working_slice = state->slices[state->last_slice]; - state->working_slice_valid = 1; - /* TODO(klempner): Combine these into a single operation that doesn't need - to refcount */ - gpr_slice_unref(gpr_slice_split_tail( - &state->slices[state->last_slice], - GPR_SLICE_LENGTH(state->slices[state->last_slice]) - bytes)); - bytes = 0; - } else { - bytes -= GPR_SLICE_LENGTH(state->slices[state->last_slice]); - gpr_slice_unref(state->slices[state->last_slice]); - --state->last_slice; - if (state->last_slice == -1) { - state->first_slice = -1; - } - } - } -} - typedef struct { grpc_endpoint base; grpc_fd *em_fd; @@ -273,12 +72,15 @@ typedef struct { size_t slice_size; gpr_refcount refcount; - grpc_endpoint_read_cb read_cb; - void *read_user_data; - grpc_endpoint_write_cb write_cb; - void *write_user_data; + gpr_slice_buffer *incoming_buffer; + gpr_slice_buffer *outgoing_buffer; + /** slice within outgoing_buffer to write next */ + size_t outgoing_slice_idx; + /** byte within outgoing_buffer->slices[outgoing_slice_idx] to write next */ + size_t outgoing_byte_idx; - grpc_tcp_slice_state write_state; + grpc_iomgr_closure *read_cb; + grpc_iomgr_closure *write_cb; grpc_iomgr_closure read_closure; grpc_iomgr_closure write_closure; @@ -288,65 +90,95 @@ typedef struct { char *peer_string; } grpc_tcp; -static void grpc_tcp_handle_read(void *arg /* grpc_tcp */, int success); -static void grpc_tcp_handle_write(void *arg /* grpc_tcp */, int success); +static void tcp_handle_read(void *arg /* grpc_tcp */, int success); +static void tcp_handle_write(void *arg /* grpc_tcp */, int success); -static void grpc_tcp_shutdown(grpc_endpoint *ep) { +static void tcp_shutdown(grpc_endpoint *ep) { grpc_tcp *tcp = (grpc_tcp *)ep; grpc_fd_shutdown(tcp->em_fd); } -static void grpc_tcp_unref(grpc_tcp *tcp) { - int refcount_zero = gpr_unref(&tcp->refcount); - if (refcount_zero) { - grpc_fd_orphan(tcp->em_fd, NULL, "tcp_unref_orphan"); - gpr_free(tcp->peer_string); - gpr_free(tcp); +static void tcp_free(grpc_tcp *tcp) { + grpc_fd_orphan(tcp->em_fd, NULL, "tcp_unref_orphan"); + gpr_free(tcp->peer_string); + gpr_free(tcp); +} + +#define GRPC_TCP_REFCOUNT_DEBUG +#define TCP_UNREF(tcp, reason) tcp_unref((tcp), (reason), __FILE__, __LINE__) +#define TCP_REF(tcp, reason) tcp_ref((tcp), (reason), __FILE__, __LINE__) +static void tcp_unref(grpc_tcp *tcp, const char *reason, const char *file, + int line) { + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP unref %p : %s %d -> %d", tcp, + reason, tcp->refcount.count, tcp->refcount.count - 1); + if (gpr_unref(&tcp->refcount)) { + tcp_free(tcp); + } +} + +static void tcp_ref(grpc_tcp *tcp, const char *reason, const char *file, + int line) { + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP ref %p : %s %d -> %d", tcp, + reason, tcp->refcount.count, tcp->refcount.count + 1); + gpr_ref(&tcp->refcount); +} +#ifdef GRPC_TCP_REFCOUNT_DEBUG +#else +#define TCP_UNREF(tcp, reason) tcp_unref((tcp)) +#define TCP_REF(tcp, reason) tcp_ref((tcp)) +static void tcp_unref(grpc_tcp *tcp) { + if (gpr_unref(&tcp->refcount)) { + tcp_free(tcp); } } -static void grpc_tcp_destroy(grpc_endpoint *ep) { +static void tcp_ref(grpc_tcp *tcp) { gpr_ref(&tcp->refcount); } +#endif + +static void tcp_destroy(grpc_endpoint *ep) { grpc_tcp *tcp = (grpc_tcp *)ep; - grpc_tcp_unref(tcp); + TCP_UNREF(tcp, "destroy"); } -static void call_read_cb(grpc_tcp *tcp, gpr_slice *slices, size_t nslices, - grpc_endpoint_cb_status status) { - grpc_endpoint_read_cb cb = tcp->read_cb; +static void call_read_cb(grpc_tcp *tcp, int success) { + grpc_iomgr_closure *cb = tcp->read_cb; if (grpc_tcp_trace) { size_t i; - gpr_log(GPR_DEBUG, "read: status=%d", status); - for (i = 0; i < nslices; i++) { - char *dump = gpr_dump_slice(slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII); + gpr_log(GPR_DEBUG, "read: success=%d", success); + for (i = 0; i < tcp->incoming_buffer->count; i++) { + char *dump = gpr_dump_slice(tcp->incoming_buffer->slices[i], + GPR_DUMP_HEX | GPR_DUMP_ASCII); gpr_log(GPR_DEBUG, "READ %p: %s", tcp, dump); gpr_free(dump); } } tcp->read_cb = NULL; - cb(tcp->read_user_data, slices, nslices, status); + tcp->incoming_buffer = NULL; + cb->cb(cb->cb_arg, success); } -#define INLINE_SLICE_BUFFER_SIZE 8 #define MAX_READ_IOVEC 4 -static void grpc_tcp_continue_read(grpc_tcp *tcp) { - gpr_slice static_read_slices[INLINE_SLICE_BUFFER_SIZE]; +static void tcp_continue_read(grpc_tcp *tcp) { struct msghdr msg; struct iovec iov[MAX_READ_IOVEC]; ssize_t read_bytes; - ssize_t allocated_bytes; - struct grpc_tcp_slice_state read_state; - gpr_slice *final_slices; - size_t final_nslices; + 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); GRPC_TIMER_BEGIN(GRPC_PTAG_HANDLE_READ, 0); - slice_state_init(&read_state, static_read_slices, INLINE_SLICE_BUFFER_SIZE, - 0); - allocated_bytes = slice_state_append_blocks_into_iovec( - &read_state, iov, tcp->iov_size, tcp->slice_size); + while (tcp->incoming_buffer->count < (size_t)tcp->iov_size) { + gpr_slice_buffer_add_indexed(tcp->incoming_buffer, + gpr_slice_malloc(tcp->slice_size)); + } + for (i = 0; i < tcp->incoming_buffer->count; i++) { + iov[i].iov_base = GPR_SLICE_START_PTR(tcp->incoming_buffer->slices[i]); + iov[i].iov_len = GPR_SLICE_LENGTH(tcp->incoming_buffer->slices[i]); + } msg.msg_name = NULL; msg.msg_namelen = 0; @@ -362,87 +194,63 @@ static void grpc_tcp_continue_read(grpc_tcp *tcp) { } while (read_bytes < 0 && errno == EINTR); GRPC_TIMER_END(GRPC_PTAG_RECVMSG, 0); - if (read_bytes < allocated_bytes) { - /* TODO(klempner): Consider a second read first, in hopes of getting a - * quick EAGAIN and saving a bunch of allocations. */ - slice_state_remove_last(&read_state, read_bytes < 0 - ? allocated_bytes - : allocated_bytes - read_bytes); - } - if (read_bytes < 0) { - /* NB: After calling the user_cb a parallel call of the read handler may + /* 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; } - if (slice_state_has_available(&read_state)) { - /* TODO(klempner): We should probably do the call into the application - without all this junk on the stack */ - /* FIXME(klempner): Refcount properly */ - slice_state_transfer_ownership(&read_state, &final_slices, - &final_nslices); - tcp->finished_edge = 1; - call_read_cb(tcp, final_slices, final_nslices, GRPC_ENDPOINT_CB_OK); - slice_state_destroy(&read_state); - grpc_tcp_unref(tcp); - } else { - /* We've consumed the edge, request a new one */ - slice_state_destroy(&read_state); - grpc_fd_notify_on_read(tcp->em_fd, &tcp->read_closure); - } + /* We've consumed the edge, request a new one */ + grpc_fd_notify_on_read(tcp->em_fd, &tcp->read_closure); } else { /* TODO(klempner): Log interesting errors */ - call_read_cb(tcp, NULL, 0, GRPC_ENDPOINT_CB_ERROR); - slice_state_destroy(&read_state); - grpc_tcp_unref(tcp); + gpr_slice_buffer_reset_and_unref(tcp->incoming_buffer); + call_read_cb(tcp, 0); + TCP_UNREF(tcp, "read"); } } else if (read_bytes == 0) { /* 0 read size ==> end of stream */ - if (slice_state_has_available(&read_state)) { - /* there were bytes already read: pass them up to the application */ - slice_state_transfer_ownership(&read_state, &final_slices, - &final_nslices); - call_read_cb(tcp, final_slices, final_nslices, GRPC_ENDPOINT_CB_EOF); - } else { - call_read_cb(tcp, NULL, 0, GRPC_ENDPOINT_CB_EOF); - } - slice_state_destroy(&read_state); - grpc_tcp_unref(tcp); + gpr_slice_buffer_reset_and_unref(tcp->incoming_buffer); + call_read_cb(tcp, 0); + TCP_UNREF(tcp, "read"); } else { - if (tcp->iov_size < MAX_READ_IOVEC) { + GPR_ASSERT((size_t)read_bytes <= tcp->incoming_buffer->length); + if ((size_t)read_bytes < tcp->incoming_buffer->length) { + gpr_slice_buffer_trim_end(tcp->incoming_buffer, + tcp->incoming_buffer->length - read_bytes); + } else if (tcp->iov_size < MAX_READ_IOVEC) { ++tcp->iov_size; } - GPR_ASSERT(slice_state_has_available(&read_state)); - slice_state_transfer_ownership(&read_state, &final_slices, &final_nslices); - call_read_cb(tcp, final_slices, final_nslices, GRPC_ENDPOINT_CB_OK); - slice_state_destroy(&read_state); - grpc_tcp_unref(tcp); + GPR_ASSERT((size_t)read_bytes == tcp->incoming_buffer->length); + call_read_cb(tcp, 1); + TCP_UNREF(tcp, "read"); } GRPC_TIMER_END(GRPC_PTAG_HANDLE_READ, 0); } -static void grpc_tcp_handle_read(void *arg /* grpc_tcp */, int success) { +static void tcp_handle_read(void *arg /* grpc_tcp */, int success) { grpc_tcp *tcp = (grpc_tcp *)arg; GPR_ASSERT(!tcp->finished_edge); if (!success) { - call_read_cb(tcp, NULL, 0, GRPC_ENDPOINT_CB_SHUTDOWN); - grpc_tcp_unref(tcp); + call_read_cb(tcp, 0); + TCP_UNREF(tcp, "read"); } else { - grpc_tcp_continue_read(tcp); + tcp_continue_read(tcp); } } -static void grpc_tcp_notify_on_read(grpc_endpoint *ep, grpc_endpoint_read_cb cb, - void *user_data) { +static grpc_endpoint_op_status tcp_read(grpc_endpoint *ep, + gpr_slice_buffer *incoming_buffer, + grpc_iomgr_closure *cb) { grpc_tcp *tcp = (grpc_tcp *)ep; GPR_ASSERT(tcp->read_cb == NULL); tcp->read_cb = cb; - tcp->read_user_data = user_data; - gpr_ref(&tcp->refcount); + tcp->incoming_buffer = incoming_buffer; + gpr_slice_buffer_reset_and_unref(incoming_buffer); + TCP_REF(tcp, "read"); if (tcp->finished_edge) { tcp->finished_edge = 0; grpc_fd_notify_on_read(tcp->em_fd, &tcp->read_closure); @@ -450,18 +258,41 @@ static void grpc_tcp_notify_on_read(grpc_endpoint *ep, grpc_endpoint_read_cb cb, tcp->handle_read_closure.cb_arg = tcp; grpc_iomgr_add_delayed_callback(&tcp->handle_read_closure, 1); } + /* TODO(ctiller): immediate return */ + return GRPC_ENDPOINT_PENDING; } #define MAX_WRITE_IOVEC 16 -static grpc_endpoint_write_status grpc_tcp_flush(grpc_tcp *tcp) { +static grpc_endpoint_op_status tcp_flush(grpc_tcp *tcp) { struct msghdr msg; struct iovec iov[MAX_WRITE_IOVEC]; int iov_size; ssize_t sent_length; - grpc_tcp_slice_state *state = &tcp->write_state; + ssize_t sending_length; + ssize_t trailing; + ssize_t unwind_slice_idx; + ssize_t unwind_byte_idx; for (;;) { - iov_size = slice_state_to_iovec(state, iov, MAX_WRITE_IOVEC); + 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 = + GPR_SLICE_START_PTR( + tcp->outgoing_buffer->slices[tcp->outgoing_slice_idx]) + + tcp->outgoing_byte_idx; + iov[iov_size].iov_len = + GPR_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; @@ -480,70 +311,75 @@ static grpc_endpoint_write_status grpc_tcp_flush(grpc_tcp *tcp) { if (sent_length < 0) { if (errno == EAGAIN) { - return GRPC_ENDPOINT_WRITE_PENDING; + tcp->outgoing_slice_idx = unwind_slice_idx; + tcp->outgoing_byte_idx = unwind_byte_idx; + return GRPC_ENDPOINT_PENDING; } else { /* TODO(klempner): Log some of these */ - slice_state_destroy(state); - return GRPC_ENDPOINT_WRITE_ERROR; + return GRPC_ENDPOINT_ERROR; } } - /* TODO(klempner): Probably better to batch this after we finish flushing */ - slice_state_remove_prefix(state, sent_length); + GPR_ASSERT(tcp->outgoing_byte_idx == 0); + trailing = sending_length - sent_length; + while (trailing > 0) { + ssize_t slice_length; + + tcp->outgoing_slice_idx--; + slice_length = GPR_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 (!slice_state_has_available(state)) { - return GRPC_ENDPOINT_WRITE_DONE; + if (tcp->outgoing_slice_idx == tcp->outgoing_buffer->count) { + return GRPC_ENDPOINT_DONE; } }; } -static void grpc_tcp_handle_write(void *arg /* grpc_tcp */, int success) { +static void tcp_handle_write(void *arg /* grpc_tcp */, int success) { grpc_tcp *tcp = (grpc_tcp *)arg; - grpc_endpoint_write_status write_status; - grpc_endpoint_cb_status cb_status; - grpc_endpoint_write_cb cb; + grpc_endpoint_op_status status; + grpc_iomgr_closure *cb; if (!success) { - slice_state_destroy(&tcp->write_state); cb = tcp->write_cb; tcp->write_cb = NULL; - cb(tcp->write_user_data, GRPC_ENDPOINT_CB_SHUTDOWN); - grpc_tcp_unref(tcp); + cb->cb(cb->cb_arg, 0); + TCP_UNREF(tcp, "write"); return; } GRPC_TIMER_BEGIN(GRPC_PTAG_TCP_CB_WRITE, 0); - write_status = grpc_tcp_flush(tcp); - if (write_status == GRPC_ENDPOINT_WRITE_PENDING) { + status = tcp_flush(tcp); + if (status == GRPC_ENDPOINT_PENDING) { grpc_fd_notify_on_write(tcp->em_fd, &tcp->write_closure); } else { - slice_state_destroy(&tcp->write_state); - if (write_status == GRPC_ENDPOINT_WRITE_DONE) { - cb_status = GRPC_ENDPOINT_CB_OK; - } else { - cb_status = GRPC_ENDPOINT_CB_ERROR; - } cb = tcp->write_cb; tcp->write_cb = NULL; - cb(tcp->write_user_data, cb_status); - grpc_tcp_unref(tcp); + cb->cb(cb->cb_arg, status == GRPC_ENDPOINT_DONE); + TCP_UNREF(tcp, "write"); } GRPC_TIMER_END(GRPC_PTAG_TCP_CB_WRITE, 0); } -static grpc_endpoint_write_status grpc_tcp_write(grpc_endpoint *ep, - gpr_slice *slices, - size_t nslices, - grpc_endpoint_write_cb cb, - void *user_data) { +static grpc_endpoint_op_status tcp_write(grpc_endpoint *ep, + gpr_slice_buffer *buf, + grpc_iomgr_closure *cb) { grpc_tcp *tcp = (grpc_tcp *)ep; - grpc_endpoint_write_status status; + grpc_endpoint_op_status status; if (grpc_tcp_trace) { size_t i; - for (i = 0; i < nslices; i++) { - char *data = gpr_dump_slice(slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII); + for (i = 0; i < buf->count; i++) { + char *data = + gpr_dump_slice(buf->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII); gpr_log(GPR_DEBUG, "WRITE %p: %s", tcp, data); gpr_free(data); } @@ -551,15 +387,19 @@ static grpc_endpoint_write_status grpc_tcp_write(grpc_endpoint *ep, GRPC_TIMER_BEGIN(GRPC_PTAG_TCP_WRITE, 0); GPR_ASSERT(tcp->write_cb == NULL); - slice_state_init(&tcp->write_state, slices, nslices, nslices); - status = grpc_tcp_flush(tcp); - if (status == GRPC_ENDPOINT_WRITE_PENDING) { - /* TODO(klempner): Consider inlining rather than malloc for small nslices */ - slice_state_realloc(&tcp->write_state, nslices); - gpr_ref(&tcp->refcount); + if (buf->length == 0) { + GRPC_TIMER_END(GRPC_PTAG_TCP_WRITE, 0); + return GRPC_ENDPOINT_DONE; + } + tcp->outgoing_buffer = buf; + tcp->outgoing_slice_idx = 0; + tcp->outgoing_byte_idx = 0; + + status = tcp_flush(tcp); + if (status == GRPC_ENDPOINT_PENDING) { + TCP_REF(tcp, "write"); tcp->write_cb = cb; - tcp->write_user_data = user_data; grpc_fd_notify_on_write(tcp->em_fd, &tcp->write_closure); } @@ -567,27 +407,25 @@ static grpc_endpoint_write_status grpc_tcp_write(grpc_endpoint *ep, return status; } -static void grpc_tcp_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset) { +static void tcp_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset) { grpc_tcp *tcp = (grpc_tcp *)ep; grpc_pollset_add_fd(pollset, tcp->em_fd); } -static void grpc_tcp_add_to_pollset_set(grpc_endpoint *ep, - grpc_pollset_set *pollset_set) { +static void tcp_add_to_pollset_set(grpc_endpoint *ep, + grpc_pollset_set *pollset_set) { grpc_tcp *tcp = (grpc_tcp *)ep; grpc_pollset_set_add_fd(pollset_set, tcp->em_fd); } -static char *grpc_tcp_get_peer(grpc_endpoint *ep) { +static char *tcp_get_peer(grpc_endpoint *ep) { grpc_tcp *tcp = (grpc_tcp *)ep; return gpr_strdup(tcp->peer_string); } static const grpc_endpoint_vtable vtable = { - grpc_tcp_notify_on_read, grpc_tcp_write, - grpc_tcp_add_to_pollset, grpc_tcp_add_to_pollset_set, - grpc_tcp_shutdown, grpc_tcp_destroy, - grpc_tcp_get_peer}; + tcp_read, tcp_write, tcp_add_to_pollset, tcp_add_to_pollset_set, + tcp_shutdown, tcp_destroy, tcp_get_peer}; grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd, size_t slice_size, const char *peer_string) { @@ -597,21 +435,19 @@ grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd, size_t slice_size, tcp->fd = em_fd->fd; tcp->read_cb = NULL; tcp->write_cb = NULL; - tcp->read_user_data = NULL; - tcp->write_user_data = NULL; + tcp->incoming_buffer = NULL; tcp->slice_size = slice_size; tcp->iov_size = 1; tcp->finished_edge = 1; - slice_state_init(&tcp->write_state, NULL, 0, 0); /* paired with unref in grpc_tcp_destroy */ gpr_ref_init(&tcp->refcount, 1); tcp->em_fd = em_fd; - tcp->read_closure.cb = grpc_tcp_handle_read; + tcp->read_closure.cb = tcp_handle_read; tcp->read_closure.cb_arg = tcp; - tcp->write_closure.cb = grpc_tcp_handle_write; + tcp->write_closure.cb = tcp_handle_write; tcp->write_closure.cb_arg = tcp; - tcp->handle_read_closure.cb = grpc_tcp_handle_read; + tcp->handle_read_closure.cb = tcp_handle_read; return &tcp->base; } diff --git a/src/core/security/secure_endpoint.c b/src/core/security/secure_endpoint.c index 81b3e33cb2..4206c39318 100644 --- a/src/core/security/secure_endpoint.c +++ b/src/core/security/secure_endpoint.c @@ -49,15 +49,15 @@ typedef struct { struct tsi_frame_protector *protector; gpr_mu protector_mu; /* saved upper level callbacks and user_data. */ - grpc_endpoint_read_cb read_cb; - void *read_user_data; - grpc_endpoint_write_cb write_cb; - void *write_user_data; + grpc_iomgr_closure *read_cb; + grpc_iomgr_closure *write_cb; + grpc_iomgr_closure on_read; + gpr_slice_buffer *read_buffer; + gpr_slice_buffer source_buffer; /* saved handshaker leftover data to unprotect. */ gpr_slice_buffer leftover_bytes; /* buffers for read and write */ gpr_slice read_staging_buffer; - gpr_slice_buffer input_buffer; gpr_slice write_staging_buffer; gpr_slice_buffer output_buffer; @@ -67,62 +67,91 @@ typedef struct { int grpc_trace_secure_endpoint = 0; -static void secure_endpoint_ref(secure_endpoint *ep) { gpr_ref(&ep->ref); } - static void destroy(secure_endpoint *secure_ep) { secure_endpoint *ep = secure_ep; grpc_endpoint_destroy(ep->wrapped_ep); tsi_frame_protector_destroy(ep->protector); gpr_slice_buffer_destroy(&ep->leftover_bytes); gpr_slice_unref(ep->read_staging_buffer); - gpr_slice_buffer_destroy(&ep->input_buffer); gpr_slice_unref(ep->write_staging_buffer); gpr_slice_buffer_destroy(&ep->output_buffer); + gpr_slice_buffer_destroy(&ep->source_buffer); gpr_mu_destroy(&ep->protector_mu); gpr_free(ep); } +#define GRPC_SECURE_ENDPOINT_REFCOUNT_DEBUG +#define SECURE_ENDPOINT_UNREF(ep, reason) \ + secure_endpoint_unref((ep), (reason), __FILE__, __LINE__) +#define SECURE_ENDPOINT_REF(ep, reason) \ + secure_endpoint_ref((ep), (reason), __FILE__, __LINE__) +static void secure_endpoint_unref(secure_endpoint *ep, const char *reason, + const char *file, int line) { + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "SECENDP unref %p : %s %d -> %d", + ep, reason, ep->ref.count, ep->ref.count - 1); + if (gpr_unref(&ep->ref)) { + destroy(ep); + } +} + +static void secure_endpoint_ref(secure_endpoint *ep, const char *reason, + const char *file, int line) { + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "SECENDP ref %p : %s %d -> %d", + ep, reason, ep->ref.count, ep->ref.count + 1); + gpr_ref(&ep->ref); +} +#ifdef GRPC_SECURE_ENDPOINT_REFCOUNT_DEBUG +#else +#define SECURE_ENDPOINT_UNREF(ep, reason) secure_endpoint_unref((ep)) +#define SECURE_ENDPOINT_REF(ep, reason) secure_endpoint_ref((ep)) static void secure_endpoint_unref(secure_endpoint *ep) { if (gpr_unref(&ep->ref)) { destroy(ep); } } +static void secure_endpoint_ref(secure_endpoint *ep) { gpr_ref(&ep->ref); } +#endif + static void flush_read_staging_buffer(secure_endpoint *ep, gpr_uint8 **cur, gpr_uint8 **end) { - gpr_slice_buffer_add(&ep->input_buffer, ep->read_staging_buffer); + gpr_slice_buffer_add(ep->read_buffer, ep->read_staging_buffer); ep->read_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE); *cur = GPR_SLICE_START_PTR(ep->read_staging_buffer); *end = GPR_SLICE_END_PTR(ep->read_staging_buffer); } -static void call_read_cb(secure_endpoint *ep, gpr_slice *slices, size_t nslices, - grpc_endpoint_cb_status error) { +static void call_read_cb(secure_endpoint *ep, int success) { if (grpc_trace_secure_endpoint) { size_t i; - for (i = 0; i < nslices; i++) { - char *data = gpr_dump_slice(slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII); + for (i = 0; i < ep->read_buffer->count; i++) { + char *data = gpr_dump_slice(ep->read_buffer->slices[i], + GPR_DUMP_HEX | GPR_DUMP_ASCII); gpr_log(GPR_DEBUG, "READ %p: %s", ep, data); gpr_free(data); } } - ep->read_cb(ep->read_user_data, slices, nslices, error); - secure_endpoint_unref(ep); + ep->read_buffer = NULL; + ep->read_cb->cb(ep->read_cb->cb_arg, success); + SECURE_ENDPOINT_UNREF(ep, "read"); } -static void on_read(void *user_data, gpr_slice *slices, size_t nslices, - grpc_endpoint_cb_status error) { +static int on_read(void *user_data, int success) { unsigned i; gpr_uint8 keep_looping = 0; - size_t input_buffer_count = 0; tsi_result result = TSI_OK; secure_endpoint *ep = (secure_endpoint *)user_data; gpr_uint8 *cur = GPR_SLICE_START_PTR(ep->read_staging_buffer); gpr_uint8 *end = GPR_SLICE_END_PTR(ep->read_staging_buffer); + if (!success) { + gpr_slice_buffer_reset_and_unref(ep->read_buffer); + return 0; + } + /* TODO(yangg) check error, maybe bail out early */ - for (i = 0; i < nslices; i++) { - gpr_slice encrypted = slices[i]; + for (i = 0; i < ep->source_buffer.count; i++) { + gpr_slice encrypted = ep->source_buffer.slices[i]; gpr_uint8 *message_bytes = GPR_SLICE_START_PTR(encrypted); size_t message_size = GPR_SLICE_LENGTH(encrypted); @@ -161,7 +190,7 @@ static void on_read(void *user_data, gpr_slice *slices, size_t nslices, if (cur != GPR_SLICE_START_PTR(ep->read_staging_buffer)) { gpr_slice_buffer_add( - &ep->input_buffer, + ep->read_buffer, gpr_slice_split_head( &ep->read_staging_buffer, (size_t)(cur - GPR_SLICE_START_PTR(ep->read_staging_buffer)))); @@ -169,38 +198,53 @@ static void on_read(void *user_data, gpr_slice *slices, size_t nslices, /* TODO(yangg) experiment with moving this block after read_cb to see if it helps latency */ - for (i = 0; i < nslices; i++) { - gpr_slice_unref(slices[i]); - } + gpr_slice_buffer_reset_and_unref(&ep->source_buffer); if (result != TSI_OK) { - gpr_slice_buffer_reset_and_unref(&ep->input_buffer); - call_read_cb(ep, NULL, 0, GRPC_ENDPOINT_CB_ERROR); - return; + gpr_slice_buffer_reset_and_unref(ep->read_buffer); + return 0; } - /* The upper level will unref the slices. */ - input_buffer_count = ep->input_buffer.count; - ep->input_buffer.count = 0; - call_read_cb(ep, ep->input_buffer.slices, input_buffer_count, error); + + return 1; +} + +static void on_read_cb(void *user_data, int success) { + call_read_cb(user_data, on_read(user_data, success)); } -static void endpoint_notify_on_read(grpc_endpoint *secure_ep, - grpc_endpoint_read_cb cb, void *user_data) { +static grpc_endpoint_op_status endpoint_read(grpc_endpoint *secure_ep, + gpr_slice_buffer *slices, + grpc_iomgr_closure *cb) { secure_endpoint *ep = (secure_endpoint *)secure_ep; + int immediate_read_success = -1; ep->read_cb = cb; - ep->read_user_data = user_data; - - secure_endpoint_ref(ep); + ep->read_buffer = slices; + gpr_slice_buffer_reset_and_unref(ep->read_buffer); if (ep->leftover_bytes.count) { - size_t leftover_nslices = ep->leftover_bytes.count; - ep->leftover_bytes.count = 0; - on_read(ep, ep->leftover_bytes.slices, leftover_nslices, - GRPC_ENDPOINT_CB_OK); - return; + gpr_slice_buffer_swap(&ep->leftover_bytes, &ep->source_buffer); + GPR_ASSERT(ep->leftover_bytes.count == 0); + return on_read(ep, 1) ? GRPC_ENDPOINT_DONE : GRPC_ENDPOINT_ERROR; } - grpc_endpoint_notify_on_read(ep->wrapped_ep, on_read, ep); + SECURE_ENDPOINT_REF(ep, "read"); + + switch ( + grpc_endpoint_read(ep->wrapped_ep, &ep->source_buffer, &ep->on_read)) { + case GRPC_ENDPOINT_DONE: + immediate_read_success = on_read(ep, 1); + break; + case GRPC_ENDPOINT_PENDING: + return GRPC_ENDPOINT_PENDING; + case GRPC_ENDPOINT_ERROR: + immediate_read_success = on_read(ep, 0); + break; + } + + GPR_ASSERT(immediate_read_success != -1); + SECURE_ENDPOINT_UNREF(ep, "read"); + + return immediate_read_success ? GRPC_ENDPOINT_DONE : GRPC_ENDPOINT_ERROR; } static void flush_write_staging_buffer(secure_endpoint *ep, gpr_uint8 **cur, @@ -211,36 +255,28 @@ static void flush_write_staging_buffer(secure_endpoint *ep, gpr_uint8 **cur, *end = GPR_SLICE_END_PTR(ep->write_staging_buffer); } -static void on_write(void *data, grpc_endpoint_cb_status error) { - secure_endpoint *ep = data; - ep->write_cb(ep->write_user_data, error); - secure_endpoint_unref(ep); -} - -static grpc_endpoint_write_status endpoint_write(grpc_endpoint *secure_ep, - gpr_slice *slices, - size_t nslices, - grpc_endpoint_write_cb cb, - void *user_data) { +static grpc_endpoint_op_status endpoint_write(grpc_endpoint *secure_ep, + gpr_slice_buffer *slices, + grpc_iomgr_closure *cb) { unsigned i; - size_t output_buffer_count = 0; tsi_result result = TSI_OK; secure_endpoint *ep = (secure_endpoint *)secure_ep; gpr_uint8 *cur = GPR_SLICE_START_PTR(ep->write_staging_buffer); gpr_uint8 *end = GPR_SLICE_END_PTR(ep->write_staging_buffer); - grpc_endpoint_write_status status; - GPR_ASSERT(ep->output_buffer.count == 0); + + gpr_slice_buffer_reset_and_unref(&ep->output_buffer); if (grpc_trace_secure_endpoint) { - for (i = 0; i < nslices; i++) { - char *data = gpr_dump_slice(slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII); + for (i = 0; i < slices->count; i++) { + char *data = + gpr_dump_slice(slices->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII); gpr_log(GPR_DEBUG, "WRITE %p: %s", ep, data); gpr_free(data); } } - for (i = 0; i < nslices; i++) { - gpr_slice plain = slices[i]; + for (i = 0; i < slices->count; i++) { + gpr_slice plain = slices->slices[i]; gpr_uint8 *message_bytes = GPR_SLICE_START_PTR(plain); size_t message_size = GPR_SLICE_LENGTH(plain); while (message_size > 0) { @@ -290,29 +326,13 @@ static grpc_endpoint_write_status endpoint_write(grpc_endpoint *secure_ep, } } - for (i = 0; i < nslices; i++) { - gpr_slice_unref(slices[i]); - } - if (result != TSI_OK) { /* TODO(yangg) do different things according to the error type? */ gpr_slice_buffer_reset_and_unref(&ep->output_buffer); - return GRPC_ENDPOINT_WRITE_ERROR; + return GRPC_ENDPOINT_ERROR; } - /* clear output_buffer and let the lower level handle its slices. */ - output_buffer_count = ep->output_buffer.count; - ep->output_buffer.count = 0; - ep->write_cb = cb; - ep->write_user_data = user_data; - /* Need to keep the endpoint alive across a transport */ - secure_endpoint_ref(ep); - status = grpc_endpoint_write(ep->wrapped_ep, ep->output_buffer.slices, - output_buffer_count, on_write, ep); - if (status != GRPC_ENDPOINT_WRITE_PENDING) { - secure_endpoint_unref(ep); - } - return status; + return grpc_endpoint_write(ep->wrapped_ep, &ep->output_buffer, cb); } static void endpoint_shutdown(grpc_endpoint *secure_ep) { @@ -320,9 +340,9 @@ static void endpoint_shutdown(grpc_endpoint *secure_ep) { grpc_endpoint_shutdown(ep->wrapped_ep); } -static void endpoint_unref(grpc_endpoint *secure_ep) { +static void endpoint_destroy(grpc_endpoint *secure_ep) { secure_endpoint *ep = (secure_endpoint *)secure_ep; - secure_endpoint_unref(ep); + SECURE_ENDPOINT_UNREF(ep, "destroy"); } static void endpoint_add_to_pollset(grpc_endpoint *secure_ep, @@ -343,9 +363,9 @@ static char *endpoint_get_peer(grpc_endpoint *secure_ep) { } static const grpc_endpoint_vtable vtable = { - endpoint_notify_on_read, endpoint_write, + endpoint_read, endpoint_write, endpoint_add_to_pollset, endpoint_add_to_pollset_set, - endpoint_shutdown, endpoint_unref, + endpoint_shutdown, endpoint_destroy, endpoint_get_peer}; grpc_endpoint *grpc_secure_endpoint_create( @@ -363,8 +383,10 @@ grpc_endpoint *grpc_secure_endpoint_create( } ep->write_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE); ep->read_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE); - gpr_slice_buffer_init(&ep->input_buffer); gpr_slice_buffer_init(&ep->output_buffer); + gpr_slice_buffer_init(&ep->source_buffer); + ep->read_buffer = NULL; + grpc_iomgr_closure_init(&ep->on_read, on_read_cb, ep); gpr_mu_init(&ep->protector_mu); gpr_ref_init(&ep->ref, 1); return &ep->base; diff --git a/src/core/security/secure_transport_setup.c b/src/core/security/secure_transport_setup.c index 0c3572b53c..bf0079577e 100644 --- a/src/core/security/secure_transport_setup.c +++ b/src/core/security/secure_transport_setup.c @@ -50,16 +50,17 @@ typedef struct { grpc_endpoint *wrapped_endpoint; grpc_endpoint *secure_endpoint; gpr_slice_buffer left_overs; + gpr_slice_buffer incoming; + gpr_slice_buffer outgoing; grpc_secure_transport_setup_done_cb cb; void *user_data; + grpc_iomgr_closure on_handshake_data_sent_to_peer; + grpc_iomgr_closure on_handshake_data_received_from_peer; } grpc_secure_transport_setup; -static void on_handshake_data_received_from_peer(void *setup, gpr_slice *slices, - size_t nslices, - grpc_endpoint_cb_status error); +static void on_handshake_data_received_from_peer(void *setup, int success); -static void on_handshake_data_sent_to_peer(void *setup, - grpc_endpoint_cb_status error); +static void on_handshake_data_sent_to_peer(void *setup, int success); static void secure_transport_setup_done(grpc_secure_transport_setup *s, int is_success) { @@ -78,6 +79,8 @@ static void secure_transport_setup_done(grpc_secure_transport_setup *s, if (s->handshaker != NULL) tsi_handshaker_destroy(s->handshaker); if (s->handshake_buffer != NULL) gpr_free(s->handshake_buffer); gpr_slice_buffer_destroy(&s->left_overs); + gpr_slice_buffer_destroy(&s->outgoing); + gpr_slice_buffer_destroy(&s->incoming); GRPC_SECURITY_CONNECTOR_UNREF(s->connector, "secure_transport_setup"); gpr_free(s); } @@ -102,6 +105,8 @@ static void on_peer_checked(void *user_data, grpc_security_status status) { s->secure_endpoint = grpc_secure_endpoint_create(protector, s->wrapped_endpoint, s->left_overs.slices, s->left_overs.count); + s->left_overs.count = 0; + s->left_overs.length = 0; secure_transport_setup_done(s, 1); return; } @@ -132,7 +137,6 @@ static void send_handshake_bytes_to_peer(grpc_secure_transport_setup *s) { size_t offset = 0; tsi_result result = TSI_OK; gpr_slice to_send; - grpc_endpoint_write_status write_status; do { size_t to_send_size = s->handshake_buffer_size - offset; @@ -155,28 +159,25 @@ static void send_handshake_bytes_to_peer(grpc_secure_transport_setup *s) { to_send = gpr_slice_from_copied_buffer((const char *)s->handshake_buffer, offset); + gpr_slice_buffer_reset_and_unref(&s->outgoing); + gpr_slice_buffer_add(&s->outgoing, to_send); /* TODO(klempner,jboeuf): This should probably use the client setup deadline */ - write_status = grpc_endpoint_write(s->wrapped_endpoint, &to_send, 1, - on_handshake_data_sent_to_peer, s); - if (write_status == GRPC_ENDPOINT_WRITE_ERROR) { - gpr_log(GPR_ERROR, "Could not send handshake data to peer."); - secure_transport_setup_done(s, 0); - } else if (write_status == GRPC_ENDPOINT_WRITE_DONE) { - on_handshake_data_sent_to_peer(s, GRPC_ENDPOINT_CB_OK); - } -} - -static void cleanup_slices(gpr_slice *slices, size_t num_slices) { - size_t i; - for (i = 0; i < num_slices; i++) { - gpr_slice_unref(slices[i]); + switch (grpc_endpoint_write(s->wrapped_endpoint, &s->outgoing, + &s->on_handshake_data_sent_to_peer)) { + case GRPC_ENDPOINT_ERROR: + gpr_log(GPR_ERROR, "Could not send handshake data to peer."); + secure_transport_setup_done(s, 0); + break; + case GRPC_ENDPOINT_DONE: + on_handshake_data_sent_to_peer(s, 1); + break; + case GRPC_ENDPOINT_PENDING: + break; } } -static void on_handshake_data_received_from_peer( - void *setup, gpr_slice *slices, size_t nslices, - grpc_endpoint_cb_status error) { +static void on_handshake_data_received_from_peer(void *setup, int success) { grpc_secure_transport_setup *s = setup; size_t consumed_slice_size = 0; tsi_result result = TSI_OK; @@ -184,32 +185,37 @@ static void on_handshake_data_received_from_peer( size_t num_left_overs; int has_left_overs_in_current_slice = 0; - if (error != GRPC_ENDPOINT_CB_OK) { + if (!success) { gpr_log(GPR_ERROR, "Read failed."); - cleanup_slices(slices, nslices); secure_transport_setup_done(s, 0); return; } - for (i = 0; i < nslices; i++) { - consumed_slice_size = GPR_SLICE_LENGTH(slices[i]); + for (i = 0; i < s->incoming.count; i++) { + consumed_slice_size = GPR_SLICE_LENGTH(s->incoming.slices[i]); result = tsi_handshaker_process_bytes_from_peer( - s->handshaker, GPR_SLICE_START_PTR(slices[i]), &consumed_slice_size); + s->handshaker, GPR_SLICE_START_PTR(s->incoming.slices[i]), + &consumed_slice_size); if (!tsi_handshaker_is_in_progress(s->handshaker)) break; } if (tsi_handshaker_is_in_progress(s->handshaker)) { /* We may need more data. */ if (result == TSI_INCOMPLETE_DATA) { - /* TODO(klempner,jboeuf): This should probably use the client setup - deadline */ - grpc_endpoint_notify_on_read(s->wrapped_endpoint, - on_handshake_data_received_from_peer, setup); - cleanup_slices(slices, nslices); + switch (grpc_endpoint_read(s->wrapped_endpoint, &s->incoming, + &s->on_handshake_data_received_from_peer)) { + case GRPC_ENDPOINT_DONE: + on_handshake_data_received_from_peer(s, 1); + break; + case GRPC_ENDPOINT_ERROR: + on_handshake_data_received_from_peer(s, 0); + break; + case GRPC_ENDPOINT_PENDING: + break; + } return; } else { send_handshake_bytes_to_peer(s); - cleanup_slices(slices, nslices); return; } } @@ -217,42 +223,40 @@ static void on_handshake_data_received_from_peer( if (result != TSI_OK) { gpr_log(GPR_ERROR, "Handshake failed with error %s", tsi_result_to_string(result)); - cleanup_slices(slices, nslices); secure_transport_setup_done(s, 0); return; } /* Handshake is done and successful this point. */ has_left_overs_in_current_slice = - (consumed_slice_size < GPR_SLICE_LENGTH(slices[i])); - num_left_overs = (has_left_overs_in_current_slice ? 1 : 0) + nslices - i - 1; + (consumed_slice_size < GPR_SLICE_LENGTH(s->incoming.slices[i])); + num_left_overs = + (has_left_overs_in_current_slice ? 1 : 0) + s->incoming.count - i - 1; if (num_left_overs == 0) { - cleanup_slices(slices, nslices); check_peer(s); return; } - cleanup_slices(slices, nslices - num_left_overs); - /* Put the leftovers in our buffer (ownership transfered). */ if (has_left_overs_in_current_slice) { - gpr_slice_buffer_add(&s->left_overs, - gpr_slice_split_tail(&slices[i], consumed_slice_size)); - gpr_slice_unref(slices[i]); /* split_tail above increments refcount. */ + gpr_slice_buffer_add( + &s->left_overs, + gpr_slice_split_tail(&s->incoming.slices[i], consumed_slice_size)); + gpr_slice_unref( + s->incoming.slices[i]); /* split_tail above increments refcount. */ } gpr_slice_buffer_addn( - &s->left_overs, &slices[i + 1], + &s->left_overs, &s->incoming.slices[i + 1], num_left_overs - (size_t)has_left_overs_in_current_slice); check_peer(s); } /* If setup is NULL, the setup is done. */ -static void on_handshake_data_sent_to_peer(void *setup, - grpc_endpoint_cb_status error) { +static void on_handshake_data_sent_to_peer(void *setup, int success) { grpc_secure_transport_setup *s = setup; /* Make sure that write is OK. */ - if (error != GRPC_ENDPOINT_CB_OK) { - gpr_log(GPR_ERROR, "Write failed with error %d.", error); + if (!success) { + gpr_log(GPR_ERROR, "Write failed."); if (setup != NULL) secure_transport_setup_done(s, 0); return; } @@ -261,8 +265,17 @@ static void on_handshake_data_sent_to_peer(void *setup, if (tsi_handshaker_is_in_progress(s->handshaker)) { /* TODO(klempner,jboeuf): This should probably use the client setup deadline */ - grpc_endpoint_notify_on_read(s->wrapped_endpoint, - on_handshake_data_received_from_peer, setup); + switch (grpc_endpoint_read(s->wrapped_endpoint, &s->incoming, + &s->on_handshake_data_received_from_peer)) { + case GRPC_ENDPOINT_ERROR: + on_handshake_data_received_from_peer(s, 0); + break; + case GRPC_ENDPOINT_PENDING: + break; + case GRPC_ENDPOINT_DONE: + on_handshake_data_received_from_peer(s, 1); + break; + } } else { check_peer(s); } @@ -288,6 +301,12 @@ void grpc_setup_secure_transport(grpc_security_connector *connector, s->wrapped_endpoint = nonsecure_endpoint; s->user_data = user_data; s->cb = cb; + grpc_iomgr_closure_init(&s->on_handshake_data_sent_to_peer, + on_handshake_data_sent_to_peer, s); + grpc_iomgr_closure_init(&s->on_handshake_data_received_from_peer, + on_handshake_data_received_from_peer, s); gpr_slice_buffer_init(&s->left_overs); + gpr_slice_buffer_init(&s->outgoing); + gpr_slice_buffer_init(&s->incoming); send_handshake_bytes_to_peer(s); } diff --git a/src/core/support/slice_buffer.c b/src/core/support/slice_buffer.c index 987d5cb9b5..6482ef9c9f 100644 --- a/src/core/support/slice_buffer.c +++ b/src/core/support/slice_buffer.c @@ -207,3 +207,25 @@ void gpr_slice_buffer_move_into(gpr_slice_buffer *src, gpr_slice_buffer *dst) { src->count = 0; src->length = 0; } + +void gpr_slice_buffer_trim_end(gpr_slice_buffer *sb, size_t n) { + GPR_ASSERT(n <= sb->length); + sb->length -= n; + for (;;) { + size_t idx = sb->count - 1; + gpr_slice slice = sb->slices[idx]; + size_t slice_len = GPR_SLICE_LENGTH(slice); + if (slice_len > n) { + sb->slices[idx] = gpr_slice_sub_no_ref(slice, 0, slice_len - n); + return; + } else if (slice_len == n) { + gpr_slice_unref(slice); + sb->count = idx; + return; + } else { + gpr_slice_unref(slice); + n -= slice_len; + sb->count = idx; + } + } +} diff --git a/src/core/transport/chttp2/internal.h b/src/core/transport/chttp2/internal.h index 42cf0ecd5b..0e7f94be38 100644 --- a/src/core/transport/chttp2/internal.h +++ b/src/core/transport/chttp2/internal.h @@ -214,6 +214,8 @@ typedef struct { grpc_chttp2_hpack_compressor hpack_compressor; /** is this a client? */ gpr_uint8 is_client; + /** callback for when writing is done */ + grpc_iomgr_closure done_cb; } grpc_chttp2_transport_writing; struct grpc_chttp2_transport_parsing { @@ -331,6 +333,11 @@ struct grpc_chttp2_transport { grpc_iomgr_closure writing_action; /** closure to start reading from the endpoint */ grpc_iomgr_closure reading_action; + /** closure to finish reading from the endpoint */ + grpc_iomgr_closure recv_data; + + /** incoming read bytes */ + gpr_slice_buffer read_buffer; /** address to place a newly accepted stream - set and unset by grpc_chttp2_parsing_accept_stream; used by init_stream to @@ -463,8 +470,7 @@ int grpc_chttp2_unlocking_check_writes(grpc_chttp2_transport_global *global, grpc_chttp2_transport_writing *writing); void grpc_chttp2_perform_writes( grpc_chttp2_transport_writing *transport_writing, grpc_endpoint *endpoint); -void grpc_chttp2_terminate_writing( - grpc_chttp2_transport_writing *transport_writing, int success); +void grpc_chttp2_terminate_writing(void *transport_writing, int success); void grpc_chttp2_cleanup_writing(grpc_chttp2_transport_global *global, grpc_chttp2_transport_writing *writing); diff --git a/src/core/transport/chttp2/writing.c b/src/core/transport/chttp2/writing.c index 123061b3fc..2c8c48f47b 100644 --- a/src/core/transport/chttp2/writing.c +++ b/src/core/transport/chttp2/writing.c @@ -37,7 +37,6 @@ #include static void finalize_outbuf(grpc_chttp2_transport_writing *transport_writing); -static void finish_write_cb(void *tw, grpc_endpoint_cb_status write_status); int grpc_chttp2_unlocking_check_writes( grpc_chttp2_transport_global *transport_global, @@ -165,16 +164,15 @@ void grpc_chttp2_perform_writes( GPR_ASSERT(transport_writing->outbuf.count > 0); GPR_ASSERT(endpoint); - switch (grpc_endpoint_write(endpoint, transport_writing->outbuf.slices, - transport_writing->outbuf.count, finish_write_cb, - transport_writing)) { - case GRPC_ENDPOINT_WRITE_DONE: + switch (grpc_endpoint_write(endpoint, &transport_writing->outbuf, + &transport_writing->done_cb)) { + case GRPC_ENDPOINT_DONE: grpc_chttp2_terminate_writing(transport_writing, 1); break; - case GRPC_ENDPOINT_WRITE_ERROR: + case GRPC_ENDPOINT_ERROR: grpc_chttp2_terminate_writing(transport_writing, 0); break; - case GRPC_ENDPOINT_WRITE_PENDING: + case GRPC_ENDPOINT_PENDING: break; } } @@ -209,12 +207,6 @@ static void finalize_outbuf(grpc_chttp2_transport_writing *transport_writing) { } } -static void finish_write_cb(void *tw, grpc_endpoint_cb_status write_status) { - grpc_chttp2_transport_writing *transport_writing = tw; - grpc_chttp2_terminate_writing(transport_writing, - write_status == GRPC_ENDPOINT_CB_OK); -} - void grpc_chttp2_cleanup_writing( grpc_chttp2_transport_global *transport_global, grpc_chttp2_transport_writing *transport_writing) { @@ -243,6 +235,5 @@ void grpc_chttp2_cleanup_writing( grpc_chttp2_list_add_read_write_state_changed(transport_global, stream_global); } - transport_writing->outbuf.count = 0; - transport_writing->outbuf.length = 0; + gpr_slice_buffer_reset_and_unref(&transport_writing->outbuf); } diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c index 1bbd210e46..3d3d708e2f 100644 --- a/src/core/transport/chttp2_transport.c +++ b/src/core/transport/chttp2_transport.c @@ -91,8 +91,7 @@ static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id, gpr_uint32 value); /** Endpoint callback to process incoming data */ -static void recv_data(void *tp, gpr_slice *slices, size_t nslices, - grpc_endpoint_cb_status error); +static void recv_data(void *tp, int success); /** Start disconnection chain */ static void drop_connection(grpc_chttp2_transport *t); @@ -143,6 +142,7 @@ static void destruct_transport(grpc_chttp2_transport *t) { grpc_chttp2_hpack_compressor_destroy(&t->writing.hpack_compressor); gpr_slice_buffer_destroy(&t->parsing.qbuf); + gpr_slice_buffer_destroy(&t->read_buffer); grpc_chttp2_hpack_parser_destroy(&t->parsing.hpack_parser); grpc_chttp2_goaway_parser_destroy(&t->parsing.goaway_parser); @@ -255,6 +255,11 @@ static void init_transport(grpc_chttp2_transport *t, grpc_chttp2_goaway_parser_init(&t->parsing.goaway_parser); grpc_chttp2_hpack_parser_init(&t->parsing.hpack_parser, t->metadata_context); + grpc_iomgr_closure_init(&t->writing.done_cb, grpc_chttp2_terminate_writing, + &t->writing); + grpc_iomgr_closure_init(&t->recv_data, recv_data, t); + gpr_slice_buffer_init(&t->read_buffer); + if (is_client) { gpr_slice_buffer_add( &t->global.qbuf, @@ -502,8 +507,8 @@ static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id, } } -void grpc_chttp2_terminate_writing( - grpc_chttp2_transport_writing *transport_writing, int success) { +void grpc_chttp2_terminate_writing(void *transport_writing_ptr, int success) { + grpc_chttp2_transport_writing *transport_writing = transport_writing_ptr; grpc_chttp2_transport *t = TRANSPORT_FROM_WRITING(transport_writing); lock(t); @@ -1060,66 +1065,56 @@ static void read_error_locked(grpc_chttp2_transport *t) { } /* tcp read callback */ -static void recv_data(void *tp, gpr_slice *slices, size_t nslices, - grpc_endpoint_cb_status error) { +static void recv_data(void *tp, int success) { grpc_chttp2_transport *t = tp; size_t i; int unref = 0; - switch (error) { - case GRPC_ENDPOINT_CB_SHUTDOWN: - case GRPC_ENDPOINT_CB_EOF: - case GRPC_ENDPOINT_CB_ERROR: - lock(t); + lock(t); + i = 0; + GPR_ASSERT(!t->parsing_active); + if (!t->closed) { + t->parsing_active = 1; + /* merge stream lists */ + grpc_chttp2_stream_map_move_into(&t->new_stream_map, + &t->parsing_stream_map); + grpc_chttp2_prepare_to_read(&t->global, &t->parsing); + gpr_mu_unlock(&t->mu); + for (; i < t->read_buffer.count && + grpc_chttp2_perform_read(&t->parsing, t->read_buffer.slices[i]); + i++) + ; + gpr_mu_lock(&t->mu); + if (i != t->read_buffer.count) { drop_connection(t); - read_error_locked(t); - unlock(t); - unref = 1; - for (i = 0; i < nslices; i++) gpr_slice_unref(slices[i]); - break; - case GRPC_ENDPOINT_CB_OK: - lock(t); - i = 0; - GPR_ASSERT(!t->parsing_active); - if (!t->closed) { - t->parsing_active = 1; - /* merge stream lists */ - grpc_chttp2_stream_map_move_into(&t->new_stream_map, - &t->parsing_stream_map); - grpc_chttp2_prepare_to_read(&t->global, &t->parsing); - gpr_mu_unlock(&t->mu); - for (; i < nslices && grpc_chttp2_perform_read(&t->parsing, slices[i]); - i++) { - gpr_slice_unref(slices[i]); - } - gpr_mu_lock(&t->mu); - if (i != nslices) { - drop_connection(t); - } - /* merge stream lists */ - grpc_chttp2_stream_map_move_into(&t->new_stream_map, - &t->parsing_stream_map); - t->global.concurrent_stream_count = - grpc_chttp2_stream_map_size(&t->parsing_stream_map); - if (t->parsing.initial_window_update != 0) { - grpc_chttp2_stream_map_for_each(&t->parsing_stream_map, - update_global_window, t); - t->parsing.initial_window_update = 0; - } - /* handle higher level things */ - grpc_chttp2_publish_reads(&t->global, &t->parsing); - t->parsing_active = 0; - } - if (i == nslices) { - grpc_chttp2_schedule_closure(&t->global, &t->reading_action, 1); - } else { - read_error_locked(t); - unref = 1; - } - unlock(t); - for (; i < nslices; i++) gpr_slice_unref(slices[i]); - break; + } + /* merge stream lists */ + grpc_chttp2_stream_map_move_into(&t->new_stream_map, + &t->parsing_stream_map); + t->global.concurrent_stream_count = + grpc_chttp2_stream_map_size(&t->parsing_stream_map); + if (t->parsing.initial_window_update != 0) { + grpc_chttp2_stream_map_for_each(&t->parsing_stream_map, + update_global_window, t); + t->parsing.initial_window_update = 0; + } + /* handle higher level things */ + grpc_chttp2_publish_reads(&t->global, &t->parsing); + t->parsing_active = 0; + } + if (!success) { + drop_connection(t); + read_error_locked(t); + unref = 1; + } else if (i == t->read_buffer.count) { + grpc_chttp2_schedule_closure(&t->global, &t->reading_action, 1); + } else { + read_error_locked(t); + unref = 1; } + gpr_slice_buffer_reset_and_unref(&t->read_buffer); + unlock(t); + if (unref) { UNREF_TRANSPORT(t, "recv_data"); } @@ -1127,7 +1122,16 @@ static void recv_data(void *tp, gpr_slice *slices, size_t nslices, static void reading_action(void *pt, int iomgr_success_ignored) { grpc_chttp2_transport *t = pt; - grpc_endpoint_notify_on_read(t->ep, recv_data, t); + switch (grpc_endpoint_read(t->ep, &t->read_buffer, &t->recv_data)) { + case GRPC_ENDPOINT_DONE: + recv_data(t, 1); + break; + case GRPC_ENDPOINT_ERROR: + recv_data(t, 0); + break; + case GRPC_ENDPOINT_PENDING: + break; + } } /* @@ -1240,5 +1244,6 @@ void grpc_chttp2_transport_start_reading(grpc_transport *transport, gpr_slice *slices, size_t nslices) { grpc_chttp2_transport *t = (grpc_chttp2_transport *)transport; REF_TRANSPORT(t, "recv_data"); /* matches unref inside recv_data */ - recv_data(t, slices, nslices, GRPC_ENDPOINT_CB_OK); + gpr_slice_buffer_addn(&t->read_buffer, slices, nslices); + recv_data(t, 1); } diff --git a/test/core/bad_client/bad_client.c b/test/core/bad_client/bad_client.c index 24bf5d3625..1d98879662 100644 --- a/test/core/bad_client/bad_client.c +++ b/test/core/bad_client/bad_client.c @@ -59,7 +59,7 @@ static void thd_func(void *arg) { gpr_event_set(&a->done_thd, (void *)1); } -static void done_write(void *arg, grpc_endpoint_cb_status status) { +static void done_write(void *arg, int success) { thd_args *a = arg; gpr_event_set(&a->done_write, (void *)1); } @@ -85,6 +85,8 @@ void grpc_run_bad_client_test(grpc_bad_client_server_side_validator validator, grpc_mdctx *mdctx = grpc_mdctx_create(); gpr_slice slice = gpr_slice_from_copied_buffer(client_payload, client_payload_length); + gpr_slice_buffer outgoing; + grpc_iomgr_closure done_write_closure; hex = gpr_dump(client_payload, client_payload_length, GPR_DUMP_HEX | GPR_DUMP_ASCII); @@ -122,14 +124,18 @@ void grpc_run_bad_client_test(grpc_bad_client_server_side_validator validator, /* Start validator */ gpr_thd_new(&id, thd_func, &a, NULL); + gpr_slice_buffer_init(&outgoing); + gpr_slice_buffer_add(&outgoing, slice); + grpc_iomgr_closure_init(&done_write_closure, done_write, &a); + /* Write data */ - switch (grpc_endpoint_write(sfd.client, &slice, 1, done_write, &a)) { - case GRPC_ENDPOINT_WRITE_DONE: + switch (grpc_endpoint_write(sfd.client, &outgoing, &done_write_closure)) { + case GRPC_ENDPOINT_DONE: done_write(&a, 1); break; - case GRPC_ENDPOINT_WRITE_PENDING: + case GRPC_ENDPOINT_PENDING: break; - case GRPC_ENDPOINT_WRITE_ERROR: + case GRPC_ENDPOINT_ERROR: done_write(&a, 0); break; } @@ -155,6 +161,7 @@ void grpc_run_bad_client_test(grpc_bad_client_server_side_validator validator, .type == GRPC_OP_COMPLETE); grpc_server_destroy(a.server); grpc_completion_queue_destroy(a.cq); + gpr_slice_buffer_destroy(&outgoing); grpc_shutdown(); } diff --git a/test/core/iomgr/endpoint_tests.c b/test/core/iomgr/endpoint_tests.c index 8186c96da1..b4f170cfbe 100644 --- a/test/core/iomgr/endpoint_tests.c +++ b/test/core/iomgr/endpoint_tests.c @@ -59,8 +59,7 @@ static grpc_pollset *g_pollset; -size_t count_and_unref_slices(gpr_slice *slices, size_t nslices, - int *current_data) { +size_t count_slices(gpr_slice *slices, size_t nslices, int *current_data) { size_t num_bytes = 0; size_t i; size_t j; @@ -72,7 +71,6 @@ size_t count_and_unref_slices(gpr_slice *slices, size_t nslices, *current_data = (*current_data + 1) % 256; } num_bytes += GPR_SLICE_LENGTH(slices[i]); - gpr_slice_unref(slices[i]); } return num_bytes; } @@ -121,86 +119,76 @@ struct read_and_write_test_state { int current_write_data; int read_done; int write_done; + gpr_slice_buffer incoming; + gpr_slice_buffer outgoing; + grpc_iomgr_closure done_read; + grpc_iomgr_closure done_write; }; -static void read_and_write_test_read_handler(void *data, gpr_slice *slices, - size_t nslices, - grpc_endpoint_cb_status error) { +static void read_and_write_test_read_handler(void *data, int success) { struct read_and_write_test_state *state = data; - GPR_ASSERT(error != GRPC_ENDPOINT_CB_ERROR); - if (error == GRPC_ENDPOINT_CB_SHUTDOWN) { - gpr_log(GPR_INFO, "Read handler shutdown"); - gpr_mu_lock(GRPC_POLLSET_MU(g_pollset)); - state->read_done = 1; - grpc_pollset_kick(g_pollset, NULL); - gpr_mu_unlock(GRPC_POLLSET_MU(g_pollset)); - return; - } - state->bytes_read += - count_and_unref_slices(slices, nslices, &state->current_read_data); - if (state->bytes_read == state->target_bytes) { + state->bytes_read += count_slices( + state->incoming.slices, state->incoming.count, &state->current_read_data); + if (state->bytes_read == state->target_bytes || !success) { gpr_log(GPR_INFO, "Read handler done"); gpr_mu_lock(GRPC_POLLSET_MU(g_pollset)); - state->read_done = 1; + state->read_done = 1 + success; grpc_pollset_kick(g_pollset, NULL); gpr_mu_unlock(GRPC_POLLSET_MU(g_pollset)); - } else { - grpc_endpoint_notify_on_read(state->read_ep, - read_and_write_test_read_handler, data); + } else if (success) { + switch (grpc_endpoint_read(state->read_ep, &state->incoming, + &state->done_read)) { + case GRPC_ENDPOINT_ERROR: + read_and_write_test_read_handler(data, 0); + break; + case GRPC_ENDPOINT_DONE: + read_and_write_test_read_handler(data, 1); + break; + case GRPC_ENDPOINT_PENDING: + break; + } } } -static void read_and_write_test_write_handler(void *data, - grpc_endpoint_cb_status error) { +static void read_and_write_test_write_handler(void *data, int success) { struct read_and_write_test_state *state = data; gpr_slice *slices = NULL; size_t nslices; - grpc_endpoint_write_status write_status; - - GPR_ASSERT(error != GRPC_ENDPOINT_CB_ERROR); - - gpr_log(GPR_DEBUG, "%s: error=%d", "read_and_write_test_write_handler", - error); - - if (error == GRPC_ENDPOINT_CB_SHUTDOWN) { - gpr_log(GPR_INFO, "Write handler shutdown"); - gpr_mu_lock(GRPC_POLLSET_MU(g_pollset)); - state->write_done = 1; - grpc_pollset_kick(g_pollset, NULL); - gpr_mu_unlock(GRPC_POLLSET_MU(g_pollset)); - return; - } - - for (;;) { - /* Need to do inline writes until they don't succeed synchronously or we - finish writing */ - state->bytes_written += state->current_write_size; - if (state->target_bytes - state->bytes_written < - state->current_write_size) { - state->current_write_size = state->target_bytes - state->bytes_written; - } - if (state->current_write_size == 0) { - break; - } - - slices = allocate_blocks(state->current_write_size, 8192, &nslices, - &state->current_write_data); - write_status = - grpc_endpoint_write(state->write_ep, slices, nslices, - read_and_write_test_write_handler, state); - gpr_log(GPR_DEBUG, "write_status=%d", write_status); - GPR_ASSERT(write_status != GRPC_ENDPOINT_WRITE_ERROR); - free(slices); - if (write_status == GRPC_ENDPOINT_WRITE_PENDING) { - return; + grpc_endpoint_op_status write_status; + + if (success) { + for (;;) { + /* Need to do inline writes until they don't succeed synchronously or we + finish writing */ + state->bytes_written += state->current_write_size; + if (state->target_bytes - state->bytes_written < + state->current_write_size) { + state->current_write_size = state->target_bytes - state->bytes_written; + } + if (state->current_write_size == 0) { + break; + } + + slices = allocate_blocks(state->current_write_size, 8192, &nslices, + &state->current_write_data); + gpr_slice_buffer_reset_and_unref(&state->outgoing); + gpr_slice_buffer_addn(&state->outgoing, slices, nslices); + write_status = grpc_endpoint_write(state->write_ep, &state->outgoing, + &state->done_write); + gpr_log(GPR_DEBUG, "write_status=%d", write_status); + GPR_ASSERT(write_status != GRPC_ENDPOINT_ERROR); + free(slices); + if (write_status == GRPC_ENDPOINT_PENDING) { + return; + } } + GPR_ASSERT(state->bytes_written == state->target_bytes); } - GPR_ASSERT(state->bytes_written == state->target_bytes); gpr_log(GPR_INFO, "Write handler done"); gpr_mu_lock(GRPC_POLLSET_MU(g_pollset)); - state->write_done = 1; + state->write_done = 1 + success; grpc_pollset_kick(g_pollset, NULL); gpr_mu_unlock(GRPC_POLLSET_MU(g_pollset)); } @@ -234,16 +222,31 @@ static void read_and_write_test(grpc_endpoint_test_config config, state.write_done = 0; state.current_read_data = 0; state.current_write_data = 0; + grpc_iomgr_closure_init(&state.done_read, read_and_write_test_read_handler, + &state); + grpc_iomgr_closure_init(&state.done_write, read_and_write_test_write_handler, + &state); + gpr_slice_buffer_init(&state.outgoing); + gpr_slice_buffer_init(&state.incoming); /* Get started by pretending an initial write completed */ /* NOTE: Sets up initial conditions so we can have the same write handler for the first iteration as for later iterations. It does the right thing even when bytes_written is unsigned. */ state.bytes_written -= state.current_write_size; - read_and_write_test_write_handler(&state, GRPC_ENDPOINT_CB_OK); + read_and_write_test_write_handler(&state, 1); - grpc_endpoint_notify_on_read(state.read_ep, read_and_write_test_read_handler, - &state); + switch ( + grpc_endpoint_read(state.read_ep, &state.incoming, &state.done_read)) { + case GRPC_ENDPOINT_PENDING: + break; + case GRPC_ENDPOINT_ERROR: + read_and_write_test_read_handler(&state, 0); + break; + case GRPC_ENDPOINT_DONE: + read_and_write_test_read_handler(&state, 1); + break; + } if (shutdown) { gpr_log(GPR_DEBUG, "shutdown read"); @@ -262,6 +265,8 @@ static void read_and_write_test(grpc_endpoint_test_config config, grpc_endpoint_destroy(state.read_ep); grpc_endpoint_destroy(state.write_ep); + gpr_slice_buffer_destroy(&state.outgoing); + gpr_slice_buffer_destroy(&state.incoming); end_test(config); } @@ -272,36 +277,40 @@ struct timeout_test_state { typedef struct { int done; grpc_endpoint *ep; + gpr_slice_buffer incoming; + grpc_iomgr_closure done_read; } shutdown_during_write_test_state; -static void shutdown_during_write_test_read_handler( - void *user_data, gpr_slice *slices, size_t nslices, - grpc_endpoint_cb_status error) { - size_t i; +static void shutdown_during_write_test_read_handler(void *user_data, + int success) { shutdown_during_write_test_state *st = user_data; - for (i = 0; i < nslices; i++) { - gpr_slice_unref(slices[i]); - } - - if (error != GRPC_ENDPOINT_CB_OK) { + if (!success) { grpc_endpoint_destroy(st->ep); gpr_mu_lock(GRPC_POLLSET_MU(g_pollset)); - st->done = error; + st->done = 1; grpc_pollset_kick(g_pollset, NULL); gpr_mu_unlock(GRPC_POLLSET_MU(g_pollset)); } else { - grpc_endpoint_notify_on_read( - st->ep, shutdown_during_write_test_read_handler, user_data); + switch (grpc_endpoint_read(st->ep, &st->incoming, &st->done_read)) { + case GRPC_ENDPOINT_PENDING: + break; + case GRPC_ENDPOINT_ERROR: + shutdown_during_write_test_read_handler(user_data, 0); + break; + case GRPC_ENDPOINT_DONE: + shutdown_during_write_test_read_handler(user_data, 1); + break; + } } } -static void shutdown_during_write_test_write_handler( - void *user_data, grpc_endpoint_cb_status error) { +static void shutdown_during_write_test_write_handler(void *user_data, + int success) { shutdown_during_write_test_state *st = user_data; - gpr_log(GPR_INFO, "shutdown_during_write_test_write_handler: error = %d", - error); - if (error == 0) { + gpr_log(GPR_INFO, "shutdown_during_write_test_write_handler: success = %d", + success); + if (success) { /* This happens about 0.5% of the time when run under TSAN, and is entirely legitimate, but means we aren't testing the path we think we are. */ /* TODO(klempner): Change this test to retry the write in that case */ @@ -324,6 +333,8 @@ static void shutdown_during_write_test(grpc_endpoint_test_config config, shutdown_during_write_test_state read_st; shutdown_during_write_test_state write_st; gpr_slice *slices; + gpr_slice_buffer outgoing; + grpc_iomgr_closure done_write; grpc_endpoint_test_fixture f = begin_test(config, "shutdown_during_write_test", slice_size); @@ -334,19 +345,26 @@ static void shutdown_during_write_test(grpc_endpoint_test_config config, read_st.done = 0; write_st.done = 0; - grpc_endpoint_notify_on_read( - read_st.ep, shutdown_during_write_test_read_handler, &read_st); + grpc_iomgr_closure_init(&done_write, shutdown_during_write_test_write_handler, + &write_st); + grpc_iomgr_closure_init(&read_st.done_read, + shutdown_during_write_test_read_handler, &read_st); + gpr_slice_buffer_init(&read_st.incoming); + gpr_slice_buffer_init(&outgoing); + + GPR_ASSERT(grpc_endpoint_read(read_st.ep, &read_st.incoming, + &read_st.done_read) == GRPC_ENDPOINT_PENDING); for (size = 1;; size *= 2) { slices = allocate_blocks(size, 1, &nblocks, ¤t_data); - switch (grpc_endpoint_write(write_st.ep, slices, nblocks, - shutdown_during_write_test_write_handler, - &write_st)) { - case GRPC_ENDPOINT_WRITE_DONE: + gpr_slice_buffer_reset_and_unref(&outgoing); + gpr_slice_buffer_addn(&outgoing, slices, nblocks); + switch (grpc_endpoint_write(write_st.ep, &outgoing, &done_write)) { + case GRPC_ENDPOINT_DONE: break; - case GRPC_ENDPOINT_WRITE_ERROR: + case GRPC_ENDPOINT_ERROR: gpr_log(GPR_ERROR, "error writing"); abort(); - case GRPC_ENDPOINT_WRITE_PENDING: + case GRPC_ENDPOINT_PENDING: grpc_endpoint_shutdown(write_st.ep); deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10); gpr_mu_lock(GRPC_POLLSET_MU(g_pollset)); @@ -365,6 +383,8 @@ static void shutdown_during_write_test(grpc_endpoint_test_config config, } gpr_mu_unlock(GRPC_POLLSET_MU(g_pollset)); gpr_free(slices); + gpr_slice_buffer_destroy(&read_st.incoming); + gpr_slice_buffer_destroy(&outgoing); end_test(config); return; } diff --git a/test/core/iomgr/tcp_posix_test.c b/test/core/iomgr/tcp_posix_test.c index 17a85ceaec..a2e3adcf29 100644 --- a/test/core/iomgr/tcp_posix_test.c +++ b/test/core/iomgr/tcp_posix_test.c @@ -118,10 +118,12 @@ struct read_socket_state { grpc_endpoint *ep; ssize_t read_bytes; ssize_t target_read_bytes; + gpr_slice_buffer incoming; + grpc_iomgr_closure read_cb; }; -static ssize_t count_and_unref_slices(gpr_slice *slices, size_t nslices, - int *current_data) { +static ssize_t count_slices(gpr_slice *slices, size_t nslices, + int *current_data) { ssize_t num_bytes = 0; unsigned i, j; unsigned char *buf; @@ -132,31 +134,41 @@ static ssize_t count_and_unref_slices(gpr_slice *slices, size_t nslices, *current_data = (*current_data + 1) % 256; } num_bytes += GPR_SLICE_LENGTH(slices[i]); - gpr_slice_unref(slices[i]); } return num_bytes; } -static void read_cb(void *user_data, gpr_slice *slices, size_t nslices, - grpc_endpoint_cb_status error) { +static void read_cb(void *user_data, int success) { struct read_socket_state *state = (struct read_socket_state *)user_data; ssize_t read_bytes; int current_data; - GPR_ASSERT(error == GRPC_ENDPOINT_CB_OK); + GPR_ASSERT(success); gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset)); current_data = state->read_bytes % 256; - read_bytes = count_and_unref_slices(slices, nslices, ¤t_data); + read_bytes = count_slices(state->incoming.slices, state->incoming.count, + ¤t_data); state->read_bytes += read_bytes; gpr_log(GPR_INFO, "Read %d bytes of %d", read_bytes, state->target_read_bytes); if (state->read_bytes >= state->target_read_bytes) { - /* empty */ + gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset)); } else { - grpc_endpoint_notify_on_read(state->ep, read_cb, state); + switch (grpc_endpoint_read(state->ep, &state->incoming, &state->read_cb)) { + case GRPC_ENDPOINT_DONE: + gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset)); + read_cb(user_data, 1); + break; + case GRPC_ENDPOINT_ERROR: + gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset)); + read_cb(user_data, 0); + break; + case GRPC_ENDPOINT_PENDING: + gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset)); + break; + } } - gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset)); } /* Write to a socket, then read from it using the grpc_tcp API. */ @@ -181,8 +193,19 @@ static void read_test(ssize_t num_bytes, ssize_t slice_size) { state.ep = ep; state.read_bytes = 0; state.target_read_bytes = written_bytes; + gpr_slice_buffer_init(&state.incoming); + grpc_iomgr_closure_init(&state.read_cb, read_cb, &state); - grpc_endpoint_notify_on_read(ep, read_cb, &state); + switch (grpc_endpoint_read(ep, &state.incoming, &state.read_cb)) { + case GRPC_ENDPOINT_DONE: + read_cb(&state, 1); + break; + case GRPC_ENDPOINT_ERROR: + read_cb(&state, 0); + break; + case GRPC_ENDPOINT_PENDING: + break; + } gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset)); while (state.read_bytes < state.target_read_bytes) { @@ -192,6 +215,7 @@ static void read_test(ssize_t num_bytes, ssize_t slice_size) { GPR_ASSERT(state.read_bytes == state.target_read_bytes); gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset)); + gpr_slice_buffer_destroy(&state.incoming); grpc_endpoint_destroy(ep); } @@ -218,8 +242,19 @@ static void large_read_test(ssize_t slice_size) { state.ep = ep; state.read_bytes = 0; state.target_read_bytes = written_bytes; + gpr_slice_buffer_init(&state.incoming); + grpc_iomgr_closure_init(&state.read_cb, read_cb, &state); - grpc_endpoint_notify_on_read(ep, read_cb, &state); + switch (grpc_endpoint_read(ep, &state.incoming, &state.read_cb)) { + case GRPC_ENDPOINT_DONE: + read_cb(&state, 1); + break; + case GRPC_ENDPOINT_ERROR: + read_cb(&state, 0); + break; + case GRPC_ENDPOINT_PENDING: + break; + } gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset)); while (state.read_bytes < state.target_read_bytes) { @@ -229,6 +264,7 @@ static void large_read_test(ssize_t slice_size) { GPR_ASSERT(state.read_bytes == state.target_read_bytes); gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset)); + gpr_slice_buffer_destroy(&state.incoming); grpc_endpoint_destroy(ep); } @@ -260,8 +296,7 @@ static gpr_slice *allocate_blocks(ssize_t num_bytes, ssize_t slice_size, return slices; } -static void write_done(void *user_data /* write_socket_state */, - grpc_endpoint_cb_status error) { +static void write_done(void *user_data /* write_socket_state */, int success) { struct write_socket_state *state = (struct write_socket_state *)user_data; gpr_log(GPR_INFO, "Write done callback called"); gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset)); @@ -336,6 +371,8 @@ static void write_test(ssize_t num_bytes, ssize_t slice_size) { size_t num_blocks; gpr_slice *slices; int current_data = 0; + gpr_slice_buffer outgoing; + grpc_iomgr_closure write_done_closure; gpr_timespec deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(20); gpr_log(GPR_INFO, "Start write test with %d bytes, slice size %d", num_bytes, @@ -352,73 +389,21 @@ static void write_test(ssize_t num_bytes, ssize_t slice_size) { slices = allocate_blocks(num_bytes, slice_size, &num_blocks, ¤t_data); - if (grpc_endpoint_write(ep, slices, num_blocks, write_done, &state) == - GRPC_ENDPOINT_WRITE_DONE) { - /* Write completed immediately */ - read_bytes = drain_socket(sv[0]); - GPR_ASSERT(read_bytes == num_bytes); - } else { - drain_socket_blocking(sv[0], num_bytes, num_bytes); - gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset)); - for (;;) { - grpc_pollset_worker worker; - if (state.write_done) { - break; - } - grpc_pollset_work(&g_pollset, &worker, deadline); - } - gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset)); - } - - grpc_endpoint_destroy(ep); - gpr_free(slices); -} - -static void read_done_for_write_error(void *ud, gpr_slice *slices, - size_t nslices, - grpc_endpoint_cb_status error) { - GPR_ASSERT(error != GRPC_ENDPOINT_CB_OK); - GPR_ASSERT(nslices == 0); -} - -/* Write to a socket using the grpc_tcp API, then drain it directly. - Note that if the write does not complete immediately we need to drain the - socket in parallel with the read. */ -static void write_error_test(ssize_t num_bytes, ssize_t slice_size) { - int sv[2]; - grpc_endpoint *ep; - struct write_socket_state state; - size_t num_blocks; - gpr_slice *slices; - int current_data = 0; - grpc_pollset_worker worker; - gpr_timespec deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(20); - - gpr_log(GPR_INFO, "Start write error test with %d bytes, slice size %d", - num_bytes, slice_size); - - create_sockets(sv); + gpr_slice_buffer_init(&outgoing); + gpr_slice_buffer_addn(&outgoing, slices, num_blocks); + grpc_iomgr_closure_init(&write_done_closure, write_done, &state); - ep = grpc_tcp_create(grpc_fd_create(sv[1], "write_error_test"), - GRPC_TCP_DEFAULT_READ_SLICE_SIZE, "test"); - grpc_endpoint_add_to_pollset(ep, &g_pollset); - - close(sv[0]); - - state.ep = ep; - state.write_done = 0; - - slices = allocate_blocks(num_bytes, slice_size, &num_blocks, ¤t_data); - - switch (grpc_endpoint_write(ep, slices, num_blocks, write_done, &state)) { - case GRPC_ENDPOINT_WRITE_DONE: - case GRPC_ENDPOINT_WRITE_ERROR: + switch (grpc_endpoint_write(ep, &outgoing, &write_done_closure)) { + case GRPC_ENDPOINT_DONE: /* Write completed immediately */ + read_bytes = drain_socket(sv[0]); + GPR_ASSERT(read_bytes == num_bytes); break; - case GRPC_ENDPOINT_WRITE_PENDING: - grpc_endpoint_notify_on_read(ep, read_done_for_write_error, NULL); + case GRPC_ENDPOINT_PENDING: + drain_socket_blocking(sv[0], num_bytes, num_bytes); gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset)); for (;;) { + grpc_pollset_worker worker; if (state.write_done) { break; } @@ -426,10 +411,14 @@ static void write_error_test(ssize_t num_bytes, ssize_t slice_size) { } gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset)); break; + case GRPC_ENDPOINT_ERROR: + gpr_log(GPR_ERROR, "endpoint got error"); + abort(); } + gpr_slice_buffer_destroy(&outgoing); grpc_endpoint_destroy(ep); - free(slices); + gpr_free(slices); } void run_tests(void) { @@ -448,10 +437,6 @@ void run_tests(void) { write_test(100000, 1); write_test(100000, 137); - for (i = 1; i < 1000; i = GPR_MAX(i + 1, i * 5 / 4)) { - write_error_test(40320, i); - } - for (i = 1; i < 1000; i = GPR_MAX(i + 1, i * 5 / 4)) { write_test(40320, i); } diff --git a/test/core/security/secure_endpoint_test.c b/test/core/security/secure_endpoint_test.c index a8368fc842..c76ddcd194 100644 --- a/test/core/security/secure_endpoint_test.c +++ b/test/core/security/secure_endpoint_test.c @@ -135,62 +135,26 @@ static grpc_endpoint_test_config configs[] = { secure_endpoint_create_fixture_tcp_socketpair_leftover, clean_up}, }; -static void verify_leftover(void *user_data, gpr_slice *slices, size_t nslices, - grpc_endpoint_cb_status error) { - gpr_slice s = - gpr_slice_from_copied_string("hello world 12345678900987654321"); - - GPR_ASSERT(error == GRPC_ENDPOINT_CB_OK); - GPR_ASSERT(nslices == 1); - - GPR_ASSERT(0 == gpr_slice_cmp(s, slices[0])); - gpr_slice_unref(slices[0]); - gpr_slice_unref(s); - *(int *)user_data = 1; -} - static void test_leftover(grpc_endpoint_test_config config, size_t slice_size) { grpc_endpoint_test_fixture f = config.create_fixture(slice_size); - int verified = 0; + gpr_slice_buffer incoming; + gpr_slice s = + gpr_slice_from_copied_string("hello world 12345678900987654321"); gpr_log(GPR_INFO, "Start test left over"); - grpc_endpoint_notify_on_read(f.client_ep, verify_leftover, &verified); - GPR_ASSERT(verified == 1); + gpr_slice_buffer_init(&incoming); + GPR_ASSERT(grpc_endpoint_read(f.client_ep, &incoming, NULL) == + GRPC_ENDPOINT_DONE); + GPR_ASSERT(incoming.count == 1); + GPR_ASSERT(0 == gpr_slice_cmp(s, incoming.slices[0])); grpc_endpoint_shutdown(f.client_ep); grpc_endpoint_shutdown(f.server_ep); grpc_endpoint_destroy(f.client_ep); grpc_endpoint_destroy(f.server_ep); - clean_up(); -} - -static void destroy_early(void *user_data, gpr_slice *slices, size_t nslices, - grpc_endpoint_cb_status error) { - grpc_endpoint_test_fixture *f = user_data; - gpr_slice s = - gpr_slice_from_copied_string("hello world 12345678900987654321"); - - GPR_ASSERT(error == GRPC_ENDPOINT_CB_OK); - GPR_ASSERT(nslices == 1); - - grpc_endpoint_shutdown(f->client_ep); - grpc_endpoint_destroy(f->client_ep); - - GPR_ASSERT(0 == gpr_slice_cmp(s, slices[0])); - gpr_slice_unref(slices[0]); gpr_slice_unref(s); -} + gpr_slice_buffer_destroy(&incoming); -/* test which destroys the ep before finishing reading */ -static void test_destroy_ep_early(grpc_endpoint_test_config config, - size_t slice_size) { - grpc_endpoint_test_fixture f = config.create_fixture(slice_size); - gpr_log(GPR_INFO, "Start test destroy early"); - - grpc_endpoint_notify_on_read(f.client_ep, destroy_early, &f); - - grpc_endpoint_shutdown(f.server_ep); - grpc_endpoint_destroy(f.server_ep); clean_up(); } @@ -203,7 +167,6 @@ int main(int argc, char **argv) { grpc_pollset_init(&g_pollset); grpc_endpoint_tests(configs[0], &g_pollset); test_leftover(configs[1], 1); - test_destroy_ep_early(configs[1], 1); grpc_pollset_shutdown(&g_pollset, destroy_pollset, &g_pollset); grpc_iomgr_shutdown(); -- cgit v1.2.3 From a0f149e8732c58241795ba6ea198819e359437d2 Mon Sep 17 00:00:00 2001 From: Hongyu Chen Date: Mon, 24 Aug 2015 16:27:19 -0700 Subject: Move core/profiling/timers_preciseclock.h to core/support/ such that we have a gpr public function which returns cycle clock. --- BUILD | 5 +- build.json | 4 +- gRPC.podspec | 4 +- include/grpc/support/time.h | 3 + src/core/profiling/basic_timers.c | 9 +- src/core/profiling/timers_preciseclock.h | 95 ---------------------- src/core/support/time_posix.c | 14 +++- src/core/support/time_precise.h | 94 +++++++++++++++++++++ src/core/support/time_win32.c | 4 + tools/doxygen/Doxyfile.core.internal | 2 +- tools/run_tests/sources_and_headers.json | 8 +- tools/run_tests/tests.json | 1 + vsprojects/gpr/gpr.vcxproj | 1 + vsprojects/gpr/gpr.vcxproj.filters | 3 + vsprojects/grpc/grpc.vcxproj | 1 - vsprojects/grpc/grpc.vcxproj.filters | 3 - vsprojects/grpc_unsecure/grpc_unsecure.vcxproj | 1 - .../grpc_unsecure/grpc_unsecure.vcxproj.filters | 3 - 18 files changed, 132 insertions(+), 123 deletions(-) delete mode 100644 src/core/profiling/timers_preciseclock.h create mode 100644 src/core/support/time_precise.h (limited to 'include') diff --git a/BUILD b/BUILD index 7eb59797d4..3ba9a6f050 100644 --- a/BUILD +++ b/BUILD @@ -51,6 +51,7 @@ cc_library( "src/core/support/string.h", "src/core/support/string_win32.h", "src/core/support/thd_internal.h", + "src/core/support/time_precise.h", "src/core/support/alloc.c", "src/core/support/cmdline.c", "src/core/support/cpu_iphone.c", @@ -208,7 +209,6 @@ cc_library( "src/core/json/json_reader.h", "src/core/json/json_writer.h", "src/core/profiling/timers.h", - "src/core/profiling/timers_preciseclock.h", "src/core/surface/byte_buffer_queue.h", "src/core/surface/call.h", "src/core/surface/channel.h", @@ -474,7 +474,6 @@ cc_library( "src/core/json/json_reader.h", "src/core/json/json_writer.h", "src/core/profiling/timers.h", - "src/core/profiling/timers_preciseclock.h", "src/core/surface/byte_buffer_queue.h", "src/core/surface/call.h", "src/core/surface/channel.h", @@ -982,6 +981,7 @@ objc_library( "src/core/support/string.h", "src/core/support/string_win32.h", "src/core/support/thd_internal.h", + "src/core/support/time_precise.h", ], includes = [ "include", @@ -1221,7 +1221,6 @@ objc_library( "src/core/json/json_reader.h", "src/core/json/json_writer.h", "src/core/profiling/timers.h", - "src/core/profiling/timers_preciseclock.h", "src/core/surface/byte_buffer_queue.h", "src/core/surface/call.h", "src/core/surface/channel.h", diff --git a/build.json b/build.json index bd707d2e34..d9ebce9099 100644 --- a/build.json +++ b/build.json @@ -179,7 +179,6 @@ "src/core/json/json_reader.h", "src/core/json/json_writer.h", "src/core/profiling/timers.h", - "src/core/profiling/timers_preciseclock.h", "src/core/surface/byte_buffer_queue.h", "src/core/surface/call.h", "src/core/surface/channel.h", @@ -399,7 +398,8 @@ "src/core/support/stack_lockfree.h", "src/core/support/string.h", "src/core/support/string_win32.h", - "src/core/support/thd_internal.h" + "src/core/support/thd_internal.h", + "src/core/support/time_precise.h" ], "src": [ "src/core/support/alloc.c", diff --git a/gRPC.podspec b/gRPC.podspec index d945c299b5..df0ba6d1ac 100644 --- a/gRPC.podspec +++ b/gRPC.podspec @@ -68,6 +68,7 @@ Pod::Spec.new do |s| 'src/core/support/grpc_string.h', 'src/core/support/string_win32.h', 'src/core/support/thd_internal.h', + 'src/core/support/time_precise.h', 'grpc/support/alloc.h', 'grpc/support/atm.h', 'grpc/support/atm_gcc_atomic.h', @@ -210,7 +211,6 @@ Pod::Spec.new do |s| 'src/core/json/json_reader.h', 'src/core/json/json_writer.h', 'src/core/profiling/timers.h', - 'src/core/profiling/timers_preciseclock.h', 'src/core/surface/byte_buffer_queue.h', 'src/core/surface/call.h', 'src/core/surface/channel.h', @@ -401,6 +401,7 @@ Pod::Spec.new do |s| 'src/core/support/string.h', 'src/core/support/string_win32.h', 'src/core/support/thd_internal.h', + 'src/core/support/time_precise.h', 'src/core/security/auth_filters.h', 'src/core/security/base64.h', 'src/core/security/credentials.h', @@ -479,7 +480,6 @@ Pod::Spec.new do |s| 'src/core/json/json_reader.h', 'src/core/json/json_writer.h', 'src/core/profiling/timers.h', - 'src/core/profiling/timers_preciseclock.h', 'src/core/surface/byte_buffer_queue.h', 'src/core/surface/call.h', 'src/core/surface/channel.h', diff --git a/include/grpc/support/time.h b/include/grpc/support/time.h index 4ef9c76459..f8ed893bc0 100644 --- a/include/grpc/support/time.h +++ b/include/grpc/support/time.h @@ -52,6 +52,9 @@ typedef enum { /* Realtime clock. May jump forwards or backwards. Settable by the system administrator. Has its epoch at 0:00:00 UTC 1 Jan 1970. */ GPR_CLOCK_REALTIME, + /* CPU cycle time obtained by rdtsc instruction on x86 platforms. Epoch + undefined. Degrades to GPR_CLOCK_REALTIME on other platforms. */ + GPR_CLOCK_PRECISE, /* Unmeasurable clock type: no base, created by taking the difference between two times */ GPR_TIMESPAN diff --git a/src/core/profiling/basic_timers.c b/src/core/profiling/basic_timers.c index ae37f584eb..9892a16120 100644 --- a/src/core/profiling/basic_timers.c +++ b/src/core/profiling/basic_timers.c @@ -53,7 +53,7 @@ typedef enum { } marker_type; typedef struct grpc_timer_entry { - grpc_precise_clock tm; + gpr_timespec tm; int tag; const char* tagstr; marker_type type; @@ -71,9 +71,8 @@ static void log_report() { int i; for (i = 0; i < count; i++) { grpc_timer_entry* entry = &(log[i]); - printf("GRPC_LAT_PROF " GRPC_PRECISE_CLOCK_FORMAT - " %p %c %d(%s) %p %s %d\n", - GRPC_PRECISE_CLOCK_PRINTF_ARGS(&entry->tm), + printf("GRPC_LAT_PROF %ld.%09d %p %c %d(%s) %p %s %d\n", + entry->tm.tv_sec, entry->tm.tv_nsec, (void*)(gpr_intptr)gpr_thd_currentid(), entry->type, entry->tag, entry->tagstr, entry->id, entry->file, entry->line); } @@ -93,7 +92,7 @@ static void grpc_timers_log_add(int tag, const char* tagstr, marker_type type, entry = &log[count++]; - grpc_precise_clock_now(&entry->tm); + entry->tm = gpr_now(GPR_CLOCK_PRECISE); entry->tag = tag; entry->tagstr = tagstr; entry->type = type; diff --git a/src/core/profiling/timers_preciseclock.h b/src/core/profiling/timers_preciseclock.h deleted file mode 100644 index 5c251b47e6..0000000000 --- a/src/core/profiling/timers_preciseclock.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef GRPC_CORE_PROFILING_TIMERS_PRECISECLOCK_H -#define GRPC_CORE_PROFILING_TIMERS_PRECISECLOCK_H - -#include -#include -#include - -#ifdef GRPC_TIMERS_RDTSC -typedef long long int grpc_precise_clock; -#if defined(__i386__) -static void grpc_precise_clock_now(grpc_precise_clock *clk) { - grpc_precise_clock ret; - __asm__ volatile("rdtsc" : "=A"(ret)); - *clk = ret; -} - -// ---------------------------------------------------------------- -#elif defined(__x86_64__) || defined(__amd64__) -static void grpc_precise_clock_now(grpc_precise_clock *clk) { - unsigned long long low, high; - __asm__ volatile("rdtsc" : "=a"(low), "=d"(high)); - *clk = (high << 32) | low; -} -#endif -static gpr_once precise_clock_init = GPR_ONCE_INIT; -static double cycles_per_second = 0.0; -static void grpc_precise_clock_init() { - time_t start = time(NULL); - grpc_precise_clock start_time; - grpc_precise_clock end_time; - while (time(NULL) == start) - ; - grpc_precise_clock_now(&start_time); - while (time(NULL) == start + 1) - ; - grpc_precise_clock_now(&end_time); - cycles_per_second = end_time - start_time; -} -static double grpc_precise_clock_scaling_factor() { - gpr_once_init(&precise_clock_init, grpc_precise_clock_init); - return 1e6 / cycles_per_second; -} -#define GRPC_PRECISE_CLOCK_FORMAT "%f" -#define GRPC_PRECISE_CLOCK_PRINTF_ARGS(clk) \ - (*(clk)*grpc_precise_clock_scaling_factor()) -#else -typedef struct grpc_precise_clock grpc_precise_clock; -struct grpc_precise_clock { - gpr_timespec clock; -}; -static void grpc_precise_clock_now(grpc_precise_clock* clk) { - clk->clock = gpr_now(GPR_CLOCK_REALTIME); -} -#define GRPC_PRECISE_CLOCK_FORMAT "%ld.%09d" -#define GRPC_PRECISE_CLOCK_PRINTF_ARGS(clk) \ - (clk)->clock.tv_sec, (clk)->clock.tv_nsec -static void grpc_precise_clock_print(const grpc_precise_clock* clk, FILE* fp) { - fprintf(fp, "%ld.%09d", clk->clock.tv_sec, clk->clock.tv_nsec); -} -#endif /* GRPC_TIMERS_RDTSC */ - -#endif /* GRPC_CORE_PROFILING_TIMERS_PRECISECLOCK_H */ diff --git a/src/core/support/time_posix.c b/src/core/support/time_posix.c index 841485c4b4..a274400243 100644 --- a/src/core/support/time_posix.c +++ b/src/core/support/time_posix.c @@ -32,6 +32,7 @@ */ #include +#include #ifdef GPR_POSIX_TIME @@ -66,8 +67,14 @@ void gpr_time_init(void) {} gpr_timespec gpr_now(gpr_clock_type clock) { struct timespec now; GPR_ASSERT(clock != GPR_TIMESPAN); - clock_gettime(clockid_for_gpr_clock[clock], &now); - return gpr_from_timespec(now, clock); + if (clock == GPR_CLOCK_PRECISE) { + gpr_timespec ret; + gpr_precise_clock_now(&ret); + return ret; + } else { + clock_gettime(clockid_for_gpr_clock[clock], &now); + return gpr_from_timespec(now, clock); + } } #else /* For some reason Apple's OSes haven't implemented clock_gettime. */ @@ -104,6 +111,9 @@ gpr_timespec gpr_now(gpr_clock_type clock) { now.tv_sec = now_dbl * 1e-9; now.tv_nsec = now_dbl - now.tv_sec * 1e9; break; + case GPR_CLOCK_PRECISE: + gpr_precise_clock_now(&now); + break; case GPR_TIMESPAN: abort(); } diff --git a/src/core/support/time_precise.h b/src/core/support/time_precise.h new file mode 100644 index 0000000000..d40ad12d0c --- /dev/null +++ b/src/core/support/time_precise.h @@ -0,0 +1,94 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef GRPC_CORE_SUPPORT_TIME_PRECISE_H_ +#define GRPC_CORE_SUPPORT_TIME_PRECISE_H_ + +#include +#include +#include + +#ifdef GRPC_TIMERS_RDTSC +#if defined(__i386__) +static void gpr_get_cycle_counter(long long int *clk) { + long long int ret; + __asm__ volatile("rdtsc" : "=A"(ret)); + *clk = ret; +} + +// ---------------------------------------------------------------- +#elif defined(__x86_64__) || defined(__amd64__) +static void gpr_get_cycle_counter(long long int *clk) { + unsigned long long low, high; + __asm__ volatile("rdtsc" : "=a"(low), "=d"(high)); + *clk = (high << 32) | low; +} +#endif + +static gpr_once precise_clock_init = GPR_ONCE_INIT; +static long long cycles_per_second = 0; +static void gpr_precise_clock_init() { + time_t start = time(NULL); + gpr_precise_clock start_cycle; + gpr_precise_clock end_cycle; + while (time(NULL) == start) + ; + gpr_precise_clock_now(); + gpr_get_cycle_counter(&start_cycle); + while (time(NULL) == start + 1) + ; + gpr_get_cycle_counter(&end_cycle); + cycles_per_second = end_cycle - start_cycle; +} + +static double grpc_precise_clock_scaling_factor() { + gpr_once_init(&precise_clock_init, grpc_precise_clock_init); + return 1e6 / cycles_per_second; +} + +static void gpr_precise_clock_now(gpr_timespec *clk) { + long long int counter; + gpr_get_cycle_counter(&counter); + clk->clock = GPR_CLOCK_REALTIME; + clk->tv_sec = counter / cycles_per_second; + clk->tv_nsec = counter % cycles_per_second; +} + +#else /* GRPC_TIMERS_RDTSC */ +static void gpr_precise_clock_now(gpr_timespec *clk) { + *clk = gpr_now(GPR_CLOCK_REALTIME); + clk->clock_type = GPR_CLOCK_PRECISE; +} +#endif /* GRPC_TIMERS_RDTSC */ + +#endif /* GRPC_CORE_SUPPORT_TIME_PRECISE_ */ diff --git a/src/core/support/time_win32.c b/src/core/support/time_win32.c index 7f64c80e27..f794855429 100644 --- a/src/core/support/time_win32.c +++ b/src/core/support/time_win32.c @@ -38,6 +38,7 @@ #ifdef GPR_WIN32 #include +#include #include static LARGE_INTEGER g_start_time; @@ -68,6 +69,9 @@ gpr_timespec gpr_now(gpr_clock_type clock) { now_tv.tv_sec = (time_t)now_dbl; now_tv.tv_nsec = (int)((now_dbl - (double)now_tv.tv_sec) * 1e9); break; + case GPR_CLOCK_PRECISE: + gpr_precise_clock_now(&now_tv); + break; } return now_tv; } diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index 325a293e04..97f38057d0 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -845,7 +845,6 @@ src/core/json/json_common.h \ src/core/json/json_reader.h \ src/core/json/json_writer.h \ src/core/profiling/timers.h \ -src/core/profiling/timers_preciseclock.h \ src/core/surface/byte_buffer_queue.h \ src/core/surface/call.h \ src/core/surface/channel.h \ @@ -1055,6 +1054,7 @@ src/core/support/stack_lockfree.h \ src/core/support/string.h \ src/core/support/string_win32.h \ src/core/support/thd_internal.h \ +src/core/support/time_precise.h \ src/core/support/alloc.c \ src/core/support/cmdline.c \ src/core/support/cpu_iphone.c \ diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json index 50f078586d..de2d8699d1 100644 --- a/tools/run_tests/sources_and_headers.json +++ b/tools/run_tests/sources_and_headers.json @@ -12165,7 +12165,8 @@ "src/core/support/stack_lockfree.h", "src/core/support/string.h", "src/core/support/string_win32.h", - "src/core/support/thd_internal.h" + "src/core/support/thd_internal.h", + "src/core/support/time_precise.h" ], "language": "c", "name": "gpr", @@ -12239,6 +12240,7 @@ "src/core/support/thd_win32.c", "src/core/support/time.c", "src/core/support/time_posix.c", + "src/core/support/time_precise.h", "src/core/support/time_win32.c", "src/core/support/tls_pthread.c" ] @@ -12336,7 +12338,6 @@ "src/core/json/json_reader.h", "src/core/json/json_writer.h", "src/core/profiling/timers.h", - "src/core/profiling/timers_preciseclock.h", "src/core/security/auth_filters.h", "src/core/security/base64.h", "src/core/security/credentials.h", @@ -12536,7 +12537,6 @@ "src/core/profiling/basic_timers.c", "src/core/profiling/stap_timers.c", "src/core/profiling/timers.h", - "src/core/profiling/timers_preciseclock.h", "src/core/security/auth_filters.h", "src/core/security/base64.c", "src/core/security/base64.h", @@ -12810,7 +12810,6 @@ "src/core/json/json_reader.h", "src/core/json/json_writer.h", "src/core/profiling/timers.h", - "src/core/profiling/timers_preciseclock.h", "src/core/surface/byte_buffer_queue.h", "src/core/surface/call.h", "src/core/surface/channel.h", @@ -12995,7 +12994,6 @@ "src/core/profiling/basic_timers.c", "src/core/profiling/stap_timers.c", "src/core/profiling/timers.h", - "src/core/profiling/timers_preciseclock.h", "src/core/surface/byte_buffer.c", "src/core/surface/byte_buffer_queue.c", "src/core/surface/byte_buffer_queue.h", diff --git a/tools/run_tests/tests.json b/tools/run_tests/tests.json index 6c06d74834..127b1dfc40 100644 --- a/tools/run_tests/tests.json +++ b/tools/run_tests/tests.json @@ -1538,6 +1538,7 @@ "posix", "windows" ], + "exclude_configs": [], "flaky": false, "language": "c++", "name": "status_test", diff --git a/vsprojects/gpr/gpr.vcxproj b/vsprojects/gpr/gpr.vcxproj index 83c295625d..3f8f554fd3 100644 --- a/vsprojects/gpr/gpr.vcxproj +++ b/vsprojects/gpr/gpr.vcxproj @@ -158,6 +158,7 @@ + diff --git a/vsprojects/gpr/gpr.vcxproj.filters b/vsprojects/gpr/gpr.vcxproj.filters index 64b90924ab..b6ac061e05 100644 --- a/vsprojects/gpr/gpr.vcxproj.filters +++ b/vsprojects/gpr/gpr.vcxproj.filters @@ -218,6 +218,9 @@ src\core\support + + src\core\support + diff --git a/vsprojects/grpc/grpc.vcxproj b/vsprojects/grpc/grpc.vcxproj index ebdc926ee7..efb3882cad 100644 --- a/vsprojects/grpc/grpc.vcxproj +++ b/vsprojects/grpc/grpc.vcxproj @@ -307,7 +307,6 @@ - diff --git a/vsprojects/grpc/grpc.vcxproj.filters b/vsprojects/grpc/grpc.vcxproj.filters index baec0db4f9..45d73b467a 100644 --- a/vsprojects/grpc/grpc.vcxproj.filters +++ b/vsprojects/grpc/grpc.vcxproj.filters @@ -677,9 +677,6 @@ src\core\profiling - - src\core\profiling - src\core\surface diff --git a/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj index 1d60839b70..3b93092ece 100644 --- a/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj +++ b/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj @@ -290,7 +290,6 @@ - diff --git a/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj.filters index cb9e8c2741..9166acd4ff 100644 --- a/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj.filters +++ b/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj.filters @@ -575,9 +575,6 @@ src\core\profiling - - src\core\profiling - src\core\surface -- cgit v1.2.3 From 775ec1decd597d9ecdf916e3d220b44283075ed9 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 25 Aug 2015 11:03:53 -0700 Subject: Use SSL override as a default host name if none is specified --- include/grpc/grpc.h | 8 ++++++++ include/grpc/grpc_security.h | 9 --------- src/core/surface/channel.c | 19 +++++++++++++++++++ 3 files changed, 27 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h index 101fc88d8f..145052b6d3 100644 --- a/include/grpc/grpc.h +++ b/include/grpc/grpc.h @@ -134,6 +134,14 @@ typedef struct { /** Secondary user agent: goes at the end of the user-agent metadata sent on each request */ #define GRPC_ARG_SECONDARY_USER_AGENT_STRING "grpc.secondary_user_agent" +/* The caller of the secure_channel_create functions may override the target + name used for SSL host name checking using this channel argument which is of + type GRPC_ARG_STRING. This *should* be used for testing only. + If this argument is not specified, the name used for SSL host name checking + will be the target parameter (assuming that the secure channel is an SSL + channel). If this parameter is specified and the underlying is not an SSL + channel, it will just be ignored. */ +#define GRPC_SSL_TARGET_NAME_OVERRIDE_ARG "grpc.ssl_target_name_override" /** Connectivity state of a channel. */ typedef enum { diff --git a/include/grpc/grpc_security.h b/include/grpc/grpc_security.h index 7f8f4d4a05..de565b2d2f 100644 --- a/include/grpc/grpc_security.h +++ b/include/grpc/grpc_security.h @@ -142,15 +142,6 @@ grpc_credentials *grpc_iam_credentials_create(const char *authorization_token, /* --- Secure channel creation. --- */ -/* The caller of the secure_channel_create functions may override the target - name used for SSL host name checking using this channel argument which is of - type GRPC_ARG_STRING. This *should* be used for testing only. - If this argument is not specified, the name used for SSL host name checking - will be the target parameter (assuming that the secure channel is an SSL - channel). If this parameter is specified and the underlying is not an SSL - channel, it will just be ignored. */ -#define GRPC_SSL_TARGET_NAME_OVERRIDE_ARG "grpc.ssl_target_name_override" - /* Creates a secure channel using the passed-in credentials. */ grpc_channel *grpc_secure_channel_create(grpc_credentials *creds, const char *target, diff --git a/src/core/surface/channel.c b/src/core/surface/channel.c index 78eeed1f59..586402e21c 100644 --- a/src/core/surface/channel.c +++ b/src/core/surface/channel.c @@ -141,9 +141,28 @@ grpc_channel *grpc_channel_create_from_filters( gpr_log(GPR_ERROR, "%s: must be an string", GRPC_ARG_DEFAULT_AUTHORITY); } else { + if (channel->default_authority) { + /* setting this takes precedence over anything else */ + GRPC_MDELEM_UNREF(channel->default_authority); + } channel->default_authority = grpc_mdelem_from_strings( mdctx, ":authority", args->args[i].value.string); } + } else if (0 == + strcmp(args->args[i].key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG)) { + if (args->args[i].type != GRPC_ARG_STRING) { + gpr_log(GPR_ERROR, "%s: must be an string", + GRPC_SSL_TARGET_NAME_OVERRIDE_ARG); + } else { + if (channel->default_authority) { + /* other ways of setting this (notably ssl) take precedence */ + gpr_log(GPR_ERROR, "%s: default host already set some other way", + GRPC_ARG_DEFAULT_AUTHORITY); + } else { + channel->default_authority = grpc_mdelem_from_strings( + mdctx, ":authority", args->args[i].value.string); + } + } } } } -- cgit v1.2.3 From d5539ec6e28c275eeb71afaf9bcc5d91a4410e6e Mon Sep 17 00:00:00 2001 From: yang-g Date: Tue, 25 Aug 2015 11:05:29 -0700 Subject: remove constexpr since gcc 4.4 or vs2010 does not support it --- include/grpc++/support/string_ref.h | 28 +++++++++++++--------------- src/cpp/util/string_ref.cc | 2 +- 2 files changed, 14 insertions(+), 16 deletions(-) (limited to 'include') diff --git a/include/grpc++/support/string_ref.h b/include/grpc++/support/string_ref.h index 0ec39a9b0a..70bacc9445 100644 --- a/include/grpc++/support/string_ref.h +++ b/include/grpc++/support/string_ref.h @@ -50,22 +50,22 @@ class string_ref { typedef std::reverse_iterator const_reverse_iterator; // constants - static constexpr size_t npos = size_t(-1); + static size_t npos = size_t(-1); // construct/copy. - constexpr string_ref() : data_(nullptr), length_(0) {} - constexpr string_ref(const string_ref& other) + string_ref() : data_(nullptr), length_(0) {} + string_ref(const string_ref& other) : data_(other.data_), length_(other.length_) {} string_ref& operator=(const string_ref& rhs); string_ref(const char* s); - constexpr string_ref(const char* s, size_t l) : data_(s), length_(l) {} + string_ref(const char* s, size_t l) : data_(s), length_(l) {} string_ref(const grpc::string& s) : data_(s.data()), length_(s.length()) {} // iterators - constexpr const_iterator begin() const { return data_; } - constexpr const_iterator end() const { return data_ + length_; } - constexpr const_iterator cbegin() const { return data_; } - constexpr const_iterator cend() const { return data_ + length_; } + const_iterator begin() const { return data_; } + const_iterator end() const { return data_ + length_; } + const_iterator cbegin() const { return data_; } + const_iterator cend() const { return data_ + length_; } const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } @@ -80,10 +80,10 @@ class string_ref { } // capacity - constexpr size_t size() const { return length_; } - constexpr size_t length() const { return length_; } - constexpr size_t max_size() const { return length_; } - constexpr bool empty() const { return length_ == 0; } + size_t size() const { return length_; } + size_t length() const { return length_; } + size_t max_size() const { return length_; } + bool empty() const { return length_ == 0; } // element access const char* data() const { return data_; } @@ -95,9 +95,7 @@ class string_ref { size_t find(string_ref s) const; size_t find(char c) const; - // Defined as constexpr in n3442 but C++11 constexpr semantics do not allow - // the implementation of this function to comply. - /* constrexpr */ string_ref substr(size_t pos, size_t n = npos) const; + string_ref substr(size_t pos, size_t n = npos) const; private: const char* data_; diff --git a/src/cpp/util/string_ref.cc b/src/cpp/util/string_ref.cc index 8483e8c2ee..ff6b7617a3 100644 --- a/src/cpp/util/string_ref.cc +++ b/src/cpp/util/string_ref.cc @@ -39,7 +39,7 @@ namespace grpc { -constexpr size_t string_ref::npos; +size_t string_ref::npos; string_ref& string_ref::operator=(const string_ref& rhs) { data_ = rhs.data_; -- cgit v1.2.3 From 1eeb21c4df03194654252d1feaee779514ecefad Mon Sep 17 00:00:00 2001 From: yang-g Date: Tue, 25 Aug 2015 11:05:50 -0700 Subject: api change to string_ref --- include/grpc++/client_context.h | 10 ++++++---- include/grpc++/server_context.h | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/grpc++/client_context.h b/include/grpc++/client_context.h index ee28f360cb..c4724cc1f0 100644 --- a/include/grpc++/client_context.h +++ b/include/grpc++/client_context.h @@ -138,12 +138,14 @@ class ClientContext { void AddMetadata(const grpc::string& meta_key, const grpc::string& meta_value); - const std::multimap& GetServerInitialMetadata() { + const std::multimap& + GetServerInitialMetadata() { GPR_ASSERT(initial_metadata_received_); return recv_initial_metadata_; } - const std::multimap& GetServerTrailingMetadata() { + const std::multimap& + GetServerTrailingMetadata() { // TODO(yangg) check finished return trailing_metadata_; } @@ -234,8 +236,8 @@ class ClientContext { mutable std::shared_ptr auth_context_; struct census_context* census_context_; std::multimap send_initial_metadata_; - std::multimap recv_initial_metadata_; - std::multimap trailing_metadata_; + std::multimap recv_initial_metadata_; + std::multimap trailing_metadata_; grpc_call* propagate_from_call_; PropagationOptions propagation_options_; diff --git a/include/grpc++/server_context.h b/include/grpc++/server_context.h index ce3cb47a23..a165d84944 100644 --- a/include/grpc++/server_context.h +++ b/include/grpc++/server_context.h @@ -103,7 +103,7 @@ class ServerContext { bool IsCancelled() const; - const std::multimap& client_metadata() { + const std::multimap& client_metadata() { return client_metadata_; } @@ -185,7 +185,7 @@ class ServerContext { CompletionQueue* cq_; bool sent_initial_metadata_; mutable std::shared_ptr auth_context_; - std::multimap client_metadata_; + std::multimap client_metadata_; std::multimap initial_metadata_; std::multimap trailing_metadata_; -- cgit v1.2.3 From e21908fcee3ffac086575e247be3442860ac7b3a Mon Sep 17 00:00:00 2001 From: yang-g Date: Tue, 25 Aug 2015 13:47:51 -0700 Subject: impl --- Makefile | 3 ++ build.json | 2 ++ include/grpc++/client_context.h | 1 + include/grpc++/impl/call.h | 9 +++--- include/grpc++/server_context.h | 1 + include/grpc++/support/string_ref.h | 2 +- src/cpp/common/call.cc | 11 ++++---- src/cpp/server/server.cc | 11 ++++---- src/cpp/server/server_context.cc | 7 ++--- src/cpp/util/string_ref.cc | 2 +- test/cpp/end2end/async_end2end_test.cc | 37 +++++++++++++++++-------- test/cpp/end2end/end2end_test.cc | 27 ++++++++++-------- test/cpp/util/cli_call.cc | 10 +++---- test/cpp/util/cli_call.h | 12 +++++--- test/cpp/util/cli_call_test.cc | 13 +++++---- test/cpp/util/grpc_cli.cc | 22 +++++++++------ test/cpp/util/string_ref_helper.cc | 44 ++++++++++++++++++++++++++++++ test/cpp/util/string_ref_helper.h | 47 ++++++++++++++++++++++++++++++++ tools/run_tests/sources_and_headers.json | 3 ++ vsprojects/Grpc.mak | 4 +-- 20 files changed, 200 insertions(+), 68 deletions(-) create mode 100644 test/cpp/util/string_ref_helper.cc create mode 100644 test/cpp/util/string_ref_helper.h (limited to 'include') diff --git a/Makefile b/Makefile index 975633f998..5fbe3d98c1 100644 --- a/Makefile +++ b/Makefile @@ -4793,6 +4793,7 @@ LIBGRPC++_TEST_UTIL_SRC = \ $(GENDIR)/test/cpp/util/echo_duplicate.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.grpc.pb.cc \ test/cpp/util/cli_call.cc \ test/cpp/util/create_test_channel.cc \ + test/cpp/util/string_ref_helper.cc \ test/cpp/util/subprocess.cc \ @@ -4839,6 +4840,7 @@ endif endif $(OBJDIR)/$(CONFIG)/test/cpp/util/cli_call.o: $(GENDIR)/test/cpp/util/messages.pb.cc $(GENDIR)/test/cpp/util/messages.grpc.pb.cc $(GENDIR)/test/cpp/util/echo.pb.cc $(GENDIR)/test/cpp/util/echo.grpc.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.grpc.pb.cc $(OBJDIR)/$(CONFIG)/test/cpp/util/create_test_channel.o: $(GENDIR)/test/cpp/util/messages.pb.cc $(GENDIR)/test/cpp/util/messages.grpc.pb.cc $(GENDIR)/test/cpp/util/echo.pb.cc $(GENDIR)/test/cpp/util/echo.grpc.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.grpc.pb.cc +$(OBJDIR)/$(CONFIG)/test/cpp/util/string_ref_helper.o: $(GENDIR)/test/cpp/util/messages.pb.cc $(GENDIR)/test/cpp/util/messages.grpc.pb.cc $(GENDIR)/test/cpp/util/echo.pb.cc $(GENDIR)/test/cpp/util/echo.grpc.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.grpc.pb.cc $(OBJDIR)/$(CONFIG)/test/cpp/util/subprocess.o: $(GENDIR)/test/cpp/util/messages.pb.cc $(GENDIR)/test/cpp/util/messages.grpc.pb.cc $(GENDIR)/test/cpp/util/echo.pb.cc $(GENDIR)/test/cpp/util/echo.grpc.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.grpc.pb.cc @@ -20672,6 +20674,7 @@ test/cpp/qps/timer.cc: $(OPENSSL_DEP) test/cpp/util/benchmark_config.cc: $(OPENSSL_DEP) test/cpp/util/cli_call.cc: $(OPENSSL_DEP) test/cpp/util/create_test_channel.cc: $(OPENSSL_DEP) +test/cpp/util/string_ref_helper.cc: $(OPENSSL_DEP) test/cpp/util/subprocess.cc: $(OPENSSL_DEP) test/cpp/util/test_config.cc: $(OPENSSL_DEP) endif diff --git a/build.json b/build.json index 4f9017a0ad..8990d925a4 100644 --- a/build.json +++ b/build.json @@ -660,6 +660,7 @@ "headers": [ "test/cpp/util/cli_call.h", "test/cpp/util/create_test_channel.h", + "test/cpp/util/string_ref_helper.h", "test/cpp/util/subprocess.h" ], "src": [ @@ -668,6 +669,7 @@ "test/cpp/util/echo_duplicate.proto", "test/cpp/util/cli_call.cc", "test/cpp/util/create_test_channel.cc", + "test/cpp/util/string_ref_helper.cc", "test/cpp/util/subprocess.cc" ], "deps": [ diff --git a/include/grpc++/client_context.h b/include/grpc++/client_context.h index c4724cc1f0..62e5260a18 100644 --- a/include/grpc++/client_context.h +++ b/include/grpc++/client_context.h @@ -45,6 +45,7 @@ #include #include #include +#include #include struct census_context; diff --git a/include/grpc++/impl/call.h b/include/grpc++/impl/call.h index e5da6c9e2a..fca5603047 100644 --- a/include/grpc++/impl/call.h +++ b/include/grpc++/impl/call.h @@ -54,8 +54,9 @@ namespace grpc { class ByteBuffer; class Call; -void FillMetadataMap(grpc_metadata_array* arr, - std::multimap* metadata); +void FillMetadataMap( + grpc_metadata_array* arr, + std::multimap* metadata); grpc_metadata* FillMetadataArray( const std::multimap& metadata); @@ -418,7 +419,7 @@ class CallOpRecvInitialMetadata { } private: - std::multimap* recv_initial_metadata_; + std::multimap* recv_initial_metadata_; grpc_metadata_array recv_initial_metadata_arr_; }; @@ -461,7 +462,7 @@ class CallOpClientRecvStatus { } private: - std::multimap* recv_trailing_metadata_; + std::multimap* recv_trailing_metadata_; Status* recv_status_; grpc_metadata_array recv_trailing_metadata_arr_; grpc_status_code status_code_; diff --git a/include/grpc++/server_context.h b/include/grpc++/server_context.h index a165d84944..4b17a28047 100644 --- a/include/grpc++/server_context.h +++ b/include/grpc++/server_context.h @@ -41,6 +41,7 @@ #include #include #include +#include #include struct gpr_timespec; diff --git a/include/grpc++/support/string_ref.h b/include/grpc++/support/string_ref.h index 70bacc9445..348c42cbba 100644 --- a/include/grpc++/support/string_ref.h +++ b/include/grpc++/support/string_ref.h @@ -50,7 +50,7 @@ class string_ref { typedef std::reverse_iterator const_reverse_iterator; // constants - static size_t npos = size_t(-1); + const static size_t npos = size_t(-1); // construct/copy. string_ref() : data_(nullptr), length_(0) {} diff --git a/src/cpp/common/call.cc b/src/cpp/common/call.cc index 16aa2c9fb9..5b87c2a806 100644 --- a/src/cpp/common/call.cc +++ b/src/cpp/common/call.cc @@ -41,13 +41,14 @@ namespace grpc { -void FillMetadataMap(grpc_metadata_array* arr, - std::multimap* metadata) { +void FillMetadataMap( + grpc_metadata_array* arr, + std::multimap* metadata) { for (size_t i = 0; i < arr->count; i++) { // TODO(yangg) handle duplicates? - metadata->insert(std::pair( - arr->metadata[i].key, - grpc::string(arr->metadata[i].value, arr->metadata[i].value_length))); + metadata->insert(std::pair( + arr->metadata[i].key, grpc::string_ref(arr->metadata[i].value, + arr->metadata[i].value_length))); } grpc_metadata_array_destroy(arr); grpc_metadata_array_init(arr); diff --git a/src/cpp/server/server.cc b/src/cpp/server/server.cc index 66cd27cc33..bb83c7d887 100644 --- a/src/cpp/server/server.cc +++ b/src/cpp/server/server.cc @@ -439,11 +439,12 @@ Server::BaseAsyncRequest::~BaseAsyncRequest() {} bool Server::BaseAsyncRequest::FinalizeResult(void** tag, bool* status) { if (*status) { for (size_t i = 0; i < initial_metadata_array_.count; i++) { - context_->client_metadata_.insert(std::make_pair( - grpc::string(initial_metadata_array_.metadata[i].key), - grpc::string(initial_metadata_array_.metadata[i].value, - initial_metadata_array_.metadata[i].value + - initial_metadata_array_.metadata[i].value_length))); + context_->client_metadata_.insert( + std::pair( + initial_metadata_array_.metadata[i].key, + grpc::string_ref( + initial_metadata_array_.metadata[i].value, + initial_metadata_array_.metadata[i].value_length))); } } grpc_metadata_array_destroy(&initial_metadata_array_); diff --git a/src/cpp/server/server_context.cc b/src/cpp/server/server_context.cc index acc163d6b5..8193e70660 100644 --- a/src/cpp/server/server_context.cc +++ b/src/cpp/server/server_context.cc @@ -136,10 +136,9 @@ ServerContext::ServerContext(gpr_timespec deadline, grpc_metadata* metadata, cq_(nullptr), sent_initial_metadata_(false) { for (size_t i = 0; i < metadata_count; i++) { - client_metadata_.insert(std::make_pair( - grpc::string(metadata[i].key), - grpc::string(metadata[i].value, - metadata[i].value + metadata[i].value_length))); + client_metadata_.insert(std::pair( + metadata[i].key, + grpc::string_ref(metadata[i].value, metadata[i].value_length))); } } diff --git a/src/cpp/util/string_ref.cc b/src/cpp/util/string_ref.cc index ff6b7617a3..d9c9019da8 100644 --- a/src/cpp/util/string_ref.cc +++ b/src/cpp/util/string_ref.cc @@ -39,7 +39,7 @@ namespace grpc { -size_t string_ref::npos; +const size_t string_ref::npos; string_ref& string_ref::operator=(const string_ref& rhs) { data_ = rhs.data_; diff --git a/test/cpp/end2end/async_end2end_test.cc b/test/cpp/end2end/async_end2end_test.cc index 6343810ee9..41b91e459b 100644 --- a/test/cpp/end2end/async_end2end_test.cc +++ b/test/cpp/end2end/async_end2end_test.cc @@ -50,6 +50,7 @@ #include "test/core/util/test_config.h" #include "test/cpp/util/echo_duplicate.grpc.pb.h" #include "test/cpp/util/echo.grpc.pb.h" +#include "test/cpp/util/string_ref_helper.h" #ifdef GPR_POSIX_SOCKET #include "src/core/iomgr/pollset_posix.h" @@ -484,8 +485,10 @@ TEST_P(AsyncEnd2endTest, ClientInitialMetadataRpc) { Verifier(GetParam()).Expect(2, true).Verify(cq_.get()); EXPECT_EQ(send_request.message(), recv_request.message()); auto client_initial_metadata = srv_ctx.client_metadata(); - EXPECT_EQ(meta1.second, client_initial_metadata.find(meta1.first)->second); - EXPECT_EQ(meta2.second, client_initial_metadata.find(meta2.first)->second); + EXPECT_EQ(meta1.second, + ToString(client_initial_metadata.find(meta1.first)->second)); + EXPECT_EQ(meta2.second, + ToString(client_initial_metadata.find(meta2.first)->second)); EXPECT_GE(client_initial_metadata.size(), static_cast(2)); send_response.set_message(recv_request.message()); @@ -532,8 +535,10 @@ TEST_P(AsyncEnd2endTest, ServerInitialMetadataRpc) { response_reader->ReadInitialMetadata(tag(4)); Verifier(GetParam()).Expect(4, true).Verify(cq_.get()); auto server_initial_metadata = cli_ctx.GetServerInitialMetadata(); - EXPECT_EQ(meta1.second, server_initial_metadata.find(meta1.first)->second); - EXPECT_EQ(meta2.second, server_initial_metadata.find(meta2.first)->second); + EXPECT_EQ(meta1.second, + ToString(server_initial_metadata.find(meta1.first)->second)); + EXPECT_EQ(meta2.second, + ToString(server_initial_metadata.find(meta2.first)->second)); EXPECT_EQ(static_cast(2), server_initial_metadata.size()); send_response.set_message(recv_request.message()); @@ -586,8 +591,10 @@ TEST_P(AsyncEnd2endTest, ServerTrailingMetadataRpc) { EXPECT_EQ(send_response.message(), recv_response.message()); EXPECT_TRUE(recv_status.ok()); auto server_trailing_metadata = cli_ctx.GetServerTrailingMetadata(); - EXPECT_EQ(meta1.second, server_trailing_metadata.find(meta1.first)->second); - EXPECT_EQ(meta2.second, server_trailing_metadata.find(meta2.first)->second); + EXPECT_EQ(meta1.second, + ToString(server_trailing_metadata.find(meta1.first)->second)); + EXPECT_EQ(meta2.second, + ToString(server_trailing_metadata.find(meta2.first)->second)); EXPECT_EQ(static_cast(2), server_trailing_metadata.size()); } @@ -631,8 +638,10 @@ TEST_P(AsyncEnd2endTest, MetadataRpc) { Verifier(GetParam()).Expect(2, true).Verify(cq_.get()); EXPECT_EQ(send_request.message(), recv_request.message()); auto client_initial_metadata = srv_ctx.client_metadata(); - EXPECT_EQ(meta1.second, client_initial_metadata.find(meta1.first)->second); - EXPECT_EQ(meta2.second, client_initial_metadata.find(meta2.first)->second); + EXPECT_EQ(meta1.second, + ToString(client_initial_metadata.find(meta1.first)->second)); + EXPECT_EQ(meta2.second, + ToString(client_initial_metadata.find(meta2.first)->second)); EXPECT_GE(client_initial_metadata.size(), static_cast(2)); srv_ctx.AddInitialMetadata(meta3.first, meta3.second); @@ -642,8 +651,10 @@ TEST_P(AsyncEnd2endTest, MetadataRpc) { response_reader->ReadInitialMetadata(tag(4)); Verifier(GetParam()).Expect(4, true).Verify(cq_.get()); auto server_initial_metadata = cli_ctx.GetServerInitialMetadata(); - EXPECT_EQ(meta3.second, server_initial_metadata.find(meta3.first)->second); - EXPECT_EQ(meta4.second, server_initial_metadata.find(meta4.first)->second); + EXPECT_EQ(meta3.second, + ToString(server_initial_metadata.find(meta3.first)->second)); + EXPECT_EQ(meta4.second, + ToString(server_initial_metadata.find(meta4.first)->second)); EXPECT_GE(server_initial_metadata.size(), static_cast(2)); send_response.set_message(recv_request.message()); @@ -658,8 +669,10 @@ TEST_P(AsyncEnd2endTest, MetadataRpc) { EXPECT_EQ(send_response.message(), recv_response.message()); EXPECT_TRUE(recv_status.ok()); auto server_trailing_metadata = cli_ctx.GetServerTrailingMetadata(); - EXPECT_EQ(meta5.second, server_trailing_metadata.find(meta5.first)->second); - EXPECT_EQ(meta6.second, server_trailing_metadata.find(meta6.first)->second); + EXPECT_EQ(meta5.second, + ToString(server_trailing_metadata.find(meta5.first)->second)); + EXPECT_EQ(meta6.second, + ToString(server_trailing_metadata.find(meta6.first)->second)); EXPECT_GE(server_trailing_metadata.size(), static_cast(2)); } diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc index 2728dce07e..0d5bf36df7 100644 --- a/test/cpp/end2end/end2end_test.cc +++ b/test/cpp/end2end/end2end_test.cc @@ -53,6 +53,7 @@ #include "test/core/util/test_config.h" #include "test/cpp/util/echo_duplicate.grpc.pb.h" #include "test/cpp/util/echo.grpc.pb.h" +#include "test/cpp/util/string_ref_helper.h" using grpc::cpp::test::util::EchoRequest; using grpc::cpp::test::util::EchoResponse; @@ -152,12 +153,13 @@ class TestServiceImpl : public ::grpc::cpp::test::util::TestService::Service { } if (request->has_param() && request->param().echo_metadata()) { - const std::multimap& client_metadata = + const std::multimap& client_metadata = context->client_metadata(); - for (std::multimap::const_iterator iter = - client_metadata.begin(); + for (std::multimap::const_iterator + iter = client_metadata.begin(); iter != client_metadata.end(); ++iter) { - context->AddTrailingMetadata((*iter).first, (*iter).second); + context->AddTrailingMetadata(ToString(iter->first), + ToString(iter->second)); } } if (request->has_param() && request->param().check_auth_context()) { @@ -182,12 +184,12 @@ class TestServiceImpl : public ::grpc::cpp::test::util::TestService::Service { EchoRequest request; response->set_message(""); int cancel_after_reads = 0; - const std::multimap client_initial_metadata = - context->client_metadata(); + const std::multimap& + client_initial_metadata = context->client_metadata(); if (client_initial_metadata.find(kServerCancelAfterReads) != client_initial_metadata.end()) { - std::istringstream iss( - client_initial_metadata.find(kServerCancelAfterReads)->second); + std::istringstream iss(ToString( + client_initial_metadata.find(kServerCancelAfterReads)->second)); iss >> cancel_after_reads; gpr_log(GPR_INFO, "cancel_after_reads %d", cancel_after_reads); } @@ -721,14 +723,15 @@ TEST_F(End2endTest, RpcMaxMessageSize) { EXPECT_FALSE(s.ok()); } -bool MetadataContains(const std::multimap& metadata, - const grpc::string& key, const grpc::string& value) { +bool MetadataContains( + const std::multimap& metadata, + const grpc::string& key, const grpc::string& value) { int count = 0; - for (std::multimap::const_iterator iter = + for (std::multimap::const_iterator iter = metadata.begin(); iter != metadata.end(); ++iter) { - if ((*iter).first == key && (*iter).second == value) { + if (ToString(iter->first) == key && ToString(iter->second) == value) { count++; } } diff --git a/test/cpp/util/cli_call.cc b/test/cpp/util/cli_call.cc index d60cee9c02..9a769848a4 100644 --- a/test/cpp/util/cli_call.cc +++ b/test/cpp/util/cli_call.cc @@ -51,14 +51,14 @@ void* tag(int i) { return (void*)(gpr_intptr)i; } Status CliCall::Call(std::shared_ptr channel, const grpc::string& method, const grpc::string& request, - grpc::string* response, const MetadataContainer& metadata, - MetadataContainer* server_initial_metadata, - MetadataContainer* server_trailing_metadata) { + grpc::string* response, + const OutgoingMetadataContainer& metadata, + IncomingMetadataContainer* server_initial_metadata, + IncomingMetadataContainer* server_trailing_metadata) { std::unique_ptr stub(new grpc::GenericStub(channel)); grpc::ClientContext ctx; if (!metadata.empty()) { - for (std::multimap::const_iterator iter = - metadata.begin(); + for (OutgoingMetadataContainer::const_iterator iter = metadata.begin(); iter != metadata.end(); ++iter) { ctx.AddMetadata(iter->first, iter->second); } diff --git a/test/cpp/util/cli_call.h b/test/cpp/util/cli_call.h index 7a3dcf2e9f..2fbc9618b6 100644 --- a/test/cpp/util/cli_call.h +++ b/test/cpp/util/cli_call.h @@ -38,18 +38,22 @@ #include #include +#include namespace grpc { namespace testing { class CliCall GRPC_FINAL { public: - typedef std::multimap MetadataContainer; + typedef std::multimap OutgoingMetadataContainer; + typedef std::multimap + IncomingMetadataContainer; static Status Call(std::shared_ptr channel, const grpc::string& method, const grpc::string& request, - grpc::string* response, const MetadataContainer& metadata, - MetadataContainer* server_initial_metadata, - MetadataContainer* server_trailing_metadata); + grpc::string* response, + const OutgoingMetadataContainer& metadata, + IncomingMetadataContainer* server_initial_metadata, + IncomingMetadataContainer* server_trailing_metadata); }; } // namespace testing diff --git a/test/cpp/util/cli_call_test.cc b/test/cpp/util/cli_call_test.cc index 35bfad202f..111a0e9f76 100644 --- a/test/cpp/util/cli_call_test.cc +++ b/test/cpp/util/cli_call_test.cc @@ -47,6 +47,7 @@ #include "test/core/util/port.h" #include "test/core/util/test_config.h" #include "test/cpp/util/echo.grpc.pb.h" +#include "test/cpp/util/string_ref_helper.h" using grpc::cpp::test::util::EchoRequest; using grpc::cpp::test::util::EchoResponse; @@ -59,10 +60,11 @@ class TestServiceImpl : public ::grpc::cpp::test::util::TestService::Service { Status Echo(ServerContext* context, const EchoRequest* request, EchoResponse* response) GRPC_OVERRIDE { if (!context->client_metadata().empty()) { - for (std::multimap::const_iterator iter = - context->client_metadata().begin(); + for (std::multimap::const_iterator + iter = context->client_metadata().begin(); iter != context->client_metadata().end(); ++iter) { - context->AddInitialMetadata(iter->first, iter->second); + context->AddInitialMetadata(ToString(iter->first), + ToString(iter->second)); } } context->AddTrailingMetadata("trailing_key", "trailing_value"); @@ -119,8 +121,9 @@ TEST_F(CliCallTest, SimpleRpc) { grpc::string request_bin, response_bin, expected_response_bin; EXPECT_TRUE(request.SerializeToString(&request_bin)); EXPECT_TRUE(response.SerializeToString(&expected_response_bin)); - std::multimap client_metadata, - server_initial_metadata, server_trailing_metadata; + std::multimap client_metadata; + std::multimap server_initial_metadata, + server_trailing_metadata; client_metadata.insert(std::pair("key1", "val1")); Status s2 = CliCall::Call(channel_, kMethod, request_bin, &response_bin, client_metadata, &server_initial_metadata, diff --git a/test/cpp/util/grpc_cli.cc b/test/cpp/util/grpc_cli.cc index 746d67deeb..a4888efebe 100644 --- a/test/cpp/util/grpc_cli.cc +++ b/test/cpp/util/grpc_cli.cc @@ -68,8 +68,10 @@ #include #include #include +#include #include "test/cpp/util/cli_call.h" +#include "test/cpp/util/string_ref_helper.h" #include "test/cpp/util/test_config.h" DEFINE_bool(enable_ssl, true, "Whether to use ssl/tls."); @@ -104,16 +106,19 @@ void ParseMetadataFlag( } } -void PrintMetadata(const std::multimap& m, - const grpc::string& message) { +template +void PrintMetadata(const T& m, const grpc::string& message) { if (m.empty()) { return; } std::cout << message << std::endl; - for (std::multimap::const_iterator iter = - m.begin(); - iter != m.end(); ++iter) { - std::cout << iter->first << " : " << iter->second << std::endl; + grpc::string pair; + for (typename T::const_iterator iter = m.begin(); iter != m.end(); ++iter) { + pair.clear(); + pair.append(iter->first.data(), iter->first.size()); + pair.append(" : "); + pair.append(iter->second.data(), iter->second.size()); + std::cout << pair << std::endl; } } @@ -157,8 +162,9 @@ int main(int argc, char** argv) { grpc::CreateChannel(server_address, creds, grpc::ChannelArguments()); grpc::string response; - std::multimap client_metadata, - server_initial_metadata, server_trailing_metadata; + std::multimap client_metadata; + std::multimap server_initial_metadata, + server_trailing_metadata; ParseMetadataFlag(&client_metadata); PrintMetadata(client_metadata, "Sending client initial metadata:"); grpc::Status s = grpc::testing::CliCall::Call( diff --git a/test/cpp/util/string_ref_helper.cc b/test/cpp/util/string_ref_helper.cc new file mode 100644 index 0000000000..4eb4fe0357 --- /dev/null +++ b/test/cpp/util/string_ref_helper.cc @@ -0,0 +1,44 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "test/cpp/util/string_ref_helper.h" + +namespace grpc { +namespace testing { + +grpc::string ToString(const grpc::string_ref& r) { + return grpc::string(r.data(), r.size()); +} + +} // namespace testing +} // namespace grpc diff --git a/test/cpp/util/string_ref_helper.h b/test/cpp/util/string_ref_helper.h new file mode 100644 index 0000000000..ac94bcd018 --- /dev/null +++ b/test/cpp/util/string_ref_helper.h @@ -0,0 +1,47 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef GRPC_TEST_CPP_UTIL_STRING_REF_HELPER_H +#define GRPC_TEST_CPP_UTIL_STRING_REF_HELPER_H + +#include + +namespace grpc { +namespace testing { + +grpc::string ToString(const grpc::string_ref& r); + +} // namespace testing +} // namespace grpc + +#endif // GRPC_TEST_CPP_UTIL_STRING_REF_HELPER_H diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json index a7fd884cd8..d4dcc92bde 100644 --- a/tools/run_tests/sources_and_headers.json +++ b/tools/run_tests/sources_and_headers.json @@ -13270,6 +13270,7 @@ "test/cpp/util/echo_duplicate.pb.h", "test/cpp/util/messages.grpc.pb.h", "test/cpp/util/messages.pb.h", + "test/cpp/util/string_ref_helper.h", "test/cpp/util/subprocess.h" ], "language": "c++", @@ -13279,6 +13280,8 @@ "test/cpp/util/cli_call.h", "test/cpp/util/create_test_channel.cc", "test/cpp/util/create_test_channel.h", + "test/cpp/util/string_ref_helper.cc", + "test/cpp/util/string_ref_helper.h", "test/cpp/util/subprocess.cc", "test/cpp/util/subprocess.h" ] diff --git a/vsprojects/Grpc.mak b/vsprojects/Grpc.mak index 2893b72c5d..19cb39741e 100644 --- a/vsprojects/Grpc.mak +++ b/vsprojects/Grpc.mak @@ -4744,8 +4744,8 @@ Debug\grpc++_test_config.lib: $(OUT_DIR) Debug\grpc++_test_util.lib: $(OUT_DIR) echo Building grpc++_test_util - $(CC) $(CXXFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\test\cpp\util\cli_call.cc $(REPO_ROOT)\test\cpp\util\create_test_channel.cc $(REPO_ROOT)\test\cpp\util\subprocess.cc $(REPO_ROOT)\test\cpp\util\messages.pb.cc $(REPO_ROOT)\test\cpp\util\messages.grpc.pb.cc $(REPO_ROOT)\test\cpp\util\echo.pb.cc $(REPO_ROOT)\test\cpp\util\echo.grpc.pb.cc $(REPO_ROOT)\test\cpp\util\echo_duplicate.pb.cc $(REPO_ROOT)\test\cpp\util\echo_duplicate.grpc.pb.cc - $(LIBTOOL) /OUT:"Debug\grpc++_test_util.lib" $(OUT_DIR)\cli_call.obj $(OUT_DIR)\create_test_channel.obj $(OUT_DIR)\subprocess.obj $(OUT_DIR)\messages.pb.obj $(OUT_DIR)\messages.grpc.pb.obj $(OUT_DIR)\echo.pb.obj $(OUT_DIR)\echo.grpc.pb.obj $(OUT_DIR)\echo_duplicate.pb.obj $(OUT_DIR)\echo_duplicate.grpc.pb.obj + $(CC) $(CXXFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\test\cpp\util\cli_call.cc $(REPO_ROOT)\test\cpp\util\create_test_channel.cc $(REPO_ROOT)\test\cpp\util\string_ref_helper.cc $(REPO_ROOT)\test\cpp\util\subprocess.cc $(REPO_ROOT)\test\cpp\util\messages.pb.cc $(REPO_ROOT)\test\cpp\util\messages.grpc.pb.cc $(REPO_ROOT)\test\cpp\util\echo.pb.cc $(REPO_ROOT)\test\cpp\util\echo.grpc.pb.cc $(REPO_ROOT)\test\cpp\util\echo_duplicate.pb.cc $(REPO_ROOT)\test\cpp\util\echo_duplicate.grpc.pb.cc + $(LIBTOOL) /OUT:"Debug\grpc++_test_util.lib" $(OUT_DIR)\cli_call.obj $(OUT_DIR)\create_test_channel.obj $(OUT_DIR)\string_ref_helper.obj $(OUT_DIR)\subprocess.obj $(OUT_DIR)\messages.pb.obj $(OUT_DIR)\messages.grpc.pb.obj $(OUT_DIR)\echo.pb.obj $(OUT_DIR)\echo.grpc.pb.obj $(OUT_DIR)\echo_duplicate.pb.obj $(OUT_DIR)\echo_duplicate.grpc.pb.obj build_grpc++_unsecure: msbuild grpc.sln /t:grpc++_unsecure /p:Configuration=Debug /p:Linkage-grpc_dependencies_zlib=static -- cgit v1.2.3 From d090fe1379932d7d785fa805339110e70b96bd87 Mon Sep 17 00:00:00 2001 From: yang-g Date: Tue, 25 Aug 2015 16:53:07 -0700 Subject: auth context api change for string_ref --- Makefile | 12 ++++++------ build.json | 6 ++++++ include/grpc++/support/auth_context.h | 7 ++++--- src/cpp/common/auth_property_iterator.cc | 6 +++--- src/cpp/common/secure_auth_context.cc | 17 +++++++++-------- src/cpp/common/secure_auth_context.h | 6 +++--- test/cpp/common/auth_property_iterator_test.cc | 15 +++++++++------ test/cpp/common/secure_auth_context_test.cc | 25 ++++++++++++++----------- test/cpp/end2end/end2end_test.cc | 15 ++++++++------- tools/run_tests/sources_and_headers.json | 10 ++++++++-- vsprojects/Grpc.mak | 8 ++++---- 11 files changed, 74 insertions(+), 53 deletions(-) (limited to 'include') diff --git a/Makefile b/Makefile index 77cb62086b..e872da981b 100644 --- a/Makefile +++ b/Makefile @@ -8945,16 +8945,16 @@ $(BINDIR)/$(CONFIG)/auth_property_iterator_test: protobuf_dep_error else -$(BINDIR)/$(CONFIG)/auth_property_iterator_test: $(PROTOBUF_DEP) $(AUTH_PROPERTY_ITERATOR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a +$(BINDIR)/$(CONFIG)/auth_property_iterator_test: $(PROTOBUF_DEP) $(AUTH_PROPERTY_ITERATOR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(E) "[LD] Linking $@" $(Q) mkdir -p `dirname $@` - $(Q) $(LDXX) $(LDFLAGS) $(AUTH_PROPERTY_ITERATOR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/auth_property_iterator_test + $(Q) $(LDXX) $(LDFLAGS) $(AUTH_PROPERTY_ITERATOR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/auth_property_iterator_test endif endif -$(OBJDIR)/$(CONFIG)/test/cpp/common/auth_property_iterator_test.o: $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a +$(OBJDIR)/$(CONFIG)/test/cpp/common/auth_property_iterator_test.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a deps_auth_property_iterator_test: $(AUTH_PROPERTY_ITERATOR_TEST_OBJS:.o=.dep) ifneq ($(NO_SECURE),true) @@ -10155,16 +10155,16 @@ $(BINDIR)/$(CONFIG)/secure_auth_context_test: protobuf_dep_error else -$(BINDIR)/$(CONFIG)/secure_auth_context_test: $(PROTOBUF_DEP) $(SECURE_AUTH_CONTEXT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a +$(BINDIR)/$(CONFIG)/secure_auth_context_test: $(PROTOBUF_DEP) $(SECURE_AUTH_CONTEXT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(E) "[LD] Linking $@" $(Q) mkdir -p `dirname $@` - $(Q) $(LDXX) $(LDFLAGS) $(SECURE_AUTH_CONTEXT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/secure_auth_context_test + $(Q) $(LDXX) $(LDFLAGS) $(SECURE_AUTH_CONTEXT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/secure_auth_context_test endif endif -$(OBJDIR)/$(CONFIG)/test/cpp/common/secure_auth_context_test.o: $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a +$(OBJDIR)/$(CONFIG)/test/cpp/common/secure_auth_context_test.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a deps_secure_auth_context_test: $(SECURE_AUTH_CONTEXT_TEST_OBJS:.o=.dep) ifneq ($(NO_SECURE),true) diff --git a/build.json b/build.json index c974250d7c..56f14c6590 100644 --- a/build.json +++ b/build.json @@ -2020,8 +2020,11 @@ "test/cpp/common/auth_property_iterator_test.cc" ], "deps": [ + "grpc++_test_util", + "grpc_test_util", "grpc++", "grpc", + "gpr_test_util", "gpr" ] }, @@ -2572,8 +2575,11 @@ "test/cpp/common/secure_auth_context_test.cc" ], "deps": [ + "grpc++_test_util", + "grpc_test_util", "grpc++", "grpc", + "gpr_test_util", "gpr" ] }, diff --git a/include/grpc++/support/auth_context.h b/include/grpc++/support/auth_context.h index f4f2dcf5bb..67e3e66c05 100644 --- a/include/grpc++/support/auth_context.h +++ b/include/grpc++/support/auth_context.h @@ -38,6 +38,7 @@ #include #include +#include struct grpc_auth_context; struct grpc_auth_property; @@ -46,7 +47,7 @@ struct grpc_auth_property_iterator; namespace grpc { class SecureAuthContext; -typedef std::pair AuthProperty; +typedef std::pair AuthProperty; class AuthPropertyIterator : public std::iterator { @@ -78,11 +79,11 @@ class AuthContext { // A peer identity, in general is one or more properties (in which case they // have the same name). - virtual std::vector GetPeerIdentity() const = 0; + virtual std::vector GetPeerIdentity() const = 0; virtual grpc::string GetPeerIdentityPropertyName() const = 0; // Returns all the property values with the given name. - virtual std::vector FindPropertyValues( + virtual std::vector FindPropertyValues( const grpc::string& name) const = 0; // Iteration over all the properties. diff --git a/src/cpp/common/auth_property_iterator.cc b/src/cpp/common/auth_property_iterator.cc index 5ccf8cf72c..fa6da9d7a8 100644 --- a/src/cpp/common/auth_property_iterator.cc +++ b/src/cpp/common/auth_property_iterator.cc @@ -77,9 +77,9 @@ bool AuthPropertyIterator::operator!=(const AuthPropertyIterator& rhs) const { } const AuthProperty AuthPropertyIterator::operator*() { - return std::make_pair( - grpc::string(property_->name), - grpc::string(property_->value, property_->value_length)); + return std::pair( + property_->name, + grpc::string_ref(property_->value, property_->value_length)); } } // namespace grpc diff --git a/src/cpp/common/secure_auth_context.cc b/src/cpp/common/secure_auth_context.cc index 87d7bab75c..b18a8537c9 100644 --- a/src/cpp/common/secure_auth_context.cc +++ b/src/cpp/common/secure_auth_context.cc @@ -41,15 +41,16 @@ SecureAuthContext::SecureAuthContext(grpc_auth_context* ctx) : ctx_(ctx) {} SecureAuthContext::~SecureAuthContext() { grpc_auth_context_release(ctx_); } -std::vector SecureAuthContext::GetPeerIdentity() const { +std::vector SecureAuthContext::GetPeerIdentity() const { if (!ctx_) { - return std::vector(); + return std::vector(); } grpc_auth_property_iterator iter = grpc_auth_context_peer_identity(ctx_); - std::vector identity; + std::vector identity; const grpc_auth_property* property = nullptr; while ((property = grpc_auth_property_iterator_next(&iter))) { - identity.push_back(grpc::string(property->value, property->value_length)); + identity.push_back( + grpc::string_ref(property->value, property->value_length)); } return identity; } @@ -62,17 +63,17 @@ grpc::string SecureAuthContext::GetPeerIdentityPropertyName() const { return name == nullptr ? "" : name; } -std::vector SecureAuthContext::FindPropertyValues( +std::vector SecureAuthContext::FindPropertyValues( const grpc::string& name) const { if (!ctx_) { - return std::vector(); + return std::vector(); } grpc_auth_property_iterator iter = grpc_auth_context_find_properties_by_name(ctx_, name.c_str()); const grpc_auth_property* property = nullptr; - std::vector values; + std::vector values; while ((property = grpc_auth_property_iterator_next(&iter))) { - values.push_back(grpc::string(property->value, property->value_length)); + values.push_back(grpc::string_ref(property->value, property->value_length)); } return values; } diff --git a/src/cpp/common/secure_auth_context.h b/src/cpp/common/secure_auth_context.h index 01b7126189..7f622b890b 100644 --- a/src/cpp/common/secure_auth_context.h +++ b/src/cpp/common/secure_auth_context.h @@ -46,12 +46,12 @@ class SecureAuthContext GRPC_FINAL : public AuthContext { ~SecureAuthContext() GRPC_OVERRIDE; - std::vector GetPeerIdentity() const GRPC_OVERRIDE; + std::vector GetPeerIdentity() const GRPC_OVERRIDE; grpc::string GetPeerIdentityPropertyName() const GRPC_OVERRIDE; - std::vector FindPropertyValues(const grpc::string& name) const - GRPC_OVERRIDE; + std::vector FindPropertyValues( + const grpc::string& name) const GRPC_OVERRIDE; AuthPropertyIterator begin() const GRPC_OVERRIDE; diff --git a/test/cpp/common/auth_property_iterator_test.cc b/test/cpp/common/auth_property_iterator_test.cc index 630c38c7f6..e6226d6a09 100644 --- a/test/cpp/common/auth_property_iterator_test.cc +++ b/test/cpp/common/auth_property_iterator_test.cc @@ -35,11 +35,14 @@ #include #include #include "src/cpp/common/secure_auth_context.h" +#include "test/cpp/util/string_ref_helper.h" extern "C" { #include "src/core/security/security_context.h" } +using ::grpc::testing::ToString; + namespace grpc { namespace { @@ -84,12 +87,12 @@ TEST_F(AuthPropertyIteratorTest, GeneralTest) { AuthProperty p1 = *iter; iter++; AuthProperty p2 = *iter; - EXPECT_EQ("name", p0.first); - EXPECT_EQ("chapi", p0.second); - EXPECT_EQ("name", p1.first); - EXPECT_EQ("chapo", p1.second); - EXPECT_EQ("foo", p2.first); - EXPECT_EQ("bar", p2.second); + EXPECT_EQ("name", ToString(p0.first)); + EXPECT_EQ("chapi", ToString(p0.second)); + EXPECT_EQ("name", ToString(p1.first)); + EXPECT_EQ("chapo", ToString(p1.second)); + EXPECT_EQ("foo", ToString(p2.first)); + EXPECT_EQ("bar", ToString(p2.second)); ++iter; EXPECT_EQ(empty_iter, iter); } diff --git a/test/cpp/common/secure_auth_context_test.cc b/test/cpp/common/secure_auth_context_test.cc index c71ef58023..25538c1853 100644 --- a/test/cpp/common/secure_auth_context_test.cc +++ b/test/cpp/common/secure_auth_context_test.cc @@ -35,11 +35,14 @@ #include #include #include "src/cpp/common/secure_auth_context.h" +#include "test/cpp/util/string_ref_helper.h" extern "C" { #include "src/core/security/security_context.h" } +using grpc::testing::ToString; + namespace grpc { namespace { @@ -63,14 +66,14 @@ TEST_F(SecureAuthContextTest, Properties) { EXPECT_EQ(1, grpc_auth_context_set_peer_identity_property_name(ctx, "name")); SecureAuthContext context(ctx); - std::vector peer_identity = context.GetPeerIdentity(); + std::vector peer_identity = context.GetPeerIdentity(); EXPECT_EQ(2u, peer_identity.size()); - EXPECT_EQ("chapi", peer_identity[0]); - EXPECT_EQ("chapo", peer_identity[1]); + EXPECT_EQ("chapi", ToString(peer_identity[0])); + EXPECT_EQ("chapo", ToString(peer_identity[1])); EXPECT_EQ("name", context.GetPeerIdentityPropertyName()); - std::vector bar = context.FindPropertyValues("foo"); + std::vector bar = context.FindPropertyValues("foo"); EXPECT_EQ(1u, bar.size()); - EXPECT_EQ("bar", bar[0]); + EXPECT_EQ("bar", ToString(bar[0])); } TEST_F(SecureAuthContextTest, Iterators) { @@ -88,12 +91,12 @@ TEST_F(SecureAuthContextTest, Iterators) { AuthProperty p1 = *iter; iter++; AuthProperty p2 = *iter; - EXPECT_EQ("name", p0.first); - EXPECT_EQ("chapi", p0.second); - EXPECT_EQ("name", p1.first); - EXPECT_EQ("chapo", p1.second); - EXPECT_EQ("foo", p2.first); - EXPECT_EQ("bar", p2.second); + EXPECT_EQ("name", ToString(p0.first)); + EXPECT_EQ("chapi", ToString(p0.second)); + EXPECT_EQ("name", ToString(p1.first)); + EXPECT_EQ("chapo", ToString(p1.second)); + EXPECT_EQ("foo", ToString(p2.first)); + EXPECT_EQ("bar", ToString(p2.second)); ++iter; EXPECT_EQ(context.end(), iter); } diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc index 0d5bf36df7..9826837c60 100644 --- a/test/cpp/end2end/end2end_test.cc +++ b/test/cpp/end2end/end2end_test.cc @@ -81,10 +81,10 @@ void MaybeEchoDeadline(ServerContext* context, const EchoRequest* request, void CheckServerAuthContext(const ServerContext* context) { std::shared_ptr auth_ctx = context->auth_context(); - std::vector ssl = + std::vector ssl = auth_ctx->FindPropertyValues("transport_security_type"); EXPECT_EQ(1u, ssl.size()); - EXPECT_EQ("ssl", ssl[0]); + EXPECT_EQ("ssl", ToString(ssl[0])); EXPECT_TRUE(auth_ctx->GetPeerIdentityPropertyName().empty()); EXPECT_TRUE(auth_ctx->GetPeerIdentity().empty()); } @@ -840,16 +840,17 @@ TEST_F(End2endTest, ClientAuthContext) { EXPECT_TRUE(s.ok()); std::shared_ptr auth_ctx = context.auth_context(); - std::vector ssl = + std::vector ssl = auth_ctx->FindPropertyValues("transport_security_type"); EXPECT_EQ(1u, ssl.size()); - EXPECT_EQ("ssl", ssl[0]); + EXPECT_EQ("ssl", ToString(ssl[0])); EXPECT_EQ("x509_subject_alternative_name", auth_ctx->GetPeerIdentityPropertyName()); EXPECT_EQ(3u, auth_ctx->GetPeerIdentity().size()); - EXPECT_EQ("*.test.google.fr", auth_ctx->GetPeerIdentity()[0]); - EXPECT_EQ("waterzooi.test.google.be", auth_ctx->GetPeerIdentity()[1]); - EXPECT_EQ("*.test.youtube.com", auth_ctx->GetPeerIdentity()[2]); + EXPECT_EQ("*.test.google.fr", ToString(auth_ctx->GetPeerIdentity()[0])); + EXPECT_EQ("waterzooi.test.google.be", + ToString(auth_ctx->GetPeerIdentity()[1])); + EXPECT_EQ("*.test.youtube.com", ToString(auth_ctx->GetPeerIdentity()[2])); } // Make the response larger than the flow control window. diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json index a89e5340ed..5facf582ce 100644 --- a/tools/run_tests/sources_and_headers.json +++ b/tools/run_tests/sources_and_headers.json @@ -1068,8 +1068,11 @@ { "deps": [ "gpr", + "gpr_test_util", "grpc", - "grpc++" + "grpc++", + "grpc++_test_util", + "grpc_test_util" ], "headers": [], "language": "c++", @@ -1573,8 +1576,11 @@ { "deps": [ "gpr", + "gpr_test_util", "grpc", - "grpc++" + "grpc++", + "grpc++_test_util", + "grpc_test_util" ], "headers": [], "language": "c++", diff --git a/vsprojects/Grpc.mak b/vsprojects/Grpc.mak index 19cb39741e..ad390e7cda 100644 --- a/vsprojects/Grpc.mak +++ b/vsprojects/Grpc.mak @@ -615,10 +615,10 @@ async_end2end_test: async_end2end_test.exe echo Running async_end2end_test $(OUT_DIR)\async_end2end_test.exe -auth_property_iterator_test.exe: build_grpc++ build_grpc build_gpr $(OUT_DIR) +auth_property_iterator_test.exe: Debug\grpc++_test_util.lib build_grpc_test_util build_grpc++ build_grpc build_gpr_test_util build_gpr $(OUT_DIR) echo Building auth_property_iterator_test $(CC) $(CXXFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\test\cpp\common\auth_property_iterator_test.cc - $(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\auth_property_iterator_test.exe" Debug\grpc++.lib Debug\grpc.lib Debug\gpr.lib $(CXX_LIBS) $(LIBS) $(OUT_DIR)\auth_property_iterator_test.obj + $(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\auth_property_iterator_test.exe" Debug\grpc++_test_util.lib Debug\grpc_test_util.lib Debug\grpc++.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(CXX_LIBS) $(LIBS) $(OUT_DIR)\auth_property_iterator_test.obj auth_property_iterator_test: auth_property_iterator_test.exe echo Running auth_property_iterator_test $(OUT_DIR)\auth_property_iterator_test.exe @@ -751,10 +751,10 @@ reconnect_interop_server: reconnect_interop_server.exe echo Running reconnect_interop_server $(OUT_DIR)\reconnect_interop_server.exe -secure_auth_context_test.exe: build_grpc++ build_grpc build_gpr $(OUT_DIR) +secure_auth_context_test.exe: Debug\grpc++_test_util.lib build_grpc_test_util build_grpc++ build_grpc build_gpr_test_util build_gpr $(OUT_DIR) echo Building secure_auth_context_test $(CC) $(CXXFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\test\cpp\common\secure_auth_context_test.cc - $(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\secure_auth_context_test.exe" Debug\grpc++.lib Debug\grpc.lib Debug\gpr.lib $(CXX_LIBS) $(LIBS) $(OUT_DIR)\secure_auth_context_test.obj + $(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\secure_auth_context_test.exe" Debug\grpc++_test_util.lib Debug\grpc_test_util.lib Debug\grpc++.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(CXX_LIBS) $(LIBS) $(OUT_DIR)\secure_auth_context_test.obj secure_auth_context_test: secure_auth_context_test.exe echo Running secure_auth_context_test $(OUT_DIR)\secure_auth_context_test.exe -- cgit v1.2.3 From 47ec9a40ade6cf5b205b035b1142e0cc539c4f70 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 26 Aug 2015 09:47:51 -0700 Subject: Add ostream support for string_ref --- include/grpc++/support/string_ref.h | 3 +++ src/cpp/util/string_ref.cc | 4 ++++ 2 files changed, 7 insertions(+) (limited to 'include') diff --git a/include/grpc++/support/string_ref.h b/include/grpc++/support/string_ref.h index 348c42cbba..fd2b3ad8e7 100644 --- a/include/grpc++/support/string_ref.h +++ b/include/grpc++/support/string_ref.h @@ -35,6 +35,7 @@ #define GRPCXX_STRING_REF_H #include +#include #include @@ -110,6 +111,8 @@ bool operator>(string_ref x, string_ref y); bool operator<=(string_ref x, string_ref y); bool operator>=(string_ref x, string_ref y); +std::ostream& operator<<(std::ostream& stream, const string_ref& string); + } // namespace grpc #endif // GRPCXX_STRING_REF_H diff --git a/src/cpp/util/string_ref.cc b/src/cpp/util/string_ref.cc index d9c9019da8..eb54f65e3a 100644 --- a/src/cpp/util/string_ref.cc +++ b/src/cpp/util/string_ref.cc @@ -108,4 +108,8 @@ bool operator>=(string_ref x, string_ref y) { return x.compare(y) >= 0; } +std::ostream& operator<<(std::ostream& out, const string_ref& string) { + return out << grpc::string(string.begin(), string.end()); +} + } // namespace grpc -- cgit v1.2.3 From 0d9f81f741b33e23941db435b9ba7a9ed37adaec Mon Sep 17 00:00:00 2001 From: yang-g Date: Wed, 26 Aug 2015 22:04:30 -0700 Subject: minor fixes --- include/grpc++/support/string_ref.h | 10 +++++----- src/cpp/util/string_ref.cc | 2 +- test/cpp/util/string_ref_test.cc | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/grpc++/support/string_ref.h b/include/grpc++/support/string_ref.h index fd2b3ad8e7..2bc1fecefe 100644 --- a/include/grpc++/support/string_ref.h +++ b/include/grpc++/support/string_ref.h @@ -31,8 +31,8 @@ * */ -#ifndef GRPCXX_STRING_REF_H -#define GRPCXX_STRING_REF_H +#ifndef GRPCXX_SUPPORT_STRING_REF_H +#define GRPCXX_SUPPORT_STRING_REF_H #include #include @@ -44,6 +44,8 @@ namespace grpc { // This class is a non owning reference to a string. // It should be a strict subset of the upcoming std::string_ref. See: // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3442.html +// The constexpr is dropped or replaced with const for legacy compiler +// compatibility. class string_ref { public: // types @@ -115,6 +117,4 @@ std::ostream& operator<<(std::ostream& stream, const string_ref& string); } // namespace grpc -#endif // GRPCXX_STRING_REF_H - - +#endif // GRPCXX_SUPPORT_STRING_REF_H diff --git a/src/cpp/util/string_ref.cc b/src/cpp/util/string_ref.cc index eb54f65e3a..9adc092013 100644 --- a/src/cpp/util/string_ref.cc +++ b/src/cpp/util/string_ref.cc @@ -80,7 +80,7 @@ size_t string_ref::find(string_ref s) const { } size_t string_ref::find(char c) const { - auto it = std::find_if(cbegin(), cend(), [c](char cc) { return cc == c; }); + auto it = std::find(cbegin(), cend(), c); return it == cend() ? npos : std::distance(cbegin(), it); } diff --git a/test/cpp/util/string_ref_test.cc b/test/cpp/util/string_ref_test.cc index c4ca4fce84..465072d43e 100644 --- a/test/cpp/util/string_ref_test.cc +++ b/test/cpp/util/string_ref_test.cc @@ -100,8 +100,8 @@ TEST_F(StringRefTest, Assignment) { TEST_F(StringRefTest, Iterator) { string_ref s(kTestString); size_t i = 0; - for (char c : s) { - EXPECT_EQ(kTestString[i++], c); + for (auto it = s.cbegin(); it != s.cend(); ++it) { + EXPECT_EQ(kTestString[i++], *it); } EXPECT_EQ(strlen(kTestString), i); } -- cgit v1.2.3 From 99d7b661bede39143d1be6040fb67c81b8117ae3 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 27 Aug 2015 07:36:12 -0700 Subject: Revert "Refactor Endpoint API" --- include/grpc/support/slice_buffer.h | 2 - src/core/httpcli/httpcli.c | 95 +++--- src/core/iomgr/endpoint.c | 17 +- src/core/iomgr/endpoint.h | 63 ++-- src/core/iomgr/tcp_posix.c | 525 +++++++++++++++++++---------- src/core/iomgr/tcp_windows.c | 192 +++++------ src/core/security/secure_endpoint.c | 188 +++++------ src/core/security/secure_transport_setup.c | 119 +++---- src/core/support/slice_buffer.c | 22 -- src/core/transport/chttp2/internal.h | 12 +- src/core/transport/chttp2/writing.c | 21 +- src/core/transport/chttp2_transport.c | 140 ++++---- test/core/bad_client/bad_client.c | 17 +- test/core/iomgr/endpoint_tests.c | 204 +++++------ test/core/iomgr/tcp_posix_test.c | 148 ++++---- test/core/security/secure_endpoint_test.c | 55 ++- test/core/util/port_posix.c | 14 +- test/core/util/port_windows.c | 91 +---- 18 files changed, 978 insertions(+), 947 deletions(-) (limited to 'include') diff --git a/include/grpc/support/slice_buffer.h b/include/grpc/support/slice_buffer.h index 04db003ac5..ec048e8c91 100644 --- a/include/grpc/support/slice_buffer.h +++ b/include/grpc/support/slice_buffer.h @@ -86,8 +86,6 @@ void gpr_slice_buffer_reset_and_unref(gpr_slice_buffer *sb); void gpr_slice_buffer_swap(gpr_slice_buffer *a, gpr_slice_buffer *b); /* move all of the elements of src into dst */ void gpr_slice_buffer_move_into(gpr_slice_buffer *src, gpr_slice_buffer *dst); -/* remove n bytes from the end of a slice buffer */ -void gpr_slice_buffer_trim_end(gpr_slice_buffer *src, size_t n); #ifdef __cplusplus } diff --git a/src/core/httpcli/httpcli.c b/src/core/httpcli/httpcli.c index 1e38479eb1..9012070e8e 100644 --- a/src/core/httpcli/httpcli.c +++ b/src/core/httpcli/httpcli.c @@ -61,10 +61,6 @@ typedef struct { grpc_httpcli_context *context; grpc_pollset *pollset; grpc_iomgr_object iomgr_obj; - gpr_slice_buffer incoming; - gpr_slice_buffer outgoing; - grpc_iomgr_closure on_read; - grpc_iomgr_closure done_write; } internal_request; static grpc_httpcli_get_override g_get_override = NULL; @@ -103,70 +99,73 @@ static void finish(internal_request *req, int success) { gpr_slice_unref(req->request_text); gpr_free(req->host); grpc_iomgr_unregister_object(&req->iomgr_obj); - gpr_slice_buffer_destroy(&req->incoming); - gpr_slice_buffer_destroy(&req->outgoing); gpr_free(req); } -static void on_read(void *user_data, int success); - -static void do_read(internal_request *req) { - switch (grpc_endpoint_read(req->ep, &req->incoming, &req->on_read)) { - case GRPC_ENDPOINT_DONE: - on_read(req, 1); - break; - case GRPC_ENDPOINT_PENDING: - break; - case GRPC_ENDPOINT_ERROR: - on_read(req, 0); - break; - } -} - -static void on_read(void *user_data, int success) { +static void on_read(void *user_data, gpr_slice *slices, size_t nslices, + grpc_endpoint_cb_status status) { internal_request *req = user_data; size_t i; - for (i = 0; i < req->incoming.count; i++) { - if (GPR_SLICE_LENGTH(req->incoming.slices[i])) { + for (i = 0; i < nslices; i++) { + if (GPR_SLICE_LENGTH(slices[i])) { req->have_read_byte = 1; - if (!grpc_httpcli_parser_parse(&req->parser, req->incoming.slices[i])) { + if (!grpc_httpcli_parser_parse(&req->parser, slices[i])) { finish(req, 0); - return; + goto done; } } } - if (success) { - do_read(req); - } else if (!req->have_read_byte) { - next_address(req); - } else { - finish(req, grpc_httpcli_parser_eof(&req->parser)); + switch (status) { + case GRPC_ENDPOINT_CB_OK: + grpc_endpoint_notify_on_read(req->ep, on_read, req); + break; + case GRPC_ENDPOINT_CB_EOF: + case GRPC_ENDPOINT_CB_ERROR: + case GRPC_ENDPOINT_CB_SHUTDOWN: + if (!req->have_read_byte) { + next_address(req); + } else { + finish(req, grpc_httpcli_parser_eof(&req->parser)); + } + break; + } + +done: + for (i = 0; i < nslices; i++) { + gpr_slice_unref(slices[i]); } } -static void on_written(internal_request *req) { do_read(req); } +static void on_written(internal_request *req) { + grpc_endpoint_notify_on_read(req->ep, on_read, req); +} -static void done_write(void *arg, int success) { +static void done_write(void *arg, grpc_endpoint_cb_status status) { internal_request *req = arg; - if (success) { - on_written(req); - } else { - next_address(req); + switch (status) { + case GRPC_ENDPOINT_CB_OK: + on_written(req); + break; + case GRPC_ENDPOINT_CB_EOF: + case GRPC_ENDPOINT_CB_SHUTDOWN: + case GRPC_ENDPOINT_CB_ERROR: + next_address(req); + break; } } static void start_write(internal_request *req) { gpr_slice_ref(req->request_text); - gpr_slice_buffer_add(&req->outgoing, req->request_text); - switch (grpc_endpoint_write(req->ep, &req->outgoing, &req->done_write)) { - case GRPC_ENDPOINT_DONE: + switch ( + grpc_endpoint_write(req->ep, &req->request_text, 1, done_write, req)) { + case GRPC_ENDPOINT_WRITE_DONE: on_written(req); break; - case GRPC_ENDPOINT_PENDING: + case GRPC_ENDPOINT_WRITE_PENDING: break; - case GRPC_ENDPOINT_ERROR: + case GRPC_ENDPOINT_WRITE_ERROR: finish(req, 0); break; } @@ -238,10 +237,6 @@ void grpc_httpcli_get(grpc_httpcli_context *context, grpc_pollset *pollset, request->handshaker ? request->handshaker : &grpc_httpcli_plaintext; req->context = context; req->pollset = pollset; - grpc_iomgr_closure_init(&req->on_read, on_read, req); - grpc_iomgr_closure_init(&req->done_write, done_write, req); - gpr_slice_buffer_init(&req->incoming); - gpr_slice_buffer_init(&req->outgoing); gpr_asprintf(&name, "HTTP:GET:%s:%s", request->host, request->path); grpc_iomgr_register_object(&req->iomgr_obj, name); gpr_free(name); @@ -275,11 +270,7 @@ void grpc_httpcli_post(grpc_httpcli_context *context, grpc_pollset *pollset, request->handshaker ? request->handshaker : &grpc_httpcli_plaintext; req->context = context; req->pollset = pollset; - grpc_iomgr_closure_init(&req->on_read, on_read, req); - grpc_iomgr_closure_init(&req->done_write, done_write, req); - gpr_slice_buffer_init(&req->incoming); - gpr_slice_buffer_init(&req->outgoing); - gpr_asprintf(&name, "HTTP:POST:%s:%s", request->host, request->path); + gpr_asprintf(&name, "HTTP:GET:%s:%s", request->host, request->path); grpc_iomgr_register_object(&req->iomgr_obj, name); gpr_free(name); req->host = gpr_strdup(request->host); diff --git a/src/core/iomgr/endpoint.c b/src/core/iomgr/endpoint.c index a7878e31dd..8ee14bce9b 100644 --- a/src/core/iomgr/endpoint.c +++ b/src/core/iomgr/endpoint.c @@ -33,16 +33,17 @@ #include "src/core/iomgr/endpoint.h" -grpc_endpoint_op_status grpc_endpoint_read(grpc_endpoint *ep, - gpr_slice_buffer *slices, - grpc_iomgr_closure *cb) { - return ep->vtable->read(ep, slices, cb); +void grpc_endpoint_notify_on_read(grpc_endpoint *ep, grpc_endpoint_read_cb cb, + void *user_data) { + ep->vtable->notify_on_read(ep, cb, user_data); } -grpc_endpoint_op_status grpc_endpoint_write(grpc_endpoint *ep, - gpr_slice_buffer *slices, - grpc_iomgr_closure *cb) { - return ep->vtable->write(ep, slices, cb); +grpc_endpoint_write_status grpc_endpoint_write(grpc_endpoint *ep, + gpr_slice *slices, + size_t nslices, + grpc_endpoint_write_cb cb, + void *user_data) { + return ep->vtable->write(ep, slices, nslices, cb, user_data); } void grpc_endpoint_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset) { diff --git a/src/core/iomgr/endpoint.h b/src/core/iomgr/endpoint.h index d14d52d561..ea92a500e8 100644 --- a/src/core/iomgr/endpoint.h +++ b/src/core/iomgr/endpoint.h @@ -37,7 +37,6 @@ #include "src/core/iomgr/pollset.h" #include "src/core/iomgr/pollset_set.h" #include -#include #include /* An endpoint caps a streaming channel between two communicating processes. @@ -46,17 +45,31 @@ typedef struct grpc_endpoint grpc_endpoint; typedef struct grpc_endpoint_vtable grpc_endpoint_vtable; -typedef enum grpc_endpoint_op_status { - GRPC_ENDPOINT_DONE, /* completed immediately, cb won't be called */ - GRPC_ENDPOINT_PENDING, /* cb will be called when completed */ - GRPC_ENDPOINT_ERROR /* write errored out, cb won't be called */ -} grpc_endpoint_op_status; +typedef enum grpc_endpoint_cb_status { + GRPC_ENDPOINT_CB_OK = 0, /* Call completed successfully */ + GRPC_ENDPOINT_CB_EOF, /* Call completed successfully, end of file reached */ + GRPC_ENDPOINT_CB_SHUTDOWN, /* Call interrupted by shutdown */ + GRPC_ENDPOINT_CB_ERROR /* Call interrupted by socket error */ +} grpc_endpoint_cb_status; + +typedef enum grpc_endpoint_write_status { + GRPC_ENDPOINT_WRITE_DONE, /* completed immediately, cb won't be called */ + GRPC_ENDPOINT_WRITE_PENDING, /* cb will be called when completed */ + GRPC_ENDPOINT_WRITE_ERROR /* write errored out, cb won't be called */ +} grpc_endpoint_write_status; + +typedef void (*grpc_endpoint_read_cb)(void *user_data, gpr_slice *slices, + size_t nslices, + grpc_endpoint_cb_status error); +typedef void (*grpc_endpoint_write_cb)(void *user_data, + grpc_endpoint_cb_status error); struct grpc_endpoint_vtable { - grpc_endpoint_op_status (*read)(grpc_endpoint *ep, gpr_slice_buffer *slices, - grpc_iomgr_closure *cb); - grpc_endpoint_op_status (*write)(grpc_endpoint *ep, gpr_slice_buffer *slices, - grpc_iomgr_closure *cb); + void (*notify_on_read)(grpc_endpoint *ep, grpc_endpoint_read_cb cb, + void *user_data); + grpc_endpoint_write_status (*write)(grpc_endpoint *ep, gpr_slice *slices, + size_t nslices, grpc_endpoint_write_cb cb, + void *user_data); void (*add_to_pollset)(grpc_endpoint *ep, grpc_pollset *pollset); void (*add_to_pollset_set)(grpc_endpoint *ep, grpc_pollset_set *pollset); void (*shutdown)(grpc_endpoint *ep); @@ -64,32 +77,26 @@ struct grpc_endpoint_vtable { char *(*get_peer)(grpc_endpoint *ep); }; -/* When data is available on the connection, calls the callback with slices. - Callback success indicates that the endpoint can accept more reads, failure - indicates the endpoint is closed. - Valid slices may be placed into \a slices even on callback success == 0. */ -grpc_endpoint_op_status grpc_endpoint_read( - grpc_endpoint *ep, gpr_slice_buffer *slices, - grpc_iomgr_closure *cb) GRPC_MUST_USE_RESULT; +/* When data is available on the connection, calls the callback with slices. */ +void grpc_endpoint_notify_on_read(grpc_endpoint *ep, grpc_endpoint_read_cb cb, + void *user_data); char *grpc_endpoint_get_peer(grpc_endpoint *ep); /* Write slices out to the socket. If the connection is ready for more data after the end of the call, it - returns GRPC_ENDPOINT_DONE. - Otherwise it returns GRPC_ENDPOINT_PENDING and calls cb when the - connection is ready for more data. - \a slices may be mutated at will by the endpoint until cb is called. - No guarantee is made to the content of slices after a write EXCEPT that - it is a valid slice buffer. - */ -grpc_endpoint_op_status grpc_endpoint_write( - grpc_endpoint *ep, gpr_slice_buffer *slices, - grpc_iomgr_closure *cb) GRPC_MUST_USE_RESULT; + returns GRPC_ENDPOINT_WRITE_DONE. + Otherwise it returns GRPC_ENDPOINT_WRITE_PENDING and calls cb when the + connection is ready for more data. */ +grpc_endpoint_write_status grpc_endpoint_write(grpc_endpoint *ep, + gpr_slice *slices, + size_t nslices, + grpc_endpoint_write_cb cb, + void *user_data); /* Causes any pending read/write callbacks to run immediately with - success==0 */ + GRPC_ENDPOINT_CB_SHUTDOWN status */ void grpc_endpoint_shutdown(grpc_endpoint *ep); void grpc_endpoint_destroy(grpc_endpoint *ep); diff --git a/src/core/iomgr/tcp_posix.c b/src/core/iomgr/tcp_posix.c index 0db7cd9f0e..360e6ebd8c 100644 --- a/src/core/iomgr/tcp_posix.c +++ b/src/core/iomgr/tcp_posix.c @@ -61,8 +61,209 @@ #define SENDMSG_FLAGS 0 #endif +/* Holds a slice array and associated state. */ +typedef struct grpc_tcp_slice_state { + gpr_slice *slices; /* Array of slices */ + size_t nslices; /* Size of slices array. */ + ssize_t first_slice; /* First valid slice in array */ + ssize_t last_slice; /* Last valid slice in array */ + gpr_slice working_slice; /* pointer to original final slice */ + int working_slice_valid; /* True if there is a working slice */ + int memory_owned; /* True if slices array is owned */ +} grpc_tcp_slice_state; + int grpc_tcp_trace = 0; +static void slice_state_init(grpc_tcp_slice_state *state, gpr_slice *slices, + size_t nslices, size_t valid_slices) { + state->slices = slices; + state->nslices = nslices; + if (valid_slices == 0) { + state->first_slice = -1; + } else { + state->first_slice = 0; + } + state->last_slice = valid_slices - 1; + state->working_slice_valid = 0; + state->memory_owned = 0; +} + +/* Returns true if there is still available data */ +static int slice_state_has_available(grpc_tcp_slice_state *state) { + return state->first_slice != -1 && state->last_slice >= state->first_slice; +} + +static ssize_t slice_state_slices_allocated(grpc_tcp_slice_state *state) { + if (state->first_slice == -1) { + return 0; + } else { + return state->last_slice - state->first_slice + 1; + } +} + +static void slice_state_realloc(grpc_tcp_slice_state *state, size_t new_size) { + /* TODO(klempner): use realloc instead when first_slice is 0 */ + /* TODO(klempner): Avoid a realloc in cases where it is unnecessary */ + gpr_slice *slices = state->slices; + size_t original_size = slice_state_slices_allocated(state); + size_t i; + gpr_slice *new_slices = gpr_malloc(sizeof(gpr_slice) * new_size); + + for (i = 0; i < original_size; ++i) { + new_slices[i] = slices[i + state->first_slice]; + } + + state->slices = new_slices; + state->last_slice = original_size - 1; + if (original_size > 0) { + state->first_slice = 0; + } else { + state->first_slice = -1; + } + state->nslices = new_size; + + if (state->memory_owned) { + gpr_free(slices); + } + state->memory_owned = 1; +} + +static void slice_state_remove_prefix(grpc_tcp_slice_state *state, + size_t prefix_bytes) { + gpr_slice *current_slice = &state->slices[state->first_slice]; + size_t current_slice_size; + + while (slice_state_has_available(state)) { + current_slice_size = GPR_SLICE_LENGTH(*current_slice); + if (current_slice_size > prefix_bytes) { + /* TODO(klempner): Get rid of the extra refcount created here by adding a + native "trim the first N bytes" operation to splice */ + /* TODO(klempner): This really shouldn't be modifying the current slice + unless we own the slices array. */ + gpr_slice tail; + tail = gpr_slice_split_tail(current_slice, prefix_bytes); + gpr_slice_unref(*current_slice); + *current_slice = tail; + return; + } else { + gpr_slice_unref(*current_slice); + ++state->first_slice; + ++current_slice; + prefix_bytes -= current_slice_size; + } + } +} + +static void slice_state_destroy(grpc_tcp_slice_state *state) { + while (slice_state_has_available(state)) { + gpr_slice_unref(state->slices[state->first_slice]); + ++state->first_slice; + } + + if (state->memory_owned) { + gpr_free(state->slices); + state->memory_owned = 0; + } +} + +void slice_state_transfer_ownership(grpc_tcp_slice_state *state, + gpr_slice **slices, size_t *nslices) { + *slices = state->slices + state->first_slice; + *nslices = state->last_slice - state->first_slice + 1; + + state->first_slice = -1; + state->last_slice = -1; +} + +/* Fills iov with the first min(iov_size, available) slices, returns number + filled */ +static size_t slice_state_to_iovec(grpc_tcp_slice_state *state, + struct iovec *iov, size_t iov_size) { + size_t nslices = state->last_slice - state->first_slice + 1; + gpr_slice *slices = state->slices + state->first_slice; + size_t i; + if (nslices < iov_size) { + iov_size = nslices; + } + + for (i = 0; i < iov_size; ++i) { + iov[i].iov_base = GPR_SLICE_START_PTR(slices[i]); + iov[i].iov_len = GPR_SLICE_LENGTH(slices[i]); + } + return iov_size; +} + +/* Makes n blocks available at the end of state, writes them into iov, and + returns the number of bytes allocated */ +static size_t slice_state_append_blocks_into_iovec(grpc_tcp_slice_state *state, + struct iovec *iov, size_t n, + size_t slice_size) { + size_t target_size; + size_t i; + size_t allocated_bytes; + ssize_t allocated_slices = slice_state_slices_allocated(state); + + if (n - state->working_slice_valid >= state->nslices - state->last_slice) { + /* Need to grow the slice array */ + target_size = state->nslices; + do { + target_size = target_size * 2; + } while (target_size < allocated_slices + n - state->working_slice_valid); + /* TODO(klempner): If this ever needs to support both prefix removal and + append, we should be smarter about the growth logic here */ + slice_state_realloc(state, target_size); + } + + i = 0; + allocated_bytes = 0; + + if (state->working_slice_valid) { + iov[0].iov_base = GPR_SLICE_END_PTR(state->slices[state->last_slice]); + iov[0].iov_len = GPR_SLICE_LENGTH(state->working_slice) - + GPR_SLICE_LENGTH(state->slices[state->last_slice]); + allocated_bytes += iov[0].iov_len; + ++i; + state->slices[state->last_slice] = state->working_slice; + state->working_slice_valid = 0; + } + + for (; i < n; ++i) { + ++state->last_slice; + state->slices[state->last_slice] = gpr_slice_malloc(slice_size); + iov[i].iov_base = GPR_SLICE_START_PTR(state->slices[state->last_slice]); + iov[i].iov_len = slice_size; + allocated_bytes += slice_size; + } + if (state->first_slice == -1) { + state->first_slice = 0; + } + return allocated_bytes; +} + +/* Remove the last n bytes from state */ +/* TODO(klempner): Consider having this defer actual deletion until later */ +static void slice_state_remove_last(grpc_tcp_slice_state *state, size_t bytes) { + while (bytes > 0 && slice_state_has_available(state)) { + if (GPR_SLICE_LENGTH(state->slices[state->last_slice]) > bytes) { + state->working_slice = state->slices[state->last_slice]; + state->working_slice_valid = 1; + /* TODO(klempner): Combine these into a single operation that doesn't need + to refcount */ + gpr_slice_unref(gpr_slice_split_tail( + &state->slices[state->last_slice], + GPR_SLICE_LENGTH(state->slices[state->last_slice]) - bytes)); + bytes = 0; + } else { + bytes -= GPR_SLICE_LENGTH(state->slices[state->last_slice]); + gpr_slice_unref(state->slices[state->last_slice]); + --state->last_slice; + if (state->last_slice == -1) { + state->first_slice = -1; + } + } + } +} + typedef struct { grpc_endpoint base; grpc_fd *em_fd; @@ -72,111 +273,80 @@ typedef struct { size_t slice_size; gpr_refcount refcount; - gpr_slice_buffer *incoming_buffer; - gpr_slice_buffer *outgoing_buffer; - /** slice within outgoing_buffer to write next */ - size_t outgoing_slice_idx; - /** byte within outgoing_buffer->slices[outgoing_slice_idx] to write next */ - size_t outgoing_byte_idx; + grpc_endpoint_read_cb read_cb; + void *read_user_data; + grpc_endpoint_write_cb write_cb; + void *write_user_data; - grpc_iomgr_closure *read_cb; - grpc_iomgr_closure *write_cb; + grpc_tcp_slice_state write_state; grpc_iomgr_closure read_closure; grpc_iomgr_closure write_closure; + grpc_iomgr_closure handle_read_closure; + char *peer_string; } grpc_tcp; -static void tcp_handle_read(void *arg /* grpc_tcp */, int success); -static void tcp_handle_write(void *arg /* grpc_tcp */, int success); +static void grpc_tcp_handle_read(void *arg /* grpc_tcp */, int success); +static void grpc_tcp_handle_write(void *arg /* grpc_tcp */, int success); -static void tcp_shutdown(grpc_endpoint *ep) { +static void grpc_tcp_shutdown(grpc_endpoint *ep) { grpc_tcp *tcp = (grpc_tcp *)ep; grpc_fd_shutdown(tcp->em_fd); } -static void tcp_free(grpc_tcp *tcp) { - grpc_fd_orphan(tcp->em_fd, NULL, "tcp_unref_orphan"); - gpr_free(tcp->peer_string); - gpr_free(tcp); -} - -/*#define GRPC_TCP_REFCOUNT_DEBUG*/ -#ifdef GRPC_TCP_REFCOUNT_DEBUG -#define TCP_UNREF(tcp, reason) tcp_unref((tcp), (reason), __FILE__, __LINE__) -#define TCP_REF(tcp, reason) tcp_ref((tcp), (reason), __FILE__, __LINE__) -static void tcp_unref(grpc_tcp *tcp, const char *reason, const char *file, - int line) { - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP unref %p : %s %d -> %d", tcp, - reason, tcp->refcount.count, tcp->refcount.count - 1); - if (gpr_unref(&tcp->refcount)) { - tcp_free(tcp); +static void grpc_tcp_unref(grpc_tcp *tcp) { + int refcount_zero = gpr_unref(&tcp->refcount); + if (refcount_zero) { + grpc_fd_orphan(tcp->em_fd, NULL, "tcp_unref_orphan"); + gpr_free(tcp->peer_string); + gpr_free(tcp); } } -static void tcp_ref(grpc_tcp *tcp, const char *reason, const char *file, - int line) { - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP ref %p : %s %d -> %d", tcp, - reason, tcp->refcount.count, tcp->refcount.count + 1); - gpr_ref(&tcp->refcount); -} -#else -#define TCP_UNREF(tcp, reason) tcp_unref((tcp)) -#define TCP_REF(tcp, reason) tcp_ref((tcp)) -static void tcp_unref(grpc_tcp *tcp) { - if (gpr_unref(&tcp->refcount)) { - tcp_free(tcp); - } -} - -static void tcp_ref(grpc_tcp *tcp) { gpr_ref(&tcp->refcount); } -#endif - -static void tcp_destroy(grpc_endpoint *ep) { +static void grpc_tcp_destroy(grpc_endpoint *ep) { grpc_tcp *tcp = (grpc_tcp *)ep; - TCP_UNREF(tcp, "destroy"); + grpc_tcp_unref(tcp); } -static void call_read_cb(grpc_tcp *tcp, int success) { - grpc_iomgr_closure *cb = tcp->read_cb; +static void call_read_cb(grpc_tcp *tcp, gpr_slice *slices, size_t nslices, + grpc_endpoint_cb_status status) { + grpc_endpoint_read_cb cb = tcp->read_cb; if (grpc_tcp_trace) { size_t i; - gpr_log(GPR_DEBUG, "read: success=%d", success); - for (i = 0; i < tcp->incoming_buffer->count; i++) { - char *dump = gpr_dump_slice(tcp->incoming_buffer->slices[i], - GPR_DUMP_HEX | GPR_DUMP_ASCII); + gpr_log(GPR_DEBUG, "read: status=%d", status); + for (i = 0; i < nslices; i++) { + char *dump = gpr_dump_slice(slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII); gpr_log(GPR_DEBUG, "READ %p: %s", tcp, dump); gpr_free(dump); } } tcp->read_cb = NULL; - tcp->incoming_buffer = NULL; - cb->cb(cb->cb_arg, success); + cb(tcp->read_user_data, slices, nslices, status); } +#define INLINE_SLICE_BUFFER_SIZE 8 #define MAX_READ_IOVEC 4 -static void tcp_continue_read(grpc_tcp *tcp) { +static void grpc_tcp_continue_read(grpc_tcp *tcp) { + gpr_slice static_read_slices[INLINE_SLICE_BUFFER_SIZE]; struct msghdr msg; struct iovec iov[MAX_READ_IOVEC]; ssize_t read_bytes; - size_t i; + ssize_t allocated_bytes; + struct grpc_tcp_slice_state read_state; + gpr_slice *final_slices; + size_t final_nslices; GPR_ASSERT(!tcp->finished_edge); - GPR_ASSERT(tcp->iov_size <= MAX_READ_IOVEC); - GPR_ASSERT(tcp->incoming_buffer->count <= MAX_READ_IOVEC); GRPC_TIMER_BEGIN(GRPC_PTAG_HANDLE_READ, 0); + slice_state_init(&read_state, static_read_slices, INLINE_SLICE_BUFFER_SIZE, + 0); - while (tcp->incoming_buffer->count < (size_t)tcp->iov_size) { - gpr_slice_buffer_add_indexed(tcp->incoming_buffer, - gpr_slice_malloc(tcp->slice_size)); - } - for (i = 0; i < tcp->incoming_buffer->count; i++) { - iov[i].iov_base = GPR_SLICE_START_PTR(tcp->incoming_buffer->slices[i]); - iov[i].iov_len = GPR_SLICE_LENGTH(tcp->incoming_buffer->slices[i]); - } + allocated_bytes = slice_state_append_blocks_into_iovec( + &read_state, iov, tcp->iov_size, tcp->slice_size); msg.msg_name = NULL; msg.msg_namelen = 0; @@ -192,105 +362,106 @@ static void tcp_continue_read(grpc_tcp *tcp) { } while (read_bytes < 0 && errno == EINTR); GRPC_TIMER_END(GRPC_PTAG_RECVMSG, 0); + if (read_bytes < allocated_bytes) { + /* TODO(klempner): Consider a second read first, in hopes of getting a + * quick EAGAIN and saving a bunch of allocations. */ + slice_state_remove_last(&read_state, read_bytes < 0 + ? allocated_bytes + : allocated_bytes - read_bytes); + } + if (read_bytes < 0) { - /* NB: After calling call_read_cb a parallel call of the read handler may + /* NB: After calling the user_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(tcp->em_fd, &tcp->read_closure); + if (slice_state_has_available(&read_state)) { + /* TODO(klempner): We should probably do the call into the application + without all this junk on the stack */ + /* FIXME(klempner): Refcount properly */ + slice_state_transfer_ownership(&read_state, &final_slices, + &final_nslices); + tcp->finished_edge = 1; + call_read_cb(tcp, final_slices, final_nslices, GRPC_ENDPOINT_CB_OK); + slice_state_destroy(&read_state); + grpc_tcp_unref(tcp); + } else { + /* We've consumed the edge, request a new one */ + slice_state_destroy(&read_state); + grpc_fd_notify_on_read(tcp->em_fd, &tcp->read_closure); + } } else { /* TODO(klempner): Log interesting errors */ - gpr_slice_buffer_reset_and_unref(tcp->incoming_buffer); - call_read_cb(tcp, 0); - TCP_UNREF(tcp, "read"); + call_read_cb(tcp, NULL, 0, GRPC_ENDPOINT_CB_ERROR); + slice_state_destroy(&read_state); + grpc_tcp_unref(tcp); } } else if (read_bytes == 0) { /* 0 read size ==> end of stream */ - gpr_slice_buffer_reset_and_unref(tcp->incoming_buffer); - call_read_cb(tcp, 0); - TCP_UNREF(tcp, "read"); + if (slice_state_has_available(&read_state)) { + /* there were bytes already read: pass them up to the application */ + slice_state_transfer_ownership(&read_state, &final_slices, + &final_nslices); + call_read_cb(tcp, final_slices, final_nslices, GRPC_ENDPOINT_CB_EOF); + } else { + call_read_cb(tcp, NULL, 0, GRPC_ENDPOINT_CB_EOF); + } + slice_state_destroy(&read_state); + grpc_tcp_unref(tcp); } else { - GPR_ASSERT((size_t)read_bytes <= tcp->incoming_buffer->length); - if ((size_t)read_bytes < tcp->incoming_buffer->length) { - gpr_slice_buffer_trim_end(tcp->incoming_buffer, - tcp->incoming_buffer->length - read_bytes); - } else if (tcp->iov_size < MAX_READ_IOVEC) { + if (tcp->iov_size < MAX_READ_IOVEC) { ++tcp->iov_size; } - GPR_ASSERT((size_t)read_bytes == tcp->incoming_buffer->length); - call_read_cb(tcp, 1); - TCP_UNREF(tcp, "read"); + GPR_ASSERT(slice_state_has_available(&read_state)); + slice_state_transfer_ownership(&read_state, &final_slices, &final_nslices); + call_read_cb(tcp, final_slices, final_nslices, GRPC_ENDPOINT_CB_OK); + slice_state_destroy(&read_state); + grpc_tcp_unref(tcp); } GRPC_TIMER_END(GRPC_PTAG_HANDLE_READ, 0); } -static void tcp_handle_read(void *arg /* grpc_tcp */, int success) { +static void grpc_tcp_handle_read(void *arg /* grpc_tcp */, int success) { grpc_tcp *tcp = (grpc_tcp *)arg; GPR_ASSERT(!tcp->finished_edge); if (!success) { - gpr_slice_buffer_reset_and_unref(tcp->incoming_buffer); - call_read_cb(tcp, 0); - TCP_UNREF(tcp, "read"); + call_read_cb(tcp, NULL, 0, GRPC_ENDPOINT_CB_SHUTDOWN); + grpc_tcp_unref(tcp); } else { - tcp_continue_read(tcp); + grpc_tcp_continue_read(tcp); } } -static grpc_endpoint_op_status tcp_read(grpc_endpoint *ep, - gpr_slice_buffer *incoming_buffer, - grpc_iomgr_closure *cb) { +static void grpc_tcp_notify_on_read(grpc_endpoint *ep, grpc_endpoint_read_cb cb, + void *user_data) { grpc_tcp *tcp = (grpc_tcp *)ep; GPR_ASSERT(tcp->read_cb == NULL); tcp->read_cb = cb; - tcp->incoming_buffer = incoming_buffer; - gpr_slice_buffer_reset_and_unref(incoming_buffer); - TCP_REF(tcp, "read"); + tcp->read_user_data = user_data; + gpr_ref(&tcp->refcount); if (tcp->finished_edge) { tcp->finished_edge = 0; grpc_fd_notify_on_read(tcp->em_fd, &tcp->read_closure); } else { - grpc_iomgr_add_delayed_callback(&tcp->read_closure, 1); + tcp->handle_read_closure.cb_arg = tcp; + grpc_iomgr_add_delayed_callback(&tcp->handle_read_closure, 1); } - /* TODO(ctiller): immediate return */ - return GRPC_ENDPOINT_PENDING; } #define MAX_WRITE_IOVEC 16 -static grpc_endpoint_op_status tcp_flush(grpc_tcp *tcp) { +static grpc_endpoint_write_status grpc_tcp_flush(grpc_tcp *tcp) { struct msghdr msg; struct iovec iov[MAX_WRITE_IOVEC]; int iov_size; ssize_t sent_length; - ssize_t sending_length; - ssize_t trailing; - ssize_t unwind_slice_idx; - ssize_t unwind_byte_idx; + grpc_tcp_slice_state *state = &tcp->write_state; 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 = - GPR_SLICE_START_PTR( - tcp->outgoing_buffer->slices[tcp->outgoing_slice_idx]) + - tcp->outgoing_byte_idx; - iov[iov_size].iov_len = - GPR_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); + iov_size = slice_state_to_iovec(state, iov, MAX_WRITE_IOVEC); msg.msg_name = NULL; msg.msg_namelen = 0; @@ -309,75 +480,70 @@ static grpc_endpoint_op_status tcp_flush(grpc_tcp *tcp) { if (sent_length < 0) { if (errno == EAGAIN) { - tcp->outgoing_slice_idx = unwind_slice_idx; - tcp->outgoing_byte_idx = unwind_byte_idx; - return GRPC_ENDPOINT_PENDING; + return GRPC_ENDPOINT_WRITE_PENDING; } else { /* TODO(klempner): Log some of these */ - return GRPC_ENDPOINT_ERROR; + slice_state_destroy(state); + return GRPC_ENDPOINT_WRITE_ERROR; } } - GPR_ASSERT(tcp->outgoing_byte_idx == 0); - trailing = sending_length - sent_length; - while (trailing > 0) { - ssize_t slice_length; - - tcp->outgoing_slice_idx--; - slice_length = GPR_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; - } - } + /* TODO(klempner): Probably better to batch this after we finish flushing */ + slice_state_remove_prefix(state, sent_length); - if (tcp->outgoing_slice_idx == tcp->outgoing_buffer->count) { - return GRPC_ENDPOINT_DONE; + if (!slice_state_has_available(state)) { + return GRPC_ENDPOINT_WRITE_DONE; } }; } -static void tcp_handle_write(void *arg /* grpc_tcp */, int success) { +static void grpc_tcp_handle_write(void *arg /* grpc_tcp */, int success) { grpc_tcp *tcp = (grpc_tcp *)arg; - grpc_endpoint_op_status status; - grpc_iomgr_closure *cb; + grpc_endpoint_write_status write_status; + grpc_endpoint_cb_status cb_status; + grpc_endpoint_write_cb cb; if (!success) { + slice_state_destroy(&tcp->write_state); cb = tcp->write_cb; tcp->write_cb = NULL; - cb->cb(cb->cb_arg, 0); - TCP_UNREF(tcp, "write"); + cb(tcp->write_user_data, GRPC_ENDPOINT_CB_SHUTDOWN); + grpc_tcp_unref(tcp); return; } GRPC_TIMER_BEGIN(GRPC_PTAG_TCP_CB_WRITE, 0); - status = tcp_flush(tcp); - if (status == GRPC_ENDPOINT_PENDING) { + write_status = grpc_tcp_flush(tcp); + if (write_status == GRPC_ENDPOINT_WRITE_PENDING) { grpc_fd_notify_on_write(tcp->em_fd, &tcp->write_closure); } else { + slice_state_destroy(&tcp->write_state); + if (write_status == GRPC_ENDPOINT_WRITE_DONE) { + cb_status = GRPC_ENDPOINT_CB_OK; + } else { + cb_status = GRPC_ENDPOINT_CB_ERROR; + } cb = tcp->write_cb; tcp->write_cb = NULL; - cb->cb(cb->cb_arg, status == GRPC_ENDPOINT_DONE); - TCP_UNREF(tcp, "write"); + cb(tcp->write_user_data, cb_status); + grpc_tcp_unref(tcp); } GRPC_TIMER_END(GRPC_PTAG_TCP_CB_WRITE, 0); } -static grpc_endpoint_op_status tcp_write(grpc_endpoint *ep, - gpr_slice_buffer *buf, - grpc_iomgr_closure *cb) { +static grpc_endpoint_write_status grpc_tcp_write(grpc_endpoint *ep, + gpr_slice *slices, + size_t nslices, + grpc_endpoint_write_cb cb, + void *user_data) { grpc_tcp *tcp = (grpc_tcp *)ep; - grpc_endpoint_op_status status; + grpc_endpoint_write_status status; if (grpc_tcp_trace) { size_t i; - for (i = 0; i < buf->count; i++) { - char *data = - gpr_dump_slice(buf->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII); + for (i = 0; i < nslices; i++) { + char *data = gpr_dump_slice(slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII); gpr_log(GPR_DEBUG, "WRITE %p: %s", tcp, data); gpr_free(data); } @@ -385,19 +551,15 @@ static grpc_endpoint_op_status tcp_write(grpc_endpoint *ep, GRPC_TIMER_BEGIN(GRPC_PTAG_TCP_WRITE, 0); GPR_ASSERT(tcp->write_cb == NULL); + slice_state_init(&tcp->write_state, slices, nslices, nslices); - if (buf->length == 0) { - GRPC_TIMER_END(GRPC_PTAG_TCP_WRITE, 0); - return GRPC_ENDPOINT_DONE; - } - tcp->outgoing_buffer = buf; - tcp->outgoing_slice_idx = 0; - tcp->outgoing_byte_idx = 0; - - status = tcp_flush(tcp); - if (status == GRPC_ENDPOINT_PENDING) { - TCP_REF(tcp, "write"); + status = grpc_tcp_flush(tcp); + if (status == GRPC_ENDPOINT_WRITE_PENDING) { + /* TODO(klempner): Consider inlining rather than malloc for small nslices */ + slice_state_realloc(&tcp->write_state, nslices); + gpr_ref(&tcp->refcount); tcp->write_cb = cb; + tcp->write_user_data = user_data; grpc_fd_notify_on_write(tcp->em_fd, &tcp->write_closure); } @@ -405,25 +567,27 @@ static grpc_endpoint_op_status tcp_write(grpc_endpoint *ep, return status; } -static void tcp_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset) { +static void grpc_tcp_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset) { grpc_tcp *tcp = (grpc_tcp *)ep; grpc_pollset_add_fd(pollset, tcp->em_fd); } -static void tcp_add_to_pollset_set(grpc_endpoint *ep, - grpc_pollset_set *pollset_set) { +static void grpc_tcp_add_to_pollset_set(grpc_endpoint *ep, + grpc_pollset_set *pollset_set) { grpc_tcp *tcp = (grpc_tcp *)ep; grpc_pollset_set_add_fd(pollset_set, tcp->em_fd); } -static char *tcp_get_peer(grpc_endpoint *ep) { +static char *grpc_tcp_get_peer(grpc_endpoint *ep) { grpc_tcp *tcp = (grpc_tcp *)ep; return gpr_strdup(tcp->peer_string); } static const grpc_endpoint_vtable vtable = { - tcp_read, tcp_write, tcp_add_to_pollset, tcp_add_to_pollset_set, - tcp_shutdown, tcp_destroy, tcp_get_peer}; + grpc_tcp_notify_on_read, grpc_tcp_write, + grpc_tcp_add_to_pollset, grpc_tcp_add_to_pollset_set, + grpc_tcp_shutdown, grpc_tcp_destroy, + grpc_tcp_get_peer}; grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd, size_t slice_size, const char *peer_string) { @@ -433,18 +597,21 @@ grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd, size_t slice_size, tcp->fd = em_fd->fd; tcp->read_cb = NULL; tcp->write_cb = NULL; - tcp->incoming_buffer = NULL; + tcp->read_user_data = NULL; + tcp->write_user_data = NULL; tcp->slice_size = slice_size; tcp->iov_size = 1; tcp->finished_edge = 1; + slice_state_init(&tcp->write_state, NULL, 0, 0); /* paired with unref in grpc_tcp_destroy */ gpr_ref_init(&tcp->refcount, 1); tcp->em_fd = em_fd; - tcp->read_closure.cb = tcp_handle_read; + tcp->read_closure.cb = grpc_tcp_handle_read; tcp->read_closure.cb_arg = tcp; - tcp->write_closure.cb = tcp_handle_write; + tcp->write_closure.cb = grpc_tcp_handle_write; tcp->write_closure.cb_arg = tcp; + tcp->handle_read_closure.cb = grpc_tcp_handle_read; return &tcp->base; } diff --git a/src/core/iomgr/tcp_windows.c b/src/core/iomgr/tcp_windows.c index 58f9160ef9..901793ec43 100644 --- a/src/core/iomgr/tcp_windows.c +++ b/src/core/iomgr/tcp_windows.c @@ -82,11 +82,13 @@ typedef struct grpc_tcp { /* Refcounting how many operations are in progress. */ gpr_refcount refcount; - grpc_iomgr_closure *read_cb; - grpc_iomgr_closure *write_cb; + grpc_endpoint_read_cb read_cb; + void *read_user_data; gpr_slice read_slice; - gpr_slice_buffer *write_slices; - gpr_slice_buffer *read_slices; + + grpc_endpoint_write_cb write_cb; + void *write_user_data; + gpr_slice_buffer write_slices; /* The IO Completion Port runs from another thread. We need some mechanism to protect ourselves when requesting a shutdown. */ @@ -96,55 +98,34 @@ typedef struct grpc_tcp { char *peer_string; } grpc_tcp; -static void tcp_free(grpc_tcp *tcp) { - grpc_winsocket_orphan(tcp->socket); - gpr_mu_destroy(&tcp->mu); - gpr_free(tcp->peer_string); - gpr_free(tcp); -} - -/*#define GRPC_TCP_REFCOUNT_DEBUG*/ -#ifdef GRPC_TCP_REFCOUNT_DEBUG -#define TCP_UNREF(tcp, reason) tcp_unref((tcp), (reason), __FILE__, __LINE__) -#define TCP_REF(tcp, reason) tcp_ref((tcp), (reason), __FILE__, __LINE__) -static void tcp_unref(grpc_tcp *tcp, const char *reason, const char *file, - int line) { - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP unref %p : %s %d -> %d", tcp, - reason, tcp->refcount.count, tcp->refcount.count - 1); - if (gpr_unref(&tcp->refcount)) { - tcp_free(tcp); - } -} +static void tcp_ref(grpc_tcp *tcp) { gpr_ref(&tcp->refcount); } -static void tcp_ref(grpc_tcp *tcp, const char *reason, const char *file, - int line) { - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP ref %p : %s %d -> %d", tcp, - reason, tcp->refcount.count, tcp->refcount.count + 1); - gpr_ref(&tcp->refcount); -} -#else -#define TCP_UNREF(tcp, reason) tcp_unref((tcp)) -#define TCP_REF(tcp, reason) tcp_ref((tcp)) static void tcp_unref(grpc_tcp *tcp) { if (gpr_unref(&tcp->refcount)) { - tcp_free(tcp); + gpr_slice_buffer_destroy(&tcp->write_slices); + grpc_winsocket_orphan(tcp->socket); + gpr_mu_destroy(&tcp->mu); + gpr_free(tcp->peer_string); + gpr_free(tcp); } } -static void tcp_ref(grpc_tcp *tcp) { gpr_ref(&tcp->refcount); } -#endif - /* Asynchronous callback from the IOCP, or the background thread. */ -static int on_read(grpc_tcp *tcp, int from_iocp) { +static void on_read(void *tcpp, int from_iocp) { + grpc_tcp *tcp = (grpc_tcp *)tcpp; grpc_winsocket *socket = tcp->socket; gpr_slice sub; gpr_slice *slice = NULL; size_t nslices = 0; - int success; + grpc_endpoint_cb_status status; + grpc_endpoint_read_cb cb; grpc_winsocket_callback_info *info = &socket->read_info; + void *opaque = tcp->read_user_data; int do_abort = 0; gpr_mu_lock(&tcp->mu); + cb = tcp->read_cb; + tcp->read_cb = NULL; if (!from_iocp || tcp->shutting_down) { /* If we are here with from_iocp set to true, it means we got raced to shutting down the endpoint. No actual abort callback will happen @@ -158,7 +139,9 @@ static int on_read(grpc_tcp *tcp, int from_iocp) { tcp->socket->read_info.outstanding = 0; gpr_slice_unref(tcp->read_slice); } - return 0; + tcp_unref(tcp); + if (cb) cb(opaque, NULL, 0, GRPC_ENDPOINT_CB_SHUTDOWN); + return; } GPR_ASSERT(tcp->socket->read_info.outstanding); @@ -169,38 +152,28 @@ static int on_read(grpc_tcp *tcp, int from_iocp) { gpr_log(GPR_ERROR, "ReadFile overlapped error: %s", utf8_message); gpr_free(utf8_message); } - success = 0; gpr_slice_unref(tcp->read_slice); + status = GRPC_ENDPOINT_CB_ERROR; } else { if (info->bytes_transfered != 0) { sub = gpr_slice_sub_no_ref(tcp->read_slice, 0, info->bytes_transfered); - gpr_slice_buffer_add(tcp->read_slices, sub); - success = 1; + status = GRPC_ENDPOINT_CB_OK; + slice = ⊂ + nslices = 1; } else { gpr_slice_unref(tcp->read_slice); - success = 0; + status = GRPC_ENDPOINT_CB_EOF; } } tcp->socket->read_info.outstanding = 0; - return success; -} - -static void on_read_cb(void *tcpp, int from_iocp) { - grpc_tcp *tcp = tcpp; - grpc_iomgr_closure *cb = tcp->read_cb; - int success = on_read(tcp, from_iocp); - tcp->read_cb = NULL; - TCP_UNREF(tcp, "read"); - if (cb) { - cb->cb(cb->cb_arg, success); - } + tcp_unref(tcp); + cb(opaque, slice, nslices, status); } -static grpc_endpoint_op_status win_read(grpc_endpoint *ep, - gpr_slice_buffer *read_slices, - grpc_iomgr_closure *cb) { +static void win_notify_on_read(grpc_endpoint *ep, grpc_endpoint_read_cb cb, + void *arg) { grpc_tcp *tcp = (grpc_tcp *)ep; grpc_winsocket *handle = tcp->socket; grpc_winsocket_callback_info *info = &handle->read_info; @@ -211,15 +184,13 @@ static grpc_endpoint_op_status win_read(grpc_endpoint *ep, GPR_ASSERT(!tcp->socket->read_info.outstanding); if (tcp->shutting_down) { - return GRPC_ENDPOINT_ERROR; + cb(arg, NULL, 0, GRPC_ENDPOINT_CB_SHUTDOWN); + return; } - - TCP_REF(tcp, "read"); - + tcp_ref(tcp); tcp->socket->read_info.outstanding = 1; tcp->read_cb = cb; - tcp->read_slices = read_slices; - gpr_slice_buffer_reset_and_unref(read_slices); + tcp->read_user_data = arg; tcp->read_slice = gpr_slice_malloc(8192); @@ -233,11 +204,10 @@ static grpc_endpoint_op_status win_read(grpc_endpoint *ep, /* Did we get data immediately ? Yay. */ if (info->wsa_error != WSAEWOULDBLOCK) { - int ok; info->bytes_transfered = bytes_read; - ok = on_read(tcp, 1); - TCP_UNREF(tcp, "read"); - return ok ? GRPC_ENDPOINT_DONE : GRPC_ENDPOINT_ERROR; + /* This might heavily recurse. */ + on_read(tcp, 1); + return; } /* Otherwise, let's retry, by queuing a read. */ @@ -248,15 +218,13 @@ static grpc_endpoint_op_status win_read(grpc_endpoint *ep, if (status != 0) { int wsa_error = WSAGetLastError(); if (wsa_error != WSA_IO_PENDING) { - int ok; info->wsa_error = wsa_error; - ok = on_read(tcp, 1); - return ok ? GRPC_ENDPOINT_DONE : GRPC_ENDPOINT_ERROR; + on_read(tcp, 1); + return; } } - grpc_socket_notify_on_read(tcp->socket, on_read_cb, tcp); - return GRPC_ENDPOINT_PENDING; + grpc_socket_notify_on_read(tcp->socket, on_read, tcp); } /* Asynchronous callback from the IOCP, or the background thread. */ @@ -264,8 +232,9 @@ static void on_write(void *tcpp, int from_iocp) { grpc_tcp *tcp = (grpc_tcp *)tcpp; grpc_winsocket *handle = tcp->socket; grpc_winsocket_callback_info *info = &handle->write_info; - grpc_iomgr_closure *cb; - int success; + grpc_endpoint_cb_status status = GRPC_ENDPOINT_CB_OK; + grpc_endpoint_write_cb cb; + void *opaque = tcp->write_user_data; int do_abort = 0; gpr_mu_lock(&tcp->mu); @@ -282,11 +251,10 @@ static void on_write(void *tcpp, int from_iocp) { if (do_abort) { if (from_iocp) { tcp->socket->write_info.outstanding = 0; + gpr_slice_buffer_reset_and_unref(&tcp->write_slices); } - TCP_UNREF(tcp, "write"); - if (cb) { - cb->cb(cb->cb_arg, 0); - } + tcp_unref(tcp); + if (cb) cb(opaque, GRPC_ENDPOINT_CB_SHUTDOWN); return; } @@ -298,22 +266,23 @@ static void on_write(void *tcpp, int from_iocp) { gpr_log(GPR_ERROR, "WSASend overlapped error: %s", utf8_message); gpr_free(utf8_message); } - success = 0; + status = GRPC_ENDPOINT_CB_ERROR; } else { - GPR_ASSERT(info->bytes_transfered == tcp->write_slices->length); - success = 1; + GPR_ASSERT(info->bytes_transfered == tcp->write_slices.length); } + gpr_slice_buffer_reset_and_unref(&tcp->write_slices); tcp->socket->write_info.outstanding = 0; - TCP_UNREF(tcp, "write"); - cb->cb(cb->cb_arg, success); + tcp_unref(tcp); + cb(opaque, status); } /* Initiates a write. */ -static grpc_endpoint_op_status win_write(grpc_endpoint *ep, - gpr_slice_buffer *slices, - grpc_iomgr_closure *cb) { +static grpc_endpoint_write_status win_write(grpc_endpoint *ep, + gpr_slice *slices, size_t nslices, + grpc_endpoint_write_cb cb, + void *arg) { grpc_tcp *tcp = (grpc_tcp *)ep; grpc_winsocket *socket = tcp->socket; grpc_winsocket_callback_info *info = &socket->write_info; @@ -326,26 +295,28 @@ static grpc_endpoint_op_status win_write(grpc_endpoint *ep, GPR_ASSERT(!tcp->socket->write_info.outstanding); if (tcp->shutting_down) { - return GRPC_ENDPOINT_ERROR; + return GRPC_ENDPOINT_WRITE_ERROR; } - TCP_REF(tcp, "write"); + tcp_ref(tcp); tcp->socket->write_info.outstanding = 1; tcp->write_cb = cb; - tcp->write_slices = slices; + tcp->write_user_data = arg; + + gpr_slice_buffer_addn(&tcp->write_slices, slices, nslices); - if (tcp->write_slices->count > GPR_ARRAY_SIZE(local_buffers)) { - buffers = (WSABUF *)gpr_malloc(sizeof(WSABUF) * tcp->write_slices->count); + 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++) { - buffers[i].len = GPR_SLICE_LENGTH(tcp->write_slices->slices[i]); - buffers[i].buf = (char *)GPR_SLICE_START_PTR(tcp->write_slices->slices[i]); + for (i = 0; i < tcp->write_slices.count; i++) { + buffers[i].len = GPR_SLICE_LENGTH(tcp->write_slices.slices[i]); + buffers[i].buf = (char *)GPR_SLICE_START_PTR(tcp->write_slices.slices[i]); } /* First, let's try a synchronous, non-blocking write. */ - status = WSASend(socket->socket, buffers, tcp->write_slices->count, + status = WSASend(socket->socket, buffers, tcp->write_slices.count, &bytes_sent, 0, NULL, NULL); info->wsa_error = status == 0 ? 0 : WSAGetLastError(); @@ -353,10 +324,10 @@ static grpc_endpoint_op_status win_write(grpc_endpoint *ep, 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_endpoint_op_status ret = GRPC_ENDPOINT_ERROR; + grpc_endpoint_write_status ret = GRPC_ENDPOINT_WRITE_ERROR; if (status == 0) { - ret = GRPC_ENDPOINT_DONE; - GPR_ASSERT(bytes_sent == tcp->write_slices->length); + ret = GRPC_ENDPOINT_WRITE_DONE; + GPR_ASSERT(bytes_sent == tcp->write_slices.length); } else { if (socket->read_info.wsa_error != WSAECONNRESET) { char *utf8_message = gpr_format_message(info->wsa_error); @@ -365,31 +336,33 @@ static grpc_endpoint_op_status win_write(grpc_endpoint *ep, } } if (allocated) gpr_free(allocated); + gpr_slice_buffer_reset_and_unref(&tcp->write_slices); tcp->socket->write_info.outstanding = 0; - TCP_UNREF(tcp, "write"); + tcp_unref(tcp); return ret; } /* 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, tcp->write_slices->count, + status = WSASend(socket->socket, buffers, 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) { + gpr_slice_buffer_reset_and_unref(&tcp->write_slices); tcp->socket->write_info.outstanding = 0; - TCP_UNREF(tcp, "write"); - return GRPC_ENDPOINT_ERROR; + tcp_unref(tcp); + return GRPC_ENDPOINT_WRITE_ERROR; } } /* 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(socket, on_write, tcp); - return GRPC_ENDPOINT_PENDING; + return GRPC_ENDPOINT_WRITE_PENDING; } static void win_add_to_pollset(grpc_endpoint *ep, grpc_pollset *ps) { @@ -414,17 +387,19 @@ static void win_add_to_pollset_set(grpc_endpoint *ep, grpc_pollset_set *pss) { concurrent access of the data structure in that regard. */ static void win_shutdown(grpc_endpoint *ep) { grpc_tcp *tcp = (grpc_tcp *)ep; + int extra_refs = 0; gpr_mu_lock(&tcp->mu); /* At that point, what may happen is that we're already inside the IOCP callback. See the comments in on_read and on_write. */ tcp->shutting_down = 1; - grpc_winsocket_shutdown(tcp->socket); + extra_refs = grpc_winsocket_shutdown(tcp->socket); + while (extra_refs--) tcp_ref(tcp); gpr_mu_unlock(&tcp->mu); } static void win_destroy(grpc_endpoint *ep) { grpc_tcp *tcp = (grpc_tcp *)ep; - TCP_UNREF(tcp, "destroy"); + tcp_unref(tcp); } static char *win_get_peer(grpc_endpoint *ep) { @@ -433,8 +408,8 @@ static char *win_get_peer(grpc_endpoint *ep) { } static grpc_endpoint_vtable vtable = { - win_read, win_write, win_add_to_pollset, win_add_to_pollset_set, - win_shutdown, win_destroy, win_get_peer}; + win_notify_on_read, win_write, win_add_to_pollset, win_add_to_pollset_set, + win_shutdown, win_destroy, win_get_peer}; grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket, char *peer_string) { grpc_tcp *tcp = (grpc_tcp *)gpr_malloc(sizeof(grpc_tcp)); @@ -442,6 +417,7 @@ grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket, char *peer_string) { tcp->base.vtable = &vtable; tcp->socket = socket; gpr_mu_init(&tcp->mu); + gpr_slice_buffer_init(&tcp->write_slices); gpr_ref_init(&tcp->refcount, 1); tcp->peer_string = gpr_strdup(peer_string); return &tcp->base; diff --git a/src/core/security/secure_endpoint.c b/src/core/security/secure_endpoint.c index b696e384fc..81b3e33cb2 100644 --- a/src/core/security/secure_endpoint.c +++ b/src/core/security/secure_endpoint.c @@ -49,15 +49,15 @@ typedef struct { struct tsi_frame_protector *protector; gpr_mu protector_mu; /* saved upper level callbacks and user_data. */ - grpc_iomgr_closure *read_cb; - grpc_iomgr_closure *write_cb; - grpc_iomgr_closure on_read; - gpr_slice_buffer *read_buffer; - gpr_slice_buffer source_buffer; + grpc_endpoint_read_cb read_cb; + void *read_user_data; + grpc_endpoint_write_cb write_cb; + void *write_user_data; /* saved handshaker leftover data to unprotect. */ gpr_slice_buffer leftover_bytes; /* buffers for read and write */ gpr_slice read_staging_buffer; + gpr_slice_buffer input_buffer; gpr_slice write_staging_buffer; gpr_slice_buffer output_buffer; @@ -67,91 +67,62 @@ typedef struct { int grpc_trace_secure_endpoint = 0; +static void secure_endpoint_ref(secure_endpoint *ep) { gpr_ref(&ep->ref); } + static void destroy(secure_endpoint *secure_ep) { secure_endpoint *ep = secure_ep; grpc_endpoint_destroy(ep->wrapped_ep); tsi_frame_protector_destroy(ep->protector); gpr_slice_buffer_destroy(&ep->leftover_bytes); gpr_slice_unref(ep->read_staging_buffer); + gpr_slice_buffer_destroy(&ep->input_buffer); gpr_slice_unref(ep->write_staging_buffer); gpr_slice_buffer_destroy(&ep->output_buffer); - gpr_slice_buffer_destroy(&ep->source_buffer); gpr_mu_destroy(&ep->protector_mu); gpr_free(ep); } -/*#define GRPC_SECURE_ENDPOINT_REFCOUNT_DEBUG*/ -#ifdef GRPC_SECURE_ENDPOINT_REFCOUNT_DEBUG -#define SECURE_ENDPOINT_UNREF(ep, reason) \ - secure_endpoint_unref((ep), (reason), __FILE__, __LINE__) -#define SECURE_ENDPOINT_REF(ep, reason) \ - secure_endpoint_ref((ep), (reason), __FILE__, __LINE__) -static void secure_endpoint_unref(secure_endpoint *ep, const char *reason, - const char *file, int line) { - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "SECENDP unref %p : %s %d -> %d", - ep, reason, ep->ref.count, ep->ref.count - 1); - if (gpr_unref(&ep->ref)) { - destroy(ep); - } -} - -static void secure_endpoint_ref(secure_endpoint *ep, const char *reason, - const char *file, int line) { - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "SECENDP ref %p : %s %d -> %d", - ep, reason, ep->ref.count, ep->ref.count + 1); - gpr_ref(&ep->ref); -} -#else -#define SECURE_ENDPOINT_UNREF(ep, reason) secure_endpoint_unref((ep)) -#define SECURE_ENDPOINT_REF(ep, reason) secure_endpoint_ref((ep)) static void secure_endpoint_unref(secure_endpoint *ep) { if (gpr_unref(&ep->ref)) { destroy(ep); } } -static void secure_endpoint_ref(secure_endpoint *ep) { gpr_ref(&ep->ref); } -#endif - static void flush_read_staging_buffer(secure_endpoint *ep, gpr_uint8 **cur, gpr_uint8 **end) { - gpr_slice_buffer_add(ep->read_buffer, ep->read_staging_buffer); + gpr_slice_buffer_add(&ep->input_buffer, ep->read_staging_buffer); ep->read_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE); *cur = GPR_SLICE_START_PTR(ep->read_staging_buffer); *end = GPR_SLICE_END_PTR(ep->read_staging_buffer); } -static void call_read_cb(secure_endpoint *ep, int success) { +static void call_read_cb(secure_endpoint *ep, gpr_slice *slices, size_t nslices, + grpc_endpoint_cb_status error) { if (grpc_trace_secure_endpoint) { size_t i; - for (i = 0; i < ep->read_buffer->count; i++) { - char *data = gpr_dump_slice(ep->read_buffer->slices[i], - GPR_DUMP_HEX | GPR_DUMP_ASCII); + for (i = 0; i < nslices; i++) { + char *data = gpr_dump_slice(slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII); gpr_log(GPR_DEBUG, "READ %p: %s", ep, data); gpr_free(data); } } - ep->read_buffer = NULL; - ep->read_cb->cb(ep->read_cb->cb_arg, success); - SECURE_ENDPOINT_UNREF(ep, "read"); + ep->read_cb(ep->read_user_data, slices, nslices, error); + secure_endpoint_unref(ep); } -static int on_read(void *user_data, int success) { +static void on_read(void *user_data, gpr_slice *slices, size_t nslices, + grpc_endpoint_cb_status error) { unsigned i; gpr_uint8 keep_looping = 0; + size_t input_buffer_count = 0; tsi_result result = TSI_OK; secure_endpoint *ep = (secure_endpoint *)user_data; gpr_uint8 *cur = GPR_SLICE_START_PTR(ep->read_staging_buffer); gpr_uint8 *end = GPR_SLICE_END_PTR(ep->read_staging_buffer); - if (!success) { - gpr_slice_buffer_reset_and_unref(ep->read_buffer); - return 0; - } - /* TODO(yangg) check error, maybe bail out early */ - for (i = 0; i < ep->source_buffer.count; i++) { - gpr_slice encrypted = ep->source_buffer.slices[i]; + for (i = 0; i < nslices; i++) { + gpr_slice encrypted = slices[i]; gpr_uint8 *message_bytes = GPR_SLICE_START_PTR(encrypted); size_t message_size = GPR_SLICE_LENGTH(encrypted); @@ -190,7 +161,7 @@ static int on_read(void *user_data, int success) { if (cur != GPR_SLICE_START_PTR(ep->read_staging_buffer)) { gpr_slice_buffer_add( - ep->read_buffer, + &ep->input_buffer, gpr_slice_split_head( &ep->read_staging_buffer, (size_t)(cur - GPR_SLICE_START_PTR(ep->read_staging_buffer)))); @@ -198,53 +169,38 @@ static int on_read(void *user_data, int success) { /* TODO(yangg) experiment with moving this block after read_cb to see if it helps latency */ - gpr_slice_buffer_reset_and_unref(&ep->source_buffer); + for (i = 0; i < nslices; i++) { + gpr_slice_unref(slices[i]); + } if (result != TSI_OK) { - gpr_slice_buffer_reset_and_unref(ep->read_buffer); - return 0; + gpr_slice_buffer_reset_and_unref(&ep->input_buffer); + call_read_cb(ep, NULL, 0, GRPC_ENDPOINT_CB_ERROR); + return; } - - return 1; -} - -static void on_read_cb(void *user_data, int success) { - call_read_cb(user_data, on_read(user_data, success)); + /* The upper level will unref the slices. */ + input_buffer_count = ep->input_buffer.count; + ep->input_buffer.count = 0; + call_read_cb(ep, ep->input_buffer.slices, input_buffer_count, error); } -static grpc_endpoint_op_status endpoint_read(grpc_endpoint *secure_ep, - gpr_slice_buffer *slices, - grpc_iomgr_closure *cb) { +static void endpoint_notify_on_read(grpc_endpoint *secure_ep, + grpc_endpoint_read_cb cb, void *user_data) { secure_endpoint *ep = (secure_endpoint *)secure_ep; - int immediate_read_success = -1; ep->read_cb = cb; - ep->read_buffer = slices; - gpr_slice_buffer_reset_and_unref(ep->read_buffer); + ep->read_user_data = user_data; - if (ep->leftover_bytes.count) { - gpr_slice_buffer_swap(&ep->leftover_bytes, &ep->source_buffer); - GPR_ASSERT(ep->leftover_bytes.count == 0); - return on_read(ep, 1) ? GRPC_ENDPOINT_DONE : GRPC_ENDPOINT_ERROR; - } + secure_endpoint_ref(ep); - SECURE_ENDPOINT_REF(ep, "read"); - - switch ( - grpc_endpoint_read(ep->wrapped_ep, &ep->source_buffer, &ep->on_read)) { - case GRPC_ENDPOINT_DONE: - immediate_read_success = on_read(ep, 1); - break; - case GRPC_ENDPOINT_PENDING: - return GRPC_ENDPOINT_PENDING; - case GRPC_ENDPOINT_ERROR: - immediate_read_success = on_read(ep, 0); - break; + if (ep->leftover_bytes.count) { + size_t leftover_nslices = ep->leftover_bytes.count; + ep->leftover_bytes.count = 0; + on_read(ep, ep->leftover_bytes.slices, leftover_nslices, + GRPC_ENDPOINT_CB_OK); + return; } - GPR_ASSERT(immediate_read_success != -1); - SECURE_ENDPOINT_UNREF(ep, "read"); - - return immediate_read_success ? GRPC_ENDPOINT_DONE : GRPC_ENDPOINT_ERROR; + grpc_endpoint_notify_on_read(ep->wrapped_ep, on_read, ep); } static void flush_write_staging_buffer(secure_endpoint *ep, gpr_uint8 **cur, @@ -255,28 +211,36 @@ static void flush_write_staging_buffer(secure_endpoint *ep, gpr_uint8 **cur, *end = GPR_SLICE_END_PTR(ep->write_staging_buffer); } -static grpc_endpoint_op_status endpoint_write(grpc_endpoint *secure_ep, - gpr_slice_buffer *slices, - grpc_iomgr_closure *cb) { +static void on_write(void *data, grpc_endpoint_cb_status error) { + secure_endpoint *ep = data; + ep->write_cb(ep->write_user_data, error); + secure_endpoint_unref(ep); +} + +static grpc_endpoint_write_status endpoint_write(grpc_endpoint *secure_ep, + gpr_slice *slices, + size_t nslices, + grpc_endpoint_write_cb cb, + void *user_data) { unsigned i; + size_t output_buffer_count = 0; tsi_result result = TSI_OK; secure_endpoint *ep = (secure_endpoint *)secure_ep; gpr_uint8 *cur = GPR_SLICE_START_PTR(ep->write_staging_buffer); gpr_uint8 *end = GPR_SLICE_END_PTR(ep->write_staging_buffer); - - gpr_slice_buffer_reset_and_unref(&ep->output_buffer); + grpc_endpoint_write_status status; + GPR_ASSERT(ep->output_buffer.count == 0); if (grpc_trace_secure_endpoint) { - for (i = 0; i < slices->count; i++) { - char *data = - gpr_dump_slice(slices->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII); + for (i = 0; i < nslices; i++) { + char *data = gpr_dump_slice(slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII); gpr_log(GPR_DEBUG, "WRITE %p: %s", ep, data); gpr_free(data); } } - for (i = 0; i < slices->count; i++) { - gpr_slice plain = slices->slices[i]; + for (i = 0; i < nslices; i++) { + gpr_slice plain = slices[i]; gpr_uint8 *message_bytes = GPR_SLICE_START_PTR(plain); size_t message_size = GPR_SLICE_LENGTH(plain); while (message_size > 0) { @@ -326,13 +290,29 @@ static grpc_endpoint_op_status endpoint_write(grpc_endpoint *secure_ep, } } + for (i = 0; i < nslices; i++) { + gpr_slice_unref(slices[i]); + } + if (result != TSI_OK) { /* TODO(yangg) do different things according to the error type? */ gpr_slice_buffer_reset_and_unref(&ep->output_buffer); - return GRPC_ENDPOINT_ERROR; + return GRPC_ENDPOINT_WRITE_ERROR; } - return grpc_endpoint_write(ep->wrapped_ep, &ep->output_buffer, cb); + /* clear output_buffer and let the lower level handle its slices. */ + output_buffer_count = ep->output_buffer.count; + ep->output_buffer.count = 0; + ep->write_cb = cb; + ep->write_user_data = user_data; + /* Need to keep the endpoint alive across a transport */ + secure_endpoint_ref(ep); + status = grpc_endpoint_write(ep->wrapped_ep, ep->output_buffer.slices, + output_buffer_count, on_write, ep); + if (status != GRPC_ENDPOINT_WRITE_PENDING) { + secure_endpoint_unref(ep); + } + return status; } static void endpoint_shutdown(grpc_endpoint *secure_ep) { @@ -340,9 +320,9 @@ static void endpoint_shutdown(grpc_endpoint *secure_ep) { grpc_endpoint_shutdown(ep->wrapped_ep); } -static void endpoint_destroy(grpc_endpoint *secure_ep) { +static void endpoint_unref(grpc_endpoint *secure_ep) { secure_endpoint *ep = (secure_endpoint *)secure_ep; - SECURE_ENDPOINT_UNREF(ep, "destroy"); + secure_endpoint_unref(ep); } static void endpoint_add_to_pollset(grpc_endpoint *secure_ep, @@ -363,9 +343,9 @@ static char *endpoint_get_peer(grpc_endpoint *secure_ep) { } static const grpc_endpoint_vtable vtable = { - endpoint_read, endpoint_write, + endpoint_notify_on_read, endpoint_write, endpoint_add_to_pollset, endpoint_add_to_pollset_set, - endpoint_shutdown, endpoint_destroy, + endpoint_shutdown, endpoint_unref, endpoint_get_peer}; grpc_endpoint *grpc_secure_endpoint_create( @@ -383,10 +363,8 @@ grpc_endpoint *grpc_secure_endpoint_create( } ep->write_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE); ep->read_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE); + gpr_slice_buffer_init(&ep->input_buffer); gpr_slice_buffer_init(&ep->output_buffer); - gpr_slice_buffer_init(&ep->source_buffer); - ep->read_buffer = NULL; - grpc_iomgr_closure_init(&ep->on_read, on_read_cb, ep); gpr_mu_init(&ep->protector_mu); gpr_ref_init(&ep->ref, 1); return &ep->base; diff --git a/src/core/security/secure_transport_setup.c b/src/core/security/secure_transport_setup.c index bf0079577e..0c3572b53c 100644 --- a/src/core/security/secure_transport_setup.c +++ b/src/core/security/secure_transport_setup.c @@ -50,17 +50,16 @@ typedef struct { grpc_endpoint *wrapped_endpoint; grpc_endpoint *secure_endpoint; gpr_slice_buffer left_overs; - gpr_slice_buffer incoming; - gpr_slice_buffer outgoing; grpc_secure_transport_setup_done_cb cb; void *user_data; - grpc_iomgr_closure on_handshake_data_sent_to_peer; - grpc_iomgr_closure on_handshake_data_received_from_peer; } grpc_secure_transport_setup; -static void on_handshake_data_received_from_peer(void *setup, int success); +static void on_handshake_data_received_from_peer(void *setup, gpr_slice *slices, + size_t nslices, + grpc_endpoint_cb_status error); -static void on_handshake_data_sent_to_peer(void *setup, int success); +static void on_handshake_data_sent_to_peer(void *setup, + grpc_endpoint_cb_status error); static void secure_transport_setup_done(grpc_secure_transport_setup *s, int is_success) { @@ -79,8 +78,6 @@ static void secure_transport_setup_done(grpc_secure_transport_setup *s, if (s->handshaker != NULL) tsi_handshaker_destroy(s->handshaker); if (s->handshake_buffer != NULL) gpr_free(s->handshake_buffer); gpr_slice_buffer_destroy(&s->left_overs); - gpr_slice_buffer_destroy(&s->outgoing); - gpr_slice_buffer_destroy(&s->incoming); GRPC_SECURITY_CONNECTOR_UNREF(s->connector, "secure_transport_setup"); gpr_free(s); } @@ -105,8 +102,6 @@ static void on_peer_checked(void *user_data, grpc_security_status status) { s->secure_endpoint = grpc_secure_endpoint_create(protector, s->wrapped_endpoint, s->left_overs.slices, s->left_overs.count); - s->left_overs.count = 0; - s->left_overs.length = 0; secure_transport_setup_done(s, 1); return; } @@ -137,6 +132,7 @@ static void send_handshake_bytes_to_peer(grpc_secure_transport_setup *s) { size_t offset = 0; tsi_result result = TSI_OK; gpr_slice to_send; + grpc_endpoint_write_status write_status; do { size_t to_send_size = s->handshake_buffer_size - offset; @@ -159,25 +155,28 @@ static void send_handshake_bytes_to_peer(grpc_secure_transport_setup *s) { to_send = gpr_slice_from_copied_buffer((const char *)s->handshake_buffer, offset); - gpr_slice_buffer_reset_and_unref(&s->outgoing); - gpr_slice_buffer_add(&s->outgoing, to_send); /* TODO(klempner,jboeuf): This should probably use the client setup deadline */ - switch (grpc_endpoint_write(s->wrapped_endpoint, &s->outgoing, - &s->on_handshake_data_sent_to_peer)) { - case GRPC_ENDPOINT_ERROR: - gpr_log(GPR_ERROR, "Could not send handshake data to peer."); - secure_transport_setup_done(s, 0); - break; - case GRPC_ENDPOINT_DONE: - on_handshake_data_sent_to_peer(s, 1); - break; - case GRPC_ENDPOINT_PENDING: - break; + write_status = grpc_endpoint_write(s->wrapped_endpoint, &to_send, 1, + on_handshake_data_sent_to_peer, s); + if (write_status == GRPC_ENDPOINT_WRITE_ERROR) { + gpr_log(GPR_ERROR, "Could not send handshake data to peer."); + secure_transport_setup_done(s, 0); + } else if (write_status == GRPC_ENDPOINT_WRITE_DONE) { + on_handshake_data_sent_to_peer(s, GRPC_ENDPOINT_CB_OK); + } +} + +static void cleanup_slices(gpr_slice *slices, size_t num_slices) { + size_t i; + for (i = 0; i < num_slices; i++) { + gpr_slice_unref(slices[i]); } } -static void on_handshake_data_received_from_peer(void *setup, int success) { +static void on_handshake_data_received_from_peer( + void *setup, gpr_slice *slices, size_t nslices, + grpc_endpoint_cb_status error) { grpc_secure_transport_setup *s = setup; size_t consumed_slice_size = 0; tsi_result result = TSI_OK; @@ -185,37 +184,32 @@ static void on_handshake_data_received_from_peer(void *setup, int success) { size_t num_left_overs; int has_left_overs_in_current_slice = 0; - if (!success) { + if (error != GRPC_ENDPOINT_CB_OK) { gpr_log(GPR_ERROR, "Read failed."); + cleanup_slices(slices, nslices); secure_transport_setup_done(s, 0); return; } - for (i = 0; i < s->incoming.count; i++) { - consumed_slice_size = GPR_SLICE_LENGTH(s->incoming.slices[i]); + for (i = 0; i < nslices; i++) { + consumed_slice_size = GPR_SLICE_LENGTH(slices[i]); result = tsi_handshaker_process_bytes_from_peer( - s->handshaker, GPR_SLICE_START_PTR(s->incoming.slices[i]), - &consumed_slice_size); + s->handshaker, GPR_SLICE_START_PTR(slices[i]), &consumed_slice_size); if (!tsi_handshaker_is_in_progress(s->handshaker)) break; } if (tsi_handshaker_is_in_progress(s->handshaker)) { /* We may need more data. */ if (result == TSI_INCOMPLETE_DATA) { - switch (grpc_endpoint_read(s->wrapped_endpoint, &s->incoming, - &s->on_handshake_data_received_from_peer)) { - case GRPC_ENDPOINT_DONE: - on_handshake_data_received_from_peer(s, 1); - break; - case GRPC_ENDPOINT_ERROR: - on_handshake_data_received_from_peer(s, 0); - break; - case GRPC_ENDPOINT_PENDING: - break; - } + /* TODO(klempner,jboeuf): This should probably use the client setup + deadline */ + grpc_endpoint_notify_on_read(s->wrapped_endpoint, + on_handshake_data_received_from_peer, setup); + cleanup_slices(slices, nslices); return; } else { send_handshake_bytes_to_peer(s); + cleanup_slices(slices, nslices); return; } } @@ -223,40 +217,42 @@ static void on_handshake_data_received_from_peer(void *setup, int success) { if (result != TSI_OK) { gpr_log(GPR_ERROR, "Handshake failed with error %s", tsi_result_to_string(result)); + cleanup_slices(slices, nslices); secure_transport_setup_done(s, 0); return; } /* Handshake is done and successful this point. */ has_left_overs_in_current_slice = - (consumed_slice_size < GPR_SLICE_LENGTH(s->incoming.slices[i])); - num_left_overs = - (has_left_overs_in_current_slice ? 1 : 0) + s->incoming.count - i - 1; + (consumed_slice_size < GPR_SLICE_LENGTH(slices[i])); + num_left_overs = (has_left_overs_in_current_slice ? 1 : 0) + nslices - i - 1; if (num_left_overs == 0) { + cleanup_slices(slices, nslices); check_peer(s); return; } + cleanup_slices(slices, nslices - num_left_overs); + /* Put the leftovers in our buffer (ownership transfered). */ if (has_left_overs_in_current_slice) { - gpr_slice_buffer_add( - &s->left_overs, - gpr_slice_split_tail(&s->incoming.slices[i], consumed_slice_size)); - gpr_slice_unref( - s->incoming.slices[i]); /* split_tail above increments refcount. */ + gpr_slice_buffer_add(&s->left_overs, + gpr_slice_split_tail(&slices[i], consumed_slice_size)); + gpr_slice_unref(slices[i]); /* split_tail above increments refcount. */ } gpr_slice_buffer_addn( - &s->left_overs, &s->incoming.slices[i + 1], + &s->left_overs, &slices[i + 1], num_left_overs - (size_t)has_left_overs_in_current_slice); check_peer(s); } /* If setup is NULL, the setup is done. */ -static void on_handshake_data_sent_to_peer(void *setup, int success) { +static void on_handshake_data_sent_to_peer(void *setup, + grpc_endpoint_cb_status error) { grpc_secure_transport_setup *s = setup; /* Make sure that write is OK. */ - if (!success) { - gpr_log(GPR_ERROR, "Write failed."); + if (error != GRPC_ENDPOINT_CB_OK) { + gpr_log(GPR_ERROR, "Write failed with error %d.", error); if (setup != NULL) secure_transport_setup_done(s, 0); return; } @@ -265,17 +261,8 @@ static void on_handshake_data_sent_to_peer(void *setup, int success) { if (tsi_handshaker_is_in_progress(s->handshaker)) { /* TODO(klempner,jboeuf): This should probably use the client setup deadline */ - switch (grpc_endpoint_read(s->wrapped_endpoint, &s->incoming, - &s->on_handshake_data_received_from_peer)) { - case GRPC_ENDPOINT_ERROR: - on_handshake_data_received_from_peer(s, 0); - break; - case GRPC_ENDPOINT_PENDING: - break; - case GRPC_ENDPOINT_DONE: - on_handshake_data_received_from_peer(s, 1); - break; - } + grpc_endpoint_notify_on_read(s->wrapped_endpoint, + on_handshake_data_received_from_peer, setup); } else { check_peer(s); } @@ -301,12 +288,6 @@ void grpc_setup_secure_transport(grpc_security_connector *connector, s->wrapped_endpoint = nonsecure_endpoint; s->user_data = user_data; s->cb = cb; - grpc_iomgr_closure_init(&s->on_handshake_data_sent_to_peer, - on_handshake_data_sent_to_peer, s); - grpc_iomgr_closure_init(&s->on_handshake_data_received_from_peer, - on_handshake_data_received_from_peer, s); gpr_slice_buffer_init(&s->left_overs); - gpr_slice_buffer_init(&s->outgoing); - gpr_slice_buffer_init(&s->incoming); send_handshake_bytes_to_peer(s); } diff --git a/src/core/support/slice_buffer.c b/src/core/support/slice_buffer.c index 6482ef9c9f..987d5cb9b5 100644 --- a/src/core/support/slice_buffer.c +++ b/src/core/support/slice_buffer.c @@ -207,25 +207,3 @@ void gpr_slice_buffer_move_into(gpr_slice_buffer *src, gpr_slice_buffer *dst) { src->count = 0; src->length = 0; } - -void gpr_slice_buffer_trim_end(gpr_slice_buffer *sb, size_t n) { - GPR_ASSERT(n <= sb->length); - sb->length -= n; - for (;;) { - size_t idx = sb->count - 1; - gpr_slice slice = sb->slices[idx]; - size_t slice_len = GPR_SLICE_LENGTH(slice); - if (slice_len > n) { - sb->slices[idx] = gpr_slice_sub_no_ref(slice, 0, slice_len - n); - return; - } else if (slice_len == n) { - gpr_slice_unref(slice); - sb->count = idx; - return; - } else { - gpr_slice_unref(slice); - n -= slice_len; - sb->count = idx; - } - } -} diff --git a/src/core/transport/chttp2/internal.h b/src/core/transport/chttp2/internal.h index a1b773b1ca..42cf0ecd5b 100644 --- a/src/core/transport/chttp2/internal.h +++ b/src/core/transport/chttp2/internal.h @@ -214,8 +214,6 @@ typedef struct { grpc_chttp2_hpack_compressor hpack_compressor; /** is this a client? */ gpr_uint8 is_client; - /** callback for when writing is done */ - grpc_iomgr_closure done_cb; } grpc_chttp2_transport_writing; struct grpc_chttp2_transport_parsing { @@ -331,11 +329,8 @@ struct grpc_chttp2_transport { /** closure to execute writing */ grpc_iomgr_closure writing_action; - /** closure to finish reading from the endpoint */ - grpc_iomgr_closure recv_data; - - /** incoming read bytes */ - gpr_slice_buffer read_buffer; + /** closure to start reading from the endpoint */ + grpc_iomgr_closure reading_action; /** address to place a newly accepted stream - set and unset by grpc_chttp2_parsing_accept_stream; used by init_stream to @@ -468,7 +463,8 @@ int grpc_chttp2_unlocking_check_writes(grpc_chttp2_transport_global *global, grpc_chttp2_transport_writing *writing); void grpc_chttp2_perform_writes( grpc_chttp2_transport_writing *transport_writing, grpc_endpoint *endpoint); -void grpc_chttp2_terminate_writing(void *transport_writing, int success); +void grpc_chttp2_terminate_writing( + grpc_chttp2_transport_writing *transport_writing, int success); void grpc_chttp2_cleanup_writing(grpc_chttp2_transport_global *global, grpc_chttp2_transport_writing *writing); diff --git a/src/core/transport/chttp2/writing.c b/src/core/transport/chttp2/writing.c index 2c8c48f47b..123061b3fc 100644 --- a/src/core/transport/chttp2/writing.c +++ b/src/core/transport/chttp2/writing.c @@ -37,6 +37,7 @@ #include static void finalize_outbuf(grpc_chttp2_transport_writing *transport_writing); +static void finish_write_cb(void *tw, grpc_endpoint_cb_status write_status); int grpc_chttp2_unlocking_check_writes( grpc_chttp2_transport_global *transport_global, @@ -164,15 +165,16 @@ void grpc_chttp2_perform_writes( GPR_ASSERT(transport_writing->outbuf.count > 0); GPR_ASSERT(endpoint); - switch (grpc_endpoint_write(endpoint, &transport_writing->outbuf, - &transport_writing->done_cb)) { - case GRPC_ENDPOINT_DONE: + switch (grpc_endpoint_write(endpoint, transport_writing->outbuf.slices, + transport_writing->outbuf.count, finish_write_cb, + transport_writing)) { + case GRPC_ENDPOINT_WRITE_DONE: grpc_chttp2_terminate_writing(transport_writing, 1); break; - case GRPC_ENDPOINT_ERROR: + case GRPC_ENDPOINT_WRITE_ERROR: grpc_chttp2_terminate_writing(transport_writing, 0); break; - case GRPC_ENDPOINT_PENDING: + case GRPC_ENDPOINT_WRITE_PENDING: break; } } @@ -207,6 +209,12 @@ static void finalize_outbuf(grpc_chttp2_transport_writing *transport_writing) { } } +static void finish_write_cb(void *tw, grpc_endpoint_cb_status write_status) { + grpc_chttp2_transport_writing *transport_writing = tw; + grpc_chttp2_terminate_writing(transport_writing, + write_status == GRPC_ENDPOINT_CB_OK); +} + void grpc_chttp2_cleanup_writing( grpc_chttp2_transport_global *transport_global, grpc_chttp2_transport_writing *transport_writing) { @@ -235,5 +243,6 @@ void grpc_chttp2_cleanup_writing( grpc_chttp2_list_add_read_write_state_changed(transport_global, stream_global); } - gpr_slice_buffer_reset_and_unref(&transport_writing->outbuf); + transport_writing->outbuf.count = 0; + transport_writing->outbuf.length = 0; } diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c index 8caa10c938..1bbd210e46 100644 --- a/src/core/transport/chttp2_transport.c +++ b/src/core/transport/chttp2_transport.c @@ -84,13 +84,15 @@ static void unlock_check_read_write_state(grpc_chttp2_transport *t); /* forward declarations of various callbacks that we'll build closures around */ static void writing_action(void *t, int iomgr_success_ignored); +static void reading_action(void *t, int iomgr_success_ignored); /** Set a transport level setting, and push it to our peer */ static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id, gpr_uint32 value); /** Endpoint callback to process incoming data */ -static void recv_data(void *tp, int success); +static void recv_data(void *tp, gpr_slice *slices, size_t nslices, + grpc_endpoint_cb_status error); /** Start disconnection chain */ static void drop_connection(grpc_chttp2_transport *t); @@ -141,7 +143,6 @@ static void destruct_transport(grpc_chttp2_transport *t) { grpc_chttp2_hpack_compressor_destroy(&t->writing.hpack_compressor); gpr_slice_buffer_destroy(&t->parsing.qbuf); - gpr_slice_buffer_destroy(&t->read_buffer); grpc_chttp2_hpack_parser_destroy(&t->parsing.hpack_parser); grpc_chttp2_goaway_parser_destroy(&t->parsing.goaway_parser); @@ -248,16 +249,12 @@ static void init_transport(grpc_chttp2_transport *t, gpr_slice_buffer_init(&t->writing.outbuf); grpc_chttp2_hpack_compressor_init(&t->writing.hpack_compressor, mdctx); grpc_iomgr_closure_init(&t->writing_action, writing_action, t); + grpc_iomgr_closure_init(&t->reading_action, reading_action, t); gpr_slice_buffer_init(&t->parsing.qbuf); grpc_chttp2_goaway_parser_init(&t->parsing.goaway_parser); grpc_chttp2_hpack_parser_init(&t->parsing.hpack_parser, t->metadata_context); - grpc_iomgr_closure_init(&t->writing.done_cb, grpc_chttp2_terminate_writing, - &t->writing); - grpc_iomgr_closure_init(&t->recv_data, recv_data, t); - gpr_slice_buffer_init(&t->read_buffer); - if (is_client) { gpr_slice_buffer_add( &t->global.qbuf, @@ -505,8 +502,8 @@ static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id, } } -void grpc_chttp2_terminate_writing(void *transport_writing_ptr, int success) { - grpc_chttp2_transport_writing *transport_writing = transport_writing_ptr; +void grpc_chttp2_terminate_writing( + grpc_chttp2_transport_writing *transport_writing, int success) { grpc_chttp2_transport *t = TRANSPORT_FROM_WRITING(transport_writing); lock(t); @@ -1063,76 +1060,74 @@ static void read_error_locked(grpc_chttp2_transport *t) { } /* tcp read callback */ -static int recv_data_loop(grpc_chttp2_transport *t, int *success) { +static void recv_data(void *tp, gpr_slice *slices, size_t nslices, + grpc_endpoint_cb_status error) { + grpc_chttp2_transport *t = tp; size_t i; - int keep_reading = 0; + int unref = 0; - lock(t); - i = 0; - GPR_ASSERT(!t->parsing_active); - if (!t->closed) { - t->parsing_active = 1; - /* merge stream lists */ - grpc_chttp2_stream_map_move_into(&t->new_stream_map, - &t->parsing_stream_map); - grpc_chttp2_prepare_to_read(&t->global, &t->parsing); - gpr_mu_unlock(&t->mu); - for (; i < t->read_buffer.count && - grpc_chttp2_perform_read(&t->parsing, t->read_buffer.slices[i]); - i++) - ; - gpr_mu_lock(&t->mu); - if (i != t->read_buffer.count) { + switch (error) { + case GRPC_ENDPOINT_CB_SHUTDOWN: + case GRPC_ENDPOINT_CB_EOF: + case GRPC_ENDPOINT_CB_ERROR: + lock(t); drop_connection(t); - } - /* merge stream lists */ - grpc_chttp2_stream_map_move_into(&t->new_stream_map, - &t->parsing_stream_map); - t->global.concurrent_stream_count = - grpc_chttp2_stream_map_size(&t->parsing_stream_map); - if (t->parsing.initial_window_update != 0) { - grpc_chttp2_stream_map_for_each(&t->parsing_stream_map, - update_global_window, t); - t->parsing.initial_window_update = 0; - } - /* handle higher level things */ - grpc_chttp2_publish_reads(&t->global, &t->parsing); - t->parsing_active = 0; - } - if (!*success || i != t->read_buffer.count) { - drop_connection(t); - read_error_locked(t); - } else { - keep_reading = 1; + read_error_locked(t); + unlock(t); + unref = 1; + for (i = 0; i < nslices; i++) gpr_slice_unref(slices[i]); + break; + case GRPC_ENDPOINT_CB_OK: + lock(t); + i = 0; + GPR_ASSERT(!t->parsing_active); + if (!t->closed) { + t->parsing_active = 1; + /* merge stream lists */ + grpc_chttp2_stream_map_move_into(&t->new_stream_map, + &t->parsing_stream_map); + grpc_chttp2_prepare_to_read(&t->global, &t->parsing); + gpr_mu_unlock(&t->mu); + for (; i < nslices && grpc_chttp2_perform_read(&t->parsing, slices[i]); + i++) { + gpr_slice_unref(slices[i]); + } + gpr_mu_lock(&t->mu); + if (i != nslices) { + drop_connection(t); + } + /* merge stream lists */ + grpc_chttp2_stream_map_move_into(&t->new_stream_map, + &t->parsing_stream_map); + t->global.concurrent_stream_count = + grpc_chttp2_stream_map_size(&t->parsing_stream_map); + if (t->parsing.initial_window_update != 0) { + grpc_chttp2_stream_map_for_each(&t->parsing_stream_map, + update_global_window, t); + t->parsing.initial_window_update = 0; + } + /* handle higher level things */ + grpc_chttp2_publish_reads(&t->global, &t->parsing); + t->parsing_active = 0; + } + if (i == nslices) { + grpc_chttp2_schedule_closure(&t->global, &t->reading_action, 1); + } else { + read_error_locked(t); + unref = 1; + } + unlock(t); + for (; i < nslices; i++) gpr_slice_unref(slices[i]); + break; } - gpr_slice_buffer_reset_and_unref(&t->read_buffer); - unlock(t); - - if (keep_reading) { - switch (grpc_endpoint_read(t->ep, &t->read_buffer, &t->recv_data)) { - case GRPC_ENDPOINT_DONE: - *success = 1; - return 1; - case GRPC_ENDPOINT_ERROR: - *success = 0; - return 1; - case GRPC_ENDPOINT_PENDING: - return 0; - } - } else { + if (unref) { UNREF_TRANSPORT(t, "recv_data"); - return 0; } - - gpr_log(GPR_ERROR, "should never reach here"); - abort(); } -static void recv_data(void *tp, int success) { - grpc_chttp2_transport *t = tp; - - while (recv_data_loop(t, &success)) - ; +static void reading_action(void *pt, int iomgr_success_ignored) { + grpc_chttp2_transport *t = pt; + grpc_endpoint_notify_on_read(t->ep, recv_data, t); } /* @@ -1245,6 +1240,5 @@ void grpc_chttp2_transport_start_reading(grpc_transport *transport, gpr_slice *slices, size_t nslices) { grpc_chttp2_transport *t = (grpc_chttp2_transport *)transport; REF_TRANSPORT(t, "recv_data"); /* matches unref inside recv_data */ - gpr_slice_buffer_addn(&t->read_buffer, slices, nslices); - recv_data(t, 1); + recv_data(t, slices, nslices, GRPC_ENDPOINT_CB_OK); } diff --git a/test/core/bad_client/bad_client.c b/test/core/bad_client/bad_client.c index 1d98879662..24bf5d3625 100644 --- a/test/core/bad_client/bad_client.c +++ b/test/core/bad_client/bad_client.c @@ -59,7 +59,7 @@ static void thd_func(void *arg) { gpr_event_set(&a->done_thd, (void *)1); } -static void done_write(void *arg, int success) { +static void done_write(void *arg, grpc_endpoint_cb_status status) { thd_args *a = arg; gpr_event_set(&a->done_write, (void *)1); } @@ -85,8 +85,6 @@ void grpc_run_bad_client_test(grpc_bad_client_server_side_validator validator, grpc_mdctx *mdctx = grpc_mdctx_create(); gpr_slice slice = gpr_slice_from_copied_buffer(client_payload, client_payload_length); - gpr_slice_buffer outgoing; - grpc_iomgr_closure done_write_closure; hex = gpr_dump(client_payload, client_payload_length, GPR_DUMP_HEX | GPR_DUMP_ASCII); @@ -124,18 +122,14 @@ void grpc_run_bad_client_test(grpc_bad_client_server_side_validator validator, /* Start validator */ gpr_thd_new(&id, thd_func, &a, NULL); - gpr_slice_buffer_init(&outgoing); - gpr_slice_buffer_add(&outgoing, slice); - grpc_iomgr_closure_init(&done_write_closure, done_write, &a); - /* Write data */ - switch (grpc_endpoint_write(sfd.client, &outgoing, &done_write_closure)) { - case GRPC_ENDPOINT_DONE: + switch (grpc_endpoint_write(sfd.client, &slice, 1, done_write, &a)) { + case GRPC_ENDPOINT_WRITE_DONE: done_write(&a, 1); break; - case GRPC_ENDPOINT_PENDING: + case GRPC_ENDPOINT_WRITE_PENDING: break; - case GRPC_ENDPOINT_ERROR: + case GRPC_ENDPOINT_WRITE_ERROR: done_write(&a, 0); break; } @@ -161,7 +155,6 @@ void grpc_run_bad_client_test(grpc_bad_client_server_side_validator validator, .type == GRPC_OP_COMPLETE); grpc_server_destroy(a.server); grpc_completion_queue_destroy(a.cq); - gpr_slice_buffer_destroy(&outgoing); grpc_shutdown(); } diff --git a/test/core/iomgr/endpoint_tests.c b/test/core/iomgr/endpoint_tests.c index ef673747a1..6ef8e9ca3b 100644 --- a/test/core/iomgr/endpoint_tests.c +++ b/test/core/iomgr/endpoint_tests.c @@ -59,7 +59,8 @@ static grpc_pollset *g_pollset; -size_t count_slices(gpr_slice *slices, size_t nslices, int *current_data) { +size_t count_and_unref_slices(gpr_slice *slices, size_t nslices, + int *current_data) { size_t num_bytes = 0; size_t i; size_t j; @@ -71,6 +72,7 @@ size_t count_slices(gpr_slice *slices, size_t nslices, int *current_data) { *current_data = (*current_data + 1) % 256; } num_bytes += GPR_SLICE_LENGTH(slices[i]); + gpr_slice_unref(slices[i]); } return num_bytes; } @@ -119,76 +121,86 @@ struct read_and_write_test_state { int current_write_data; int read_done; int write_done; - gpr_slice_buffer incoming; - gpr_slice_buffer outgoing; - grpc_iomgr_closure done_read; - grpc_iomgr_closure done_write; }; -static void read_and_write_test_read_handler(void *data, int success) { +static void read_and_write_test_read_handler(void *data, gpr_slice *slices, + size_t nslices, + grpc_endpoint_cb_status error) { struct read_and_write_test_state *state = data; + GPR_ASSERT(error != GRPC_ENDPOINT_CB_ERROR); + if (error == GRPC_ENDPOINT_CB_SHUTDOWN) { + gpr_log(GPR_INFO, "Read handler shutdown"); + gpr_mu_lock(GRPC_POLLSET_MU(g_pollset)); + state->read_done = 1; + grpc_pollset_kick(g_pollset, NULL); + gpr_mu_unlock(GRPC_POLLSET_MU(g_pollset)); + return; + } - state->bytes_read += count_slices( - state->incoming.slices, state->incoming.count, &state->current_read_data); - if (state->bytes_read == state->target_bytes || !success) { + state->bytes_read += + count_and_unref_slices(slices, nslices, &state->current_read_data); + if (state->bytes_read == state->target_bytes) { gpr_log(GPR_INFO, "Read handler done"); gpr_mu_lock(GRPC_POLLSET_MU(g_pollset)); - state->read_done = 1 + success; + state->read_done = 1; grpc_pollset_kick(g_pollset, NULL); gpr_mu_unlock(GRPC_POLLSET_MU(g_pollset)); - } else if (success) { - switch (grpc_endpoint_read(state->read_ep, &state->incoming, - &state->done_read)) { - case GRPC_ENDPOINT_ERROR: - read_and_write_test_read_handler(data, 0); - break; - case GRPC_ENDPOINT_DONE: - read_and_write_test_read_handler(data, 1); - break; - case GRPC_ENDPOINT_PENDING: - break; - } + } else { + grpc_endpoint_notify_on_read(state->read_ep, + read_and_write_test_read_handler, data); } } -static void read_and_write_test_write_handler(void *data, int success) { +static void read_and_write_test_write_handler(void *data, + grpc_endpoint_cb_status error) { struct read_and_write_test_state *state = data; gpr_slice *slices = NULL; size_t nslices; - grpc_endpoint_op_status write_status; - - if (success) { - for (;;) { - /* Need to do inline writes until they don't succeed synchronously or we - finish writing */ - state->bytes_written += state->current_write_size; - if (state->target_bytes - state->bytes_written < - state->current_write_size) { - state->current_write_size = state->target_bytes - state->bytes_written; - } - if (state->current_write_size == 0) { - break; - } - - slices = allocate_blocks(state->current_write_size, 8192, &nslices, - &state->current_write_data); - gpr_slice_buffer_reset_and_unref(&state->outgoing); - gpr_slice_buffer_addn(&state->outgoing, slices, nslices); - write_status = grpc_endpoint_write(state->write_ep, &state->outgoing, - &state->done_write); - gpr_log(GPR_DEBUG, "write_status=%d", write_status); - GPR_ASSERT(write_status != GRPC_ENDPOINT_ERROR); - free(slices); - if (write_status == GRPC_ENDPOINT_PENDING) { - return; - } + grpc_endpoint_write_status write_status; + + GPR_ASSERT(error != GRPC_ENDPOINT_CB_ERROR); + + gpr_log(GPR_DEBUG, "%s: error=%d", "read_and_write_test_write_handler", + error); + + if (error == GRPC_ENDPOINT_CB_SHUTDOWN) { + gpr_log(GPR_INFO, "Write handler shutdown"); + gpr_mu_lock(GRPC_POLLSET_MU(g_pollset)); + state->write_done = 1; + grpc_pollset_kick(g_pollset, NULL); + gpr_mu_unlock(GRPC_POLLSET_MU(g_pollset)); + return; + } + + for (;;) { + /* Need to do inline writes until they don't succeed synchronously or we + finish writing */ + state->bytes_written += state->current_write_size; + if (state->target_bytes - state->bytes_written < + state->current_write_size) { + state->current_write_size = state->target_bytes - state->bytes_written; + } + if (state->current_write_size == 0) { + break; + } + + slices = allocate_blocks(state->current_write_size, 8192, &nslices, + &state->current_write_data); + write_status = + grpc_endpoint_write(state->write_ep, slices, nslices, + read_and_write_test_write_handler, state); + gpr_log(GPR_DEBUG, "write_status=%d", write_status); + GPR_ASSERT(write_status != GRPC_ENDPOINT_WRITE_ERROR); + free(slices); + if (write_status == GRPC_ENDPOINT_WRITE_PENDING) { + return; } - GPR_ASSERT(state->bytes_written == state->target_bytes); } + GPR_ASSERT(state->bytes_written == state->target_bytes); gpr_log(GPR_INFO, "Write handler done"); gpr_mu_lock(GRPC_POLLSET_MU(g_pollset)); - state->write_done = 1 + success; + state->write_done = 1; grpc_pollset_kick(g_pollset, NULL); gpr_mu_unlock(GRPC_POLLSET_MU(g_pollset)); } @@ -222,31 +234,16 @@ static void read_and_write_test(grpc_endpoint_test_config config, state.write_done = 0; state.current_read_data = 0; state.current_write_data = 0; - grpc_iomgr_closure_init(&state.done_read, read_and_write_test_read_handler, - &state); - grpc_iomgr_closure_init(&state.done_write, read_and_write_test_write_handler, - &state); - gpr_slice_buffer_init(&state.outgoing); - gpr_slice_buffer_init(&state.incoming); /* Get started by pretending an initial write completed */ /* NOTE: Sets up initial conditions so we can have the same write handler for the first iteration as for later iterations. It does the right thing even when bytes_written is unsigned. */ state.bytes_written -= state.current_write_size; - read_and_write_test_write_handler(&state, 1); + read_and_write_test_write_handler(&state, GRPC_ENDPOINT_CB_OK); - switch ( - grpc_endpoint_read(state.read_ep, &state.incoming, &state.done_read)) { - case GRPC_ENDPOINT_PENDING: - break; - case GRPC_ENDPOINT_ERROR: - read_and_write_test_read_handler(&state, 0); - break; - case GRPC_ENDPOINT_DONE: - read_and_write_test_read_handler(&state, 1); - break; - } + grpc_endpoint_notify_on_read(state.read_ep, read_and_write_test_read_handler, + &state); if (shutdown) { gpr_log(GPR_DEBUG, "shutdown read"); @@ -266,8 +263,6 @@ static void read_and_write_test(grpc_endpoint_test_config config, grpc_endpoint_destroy(state.read_ep); grpc_endpoint_destroy(state.write_ep); - gpr_slice_buffer_destroy(&state.outgoing); - gpr_slice_buffer_destroy(&state.incoming); end_test(config); } @@ -278,40 +273,36 @@ struct timeout_test_state { typedef struct { int done; grpc_endpoint *ep; - gpr_slice_buffer incoming; - grpc_iomgr_closure done_read; } shutdown_during_write_test_state; -static void shutdown_during_write_test_read_handler(void *user_data, - int success) { +static void shutdown_during_write_test_read_handler( + void *user_data, gpr_slice *slices, size_t nslices, + grpc_endpoint_cb_status error) { + size_t i; shutdown_during_write_test_state *st = user_data; - if (!success) { + for (i = 0; i < nslices; i++) { + gpr_slice_unref(slices[i]); + } + + if (error != GRPC_ENDPOINT_CB_OK) { grpc_endpoint_destroy(st->ep); gpr_mu_lock(GRPC_POLLSET_MU(g_pollset)); - st->done = 1; + st->done = error; grpc_pollset_kick(g_pollset, NULL); gpr_mu_unlock(GRPC_POLLSET_MU(g_pollset)); } else { - switch (grpc_endpoint_read(st->ep, &st->incoming, &st->done_read)) { - case GRPC_ENDPOINT_PENDING: - break; - case GRPC_ENDPOINT_ERROR: - shutdown_during_write_test_read_handler(user_data, 0); - break; - case GRPC_ENDPOINT_DONE: - shutdown_during_write_test_read_handler(user_data, 1); - break; - } + grpc_endpoint_notify_on_read( + st->ep, shutdown_during_write_test_read_handler, user_data); } } -static void shutdown_during_write_test_write_handler(void *user_data, - int success) { +static void shutdown_during_write_test_write_handler( + void *user_data, grpc_endpoint_cb_status error) { shutdown_during_write_test_state *st = user_data; - gpr_log(GPR_INFO, "shutdown_during_write_test_write_handler: success = %d", - success); - if (success) { + gpr_log(GPR_INFO, "shutdown_during_write_test_write_handler: error = %d", + error); + if (error == 0) { /* This happens about 0.5% of the time when run under TSAN, and is entirely legitimate, but means we aren't testing the path we think we are. */ /* TODO(klempner): Change this test to retry the write in that case */ @@ -334,8 +325,6 @@ static void shutdown_during_write_test(grpc_endpoint_test_config config, shutdown_during_write_test_state read_st; shutdown_during_write_test_state write_st; gpr_slice *slices; - gpr_slice_buffer outgoing; - grpc_iomgr_closure done_write; grpc_endpoint_test_fixture f = begin_test(config, "shutdown_during_write_test", slice_size); @@ -346,26 +335,19 @@ static void shutdown_during_write_test(grpc_endpoint_test_config config, read_st.done = 0; write_st.done = 0; - grpc_iomgr_closure_init(&done_write, shutdown_during_write_test_write_handler, - &write_st); - grpc_iomgr_closure_init(&read_st.done_read, - shutdown_during_write_test_read_handler, &read_st); - gpr_slice_buffer_init(&read_st.incoming); - gpr_slice_buffer_init(&outgoing); - - GPR_ASSERT(grpc_endpoint_read(read_st.ep, &read_st.incoming, - &read_st.done_read) == GRPC_ENDPOINT_PENDING); + grpc_endpoint_notify_on_read( + read_st.ep, shutdown_during_write_test_read_handler, &read_st); for (size = 1;; size *= 2) { slices = allocate_blocks(size, 1, &nblocks, ¤t_data); - gpr_slice_buffer_reset_and_unref(&outgoing); - gpr_slice_buffer_addn(&outgoing, slices, nblocks); - switch (grpc_endpoint_write(write_st.ep, &outgoing, &done_write)) { - case GRPC_ENDPOINT_DONE: + switch (grpc_endpoint_write(write_st.ep, slices, nblocks, + shutdown_during_write_test_write_handler, + &write_st)) { + case GRPC_ENDPOINT_WRITE_DONE: break; - case GRPC_ENDPOINT_ERROR: + case GRPC_ENDPOINT_WRITE_ERROR: gpr_log(GPR_ERROR, "error writing"); abort(); - case GRPC_ENDPOINT_PENDING: + case GRPC_ENDPOINT_WRITE_PENDING: grpc_endpoint_shutdown(write_st.ep); deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10); gpr_mu_lock(GRPC_POLLSET_MU(g_pollset)); @@ -386,8 +368,6 @@ static void shutdown_during_write_test(grpc_endpoint_test_config config, } gpr_mu_unlock(GRPC_POLLSET_MU(g_pollset)); gpr_free(slices); - gpr_slice_buffer_destroy(&read_st.incoming); - gpr_slice_buffer_destroy(&outgoing); end_test(config); return; } diff --git a/test/core/iomgr/tcp_posix_test.c b/test/core/iomgr/tcp_posix_test.c index 8acaa433bb..6ad832231f 100644 --- a/test/core/iomgr/tcp_posix_test.c +++ b/test/core/iomgr/tcp_posix_test.c @@ -118,12 +118,10 @@ struct read_socket_state { grpc_endpoint *ep; ssize_t read_bytes; ssize_t target_read_bytes; - gpr_slice_buffer incoming; - grpc_iomgr_closure read_cb; }; -static ssize_t count_slices(gpr_slice *slices, size_t nslices, - int *current_data) { +static ssize_t count_and_unref_slices(gpr_slice *slices, size_t nslices, + int *current_data) { ssize_t num_bytes = 0; unsigned i, j; unsigned char *buf; @@ -134,41 +132,31 @@ static ssize_t count_slices(gpr_slice *slices, size_t nslices, *current_data = (*current_data + 1) % 256; } num_bytes += GPR_SLICE_LENGTH(slices[i]); + gpr_slice_unref(slices[i]); } return num_bytes; } -static void read_cb(void *user_data, int success) { +static void read_cb(void *user_data, gpr_slice *slices, size_t nslices, + grpc_endpoint_cb_status error) { struct read_socket_state *state = (struct read_socket_state *)user_data; ssize_t read_bytes; int current_data; - GPR_ASSERT(success); + GPR_ASSERT(error == GRPC_ENDPOINT_CB_OK); gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset)); current_data = state->read_bytes % 256; - read_bytes = count_slices(state->incoming.slices, state->incoming.count, - ¤t_data); + read_bytes = count_and_unref_slices(slices, nslices, ¤t_data); state->read_bytes += read_bytes; gpr_log(GPR_INFO, "Read %d bytes of %d", read_bytes, state->target_read_bytes); if (state->read_bytes >= state->target_read_bytes) { - gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset)); + /* empty */ } else { - switch (grpc_endpoint_read(state->ep, &state->incoming, &state->read_cb)) { - case GRPC_ENDPOINT_DONE: - gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset)); - read_cb(user_data, 1); - break; - case GRPC_ENDPOINT_ERROR: - gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset)); - read_cb(user_data, 0); - break; - case GRPC_ENDPOINT_PENDING: - gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset)); - break; - } + grpc_endpoint_notify_on_read(state->ep, read_cb, state); } + gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset)); } /* Write to a socket, then read from it using the grpc_tcp API. */ @@ -193,19 +181,8 @@ static void read_test(ssize_t num_bytes, ssize_t slice_size) { state.ep = ep; state.read_bytes = 0; state.target_read_bytes = written_bytes; - gpr_slice_buffer_init(&state.incoming); - grpc_iomgr_closure_init(&state.read_cb, read_cb, &state); - switch (grpc_endpoint_read(ep, &state.incoming, &state.read_cb)) { - case GRPC_ENDPOINT_DONE: - read_cb(&state, 1); - break; - case GRPC_ENDPOINT_ERROR: - read_cb(&state, 0); - break; - case GRPC_ENDPOINT_PENDING: - break; - } + grpc_endpoint_notify_on_read(ep, read_cb, &state); gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset)); while (state.read_bytes < state.target_read_bytes) { @@ -216,7 +193,6 @@ static void read_test(ssize_t num_bytes, ssize_t slice_size) { GPR_ASSERT(state.read_bytes == state.target_read_bytes); gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset)); - gpr_slice_buffer_destroy(&state.incoming); grpc_endpoint_destroy(ep); } @@ -243,19 +219,8 @@ static void large_read_test(ssize_t slice_size) { state.ep = ep; state.read_bytes = 0; state.target_read_bytes = written_bytes; - gpr_slice_buffer_init(&state.incoming); - grpc_iomgr_closure_init(&state.read_cb, read_cb, &state); - switch (grpc_endpoint_read(ep, &state.incoming, &state.read_cb)) { - case GRPC_ENDPOINT_DONE: - read_cb(&state, 1); - break; - case GRPC_ENDPOINT_ERROR: - read_cb(&state, 0); - break; - case GRPC_ENDPOINT_PENDING: - break; - } + grpc_endpoint_notify_on_read(ep, read_cb, &state); gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset)); while (state.read_bytes < state.target_read_bytes) { @@ -266,7 +231,6 @@ static void large_read_test(ssize_t slice_size) { GPR_ASSERT(state.read_bytes == state.target_read_bytes); gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset)); - gpr_slice_buffer_destroy(&state.incoming); grpc_endpoint_destroy(ep); } @@ -298,7 +262,8 @@ static gpr_slice *allocate_blocks(ssize_t num_bytes, ssize_t slice_size, return slices; } -static void write_done(void *user_data /* write_socket_state */, int success) { +static void write_done(void *user_data /* write_socket_state */, + grpc_endpoint_cb_status error) { struct write_socket_state *state = (struct write_socket_state *)user_data; gpr_log(GPR_INFO, "Write done callback called"); gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset)); @@ -374,8 +339,6 @@ static void write_test(ssize_t num_bytes, ssize_t slice_size) { size_t num_blocks; gpr_slice *slices; int current_data = 0; - gpr_slice_buffer outgoing; - grpc_iomgr_closure write_done_closure; gpr_timespec deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(20); gpr_log(GPR_INFO, "Start write test with %d bytes, slice size %d", num_bytes, @@ -392,21 +355,74 @@ static void write_test(ssize_t num_bytes, ssize_t slice_size) { slices = allocate_blocks(num_bytes, slice_size, &num_blocks, ¤t_data); - gpr_slice_buffer_init(&outgoing); - gpr_slice_buffer_addn(&outgoing, slices, num_blocks); - grpc_iomgr_closure_init(&write_done_closure, write_done, &state); + if (grpc_endpoint_write(ep, slices, num_blocks, write_done, &state) == + GRPC_ENDPOINT_WRITE_DONE) { + /* Write completed immediately */ + read_bytes = drain_socket(sv[0]); + GPR_ASSERT(read_bytes == num_bytes); + } else { + drain_socket_blocking(sv[0], num_bytes, num_bytes); + gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset)); + for (;;) { + grpc_pollset_worker worker; + if (state.write_done) { + break; + } + grpc_pollset_work(&g_pollset, &worker, gpr_now(GPR_CLOCK_MONOTONIC), + deadline); + } + gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset)); + } + + grpc_endpoint_destroy(ep); + gpr_free(slices); +} + +static void read_done_for_write_error(void *ud, gpr_slice *slices, + size_t nslices, + grpc_endpoint_cb_status error) { + GPR_ASSERT(error != GRPC_ENDPOINT_CB_OK); + GPR_ASSERT(nslices == 0); +} + +/* Write to a socket using the grpc_tcp API, then drain it directly. + Note that if the write does not complete immediately we need to drain the + socket in parallel with the read. */ +static void write_error_test(ssize_t num_bytes, ssize_t slice_size) { + int sv[2]; + grpc_endpoint *ep; + struct write_socket_state state; + size_t num_blocks; + gpr_slice *slices; + int current_data = 0; + grpc_pollset_worker worker; + gpr_timespec deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(20); + + gpr_log(GPR_INFO, "Start write error test with %d bytes, slice size %d", + num_bytes, slice_size); + + create_sockets(sv); - switch (grpc_endpoint_write(ep, &outgoing, &write_done_closure)) { - case GRPC_ENDPOINT_DONE: + ep = grpc_tcp_create(grpc_fd_create(sv[1], "write_error_test"), + GRPC_TCP_DEFAULT_READ_SLICE_SIZE, "test"); + grpc_endpoint_add_to_pollset(ep, &g_pollset); + + close(sv[0]); + + state.ep = ep; + state.write_done = 0; + + slices = allocate_blocks(num_bytes, slice_size, &num_blocks, ¤t_data); + + switch (grpc_endpoint_write(ep, slices, num_blocks, write_done, &state)) { + case GRPC_ENDPOINT_WRITE_DONE: + case GRPC_ENDPOINT_WRITE_ERROR: /* Write completed immediately */ - read_bytes = drain_socket(sv[0]); - GPR_ASSERT(read_bytes == num_bytes); break; - case GRPC_ENDPOINT_PENDING: - drain_socket_blocking(sv[0], num_bytes, num_bytes); + case GRPC_ENDPOINT_WRITE_PENDING: + grpc_endpoint_notify_on_read(ep, read_done_for_write_error, NULL); gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset)); for (;;) { - grpc_pollset_worker worker; if (state.write_done) { break; } @@ -415,14 +431,10 @@ static void write_test(ssize_t num_bytes, ssize_t slice_size) { } gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset)); break; - case GRPC_ENDPOINT_ERROR: - gpr_log(GPR_ERROR, "endpoint got error"); - abort(); } - gpr_slice_buffer_destroy(&outgoing); grpc_endpoint_destroy(ep); - gpr_free(slices); + free(slices); } void run_tests(void) { @@ -441,6 +453,10 @@ void run_tests(void) { write_test(100000, 1); write_test(100000, 137); + for (i = 1; i < 1000; i = GPR_MAX(i + 1, i * 5 / 4)) { + write_error_test(40320, i); + } + for (i = 1; i < 1000; i = GPR_MAX(i + 1, i * 5 / 4)) { write_test(40320, i); } diff --git a/test/core/security/secure_endpoint_test.c b/test/core/security/secure_endpoint_test.c index c76ddcd194..a8368fc842 100644 --- a/test/core/security/secure_endpoint_test.c +++ b/test/core/security/secure_endpoint_test.c @@ -135,26 +135,62 @@ static grpc_endpoint_test_config configs[] = { secure_endpoint_create_fixture_tcp_socketpair_leftover, clean_up}, }; -static void test_leftover(grpc_endpoint_test_config config, size_t slice_size) { - grpc_endpoint_test_fixture f = config.create_fixture(slice_size); - gpr_slice_buffer incoming; +static void verify_leftover(void *user_data, gpr_slice *slices, size_t nslices, + grpc_endpoint_cb_status error) { gpr_slice s = gpr_slice_from_copied_string("hello world 12345678900987654321"); + + GPR_ASSERT(error == GRPC_ENDPOINT_CB_OK); + GPR_ASSERT(nslices == 1); + + GPR_ASSERT(0 == gpr_slice_cmp(s, slices[0])); + gpr_slice_unref(slices[0]); + gpr_slice_unref(s); + *(int *)user_data = 1; +} + +static void test_leftover(grpc_endpoint_test_config config, size_t slice_size) { + grpc_endpoint_test_fixture f = config.create_fixture(slice_size); + int verified = 0; gpr_log(GPR_INFO, "Start test left over"); - gpr_slice_buffer_init(&incoming); - GPR_ASSERT(grpc_endpoint_read(f.client_ep, &incoming, NULL) == - GRPC_ENDPOINT_DONE); - GPR_ASSERT(incoming.count == 1); - GPR_ASSERT(0 == gpr_slice_cmp(s, incoming.slices[0])); + grpc_endpoint_notify_on_read(f.client_ep, verify_leftover, &verified); + GPR_ASSERT(verified == 1); grpc_endpoint_shutdown(f.client_ep); grpc_endpoint_shutdown(f.server_ep); grpc_endpoint_destroy(f.client_ep); grpc_endpoint_destroy(f.server_ep); + clean_up(); +} + +static void destroy_early(void *user_data, gpr_slice *slices, size_t nslices, + grpc_endpoint_cb_status error) { + grpc_endpoint_test_fixture *f = user_data; + gpr_slice s = + gpr_slice_from_copied_string("hello world 12345678900987654321"); + + GPR_ASSERT(error == GRPC_ENDPOINT_CB_OK); + GPR_ASSERT(nslices == 1); + + grpc_endpoint_shutdown(f->client_ep); + grpc_endpoint_destroy(f->client_ep); + + GPR_ASSERT(0 == gpr_slice_cmp(s, slices[0])); + gpr_slice_unref(slices[0]); gpr_slice_unref(s); - gpr_slice_buffer_destroy(&incoming); +} +/* test which destroys the ep before finishing reading */ +static void test_destroy_ep_early(grpc_endpoint_test_config config, + size_t slice_size) { + grpc_endpoint_test_fixture f = config.create_fixture(slice_size); + gpr_log(GPR_INFO, "Start test destroy early"); + + grpc_endpoint_notify_on_read(f.client_ep, destroy_early, &f); + + grpc_endpoint_shutdown(f.server_ep); + grpc_endpoint_destroy(f.server_ep); clean_up(); } @@ -167,6 +203,7 @@ int main(int argc, char **argv) { grpc_pollset_init(&g_pollset); grpc_endpoint_tests(configs[0], &g_pollset); test_leftover(configs[1], 1); + test_destroy_ep_early(configs[1], 1); grpc_pollset_shutdown(&g_pollset, destroy_pollset, &g_pollset); grpc_iomgr_shutdown(); diff --git a/test/core/util/port_posix.c b/test/core/util/port_posix.c index 4781d334e2..836e62a541 100644 --- a/test/core/util/port_posix.c +++ b/test/core/util/port_posix.c @@ -198,13 +198,14 @@ int grpc_pick_unused_port(void) { races with other processes on kernels that want to reuse the same port numbers over and over. */ - /* In alternating iterations we trial UDP ports before TCP ports UDP + /* In alternating iterations we try UDP ports before TCP ports UDP ports -- it could be the case that this machine has been using up UDP ports and they are scarcer. */ /* Type of port to first pick in next iteration */ int is_tcp = 1; - int trial = 0; + int try + = 0; char *env = gpr_getenv("GRPC_TEST_PORT_SERVER"); if (env) { @@ -217,10 +218,11 @@ int grpc_pick_unused_port(void) { for (;;) { int port; - trial++; - if (trial == 1) { + try + ++; + if (try == 1) { port = getpid() % (65536 - 30000) + 30000; - } else if (trial <= NUM_RANDOM_PORTS_TO_PICK) { + } else if (try <= NUM_RANDOM_PORTS_TO_PICK) { port = rand() % (65536 - 30000) + 30000; } else { port = 0; @@ -237,7 +239,7 @@ int grpc_pick_unused_port(void) { GPR_ASSERT(port > 0); /* Check that the port # is free for the other type of socket also */ if (!is_port_available(&port, !is_tcp)) { - /* In the next iteration trial to bind to the other type first + /* In the next iteration try to bind to the other type first because perhaps it is more rare. */ is_tcp = !is_tcp; continue; diff --git a/test/core/util/port_windows.c b/test/core/util/port_windows.c index 2f64626cf3..5b072f805a 100644 --- a/test/core/util/port_windows.c +++ b/test/core/util/port_windows.c @@ -35,6 +35,7 @@ #include "test/core/util/test_config.h" #if defined(GPR_WINSOCK_SOCKET) && defined(GRPC_TEST_PICK_PORT) +#include "src/core/iomgr/sockaddr_utils.h" #include "test/core/util/port.h" #include @@ -42,14 +43,8 @@ #include #include -#include -#include #include -#include "src/core/support/env.h" -#include "src/core/httpcli/httpcli.h" -#include "src/core/iomgr/sockaddr_utils.h" - #define NUM_RANDOM_PORTS_TO_PICK 100 static int is_port_available(int *port, int is_tcp) { @@ -104,67 +99,6 @@ static int is_port_available(int *port, int is_tcp) { return 1; } -typedef struct portreq { - grpc_pollset pollset; - int port; -} portreq; - -static void got_port_from_server(void *arg, - const grpc_httpcli_response *response) { - size_t i; - int port = 0; - portreq *pr = arg; - GPR_ASSERT(response); - GPR_ASSERT(response->status == 200); - for (i = 0; i < response->body_length; i++) { - GPR_ASSERT(response->body[i] >= '0' && response->body[i] <= '9'); - port = port * 10 + response->body[i] - '0'; - } - GPR_ASSERT(port > 1024); - gpr_mu_lock(GRPC_POLLSET_MU(&pr->pollset)); - pr->port = port; - grpc_pollset_kick(&pr->pollset, NULL); - gpr_mu_unlock(GRPC_POLLSET_MU(&pr->pollset)); -} - -static void destroy_pollset_and_shutdown(void *p) { - grpc_pollset_destroy(p); - grpc_shutdown(); -} - -static int pick_port_using_server(char *server) { - grpc_httpcli_context context; - grpc_httpcli_request req; - portreq pr; - - grpc_init(); - - memset(&pr, 0, sizeof(pr)); - memset(&req, 0, sizeof(req)); - grpc_pollset_init(&pr.pollset); - pr.port = -1; - - req.host = server; - req.path = "/get"; - - grpc_httpcli_context_init(&context); - grpc_httpcli_get(&context, &pr.pollset, &req, - GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10), got_port_from_server, - &pr); - gpr_mu_lock(GRPC_POLLSET_MU(&pr.pollset)); - while (pr.port == -1) { - grpc_pollset_worker worker; - grpc_pollset_work(&pr.pollset, &worker, gpr_now(GPR_CLOCK_MONOTONIC), - GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1)); - } - gpr_mu_unlock(GRPC_POLLSET_MU(&pr.pollset)); - - grpc_httpcli_context_destroy(&context); - grpc_pollset_shutdown(&pr.pollset, destroy_pollset_and_shutdown, &pr.pollset); - - return pr.port; -} - int grpc_pick_unused_port(void) { /* We repeatedly pick a port and then see whether or not it is available for use both as a TCP socket and a UDP socket. First, we @@ -174,29 +108,22 @@ int grpc_pick_unused_port(void) { races with other processes on kernels that want to reuse the same port numbers over and over. */ - /* In alternating iterations we trial UDP ports before TCP ports UDP + /* In alternating iterations we try UDP ports before TCP ports UDP ports -- it could be the case that this machine has been using up UDP ports and they are scarcer. */ /* Type of port to first pick in next iteration */ int is_tcp = 1; - int trial = 0; - - char *env = gpr_getenv("GRPC_TEST_PORT_SERVER"); - if (env) { - int port = pick_port_using_server(env); - gpr_free(env); - if (port != 0) { - return port; - } - } + int try + = 0; for (;;) { int port; - trial++; - if (trial == 1) { + try + ++; + if (try == 1) { port = _getpid() % (65536 - 30000) + 30000; - } else if (trial <= NUM_RANDOM_PORTS_TO_PICK) { + } else if (try <= NUM_RANDOM_PORTS_TO_PICK) { port = rand() % (65536 - 30000) + 30000; } else { port = 0; @@ -209,7 +136,7 @@ int grpc_pick_unused_port(void) { GPR_ASSERT(port > 0); /* Check that the port # is free for the other type of socket also */ if (!is_port_available(&port, !is_tcp)) { - /* In the next iteration trial to bind to the other type first + /* In the next iteration try to bind to the other type first because perhaps it is more rare. */ is_tcp = !is_tcp; continue; -- cgit v1.2.3 From dafcce980d847e3a90cb7aa31641c464bbc5809a Mon Sep 17 00:00:00 2001 From: yang-g Date: Thu, 27 Aug 2015 11:34:05 -0700 Subject: channel creation API change --- include/grpc++/create_channel.h | 6 ++++++ src/cpp/client/create_channel.cc | 8 +++++++- 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/grpc++/create_channel.h b/include/grpc++/create_channel.h index 0e559ac53e..916f3b0b97 100644 --- a/include/grpc++/create_channel.h +++ b/include/grpc++/create_channel.h @@ -44,6 +44,12 @@ namespace grpc { // If creds does not hold an object or is invalid, a lame channel is returned. std::shared_ptr CreateChannel( + const grpc::string& target, const std::shared_ptr& creds); + +// For advanced use and testing ONLY. Override default channel arguments only +// if necessary. +// If creds does not hold an object or is invalid, a lame channel is returned. +std::shared_ptr CreateCustomChannel( const grpc::string& target, const std::shared_ptr& creds, const ChannelArguments& args); diff --git a/src/cpp/client/create_channel.cc b/src/cpp/client/create_channel.cc index 8c571cbbaa..8d2f1bf37a 100644 --- a/src/cpp/client/create_channel.cc +++ b/src/cpp/client/create_channel.cc @@ -43,7 +43,12 @@ namespace grpc { class ChannelArguments; -std::shared_ptr CreateChannel( +std::shared_ptr CreateCustomChannel( + const grpc::string& target, const std::shared_ptr& creds) { + return CreateCustomChannel(target, creds, ChannelArguments()); +} + +std::shared_ptr CreateCustomChannel( const grpc::string& target, const std::shared_ptr& creds, const ChannelArguments& args) { ChannelArguments cp_args = args; @@ -57,4 +62,5 @@ std::shared_ptr CreateChannel( NULL, GRPC_STATUS_INVALID_ARGUMENT, "Invalid credentials.")); } + } // namespace grpc -- cgit v1.2.3 From 730055d9628ca6d27e46d7c6716148a8d93bf95d Mon Sep 17 00:00:00 2001 From: yang-g Date: Thu, 27 Aug 2015 12:29:45 -0700 Subject: implementation fix --- include/grpc++/credentials.h | 2 +- src/cpp/client/create_channel.cc | 2 +- test/cpp/end2end/async_end2end_test.cc | 8 ++++---- test/cpp/end2end/client_crash_test.cc | 2 +- test/cpp/end2end/end2end_test.cc | 9 ++++----- test/cpp/end2end/generic_end2end_test.cc | 4 ++-- test/cpp/end2end/mock_test.cc | 4 ++-- test/cpp/end2end/server_crash_test_client.cc | 4 ++-- test/cpp/end2end/shutdown_test.cc | 2 +- test/cpp/end2end/thread_stress_test.cc | 4 ++-- test/cpp/end2end/zookeeper_test.cc | 2 +- test/cpp/qps/driver.cc | 8 ++++---- test/cpp/qps/report.h | 4 ++-- test/cpp/util/cli_call_test.cc | 3 +-- test/cpp/util/create_test_channel.cc | 4 ++-- test/cpp/util/grpc_cli.cc | 2 +- 16 files changed, 31 insertions(+), 33 deletions(-) (limited to 'include') diff --git a/include/grpc++/credentials.h b/include/grpc++/credentials.h index 71e1f00f15..d623bcef60 100644 --- a/include/grpc++/credentials.h +++ b/include/grpc++/credentials.h @@ -57,7 +57,7 @@ class Credentials : public GrpcLibrary { virtual SecureCredentials* AsSecureCredentials() = 0; private: - friend std::shared_ptr CreateChannel( + friend std::shared_ptr CreateCustomChannel( const grpc::string& target, const std::shared_ptr& creds, const ChannelArguments& args); diff --git a/src/cpp/client/create_channel.cc b/src/cpp/client/create_channel.cc index 8d2f1bf37a..1dac960017 100644 --- a/src/cpp/client/create_channel.cc +++ b/src/cpp/client/create_channel.cc @@ -43,7 +43,7 @@ namespace grpc { class ChannelArguments; -std::shared_ptr CreateCustomChannel( +std::shared_ptr CreateChannel( const grpc::string& target, const std::shared_ptr& creds) { return CreateCustomChannel(target, creds, ChannelArguments()); } diff --git a/test/cpp/end2end/async_end2end_test.cc b/test/cpp/end2end/async_end2end_test.cc index 41b91e459b..bbcac9ba34 100644 --- a/test/cpp/end2end/async_end2end_test.cc +++ b/test/cpp/end2end/async_end2end_test.cc @@ -200,8 +200,8 @@ class AsyncEnd2endTest : public ::testing::TestWithParam { } void ResetStub() { - std::shared_ptr channel = CreateChannel( - server_address_.str(), InsecureCredentials(), ChannelArguments()); + std::shared_ptr channel = + CreateChannel(server_address_.str(), InsecureCredentials()); stub_ = std::move(grpc::cpp::test::util::TestService::NewStub(channel)); } @@ -750,8 +750,8 @@ TEST_P(AsyncEnd2endTest, ServerCheckDone) { } TEST_P(AsyncEnd2endTest, UnimplementedRpc) { - std::shared_ptr channel = CreateChannel( - server_address_.str(), InsecureCredentials(), ChannelArguments()); + std::shared_ptr channel = + CreateChannel(server_address_.str(), InsecureCredentials()); std::unique_ptr stub; stub = std::move(grpc::cpp::test::util::UnimplementedService::NewStub(channel)); diff --git a/test/cpp/end2end/client_crash_test.cc b/test/cpp/end2end/client_crash_test.cc index 3359080cec..3a6e55216a 100644 --- a/test/cpp/end2end/client_crash_test.cc +++ b/test/cpp/end2end/client_crash_test.cc @@ -76,7 +76,7 @@ class CrashTest : public ::testing::Test { })); GPR_ASSERT(server_); return grpc::cpp::test::util::TestService::NewStub( - CreateChannel(addr, InsecureCredentials(), ChannelArguments())); + CreateChannel(addr, InsecureCredentials())); } void KillServer() { server_.reset(); } diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc index 9826837c60..37a6e693e6 100644 --- a/test/cpp/end2end/end2end_test.cc +++ b/test/cpp/end2end/end2end_test.cc @@ -291,8 +291,8 @@ class End2endTest : public ::testing::TestWithParam { ChannelArguments args; args.SetSslTargetNameOverride("foo.test.google.fr"); args.SetString(GRPC_ARG_SECONDARY_USER_AGENT_STRING, "end2end_test"); - channel_ = - CreateChannel(server_address_.str(), SslCredentials(ssl_opts), args); + channel_ = CreateCustomChannel(server_address_.str(), + SslCredentials(ssl_opts), args); } void ResetStub(bool use_proxy) { @@ -307,8 +307,7 @@ class End2endTest : public ::testing::TestWithParam { builder.RegisterService(proxy_service_.get()); proxy_server_ = builder.BuildAndStart(); - channel_ = CreateChannel(proxyaddr.str(), InsecureCredentials(), - ChannelArguments()); + channel_ = CreateChannel(proxyaddr.str(), InsecureCredentials()); } stub_ = std::move(grpc::cpp::test::util::TestService::NewStub(channel_)); @@ -566,7 +565,7 @@ TEST_F(End2endTest, BadCredentials) { std::shared_ptr bad_creds = ServiceAccountCredentials("", "", 1); EXPECT_EQ(static_cast(nullptr), bad_creds.get()); std::shared_ptr channel = - CreateChannel(server_address_.str(), bad_creds, ChannelArguments()); + CreateChannel(server_address_.str(), bad_creds); std::unique_ptr stub( grpc::cpp::test::util::TestService::NewStub(channel)); EchoRequest request; diff --git a/test/cpp/end2end/generic_end2end_test.cc b/test/cpp/end2end/generic_end2end_test.cc index 809eef058c..7acbc711fb 100644 --- a/test/cpp/end2end/generic_end2end_test.cc +++ b/test/cpp/end2end/generic_end2end_test.cc @@ -121,8 +121,8 @@ class GenericEnd2endTest : public ::testing::Test { } void ResetStub() { - std::shared_ptr channel = CreateChannel( - server_address_.str(), InsecureCredentials(), ChannelArguments()); + std::shared_ptr channel = + CreateChannel(server_address_.str(), InsecureCredentials()); generic_stub_.reset(new GenericStub(channel)); } diff --git a/test/cpp/end2end/mock_test.cc b/test/cpp/end2end/mock_test.cc index b2c6dc39a8..077d21aa72 100644 --- a/test/cpp/end2end/mock_test.cc +++ b/test/cpp/end2end/mock_test.cc @@ -245,8 +245,8 @@ class MockTest : public ::testing::Test { void TearDown() GRPC_OVERRIDE { server_->Shutdown(); } void ResetStub() { - std::shared_ptr channel = CreateChannel( - server_address_.str(), InsecureCredentials(), ChannelArguments()); + std::shared_ptr channel = + CreateChannel(server_address_.str(), InsecureCredentials()); stub_ = std::move(grpc::cpp::test::util::TestService::NewStub(channel)); } diff --git a/test/cpp/end2end/server_crash_test_client.cc b/test/cpp/end2end/server_crash_test_client.cc index 7ca43a0c5b..6ff42fcb30 100644 --- a/test/cpp/end2end/server_crash_test_client.cc +++ b/test/cpp/end2end/server_crash_test_client.cc @@ -58,8 +58,8 @@ using namespace gflags; int main(int argc, char** argv) { ParseCommandLineFlags(&argc, &argv, true); - auto stub = grpc::cpp::test::util::TestService::NewStub(grpc::CreateChannel( - FLAGS_address, grpc::InsecureCredentials(), grpc::ChannelArguments())); + auto stub = grpc::cpp::test::util::TestService::NewStub( + grpc::CreateChannel(FLAGS_address, grpc::InsecureCredentials())); EchoRequest request; EchoResponse response; diff --git a/test/cpp/end2end/shutdown_test.cc b/test/cpp/end2end/shutdown_test.cc index e83f86f7ec..59fec6ad40 100644 --- a/test/cpp/end2end/shutdown_test.cc +++ b/test/cpp/end2end/shutdown_test.cc @@ -95,7 +95,7 @@ class ShutdownTest : public ::testing::Test { void ResetStub() { string target = "dns:localhost:" + to_string(port_); - channel_ = CreateChannel(target, InsecureCredentials(), ChannelArguments()); + channel_ = CreateChannel(target, InsecureCredentials()); stub_ = std::move(grpc::cpp::test::util::TestService::NewStub(channel_)); } diff --git a/test/cpp/end2end/thread_stress_test.cc b/test/cpp/end2end/thread_stress_test.cc index 8304f04d56..2a16481972 100644 --- a/test/cpp/end2end/thread_stress_test.cc +++ b/test/cpp/end2end/thread_stress_test.cc @@ -191,8 +191,8 @@ class End2endTest : public ::testing::Test { void TearDown() GRPC_OVERRIDE { server_->Shutdown(); } void ResetStub() { - std::shared_ptr channel = CreateChannel( - server_address_.str(), InsecureCredentials(), ChannelArguments()); + std::shared_ptr channel = + CreateChannel(server_address_.str(), InsecureCredentials()); stub_ = std::move(grpc::cpp::test::util::TestService::NewStub(channel)); } diff --git a/test/cpp/end2end/zookeeper_test.cc b/test/cpp/end2end/zookeeper_test.cc index e7d95b1c46..931541ca34 100644 --- a/test/cpp/end2end/zookeeper_test.cc +++ b/test/cpp/end2end/zookeeper_test.cc @@ -159,7 +159,7 @@ class ZookeeperTest : public ::testing::Test { void ResetStub() { string target = "zookeeper://" + zookeeper_address_ + "/test"; - channel_ = CreateChannel(target, InsecureCredentials(), ChannelArguments()); + channel_ = CreateChannel(target, InsecureCredentials()); stub_ = std::move(grpc::cpp::test::util::TestService::NewStub(channel_)); } diff --git a/test/cpp/qps/driver.cc b/test/cpp/qps/driver.cc index 3bd61ea4e8..0e771d6b81 100644 --- a/test/cpp/qps/driver.cc +++ b/test/cpp/qps/driver.cc @@ -154,8 +154,8 @@ std::unique_ptr RunScenario( // where class contained in std::vector must have a copy constructor auto* servers = new ServerData[num_servers]; for (size_t i = 0; i < num_servers; i++) { - servers[i].stub = std::move(Worker::NewStub( - CreateChannel(workers[i], InsecureCredentials(), ChannelArguments()))); + servers[i].stub = std::move( + Worker::NewStub(CreateChannel(workers[i], InsecureCredentials()))); ServerArgs args; result_server_config = server_config; result_server_config.set_host(workers[i]); @@ -182,8 +182,8 @@ std::unique_ptr RunScenario( // where class contained in std::vector must have a copy constructor auto* clients = new ClientData[num_clients]; for (size_t i = 0; i < num_clients; i++) { - clients[i].stub = std::move(Worker::NewStub(CreateChannel( - workers[i + num_servers], InsecureCredentials(), ChannelArguments()))); + clients[i].stub = std::move(Worker::NewStub( + CreateChannel(workers[i + num_servers], InsecureCredentials()))); ClientArgs args; result_client_config = client_config; result_client_config.set_host(workers[i + num_servers]); diff --git a/test/cpp/qps/report.h b/test/cpp/qps/report.h index 620abade39..5914fc4e30 100644 --- a/test/cpp/qps/report.h +++ b/test/cpp/qps/report.h @@ -116,8 +116,8 @@ class PerfDbReporter : public Reporter { test_name_(test_name), sys_info_(sys_info), tag_(tag) { - perf_db_client_.init(grpc::CreateChannel( - server_address, grpc::InsecureCredentials(), ChannelArguments())); + perf_db_client_.init( + grpc::CreateChannel(server_address, grpc::InsecureCredentials())); } ~PerfDbReporter() GRPC_OVERRIDE { SendData(); }; diff --git a/test/cpp/util/cli_call_test.cc b/test/cpp/util/cli_call_test.cc index 111a0e9f76..0efa201622 100644 --- a/test/cpp/util/cli_call_test.cc +++ b/test/cpp/util/cli_call_test.cc @@ -91,8 +91,7 @@ class CliCallTest : public ::testing::Test { void TearDown() GRPC_OVERRIDE { server_->Shutdown(); } void ResetStub() { - channel_ = CreateChannel(server_address_.str(), InsecureCredentials(), - ChannelArguments()); + channel_ = CreateChannel(server_address_.str(), InsecureCredentials()); stub_ = std::move(grpc::cpp::test::util::TestService::NewStub(channel_)); } diff --git a/test/cpp/util/create_test_channel.cc b/test/cpp/util/create_test_channel.cc index 161b4bdc1d..e993d14e71 100644 --- a/test/cpp/util/create_test_channel.cc +++ b/test/cpp/util/create_test_channel.cc @@ -74,9 +74,9 @@ std::shared_ptr CreateTestChannel( if (creds.get()) { channel_creds = CompositeCredentials(creds, channel_creds); } - return CreateChannel(connect_to, channel_creds, channel_args); + return CreateCustomChannel(connect_to, channel_creds, channel_args); } else { - return CreateChannel(server, InsecureCredentials(), channel_args); + return CreateChannel(server, InsecureCredentials()); } } diff --git a/test/cpp/util/grpc_cli.cc b/test/cpp/util/grpc_cli.cc index a4888efebe..22cac21f77 100644 --- a/test/cpp/util/grpc_cli.cc +++ b/test/cpp/util/grpc_cli.cc @@ -159,7 +159,7 @@ int main(int argc, char** argv) { } } std::shared_ptr channel = - grpc::CreateChannel(server_address, creds, grpc::ChannelArguments()); + grpc::CreateChannel(server_address, creds); grpc::string response; std::multimap client_metadata; -- cgit v1.2.3