diff options
author | 2015-11-21 09:00:11 -0800 | |
---|---|---|
committer | 2015-11-21 09:00:11 -0800 | |
commit | d653b394714b1fa342f0872c8262c8cde5511f4b (patch) | |
tree | 91573a209f253d58bb4a8b14d759db7e80167b3a /src | |
parent | 860f484f43841d14df61cfeda6ca5e637ed99d19 (diff) | |
parent | ceb7318d794b4174e18364f6780a5d20e6249e23 (diff) |
Merge github.com:grpc/grpc into better-profile
Diffstat (limited to 'src')
154 files changed, 7600 insertions, 1638 deletions
diff --git a/src/core/client_config/subchannel.c b/src/core/client_config/subchannel.c index 49c2cf9a19..b15a9033af 100644 --- a/src/core/client_config/subchannel.c +++ b/src/core/client_config/subchannel.c @@ -697,10 +697,25 @@ static double generate_uniform_random_number(grpc_subchannel *c) { /* Update backoff_delta and next_attempt in subchannel */ static void update_reconnect_parameters(grpc_subchannel *c) { + size_t i; gpr_int32 backoff_delta_millis, jitter; gpr_int32 max_backoff_millis = GRPC_SUBCHANNEL_RECONNECT_MAX_BACKOFF_SECONDS * 1000; double jitter_range; + + if (c->args) { + for (i = 0; i < c->args->num_args; i++) { + if (0 == strcmp(c->args->args[i].key, + "grpc.testing.fixed_reconnect_backoff")) { + GPR_ASSERT(c->args->args[i].type == GRPC_ARG_INTEGER); + c->next_attempt = gpr_time_add( + gpr_now(GPR_CLOCK_MONOTONIC), + gpr_time_from_millis(c->args->args[i].value.integer, GPR_TIMESPAN)); + return; + } + } + } + backoff_delta_millis = (gpr_int32)(gpr_time_to_millis(c->backoff_delta) * GRPC_SUBCHANNEL_RECONNECT_BACKOFF_MULTIPLIER); diff --git a/src/core/client_config/subchannel.h b/src/core/client_config/subchannel.h index 1fefa1888a..381b7689b8 100644 --- a/src/core/client_config/subchannel.h +++ b/src/core/client_config/subchannel.h @@ -77,10 +77,10 @@ void grpc_subchannel_call_unref(grpc_exec_ctx *exec_ctx, /** construct a subchannel call (possibly asynchronously). * - * If the returned status is 1, the call will return immediately and \a target - * will point to a connected \a subchannel_call instance. Note that \a notify + * If the returned status is 1, the call will return immediately and \a target + * will point to a connected \a subchannel_call instance. Note that \a notify * will \em not be invoked in this case. - * Otherwise, if the returned status is 0, the subchannel call will be created + * Otherwise, if the returned status is 0, the subchannel call will be created * asynchronously, invoking the \a notify callback upon completion. */ int grpc_subchannel_create_call(grpc_exec_ctx *exec_ctx, grpc_subchannel *subchannel, diff --git a/src/core/iomgr/pollset_windows.c b/src/core/iomgr/pollset_windows.c index c3f310ee27..deb661548d 100644 --- a/src/core/iomgr/pollset_windows.c +++ b/src/core/iomgr/pollset_windows.c @@ -126,7 +126,8 @@ void grpc_pollset_destroy(grpc_pollset *pollset) {} void grpc_pollset_reset(grpc_pollset *pollset) { GPR_ASSERT(pollset->shutting_down); - GPR_ASSERT(!has_workers(&pollset->root_worker, GRPC_POLLSET_WORKER_LINK_POLLSET)); + GPR_ASSERT( + !has_workers(&pollset->root_worker, GRPC_POLLSET_WORKER_LINK_POLLSET)); pollset->shutting_down = 0; pollset->is_iocp_worker = 0; pollset->kicked_without_pollers = 0; diff --git a/src/core/iomgr/tcp_server.h b/src/core/iomgr/tcp_server.h index 882635f638..3df36174e7 100644 --- a/src/core/iomgr/tcp_server.h +++ b/src/core/iomgr/tcp_server.h @@ -39,6 +39,9 @@ /* Forward decl of grpc_tcp_server */ typedef struct grpc_tcp_server grpc_tcp_server; +/* Forward decl of grpc_tcp_listener */ +typedef struct grpc_tcp_listener grpc_tcp_listener; + /* Called for newly connected TCP connections. */ typedef void (*grpc_tcp_server_cb)(grpc_exec_ctx *exec_ctx, void *arg, grpc_endpoint *ep); @@ -51,19 +54,18 @@ void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *server, grpc_pollset **pollsets, size_t pollset_count, grpc_tcp_server_cb on_accept_cb, void *cb_arg); -/* Add a port to the server, returning port number on success, or negative - on failure. +/* Add a port to the server, returning the newly created listener on success, + or a null pointer on failure. The :: and 0.0.0.0 wildcard addresses are treated identically, accepting both IPv4 and IPv6 connections, but :: is the preferred style. This usually creates one socket, but possibly two on systems which support IPv6, - but not dualstack sockets. - - For raw access to the underlying sockets, see grpc_tcp_server_get_fd(). */ + but not dualstack sockets. */ /* TODO(ctiller): deprecate this, and make grpc_tcp_server_add_ports to handle all of the multiple socket port matching logic in one place */ -int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr, - size_t addr_len); +grpc_tcp_listener *grpc_tcp_server_add_port(grpc_tcp_server *s, + const void *addr, + size_t addr_len); /* Returns the file descriptor of the Nth listening socket on this server, or -1 if the index is out of bounds. @@ -75,4 +77,8 @@ int grpc_tcp_server_get_fd(grpc_tcp_server *s, unsigned index); void grpc_tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *server, grpc_closure *closure); +int grpc_tcp_listener_get_port(grpc_tcp_listener *listener); +void grpc_tcp_listener_ref(grpc_tcp_listener *listener); +void grpc_tcp_listener_unref(grpc_tcp_listener *listener); + #endif /* GRPC_INTERNAL_CORE_IOMGR_TCP_SERVER_H */ diff --git a/src/core/iomgr/tcp_server_posix.c b/src/core/iomgr/tcp_server_posix.c index 99c76dcbe9..1439dfcd6e 100644 --- a/src/core/iomgr/tcp_server_posix.c +++ b/src/core/iomgr/tcp_server_posix.c @@ -67,14 +67,13 @@ #include <grpc/support/sync.h> #include <grpc/support/time.h> -#define INIT_PORT_CAP 2 #define MIN_SAFE_ACCEPT_QUEUE_SIZE 100 static gpr_once s_init_max_accept_queue_size; static int s_max_accept_queue_size; /* one listening port */ -typedef struct { +struct grpc_tcp_listener { int fd; grpc_fd *emfd; grpc_tcp_server *server; @@ -84,9 +83,18 @@ typedef struct { struct sockaddr_un un; } addr; size_t addr_len; + int port; grpc_closure read_closure; grpc_closure destroyed_closure; -} server_port; + gpr_refcount refs; + struct grpc_tcp_listener *next; + /* When we add a listener, more than one can be created, mainly because of + IPv6. A sibling will still be in the normal list, but will be flagged + as such. Any action, such as ref or unref, will affect all of the + siblings in the list. */ + struct grpc_tcp_listener *sibling; + int is_sibling; +}; static void unlink_if_unix_domain_socket(const struct sockaddr_un *un) { struct stat st; @@ -112,10 +120,9 @@ struct grpc_tcp_server { /* is this server shutting down? (boolean) */ int shutdown; - /* all listening ports */ - server_port *ports; - size_t nports; - size_t port_capacity; + /* linked list of server ports */ + grpc_tcp_listener *head; + unsigned nports; /* shutdown callback */ grpc_closure *shutdown_complete; @@ -134,9 +141,8 @@ grpc_tcp_server *grpc_tcp_server_create(void) { s->shutdown = 0; s->on_accept_cb = NULL; s->on_accept_cb_arg = NULL; - s->ports = gpr_malloc(sizeof(server_port) * INIT_PORT_CAP); + s->head = NULL; s->nports = 0; - s->port_capacity = INIT_PORT_CAP; return s; } @@ -145,7 +151,12 @@ static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { gpr_mu_destroy(&s->mu); - gpr_free(s->ports); + while (s->head) { + grpc_tcp_listener *sp = s->head; + s->head = sp->next; + grpc_tcp_listener_unref(sp); + } + gpr_free(s); } @@ -166,8 +177,6 @@ static void destroyed_port(grpc_exec_ctx *exec_ctx, void *server, int success) { events will be received on them - at this point it's safe to destroy things */ static void deactivated_all_ports(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { - size_t i; - /* delete ALL the things */ gpr_mu_lock(&s->mu); @@ -176,9 +185,9 @@ static void deactivated_all_ports(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { return; } - if (s->nports) { - for (i = 0; i < s->nports; i++) { - server_port *sp = &s->ports[i]; + if (s->head) { + grpc_tcp_listener *sp; + for (sp = s->head; sp; sp = sp->next) { if (sp->addr.sockaddr.sa_family == AF_UNIX) { unlink_if_unix_domain_socket(&sp->addr.un); } @@ -196,7 +205,6 @@ static void deactivated_all_ports(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { void grpc_tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s, grpc_closure *closure) { - size_t i; gpr_mu_lock(&s->mu); GPR_ASSERT(!s->shutdown); @@ -206,8 +214,9 @@ void grpc_tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s, /* shutdown all fd's */ if (s->active_ports) { - for (i = 0; i < s->nports; i++) { - grpc_fd_shutdown(exec_ctx, s->ports[i].emfd); + grpc_tcp_listener *sp; + for (sp = s->head; sp; sp = sp->next) { + grpc_fd_shutdown(exec_ctx, sp->emfd); } gpr_mu_unlock(&s->mu); } else { @@ -298,7 +307,7 @@ error: /* event manager callback when reads are ready */ static void on_read(grpc_exec_ctx *exec_ctx, void *arg, int success) { - server_port *sp = arg; + grpc_tcp_listener *sp = arg; grpc_fd *fdobj; size_t i; @@ -364,9 +373,10 @@ error: } } -static int add_socket_to_server(grpc_tcp_server *s, int fd, - const struct sockaddr *addr, size_t addr_len) { - server_port *sp; +static grpc_tcp_listener *add_socket_to_server(grpc_tcp_server *s, int fd, + const struct sockaddr *addr, + size_t addr_len) { + grpc_tcp_listener *sp = NULL; int port; char *addr_str; char *name; @@ -376,32 +386,35 @@ static int add_socket_to_server(grpc_tcp_server *s, int fd, grpc_sockaddr_to_string(&addr_str, (struct sockaddr *)&addr, 1); gpr_asprintf(&name, "tcp-server-listener:%s", addr_str); gpr_mu_lock(&s->mu); + s->nports++; GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server"); - /* append it to the list under a lock */ - if (s->nports == s->port_capacity) { - s->port_capacity *= 2; - s->ports = gpr_realloc(s->ports, sizeof(server_port) * s->port_capacity); - } - sp = &s->ports[s->nports++]; + sp = gpr_malloc(sizeof(grpc_tcp_listener)); + sp->next = s->head; + s->head = sp; sp->server = s; sp->fd = fd; sp->emfd = grpc_fd_create(fd, name); memcpy(sp->addr.untyped, addr, addr_len); sp->addr_len = addr_len; + sp->port = port; + sp->is_sibling = 0; + sp->sibling = NULL; + gpr_ref_init(&sp->refs, 1); GPR_ASSERT(sp->emfd); gpr_mu_unlock(&s->mu); gpr_free(addr_str); gpr_free(name); } - return port; + return sp; } -int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr, - size_t addr_len) { - int allocated_port1 = -1; - int allocated_port2 = -1; - unsigned i; +grpc_tcp_listener *grpc_tcp_server_add_port(grpc_tcp_server *s, + const void *addr, + size_t addr_len) { + int allocated_port = -1; + grpc_tcp_listener *sp; + grpc_tcp_listener *sp2 = NULL; int fd; grpc_dualstack_mode dsmode; struct sockaddr_in6 addr6_v4mapped; @@ -420,9 +433,9 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr, /* Check if this is a wildcard port, and if so, try to keep the port the same as some previously created listener. */ if (grpc_sockaddr_get_port(addr) == 0) { - for (i = 0; i < s->nports; i++) { + for (sp = s->head; sp; sp = sp->next) { sockname_len = sizeof(sockname_temp); - if (0 == getsockname(s->ports[i].fd, (struct sockaddr *)&sockname_temp, + if (0 == getsockname(sp->fd, (struct sockaddr *)&sockname_temp, &sockname_len)) { port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp); if (port > 0) { @@ -436,6 +449,8 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr, } } + sp = NULL; + if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) { addr = (const struct sockaddr *)&addr6_v4mapped; addr_len = sizeof(addr6_v4mapped); @@ -449,14 +464,16 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr, addr = (struct sockaddr *)&wild6; addr_len = sizeof(wild6); fd = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode); - allocated_port1 = add_socket_to_server(s, fd, addr, addr_len); + sp = add_socket_to_server(s, fd, addr, addr_len); + allocated_port = sp->port; if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) { goto done; } /* If we didn't get a dualstack socket, also listen on 0.0.0.0. */ - if (port == 0 && allocated_port1 > 0) { - grpc_sockaddr_set_port((struct sockaddr *)&wild4, allocated_port1); + if (port == 0 && allocated_port > 0) { + grpc_sockaddr_set_port((struct sockaddr *)&wild4, allocated_port); + sp2 = sp; } addr = (struct sockaddr *)&wild4; addr_len = sizeof(wild4); @@ -471,22 +488,31 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr, addr = (struct sockaddr *)&addr4_copy; addr_len = sizeof(addr4_copy); } - allocated_port2 = add_socket_to_server(s, fd, addr, addr_len); + sp = add_socket_to_server(s, fd, addr, addr_len); + sp->sibling = sp2; + if (sp2) sp2->is_sibling = 1; done: gpr_free(allocated_addr); - return allocated_port1 >= 0 ? allocated_port1 : allocated_port2; + return sp; } int grpc_tcp_server_get_fd(grpc_tcp_server *s, unsigned port_index) { - return (port_index < s->nports) ? s->ports[port_index].fd : -1; + grpc_tcp_listener *sp; + for (sp = s->head; sp && port_index != 0; sp = sp->next, port_index--); + if (port_index == 0 && sp) { + return sp->fd; + } else { + return -1; + } } void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s, grpc_pollset **pollsets, size_t pollset_count, grpc_tcp_server_cb on_accept_cb, void *on_accept_cb_arg) { - size_t i, j; + size_t i; + grpc_tcp_listener *sp; GPR_ASSERT(on_accept_cb); gpr_mu_lock(&s->mu); GPR_ASSERT(!s->on_accept_cb); @@ -495,17 +521,41 @@ void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s, s->on_accept_cb_arg = on_accept_cb_arg; s->pollsets = pollsets; s->pollset_count = pollset_count; - for (i = 0; i < s->nports; i++) { - for (j = 0; j < pollset_count; j++) { - grpc_pollset_add_fd(exec_ctx, pollsets[j], s->ports[i].emfd); + for (sp = s->head; sp; sp = sp->next) { + for (i = 0; i < pollset_count; i++) { + grpc_pollset_add_fd(exec_ctx, pollsets[i], sp->emfd); } - s->ports[i].read_closure.cb = on_read; - s->ports[i].read_closure.cb_arg = &s->ports[i]; - grpc_fd_notify_on_read(exec_ctx, s->ports[i].emfd, - &s->ports[i].read_closure); + sp->read_closure.cb = on_read; + sp->read_closure.cb_arg = sp; + grpc_fd_notify_on_read(exec_ctx, sp->emfd, + &sp->read_closure); s->active_ports++; } gpr_mu_unlock(&s->mu); } +int grpc_tcp_listener_get_port(grpc_tcp_listener *listener) { + grpc_tcp_listener *sp = listener; + return sp->port; +} + +void grpc_tcp_listener_ref(grpc_tcp_listener *listener) { + grpc_tcp_listener *sp = listener; + gpr_ref(&sp->refs); +} + +void grpc_tcp_listener_unref(grpc_tcp_listener *listener) { + grpc_tcp_listener *sp = listener; + if (sp->is_sibling) return; + if (gpr_unref(&sp->refs)) { + grpc_tcp_listener *sibling = sp->sibling; + while (sibling) { + sp = sibling; + sibling = sp->sibling; + gpr_free(sp); + } + gpr_free(listener); + } +} + #endif diff --git a/src/core/iomgr/tcp_server_windows.c b/src/core/iomgr/tcp_server_windows.c index 3fea8b5b35..e4a1d7f498 100644 --- a/src/core/iomgr/tcp_server_windows.c +++ b/src/core/iomgr/tcp_server_windows.c @@ -35,7 +35,8 @@ #ifdef GPR_WINSOCK_SOCKET -#define _GNU_SOURCE +#include <io.h> + #include "src/core/iomgr/sockaddr_utils.h" #include <grpc/support/alloc.h> @@ -51,25 +52,29 @@ #include "src/core/iomgr/tcp_server.h" #include "src/core/iomgr/tcp_windows.h" -#define INIT_PORT_CAP 2 #define MIN_SAFE_ACCEPT_QUEUE_SIZE 100 /* one listening port */ -typedef struct server_port { +struct grpc_tcp_listener { /* This seemingly magic number comes from AcceptEx's documentation. each address buffer needs to have at least 16 more bytes at their end. */ gpr_uint8 addresses[(sizeof(struct sockaddr_in6) + 16) * 2]; /* This will hold the socket for the next accept. */ SOCKET new_socket; - /* The listener winsocked. */ + /* The listener winsocket. */ grpc_winsocket *socket; + /* The actual TCP port number. */ + int port; grpc_tcp_server *server; /* The cached AcceptEx for that port. */ LPFN_ACCEPTEX AcceptEx; int shutting_down; /* closure for socket notification of accept being ready */ grpc_closure on_accept; -} server_port; + gpr_refcount refs; + /* linked list */ + struct grpc_tcp_listener *next; +}; /* the overall server */ struct grpc_tcp_server { @@ -82,10 +87,8 @@ struct grpc_tcp_server { /* active port count: how many ports are actually still listening */ int active_ports; - /* all listening ports */ - server_port *ports; - size_t nports; - size_t port_capacity; + /* linked list of server ports */ + grpc_tcp_listener *head; /* shutdown callback */ grpc_closure *shutdown_complete; @@ -99,9 +102,7 @@ grpc_tcp_server *grpc_tcp_server_create(void) { s->active_ports = 0; s->on_accept_cb = NULL; s->on_accept_cb_arg = NULL; - s->ports = gpr_malloc(sizeof(server_port) * INIT_PORT_CAP); - s->nports = 0; - s->port_capacity = INIT_PORT_CAP; + s->head = NULL; s->shutdown_complete = NULL; return s; } @@ -109,26 +110,26 @@ grpc_tcp_server *grpc_tcp_server_create(void) { static void dont_care_about_shutdown_completion(void *arg) {} static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { - size_t i; - grpc_exec_ctx_enqueue(exec_ctx, s->shutdown_complete, 1); /* Now that the accepts have been aborted, we can destroy the sockets. The IOCP won't get notified on these, so we can flag them as already closed by the system. */ - for (i = 0; i < s->nports; i++) { - server_port *sp = &s->ports[i]; + while (s->head) { + grpc_tcp_listener *sp = s->head; + s->head = sp->next; + sp->next = NULL; grpc_winsocket_destroy(sp->socket); + grpc_tcp_listener_unref(sp); } - gpr_free(s->ports); gpr_free(s); } /* Public function. Stops and destroys a grpc_tcp_server. */ void grpc_tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s, grpc_closure *shutdown_complete) { - size_t i; int immediately_done = 0; + grpc_tcp_listener *sp; gpr_mu_lock(&s->mu); s->shutdown_complete = shutdown_complete; @@ -138,8 +139,7 @@ void grpc_tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s, if (s->active_ports == 0) { immediately_done = 1; } - for (i = 0; i < s->nports; i++) { - server_port *sp = &s->ports[i]; + for (sp = s->head; sp; sp = sp->next) { sp->shutting_down = 1; grpc_winsocket_shutdown(sp->socket); } @@ -199,7 +199,7 @@ error: } static void decrement_active_ports_and_notify(grpc_exec_ctx *exec_ctx, - server_port *sp) { + grpc_tcp_listener *sp) { int notify = 0; sp->shutting_down = 0; gpr_mu_lock(&sp->server->mu); @@ -216,7 +216,7 @@ static void decrement_active_ports_and_notify(grpc_exec_ctx *exec_ctx, /* In order to do an async accept, we need to create a socket first which will be the one assigned to the new incoming connection. */ -static void start_accept(grpc_exec_ctx *exec_ctx, server_port *port) { +static void start_accept(grpc_exec_ctx *exec_ctx, grpc_tcp_listener *port) { SOCKET sock = INVALID_SOCKET; char *message; char *utf8_message; @@ -276,7 +276,7 @@ failure: /* Event manager callback when reads are ready. */ static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, int from_iocp) { - server_port *sp = arg; + grpc_tcp_listener *sp = arg; SOCKET sock = sp->new_socket; grpc_winsocket_callback_info *info = &sp->socket->read_info; grpc_endpoint *ep = NULL; @@ -351,16 +351,17 @@ static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, int from_iocp) { start_accept(exec_ctx, sp); } -static int add_socket_to_server(grpc_tcp_server *s, SOCKET sock, - const struct sockaddr *addr, size_t addr_len) { - server_port *sp; +static grpc_tcp_listener *add_socket_to_server(grpc_tcp_server *s, SOCKET sock, + const struct sockaddr *addr, + size_t addr_len) { + grpc_tcp_listener *sp = NULL; int port; int status; GUID guid = WSAID_ACCEPTEX; DWORD ioctl_num_bytes; LPFN_ACCEPTEX AcceptEx; - if (sock == INVALID_SOCKET) return -1; + if (sock == INVALID_SOCKET) return NULL; /* We need to grab the AcceptEx pointer for that port, as it may be interface-dependent. We'll cache it to avoid doing that again. */ @@ -373,37 +374,35 @@ static int add_socket_to_server(grpc_tcp_server *s, SOCKET sock, gpr_log(GPR_ERROR, "on_connect error: %s", utf8_message); gpr_free(utf8_message); closesocket(sock); - return -1; + return NULL; } port = prepare_socket(sock, addr, addr_len); if (port >= 0) { gpr_mu_lock(&s->mu); GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server"); - /* append it to the list under a lock */ - if (s->nports == s->port_capacity) { - /* too many ports, and we need to store their address in a closure */ - /* TODO(ctiller): make server_port a linked list */ - abort(); - } - sp = &s->ports[s->nports++]; + sp = gpr_malloc(sizeof(grpc_tcp_listener)); + sp->next = s->head; + s->head = sp; sp->server = s; sp->socket = grpc_winsocket_create(sock, "listener"); sp->shutting_down = 0; sp->AcceptEx = AcceptEx; sp->new_socket = INVALID_SOCKET; + sp->port = port; + gpr_ref_init(&sp->refs, 1); grpc_closure_init(&sp->on_accept, on_accept, sp); GPR_ASSERT(sp->socket); gpr_mu_unlock(&s->mu); } - return port; + return sp; } -int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr, - size_t addr_len) { - int allocated_port = -1; - unsigned i; +grpc_tcp_listener *grpc_tcp_server_add_port(grpc_tcp_server *s, + const void *addr, + size_t addr_len) { + grpc_tcp_listener *sp; SOCKET sock; struct sockaddr_in6 addr6_v4mapped; struct sockaddr_in6 wildcard; @@ -415,9 +414,9 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr, /* Check if this is a wildcard port, and if so, try to keep the port the same as some previously created listener. */ if (grpc_sockaddr_get_port(addr) == 0) { - for (i = 0; i < s->nports; i++) { + for (sp = s->head; sp; sp = sp->next) { sockname_len = sizeof(sockname_temp); - if (0 == getsockname(s->ports[i].socket->socket, + if (0 == getsockname(sp->socket->socket, (struct sockaddr *)&sockname_temp, &sockname_len)) { port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp); if (port > 0) { @@ -452,33 +451,55 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr, gpr_free(utf8_message); } - allocated_port = add_socket_to_server(s, sock, addr, addr_len); + sp = add_socket_to_server(s, sock, addr, addr_len); gpr_free(allocated_addr); - return allocated_port; + return sp; } -SOCKET -grpc_tcp_server_get_socket(grpc_tcp_server *s, unsigned index) { - return (index < s->nports) ? s->ports[index].socket->socket : INVALID_SOCKET; +int grpc_tcp_server_get_fd(grpc_tcp_server *s, unsigned port_index) { + grpc_tcp_listener *sp; + for (sp = s->head; sp && port_index != 0; sp = sp->next, port_index--); + if (port_index == 0 && sp) { + return _open_osfhandle(sp->socket->socket, 0); + } else { + return -1; + } } void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s, grpc_pollset **pollset, size_t pollset_count, grpc_tcp_server_cb on_accept_cb, void *on_accept_cb_arg) { - size_t i; + grpc_tcp_listener *sp; GPR_ASSERT(on_accept_cb); gpr_mu_lock(&s->mu); GPR_ASSERT(!s->on_accept_cb); GPR_ASSERT(s->active_ports == 0); s->on_accept_cb = on_accept_cb; s->on_accept_cb_arg = on_accept_cb_arg; - for (i = 0; i < s->nports; i++) { - start_accept(exec_ctx, s->ports + i); + for (sp = s->head; sp; sp = sp->next) { + start_accept(exec_ctx, sp); s->active_ports++; } gpr_mu_unlock(&s->mu); } +int grpc_tcp_listener_get_port(grpc_tcp_listener *listener) { + grpc_tcp_listener *sp = listener; + return sp->port; +} + +void grpc_tcp_listener_ref(grpc_tcp_listener *listener) { + grpc_tcp_listener *sp = listener; + gpr_ref(&sp->refs); +} + +void grpc_tcp_listener_unref(grpc_tcp_listener *listener) { + grpc_tcp_listener *sp = listener; + if (gpr_unref(&sp->refs)) { + gpr_free(listener); + } +} + #endif /* GPR_WINSOCK_SOCKET */ diff --git a/src/core/security/client_auth_filter.c b/src/core/security/client_auth_filter.c index c780b65873..be2522a7a0 100644 --- a/src/core/security/client_auth_filter.c +++ b/src/core/security/client_auth_filter.c @@ -50,7 +50,7 @@ /* We can have a per-call credentials. */ typedef struct { - grpc_credentials *creds; + grpc_call_credentials *creds; grpc_mdstr *host; grpc_mdstr *method; /* pollset bound to this call; if we need to make external @@ -143,39 +143,35 @@ static void send_security_metadata(grpc_exec_ctx *exec_ctx, channel_data *chand = elem->channel_data; grpc_client_security_context *ctx = (grpc_client_security_context *)op->context[GRPC_CONTEXT_SECURITY].value; - grpc_credentials *channel_creds = + grpc_call_credentials *channel_call_creds = chand->security_connector->request_metadata_creds; - int channel_creds_has_md = - (channel_creds != NULL) && - grpc_credentials_has_request_metadata(channel_creds); - int call_creds_has_md = (ctx != NULL) && (ctx->creds != NULL) && - grpc_credentials_has_request_metadata(ctx->creds); + int call_creds_has_md = (ctx != NULL) && (ctx->creds != NULL); - if (!channel_creds_has_md && !call_creds_has_md) { + if (channel_call_creds == NULL && !call_creds_has_md) { /* Skip sending metadata altogether. */ grpc_call_next_op(exec_ctx, elem, op); return; } - if (channel_creds_has_md && call_creds_has_md) { - calld->creds = - grpc_composite_credentials_create(channel_creds, ctx->creds, NULL); + if (channel_call_creds != NULL && call_creds_has_md) { + calld->creds = grpc_composite_call_credentials_create(channel_call_creds, + ctx->creds, NULL); if (calld->creds == NULL) { bubble_up_error(exec_ctx, elem, GRPC_STATUS_INVALID_ARGUMENT, "Incompatible credentials set on channel and call."); return; } } else { - calld->creds = - grpc_credentials_ref(call_creds_has_md ? ctx->creds : channel_creds); + calld->creds = grpc_call_credentials_ref( + call_creds_has_md ? ctx->creds : channel_call_creds); } build_service_url(chand->security_connector->base.url_scheme, calld); calld->op = *op; /* Copy op (originates from the caller's stack). */ GPR_ASSERT(calld->pollset); - grpc_credentials_get_request_metadata(exec_ctx, calld->creds, calld->pollset, - calld->service_url, - on_credentials_metadata, elem); + grpc_call_credentials_get_request_metadata(exec_ctx, calld->creds, + calld->pollset, calld->service_url, + on_credentials_metadata, elem); } static void on_host_checked(grpc_exec_ctx *exec_ctx, void *user_data, @@ -282,7 +278,7 @@ static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) { call_data *calld = elem->call_data; - grpc_credentials_unref(calld->creds); + grpc_call_credentials_unref(calld->creds); if (calld->host != NULL) { GRPC_MDSTR_UNREF(calld->host); } diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c index 2a8ffae5d7..f7a2e73785 100644 --- a/src/core/security/credentials.c +++ b/src/core/security/credentials.c @@ -54,18 +54,18 @@ /* -- Common. -- */ struct grpc_credentials_metadata_request { - grpc_credentials *creds; + grpc_call_credentials *creds; grpc_credentials_metadata_cb cb; void *user_data; }; static grpc_credentials_metadata_request * -grpc_credentials_metadata_request_create(grpc_credentials *creds, +grpc_credentials_metadata_request_create(grpc_call_credentials *creds, grpc_credentials_metadata_cb cb, void *user_data) { grpc_credentials_metadata_request *r = gpr_malloc(sizeof(grpc_credentials_metadata_request)); - r->creds = grpc_credentials_ref(creds); + r->creds = grpc_call_credentials_ref(creds); r->cb = cb; r->user_data = user_data; return r; @@ -73,44 +73,56 @@ grpc_credentials_metadata_request_create(grpc_credentials *creds, static void grpc_credentials_metadata_request_destroy( grpc_credentials_metadata_request *r) { - grpc_credentials_unref(r->creds); + grpc_call_credentials_unref(r->creds); gpr_free(r); } -grpc_credentials *grpc_credentials_ref(grpc_credentials *creds) { +grpc_channel_credentials *grpc_channel_credentials_ref( + grpc_channel_credentials *creds) { if (creds == NULL) return NULL; gpr_ref(&creds->refcount); return creds; } -void grpc_credentials_unref(grpc_credentials *creds) { +void grpc_channel_credentials_unref(grpc_channel_credentials *creds) { if (creds == NULL) return; if (gpr_unref(&creds->refcount)) { - creds->vtable->destruct(creds); + if (creds->vtable->destruct != NULL) creds->vtable->destruct(creds); gpr_free(creds); } } -void grpc_credentials_release(grpc_credentials *creds) { - GRPC_API_TRACE("grpc_credentials_release(creds=%p)", 1, (creds)); - grpc_credentials_unref(creds); +void grpc_channel_credentials_release(grpc_channel_credentials *creds) { + GRPC_API_TRACE("grpc_channel_credentials_release(creds=%p)", 1, (creds)); + grpc_channel_credentials_unref(creds); } -int grpc_credentials_has_request_metadata(grpc_credentials *creds) { - if (creds == NULL) return 0; - return creds->vtable->has_request_metadata(creds); +grpc_call_credentials *grpc_call_credentials_ref(grpc_call_credentials *creds) { + if (creds == NULL) return NULL; + gpr_ref(&creds->refcount); + return creds; +} + +void grpc_call_credentials_unref(grpc_call_credentials *creds) { + if (creds == NULL) return; + if (gpr_unref(&creds->refcount)) { + if (creds->vtable->destruct != NULL) creds->vtable->destruct(creds); + gpr_free(creds); + } } -int grpc_credentials_has_request_metadata_only(grpc_credentials *creds) { - if (creds == NULL) return 0; - return creds->vtable->has_request_metadata_only(creds); +void grpc_call_credentials_release(grpc_call_credentials *creds) { + GRPC_API_TRACE("grpc_call_credentials_release(creds=%p)", 1, (creds)); + grpc_call_credentials_unref(creds); } -void grpc_credentials_get_request_metadata( - grpc_exec_ctx *exec_ctx, grpc_credentials *creds, grpc_pollset *pollset, - const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) { - if (creds == NULL || !grpc_credentials_has_request_metadata(creds) || - creds->vtable->get_request_metadata == NULL) { +void grpc_call_credentials_get_request_metadata(grpc_exec_ctx *exec_ctx, + grpc_call_credentials *creds, + grpc_pollset *pollset, + const char *service_url, + grpc_credentials_metadata_cb cb, + void *user_data) { + if (creds == NULL || creds->vtable->get_request_metadata == NULL) { if (cb != NULL) { cb(exec_ctx, user_data, NULL, 0, GRPC_CREDENTIALS_OK); } @@ -120,19 +132,17 @@ void grpc_credentials_get_request_metadata( user_data); } -grpc_security_status grpc_credentials_create_security_connector( - grpc_credentials *creds, const char *target, const grpc_channel_args *args, - grpc_credentials *request_metadata_creds, - grpc_channel_security_connector **sc, grpc_channel_args **new_args) { +grpc_security_status grpc_channel_credentials_create_security_connector( + grpc_channel_credentials *channel_creds, const char *target, + const grpc_channel_args *args, grpc_channel_security_connector **sc, + grpc_channel_args **new_args) { *new_args = NULL; - if (creds == NULL || creds->vtable->create_security_connector == NULL || - grpc_credentials_has_request_metadata_only(creds)) { - gpr_log(GPR_ERROR, - "Invalid credentials for creating a security connector."); + if (channel_creds == NULL) { return GRPC_SECURITY_ERROR; } - return creds->vtable->create_security_connector( - creds, target, args, request_metadata_creds, sc, new_args); + GPR_ASSERT(channel_creds->vtable->create_security_connector != NULL); + return channel_creds->vtable->create_security_connector( + channel_creds, NULL, target, args, sc, new_args); } grpc_server_credentials *grpc_server_credentials_ref( @@ -145,7 +155,7 @@ grpc_server_credentials *grpc_server_credentials_ref( void grpc_server_credentials_unref(grpc_server_credentials *creds) { if (creds == NULL) return; if (gpr_unref(&creds->refcount)) { - creds->vtable->destruct(creds); + if (creds->vtable->destruct != NULL) creds->vtable->destruct(creds); if (creds->processor.destroy != NULL && creds->processor.state != NULL) { creds->processor.destroy(creds->processor.state); } @@ -224,7 +234,7 @@ grpc_server_credentials *grpc_find_server_credentials_in_args( /* -- Ssl credentials. -- */ -static void ssl_destruct(grpc_credentials *creds) { +static void ssl_destruct(grpc_channel_credentials *creds) { grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds; if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs); if (c->config.pem_private_key != NULL) gpr_free(c->config.pem_private_key); @@ -253,15 +263,9 @@ static void ssl_server_destruct(grpc_server_credentials *creds) { if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs); } -static int ssl_has_request_metadata(const grpc_credentials *creds) { return 0; } - -static int ssl_has_request_metadata_only(const grpc_credentials *creds) { - return 0; -} - static grpc_security_status ssl_create_security_connector( - grpc_credentials *creds, const char *target, const grpc_channel_args *args, - grpc_credentials *request_metadata_creds, + grpc_channel_credentials *creds, grpc_call_credentials *call_creds, + const char *target, const grpc_channel_args *args, grpc_channel_security_connector **sc, grpc_channel_args **new_args) { grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds; grpc_security_status status = GRPC_SECURITY_OK; @@ -278,7 +282,7 @@ static grpc_security_status ssl_create_security_connector( } } status = grpc_ssl_channel_security_connector_create( - request_metadata_creds, &c->config, target, overridden_target_name, sc); + call_creds, &c->config, target, overridden_target_name, sc); if (status != GRPC_SECURITY_OK) { return status; } @@ -295,9 +299,8 @@ static grpc_security_status ssl_server_create_security_connector( return grpc_ssl_server_security_connector_create(&c->config, sc); } -static grpc_credentials_vtable ssl_vtable = { - ssl_destruct, ssl_has_request_metadata, ssl_has_request_metadata_only, NULL, - ssl_create_security_connector}; +static grpc_channel_credentials_vtable ssl_vtable = { + ssl_destruct, ssl_create_security_connector}; static grpc_server_credentials_vtable ssl_server_vtable = { ssl_server_destruct, ssl_server_create_security_connector}; @@ -362,7 +365,7 @@ static void ssl_build_server_config( } } -grpc_credentials *grpc_ssl_credentials_create( +grpc_channel_credentials *grpc_ssl_credentials_create( const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair, void *reserved) { grpc_ssl_credentials *c = gpr_malloc(sizeof(grpc_ssl_credentials)); @@ -373,7 +376,7 @@ grpc_credentials *grpc_ssl_credentials_create( 3, (pem_root_certs, pem_key_cert_pair, reserved)); GPR_ASSERT(reserved == NULL); memset(c, 0, sizeof(grpc_ssl_credentials)); - c->base.type = GRPC_CREDENTIALS_TYPE_SSL; + c->base.type = GRPC_CHANNEL_CREDENTIALS_TYPE_SSL; c->base.vtable = &ssl_vtable; gpr_ref_init(&c->base.refcount, 1); ssl_build_config(pem_root_certs, pem_key_cert_pair, &c->config); @@ -393,7 +396,7 @@ grpc_server_credentials *grpc_ssl_server_credentials_create( force_client_auth, reserved)); GPR_ASSERT(reserved == NULL); memset(c, 0, sizeof(grpc_ssl_server_credentials)); - c->base.type = GRPC_CREDENTIALS_TYPE_SSL; + c->base.type = GRPC_CHANNEL_CREDENTIALS_TYPE_SSL; gpr_ref_init(&c->base.refcount, 1); c->base.vtable = &ssl_server_vtable; ssl_build_server_config(pem_root_certs, pem_key_cert_pairs, @@ -415,7 +418,7 @@ static void jwt_reset_cache(grpc_service_account_jwt_access_credentials *c) { c->cached.jwt_expiration = gpr_inf_past(GPR_CLOCK_REALTIME); } -static void jwt_destruct(grpc_credentials *creds) { +static void jwt_destruct(grpc_call_credentials *creds) { grpc_service_account_jwt_access_credentials *c = (grpc_service_account_jwt_access_credentials *)creds; grpc_auth_json_key_destruct(&c->key); @@ -423,15 +426,12 @@ static void jwt_destruct(grpc_credentials *creds) { gpr_mu_destroy(&c->cache_mu); } -static int jwt_has_request_metadata(const grpc_credentials *creds) { return 1; } - -static int jwt_has_request_metadata_only(const grpc_credentials *creds) { - return 1; -} - -static void jwt_get_request_metadata( - grpc_exec_ctx *exec_ctx, grpc_credentials *creds, grpc_pollset *pollset, - const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) { +static void jwt_get_request_metadata(grpc_exec_ctx *exec_ctx, + grpc_call_credentials *creds, + grpc_pollset *pollset, + const char *service_url, + grpc_credentials_metadata_cb cb, + void *user_data) { grpc_service_account_jwt_access_credentials *c = (grpc_service_account_jwt_access_credentials *)creds; gpr_timespec refresh_threshold = gpr_time_from_seconds( @@ -483,11 +483,10 @@ static void jwt_get_request_metadata( } } -static grpc_credentials_vtable jwt_vtable = { - jwt_destruct, jwt_has_request_metadata, jwt_has_request_metadata_only, - jwt_get_request_metadata, NULL}; +static grpc_call_credentials_vtable jwt_vtable = {jwt_destruct, + jwt_get_request_metadata}; -grpc_credentials * +grpc_call_credentials * grpc_service_account_jwt_access_credentials_create_from_auth_json_key( grpc_auth_json_key key, gpr_timespec token_lifetime) { grpc_service_account_jwt_access_credentials *c; @@ -497,7 +496,7 @@ grpc_service_account_jwt_access_credentials_create_from_auth_json_key( } c = gpr_malloc(sizeof(grpc_service_account_jwt_access_credentials)); memset(c, 0, sizeof(grpc_service_account_jwt_access_credentials)); - c->base.type = GRPC_CREDENTIALS_TYPE_JWT; + c->base.type = GRPC_CALL_CREDENTIALS_TYPE_JWT; gpr_ref_init(&c->base.refcount, 1); c->base.vtable = &jwt_vtable; c->key = key; @@ -507,7 +506,7 @@ grpc_service_account_jwt_access_credentials_create_from_auth_json_key( return &c->base; } -grpc_credentials *grpc_service_account_jwt_access_credentials_create( +grpc_call_credentials *grpc_service_account_jwt_access_credentials_create( const char *json_key, gpr_timespec token_lifetime, void *reserved) { GRPC_API_TRACE( "grpc_service_account_jwt_access_credentials_create(" @@ -524,7 +523,7 @@ grpc_credentials *grpc_service_account_jwt_access_credentials_create( /* -- Oauth2TokenFetcher credentials -- */ -static void oauth2_token_fetcher_destruct(grpc_credentials *creds) { +static void oauth2_token_fetcher_destruct(grpc_call_credentials *creds) { grpc_oauth2_token_fetcher_credentials *c = (grpc_oauth2_token_fetcher_credentials *)creds; grpc_credentials_md_store_unref(c->access_token_md); @@ -532,16 +531,6 @@ static void oauth2_token_fetcher_destruct(grpc_credentials *creds) { grpc_httpcli_context_destroy(&c->httpcli_context); } -static int oauth2_token_fetcher_has_request_metadata( - const grpc_credentials *creds) { - return 1; -} - -static int oauth2_token_fetcher_has_request_metadata_only( - const grpc_credentials *creds) { - return 1; -} - grpc_credentials_status grpc_oauth2_token_fetcher_credentials_parse_server_response( const grpc_httpcli_response *response, grpc_credentials_md_store **token_md, @@ -659,8 +648,9 @@ static void on_oauth2_token_fetcher_http_response( } static void oauth2_token_fetcher_get_request_metadata( - grpc_exec_ctx *exec_ctx, grpc_credentials *creds, grpc_pollset *pollset, - const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) { + grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, + grpc_pollset *pollset, const char *service_url, + grpc_credentials_metadata_cb cb, void *user_data) { grpc_oauth2_token_fetcher_credentials *c = (grpc_oauth2_token_fetcher_credentials *)creds; gpr_timespec refresh_threshold = gpr_time_from_seconds( @@ -693,7 +683,7 @@ static void oauth2_token_fetcher_get_request_metadata( static void init_oauth2_token_fetcher(grpc_oauth2_token_fetcher_credentials *c, grpc_fetch_oauth2_func fetch_func) { memset(c, 0, sizeof(grpc_oauth2_token_fetcher_credentials)); - c->base.type = GRPC_CREDENTIALS_TYPE_OAUTH2; + c->base.type = GRPC_CALL_CREDENTIALS_TYPE_OAUTH2; gpr_ref_init(&c->base.refcount, 1); gpr_mu_init(&c->mu); c->token_expiration = gpr_inf_past(GPR_CLOCK_REALTIME); @@ -703,10 +693,8 @@ static void init_oauth2_token_fetcher(grpc_oauth2_token_fetcher_credentials *c, /* -- GoogleComputeEngine credentials. -- */ -static grpc_credentials_vtable compute_engine_vtable = { - oauth2_token_fetcher_destruct, oauth2_token_fetcher_has_request_metadata, - oauth2_token_fetcher_has_request_metadata_only, - oauth2_token_fetcher_get_request_metadata, NULL}; +static grpc_call_credentials_vtable compute_engine_vtable = { + oauth2_token_fetcher_destruct, oauth2_token_fetcher_get_request_metadata}; static void compute_engine_fetch_oauth2( grpc_exec_ctx *exec_ctx, grpc_credentials_metadata_request *metadata_req, @@ -723,7 +711,7 @@ static void compute_engine_fetch_oauth2( response_cb, metadata_req); } -grpc_credentials *grpc_google_compute_engine_credentials_create( +grpc_call_credentials *grpc_google_compute_engine_credentials_create( void *reserved) { grpc_oauth2_token_fetcher_credentials *c = gpr_malloc(sizeof(grpc_oauth2_token_fetcher_credentials)); @@ -737,17 +725,15 @@ grpc_credentials *grpc_google_compute_engine_credentials_create( /* -- GoogleRefreshToken credentials. -- */ -static void refresh_token_destruct(grpc_credentials *creds) { +static void refresh_token_destruct(grpc_call_credentials *creds) { grpc_google_refresh_token_credentials *c = (grpc_google_refresh_token_credentials *)creds; grpc_auth_refresh_token_destruct(&c->refresh_token); oauth2_token_fetcher_destruct(&c->base.base); } -static grpc_credentials_vtable refresh_token_vtable = { - refresh_token_destruct, oauth2_token_fetcher_has_request_metadata, - oauth2_token_fetcher_has_request_metadata_only, - oauth2_token_fetcher_get_request_metadata, NULL}; +static grpc_call_credentials_vtable refresh_token_vtable = { + refresh_token_destruct, oauth2_token_fetcher_get_request_metadata}; static void refresh_token_fetch_oauth2( grpc_exec_ctx *exec_ctx, grpc_credentials_metadata_request *metadata_req, @@ -773,7 +759,8 @@ static void refresh_token_fetch_oauth2( gpr_free(body); } -grpc_credentials *grpc_refresh_token_credentials_create_from_auth_refresh_token( +grpc_call_credentials * +grpc_refresh_token_credentials_create_from_auth_refresh_token( grpc_auth_refresh_token refresh_token) { grpc_google_refresh_token_credentials *c; if (!grpc_auth_refresh_token_is_valid(&refresh_token)) { @@ -788,7 +775,7 @@ grpc_credentials *grpc_refresh_token_credentials_create_from_auth_refresh_token( return &c->base.base; } -grpc_credentials *grpc_google_refresh_token_credentials_create( +grpc_call_credentials *grpc_google_refresh_token_credentials_create( const char *json_refresh_token, void *reserved) { GRPC_API_TRACE( "grpc_refresh_token_credentials_create(json_refresh_token=%s, " @@ -801,20 +788,11 @@ grpc_credentials *grpc_google_refresh_token_credentials_create( /* -- Metadata-only credentials. -- */ -static void md_only_test_destruct(grpc_credentials *creds) { +static void md_only_test_destruct(grpc_call_credentials *creds) { grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)creds; grpc_credentials_md_store_unref(c->md_store); } -static int md_only_test_has_request_metadata(const grpc_credentials *creds) { - return 1; -} - -static int md_only_test_has_request_metadata_only( - const grpc_credentials *creds) { - return 1; -} - static void on_simulated_token_fetch_done(void *user_data) { grpc_credentials_metadata_request *r = (grpc_credentials_metadata_request *)user_data; @@ -826,9 +804,12 @@ static void on_simulated_token_fetch_done(void *user_data) { grpc_exec_ctx_finish(&exec_ctx); } -static void md_only_test_get_request_metadata( - grpc_exec_ctx *exec_ctx, grpc_credentials *creds, grpc_pollset *pollset, - const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) { +static void md_only_test_get_request_metadata(grpc_exec_ctx *exec_ctx, + grpc_call_credentials *creds, + grpc_pollset *pollset, + const char *service_url, + grpc_credentials_metadata_cb cb, + void *user_data) { grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)creds; if (c->is_async) { @@ -841,18 +822,15 @@ static void md_only_test_get_request_metadata( } } -static grpc_credentials_vtable md_only_test_vtable = { - md_only_test_destruct, md_only_test_has_request_metadata, - md_only_test_has_request_metadata_only, md_only_test_get_request_metadata, - NULL}; +static grpc_call_credentials_vtable md_only_test_vtable = { + md_only_test_destruct, md_only_test_get_request_metadata}; -grpc_credentials *grpc_md_only_test_credentials_create(const char *md_key, - const char *md_value, - int is_async) { +grpc_call_credentials *grpc_md_only_test_credentials_create( + const char *md_key, const char *md_value, int is_async) { grpc_md_only_test_credentials *c = gpr_malloc(sizeof(grpc_md_only_test_credentials)); memset(c, 0, sizeof(grpc_md_only_test_credentials)); - c->base.type = GRPC_CREDENTIALS_TYPE_OAUTH2; + c->base.type = GRPC_CALL_CREDENTIALS_TYPE_OAUTH2; c->base.vtable = &md_only_test_vtable; gpr_ref_init(&c->base.refcount, 1); c->md_store = grpc_credentials_md_store_create(1); @@ -863,34 +841,26 @@ grpc_credentials *grpc_md_only_test_credentials_create(const char *md_key, /* -- Oauth2 Access Token credentials. -- */ -static void access_token_destruct(grpc_credentials *creds) { +static void access_token_destruct(grpc_call_credentials *creds) { grpc_access_token_credentials *c = (grpc_access_token_credentials *)creds; grpc_credentials_md_store_unref(c->access_token_md); } -static int access_token_has_request_metadata(const grpc_credentials *creds) { - return 1; -} - -static int access_token_has_request_metadata_only( - const grpc_credentials *creds) { - return 1; -} - -static void access_token_get_request_metadata( - grpc_exec_ctx *exec_ctx, grpc_credentials *creds, grpc_pollset *pollset, - const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) { +static void access_token_get_request_metadata(grpc_exec_ctx *exec_ctx, + grpc_call_credentials *creds, + grpc_pollset *pollset, + const char *service_url, + grpc_credentials_metadata_cb cb, + void *user_data) { grpc_access_token_credentials *c = (grpc_access_token_credentials *)creds; cb(exec_ctx, user_data, c->access_token_md->entries, 1, GRPC_CREDENTIALS_OK); } -static grpc_credentials_vtable access_token_vtable = { - access_token_destruct, access_token_has_request_metadata, - access_token_has_request_metadata_only, access_token_get_request_metadata, - NULL}; +static grpc_call_credentials_vtable access_token_vtable = { + access_token_destruct, access_token_get_request_metadata}; -grpc_credentials *grpc_access_token_credentials_create(const char *access_token, - void *reserved) { +grpc_call_credentials *grpc_access_token_credentials_create( + const char *access_token, void *reserved) { grpc_access_token_credentials *c = gpr_malloc(sizeof(grpc_access_token_credentials)); char *token_md_value; @@ -900,7 +870,7 @@ grpc_credentials *grpc_access_token_credentials_create(const char *access_token, 2, (access_token, reserved)); GPR_ASSERT(reserved == NULL); memset(c, 0, sizeof(grpc_access_token_credentials)); - c->base.type = GRPC_CREDENTIALS_TYPE_OAUTH2; + c->base.type = GRPC_CALL_CREDENTIALS_TYPE_OAUTH2; c->base.vtable = &access_token_vtable; gpr_ref_init(&c->base.refcount, 1); c->access_token_md = grpc_credentials_md_store_create(1); @@ -913,31 +883,11 @@ grpc_credentials *grpc_access_token_credentials_create(const char *access_token, /* -- Fake transport security credentials. -- */ -static void fake_transport_security_credentials_destruct( - grpc_credentials *creds) { - /* Nothing to do here. */ -} - -static void fake_transport_security_server_credentials_destruct( - grpc_server_credentials *creds) { - /* Nothing to do here. */ -} - -static int fake_transport_security_has_request_metadata( - const grpc_credentials *creds) { - return 0; -} - -static int fake_transport_security_has_request_metadata_only( - const grpc_credentials *creds) { - return 0; -} - static grpc_security_status fake_transport_security_create_security_connector( - grpc_credentials *c, const char *target, const grpc_channel_args *args, - grpc_credentials *request_metadata_creds, + grpc_channel_credentials *c, grpc_call_credentials *call_creds, + const char *target, const grpc_channel_args *args, grpc_channel_security_connector **sc, grpc_channel_args **new_args) { - *sc = grpc_fake_channel_security_connector_create(request_metadata_creds, 1); + *sc = grpc_fake_channel_security_connector_create(call_creds, 1); return GRPC_SECURITY_OK; } @@ -948,21 +898,19 @@ fake_transport_security_server_create_security_connector( return GRPC_SECURITY_OK; } -static grpc_credentials_vtable fake_transport_security_credentials_vtable = { - fake_transport_security_credentials_destruct, - fake_transport_security_has_request_metadata, - fake_transport_security_has_request_metadata_only, NULL, - fake_transport_security_create_security_connector}; +static grpc_channel_credentials_vtable + fake_transport_security_credentials_vtable = { + NULL, fake_transport_security_create_security_connector}; static grpc_server_credentials_vtable fake_transport_security_server_credentials_vtable = { - fake_transport_security_server_credentials_destruct, - fake_transport_security_server_create_security_connector}; + NULL, fake_transport_security_server_create_security_connector}; -grpc_credentials *grpc_fake_transport_security_credentials_create(void) { - grpc_credentials *c = gpr_malloc(sizeof(grpc_credentials)); - memset(c, 0, sizeof(grpc_credentials)); - c->type = GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY; +grpc_channel_credentials *grpc_fake_transport_security_credentials_create( + void) { + grpc_channel_credentials *c = gpr_malloc(sizeof(grpc_channel_credentials)); + memset(c, 0, sizeof(grpc_channel_credentials)); + c->type = GRPC_CHANNEL_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY; c->vtable = &fake_transport_security_credentials_vtable; gpr_ref_init(&c->refcount, 1); return c; @@ -972,69 +920,46 @@ grpc_server_credentials *grpc_fake_transport_security_server_credentials_create( void) { grpc_server_credentials *c = gpr_malloc(sizeof(grpc_server_credentials)); memset(c, 0, sizeof(grpc_server_credentials)); - c->type = GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY; + c->type = GRPC_CHANNEL_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY; gpr_ref_init(&c->refcount, 1); c->vtable = &fake_transport_security_server_credentials_vtable; return c; } -/* -- Composite credentials. -- */ +/* -- Composite call credentials. -- */ typedef struct { - grpc_composite_credentials *composite_creds; + grpc_composite_call_credentials *composite_creds; size_t creds_index; grpc_credentials_md_store *md_elems; char *service_url; void *user_data; grpc_pollset *pollset; grpc_credentials_metadata_cb cb; -} grpc_composite_credentials_metadata_context; +} grpc_composite_call_credentials_metadata_context; -static void composite_destruct(grpc_credentials *creds) { - grpc_composite_credentials *c = (grpc_composite_credentials *)creds; +static void composite_call_destruct(grpc_call_credentials *creds) { + grpc_composite_call_credentials *c = (grpc_composite_call_credentials *)creds; size_t i; for (i = 0; i < c->inner.num_creds; i++) { - grpc_credentials_unref(c->inner.creds_array[i]); + grpc_call_credentials_unref(c->inner.creds_array[i]); } gpr_free(c->inner.creds_array); } -static int composite_has_request_metadata(const grpc_credentials *creds) { - const grpc_composite_credentials *c = - (const grpc_composite_credentials *)creds; - size_t i; - for (i = 0; i < c->inner.num_creds; i++) { - if (grpc_credentials_has_request_metadata(c->inner.creds_array[i])) { - return 1; - } - } - return 0; -} - -static int composite_has_request_metadata_only(const grpc_credentials *creds) { - const grpc_composite_credentials *c = - (const grpc_composite_credentials *)creds; - size_t i; - for (i = 0; i < c->inner.num_creds; i++) { - if (!grpc_credentials_has_request_metadata_only(c->inner.creds_array[i])) { - return 0; - } - } - return 1; -} - -static void composite_md_context_destroy( - grpc_composite_credentials_metadata_context *ctx) { +static void composite_call_md_context_destroy( + grpc_composite_call_credentials_metadata_context *ctx) { grpc_credentials_md_store_unref(ctx->md_elems); if (ctx->service_url != NULL) gpr_free(ctx->service_url); gpr_free(ctx); } -static void composite_metadata_cb(grpc_exec_ctx *exec_ctx, void *user_data, - grpc_credentials_md *md_elems, size_t num_md, - grpc_credentials_status status) { - grpc_composite_credentials_metadata_context *ctx = - (grpc_composite_credentials_metadata_context *)user_data; +static void composite_call_metadata_cb(grpc_exec_ctx *exec_ctx, void *user_data, + grpc_credentials_md *md_elems, + size_t num_md, + grpc_credentials_status status) { + grpc_composite_call_credentials_metadata_context *ctx = + (grpc_composite_call_credentials_metadata_context *)user_data; if (status != GRPC_CREDENTIALS_OK) { ctx->cb(exec_ctx, ctx->user_data, NULL, 0, status); return; @@ -1050,158 +975,114 @@ static void composite_metadata_cb(grpc_exec_ctx *exec_ctx, void *user_data, } /* See if we need to get some more metadata. */ - while (ctx->creds_index < ctx->composite_creds->inner.num_creds) { - grpc_credentials *inner_creds = + if (ctx->creds_index < ctx->composite_creds->inner.num_creds) { + grpc_call_credentials *inner_creds = ctx->composite_creds->inner.creds_array[ctx->creds_index++]; - if (grpc_credentials_has_request_metadata(inner_creds)) { - grpc_credentials_get_request_metadata(exec_ctx, inner_creds, ctx->pollset, - ctx->service_url, - composite_metadata_cb, ctx); - return; - } + grpc_call_credentials_get_request_metadata(exec_ctx, inner_creds, + ctx->pollset, ctx->service_url, + composite_call_metadata_cb, ctx); + return; } /* We're done!. */ ctx->cb(exec_ctx, ctx->user_data, ctx->md_elems->entries, ctx->md_elems->num_entries, GRPC_CREDENTIALS_OK); - composite_md_context_destroy(ctx); + composite_call_md_context_destroy(ctx); } -static void composite_get_request_metadata( - grpc_exec_ctx *exec_ctx, grpc_credentials *creds, grpc_pollset *pollset, - const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) { - grpc_composite_credentials *c = (grpc_composite_credentials *)creds; - grpc_composite_credentials_metadata_context *ctx; - if (!grpc_credentials_has_request_metadata(creds)) { - cb(exec_ctx, user_data, NULL, 0, GRPC_CREDENTIALS_OK); - return; - } - ctx = gpr_malloc(sizeof(grpc_composite_credentials_metadata_context)); - memset(ctx, 0, sizeof(grpc_composite_credentials_metadata_context)); +static void composite_call_get_request_metadata(grpc_exec_ctx *exec_ctx, + grpc_call_credentials *creds, + grpc_pollset *pollset, + const char *service_url, + grpc_credentials_metadata_cb cb, + void *user_data) { + grpc_composite_call_credentials *c = (grpc_composite_call_credentials *)creds; + grpc_composite_call_credentials_metadata_context *ctx; + + ctx = gpr_malloc(sizeof(grpc_composite_call_credentials_metadata_context)); + memset(ctx, 0, sizeof(grpc_composite_call_credentials_metadata_context)); ctx->service_url = gpr_strdup(service_url); ctx->user_data = user_data; ctx->cb = cb; ctx->composite_creds = c; ctx->pollset = pollset; ctx->md_elems = grpc_credentials_md_store_create(c->inner.num_creds); - while (ctx->creds_index < c->inner.num_creds) { - grpc_credentials *inner_creds = c->inner.creds_array[ctx->creds_index++]; - if (grpc_credentials_has_request_metadata(inner_creds)) { - grpc_credentials_get_request_metadata(exec_ctx, inner_creds, pollset, - service_url, composite_metadata_cb, - ctx); - return; - } - } - GPR_ASSERT(0); /* Should have exited before. */ -} - -static grpc_security_status composite_create_security_connector( - grpc_credentials *creds, const char *target, const grpc_channel_args *args, - grpc_credentials *request_metadata_creds, - grpc_channel_security_connector **sc, grpc_channel_args **new_args) { - grpc_composite_credentials *c = (grpc_composite_credentials *)creds; - if (c->connector_creds == NULL) { - gpr_log(GPR_ERROR, - "Cannot create security connector, missing connector credentials."); - return GRPC_SECURITY_ERROR; - } - return grpc_credentials_create_security_connector(c->connector_creds, target, - args, creds, sc, new_args); + grpc_call_credentials_get_request_metadata( + exec_ctx, c->inner.creds_array[ctx->creds_index++], pollset, service_url, + composite_call_metadata_cb, ctx); } -static grpc_credentials_vtable composite_credentials_vtable = { - composite_destruct, composite_has_request_metadata, - composite_has_request_metadata_only, composite_get_request_metadata, - composite_create_security_connector}; +static grpc_call_credentials_vtable composite_call_credentials_vtable = { + composite_call_destruct, composite_call_get_request_metadata}; -static grpc_credentials_array get_creds_array(grpc_credentials **creds_addr) { - grpc_credentials_array result; - grpc_credentials *creds = *creds_addr; +static grpc_call_credentials_array get_creds_array( + grpc_call_credentials **creds_addr) { + grpc_call_credentials_array result; + grpc_call_credentials *creds = *creds_addr; result.creds_array = creds_addr; result.num_creds = 1; - if (strcmp(creds->type, GRPC_CREDENTIALS_TYPE_COMPOSITE) == 0) { - result = *grpc_composite_credentials_get_credentials(creds); + if (strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0) { + result = *grpc_composite_call_credentials_get_credentials(creds); } return result; } -grpc_credentials *grpc_composite_credentials_create(grpc_credentials *creds1, - grpc_credentials *creds2, - void *reserved) { +grpc_call_credentials *grpc_composite_call_credentials_create( + grpc_call_credentials *creds1, grpc_call_credentials *creds2, + void *reserved) { size_t i; size_t creds_array_byte_size; - grpc_credentials_array creds1_array; - grpc_credentials_array creds2_array; - grpc_composite_credentials *c; + grpc_call_credentials_array creds1_array; + grpc_call_credentials_array creds2_array; + grpc_composite_call_credentials *c; GRPC_API_TRACE( - "grpc_composite_credentials_create(creds1=%p, creds2=%p, " + "grpc_composite_call_credentials_create(creds1=%p, creds2=%p, " "reserved=%p)", 3, (creds1, creds2, reserved)); GPR_ASSERT(reserved == NULL); GPR_ASSERT(creds1 != NULL); GPR_ASSERT(creds2 != NULL); - c = gpr_malloc(sizeof(grpc_composite_credentials)); - memset(c, 0, sizeof(grpc_composite_credentials)); - c->base.type = GRPC_CREDENTIALS_TYPE_COMPOSITE; - c->base.vtable = &composite_credentials_vtable; + c = gpr_malloc(sizeof(grpc_composite_call_credentials)); + memset(c, 0, sizeof(grpc_composite_call_credentials)); + c->base.type = GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE; + c->base.vtable = &composite_call_credentials_vtable; gpr_ref_init(&c->base.refcount, 1); creds1_array = get_creds_array(&creds1); creds2_array = get_creds_array(&creds2); c->inner.num_creds = creds1_array.num_creds + creds2_array.num_creds; - creds_array_byte_size = c->inner.num_creds * sizeof(grpc_credentials *); + creds_array_byte_size = c->inner.num_creds * sizeof(grpc_call_credentials *); c->inner.creds_array = gpr_malloc(creds_array_byte_size); memset(c->inner.creds_array, 0, creds_array_byte_size); for (i = 0; i < creds1_array.num_creds; i++) { - grpc_credentials *cur_creds = creds1_array.creds_array[i]; - if (!grpc_credentials_has_request_metadata_only(cur_creds)) { - if (c->connector_creds == NULL) { - c->connector_creds = cur_creds; - } else { - gpr_log(GPR_ERROR, "Cannot compose multiple connector credentials."); - goto fail; - } - } - c->inner.creds_array[i] = grpc_credentials_ref(cur_creds); + grpc_call_credentials *cur_creds = creds1_array.creds_array[i]; + c->inner.creds_array[i] = grpc_call_credentials_ref(cur_creds); } for (i = 0; i < creds2_array.num_creds; i++) { - grpc_credentials *cur_creds = creds2_array.creds_array[i]; - if (!grpc_credentials_has_request_metadata_only(cur_creds)) { - if (c->connector_creds == NULL) { - c->connector_creds = cur_creds; - } else { - gpr_log(GPR_ERROR, "Cannot compose multiple connector credentials."); - goto fail; - } - } + grpc_call_credentials *cur_creds = creds2_array.creds_array[i]; c->inner.creds_array[i + creds1_array.num_creds] = - grpc_credentials_ref(cur_creds); + grpc_call_credentials_ref(cur_creds); } return &c->base; - -fail: - grpc_credentials_unref(&c->base); - return NULL; } -const grpc_credentials_array *grpc_composite_credentials_get_credentials( - grpc_credentials *creds) { - const grpc_composite_credentials *c = - (const grpc_composite_credentials *)creds; - GPR_ASSERT(strcmp(creds->type, GRPC_CREDENTIALS_TYPE_COMPOSITE) == 0); +const grpc_call_credentials_array * +grpc_composite_call_credentials_get_credentials(grpc_call_credentials *creds) { + const grpc_composite_call_credentials *c = + (const grpc_composite_call_credentials *)creds; + GPR_ASSERT(strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0); return &c->inner; } -grpc_credentials *grpc_credentials_contains_type( - grpc_credentials *creds, const char *type, - grpc_credentials **composite_creds) { +grpc_call_credentials *grpc_credentials_contains_type( + grpc_call_credentials *creds, const char *type, + grpc_call_credentials **composite_creds) { size_t i; if (strcmp(creds->type, type) == 0) { if (composite_creds != NULL) *composite_creds = NULL; return creds; - } else if (strcmp(creds->type, GRPC_CREDENTIALS_TYPE_COMPOSITE) == 0) { - const grpc_credentials_array *inner_creds_array = - grpc_composite_credentials_get_credentials(creds); + } else if (strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0) { + const grpc_call_credentials_array *inner_creds_array = + grpc_composite_call_credentials_get_credentials(creds); for (i = 0; i < inner_creds_array->num_creds; i++) { if (strcmp(type, inner_creds_array->creds_array[i]->type) == 0) { if (composite_creds != NULL) *composite_creds = creds; @@ -1214,30 +1095,26 @@ grpc_credentials *grpc_credentials_contains_type( /* -- IAM credentials. -- */ -static void iam_destruct(grpc_credentials *creds) { +static void iam_destruct(grpc_call_credentials *creds) { grpc_google_iam_credentials *c = (grpc_google_iam_credentials *)creds; grpc_credentials_md_store_unref(c->iam_md); } -static int iam_has_request_metadata(const grpc_credentials *creds) { return 1; } - -static int iam_has_request_metadata_only(const grpc_credentials *creds) { - return 1; -} - -static void iam_get_request_metadata( - grpc_exec_ctx *exec_ctx, grpc_credentials *creds, grpc_pollset *pollset, - const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) { +static void iam_get_request_metadata(grpc_exec_ctx *exec_ctx, + grpc_call_credentials *creds, + grpc_pollset *pollset, + const char *service_url, + grpc_credentials_metadata_cb cb, + void *user_data) { grpc_google_iam_credentials *c = (grpc_google_iam_credentials *)creds; cb(exec_ctx, user_data, c->iam_md->entries, c->iam_md->num_entries, GRPC_CREDENTIALS_OK); } -static grpc_credentials_vtable iam_vtable = { - iam_destruct, iam_has_request_metadata, iam_has_request_metadata_only, - iam_get_request_metadata, NULL}; +static grpc_call_credentials_vtable iam_vtable = {iam_destruct, + iam_get_request_metadata}; -grpc_credentials *grpc_google_iam_credentials_create( +grpc_call_credentials *grpc_google_iam_credentials_create( const char *token, const char *authority_selector, void *reserved) { grpc_google_iam_credentials *c; GRPC_API_TRACE( @@ -1249,7 +1126,7 @@ grpc_credentials *grpc_google_iam_credentials_create( GPR_ASSERT(authority_selector != NULL); c = gpr_malloc(sizeof(grpc_google_iam_credentials)); memset(c, 0, sizeof(grpc_google_iam_credentials)); - c->base.type = GRPC_CREDENTIALS_TYPE_IAM; + c->base.type = GRPC_CALL_CREDENTIALS_TYPE_IAM; c->base.vtable = &iam_vtable; gpr_ref_init(&c->base.refcount, 1); c->iam_md = grpc_credentials_md_store_create(2); @@ -1267,21 +1144,13 @@ typedef struct { grpc_credentials_metadata_cb cb; } grpc_metadata_plugin_request; -static void plugin_destruct(grpc_credentials *creds) { +static void plugin_destruct(grpc_call_credentials *creds) { grpc_plugin_credentials *c = (grpc_plugin_credentials *)creds; if (c->plugin.state != NULL && c->plugin.destroy != NULL) { c->plugin.destroy(c->plugin.state); } } -static int plugin_has_request_metadata(const grpc_credentials *creds) { - return 1; -} - -static int plugin_has_request_metadata_only(const grpc_credentials *creds) { - return 1; -} - static void plugin_md_request_metadata_ready(void *request, const grpc_metadata *md, size_t num_md, @@ -1320,9 +1189,12 @@ static void plugin_md_request_metadata_ready(void *request, grpc_exec_ctx_finish(&exec_ctx); } -static void plugin_get_request_metadata( - grpc_exec_ctx *exec_ctx, grpc_credentials *creds, grpc_pollset *pollset, - const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) { +static void plugin_get_request_metadata(grpc_exec_ctx *exec_ctx, + grpc_call_credentials *creds, + grpc_pollset *pollset, + const char *service_url, + grpc_credentials_metadata_cb cb, + void *user_data) { grpc_plugin_credentials *c = (grpc_plugin_credentials *)creds; if (c->plugin.get_metadata != NULL) { grpc_metadata_plugin_request *request = gpr_malloc(sizeof(*request)); @@ -1336,18 +1208,75 @@ static void plugin_get_request_metadata( } } -static grpc_credentials_vtable plugin_vtable = { - plugin_destruct, plugin_has_request_metadata, - plugin_has_request_metadata_only, plugin_get_request_metadata, NULL}; +static grpc_call_credentials_vtable plugin_vtable = { + plugin_destruct, plugin_get_request_metadata}; -grpc_credentials *grpc_metadata_credentials_create_from_plugin( +grpc_call_credentials *grpc_metadata_credentials_create_from_plugin( grpc_metadata_credentials_plugin plugin, void *reserved) { grpc_plugin_credentials *c = gpr_malloc(sizeof(*c)); + GRPC_API_TRACE("grpc_metadata_credentials_create_from_plugin(reserved=%p)", 1, + (reserved)); GPR_ASSERT(reserved == NULL); memset(c, 0, sizeof(*c)); - c->base.type = GRPC_CREDENTIALS_TYPE_METADATA_PLUGIN; + c->base.type = GRPC_CALL_CREDENTIALS_TYPE_METADATA_PLUGIN; c->base.vtable = &plugin_vtable; gpr_ref_init(&c->base.refcount, 1); c->plugin = plugin; return &c->base; } + +/* -- Composite channel credentials. -- */ + +static void composite_channel_destruct(grpc_channel_credentials *creds) { + grpc_composite_channel_credentials *c = + (grpc_composite_channel_credentials *)creds; + grpc_channel_credentials_unref(c->inner_creds); + grpc_call_credentials_unref(c->call_creds); +} + +static grpc_security_status composite_channel_create_security_connector( + grpc_channel_credentials *creds, grpc_call_credentials *call_creds, + const char *target, const grpc_channel_args *args, + grpc_channel_security_connector **sc, grpc_channel_args **new_args) { + grpc_composite_channel_credentials *c = + (grpc_composite_channel_credentials *)creds; + grpc_security_status status = GRPC_SECURITY_ERROR; + + GPR_ASSERT(c->inner_creds != NULL && c->call_creds != NULL && + c->inner_creds->vtable != NULL && + c->inner_creds->vtable->create_security_connector != NULL); + /* If we are passed a call_creds, create a call composite to pass it + downstream. */ + if (call_creds != NULL) { + grpc_call_credentials *composite_call_creds = + grpc_composite_call_credentials_create(c->call_creds, call_creds, NULL); + status = c->inner_creds->vtable->create_security_connector( + c->inner_creds, composite_call_creds, target, args, sc, new_args); + grpc_call_credentials_unref(composite_call_creds); + } else { + status = c->inner_creds->vtable->create_security_connector( + c->inner_creds, c->call_creds, target, args, sc, new_args); + } + return status; +} + +static grpc_channel_credentials_vtable composite_channel_credentials_vtable = { + composite_channel_destruct, composite_channel_create_security_connector}; + +grpc_channel_credentials *grpc_composite_channel_credentials_create( + grpc_channel_credentials *channel_creds, grpc_call_credentials *call_creds, + void *reserved) { + grpc_composite_channel_credentials *c = gpr_malloc(sizeof(*c)); + memset(c, 0, sizeof(*c)); + GPR_ASSERT(channel_creds != NULL && call_creds != NULL && reserved == NULL); + GRPC_API_TRACE( + "grpc_composite_channel_credentials_create(channel_creds=%p, " + "call_creds=%p, reserved=%p)", + 3, (channel_creds, call_creds, reserved)); + c->base.type = channel_creds->type; + c->base.vtable = &composite_channel_credentials_vtable; + gpr_ref_init(&c->base.refcount, 1); + c->inner_creds = grpc_channel_credentials_ref(channel_creds); + c->call_creds = grpc_call_credentials_ref(call_creds); + return &c->base; +} diff --git a/src/core/security/credentials.h b/src/core/security/credentials.h index c74beef0e4..132060910e 100644 --- a/src/core/security/credentials.h +++ b/src/core/security/credentials.h @@ -54,15 +54,17 @@ typedef enum { #define GRPC_FAKE_TRANSPORT_SECURITY_TYPE "fake" -#define GRPC_CREDENTIALS_TYPE_SSL "Ssl" -#define GRPC_CREDENTIALS_TYPE_OAUTH2 "Oauth2" -#define GRPC_CREDENTIALS_TYPE_METADATA_PLUGIN "Plugin" -#define GRPC_CREDENTIALS_TYPE_JWT "Jwt" -#define GRPC_CREDENTIALS_TYPE_IAM "Iam" -#define GRPC_CREDENTIALS_TYPE_COMPOSITE "Composite" -#define GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY "FakeTransportSecurity" - -#define GRPC_AUTHORIZATION_METADATA_KEY "Authorization" +#define GRPC_CHANNEL_CREDENTIALS_TYPE_SSL "Ssl" +#define GRPC_CHANNEL_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY \ + "FakeTransportSecurity" + +#define GRPC_CALL_CREDENTIALS_TYPE_OAUTH2 "Oauth2" +#define GRPC_CALL_CREDENTIALS_TYPE_METADATA_PLUGIN "Plugin" +#define GRPC_CALL_CREDENTIALS_TYPE_JWT "Jwt" +#define GRPC_CALL_CREDENTIALS_TYPE_IAM "Iam" +#define GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE "Composite" + +#define GRPC_AUTHORIZATION_METADATA_KEY "authorization" #define GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY \ "x-goog-iam-authorization-token" #define GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY "x-goog-iam-authority-selector" @@ -87,6 +89,41 @@ typedef enum { #define GRPC_REFRESH_TOKEN_POST_BODY_FORMAT_STRING \ "client_id=%s&client_secret=%s&refresh_token=%s&grant_type=refresh_token" +/* --- Google utils --- */ + +/* It is the caller's responsibility to gpr_free the result if not NULL. */ +char *grpc_get_well_known_google_credentials_file_path(void); + +/* --- grpc_channel_credentials. --- */ + +typedef struct { + void (*destruct)(grpc_channel_credentials *c); + + grpc_security_status (*create_security_connector)( + grpc_channel_credentials *c, grpc_call_credentials *call_creds, + const char *target, const grpc_channel_args *args, + grpc_channel_security_connector **sc, grpc_channel_args **new_args); +} grpc_channel_credentials_vtable; + +struct grpc_channel_credentials { + const grpc_channel_credentials_vtable *vtable; + const char *type; + gpr_refcount refcount; +}; + +grpc_channel_credentials *grpc_channel_credentials_ref( + grpc_channel_credentials *creds); +void grpc_channel_credentials_unref(grpc_channel_credentials *creds); + +/* Creates a security connector for the channel. May also create new channel + args for the channel to be used in place of the passed in const args if + returned non NULL. In that case the caller is responsible for destroying + new_args after channel creation. */ +grpc_security_status grpc_channel_credentials_create_security_connector( + grpc_channel_credentials *creds, const char *target, + const grpc_channel_args *args, grpc_channel_security_connector **sc, + grpc_channel_args **new_args); + /* --- grpc_credentials_md. --- */ typedef struct { @@ -113,16 +150,7 @@ grpc_credentials_md_store *grpc_credentials_md_store_ref( grpc_credentials_md_store *store); void grpc_credentials_md_store_unref(grpc_credentials_md_store *store); -/* --- grpc_credentials. --- */ - -/* Creates a fake transport security credentials object for testing. */ -grpc_credentials *grpc_fake_transport_security_credentials_create(void); -/* Creates a fake server transport security credentials object for testing. */ -grpc_server_credentials *grpc_fake_transport_security_server_credentials_create( - void); - -/* It is the caller's responsibility to gpr_free the result if not NULL. */ -char *grpc_get_well_known_google_credentials_file_path(void); +/* --- grpc_call_credentials. --- */ typedef void (*grpc_credentials_metadata_cb)(grpc_exec_ctx *exec_ctx, void *user_data, @@ -131,57 +159,45 @@ typedef void (*grpc_credentials_metadata_cb)(grpc_exec_ctx *exec_ctx, grpc_credentials_status status); typedef struct { - void (*destruct)(grpc_credentials *c); - int (*has_request_metadata)(const grpc_credentials *c); - int (*has_request_metadata_only)(const grpc_credentials *c); - void (*get_request_metadata)(grpc_exec_ctx *exec_ctx, grpc_credentials *c, - grpc_pollset *pollset, const char *service_url, + void (*destruct)(grpc_call_credentials *c); + void (*get_request_metadata)(grpc_exec_ctx *exec_ctx, + grpc_call_credentials *c, grpc_pollset *pollset, + const char *service_url, grpc_credentials_metadata_cb cb, void *user_data); - grpc_security_status (*create_security_connector)( - grpc_credentials *c, const char *target, const grpc_channel_args *args, - grpc_credentials *request_metadata_creds, - grpc_channel_security_connector **sc, grpc_channel_args **new_args); -} grpc_credentials_vtable; +} grpc_call_credentials_vtable; -struct grpc_credentials { - const grpc_credentials_vtable *vtable; +struct grpc_call_credentials { + const grpc_call_credentials_vtable *vtable; const char *type; gpr_refcount refcount; }; -grpc_credentials *grpc_credentials_ref(grpc_credentials *creds); -void grpc_credentials_unref(grpc_credentials *creds); -int grpc_credentials_has_request_metadata(grpc_credentials *creds); -int grpc_credentials_has_request_metadata_only(grpc_credentials *creds); -void grpc_credentials_get_request_metadata( - grpc_exec_ctx *exec_ctx, grpc_credentials *creds, grpc_pollset *pollset, - const char *service_url, grpc_credentials_metadata_cb cb, void *user_data); - -/* Creates a security connector for the channel. May also create new channel - args for the channel to be used in place of the passed in const args if - returned non NULL. In that case the caller is responsible for destroying - new_args after channel creation. */ -grpc_security_status grpc_credentials_create_security_connector( - grpc_credentials *creds, const char *target, const grpc_channel_args *args, - grpc_credentials *request_metadata_creds, - grpc_channel_security_connector **sc, grpc_channel_args **new_args); +grpc_call_credentials *grpc_call_credentials_ref(grpc_call_credentials *creds); +void grpc_call_credentials_unref(grpc_call_credentials *creds); +void grpc_call_credentials_get_request_metadata(grpc_exec_ctx *exec_ctx, + grpc_call_credentials *creds, + grpc_pollset *pollset, + const char *service_url, + grpc_credentials_metadata_cb cb, + void *user_data); typedef struct { - grpc_credentials **creds_array; + grpc_call_credentials **creds_array; size_t num_creds; -} grpc_credentials_array; +} grpc_call_credentials_array; -const grpc_credentials_array *grpc_composite_credentials_get_credentials( - grpc_credentials *composite_creds); +const grpc_call_credentials_array * +grpc_composite_call_credentials_get_credentials( + grpc_call_credentials *composite_creds); /* Returns creds if creds is of the specified type or the inner creds of the specified type (if found), if the creds is of type COMPOSITE. If composite_creds is not NULL, *composite_creds will point to creds if of type COMPOSITE in case of success. */ -grpc_credentials *grpc_credentials_contains_type( - grpc_credentials *creds, const char *type, - grpc_credentials **composite_creds); +grpc_call_credentials *grpc_credentials_contains_type( + grpc_call_credentials *creds, const char *type, + grpc_call_credentials **composite_creds); /* Exposed for testing only. */ grpc_credentials_status @@ -192,19 +208,19 @@ void grpc_flush_cached_google_default_credentials(void); /* Metadata-only credentials with the specified key and value where asynchronicity can be simulated for testing. */ -grpc_credentials *grpc_md_only_test_credentials_create(const char *md_key, - const char *md_value, - int is_async); +grpc_call_credentials *grpc_md_only_test_credentials_create( + const char *md_key, const char *md_value, int is_async); /* Private constructor for jwt credentials from an already parsed json key. Takes ownership of the key. */ -grpc_credentials * +grpc_call_credentials * grpc_service_account_jwt_access_credentials_create_from_auth_json_key( grpc_auth_json_key key, gpr_timespec token_lifetime); /* Private constructor for refresh token credentials from an already parsed refresh token. Takes ownership of the refresh token. */ -grpc_credentials *grpc_refresh_token_credentials_create_from_auth_refresh_token( +grpc_call_credentials * +grpc_refresh_token_credentials_create_from_auth_refresh_token( grpc_auth_refresh_token token); /* --- grpc_server_credentials. --- */ @@ -237,10 +253,18 @@ grpc_server_credentials *grpc_server_credentials_from_arg(const grpc_arg *arg); grpc_server_credentials *grpc_find_server_credentials_in_args( const grpc_channel_args *args); +/* -- Fake transport security credentials. -- */ + +/* Creates a fake transport security credentials object for testing. */ +grpc_channel_credentials *grpc_fake_transport_security_credentials_create(void); +/* Creates a fake server transport security credentials object for testing. */ +grpc_server_credentials *grpc_fake_transport_security_server_credentials_create( + void); + /* -- Ssl credentials. -- */ typedef struct { - grpc_credentials base; + grpc_channel_credentials base; grpc_ssl_config config; } grpc_ssl_credentials; @@ -249,10 +273,18 @@ typedef struct { grpc_ssl_server_config config; } grpc_ssl_server_credentials; +/* -- Channel composite credentials. -- */ + +typedef struct { + grpc_channel_credentials base; + grpc_channel_credentials *inner_creds; + grpc_call_credentials *call_creds; +} grpc_composite_channel_credentials; + /* -- Jwt credentials -- */ typedef struct { - grpc_credentials base; + grpc_call_credentials base; /* Have a simple cache for now with just 1 entry. We could have a map based on the service_url for a more sophisticated one. */ @@ -283,7 +315,7 @@ typedef void (*grpc_fetch_oauth2_func)(grpc_exec_ctx *exec_ctx, gpr_timespec deadline); typedef struct { - grpc_credentials base; + grpc_call_credentials base; gpr_mu mu; grpc_credentials_md_store *access_token_md; gpr_timespec token_expiration; @@ -301,14 +333,14 @@ typedef struct { /* -- Oauth2 Access Token credentials. -- */ typedef struct { - grpc_credentials base; + grpc_call_credentials base; grpc_credentials_md_store *access_token_md; } grpc_access_token_credentials; /* -- Metadata-only Test credentials. -- */ typedef struct { - grpc_credentials base; + grpc_call_credentials base; grpc_credentials_md_store *md_store; int is_async; } grpc_md_only_test_credentials; @@ -316,22 +348,21 @@ typedef struct { /* -- GoogleIAM credentials. -- */ typedef struct { - grpc_credentials base; + grpc_call_credentials base; grpc_credentials_md_store *iam_md; } grpc_google_iam_credentials; /* -- Composite credentials. -- */ typedef struct { - grpc_credentials base; - grpc_credentials_array inner; - grpc_credentials *connector_creds; -} grpc_composite_credentials; + grpc_call_credentials base; + grpc_call_credentials_array inner; +} grpc_composite_call_credentials; /* -- Plugin credentials. -- */ typedef struct { - grpc_credentials base; + grpc_call_credentials base; grpc_metadata_credentials_plugin plugin; grpc_credentials_md_store *plugin_md; } grpc_plugin_credentials; diff --git a/src/core/security/google_default_credentials.c b/src/core/security/google_default_credentials.c index 45135305b2..6a54fe4e47 100644 --- a/src/core/security/google_default_credentials.c +++ b/src/core/security/google_default_credentials.c @@ -50,7 +50,7 @@ /* -- Default credentials. -- */ -static grpc_credentials *default_credentials = NULL; +static grpc_channel_credentials *default_credentials = NULL; static int compute_engine_detection_done = 0; static gpr_mu g_mu; static gpr_once g_once = GPR_ONCE_INIT; @@ -138,11 +138,11 @@ static int is_stack_running_on_compute_engine(void) { } /* Takes ownership of creds_path if not NULL. */ -static grpc_credentials *create_default_creds_from_path(char *creds_path) { +static grpc_call_credentials *create_default_creds_from_path(char *creds_path) { grpc_json *json = NULL; grpc_auth_json_key key; grpc_auth_refresh_token token; - grpc_credentials *result = NULL; + grpc_call_credentials *result = NULL; gpr_slice creds_data = gpr_empty_slice(); int file_ok = 0; if (creds_path == NULL) goto end; @@ -176,9 +176,9 @@ end: return result; } -grpc_credentials *grpc_google_default_credentials_create(void) { - grpc_credentials *result = NULL; - int serving_cached_credentials = 0; +grpc_channel_credentials *grpc_google_default_credentials_create(void) { + grpc_channel_credentials *result = NULL; + grpc_call_credentials *call_creds = NULL; GRPC_API_TRACE("grpc_google_default_credentials_create(void)", 0, ()); @@ -187,20 +187,19 @@ grpc_credentials *grpc_google_default_credentials_create(void) { gpr_mu_lock(&g_mu); if (default_credentials != NULL) { - result = grpc_credentials_ref(default_credentials); - serving_cached_credentials = 1; + result = grpc_channel_credentials_ref(default_credentials); goto end; } /* First, try the environment variable. */ - result = create_default_creds_from_path( + call_creds = create_default_creds_from_path( gpr_getenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR)); - if (result != NULL) goto end; + if (call_creds != NULL) goto end; /* Then the well-known file. */ - result = create_default_creds_from_path( + call_creds = create_default_creds_from_path( grpc_get_well_known_google_credentials_file_path()); - if (result != NULL) goto end; + if (call_creds != NULL) goto end; /* At last try to see if we're on compute engine (do the detection only once since it requires a network test). */ @@ -208,21 +207,28 @@ grpc_credentials *grpc_google_default_credentials_create(void) { int need_compute_engine_creds = is_stack_running_on_compute_engine(); compute_engine_detection_done = 1; if (need_compute_engine_creds) { - result = grpc_google_compute_engine_credentials_create(NULL); + call_creds = grpc_google_compute_engine_credentials_create(NULL); } } end: - if (!serving_cached_credentials && result != NULL) { - /* Blend with default ssl credentials and add a global reference so that it - can be cached and re-served. */ - grpc_credentials *ssl_creds = grpc_ssl_credentials_create(NULL, NULL, NULL); - default_credentials = grpc_credentials_ref( - grpc_composite_credentials_create(ssl_creds, result, NULL)); - GPR_ASSERT(default_credentials != NULL); - grpc_credentials_unref(ssl_creds); - grpc_credentials_unref(result); - result = default_credentials; + if (result == NULL) { + if (call_creds != NULL) { + /* Blend with default ssl credentials and add a global reference so that + it + can be cached and re-served. */ + grpc_channel_credentials *ssl_creds = + grpc_ssl_credentials_create(NULL, NULL, NULL); + default_credentials = grpc_channel_credentials_ref( + grpc_composite_channel_credentials_create(ssl_creds, call_creds, + NULL)); + GPR_ASSERT(default_credentials != NULL); + grpc_channel_credentials_unref(ssl_creds); + grpc_call_credentials_unref(call_creds); + result = default_credentials; + } else { + gpr_log(GPR_ERROR, "Could not create google default credentials."); + } } gpr_mu_unlock(&g_mu); return result; @@ -232,7 +238,7 @@ void grpc_flush_cached_google_default_credentials(void) { gpr_once_init(&g_once, init_default_credentials); gpr_mu_lock(&g_mu); if (default_credentials != NULL) { - grpc_credentials_unref(default_credentials); + grpc_channel_credentials_unref(default_credentials); default_credentials = NULL; } gpr_mu_unlock(&g_mu); diff --git a/src/core/security/security_connector.c b/src/core/security/security_connector.c index 7c4cf6f04d..3c54a4deae 100644 --- a/src/core/security/security_connector.c +++ b/src/core/security/security_connector.c @@ -203,16 +203,6 @@ grpc_security_connector *grpc_find_security_connector_in_args( return NULL; } -static int check_request_metadata_creds(grpc_credentials *creds) { - if (creds != NULL && !grpc_credentials_has_request_metadata(creds)) { - gpr_log(GPR_ERROR, - "Incompatible credentials for channel security connector: needs to " - "set request metadata."); - return 0; - } - return 1; -} - /* -- Fake implementation. -- */ typedef struct { @@ -222,7 +212,7 @@ typedef struct { static void fake_channel_destroy(grpc_security_connector *sc) { grpc_channel_security_connector *c = (grpc_channel_security_connector *)sc; - grpc_credentials_unref(c->request_metadata_creds); + grpc_call_credentials_unref(c->request_metadata_creds); GRPC_AUTH_CONTEXT_UNREF(sc->auth_context, "connector"); gpr_free(sc); } @@ -306,7 +296,8 @@ static grpc_security_connector_vtable fake_server_vtable = { fake_server_destroy, fake_server_do_handshake, fake_check_peer}; grpc_channel_security_connector *grpc_fake_channel_security_connector_create( - grpc_credentials *request_metadata_creds, int call_host_check_is_async) { + grpc_call_credentials *request_metadata_creds, + int call_host_check_is_async) { grpc_fake_channel_security_connector *c = gpr_malloc(sizeof(grpc_fake_channel_security_connector)); memset(c, 0, sizeof(grpc_fake_channel_security_connector)); @@ -314,8 +305,8 @@ grpc_channel_security_connector *grpc_fake_channel_security_connector_create( c->base.base.is_client_side = 1; c->base.base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME; c->base.base.vtable = &fake_channel_vtable; - GPR_ASSERT(check_request_metadata_creds(request_metadata_creds)); - c->base.request_metadata_creds = grpc_credentials_ref(request_metadata_creds); + c->base.request_metadata_creds = + grpc_call_credentials_ref(request_metadata_creds); c->base.check_call_host = fake_channel_check_call_host; c->call_host_check_is_async = call_host_check_is_async; return &c->base; @@ -349,7 +340,7 @@ typedef struct { static void ssl_channel_destroy(grpc_security_connector *sc) { grpc_ssl_channel_security_connector *c = (grpc_ssl_channel_security_connector *)sc; - grpc_credentials_unref(c->base.request_metadata_creds); + grpc_call_credentials_unref(c->base.request_metadata_creds); if (c->handshaker_factory != NULL) { tsi_ssl_handshaker_factory_destroy(c->handshaker_factory); } @@ -580,9 +571,9 @@ size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs) { } grpc_security_status grpc_ssl_channel_security_connector_create( - grpc_credentials *request_metadata_creds, const grpc_ssl_config *config, - const char *target_name, const char *overridden_target_name, - grpc_channel_security_connector **sc) { + grpc_call_credentials *request_metadata_creds, + const grpc_ssl_config *config, const char *target_name, + const char *overridden_target_name, grpc_channel_security_connector **sc) { size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions(); const unsigned char **alpn_protocol_strings = gpr_malloc(sizeof(const char *) * num_alpn_protocols); @@ -606,9 +597,6 @@ grpc_security_status grpc_ssl_channel_security_connector_create( gpr_log(GPR_ERROR, "An ssl channel needs a config and a target name."); goto error; } - if (!check_request_metadata_creds(request_metadata_creds)) { - goto error; - } if (config->pem_root_certs == NULL) { pem_root_certs_size = grpc_get_default_ssl_roots(&pem_root_certs); if (pem_root_certs == NULL || pem_root_certs_size == 0) { @@ -627,7 +615,8 @@ grpc_security_status grpc_ssl_channel_security_connector_create( c->base.base.vtable = &ssl_channel_vtable; c->base.base.is_client_side = 1; c->base.base.url_scheme = GRPC_SSL_URL_SCHEME; - c->base.request_metadata_creds = grpc_credentials_ref(request_metadata_creds); + c->base.request_metadata_creds = + grpc_call_credentials_ref(request_metadata_creds); c->base.check_call_host = ssl_channel_check_call_host; gpr_split_host_port(target_name, &c->target_name, &port); gpr_free(port); diff --git a/src/core/security/security_connector.h b/src/core/security/security_connector.h index 9218a3caab..c5f00c5563 100644 --- a/src/core/security/security_connector.h +++ b/src/core/security/security_connector.h @@ -145,7 +145,7 @@ typedef struct grpc_channel_security_connector grpc_channel_security_connector; struct grpc_channel_security_connector { grpc_security_connector base; /* requires is_client_side to be non 0. */ - grpc_credentials *request_metadata_creds; + grpc_call_credentials *request_metadata_creds; grpc_security_status (*check_call_host)(grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc, const char *host, @@ -167,7 +167,8 @@ grpc_security_status grpc_channel_security_connector_check_call_host( /* For TESTING ONLY! Creates a fake connector that emulates real channel security. */ grpc_channel_security_connector *grpc_fake_channel_security_connector_create( - grpc_credentials *request_metadata_creds, int call_host_check_is_async); + grpc_call_credentials *request_metadata_creds, + int call_host_check_is_async); /* For TESTING ONLY! Creates a fake connector that emulates real server security. */ @@ -197,9 +198,9 @@ typedef struct { specific error code otherwise. */ grpc_security_status grpc_ssl_channel_security_connector_create( - grpc_credentials *request_metadata_creds, const grpc_ssl_config *config, - const char *target_name, const char *overridden_target_name, - grpc_channel_security_connector **sc); + grpc_call_credentials *request_metadata_creds, + const grpc_ssl_config *config, const char *target_name, + const char *overridden_target_name, grpc_channel_security_connector **sc); /* Gets the default ssl roots. */ size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs); diff --git a/src/core/security/security_context.c b/src/core/security/security_context.c index ff3ad64d92..2068c97d78 100644 --- a/src/core/security/security_context.c +++ b/src/core/security/security_context.c @@ -46,7 +46,7 @@ /* --- grpc_call --- */ grpc_call_error grpc_call_set_credentials(grpc_call *call, - grpc_credentials *creds) { + grpc_call_credentials *creds) { grpc_client_security_context *ctx = NULL; GRPC_API_TRACE("grpc_call_set_credentials(call=%p, creds=%p)", 2, (call, creds)); @@ -54,20 +54,16 @@ grpc_call_error grpc_call_set_credentials(grpc_call *call, gpr_log(GPR_ERROR, "Method is client-side only."); return GRPC_CALL_ERROR_NOT_ON_SERVER; } - if (creds != NULL && !grpc_credentials_has_request_metadata_only(creds)) { - gpr_log(GPR_ERROR, "Incompatible credentials to set on a call."); - return GRPC_CALL_ERROR; - } ctx = (grpc_client_security_context *)grpc_call_context_get( call, GRPC_CONTEXT_SECURITY); if (ctx == NULL) { ctx = grpc_client_security_context_create(); - ctx->creds = grpc_credentials_ref(creds); + ctx->creds = grpc_call_credentials_ref(creds); grpc_call_context_set(call, GRPC_CONTEXT_SECURITY, ctx, grpc_client_security_context_destroy); } else { - grpc_credentials_unref(ctx->creds); - ctx->creds = grpc_credentials_ref(creds); + grpc_call_credentials_unref(ctx->creds); + ctx->creds = grpc_call_credentials_ref(creds); } return GRPC_CALL_OK; } @@ -101,7 +97,7 @@ grpc_client_security_context *grpc_client_security_context_create(void) { void grpc_client_security_context_destroy(void *ctx) { grpc_client_security_context *c = (grpc_client_security_context *)ctx; - grpc_credentials_unref(c->creds); + grpc_call_credentials_unref(c->creds); GRPC_AUTH_CONTEXT_UNREF(c->auth_context, "client_security_context"); gpr_free(ctx); } diff --git a/src/core/security/security_context.h b/src/core/security/security_context.h index 2bbdc4be97..794258edbc 100644 --- a/src/core/security/security_context.h +++ b/src/core/security/security_context.h @@ -85,7 +85,7 @@ void grpc_auth_property_reset(grpc_auth_property *property); Internal client-side security context. */ typedef struct { - grpc_credentials *creds; + grpc_call_credentials *creds; grpc_auth_context *auth_context; } grpc_client_security_context; diff --git a/src/core/security/server_secure_chttp2.c b/src/core/security/server_secure_chttp2.c index 851e0cfab3..1ea269bf8f 100644 --- a/src/core/security/server_secure_chttp2.c +++ b/src/core/security/server_secure_chttp2.c @@ -249,9 +249,11 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr, } for (i = 0; i < resolved->naddrs; i++) { - port_temp = grpc_tcp_server_add_port( + grpc_tcp_listener *listener; + listener = grpc_tcp_server_add_port( tcp, (struct sockaddr *)&resolved->addrs[i].addr, resolved->addrs[i].len); + port_temp = grpc_tcp_listener_get_port(listener); if (port_temp >= 0) { if (port_num == -1) { port_num = port_temp; diff --git a/src/core/support/slice_buffer.c b/src/core/support/slice_buffer.c index 17c0b6c0f6..856d3a2439 100644 --- a/src/core/support/slice_buffer.c +++ b/src/core/support/slice_buffer.c @@ -220,7 +220,7 @@ void gpr_slice_buffer_move_first(gpr_slice_buffer *src, size_t n, return; } src_idx = 0; - for (;;) { + while (src_idx < src->capacity) { gpr_slice slice = src->slices[src_idx]; size_t slice_len = GPR_SLICE_LENGTH(slice); if (n > slice_len) { diff --git a/src/core/support/time_win32.c b/src/core/support/time_win32.c index bc0586d069..623a8d9233 100644 --- a/src/core/support/time_win32.c +++ b/src/core/support/time_win32.c @@ -66,14 +66,12 @@ gpr_timespec gpr_now(gpr_clock_type clock) { now_tv.tv_nsec = now_tb.millitm * 1000000; break; case GPR_CLOCK_MONOTONIC: + case GPR_CLOCK_PRECISE: QueryPerformanceCounter(×tamp); now_dbl = (timestamp.QuadPart - g_start_time.QuadPart) * g_time_scale; 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/src/core/surface/byte_buffer_reader.c b/src/core/surface/byte_buffer_reader.c index 9f830df68c..57417f41b0 100644 --- a/src/core/surface/byte_buffer_reader.c +++ b/src/core/surface/byte_buffer_reader.c @@ -121,4 +121,3 @@ gpr_slice grpc_byte_buffer_reader_readall(grpc_byte_buffer_reader *reader) { } return out_slice; } - diff --git a/src/core/surface/call.c b/src/core/surface/call.c index aa435d44d3..86d5fca388 100644 --- a/src/core/surface/call.c +++ b/src/core/surface/call.c @@ -922,7 +922,8 @@ static batch_control *allocate_batch_control(grpc_call *call) { size_t i; for (i = 0; i < MAX_CONCURRENT_BATCHES; i++) { if ((call->used_batches & (1 << i)) == 0) { - call->used_batches |= (gpr_uint8)(1 << i); + call->used_batches = + (gpr_uint8)(call->used_batches | (gpr_uint8)(1 << i)); return &call->active_batches[i]; } } diff --git a/src/core/surface/secure_channel_create.c b/src/core/surface/secure_channel_create.c index 1282ee99ed..0dd0a31169 100644 --- a/src/core/surface/secure_channel_create.c +++ b/src/core/surface/secure_channel_create.c @@ -230,7 +230,7 @@ static const grpc_subchannel_factory_vtable subchannel_factory_vtable = { Asynchronously: - resolve target - connect to it (trying alternatives as presented) - perform handshakes */ -grpc_channel *grpc_secure_channel_create(grpc_credentials *creds, +grpc_channel *grpc_secure_channel_create(grpc_channel_credentials *creds, const char *target, const grpc_channel_args *args, void *reserved) { @@ -261,9 +261,9 @@ grpc_channel *grpc_secure_channel_create(grpc_credentials *creds, "Security connector exists in channel args."); } - if (grpc_credentials_create_security_connector( - creds, target, args, NULL, &security_connector, - &new_args_from_connector) != GRPC_SECURITY_OK) { + if (grpc_channel_credentials_create_security_connector( + creds, target, args, &security_connector, &new_args_from_connector) != + GRPC_SECURITY_OK) { grpc_exec_ctx_finish(&exec_ctx); return grpc_lame_client_channel_create( target, GRPC_STATUS_INVALID_ARGUMENT, diff --git a/src/core/surface/server_chttp2.c b/src/core/surface/server_chttp2.c index 580b91573c..1408f9c159 100644 --- a/src/core/surface/server_chttp2.c +++ b/src/core/surface/server_chttp2.c @@ -107,9 +107,11 @@ int grpc_server_add_insecure_http2_port(grpc_server *server, const char *addr) { } for (i = 0; i < resolved->naddrs; i++) { - port_temp = grpc_tcp_server_add_port( + grpc_tcp_listener *listener; + listener = grpc_tcp_server_add_port( tcp, (struct sockaddr *)&resolved->addrs[i].addr, resolved->addrs[i].len); + port_temp = grpc_tcp_listener_get_port(listener); if (port_temp >= 0) { if (port_num == -1) { port_num = port_temp; diff --git a/src/core/surface/version.c b/src/core/surface/version.c index e559d51448..962a72112a 100644 --- a/src/core/surface/version.c +++ b/src/core/surface/version.c @@ -36,4 +36,4 @@ #include <grpc/grpc.h> -const char *grpc_version_string(void) { return "0.11.0.0"; } +const char *grpc_version_string(void) { return "0.12.0.0"; } diff --git a/src/core/transport/chttp2/hpack_encoder.c b/src/core/transport/chttp2/hpack_encoder.c index 6c7c00b7c3..758babc3d0 100644 --- a/src/core/transport/chttp2/hpack_encoder.c +++ b/src/core/transport/chttp2/hpack_encoder.c @@ -36,8 +36,10 @@ #include <assert.h> #include <string.h> +#include <grpc/support/alloc.h> #include <grpc/support/log.h> #include <grpc/support/useful.h> + #include "src/core/transport/chttp2/bin_encoder.h" #include "src/core/transport/chttp2/hpack_table.h" #include "src/core/transport/chttp2/timeout_encoding.h" @@ -154,6 +156,18 @@ static gpr_uint8 *add_tiny_header_data(framer_state *st, size_t len) { return gpr_slice_buffer_tiny_add(st->output, len); } +static void evict_entry(grpc_chttp2_hpack_compressor *c) { + c->tail_remote_index++; + GPR_ASSERT(c->tail_remote_index > 0); + GPR_ASSERT(c->table_size >= + c->table_elem_size[c->tail_remote_index % c->cap_table_elems]); + GPR_ASSERT(c->table_elems > 0); + c->table_size = (gpr_uint16)( + c->table_size - + c->table_elem_size[c->tail_remote_index % c->cap_table_elems]); + c->table_elems--; +} + /* add an element to the decoder table */ static void add_elem(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem) { gpr_uint32 key_hash = elem->key->hash; @@ -164,26 +178,21 @@ static void add_elem(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem) { GPR_ASSERT(elem_size < 65536); + if (elem_size > c->max_table_size) { + while (c->table_size > 0) { + evict_entry(c); + } + return; + } + /* Reserve space for this element in the remote table: if this overflows the current table, drop elements until it fits, matching the decompressor algorithm */ - /* TODO(ctiller): constant */ - while (c->table_size + elem_size > 4096) { - c->tail_remote_index++; - GPR_ASSERT(c->tail_remote_index > 0); - GPR_ASSERT(c->table_size >= - c->table_elem_size[c->tail_remote_index % - GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS]); - GPR_ASSERT(c->table_elems > 0); - c->table_size = - (gpr_uint16)(c->table_size - - c->table_elem_size[c->tail_remote_index % - GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS]); - c->table_elems--; + while (c->table_size + elem_size > c->max_table_size) { + evict_entry(c); } - GPR_ASSERT(c->table_elems < GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS); - c->table_elem_size[new_index % GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS] = - (gpr_uint16)elem_size; + GPR_ASSERT(c->table_elems < c->max_table_size); + c->table_elem_size[new_index % c->cap_table_elems] = (gpr_uint16)elem_size; c->table_size = (gpr_uint16)(c->table_size + elem_size); c->table_elems++; @@ -329,6 +338,14 @@ static void emit_lithdr_noidx_v(grpc_chttp2_hpack_compressor *c, add_header_data(st, gpr_slice_ref(value_slice)); } +static void emit_advertise_table_size_change(grpc_chttp2_hpack_compressor *c, + framer_state *st) { + gpr_uint32 len = GRPC_CHTTP2_VARINT_LENGTH(c->max_table_size, 3); + GRPC_CHTTP2_WRITE_VARINT(c->max_table_size, 3, 0x20, + add_tiny_header_data(st, len), len); + c->advertise_table_size_change = 0; +} + static gpr_uint32 dynidx(grpc_chttp2_hpack_compressor *c, gpr_uint32 elem_index) { return 1 + GRPC_CHTTP2_LAST_STATIC_ENTRY + c->tail_remote_index + @@ -447,11 +464,23 @@ gpr_slice grpc_chttp2_data_frame_create_empty_close(gpr_uint32 id) { return slice; } +static gpr_uint32 elems_for_bytes(gpr_uint32 bytes) { + return (bytes + 31) / 32; +} + void grpc_chttp2_hpack_compressor_init(grpc_chttp2_hpack_compressor *c, grpc_mdctx *ctx) { memset(c, 0, sizeof(*c)); c->mdctx = ctx; c->timeout_key_str = grpc_mdstr_from_string(ctx, "grpc-timeout"); + c->max_table_size = GRPC_CHTTP2_HPACKC_INITIAL_TABLE_SIZE; + c->cap_table_elems = elems_for_bytes(c->max_table_size); + c->max_table_elems = c->cap_table_elems; + c->max_usable_size = GRPC_CHTTP2_HPACKC_INITIAL_TABLE_SIZE; + c->table_elem_size = + gpr_malloc(sizeof(*c->table_elem_size) * c->cap_table_elems); + memset(c->table_elem_size, 0, + sizeof(*c->table_elem_size) * c->cap_table_elems); } void grpc_chttp2_hpack_compressor_destroy(grpc_chttp2_hpack_compressor *c) { @@ -461,6 +490,54 @@ void grpc_chttp2_hpack_compressor_destroy(grpc_chttp2_hpack_compressor *c) { if (c->entries_elems[i]) GRPC_MDELEM_UNREF(c->entries_elems[i]); } GRPC_MDSTR_UNREF(c->timeout_key_str); + gpr_free(c->table_elem_size); +} + +void grpc_chttp2_hpack_compressor_set_max_usable_size( + grpc_chttp2_hpack_compressor *c, gpr_uint32 max_table_size) { + c->max_usable_size = max_table_size; + grpc_chttp2_hpack_compressor_set_max_table_size( + c, GPR_MIN(c->max_table_size, max_table_size)); +} + +static void rebuild_elems(grpc_chttp2_hpack_compressor *c, gpr_uint32 new_cap) { + gpr_uint16 *table_elem_size = gpr_malloc(sizeof(*table_elem_size) * new_cap); + gpr_uint32 i; + + memset(table_elem_size, 0, sizeof(*table_elem_size) * new_cap); + GPR_ASSERT(c->table_elems <= new_cap); + + for (i = 0; i < c->table_elems; i++) { + gpr_uint32 ofs = c->tail_remote_index + i + 1; + table_elem_size[ofs % new_cap] = c->table_elem_size[ofs % c->cap_table_elems]; + } + + c->cap_table_elems = new_cap; + gpr_free(c->table_elem_size); + c->table_elem_size = table_elem_size; +} + +void grpc_chttp2_hpack_compressor_set_max_table_size( + grpc_chttp2_hpack_compressor *c, gpr_uint32 max_table_size) { + max_table_size = GPR_MIN(max_table_size, c->max_usable_size); + if (max_table_size == c->max_table_size) { + return; + } + while (c->table_size > 0 && c->table_size > max_table_size) { + evict_entry(c); + } + c->max_table_size = max_table_size; + c->max_table_elems = elems_for_bytes(max_table_size); + if (c->max_table_elems > c->cap_table_elems) { + rebuild_elems(c, GPR_MAX(c->max_table_elems, 2 * c->cap_table_elems)); + } else if (c->max_table_elems < c->cap_table_elems / 3) { + gpr_uint32 new_cap = GPR_MAX(c->max_table_elems, 16); + if (new_cap != c->cap_table_elems) { + rebuild_elems(c, new_cap); + } + } + c->advertise_table_size_change = 1; + gpr_log(GPR_DEBUG, "set max table size from encoder to %d", max_table_size); } void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor *c, @@ -483,6 +560,9 @@ void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor *c, slot. THIS MAY NOT BE THE SAME ELEMENT (if a decoder table slot got updated). After this loop, we'll do a batch unref of elements. */ begin_frame(&st); + if (c->advertise_table_size_change != 0) { + emit_advertise_table_size_change(c, &st); + } grpc_metadata_batch_assert_ok(metadata); for (l = metadata->list.head; l; l = l->next) { hpack_enc(c, l->md, &st); diff --git a/src/core/transport/chttp2/hpack_encoder.h b/src/core/transport/chttp2/hpack_encoder.h index 59b122dfda..ce83d101f2 100644 --- a/src/core/transport/chttp2/hpack_encoder.h +++ b/src/core/transport/chttp2/hpack_encoder.h @@ -43,14 +43,26 @@ #define GRPC_CHTTP2_HPACKC_NUM_FILTERS 256 #define GRPC_CHTTP2_HPACKC_NUM_VALUES 256 -#define GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS (4096 / 32) +/* initial table size, per spec */ +#define GRPC_CHTTP2_HPACKC_INITIAL_TABLE_SIZE 4096 +/* maximum table size we'll actually use */ +#define GRPC_CHTTP2_HPACKC_MAX_TABLE_SIZE (1024 * 1024) typedef struct { gpr_uint32 filter_elems_sum; + gpr_uint32 max_table_size; + gpr_uint32 max_table_elems; + gpr_uint32 cap_table_elems; + /** if non-zero, advertise to the decoder that we'll start using a table + of this size */ + gpr_uint8 advertise_table_size_change; + /** maximum number of bytes we'll use for the decode table (to guard against + peers ooming us by setting decode table size high) */ + gpr_uint32 max_usable_size; /* one before the lowest usable table index */ gpr_uint32 tail_remote_index; - gpr_uint16 table_size; - gpr_uint16 table_elems; + gpr_uint32 table_size; + gpr_uint32 table_elems; /* filter tables for elems: this tables provides an approximate popularity count for particular hashes, and are used to determine whether @@ -71,12 +83,16 @@ typedef struct { gpr_uint32 indices_keys[GRPC_CHTTP2_HPACKC_NUM_VALUES]; gpr_uint32 indices_elems[GRPC_CHTTP2_HPACKC_NUM_VALUES]; - gpr_uint16 table_elem_size[GRPC_CHTTP2_HPACKC_MAX_TABLE_ELEMS]; + gpr_uint16 *table_elem_size; } grpc_chttp2_hpack_compressor; void grpc_chttp2_hpack_compressor_init(grpc_chttp2_hpack_compressor *c, grpc_mdctx *mdctx); void grpc_chttp2_hpack_compressor_destroy(grpc_chttp2_hpack_compressor *c); +void grpc_chttp2_hpack_compressor_set_max_table_size( + grpc_chttp2_hpack_compressor *c, gpr_uint32 max_table_size); +void grpc_chttp2_hpack_compressor_set_max_usable_size( + grpc_chttp2_hpack_compressor *c, gpr_uint32 max_table_size); void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor *c, gpr_uint32 id, grpc_metadata_batch *metadata, int is_eof, diff --git a/src/core/transport/chttp2/hpack_parser.c b/src/core/transport/chttp2/hpack_parser.c index 6eebfc3ce4..57a3a20b1d 100644 --- a/src/core/transport/chttp2/hpack_parser.c +++ b/src/core/transport/chttp2/hpack_parser.c @@ -74,6 +74,8 @@ static int parse_begin(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end); static int parse_error(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end); +static int parse_illegal_op(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, + const gpr_uint8 *end); static int parse_string_prefix(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end); @@ -156,7 +158,7 @@ static const grpc_chttp2_hpack_parser_state first_byte_action[] = { parse_lithdr_incidx_x, parse_lithdr_incidx_v, parse_lithdr_notidx, parse_lithdr_notidx_x, parse_lithdr_notidx_v, parse_lithdr_nvridx, parse_lithdr_nvridx_x, parse_lithdr_nvridx_v, parse_max_tbl_size, - parse_max_tbl_size_x, parse_error}; + parse_max_tbl_size_x, parse_illegal_op}; /* indexes the first byte to a parse state function - generated by gen_hpack_tables.c */ @@ -169,7 +171,7 @@ static const gpr_uint8 first_byte_lut[256] = { LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX_X, - ILLEGAL, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, + MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, MAX_TBL_SIZE, @@ -622,13 +624,15 @@ static const gpr_uint8 inverse_base64[256] = { }; /* emission helpers */ -static void on_hdr(grpc_chttp2_hpack_parser *p, grpc_mdelem *md, - int add_to_table) { +static int on_hdr(grpc_chttp2_hpack_parser *p, grpc_mdelem *md, + int add_to_table) { if (add_to_table) { - GRPC_MDELEM_REF(md); - grpc_chttp2_hptbl_add(&p->table, md); + if (!grpc_chttp2_hptbl_add(&p->table, md)) { + return 0; + } } p->on_header(p->on_header_user_data, md); + return 1; } static grpc_mdstr *take_string(grpc_chttp2_hpack_parser *p, @@ -714,9 +718,12 @@ static int parse_stream_dep0(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, static int finish_indexed_field(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index); + if (md == NULL) { + gpr_log(GPR_ERROR, "Invalid HPACK index received: %d", p->index); + return 0; + } GRPC_MDELEM_REF(md); - on_hdr(p, md, 0); - return parse_begin(p, cur, end); + return on_hdr(p, md, 0) && parse_begin(p, cur, end); } /* parse an indexed field with index < 127 */ @@ -742,21 +749,21 @@ static int parse_indexed_field_x(grpc_chttp2_hpack_parser *p, static int finish_lithdr_incidx(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index); - on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx, - GRPC_MDSTR_REF(md->key), - take_string(p, &p->value)), - 1); - return parse_begin(p, cur, end); + return on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx, + GRPC_MDSTR_REF(md->key), + take_string(p, &p->value)), + 1) && + parse_begin(p, cur, end); } /* finish a literal header with incremental indexing with no index */ static int finish_lithdr_incidx_v(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { - on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx, - take_string(p, &p->key), - take_string(p, &p->value)), - 1); - return parse_begin(p, cur, end); + return on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx, + take_string(p, &p->key), + take_string(p, &p->value)), + 1) && + parse_begin(p, cur, end); } /* parse a literal header with incremental indexing; index < 63 */ @@ -795,21 +802,21 @@ static int parse_lithdr_incidx_v(grpc_chttp2_hpack_parser *p, static int finish_lithdr_notidx(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index); - on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx, - GRPC_MDSTR_REF(md->key), - take_string(p, &p->value)), - 0); - return parse_begin(p, cur, end); + return on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx, + GRPC_MDSTR_REF(md->key), + take_string(p, &p->value)), + 0) && + parse_begin(p, cur, end); } /* finish a literal header without incremental indexing with index = 0 */ static int finish_lithdr_notidx_v(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { - on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx, - take_string(p, &p->key), - take_string(p, &p->value)), - 0); - return parse_begin(p, cur, end); + return on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx, + take_string(p, &p->key), + take_string(p, &p->value)), + 0) && + parse_begin(p, cur, end); } /* parse a literal header without incremental indexing; index < 15 */ @@ -848,21 +855,21 @@ static int parse_lithdr_notidx_v(grpc_chttp2_hpack_parser *p, static int finish_lithdr_nvridx(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index); - on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx, - GRPC_MDSTR_REF(md->key), - take_string(p, &p->value)), - 0); - return parse_begin(p, cur, end); + return on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx, + GRPC_MDSTR_REF(md->key), + take_string(p, &p->value)), + 0) && + parse_begin(p, cur, end); } /* finish a literal header that is never indexed with an extra value */ static int finish_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { - on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx, - take_string(p, &p->key), - take_string(p, &p->value)), - 0); - return parse_begin(p, cur, end); + return on_hdr(p, grpc_mdelem_from_metadata_strings(p->table.mdctx, + take_string(p, &p->key), + take_string(p, &p->value)), + 0) && + parse_begin(p, cur, end); } /* parse a literal header that is never indexed; index < 15 */ @@ -901,14 +908,14 @@ static int parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p, static int finish_max_tbl_size(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { gpr_log(GPR_INFO, "MAX TABLE SIZE: %d", p->index); - abort(); /* not implemented */ - return parse_begin(p, cur, end); + return grpc_chttp2_hptbl_set_current_table_size(&p->table, p->index) && + parse_begin(p, cur, end); } /* parse a max table size change, max size < 15 */ static int parse_max_tbl_size(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, const gpr_uint8 *end) { - p->index = (*cur) & 0xf; + p->index = (*cur) & 0x1f; return finish_max_tbl_size(p, cur + 1, end); } @@ -918,7 +925,7 @@ static int parse_max_tbl_size_x(grpc_chttp2_hpack_parser *p, static const grpc_chttp2_hpack_parser_state and_then[] = { finish_max_tbl_size}; p->next_state = and_then; - p->index = 0xf; + p->index = 0x1f; p->parsing.value = &p->index; return parse_value0(p, cur + 1, end); } @@ -930,6 +937,13 @@ static int parse_error(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, return 0; } +static int parse_illegal_op(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, + const gpr_uint8 *end) { + GPR_ASSERT(cur != end); + gpr_log(GPR_DEBUG, "Illegal hpack op code %d", *cur); + return parse_error(p, cur, end); +} + /* parse the 1st byte of a varint into p->parsing.value no overflow is possible */ static int parse_value0(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, diff --git a/src/core/transport/chttp2/hpack_table.c b/src/core/transport/chttp2/hpack_table.c index c442c2c341..f2362b056c 100644 --- a/src/core/transport/chttp2/hpack_table.c +++ b/src/core/transport/chttp2/hpack_table.c @@ -36,7 +36,9 @@ #include <assert.h> #include <string.h> +#include <grpc/support/alloc.h> #include <grpc/support/log.h> + #include "src/core/support/murmur_hash.h" static struct { @@ -169,12 +171,22 @@ static struct { {"www-authenticate", ""}, }; +static gpr_uint32 entries_for_bytes(gpr_uint32 bytes) { + return (bytes + GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD - 1) / + GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD; +} + void grpc_chttp2_hptbl_init(grpc_chttp2_hptbl *tbl, grpc_mdctx *mdctx) { size_t i; memset(tbl, 0, sizeof(*tbl)); tbl->mdctx = mdctx; - tbl->max_bytes = GRPC_CHTTP2_INITIAL_HPACK_TABLE_SIZE; + tbl->current_table_bytes = tbl->max_bytes = + GRPC_CHTTP2_INITIAL_HPACK_TABLE_SIZE; + tbl->max_entries = tbl->cap_entries = + entries_for_bytes(tbl->current_table_bytes); + tbl->ents = gpr_malloc(sizeof(*tbl->ents) * tbl->cap_entries); + memset(tbl->ents, 0, sizeof(*tbl->ents) * tbl->cap_entries); for (i = 1; i <= GRPC_CHTTP2_LAST_STATIC_ENTRY; i++) { tbl->static_ents[i - 1] = grpc_mdelem_from_strings( mdctx, static_table[i].key, static_table[i].value); @@ -187,9 +199,9 @@ void grpc_chttp2_hptbl_destroy(grpc_chttp2_hptbl *tbl) { GRPC_MDELEM_UNREF(tbl->static_ents[i]); } for (i = 0; i < tbl->num_ents; i++) { - GRPC_MDELEM_UNREF( - tbl->ents[(tbl->first_ent + i) % GRPC_CHTTP2_MAX_TABLE_COUNT]); + GRPC_MDELEM_UNREF(tbl->ents[(tbl->first_ent + i) % tbl->cap_entries]); } + gpr_free(tbl->ents); } grpc_mdelem *grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl, @@ -201,8 +213,8 @@ grpc_mdelem *grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl, /* Otherwise, find the value in the list of valid entries */ tbl_index -= (GRPC_CHTTP2_LAST_STATIC_ENTRY + 1); if (tbl_index < tbl->num_ents) { - gpr_uint32 offset = (tbl->num_ents - 1u - tbl_index + tbl->first_ent) % - GRPC_CHTTP2_MAX_TABLE_COUNT; + gpr_uint32 offset = + (tbl->num_ents - 1u - tbl_index + tbl->first_ent) % tbl->cap_entries; return tbl->ents[offset]; } /* Invalid entry: return error */ @@ -216,21 +228,81 @@ static void evict1(grpc_chttp2_hptbl *tbl) { GPR_SLICE_LENGTH(first_ent->value->slice) + GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD; GPR_ASSERT(elem_bytes <= tbl->mem_used); - tbl->mem_used = (gpr_uint16)(tbl->mem_used - elem_bytes); - tbl->first_ent = - (gpr_uint16)((tbl->first_ent + 1) % GRPC_CHTTP2_MAX_TABLE_COUNT); + tbl->mem_used -= (gpr_uint32)elem_bytes; + tbl->first_ent = ((tbl->first_ent + 1) % tbl->cap_entries); tbl->num_ents--; GRPC_MDELEM_UNREF(first_ent); } -void grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) { +static void rebuild_ents(grpc_chttp2_hptbl *tbl, gpr_uint32 new_cap) { + grpc_mdelem **ents = gpr_malloc(sizeof(*ents) * new_cap); + gpr_uint32 i; + + for (i = 0; i < tbl->num_ents; i++) { + ents[i] = tbl->ents[(tbl->first_ent + i) % tbl->cap_entries]; + } + gpr_free(tbl->ents); + tbl->ents = ents; + tbl->cap_entries = new_cap; + tbl->first_ent = 0; +} + +void grpc_chttp2_hptbl_set_max_bytes(grpc_chttp2_hptbl *tbl, + gpr_uint32 max_bytes) { + if (tbl->max_bytes == max_bytes) { + return; + } + gpr_log(GPR_DEBUG, "Update hpack parser max size to %d", max_bytes); + while (tbl->mem_used > max_bytes) { + evict1(tbl); + } + tbl->max_bytes = max_bytes; +} + +int grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl, + gpr_uint32 bytes) { + if (tbl->current_table_bytes == bytes) { + return 1; + } + if (bytes > tbl->max_bytes) { + gpr_log(GPR_ERROR, + "Attempt to make hpack table %d bytes when max is %d bytes", bytes, + tbl->max_bytes); + return 0; + } + gpr_log(GPR_DEBUG, "Update hpack parser table size to %d", bytes); + while (tbl->mem_used > bytes) { + evict1(tbl); + } + tbl->current_table_bytes = bytes; + tbl->max_entries = entries_for_bytes(bytes); + if (tbl->max_entries > tbl->cap_entries) { + rebuild_ents(tbl, GPR_MAX(tbl->max_entries, 2 * tbl->cap_entries)); + } else if (tbl->max_entries < tbl->cap_entries / 3) { + gpr_uint32 new_cap = GPR_MAX(tbl->max_entries, 16u); + if (new_cap != tbl->cap_entries) { + rebuild_ents(tbl, new_cap); + } + } + return 1; +} + +int grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) { /* determine how many bytes of buffer this entry represents */ size_t elem_bytes = GPR_SLICE_LENGTH(md->key->slice) + GPR_SLICE_LENGTH(md->value->slice) + GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD; + if (tbl->current_table_bytes > tbl->max_bytes) { + gpr_log(GPR_ERROR, + "HPACK max table size reduced to %d but not reflected by hpack " + "stream (still at %d)", + tbl->max_bytes, tbl->current_table_bytes); + return 0; + } + /* we can't add elements bigger than the max table size */ - if (elem_bytes > tbl->max_bytes) { + if (elem_bytes > tbl->current_table_bytes) { /* HPACK draft 10 section 4.4 states: * If the size of the new entry is less than or equal to the maximum * size, that entry is added to the table. It is not an error to @@ -243,44 +315,43 @@ void grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) { while (tbl->num_ents) { evict1(tbl); } - return; + return 1; } /* evict entries to ensure no overflow */ - while (elem_bytes > (size_t)tbl->max_bytes - tbl->mem_used) { + while (elem_bytes > (size_t)tbl->current_table_bytes - tbl->mem_used) { evict1(tbl); } /* copy the finalized entry in */ - tbl->ents[tbl->last_ent] = md; + tbl->ents[(tbl->first_ent + tbl->num_ents) % tbl->cap_entries] = + GRPC_MDELEM_REF(md); /* update accounting values */ - tbl->last_ent = - (gpr_uint16)((tbl->last_ent + 1) % GRPC_CHTTP2_MAX_TABLE_COUNT); tbl->num_ents++; - tbl->mem_used = (gpr_uint16)(tbl->mem_used + elem_bytes); + tbl->mem_used += (gpr_uint32)elem_bytes; + return 1; } grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find( const grpc_chttp2_hptbl *tbl, grpc_mdelem *md) { grpc_chttp2_hptbl_find_result r = {0, 0}; - gpr_uint16 i; + gpr_uint32 i; /* See if the string is in the static table */ for (i = 0; i < GRPC_CHTTP2_LAST_STATIC_ENTRY; i++) { grpc_mdelem *ent = tbl->static_ents[i]; if (md->key != ent->key) continue; - r.index = (gpr_uint16)(i + 1); + r.index = i + 1u; r.has_value = md->value == ent->value; if (r.has_value) return r; } /* Scan the dynamic table */ for (i = 0; i < tbl->num_ents; i++) { - gpr_uint16 idx = - (gpr_uint16)(tbl->num_ents - i + GRPC_CHTTP2_LAST_STATIC_ENTRY); - grpc_mdelem *ent = - tbl->ents[(tbl->first_ent + i) % GRPC_CHTTP2_MAX_TABLE_COUNT]; + gpr_uint32 idx = + (gpr_uint32)(tbl->num_ents - i + GRPC_CHTTP2_LAST_STATIC_ENTRY); + grpc_mdelem *ent = tbl->ents[(tbl->first_ent + i) % tbl->cap_entries]; if (md->key != ent->key) continue; r.index = idx; r.has_value = md->value == ent->value; diff --git a/src/core/transport/chttp2/hpack_table.h b/src/core/transport/chttp2/hpack_table.h index 4f882e2e03..e03b8c19b3 100644 --- a/src/core/transport/chttp2/hpack_table.h +++ b/src/core/transport/chttp2/hpack_table.h @@ -49,47 +49,59 @@ #define GRPC_CHTTP2_MAX_HPACK_TABLE_SIZE GRPC_CHTTP2_INITIAL_HPACK_TABLE_SIZE /* Per entry overhead bytes as per the spec */ #define GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD 32 +#if 0 /* Maximum number of entries we could possibly fit in the table, given defined overheads */ #define GRPC_CHTTP2_MAX_TABLE_COUNT \ ((GRPC_CHTTP2_MAX_HPACK_TABLE_SIZE + GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD - 1) / \ GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD) +#endif /* hpack decoder table */ typedef struct { grpc_mdctx *mdctx; /* the first used entry in ents */ - gpr_uint16 first_ent; - /* the last used entry in ents */ - gpr_uint16 last_ent; + gpr_uint32 first_ent; /* how many entries are in the table */ - gpr_uint16 num_ents; + gpr_uint32 num_ents; /* the amount of memory used by the table, according to the hpack algorithm */ - gpr_uint16 mem_used; + gpr_uint32 mem_used; /* the max memory allowed to be used by the table, according to the hpack algorithm */ - gpr_uint16 max_bytes; + gpr_uint32 max_bytes; + /* the currently agreed size of the table, according to the hpack algorithm */ + gpr_uint32 current_table_bytes; + /* Maximum number of entries we could possibly fit in the table, given defined + overheads */ + gpr_uint32 max_entries; + /* Number of entries allocated in ents */ + gpr_uint32 cap_entries; /* a circular buffer of headers - this is stored in the opposite order to what hpack specifies, in order to simplify table management a little... meaning lookups need to SUBTRACT from the end position */ - grpc_mdelem *ents[GRPC_CHTTP2_MAX_TABLE_COUNT]; + grpc_mdelem **ents; grpc_mdelem *static_ents[GRPC_CHTTP2_LAST_STATIC_ENTRY]; } grpc_chttp2_hptbl; /* initialize a hpack table */ void grpc_chttp2_hptbl_init(grpc_chttp2_hptbl *tbl, grpc_mdctx *mdctx); void grpc_chttp2_hptbl_destroy(grpc_chttp2_hptbl *tbl); +void grpc_chttp2_hptbl_set_max_bytes(grpc_chttp2_hptbl *tbl, + gpr_uint32 max_bytes); +int grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl, + gpr_uint32 bytes); /* lookup a table entry based on its hpack index */ grpc_mdelem *grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl, gpr_uint32 index); /* add a table entry to the index */ -void grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md); +int grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, + grpc_mdelem *md) GRPC_MUST_USE_RESULT; /* Find a key/value pair in the table... returns the index in the table of the most similar entry, or 0 if the value was not found */ typedef struct { - gpr_uint16 index; - gpr_uint8 has_value; + gpr_uint32 index; + int has_value; } grpc_chttp2_hptbl_find_result; grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find( const grpc_chttp2_hptbl *tbl, grpc_mdelem *md); diff --git a/src/core/transport/chttp2/internal.h b/src/core/transport/chttp2/internal.h index 2d0cb4abdb..216439549c 100644 --- a/src/core/transport/chttp2/internal.h +++ b/src/core/transport/chttp2/internal.h @@ -227,6 +227,9 @@ struct grpc_chttp2_transport_parsing { /** was a goaway frame received? */ gpr_uint8 goaway_received; + /** the last sent max_table_size setting */ + gpr_uint32 last_sent_max_table_size; + /** initial window change */ gpr_int64 initial_window_update; @@ -483,7 +486,8 @@ struct grpc_chttp2_stream { /** Someone is unlocking the transport mutex: check to see if writes are required, and schedule them if so */ int grpc_chttp2_unlocking_check_writes(grpc_chttp2_transport_global *global, - grpc_chttp2_transport_writing *writing); + grpc_chttp2_transport_writing *writing, + int is_parsing); void grpc_chttp2_perform_writes( grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing, grpc_endpoint *endpoint); diff --git a/src/core/transport/chttp2/parsing.c b/src/core/transport/chttp2/parsing.c index 8cef8fbb77..1e06532c03 100644 --- a/src/core/transport/chttp2/parsing.c +++ b/src/core/transport/chttp2/parsing.c @@ -78,6 +78,9 @@ void grpc_chttp2_prepare_to_read( GPR_TIMER_BEGIN("grpc_chttp2_prepare_to_read", 0); transport_parsing->next_stream_id = transport_global->next_stream_id; + transport_parsing->last_sent_max_table_size = + transport_global->settings[GRPC_SENT_SETTINGS] + [GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE]; /* update the parsing view of incoming window */ while (grpc_chttp2_list_pop_unannounced_incoming_window_available( @@ -127,6 +130,7 @@ void grpc_chttp2_publish_reads( transport_global->settings[GRPC_SENT_SETTINGS], GRPC_CHTTP2_NUM_SETTINGS * sizeof(gpr_uint32)); transport_parsing->settings_ack_received = 0; + transport_global->sent_local_settings = 0; } /* move goaway to the global state if we received one (it will be @@ -819,6 +823,9 @@ static int init_settings_frame_parser( } if (transport_parsing->incoming_frame_flags & GRPC_CHTTP2_FLAG_ACK) { transport_parsing->settings_ack_received = 1; + grpc_chttp2_hptbl_set_max_bytes( + &transport_parsing->hpack_parser.table, + transport_parsing->last_sent_max_table_size); } transport_parsing->parser = grpc_chttp2_settings_parser_parse; transport_parsing->parser_data = &transport_parsing->simple.settings; diff --git a/src/core/transport/chttp2/writing.c b/src/core/transport/chttp2/writing.c index 7fe5649e5e..805d05222d 100644 --- a/src/core/transport/chttp2/writing.c +++ b/src/core/transport/chttp2/writing.c @@ -45,7 +45,7 @@ static void finalize_outbuf(grpc_exec_ctx *exec_ctx, int grpc_chttp2_unlocking_check_writes( grpc_chttp2_transport_global *transport_global, - grpc_chttp2_transport_writing *transport_writing) { + grpc_chttp2_transport_writing *transport_writing, int is_parsing) { grpc_chttp2_stream_global *stream_global; grpc_chttp2_stream_writing *stream_writing; @@ -55,8 +55,13 @@ int grpc_chttp2_unlocking_check_writes( gpr_slice_buffer_swap(&transport_global->qbuf, &transport_writing->outbuf); GPR_ASSERT(transport_global->qbuf.count == 0); + grpc_chttp2_hpack_compressor_set_max_table_size( + &transport_writing->hpack_compressor, + transport_global->settings[GRPC_PEER_SETTINGS] + [GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE]); + if (transport_global->dirtied_local_settings && - !transport_global->sent_local_settings) { + !transport_global->sent_local_settings && !is_parsing) { gpr_slice_buffer_add( &transport_writing->outbuf, grpc_chttp2_settings_create( diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c index f62294c7c5..fdd835def9 100644 --- a/src/core/transport/chttp2_transport.c +++ b/src/core/transport/chttp2_transport.c @@ -338,6 +338,31 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, t->global.next_stream_id = (gpr_uint32)channel_args->args[i].value.integer; } + } else if (0 == strcmp(channel_args->args[i].key, + GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER)) { + if (channel_args->args[i].type != GRPC_ARG_INTEGER) { + gpr_log(GPR_ERROR, "%s: must be an integer", + GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER); + } else if (channel_args->args[i].value.integer < 0) { + gpr_log(GPR_DEBUG, "%s: must be non-negative", + GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER); + } else { + push_setting(t, GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE, + (gpr_uint32)channel_args->args[i].value.integer); + } + } else if (0 == strcmp(channel_args->args[i].key, + GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER)) { + if (channel_args->args[i].type != GRPC_ARG_INTEGER) { + gpr_log(GPR_ERROR, "%s: must be an integer", + GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER); + } else if (channel_args->args[i].value.integer < 0) { + gpr_log(GPR_DEBUG, "%s: must be non-negative", + GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER); + } else { + grpc_chttp2_hpack_compressor_set_max_usable_size( + &t->writing.hpack_compressor, + (gpr_uint32)channel_args->args[i].value.integer); + } } } } @@ -563,7 +588,8 @@ static void lock(grpc_chttp2_transport *t) { gpr_mu_lock(&t->mu); } static void unlock(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) { GPR_TIMER_BEGIN("unlock", 0); if (!t->writing_active && !t->closed && - grpc_chttp2_unlocking_check_writes(&t->global, &t->writing)) { + grpc_chttp2_unlocking_check_writes(&t->global, &t->writing, + t->parsing_active)) { t->writing_active = 1; REF_TRANSPORT(t, "writing"); grpc_exec_ctx_enqueue(exec_ctx, &t->writing_action, 1); @@ -735,6 +761,8 @@ static int contains_non_ok_status( return 0; } +static void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, int success) {} + static void perform_stream_op_locked( grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global *stream_global, grpc_transport_stream_op *op) { @@ -743,6 +771,9 @@ static void perform_stream_op_locked( GPR_TIMER_BEGIN("perform_stream_op_locked", 0); on_complete = op->on_complete; + if (on_complete == NULL) { + on_complete = grpc_closure_create(do_nothing, NULL); + } /* use final_data as a barrier until enqueue time; the inital counter is dropped at the end of this function */ on_complete->final_data = 2; @@ -806,7 +837,7 @@ static void perform_stream_op_locked( } if (stream_global->write_closed) { grpc_chttp2_complete_closure_step( - exec_ctx, &stream_global->send_trailing_metadata_finished, + exec_ctx, &stream_global->send_trailing_metadata_finished, grpc_metadata_batch_is_empty(op->send_trailing_metadata)); } else if (stream_global->id != 0) { /* TODO(ctiller): check if there's flow control for any outstanding @@ -1033,7 +1064,8 @@ void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx, to the upper layers - drop what we've got, and then publish what we want - which is safe because we haven't told anyone about the metadata yet */ - if (!stream_global->published_trailing_metadata || stream_global->recv_trailing_metadata_finished != NULL) { + if (!stream_global->published_trailing_metadata || + stream_global->recv_trailing_metadata_finished != NULL) { grpc_mdctx *mdctx = TRANSPORT_FROM_GLOBAL(transport_global)->metadata_context; char status_string[GPR_LTOA_MIN_BUFSIZE]; diff --git a/src/core/tsi/test_creds/server1.pem b/src/core/tsi/test_creds/server1.pem index 8e582e571f..f3d43fcc5b 100644 --- a/src/core/tsi/test_creds/server1.pem +++ b/src/core/tsi/test_creds/server1.pem @@ -1,16 +1,16 @@ -----BEGIN CERTIFICATE----- -MIICmzCCAgSgAwIBAgIBAzANBgkqhkiG9w0BAQUFADBWMQswCQYDVQQGEwJBVTET -MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ -dHkgTHRkMQ8wDQYDVQQDDAZ0ZXN0Y2EwHhcNMTQwNzIyMDYwMDU3WhcNMjQwNzE5 -MDYwMDU3WjBkMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV -BAcTB0NoaWNhZ28xFDASBgNVBAoTC0dvb2dsZSBJbmMuMRowGAYDVQQDFBEqLnRl -c3QuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4cMVJygs -JUmlgMMzgdi0h1XoCR7+ww1pop04OMMyy7H/i0PJ2W6Y35+b4CM8QrkYeEafUGDO -RYX6yV/cHGGsD/x02ye6ey1UDtkGAD/mpDEx8YCrjAc1Vfvt8Fk6Cn1WVIxV/J30 -3xjBsFgByQ55RBp1OLZfVLo6AleBDSbcxaECAwEAAaNrMGkwCQYDVR0TBAIwADAL -BgNVHQ8EBAMCBeAwTwYDVR0RBEgwRoIQKi50ZXN0Lmdvb2dsZS5mcoIYd2F0ZXJ6 -b29pLnRlc3QuZ29vZ2xlLmJlghIqLnRlc3QueW91dHViZS5jb22HBMCoAQMwDQYJ -KoZIhvcNAQEFBQADgYEAM2Ii0LgTGbJ1j4oqX9bxVcxm+/R5Yf8oi0aZqTJlnLYS -wXcBykxTx181s7WyfJ49WwrYXo78zTDAnf1ma0fPq3e4mpspvyndLh1a+OarHa1e -aT0DIIYk7qeEa1YcVljx2KyLd0r1BBAfrwyGaEPVeJQVYWaOJRU2we/KD4ojf9s= +MIICnDCCAgWgAwIBAgIBBzANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJBVTET +MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ +dHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2EwHhcNMTUxMTA0MDIyMDI0WhcNMjUxMTAx +MDIyMDI0WjBlMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV +BAcTB0NoaWNhZ28xFTATBgNVBAoTDEV4YW1wbGUsIENvLjEaMBgGA1UEAxQRKi50 +ZXN0Lmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOHDFSco +LCVJpYDDM4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1Bg +zkWF+slf3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd +9N8YwbBYAckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAGjazBpMAkGA1UdEwQCMAAw +CwYDVR0PBAQDAgXgME8GA1UdEQRIMEaCECoudGVzdC5nb29nbGUuZnKCGHdhdGVy +em9vaS50ZXN0Lmdvb2dsZS5iZYISKi50ZXN0LnlvdXR1YmUuY29thwTAqAEDMA0G +CSqGSIb3DQEBCwUAA4GBAJFXVifQNub1LUP4JlnX5lXNlo8FxZ2a12AFQs+bzoJ6 +hM044EDjqyxUqSbVePK0ni3w1fHQB5rY9yYC5f8G7aqqTY1QOhoUk8ZTSTRpnkTh +y4jjdvTZeLDVBlueZUTDRmy2feY5aZIU18vFDK08dTG0A87pppuv1LNIR3loveU8 -----END CERTIFICATE----- diff --git a/src/cpp/client/client_context.cc b/src/cpp/client/client_context.cc index 574656a7e9..9bb358b233 100644 --- a/src/cpp/client/client_context.cc +++ b/src/cpp/client/client_context.cc @@ -48,6 +48,7 @@ namespace grpc { ClientContext::ClientContext() : initial_metadata_received_(false), call_(nullptr), + call_canceled_(false), deadline_(gpr_inf_future(GPR_CLOCK_REALTIME)), propagate_from_call_(nullptr) {} @@ -72,6 +73,7 @@ void ClientContext::AddMetadata(const grpc::string& meta_key, void ClientContext::set_call(grpc_call* call, const std::shared_ptr<Channel>& channel) { + grpc::unique_lock<grpc::mutex> lock(mu_); GPR_ASSERT(call_ == nullptr); call_ = call; channel_ = channel; @@ -79,6 +81,9 @@ void ClientContext::set_call(grpc_call* call, grpc_call_cancel_with_status(call, GRPC_STATUS_CANCELLED, "Failed to set credentials to rpc.", nullptr); } + if (call_canceled_) { + grpc_call_cancel(call_, nullptr); + } } void ClientContext::set_compression_algorithm( @@ -101,8 +106,11 @@ std::shared_ptr<const AuthContext> ClientContext::auth_context() const { } void ClientContext::TryCancel() { + grpc::unique_lock<grpc::mutex> lock(mu_); if (call_) { grpc_call_cancel(call_, nullptr); + } else { + call_canceled_ = true; } } diff --git a/src/cpp/client/create_channel.cc b/src/cpp/client/create_channel.cc index d2b2d30126..3bbca807d3 100644 --- a/src/cpp/client/create_channel.cc +++ b/src/cpp/client/create_channel.cc @@ -44,12 +44,14 @@ namespace grpc { class ChannelArguments; std::shared_ptr<Channel> CreateChannel( - const grpc::string& target, const std::shared_ptr<Credentials>& creds) { + const grpc::string& target, + const std::shared_ptr<ChannelCredentials>& creds) { return CreateCustomChannel(target, creds, ChannelArguments()); } std::shared_ptr<Channel> CreateCustomChannel( - const grpc::string& target, const std::shared_ptr<Credentials>& creds, + const grpc::string& target, + const std::shared_ptr<ChannelCredentials>& creds, const ChannelArguments& args) { GrpcLibrary init_lib; // We need to call init in case of a bad creds. ChannelArguments cp_args = args; diff --git a/src/cpp/client/credentials.cc b/src/cpp/client/credentials.cc index 7a8149e9c7..0c08db11a9 100644 --- a/src/cpp/client/credentials.cc +++ b/src/cpp/client/credentials.cc @@ -35,6 +35,8 @@ namespace grpc { -Credentials::~Credentials() {} +ChannelCredentials::~ChannelCredentials() {} + +CallCredentials::~CallCredentials() {} } // namespace grpc diff --git a/src/cpp/client/insecure_credentials.cc b/src/cpp/client/insecure_credentials.cc index c476f3ce95..1293203b93 100644 --- a/src/cpp/client/insecure_credentials.cc +++ b/src/cpp/client/insecure_credentials.cc @@ -43,7 +43,7 @@ namespace grpc { namespace { -class InsecureCredentialsImpl GRPC_FINAL : public Credentials { +class InsecureChannelCredentialsImpl GRPC_FINAL : public ChannelCredentials { public: std::shared_ptr<grpc::Channel> CreateChannel( const string& target, const grpc::ChannelArguments& args) GRPC_OVERRIDE { @@ -54,15 +54,15 @@ class InsecureCredentialsImpl GRPC_FINAL : public Credentials { grpc_insecure_channel_create(target.c_str(), &channel_args, nullptr)); } - // InsecureCredentials should not be applied to a call. - bool ApplyToCall(grpc_call* call) GRPC_OVERRIDE { return false; } - - SecureCredentials* AsSecureCredentials() GRPC_OVERRIDE { return nullptr; } + SecureChannelCredentials* AsSecureCredentials() GRPC_OVERRIDE { + return nullptr; + } }; } // namespace -std::shared_ptr<Credentials> InsecureCredentials() { - return std::shared_ptr<Credentials>(new InsecureCredentialsImpl()); +std::shared_ptr<ChannelCredentials> InsecureChannelCredentials() { + return std::shared_ptr<ChannelCredentials>( + new InsecureChannelCredentialsImpl()); } } // namespace grpc diff --git a/src/cpp/client/secure_credentials.cc b/src/cpp/client/secure_credentials.cc index 8299ebeb8a..a1b9a3018e 100644 --- a/src/cpp/client/secure_credentials.cc +++ b/src/cpp/client/secure_credentials.cc @@ -40,7 +40,7 @@ namespace grpc { -std::shared_ptr<grpc::Channel> SecureCredentials::CreateChannel( +std::shared_ptr<grpc::Channel> SecureChannelCredentials::CreateChannel( const string& target, const grpc::ChannelArguments& args) { grpc_channel_args channel_args; args.SetChannelArgs(&channel_args); @@ -50,96 +50,104 @@ std::shared_ptr<grpc::Channel> SecureCredentials::CreateChannel( nullptr)); } -bool SecureCredentials::ApplyToCall(grpc_call* call) { +bool SecureCallCredentials::ApplyToCall(grpc_call* call) { return grpc_call_set_credentials(call, c_creds_) == GRPC_CALL_OK; } namespace { -std::shared_ptr<Credentials> WrapCredentials(grpc_credentials* creds) { - return creds == nullptr - ? nullptr - : std::shared_ptr<Credentials>(new SecureCredentials(creds)); +std::shared_ptr<ChannelCredentials> WrapChannelCredentials( + grpc_channel_credentials* creds) { + return creds == nullptr ? nullptr : std::shared_ptr<ChannelCredentials>( + new SecureChannelCredentials(creds)); +} + +std::shared_ptr<CallCredentials> WrapCallCredentials( + grpc_call_credentials* creds) { + return creds == nullptr ? nullptr : std::shared_ptr<CallCredentials>( + new SecureCallCredentials(creds)); } } // namespace -std::shared_ptr<Credentials> GoogleDefaultCredentials() { +std::shared_ptr<ChannelCredentials> GoogleDefaultCredentials() { GrpcLibrary init; // To call grpc_init(). - return WrapCredentials(grpc_google_default_credentials_create()); + return WrapChannelCredentials(grpc_google_default_credentials_create()); } // Builds SSL Credentials given SSL specific options -std::shared_ptr<Credentials> SslCredentials( +std::shared_ptr<ChannelCredentials> SslCredentials( const SslCredentialsOptions& options) { GrpcLibrary init; // To call grpc_init(). grpc_ssl_pem_key_cert_pair pem_key_cert_pair = { options.pem_private_key.c_str(), options.pem_cert_chain.c_str()}; - grpc_credentials* c_creds = grpc_ssl_credentials_create( + grpc_channel_credentials* c_creds = grpc_ssl_credentials_create( options.pem_root_certs.empty() ? nullptr : options.pem_root_certs.c_str(), options.pem_private_key.empty() ? nullptr : &pem_key_cert_pair, nullptr); - return WrapCredentials(c_creds); + return WrapChannelCredentials(c_creds); } // Builds credentials for use when running in GCE -std::shared_ptr<Credentials> GoogleComputeEngineCredentials() { +std::shared_ptr<CallCredentials> GoogleComputeEngineCredentials() { GrpcLibrary init; // To call grpc_init(). - return WrapCredentials( + return WrapCallCredentials( grpc_google_compute_engine_credentials_create(nullptr)); } // Builds JWT credentials. -std::shared_ptr<Credentials> ServiceAccountJWTAccessCredentials( +std::shared_ptr<CallCredentials> ServiceAccountJWTAccessCredentials( const grpc::string& json_key, long token_lifetime_seconds) { GrpcLibrary init; // To call grpc_init(). if (token_lifetime_seconds <= 0) { gpr_log(GPR_ERROR, "Trying to create JWTCredentials with non-positive lifetime"); - return WrapCredentials(nullptr); + return WrapCallCredentials(nullptr); } gpr_timespec lifetime = gpr_time_from_seconds(token_lifetime_seconds, GPR_TIMESPAN); - return WrapCredentials(grpc_service_account_jwt_access_credentials_create( + return WrapCallCredentials(grpc_service_account_jwt_access_credentials_create( json_key.c_str(), lifetime, nullptr)); } // Builds refresh token credentials. -std::shared_ptr<Credentials> GoogleRefreshTokenCredentials( +std::shared_ptr<CallCredentials> GoogleRefreshTokenCredentials( const grpc::string& json_refresh_token) { GrpcLibrary init; // To call grpc_init(). - return WrapCredentials(grpc_google_refresh_token_credentials_create( + return WrapCallCredentials(grpc_google_refresh_token_credentials_create( json_refresh_token.c_str(), nullptr)); } // Builds access token credentials. -std::shared_ptr<Credentials> AccessTokenCredentials( +std::shared_ptr<CallCredentials> AccessTokenCredentials( const grpc::string& access_token) { GrpcLibrary init; // To call grpc_init(). - return WrapCredentials( + return WrapCallCredentials( grpc_access_token_credentials_create(access_token.c_str(), nullptr)); } // Builds IAM credentials. -std::shared_ptr<Credentials> GoogleIAMCredentials( +std::shared_ptr<CallCredentials> GoogleIAMCredentials( const grpc::string& authorization_token, const grpc::string& authority_selector) { GrpcLibrary init; // To call grpc_init(). - return WrapCredentials(grpc_google_iam_credentials_create( + return WrapCallCredentials(grpc_google_iam_credentials_create( authorization_token.c_str(), authority_selector.c_str(), nullptr)); } -// Combines two credentials objects into a composite credentials. -std::shared_ptr<Credentials> CompositeCredentials( - const std::shared_ptr<Credentials>& creds1, - const std::shared_ptr<Credentials>& creds2) { - // Note that we are not saving shared_ptrs to the two credentials - // passed in here. This is OK because the underlying C objects (i.e., - // creds1 and creds2) into grpc_composite_credentials_create will see their - // refcounts incremented. - SecureCredentials* s1 = creds1->AsSecureCredentials(); - SecureCredentials* s2 = creds2->AsSecureCredentials(); - if (s1 && s2) { - return WrapCredentials(grpc_composite_credentials_create( - s1->GetRawCreds(), s2->GetRawCreds(), nullptr)); +// Combines one channel credentials and one call credentials into a channel +// composite credentials. +std::shared_ptr<ChannelCredentials> CompositeChannelCredentials( + const std::shared_ptr<ChannelCredentials>& channel_creds, + const std::shared_ptr<CallCredentials>& call_creds) { + // Note that we are not saving shared_ptrs to the two credentials passed in + // here. This is OK because the underlying C objects (i.e., channel_creds and + // call_creds) into grpc_composite_credentials_create will see their refcounts + // incremented. + SecureChannelCredentials* s_channel_creds = + channel_creds->AsSecureCredentials(); + SecureCallCredentials* s_call_creds = call_creds->AsSecureCredentials(); + if (s_channel_creds && s_call_creds) { + return WrapChannelCredentials(grpc_composite_channel_credentials_create( + s_channel_creds->GetRawCreds(), s_call_creds->GetRawCreds(), nullptr)); } return nullptr; } @@ -193,7 +201,7 @@ MetadataCredentialsPluginWrapper::MetadataCredentialsPluginWrapper( std::unique_ptr<MetadataCredentialsPlugin> plugin) : thread_pool_(CreateDefaultThreadPool()), plugin_(std::move(plugin)) {} -std::shared_ptr<Credentials> MetadataCredentialsFromPlugin( +std::shared_ptr<CallCredentials> MetadataCredentialsFromPlugin( std::unique_ptr<MetadataCredentialsPlugin> plugin) { GrpcLibrary init; // To call grpc_init(). MetadataCredentialsPluginWrapper* wrapper = @@ -201,7 +209,7 @@ std::shared_ptr<Credentials> MetadataCredentialsFromPlugin( grpc_metadata_credentials_plugin c_plugin = { MetadataCredentialsPluginWrapper::GetMetadata, MetadataCredentialsPluginWrapper::Destroy, wrapper}; - return WrapCredentials( + return WrapCallCredentials( grpc_metadata_credentials_create_from_plugin(c_plugin, nullptr)); } diff --git a/src/cpp/client/secure_credentials.h b/src/cpp/client/secure_credentials.h index d354827725..e9afa9e57f 100644 --- a/src/cpp/client/secure_credentials.h +++ b/src/cpp/client/secure_credentials.h @@ -43,19 +43,37 @@ namespace grpc { -class SecureCredentials GRPC_FINAL : public Credentials { +class SecureChannelCredentials GRPC_FINAL : public ChannelCredentials { public: - explicit SecureCredentials(grpc_credentials* c_creds) : c_creds_(c_creds) {} - ~SecureCredentials() GRPC_OVERRIDE { grpc_credentials_release(c_creds_); } - grpc_credentials* GetRawCreds() { return c_creds_; } - bool ApplyToCall(grpc_call* call) GRPC_OVERRIDE; + explicit SecureChannelCredentials(grpc_channel_credentials* c_creds) + : c_creds_(c_creds) {} + ~SecureChannelCredentials() GRPC_OVERRIDE { + grpc_channel_credentials_release(c_creds_); + } + grpc_channel_credentials* GetRawCreds() { return c_creds_; } std::shared_ptr<grpc::Channel> CreateChannel( const string& target, const grpc::ChannelArguments& args) GRPC_OVERRIDE; - SecureCredentials* AsSecureCredentials() GRPC_OVERRIDE { return this; } + SecureChannelCredentials* AsSecureCredentials() GRPC_OVERRIDE { return this; } + + private: + grpc_channel_credentials* const c_creds_; +}; + +class SecureCallCredentials GRPC_FINAL : public CallCredentials { + public: + explicit SecureCallCredentials(grpc_call_credentials* c_creds) + : c_creds_(c_creds) {} + ~SecureCallCredentials() GRPC_OVERRIDE { + grpc_call_credentials_release(c_creds_); + } + grpc_call_credentials* GetRawCreds() { return c_creds_; } + + bool ApplyToCall(grpc_call* call) GRPC_OVERRIDE; + SecureCallCredentials* AsSecureCredentials() GRPC_OVERRIDE { return this; } private: - grpc_credentials* const c_creds_; + grpc_call_credentials* const c_creds_; }; class MetadataCredentialsPluginWrapper GRPC_FINAL { diff --git a/src/csharp/Grpc.Core.Tests/FakeCredentials.cs b/src/csharp/Grpc.Core.Tests/FakeCredentials.cs index 87d55cd276..144b8320b9 100644 --- a/src/csharp/Grpc.Core.Tests/FakeCredentials.cs +++ b/src/csharp/Grpc.Core.Tests/FakeCredentials.cs @@ -57,7 +57,7 @@ namespace Grpc.Core.Tests get { return composable; } } - internal override CredentialsSafeHandle ToNativeCredentials() + internal override ChannelCredentialsSafeHandle ToNativeCredentials() { return null; } @@ -65,7 +65,7 @@ namespace Grpc.Core.Tests internal class FakeCallCredentials : CallCredentials { - internal override CredentialsSafeHandle ToNativeCredentials() + internal override CallCredentialsSafeHandle ToNativeCredentials() { return null; } diff --git a/src/csharp/Grpc.Core/CallCredentials.cs b/src/csharp/Grpc.Core/CallCredentials.cs index 400a9825de..5ea179dfea 100644 --- a/src/csharp/Grpc.Core/CallCredentials.cs +++ b/src/csharp/Grpc.Core/CallCredentials.cs @@ -78,7 +78,7 @@ namespace Grpc.Core /// Creates native object for the credentials. /// </summary> /// <returns>The native credentials.</returns> - internal abstract CredentialsSafeHandle ToNativeCredentials(); + internal abstract CallCredentialsSafeHandle ToNativeCredentials(); } /// <summary> @@ -98,7 +98,7 @@ namespace Grpc.Core this.interceptor = Preconditions.CheckNotNull(interceptor); } - internal override CredentialsSafeHandle ToNativeCredentials() + internal override CallCredentialsSafeHandle ToNativeCredentials() { NativeMetadataCredentialsPlugin plugin = new NativeMetadataCredentialsPlugin(interceptor); return plugin.Credentials; @@ -123,14 +123,14 @@ namespace Grpc.Core this.credentials = new List<CallCredentials>(credentials); } - internal override CredentialsSafeHandle ToNativeCredentials() + internal override CallCredentialsSafeHandle ToNativeCredentials() { return ToNativeRecursive(0); } // Recursive descent makes managing lifetime of intermediate CredentialSafeHandle instances easier. // In practice, we won't usually see composites from more than two credentials anyway. - private CredentialsSafeHandle ToNativeRecursive(int startIndex) + private CallCredentialsSafeHandle ToNativeRecursive(int startIndex) { if (startIndex == credentials.Count - 1) { @@ -140,7 +140,7 @@ namespace Grpc.Core using (var cred1 = credentials[startIndex].ToNativeCredentials()) using (var cred2 = ToNativeRecursive(startIndex + 1)) { - var nativeComposite = CredentialsSafeHandle.CreateComposite(cred1, cred2); + var nativeComposite = CallCredentialsSafeHandle.CreateComposite(cred1, cred2); if (nativeComposite.IsInvalid) { throw new ArgumentException("Error creating native composite credentials. Likely, this is because you are trying to compose incompatible credentials."); diff --git a/src/csharp/Grpc.Core/Channel.cs b/src/csharp/Grpc.Core/Channel.cs index 6b99055d4c..f5eec969f5 100644 --- a/src/csharp/Grpc.Core/Channel.cs +++ b/src/csharp/Grpc.Core/Channel.cs @@ -75,8 +75,8 @@ namespace Grpc.Core this.options = options != null ? new List<ChannelOption>(options) : new List<ChannelOption>(); EnsureUserAgentChannelOption(this.options); - using (CredentialsSafeHandle nativeCredentials = credentials.ToNativeCredentials()) - using (ChannelArgsSafeHandle nativeChannelArgs = ChannelOptions.CreateChannelArgs(this.options)) + using (var nativeCredentials = credentials.ToNativeCredentials()) + using (var nativeChannelArgs = ChannelOptions.CreateChannelArgs(this.options)) { if (nativeCredentials != null) { diff --git a/src/csharp/Grpc.Core/ChannelCredentials.cs b/src/csharp/Grpc.Core/ChannelCredentials.cs index 9d2bcdabe8..5d96958e7c 100644 --- a/src/csharp/Grpc.Core/ChannelCredentials.cs +++ b/src/csharp/Grpc.Core/ChannelCredentials.cs @@ -76,7 +76,7 @@ namespace Grpc.Core /// should be created. /// </summary> /// <returns>The native credentials.</returns> - internal abstract CredentialsSafeHandle ToNativeCredentials(); + internal abstract ChannelCredentialsSafeHandle ToNativeCredentials(); /// <summary> /// Returns <c>true</c> if this credential type allows being composed by <c>CompositeCredentials</c>. @@ -88,7 +88,7 @@ namespace Grpc.Core private sealed class InsecureCredentialsImpl : ChannelCredentials { - internal override CredentialsSafeHandle ToNativeCredentials() + internal override ChannelCredentialsSafeHandle ToNativeCredentials() { return null; } @@ -160,9 +160,9 @@ namespace Grpc.Core get { return true; } } - internal override CredentialsSafeHandle ToNativeCredentials() + internal override ChannelCredentialsSafeHandle ToNativeCredentials() { - return CredentialsSafeHandle.CreateSslCredentials(rootCertificates, keyCertificatePair); + return ChannelCredentialsSafeHandle.CreateSslCredentials(rootCertificates, keyCertificatePair); } } @@ -188,12 +188,12 @@ namespace Grpc.Core Preconditions.CheckArgument(channelCredentials.IsComposable, "Supplied channel credentials do not allow composition."); } - internal override CredentialsSafeHandle ToNativeCredentials() + internal override ChannelCredentialsSafeHandle ToNativeCredentials() { - using (var cred1 = channelCredentials.ToNativeCredentials()) - using (var cred2 = callCredentials.ToNativeCredentials()) + using (var channelCreds = channelCredentials.ToNativeCredentials()) + using (var callCreds = callCredentials.ToNativeCredentials()) { - var nativeComposite = CredentialsSafeHandle.CreateComposite(cred1, cred2); + var nativeComposite = ChannelCredentialsSafeHandle.CreateComposite(channelCreds, callCreds); if (nativeComposite.IsInvalid) { throw new ArgumentException("Error creating native composite credentials. Likely, this is because you are trying to compose incompatible credentials."); diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj index 0aab7bdd8a..c4f799297d 100644 --- a/src/csharp/Grpc.Core/Grpc.Core.csproj +++ b/src/csharp/Grpc.Core/Grpc.Core.csproj @@ -80,7 +80,6 @@ <Compile Include="ServerServiceDefinition.cs" /> <Compile Include="Utils\AsyncStreamExtensions.cs" /> <Compile Include="Utils\BenchmarkUtil.cs" /> - <Compile Include="Internal\CredentialsSafeHandle.cs" /> <Compile Include="ChannelCredentials.cs" /> <Compile Include="Internal\ChannelArgsSafeHandle.cs" /> <Compile Include="Internal\AsyncCompletion.cs" /> @@ -119,6 +118,8 @@ <Compile Include="CompressionLevel.cs" /> <Compile Include="WriteOptions.cs" /> <Compile Include="ContextPropagationToken.cs" /> + <Compile Include="Internal\CallCredentialsSafeHandle.cs" /> + <Compile Include="Internal\ChannelCredentialsSafeHandle.cs" /> <Compile Include="Profiling\ProfilerEntry.cs" /> <Compile Include="Profiling\ProfilerScope.cs" /> <Compile Include="Profiling\IProfiler.cs" /> @@ -157,4 +158,4 @@ <ItemGroup> <Folder Include="Profiling\" /> </ItemGroup> -</Project>
\ No newline at end of file +</Project> diff --git a/src/csharp/Grpc.Core/Internal/CallCredentialsSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CallCredentialsSafeHandle.cs new file mode 100644 index 0000000000..3678c7dd86 --- /dev/null +++ b/src/csharp/Grpc.Core/Internal/CallCredentialsSafeHandle.cs @@ -0,0 +1,64 @@ +#region Copyright notice and license +// 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. +#endregion +using System; +using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; + +namespace Grpc.Core.Internal +{ + /// <summary> + /// grpc_call_credentials from <c>grpc/grpc_security.h</c> + /// </summary> + internal class CallCredentialsSafeHandle : SafeHandleZeroIsInvalid + { + [DllImport("grpc_csharp_ext.dll")] + static extern CallCredentialsSafeHandle grpcsharp_composite_call_credentials_create(CallCredentialsSafeHandle creds1, CallCredentialsSafeHandle creds2); + + [DllImport("grpc_csharp_ext.dll")] + static extern void grpcsharp_call_credentials_release(IntPtr credentials); + + private CallCredentialsSafeHandle() + { + } + + public static CallCredentialsSafeHandle CreateComposite(CallCredentialsSafeHandle creds1, CallCredentialsSafeHandle creds2) + { + return grpcsharp_composite_call_credentials_create(creds1, creds2); + } + + protected override bool ReleaseHandle() + { + grpcsharp_call_credentials_release(handle); + return true; + } + } +} diff --git a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs index ddeedebd11..ad2e2919b7 100644 --- a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs @@ -100,7 +100,7 @@ namespace Grpc.Core.Internal BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray); [DllImport("grpc_csharp_ext.dll")] - static extern GRPCCallError grpcsharp_call_set_credentials(CallSafeHandle call, CredentialsSafeHandle credentials); + static extern GRPCCallError grpcsharp_call_set_credentials(CallSafeHandle call, CallCredentialsSafeHandle credentials); [DllImport("grpc_csharp_ext.dll")] static extern CStringSafeHandle grpcsharp_call_get_peer(CallSafeHandle call); @@ -117,7 +117,7 @@ namespace Grpc.Core.Internal this.completionRegistry = completionRegistry; } - public void SetCredentials(CredentialsSafeHandle credentials) + public void SetCredentials(CallCredentialsSafeHandle credentials) { grpcsharp_call_set_credentials(this, credentials).CheckOk(); } diff --git a/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ChannelCredentialsSafeHandle.cs index bab45108e0..8a58c64478 100644 --- a/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/ChannelCredentialsSafeHandle.cs @@ -36,31 +36,31 @@ using System.Threading.Tasks; namespace Grpc.Core.Internal { /// <summary> - /// grpc_credentials from <c>grpc/grpc_security.h</c> + /// grpc_channel_credentials from <c>grpc/grpc_security.h</c> /// </summary> - internal class CredentialsSafeHandle : SafeHandleZeroIsInvalid + internal class ChannelCredentialsSafeHandle : SafeHandleZeroIsInvalid { [DllImport("grpc_csharp_ext.dll", CharSet = CharSet.Ansi)] - static extern CredentialsSafeHandle grpcsharp_ssl_credentials_create(string pemRootCerts, string keyCertPairCertChain, string keyCertPairPrivateKey); + static extern ChannelCredentialsSafeHandle grpcsharp_ssl_credentials_create(string pemRootCerts, string keyCertPairCertChain, string keyCertPairPrivateKey); [DllImport("grpc_csharp_ext.dll")] - static extern CredentialsSafeHandle grpcsharp_composite_credentials_create(CredentialsSafeHandle creds1, CredentialsSafeHandle creds2); + static extern ChannelCredentialsSafeHandle grpcsharp_composite_channel_credentials_create(ChannelCredentialsSafeHandle channelCreds, CallCredentialsSafeHandle callCreds); [DllImport("grpc_csharp_ext.dll")] - static extern void grpcsharp_credentials_release(IntPtr credentials); + static extern void grpcsharp_channel_credentials_release(IntPtr credentials); - private CredentialsSafeHandle() + private ChannelCredentialsSafeHandle() { } - public static CredentialsSafeHandle CreateNullCredentials() + public static ChannelCredentialsSafeHandle CreateNullCredentials() { - var creds = new CredentialsSafeHandle(); + var creds = new ChannelCredentialsSafeHandle(); creds.SetHandle(IntPtr.Zero); return creds; } - public static CredentialsSafeHandle CreateSslCredentials(string pemRootCerts, KeyCertificatePair keyCertPair) + public static ChannelCredentialsSafeHandle CreateSslCredentials(string pemRootCerts, KeyCertificatePair keyCertPair) { if (keyCertPair != null) { @@ -72,14 +72,14 @@ namespace Grpc.Core.Internal } } - public static CredentialsSafeHandle CreateComposite(CredentialsSafeHandle creds1, CredentialsSafeHandle creds2) + public static ChannelCredentialsSafeHandle CreateComposite(ChannelCredentialsSafeHandle channelCreds, CallCredentialsSafeHandle callCreds) { - return grpcsharp_composite_credentials_create(creds1, creds2); + return grpcsharp_composite_channel_credentials_create(channelCreds, callCreds); } protected override bool ReleaseHandle() { - grpcsharp_credentials_release(handle); + grpcsharp_channel_credentials_release(handle); return true; } } diff --git a/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs index 5f9169bcb2..b3aa27c40f 100644 --- a/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs @@ -45,7 +45,7 @@ namespace Grpc.Core.Internal static extern ChannelSafeHandle grpcsharp_insecure_channel_create(string target, ChannelArgsSafeHandle channelArgs); [DllImport("grpc_csharp_ext.dll")] - static extern ChannelSafeHandle grpcsharp_secure_channel_create(CredentialsSafeHandle credentials, string target, ChannelArgsSafeHandle channelArgs); + static extern ChannelSafeHandle grpcsharp_secure_channel_create(ChannelCredentialsSafeHandle credentials, string target, ChannelArgsSafeHandle channelArgs); [DllImport("grpc_csharp_ext.dll")] static extern CallSafeHandle grpcsharp_channel_create_call(ChannelSafeHandle channel, CallSafeHandle parentCall, ContextPropagationFlags propagationMask, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline); @@ -75,7 +75,7 @@ namespace Grpc.Core.Internal return grpcsharp_insecure_channel_create(target, channelArgs); } - public static ChannelSafeHandle CreateSecure(CredentialsSafeHandle credentials, string target, ChannelArgsSafeHandle channelArgs) + public static ChannelSafeHandle CreateSecure(ChannelCredentialsSafeHandle credentials, string target, ChannelArgsSafeHandle channelArgs) { // Increment reference count for the native gRPC environment to make sure we don't do grpc_shutdown() before destroying the server handle. // Doing so would make object finalizer crash if we end up abandoning the handle. @@ -83,7 +83,7 @@ namespace Grpc.Core.Internal return grpcsharp_secure_channel_create(credentials, target, channelArgs); } - public CallSafeHandle CreateCall(CompletionRegistry registry, CallSafeHandle parentCall, ContextPropagationFlags propagationMask, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline, CredentialsSafeHandle credentials) + public CallSafeHandle CreateCall(CompletionRegistry registry, CallSafeHandle parentCall, ContextPropagationFlags propagationMask, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline, CallCredentialsSafeHandle credentials) { using (Profilers.ForCurrentThread().NewScope("ChannelSafeHandle.CreateCall")) { diff --git a/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs b/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs index f76492cba4..2a571cd6c9 100644 --- a/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs +++ b/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs @@ -46,7 +46,7 @@ namespace Grpc.Core.Internal static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<NativeMetadataCredentialsPlugin>(); [DllImport("grpc_csharp_ext.dll")] - static extern CredentialsSafeHandle grpcsharp_metadata_credentials_create_from_plugin(NativeMetadataInterceptor interceptor); + static extern CallCredentialsSafeHandle grpcsharp_metadata_credentials_create_from_plugin(NativeMetadataInterceptor interceptor); [DllImport("grpc_csharp_ext.dll", CharSet = CharSet.Ansi)] static extern void grpcsharp_metadata_credentials_notify_from_plugin(IntPtr callbackPtr, IntPtr userData, MetadataArraySafeHandle metadataArray, StatusCode statusCode, string errorDetails); @@ -54,7 +54,7 @@ namespace Grpc.Core.Internal AsyncAuthInterceptor interceptor; GCHandle gcHandle; NativeMetadataInterceptor nativeInterceptor; - CredentialsSafeHandle credentials; + CallCredentialsSafeHandle credentials; public NativeMetadataCredentialsPlugin(AsyncAuthInterceptor interceptor) { @@ -66,7 +66,7 @@ namespace Grpc.Core.Internal this.credentials = grpcsharp_metadata_credentials_create_from_plugin(nativeInterceptor); } - public CredentialsSafeHandle Credentials + public CallCredentialsSafeHandle Credentials { get { return credentials; } } diff --git a/src/csharp/Grpc.Core/Profiling/IProfiler.cs b/src/csharp/Grpc.Core/Profiling/IProfiler.cs index c426c365d2..e850375004 100644 --- a/src/csharp/Grpc.Core/Profiling/IProfiler.cs +++ b/src/csharp/Grpc.Core/Profiling/IProfiler.cs @@ -41,7 +41,9 @@ namespace Grpc.Core.Profiling internal interface IProfiler { void Begin(string tag); + void End(string tag); + void Mark(string tag); } } diff --git a/src/csharp/Grpc.Core/Profiling/ProfilerEntry.cs b/src/csharp/Grpc.Core/Profiling/ProfilerEntry.cs index 5cc4c3c054..792e3c3cd0 100644 --- a/src/csharp/Grpc.Core/Profiling/ProfilerEntry.cs +++ b/src/csharp/Grpc.Core/Profiling/ProfilerEntry.cs @@ -40,7 +40,8 @@ namespace Grpc.Core.Profiling { internal struct ProfilerEntry { - public enum Type { + public enum Type + { BEGIN, END, MARK diff --git a/src/csharp/Grpc.Core/Profiling/Profilers.cs b/src/csharp/Grpc.Core/Profiling/Profilers.cs index c8123347f2..471ee20875 100644 --- a/src/csharp/Grpc.Core/Profiling/Profilers.cs +++ b/src/csharp/Grpc.Core/Profiling/Profilers.cs @@ -40,12 +40,12 @@ namespace Grpc.Core.Profiling { internal static class Profilers { - static readonly NopProfiler defaultProfiler = new NopProfiler(); + static readonly NopProfiler DefaultProfiler = new NopProfiler(); static readonly ThreadLocal<IProfiler> profilers = new ThreadLocal<IProfiler>(); public static IProfiler ForCurrentThread() { - return profilers.Value ?? defaultProfiler; + return profilers.Value ?? DefaultProfiler; } public static void SetForCurrentThread(IProfiler profiler) @@ -89,15 +89,18 @@ namespace Grpc.Core.Profiling this.entries = new ProfilerEntry[capacity]; } - public void Begin(string tag) { + public void Begin(string tag) + { AddEntry(new ProfilerEntry(Timespec.PreciseNow, ProfilerEntry.Type.BEGIN, tag)); } - public void End(string tag) { + public void End(string tag) + { AddEntry(new ProfilerEntry(Timespec.PreciseNow, ProfilerEntry.Type.END, tag)); } - public void Mark(string tag) { + public void Mark(string tag) + { AddEntry(new ProfilerEntry(Timespec.PreciseNow, ProfilerEntry.Type.MARK, tag)); } diff --git a/src/csharp/Grpc.IntegrationTesting.QpsWorker/.gitignore b/src/csharp/Grpc.IntegrationTesting.QpsWorker/.gitignore new file mode 100644 index 0000000000..a382af2294 --- /dev/null +++ b/src/csharp/Grpc.IntegrationTesting.QpsWorker/.gitignore @@ -0,0 +1,3 @@ +bin +obj + diff --git a/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.csproj b/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.csproj new file mode 100644 index 0000000000..8b245ade2e --- /dev/null +++ b/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.csproj @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProjectGuid>{B82B7DFE-7F7B-40EF-B3D6-064FF2B01294}</ProjectGuid> + <OutputType>Exe</OutputType> + <RootNamespace>Grpc.IntegrationTesting.QpsWorker</RootNamespace> + <AssemblyName>Grpc.IntegrationTesting.QpsWorker</AssemblyName> + <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug</OutputPath> + <DefineConstants>DEBUG;</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <PlatformTarget>AnyCPU</PlatformTarget> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release</OutputPath> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <PlatformTarget>AnyCPU</PlatformTarget> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\ReleaseSigned</OutputPath> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <SignAssembly>True</SignAssembly> + <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile> + </PropertyGroup> + <ItemGroup> + <Reference Include="System" /> + </ItemGroup> + <ItemGroup> + <Compile Include="..\Grpc.Core\Version.cs"> + <Link>Version.cs</Link> + </Compile> + <Compile Include="Program.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + </ItemGroup> + <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> + <ItemGroup> + <ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj"> + <Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project> + <Name>Grpc.Core</Name> + </ProjectReference> + <ProjectReference Include="..\Grpc.IntegrationTesting\Grpc.IntegrationTesting.csproj"> + <Project>{C61154BA-DD4A-4838-8420-0162A28925E0}</Project> + <Name>Grpc.IntegrationTesting</Name> + </ProjectReference> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/src/csharp/Grpc.IntegrationTesting.QpsWorker/Program.cs b/src/csharp/Grpc.IntegrationTesting.QpsWorker/Program.cs new file mode 100644 index 0000000000..308463337f --- /dev/null +++ b/src/csharp/Grpc.IntegrationTesting.QpsWorker/Program.cs @@ -0,0 +1,46 @@ +#region Copyright notice and license + +// 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. + +#endregion + +using System; +using Grpc.IntegrationTesting; + +namespace Grpc.IntegrationTesting +{ + class Program + { + public static void Main(string[] args) + { + QpsWorker.Run(args); + } + } +} diff --git a/src/csharp/Grpc.IntegrationTesting.QpsWorker/Properties/AssemblyInfo.cs b/src/csharp/Grpc.IntegrationTesting.QpsWorker/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..aacfc16ef4 --- /dev/null +++ b/src/csharp/Grpc.IntegrationTesting.QpsWorker/Properties/AssemblyInfo.cs @@ -0,0 +1,11 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +[assembly: AssemblyTitle("Grpc.IntegrationTesting.QpsWorker")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("Google Inc. All rights reserved.")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] diff --git a/src/csharp/Grpc.IntegrationTesting/BenchmarkServiceImpl.cs b/src/csharp/Grpc.IntegrationTesting/BenchmarkServiceImpl.cs new file mode 100644 index 0000000000..47a15224f1 --- /dev/null +++ b/src/csharp/Grpc.IntegrationTesting/BenchmarkServiceImpl.cs @@ -0,0 +1,76 @@ +#region Copyright notice and license + +// 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. + +#endregion + +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Google.Protobuf; +using Grpc.Core; +using Grpc.Core.Utils; + +namespace Grpc.Testing +{ + /// <summary> + /// Implementation of BenchmarkService server + /// </summary> + public class BenchmarkServiceImpl : BenchmarkService.IBenchmarkService + { + private readonly int responseSize; + + public BenchmarkServiceImpl(int responseSize) + { + this.responseSize = responseSize; + } + + public Task<SimpleResponse> UnaryCall(SimpleRequest request, ServerCallContext context) + { + var response = new SimpleResponse { Payload = CreateZerosPayload(responseSize) }; + return Task.FromResult(response); + } + + public async Task StreamingCall(IAsyncStreamReader<SimpleRequest> requestStream, IServerStreamWriter<SimpleResponse> responseStream, ServerCallContext context) + { + await requestStream.ForEachAsync(async request => + { + var response = new SimpleResponse { Payload = CreateZerosPayload(responseSize) }; + await responseStream.WriteAsync(response); + }); + } + + private static Payload CreateZerosPayload(int size) + { + return new Payload { Body = ByteString.CopyFrom(new byte[size]) }; + } + } +} diff --git a/src/csharp/Grpc.IntegrationTesting/ClientRunners.cs b/src/csharp/Grpc.IntegrationTesting/ClientRunners.cs new file mode 100644 index 0000000000..e9e659cb1f --- /dev/null +++ b/src/csharp/Grpc.IntegrationTesting/ClientRunners.cs @@ -0,0 +1,153 @@ +#region Copyright notice and license + +// 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. + +#endregion + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; +using Google.Protobuf; +using Grpc.Core; +using Grpc.Core.Utils; +using NUnit.Framework; +using Grpc.Testing; + +namespace Grpc.IntegrationTesting +{ + /// <summary> + /// Helper methods to start client runners for performance testing. + /// </summary> + public static class ClientRunners + { + /// <summary> + /// Creates a started client runner. + /// </summary> + public static IClientRunner CreateStarted(ClientConfig config) + { + string target = config.ServerTargets.Single(); + Grpc.Core.Utils.Preconditions.CheckArgument(config.LoadParams.LoadCase == LoadParams.LoadOneofCase.ClosedLoop); + + var credentials = config.SecurityParams != null ? TestCredentials.CreateSslCredentials() : ChannelCredentials.Insecure; + var channel = new Channel(target, credentials); + + switch (config.RpcType) + { + case RpcType.UNARY: + return new SyncUnaryClientRunner(channel, + config.PayloadConfig.SimpleParams.ReqSize, + config.HistogramParams); + + case RpcType.STREAMING: + default: + throw new ArgumentException("Unsupported RpcType."); + } + } + } + + /// <summary> + /// Client that starts synchronous unary calls in a closed loop. + /// </summary> + public class SyncUnaryClientRunner : IClientRunner + { + const double SecondsToNanos = 1e9; + + readonly Channel channel; + readonly int payloadSize; + readonly Histogram histogram; + + readonly BenchmarkService.IBenchmarkServiceClient client; + readonly Task runnerTask; + readonly CancellationTokenSource stoppedCts; + readonly WallClockStopwatch wallClockStopwatch = new WallClockStopwatch(); + + public SyncUnaryClientRunner(Channel channel, int payloadSize, HistogramParams histogramParams) + { + this.channel = Grpc.Core.Utils.Preconditions.CheckNotNull(channel); + this.payloadSize = payloadSize; + this.histogram = new Histogram(histogramParams.Resolution, histogramParams.MaxPossible); + + this.stoppedCts = new CancellationTokenSource(); + this.client = BenchmarkService.NewClient(channel); + this.runnerTask = Task.Factory.StartNew(Run, TaskCreationOptions.LongRunning); + } + + public ClientStats GetStats(bool reset) + { + var histogramData = histogram.GetSnapshot(reset); + var secondsElapsed = wallClockStopwatch.GetElapsedSnapshot(reset).TotalSeconds; + + // TODO: populate user time and system time + return new ClientStats + { + Latencies = histogramData, + TimeElapsed = secondsElapsed, + TimeUser = 0, + TimeSystem = 0 + }; + } + + public async Task StopAsync() + { + stoppedCts.Cancel(); + await runnerTask; + await channel.ShutdownAsync(); + } + + private void Run() + { + var request = new SimpleRequest + { + Payload = CreateZerosPayload(payloadSize) + }; + var stopwatch = new Stopwatch(); + + while (!stoppedCts.Token.IsCancellationRequested) + { + stopwatch.Restart(); + client.UnaryCall(request); + stopwatch.Stop(); + + // spec requires data point in nanoseconds. + histogram.AddObservation(stopwatch.Elapsed.TotalSeconds * SecondsToNanos); + } + } + + private static Payload CreateZerosPayload(int size) + { + return new Payload { Body = ByteString.CopyFrom(new byte[size]) }; + } + } +} diff --git a/src/csharp/Grpc.IntegrationTesting/Control.cs b/src/csharp/Grpc.IntegrationTesting/Control.cs new file mode 100644 index 0000000000..4764e1072b --- /dev/null +++ b/src/csharp/Grpc.IntegrationTesting/Control.cs @@ -0,0 +1,2362 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: test/proto/benchmarks/control.proto +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; +using scg = global::System.Collections.Generic; +namespace Grpc.Testing { + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public static partial class Control { + + #region Descriptor + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static Control() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "CiN0ZXN0L3Byb3RvL2JlbmNobWFya3MvY29udHJvbC5wcm90bxIMZ3JwYy50", + "ZXN0aW5nGiR0ZXN0L3Byb3RvL2JlbmNobWFya3MvcGF5bG9hZHMucHJvdG8a", + "IXRlc3QvcHJvdG8vYmVuY2htYXJrcy9zdGF0cy5wcm90byIlCg1Qb2lzc29u", + "UGFyYW1zEhQKDG9mZmVyZWRfbG9hZBgBIAEoASJBCg1Vbmlmb3JtUGFyYW1z", + "EhcKD2ludGVyYXJyaXZhbF9sbxgBIAEoARIXCg9pbnRlcmFycml2YWxfaGkY", + "AiABKAEiKwoTRGV0ZXJtaW5pc3RpY1BhcmFtcxIUCgxvZmZlcmVkX2xvYWQY", + "ASABKAEiOAoMUGFyZXRvUGFyYW1zEhkKEWludGVyYXJyaXZhbF9iYXNlGAEg", + "ASgBEg0KBWFscGhhGAIgASgBIhIKEENsb3NlZExvb3BQYXJhbXMijgIKCkxv", + "YWRQYXJhbXMSNQoLY2xvc2VkX2xvb3AYASABKAsyHi5ncnBjLnRlc3Rpbmcu", + "Q2xvc2VkTG9vcFBhcmFtc0gAEi4KB3BvaXNzb24YAiABKAsyGy5ncnBjLnRl", + "c3RpbmcuUG9pc3NvblBhcmFtc0gAEi4KB3VuaWZvcm0YAyABKAsyGy5ncnBj", + "LnRlc3RpbmcuVW5pZm9ybVBhcmFtc0gAEjMKBmRldGVybRgEIAEoCzIhLmdy", + "cGMudGVzdGluZy5EZXRlcm1pbmlzdGljUGFyYW1zSAASLAoGcGFyZXRvGAUg", + "ASgLMhouZ3JwYy50ZXN0aW5nLlBhcmV0b1BhcmFtc0gAQgYKBGxvYWQiQwoO", + "U2VjdXJpdHlQYXJhbXMSEwoLdXNlX3Rlc3RfY2EYASABKAgSHAoUc2VydmVy", + "X2hvc3Rfb3ZlcnJpZGUYAiABKAkirwMKDENsaWVudENvbmZpZxIWCg5zZXJ2", + "ZXJfdGFyZ2V0cxgBIAMoCRItCgtjbGllbnRfdHlwZRgCIAEoDjIYLmdycGMu", + "dGVzdGluZy5DbGllbnRUeXBlEjUKD3NlY3VyaXR5X3BhcmFtcxgDIAEoCzIc", + "LmdycGMudGVzdGluZy5TZWN1cml0eVBhcmFtcxIkChxvdXRzdGFuZGluZ19y", + "cGNzX3Blcl9jaGFubmVsGAQgASgFEhcKD2NsaWVudF9jaGFubmVscxgFIAEo", + "BRIcChRhc3luY19jbGllbnRfdGhyZWFkcxgHIAEoBRInCghycGNfdHlwZRgI", + "IAEoDjIVLmdycGMudGVzdGluZy5ScGNUeXBlEi0KC2xvYWRfcGFyYW1zGAog", + "ASgLMhguZ3JwYy50ZXN0aW5nLkxvYWRQYXJhbXMSMwoOcGF5bG9hZF9jb25m", + "aWcYCyABKAsyGy5ncnBjLnRlc3RpbmcuUGF5bG9hZENvbmZpZxI3ChBoaXN0", + "b2dyYW1fcGFyYW1zGAwgASgLMh0uZ3JwYy50ZXN0aW5nLkhpc3RvZ3JhbVBh", + "cmFtcyI4CgxDbGllbnRTdGF0dXMSKAoFc3RhdHMYASABKAsyGS5ncnBjLnRl", + "c3RpbmcuQ2xpZW50U3RhdHMiFQoETWFyaxINCgVyZXNldBgBIAEoCCJoCgpD", + "bGllbnRBcmdzEisKBXNldHVwGAEgASgLMhouZ3JwYy50ZXN0aW5nLkNsaWVu", + "dENvbmZpZ0gAEiIKBG1hcmsYAiABKAsyEi5ncnBjLnRlc3RpbmcuTWFya0gA", + "QgkKB2FyZ3R5cGUi9wEKDFNlcnZlckNvbmZpZxItCgtzZXJ2ZXJfdHlwZRgB", + "IAEoDjIYLmdycGMudGVzdGluZy5TZXJ2ZXJUeXBlEjUKD3NlY3VyaXR5X3Bh", + "cmFtcxgCIAEoCzIcLmdycGMudGVzdGluZy5TZWN1cml0eVBhcmFtcxIMCgRo", + "b3N0GAMgASgJEgwKBHBvcnQYBCABKAUSHAoUYXN5bmNfc2VydmVyX3RocmVh", + "ZHMYByABKAUSEgoKY29yZV9saW1pdBgIIAEoBRIzCg5wYXlsb2FkX2NvbmZp", + "ZxgJIAEoCzIbLmdycGMudGVzdGluZy5QYXlsb2FkQ29uZmlnImgKClNlcnZl", + "ckFyZ3MSKwoFc2V0dXAYASABKAsyGi5ncnBjLnRlc3RpbmcuU2VydmVyQ29u", + "ZmlnSAASIgoEbWFyaxgCIAEoCzISLmdycGMudGVzdGluZy5NYXJrSABCCQoH", + "YXJndHlwZSJVCgxTZXJ2ZXJTdGF0dXMSKAoFc3RhdHMYASABKAsyGS5ncnBj", + "LnRlc3RpbmcuU2VydmVyU3RhdHMSDAoEcG9ydBgCIAEoBRINCgVjb3JlcxgD", + "IAEoBSovCgpDbGllbnRUeXBlEg8KC1NZTkNfQ0xJRU5UEAASEAoMQVNZTkNf", + "Q0xJRU5UEAEqLwoKU2VydmVyVHlwZRIPCgtTWU5DX1NFUlZFUhAAEhAKDEFT", + "WU5DX1NFUlZFUhABKiMKB1JwY1R5cGUSCQoFVU5BUlkQABINCglTVFJFQU1J", + "TkcQAWIGcHJvdG8z")); + descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData, + new pbr::FileDescriptor[] { global::Grpc.Testing.Payloads.Descriptor, global::Grpc.Testing.Stats.Descriptor, }, + new pbr::GeneratedCodeInfo(new[] {typeof(global::Grpc.Testing.ClientType), typeof(global::Grpc.Testing.ServerType), typeof(global::Grpc.Testing.RpcType), }, new pbr::GeneratedCodeInfo[] { + new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.PoissonParams), new[]{ "OfferedLoad" }, null, null, null), + new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.UniformParams), new[]{ "InterarrivalLo", "InterarrivalHi" }, null, null, null), + new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.DeterministicParams), new[]{ "OfferedLoad" }, null, null, null), + new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ParetoParams), new[]{ "InterarrivalBase", "Alpha" }, null, null, null), + new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ClosedLoopParams), null, null, null, null), + new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.LoadParams), new[]{ "ClosedLoop", "Poisson", "Uniform", "Determ", "Pareto" }, new[]{ "Load" }, null, null), + new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.SecurityParams), new[]{ "UseTestCa", "ServerHostOverride" }, null, null, null), + new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ClientConfig), new[]{ "ServerTargets", "ClientType", "SecurityParams", "OutstandingRpcsPerChannel", "ClientChannels", "AsyncClientThreads", "RpcType", "LoadParams", "PayloadConfig", "HistogramParams" }, null, null, null), + new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ClientStatus), new[]{ "Stats" }, null, null, null), + new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.Mark), new[]{ "Reset" }, null, null, null), + new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ClientArgs), new[]{ "Setup", "Mark" }, new[]{ "Argtype" }, null, null), + new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ServerConfig), new[]{ "ServerType", "SecurityParams", "Host", "Port", "AsyncServerThreads", "CoreLimit", "PayloadConfig" }, null, null, null), + new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ServerArgs), new[]{ "Setup", "Mark" }, new[]{ "Argtype" }, null, null), + new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ServerStatus), new[]{ "Stats", "Port", "Cores" }, null, null, null) + })); + } + #endregion + + } + #region Enums + public enum ClientType { + SYNC_CLIENT = 0, + ASYNC_CLIENT = 1, + } + + public enum ServerType { + SYNC_SERVER = 0, + ASYNC_SERVER = 1, + } + + public enum RpcType { + UNARY = 0, + STREAMING = 1, + } + + #endregion + + #region Messages + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class PoissonParams : pb::IMessage<PoissonParams> { + private static readonly pb::MessageParser<PoissonParams> _parser = new pb::MessageParser<PoissonParams>(() => new PoissonParams()); + public static pb::MessageParser<PoissonParams> Parser { get { return _parser; } } + + public static pbr::MessageDescriptor Descriptor { + get { return global::Grpc.Testing.Control.Descriptor.MessageTypes[0]; } + } + + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + public PoissonParams() { + OnConstruction(); + } + + partial void OnConstruction(); + + public PoissonParams(PoissonParams other) : this() { + offeredLoad_ = other.offeredLoad_; + } + + public PoissonParams Clone() { + return new PoissonParams(this); + } + + public const int OfferedLoadFieldNumber = 1; + private double offeredLoad_; + public double OfferedLoad { + get { return offeredLoad_; } + set { + offeredLoad_ = value; + } + } + + public override bool Equals(object other) { + return Equals(other as PoissonParams); + } + + public bool Equals(PoissonParams other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (OfferedLoad != other.OfferedLoad) return false; + return true; + } + + public override int GetHashCode() { + int hash = 1; + if (OfferedLoad != 0D) hash ^= OfferedLoad.GetHashCode(); + return hash; + } + + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); + } + + public void WriteTo(pb::CodedOutputStream output) { + if (OfferedLoad != 0D) { + output.WriteRawTag(9); + output.WriteDouble(OfferedLoad); + } + } + + public int CalculateSize() { + int size = 0; + if (OfferedLoad != 0D) { + size += 1 + 8; + } + return size; + } + + public void MergeFrom(PoissonParams other) { + if (other == null) { + return; + } + if (other.OfferedLoad != 0D) { + OfferedLoad = other.OfferedLoad; + } + } + + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 9: { + OfferedLoad = input.ReadDouble(); + break; + } + } + } + } + + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class UniformParams : pb::IMessage<UniformParams> { + private static readonly pb::MessageParser<UniformParams> _parser = new pb::MessageParser<UniformParams>(() => new UniformParams()); + public static pb::MessageParser<UniformParams> Parser { get { return _parser; } } + + public static pbr::MessageDescriptor Descriptor { + get { return global::Grpc.Testing.Control.Descriptor.MessageTypes[1]; } + } + + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + public UniformParams() { + OnConstruction(); + } + + partial void OnConstruction(); + + public UniformParams(UniformParams other) : this() { + interarrivalLo_ = other.interarrivalLo_; + interarrivalHi_ = other.interarrivalHi_; + } + + public UniformParams Clone() { + return new UniformParams(this); + } + + public const int InterarrivalLoFieldNumber = 1; + private double interarrivalLo_; + public double InterarrivalLo { + get { return interarrivalLo_; } + set { + interarrivalLo_ = value; + } + } + + public const int InterarrivalHiFieldNumber = 2; + private double interarrivalHi_; + public double InterarrivalHi { + get { return interarrivalHi_; } + set { + interarrivalHi_ = value; + } + } + + public override bool Equals(object other) { + return Equals(other as UniformParams); + } + + public bool Equals(UniformParams other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (InterarrivalLo != other.InterarrivalLo) return false; + if (InterarrivalHi != other.InterarrivalHi) return false; + return true; + } + + public override int GetHashCode() { + int hash = 1; + if (InterarrivalLo != 0D) hash ^= InterarrivalLo.GetHashCode(); + if (InterarrivalHi != 0D) hash ^= InterarrivalHi.GetHashCode(); + return hash; + } + + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); + } + + public void WriteTo(pb::CodedOutputStream output) { + if (InterarrivalLo != 0D) { + output.WriteRawTag(9); + output.WriteDouble(InterarrivalLo); + } + if (InterarrivalHi != 0D) { + output.WriteRawTag(17); + output.WriteDouble(InterarrivalHi); + } + } + + public int CalculateSize() { + int size = 0; + if (InterarrivalLo != 0D) { + size += 1 + 8; + } + if (InterarrivalHi != 0D) { + size += 1 + 8; + } + return size; + } + + public void MergeFrom(UniformParams other) { + if (other == null) { + return; + } + if (other.InterarrivalLo != 0D) { + InterarrivalLo = other.InterarrivalLo; + } + if (other.InterarrivalHi != 0D) { + InterarrivalHi = other.InterarrivalHi; + } + } + + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 9: { + InterarrivalLo = input.ReadDouble(); + break; + } + case 17: { + InterarrivalHi = input.ReadDouble(); + break; + } + } + } + } + + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class DeterministicParams : pb::IMessage<DeterministicParams> { + private static readonly pb::MessageParser<DeterministicParams> _parser = new pb::MessageParser<DeterministicParams>(() => new DeterministicParams()); + public static pb::MessageParser<DeterministicParams> Parser { get { return _parser; } } + + public static pbr::MessageDescriptor Descriptor { + get { return global::Grpc.Testing.Control.Descriptor.MessageTypes[2]; } + } + + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + public DeterministicParams() { + OnConstruction(); + } + + partial void OnConstruction(); + + public DeterministicParams(DeterministicParams other) : this() { + offeredLoad_ = other.offeredLoad_; + } + + public DeterministicParams Clone() { + return new DeterministicParams(this); + } + + public const int OfferedLoadFieldNumber = 1; + private double offeredLoad_; + public double OfferedLoad { + get { return offeredLoad_; } + set { + offeredLoad_ = value; + } + } + + public override bool Equals(object other) { + return Equals(other as DeterministicParams); + } + + public bool Equals(DeterministicParams other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (OfferedLoad != other.OfferedLoad) return false; + return true; + } + + public override int GetHashCode() { + int hash = 1; + if (OfferedLoad != 0D) hash ^= OfferedLoad.GetHashCode(); + return hash; + } + + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); + } + + public void WriteTo(pb::CodedOutputStream output) { + if (OfferedLoad != 0D) { + output.WriteRawTag(9); + output.WriteDouble(OfferedLoad); + } + } + + public int CalculateSize() { + int size = 0; + if (OfferedLoad != 0D) { + size += 1 + 8; + } + return size; + } + + public void MergeFrom(DeterministicParams other) { + if (other == null) { + return; + } + if (other.OfferedLoad != 0D) { + OfferedLoad = other.OfferedLoad; + } + } + + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 9: { + OfferedLoad = input.ReadDouble(); + break; + } + } + } + } + + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class ParetoParams : pb::IMessage<ParetoParams> { + private static readonly pb::MessageParser<ParetoParams> _parser = new pb::MessageParser<ParetoParams>(() => new ParetoParams()); + public static pb::MessageParser<ParetoParams> Parser { get { return _parser; } } + + public static pbr::MessageDescriptor Descriptor { + get { return global::Grpc.Testing.Control.Descriptor.MessageTypes[3]; } + } + + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + public ParetoParams() { + OnConstruction(); + } + + partial void OnConstruction(); + + public ParetoParams(ParetoParams other) : this() { + interarrivalBase_ = other.interarrivalBase_; + alpha_ = other.alpha_; + } + + public ParetoParams Clone() { + return new ParetoParams(this); + } + + public const int InterarrivalBaseFieldNumber = 1; + private double interarrivalBase_; + public double InterarrivalBase { + get { return interarrivalBase_; } + set { + interarrivalBase_ = value; + } + } + + public const int AlphaFieldNumber = 2; + private double alpha_; + public double Alpha { + get { return alpha_; } + set { + alpha_ = value; + } + } + + public override bool Equals(object other) { + return Equals(other as ParetoParams); + } + + public bool Equals(ParetoParams other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (InterarrivalBase != other.InterarrivalBase) return false; + if (Alpha != other.Alpha) return false; + return true; + } + + public override int GetHashCode() { + int hash = 1; + if (InterarrivalBase != 0D) hash ^= InterarrivalBase.GetHashCode(); + if (Alpha != 0D) hash ^= Alpha.GetHashCode(); + return hash; + } + + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); + } + + public void WriteTo(pb::CodedOutputStream output) { + if (InterarrivalBase != 0D) { + output.WriteRawTag(9); + output.WriteDouble(InterarrivalBase); + } + if (Alpha != 0D) { + output.WriteRawTag(17); + output.WriteDouble(Alpha); + } + } + + public int CalculateSize() { + int size = 0; + if (InterarrivalBase != 0D) { + size += 1 + 8; + } + if (Alpha != 0D) { + size += 1 + 8; + } + return size; + } + + public void MergeFrom(ParetoParams other) { + if (other == null) { + return; + } + if (other.InterarrivalBase != 0D) { + InterarrivalBase = other.InterarrivalBase; + } + if (other.Alpha != 0D) { + Alpha = other.Alpha; + } + } + + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 9: { + InterarrivalBase = input.ReadDouble(); + break; + } + case 17: { + Alpha = input.ReadDouble(); + break; + } + } + } + } + + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class ClosedLoopParams : pb::IMessage<ClosedLoopParams> { + private static readonly pb::MessageParser<ClosedLoopParams> _parser = new pb::MessageParser<ClosedLoopParams>(() => new ClosedLoopParams()); + public static pb::MessageParser<ClosedLoopParams> Parser { get { return _parser; } } + + public static pbr::MessageDescriptor Descriptor { + get { return global::Grpc.Testing.Control.Descriptor.MessageTypes[4]; } + } + + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + public ClosedLoopParams() { + OnConstruction(); + } + + partial void OnConstruction(); + + public ClosedLoopParams(ClosedLoopParams other) : this() { + } + + public ClosedLoopParams Clone() { + return new ClosedLoopParams(this); + } + + public override bool Equals(object other) { + return Equals(other as ClosedLoopParams); + } + + public bool Equals(ClosedLoopParams other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + return true; + } + + public override int GetHashCode() { + int hash = 1; + return hash; + } + + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); + } + + public void WriteTo(pb::CodedOutputStream output) { + } + + public int CalculateSize() { + int size = 0; + return size; + } + + public void MergeFrom(ClosedLoopParams other) { + if (other == null) { + return; + } + } + + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + } + } + } + + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class LoadParams : pb::IMessage<LoadParams> { + private static readonly pb::MessageParser<LoadParams> _parser = new pb::MessageParser<LoadParams>(() => new LoadParams()); + public static pb::MessageParser<LoadParams> Parser { get { return _parser; } } + + public static pbr::MessageDescriptor Descriptor { + get { return global::Grpc.Testing.Control.Descriptor.MessageTypes[5]; } + } + + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + public LoadParams() { + OnConstruction(); + } + + partial void OnConstruction(); + + public LoadParams(LoadParams other) : this() { + switch (other.LoadCase) { + case LoadOneofCase.ClosedLoop: + ClosedLoop = other.ClosedLoop.Clone(); + break; + case LoadOneofCase.Poisson: + Poisson = other.Poisson.Clone(); + break; + case LoadOneofCase.Uniform: + Uniform = other.Uniform.Clone(); + break; + case LoadOneofCase.Determ: + Determ = other.Determ.Clone(); + break; + case LoadOneofCase.Pareto: + Pareto = other.Pareto.Clone(); + break; + } + + } + + public LoadParams Clone() { + return new LoadParams(this); + } + + public const int ClosedLoopFieldNumber = 1; + public global::Grpc.Testing.ClosedLoopParams ClosedLoop { + get { return loadCase_ == LoadOneofCase.ClosedLoop ? (global::Grpc.Testing.ClosedLoopParams) load_ : null; } + set { + load_ = value; + loadCase_ = value == null ? LoadOneofCase.None : LoadOneofCase.ClosedLoop; + } + } + + public const int PoissonFieldNumber = 2; + public global::Grpc.Testing.PoissonParams Poisson { + get { return loadCase_ == LoadOneofCase.Poisson ? (global::Grpc.Testing.PoissonParams) load_ : null; } + set { + load_ = value; + loadCase_ = value == null ? LoadOneofCase.None : LoadOneofCase.Poisson; + } + } + + public const int UniformFieldNumber = 3; + public global::Grpc.Testing.UniformParams Uniform { + get { return loadCase_ == LoadOneofCase.Uniform ? (global::Grpc.Testing.UniformParams) load_ : null; } + set { + load_ = value; + loadCase_ = value == null ? LoadOneofCase.None : LoadOneofCase.Uniform; + } + } + + public const int DetermFieldNumber = 4; + public global::Grpc.Testing.DeterministicParams Determ { + get { return loadCase_ == LoadOneofCase.Determ ? (global::Grpc.Testing.DeterministicParams) load_ : null; } + set { + load_ = value; + loadCase_ = value == null ? LoadOneofCase.None : LoadOneofCase.Determ; + } + } + + public const int ParetoFieldNumber = 5; + public global::Grpc.Testing.ParetoParams Pareto { + get { return loadCase_ == LoadOneofCase.Pareto ? (global::Grpc.Testing.ParetoParams) load_ : null; } + set { + load_ = value; + loadCase_ = value == null ? LoadOneofCase.None : LoadOneofCase.Pareto; + } + } + + private object load_; + public enum LoadOneofCase { + None = 0, + ClosedLoop = 1, + Poisson = 2, + Uniform = 3, + Determ = 4, + Pareto = 5, + } + private LoadOneofCase loadCase_ = LoadOneofCase.None; + public LoadOneofCase LoadCase { + get { return loadCase_; } + } + + public void ClearLoad() { + loadCase_ = LoadOneofCase.None; + load_ = null; + } + + public override bool Equals(object other) { + return Equals(other as LoadParams); + } + + public bool Equals(LoadParams other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(ClosedLoop, other.ClosedLoop)) return false; + if (!object.Equals(Poisson, other.Poisson)) return false; + if (!object.Equals(Uniform, other.Uniform)) return false; + if (!object.Equals(Determ, other.Determ)) return false; + if (!object.Equals(Pareto, other.Pareto)) return false; + return true; + } + + public override int GetHashCode() { + int hash = 1; + if (loadCase_ == LoadOneofCase.ClosedLoop) hash ^= ClosedLoop.GetHashCode(); + if (loadCase_ == LoadOneofCase.Poisson) hash ^= Poisson.GetHashCode(); + if (loadCase_ == LoadOneofCase.Uniform) hash ^= Uniform.GetHashCode(); + if (loadCase_ == LoadOneofCase.Determ) hash ^= Determ.GetHashCode(); + if (loadCase_ == LoadOneofCase.Pareto) hash ^= Pareto.GetHashCode(); + return hash; + } + + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); + } + + public void WriteTo(pb::CodedOutputStream output) { + if (loadCase_ == LoadOneofCase.ClosedLoop) { + output.WriteRawTag(10); + output.WriteMessage(ClosedLoop); + } + if (loadCase_ == LoadOneofCase.Poisson) { + output.WriteRawTag(18); + output.WriteMessage(Poisson); + } + if (loadCase_ == LoadOneofCase.Uniform) { + output.WriteRawTag(26); + output.WriteMessage(Uniform); + } + if (loadCase_ == LoadOneofCase.Determ) { + output.WriteRawTag(34); + output.WriteMessage(Determ); + } + if (loadCase_ == LoadOneofCase.Pareto) { + output.WriteRawTag(42); + output.WriteMessage(Pareto); + } + } + + public int CalculateSize() { + int size = 0; + if (loadCase_ == LoadOneofCase.ClosedLoop) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ClosedLoop); + } + if (loadCase_ == LoadOneofCase.Poisson) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Poisson); + } + if (loadCase_ == LoadOneofCase.Uniform) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Uniform); + } + if (loadCase_ == LoadOneofCase.Determ) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Determ); + } + if (loadCase_ == LoadOneofCase.Pareto) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Pareto); + } + return size; + } + + public void MergeFrom(LoadParams other) { + if (other == null) { + return; + } + switch (other.LoadCase) { + case LoadOneofCase.ClosedLoop: + ClosedLoop = other.ClosedLoop; + break; + case LoadOneofCase.Poisson: + Poisson = other.Poisson; + break; + case LoadOneofCase.Uniform: + Uniform = other.Uniform; + break; + case LoadOneofCase.Determ: + Determ = other.Determ; + break; + case LoadOneofCase.Pareto: + Pareto = other.Pareto; + break; + } + + } + + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 10: { + global::Grpc.Testing.ClosedLoopParams subBuilder = new global::Grpc.Testing.ClosedLoopParams(); + if (loadCase_ == LoadOneofCase.ClosedLoop) { + subBuilder.MergeFrom(ClosedLoop); + } + input.ReadMessage(subBuilder); + ClosedLoop = subBuilder; + break; + } + case 18: { + global::Grpc.Testing.PoissonParams subBuilder = new global::Grpc.Testing.PoissonParams(); + if (loadCase_ == LoadOneofCase.Poisson) { + subBuilder.MergeFrom(Poisson); + } + input.ReadMessage(subBuilder); + Poisson = subBuilder; + break; + } + case 26: { + global::Grpc.Testing.UniformParams subBuilder = new global::Grpc.Testing.UniformParams(); + if (loadCase_ == LoadOneofCase.Uniform) { + subBuilder.MergeFrom(Uniform); + } + input.ReadMessage(subBuilder); + Uniform = subBuilder; + break; + } + case 34: { + global::Grpc.Testing.DeterministicParams subBuilder = new global::Grpc.Testing.DeterministicParams(); + if (loadCase_ == LoadOneofCase.Determ) { + subBuilder.MergeFrom(Determ); + } + input.ReadMessage(subBuilder); + Determ = subBuilder; + break; + } + case 42: { + global::Grpc.Testing.ParetoParams subBuilder = new global::Grpc.Testing.ParetoParams(); + if (loadCase_ == LoadOneofCase.Pareto) { + subBuilder.MergeFrom(Pareto); + } + input.ReadMessage(subBuilder); + Pareto = subBuilder; + break; + } + } + } + } + + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class SecurityParams : pb::IMessage<SecurityParams> { + private static readonly pb::MessageParser<SecurityParams> _parser = new pb::MessageParser<SecurityParams>(() => new SecurityParams()); + public static pb::MessageParser<SecurityParams> Parser { get { return _parser; } } + + public static pbr::MessageDescriptor Descriptor { + get { return global::Grpc.Testing.Control.Descriptor.MessageTypes[6]; } + } + + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + public SecurityParams() { + OnConstruction(); + } + + partial void OnConstruction(); + + public SecurityParams(SecurityParams other) : this() { + useTestCa_ = other.useTestCa_; + serverHostOverride_ = other.serverHostOverride_; + } + + public SecurityParams Clone() { + return new SecurityParams(this); + } + + public const int UseTestCaFieldNumber = 1; + private bool useTestCa_; + public bool UseTestCa { + get { return useTestCa_; } + set { + useTestCa_ = value; + } + } + + public const int ServerHostOverrideFieldNumber = 2; + private string serverHostOverride_ = ""; + public string ServerHostOverride { + get { return serverHostOverride_; } + set { + serverHostOverride_ = pb::Preconditions.CheckNotNull(value, "value"); + } + } + + public override bool Equals(object other) { + return Equals(other as SecurityParams); + } + + public bool Equals(SecurityParams other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (UseTestCa != other.UseTestCa) return false; + if (ServerHostOverride != other.ServerHostOverride) return false; + return true; + } + + public override int GetHashCode() { + int hash = 1; + if (UseTestCa != false) hash ^= UseTestCa.GetHashCode(); + if (ServerHostOverride.Length != 0) hash ^= ServerHostOverride.GetHashCode(); + return hash; + } + + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); + } + + public void WriteTo(pb::CodedOutputStream output) { + if (UseTestCa != false) { + output.WriteRawTag(8); + output.WriteBool(UseTestCa); + } + if (ServerHostOverride.Length != 0) { + output.WriteRawTag(18); + output.WriteString(ServerHostOverride); + } + } + + public int CalculateSize() { + int size = 0; + if (UseTestCa != false) { + size += 1 + 1; + } + if (ServerHostOverride.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(ServerHostOverride); + } + return size; + } + + public void MergeFrom(SecurityParams other) { + if (other == null) { + return; + } + if (other.UseTestCa != false) { + UseTestCa = other.UseTestCa; + } + if (other.ServerHostOverride.Length != 0) { + ServerHostOverride = other.ServerHostOverride; + } + } + + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 8: { + UseTestCa = input.ReadBool(); + break; + } + case 18: { + ServerHostOverride = input.ReadString(); + break; + } + } + } + } + + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class ClientConfig : pb::IMessage<ClientConfig> { + private static readonly pb::MessageParser<ClientConfig> _parser = new pb::MessageParser<ClientConfig>(() => new ClientConfig()); + public static pb::MessageParser<ClientConfig> Parser { get { return _parser; } } + + public static pbr::MessageDescriptor Descriptor { + get { return global::Grpc.Testing.Control.Descriptor.MessageTypes[7]; } + } + + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + public ClientConfig() { + OnConstruction(); + } + + partial void OnConstruction(); + + public ClientConfig(ClientConfig other) : this() { + serverTargets_ = other.serverTargets_.Clone(); + clientType_ = other.clientType_; + SecurityParams = other.securityParams_ != null ? other.SecurityParams.Clone() : null; + outstandingRpcsPerChannel_ = other.outstandingRpcsPerChannel_; + clientChannels_ = other.clientChannels_; + asyncClientThreads_ = other.asyncClientThreads_; + rpcType_ = other.rpcType_; + LoadParams = other.loadParams_ != null ? other.LoadParams.Clone() : null; + PayloadConfig = other.payloadConfig_ != null ? other.PayloadConfig.Clone() : null; + HistogramParams = other.histogramParams_ != null ? other.HistogramParams.Clone() : null; + } + + public ClientConfig Clone() { + return new ClientConfig(this); + } + + public const int ServerTargetsFieldNumber = 1; + private static readonly pb::FieldCodec<string> _repeated_serverTargets_codec + = pb::FieldCodec.ForString(10); + private readonly pbc::RepeatedField<string> serverTargets_ = new pbc::RepeatedField<string>(); + public pbc::RepeatedField<string> ServerTargets { + get { return serverTargets_; } + } + + public const int ClientTypeFieldNumber = 2; + private global::Grpc.Testing.ClientType clientType_ = global::Grpc.Testing.ClientType.SYNC_CLIENT; + public global::Grpc.Testing.ClientType ClientType { + get { return clientType_; } + set { + clientType_ = value; + } + } + + public const int SecurityParamsFieldNumber = 3; + private global::Grpc.Testing.SecurityParams securityParams_; + public global::Grpc.Testing.SecurityParams SecurityParams { + get { return securityParams_; } + set { + securityParams_ = value; + } + } + + public const int OutstandingRpcsPerChannelFieldNumber = 4; + private int outstandingRpcsPerChannel_; + public int OutstandingRpcsPerChannel { + get { return outstandingRpcsPerChannel_; } + set { + outstandingRpcsPerChannel_ = value; + } + } + + public const int ClientChannelsFieldNumber = 5; + private int clientChannels_; + public int ClientChannels { + get { return clientChannels_; } + set { + clientChannels_ = value; + } + } + + public const int AsyncClientThreadsFieldNumber = 7; + private int asyncClientThreads_; + public int AsyncClientThreads { + get { return asyncClientThreads_; } + set { + asyncClientThreads_ = value; + } + } + + public const int RpcTypeFieldNumber = 8; + private global::Grpc.Testing.RpcType rpcType_ = global::Grpc.Testing.RpcType.UNARY; + public global::Grpc.Testing.RpcType RpcType { + get { return rpcType_; } + set { + rpcType_ = value; + } + } + + public const int LoadParamsFieldNumber = 10; + private global::Grpc.Testing.LoadParams loadParams_; + public global::Grpc.Testing.LoadParams LoadParams { + get { return loadParams_; } + set { + loadParams_ = value; + } + } + + public const int PayloadConfigFieldNumber = 11; + private global::Grpc.Testing.PayloadConfig payloadConfig_; + public global::Grpc.Testing.PayloadConfig PayloadConfig { + get { return payloadConfig_; } + set { + payloadConfig_ = value; + } + } + + public const int HistogramParamsFieldNumber = 12; + private global::Grpc.Testing.HistogramParams histogramParams_; + public global::Grpc.Testing.HistogramParams HistogramParams { + get { return histogramParams_; } + set { + histogramParams_ = value; + } + } + + public override bool Equals(object other) { + return Equals(other as ClientConfig); + } + + public bool Equals(ClientConfig other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!serverTargets_.Equals(other.serverTargets_)) return false; + if (ClientType != other.ClientType) return false; + if (!object.Equals(SecurityParams, other.SecurityParams)) return false; + if (OutstandingRpcsPerChannel != other.OutstandingRpcsPerChannel) return false; + if (ClientChannels != other.ClientChannels) return false; + if (AsyncClientThreads != other.AsyncClientThreads) return false; + if (RpcType != other.RpcType) return false; + if (!object.Equals(LoadParams, other.LoadParams)) return false; + if (!object.Equals(PayloadConfig, other.PayloadConfig)) return false; + if (!object.Equals(HistogramParams, other.HistogramParams)) return false; + return true; + } + + public override int GetHashCode() { + int hash = 1; + hash ^= serverTargets_.GetHashCode(); + if (ClientType != global::Grpc.Testing.ClientType.SYNC_CLIENT) hash ^= ClientType.GetHashCode(); + if (securityParams_ != null) hash ^= SecurityParams.GetHashCode(); + if (OutstandingRpcsPerChannel != 0) hash ^= OutstandingRpcsPerChannel.GetHashCode(); + if (ClientChannels != 0) hash ^= ClientChannels.GetHashCode(); + if (AsyncClientThreads != 0) hash ^= AsyncClientThreads.GetHashCode(); + if (RpcType != global::Grpc.Testing.RpcType.UNARY) hash ^= RpcType.GetHashCode(); + if (loadParams_ != null) hash ^= LoadParams.GetHashCode(); + if (payloadConfig_ != null) hash ^= PayloadConfig.GetHashCode(); + if (histogramParams_ != null) hash ^= HistogramParams.GetHashCode(); + return hash; + } + + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); + } + + public void WriteTo(pb::CodedOutputStream output) { + serverTargets_.WriteTo(output, _repeated_serverTargets_codec); + if (ClientType != global::Grpc.Testing.ClientType.SYNC_CLIENT) { + output.WriteRawTag(16); + output.WriteEnum((int) ClientType); + } + if (securityParams_ != null) { + output.WriteRawTag(26); + output.WriteMessage(SecurityParams); + } + if (OutstandingRpcsPerChannel != 0) { + output.WriteRawTag(32); + output.WriteInt32(OutstandingRpcsPerChannel); + } + if (ClientChannels != 0) { + output.WriteRawTag(40); + output.WriteInt32(ClientChannels); + } + if (AsyncClientThreads != 0) { + output.WriteRawTag(56); + output.WriteInt32(AsyncClientThreads); + } + if (RpcType != global::Grpc.Testing.RpcType.UNARY) { + output.WriteRawTag(64); + output.WriteEnum((int) RpcType); + } + if (loadParams_ != null) { + output.WriteRawTag(82); + output.WriteMessage(LoadParams); + } + if (payloadConfig_ != null) { + output.WriteRawTag(90); + output.WriteMessage(PayloadConfig); + } + if (histogramParams_ != null) { + output.WriteRawTag(98); + output.WriteMessage(HistogramParams); + } + } + + public int CalculateSize() { + int size = 0; + size += serverTargets_.CalculateSize(_repeated_serverTargets_codec); + if (ClientType != global::Grpc.Testing.ClientType.SYNC_CLIENT) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) ClientType); + } + if (securityParams_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(SecurityParams); + } + if (OutstandingRpcsPerChannel != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(OutstandingRpcsPerChannel); + } + if (ClientChannels != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ClientChannels); + } + if (AsyncClientThreads != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(AsyncClientThreads); + } + if (RpcType != global::Grpc.Testing.RpcType.UNARY) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) RpcType); + } + if (loadParams_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(LoadParams); + } + if (payloadConfig_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(PayloadConfig); + } + if (histogramParams_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(HistogramParams); + } + return size; + } + + public void MergeFrom(ClientConfig other) { + if (other == null) { + return; + } + serverTargets_.Add(other.serverTargets_); + if (other.ClientType != global::Grpc.Testing.ClientType.SYNC_CLIENT) { + ClientType = other.ClientType; + } + if (other.securityParams_ != null) { + if (securityParams_ == null) { + securityParams_ = new global::Grpc.Testing.SecurityParams(); + } + SecurityParams.MergeFrom(other.SecurityParams); + } + if (other.OutstandingRpcsPerChannel != 0) { + OutstandingRpcsPerChannel = other.OutstandingRpcsPerChannel; + } + if (other.ClientChannels != 0) { + ClientChannels = other.ClientChannels; + } + if (other.AsyncClientThreads != 0) { + AsyncClientThreads = other.AsyncClientThreads; + } + if (other.RpcType != global::Grpc.Testing.RpcType.UNARY) { + RpcType = other.RpcType; + } + if (other.loadParams_ != null) { + if (loadParams_ == null) { + loadParams_ = new global::Grpc.Testing.LoadParams(); + } + LoadParams.MergeFrom(other.LoadParams); + } + if (other.payloadConfig_ != null) { + if (payloadConfig_ == null) { + payloadConfig_ = new global::Grpc.Testing.PayloadConfig(); + } + PayloadConfig.MergeFrom(other.PayloadConfig); + } + if (other.histogramParams_ != null) { + if (histogramParams_ == null) { + histogramParams_ = new global::Grpc.Testing.HistogramParams(); + } + HistogramParams.MergeFrom(other.HistogramParams); + } + } + + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 10: { + serverTargets_.AddEntriesFrom(input, _repeated_serverTargets_codec); + break; + } + case 16: { + clientType_ = (global::Grpc.Testing.ClientType) input.ReadEnum(); + break; + } + case 26: { + if (securityParams_ == null) { + securityParams_ = new global::Grpc.Testing.SecurityParams(); + } + input.ReadMessage(securityParams_); + break; + } + case 32: { + OutstandingRpcsPerChannel = input.ReadInt32(); + break; + } + case 40: { + ClientChannels = input.ReadInt32(); + break; + } + case 56: { + AsyncClientThreads = input.ReadInt32(); + break; + } + case 64: { + rpcType_ = (global::Grpc.Testing.RpcType) input.ReadEnum(); + break; + } + case 82: { + if (loadParams_ == null) { + loadParams_ = new global::Grpc.Testing.LoadParams(); + } + input.ReadMessage(loadParams_); + break; + } + case 90: { + if (payloadConfig_ == null) { + payloadConfig_ = new global::Grpc.Testing.PayloadConfig(); + } + input.ReadMessage(payloadConfig_); + break; + } + case 98: { + if (histogramParams_ == null) { + histogramParams_ = new global::Grpc.Testing.HistogramParams(); + } + input.ReadMessage(histogramParams_); + break; + } + } + } + } + + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class ClientStatus : pb::IMessage<ClientStatus> { + private static readonly pb::MessageParser<ClientStatus> _parser = new pb::MessageParser<ClientStatus>(() => new ClientStatus()); + public static pb::MessageParser<ClientStatus> Parser { get { return _parser; } } + + public static pbr::MessageDescriptor Descriptor { + get { return global::Grpc.Testing.Control.Descriptor.MessageTypes[8]; } + } + + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + public ClientStatus() { + OnConstruction(); + } + + partial void OnConstruction(); + + public ClientStatus(ClientStatus other) : this() { + Stats = other.stats_ != null ? other.Stats.Clone() : null; + } + + public ClientStatus Clone() { + return new ClientStatus(this); + } + + public const int StatsFieldNumber = 1; + private global::Grpc.Testing.ClientStats stats_; + public global::Grpc.Testing.ClientStats Stats { + get { return stats_; } + set { + stats_ = value; + } + } + + public override bool Equals(object other) { + return Equals(other as ClientStatus); + } + + public bool Equals(ClientStatus other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Stats, other.Stats)) return false; + return true; + } + + public override int GetHashCode() { + int hash = 1; + if (stats_ != null) hash ^= Stats.GetHashCode(); + return hash; + } + + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); + } + + public void WriteTo(pb::CodedOutputStream output) { + if (stats_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Stats); + } + } + + public int CalculateSize() { + int size = 0; + if (stats_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Stats); + } + return size; + } + + public void MergeFrom(ClientStatus other) { + if (other == null) { + return; + } + if (other.stats_ != null) { + if (stats_ == null) { + stats_ = new global::Grpc.Testing.ClientStats(); + } + Stats.MergeFrom(other.Stats); + } + } + + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 10: { + if (stats_ == null) { + stats_ = new global::Grpc.Testing.ClientStats(); + } + input.ReadMessage(stats_); + break; + } + } + } + } + + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class Mark : pb::IMessage<Mark> { + private static readonly pb::MessageParser<Mark> _parser = new pb::MessageParser<Mark>(() => new Mark()); + public static pb::MessageParser<Mark> Parser { get { return _parser; } } + + public static pbr::MessageDescriptor Descriptor { + get { return global::Grpc.Testing.Control.Descriptor.MessageTypes[9]; } + } + + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + public Mark() { + OnConstruction(); + } + + partial void OnConstruction(); + + public Mark(Mark other) : this() { + reset_ = other.reset_; + } + + public Mark Clone() { + return new Mark(this); + } + + public const int ResetFieldNumber = 1; + private bool reset_; + public bool Reset { + get { return reset_; } + set { + reset_ = value; + } + } + + public override bool Equals(object other) { + return Equals(other as Mark); + } + + public bool Equals(Mark other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Reset != other.Reset) return false; + return true; + } + + public override int GetHashCode() { + int hash = 1; + if (Reset != false) hash ^= Reset.GetHashCode(); + return hash; + } + + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); + } + + public void WriteTo(pb::CodedOutputStream output) { + if (Reset != false) { + output.WriteRawTag(8); + output.WriteBool(Reset); + } + } + + public int CalculateSize() { + int size = 0; + if (Reset != false) { + size += 1 + 1; + } + return size; + } + + public void MergeFrom(Mark other) { + if (other == null) { + return; + } + if (other.Reset != false) { + Reset = other.Reset; + } + } + + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 8: { + Reset = input.ReadBool(); + break; + } + } + } + } + + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class ClientArgs : pb::IMessage<ClientArgs> { + private static readonly pb::MessageParser<ClientArgs> _parser = new pb::MessageParser<ClientArgs>(() => new ClientArgs()); + public static pb::MessageParser<ClientArgs> Parser { get { return _parser; } } + + public static pbr::MessageDescriptor Descriptor { + get { return global::Grpc.Testing.Control.Descriptor.MessageTypes[10]; } + } + + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + public ClientArgs() { + OnConstruction(); + } + + partial void OnConstruction(); + + public ClientArgs(ClientArgs other) : this() { + switch (other.ArgtypeCase) { + case ArgtypeOneofCase.Setup: + Setup = other.Setup.Clone(); + break; + case ArgtypeOneofCase.Mark: + Mark = other.Mark.Clone(); + break; + } + + } + + public ClientArgs Clone() { + return new ClientArgs(this); + } + + public const int SetupFieldNumber = 1; + public global::Grpc.Testing.ClientConfig Setup { + get { return argtypeCase_ == ArgtypeOneofCase.Setup ? (global::Grpc.Testing.ClientConfig) argtype_ : null; } + set { + argtype_ = value; + argtypeCase_ = value == null ? ArgtypeOneofCase.None : ArgtypeOneofCase.Setup; + } + } + + public const int MarkFieldNumber = 2; + public global::Grpc.Testing.Mark Mark { + get { return argtypeCase_ == ArgtypeOneofCase.Mark ? (global::Grpc.Testing.Mark) argtype_ : null; } + set { + argtype_ = value; + argtypeCase_ = value == null ? ArgtypeOneofCase.None : ArgtypeOneofCase.Mark; + } + } + + private object argtype_; + public enum ArgtypeOneofCase { + None = 0, + Setup = 1, + Mark = 2, + } + private ArgtypeOneofCase argtypeCase_ = ArgtypeOneofCase.None; + public ArgtypeOneofCase ArgtypeCase { + get { return argtypeCase_; } + } + + public void ClearArgtype() { + argtypeCase_ = ArgtypeOneofCase.None; + argtype_ = null; + } + + public override bool Equals(object other) { + return Equals(other as ClientArgs); + } + + public bool Equals(ClientArgs other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Setup, other.Setup)) return false; + if (!object.Equals(Mark, other.Mark)) return false; + return true; + } + + public override int GetHashCode() { + int hash = 1; + if (argtypeCase_ == ArgtypeOneofCase.Setup) hash ^= Setup.GetHashCode(); + if (argtypeCase_ == ArgtypeOneofCase.Mark) hash ^= Mark.GetHashCode(); + return hash; + } + + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); + } + + public void WriteTo(pb::CodedOutputStream output) { + if (argtypeCase_ == ArgtypeOneofCase.Setup) { + output.WriteRawTag(10); + output.WriteMessage(Setup); + } + if (argtypeCase_ == ArgtypeOneofCase.Mark) { + output.WriteRawTag(18); + output.WriteMessage(Mark); + } + } + + public int CalculateSize() { + int size = 0; + if (argtypeCase_ == ArgtypeOneofCase.Setup) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Setup); + } + if (argtypeCase_ == ArgtypeOneofCase.Mark) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Mark); + } + return size; + } + + public void MergeFrom(ClientArgs other) { + if (other == null) { + return; + } + switch (other.ArgtypeCase) { + case ArgtypeOneofCase.Setup: + Setup = other.Setup; + break; + case ArgtypeOneofCase.Mark: + Mark = other.Mark; + break; + } + + } + + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 10: { + global::Grpc.Testing.ClientConfig subBuilder = new global::Grpc.Testing.ClientConfig(); + if (argtypeCase_ == ArgtypeOneofCase.Setup) { + subBuilder.MergeFrom(Setup); + } + input.ReadMessage(subBuilder); + Setup = subBuilder; + break; + } + case 18: { + global::Grpc.Testing.Mark subBuilder = new global::Grpc.Testing.Mark(); + if (argtypeCase_ == ArgtypeOneofCase.Mark) { + subBuilder.MergeFrom(Mark); + } + input.ReadMessage(subBuilder); + Mark = subBuilder; + break; + } + } + } + } + + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class ServerConfig : pb::IMessage<ServerConfig> { + private static readonly pb::MessageParser<ServerConfig> _parser = new pb::MessageParser<ServerConfig>(() => new ServerConfig()); + public static pb::MessageParser<ServerConfig> Parser { get { return _parser; } } + + public static pbr::MessageDescriptor Descriptor { + get { return global::Grpc.Testing.Control.Descriptor.MessageTypes[11]; } + } + + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + public ServerConfig() { + OnConstruction(); + } + + partial void OnConstruction(); + + public ServerConfig(ServerConfig other) : this() { + serverType_ = other.serverType_; + SecurityParams = other.securityParams_ != null ? other.SecurityParams.Clone() : null; + host_ = other.host_; + port_ = other.port_; + asyncServerThreads_ = other.asyncServerThreads_; + coreLimit_ = other.coreLimit_; + PayloadConfig = other.payloadConfig_ != null ? other.PayloadConfig.Clone() : null; + } + + public ServerConfig Clone() { + return new ServerConfig(this); + } + + public const int ServerTypeFieldNumber = 1; + private global::Grpc.Testing.ServerType serverType_ = global::Grpc.Testing.ServerType.SYNC_SERVER; + public global::Grpc.Testing.ServerType ServerType { + get { return serverType_; } + set { + serverType_ = value; + } + } + + public const int SecurityParamsFieldNumber = 2; + private global::Grpc.Testing.SecurityParams securityParams_; + public global::Grpc.Testing.SecurityParams SecurityParams { + get { return securityParams_; } + set { + securityParams_ = value; + } + } + + public const int HostFieldNumber = 3; + private string host_ = ""; + public string Host { + get { return host_; } + set { + host_ = pb::Preconditions.CheckNotNull(value, "value"); + } + } + + public const int PortFieldNumber = 4; + private int port_; + public int Port { + get { return port_; } + set { + port_ = value; + } + } + + public const int AsyncServerThreadsFieldNumber = 7; + private int asyncServerThreads_; + public int AsyncServerThreads { + get { return asyncServerThreads_; } + set { + asyncServerThreads_ = value; + } + } + + public const int CoreLimitFieldNumber = 8; + private int coreLimit_; + public int CoreLimit { + get { return coreLimit_; } + set { + coreLimit_ = value; + } + } + + public const int PayloadConfigFieldNumber = 9; + private global::Grpc.Testing.PayloadConfig payloadConfig_; + public global::Grpc.Testing.PayloadConfig PayloadConfig { + get { return payloadConfig_; } + set { + payloadConfig_ = value; + } + } + + public override bool Equals(object other) { + return Equals(other as ServerConfig); + } + + public bool Equals(ServerConfig other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (ServerType != other.ServerType) return false; + if (!object.Equals(SecurityParams, other.SecurityParams)) return false; + if (Host != other.Host) return false; + if (Port != other.Port) return false; + if (AsyncServerThreads != other.AsyncServerThreads) return false; + if (CoreLimit != other.CoreLimit) return false; + if (!object.Equals(PayloadConfig, other.PayloadConfig)) return false; + return true; + } + + public override int GetHashCode() { + int hash = 1; + if (ServerType != global::Grpc.Testing.ServerType.SYNC_SERVER) hash ^= ServerType.GetHashCode(); + if (securityParams_ != null) hash ^= SecurityParams.GetHashCode(); + if (Host.Length != 0) hash ^= Host.GetHashCode(); + if (Port != 0) hash ^= Port.GetHashCode(); + if (AsyncServerThreads != 0) hash ^= AsyncServerThreads.GetHashCode(); + if (CoreLimit != 0) hash ^= CoreLimit.GetHashCode(); + if (payloadConfig_ != null) hash ^= PayloadConfig.GetHashCode(); + return hash; + } + + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); + } + + public void WriteTo(pb::CodedOutputStream output) { + if (ServerType != global::Grpc.Testing.ServerType.SYNC_SERVER) { + output.WriteRawTag(8); + output.WriteEnum((int) ServerType); + } + if (securityParams_ != null) { + output.WriteRawTag(18); + output.WriteMessage(SecurityParams); + } + if (Host.Length != 0) { + output.WriteRawTag(26); + output.WriteString(Host); + } + if (Port != 0) { + output.WriteRawTag(32); + output.WriteInt32(Port); + } + if (AsyncServerThreads != 0) { + output.WriteRawTag(56); + output.WriteInt32(AsyncServerThreads); + } + if (CoreLimit != 0) { + output.WriteRawTag(64); + output.WriteInt32(CoreLimit); + } + if (payloadConfig_ != null) { + output.WriteRawTag(74); + output.WriteMessage(PayloadConfig); + } + } + + public int CalculateSize() { + int size = 0; + if (ServerType != global::Grpc.Testing.ServerType.SYNC_SERVER) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) ServerType); + } + if (securityParams_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(SecurityParams); + } + if (Host.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Host); + } + if (Port != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Port); + } + if (AsyncServerThreads != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(AsyncServerThreads); + } + if (CoreLimit != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(CoreLimit); + } + if (payloadConfig_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(PayloadConfig); + } + return size; + } + + public void MergeFrom(ServerConfig other) { + if (other == null) { + return; + } + if (other.ServerType != global::Grpc.Testing.ServerType.SYNC_SERVER) { + ServerType = other.ServerType; + } + if (other.securityParams_ != null) { + if (securityParams_ == null) { + securityParams_ = new global::Grpc.Testing.SecurityParams(); + } + SecurityParams.MergeFrom(other.SecurityParams); + } + if (other.Host.Length != 0) { + Host = other.Host; + } + if (other.Port != 0) { + Port = other.Port; + } + if (other.AsyncServerThreads != 0) { + AsyncServerThreads = other.AsyncServerThreads; + } + if (other.CoreLimit != 0) { + CoreLimit = other.CoreLimit; + } + if (other.payloadConfig_ != null) { + if (payloadConfig_ == null) { + payloadConfig_ = new global::Grpc.Testing.PayloadConfig(); + } + PayloadConfig.MergeFrom(other.PayloadConfig); + } + } + + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 8: { + serverType_ = (global::Grpc.Testing.ServerType) input.ReadEnum(); + break; + } + case 18: { + if (securityParams_ == null) { + securityParams_ = new global::Grpc.Testing.SecurityParams(); + } + input.ReadMessage(securityParams_); + break; + } + case 26: { + Host = input.ReadString(); + break; + } + case 32: { + Port = input.ReadInt32(); + break; + } + case 56: { + AsyncServerThreads = input.ReadInt32(); + break; + } + case 64: { + CoreLimit = input.ReadInt32(); + break; + } + case 74: { + if (payloadConfig_ == null) { + payloadConfig_ = new global::Grpc.Testing.PayloadConfig(); + } + input.ReadMessage(payloadConfig_); + break; + } + } + } + } + + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class ServerArgs : pb::IMessage<ServerArgs> { + private static readonly pb::MessageParser<ServerArgs> _parser = new pb::MessageParser<ServerArgs>(() => new ServerArgs()); + public static pb::MessageParser<ServerArgs> Parser { get { return _parser; } } + + public static pbr::MessageDescriptor Descriptor { + get { return global::Grpc.Testing.Control.Descriptor.MessageTypes[12]; } + } + + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + public ServerArgs() { + OnConstruction(); + } + + partial void OnConstruction(); + + public ServerArgs(ServerArgs other) : this() { + switch (other.ArgtypeCase) { + case ArgtypeOneofCase.Setup: + Setup = other.Setup.Clone(); + break; + case ArgtypeOneofCase.Mark: + Mark = other.Mark.Clone(); + break; + } + + } + + public ServerArgs Clone() { + return new ServerArgs(this); + } + + public const int SetupFieldNumber = 1; + public global::Grpc.Testing.ServerConfig Setup { + get { return argtypeCase_ == ArgtypeOneofCase.Setup ? (global::Grpc.Testing.ServerConfig) argtype_ : null; } + set { + argtype_ = value; + argtypeCase_ = value == null ? ArgtypeOneofCase.None : ArgtypeOneofCase.Setup; + } + } + + public const int MarkFieldNumber = 2; + public global::Grpc.Testing.Mark Mark { + get { return argtypeCase_ == ArgtypeOneofCase.Mark ? (global::Grpc.Testing.Mark) argtype_ : null; } + set { + argtype_ = value; + argtypeCase_ = value == null ? ArgtypeOneofCase.None : ArgtypeOneofCase.Mark; + } + } + + private object argtype_; + public enum ArgtypeOneofCase { + None = 0, + Setup = 1, + Mark = 2, + } + private ArgtypeOneofCase argtypeCase_ = ArgtypeOneofCase.None; + public ArgtypeOneofCase ArgtypeCase { + get { return argtypeCase_; } + } + + public void ClearArgtype() { + argtypeCase_ = ArgtypeOneofCase.None; + argtype_ = null; + } + + public override bool Equals(object other) { + return Equals(other as ServerArgs); + } + + public bool Equals(ServerArgs other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Setup, other.Setup)) return false; + if (!object.Equals(Mark, other.Mark)) return false; + return true; + } + + public override int GetHashCode() { + int hash = 1; + if (argtypeCase_ == ArgtypeOneofCase.Setup) hash ^= Setup.GetHashCode(); + if (argtypeCase_ == ArgtypeOneofCase.Mark) hash ^= Mark.GetHashCode(); + return hash; + } + + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); + } + + public void WriteTo(pb::CodedOutputStream output) { + if (argtypeCase_ == ArgtypeOneofCase.Setup) { + output.WriteRawTag(10); + output.WriteMessage(Setup); + } + if (argtypeCase_ == ArgtypeOneofCase.Mark) { + output.WriteRawTag(18); + output.WriteMessage(Mark); + } + } + + public int CalculateSize() { + int size = 0; + if (argtypeCase_ == ArgtypeOneofCase.Setup) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Setup); + } + if (argtypeCase_ == ArgtypeOneofCase.Mark) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Mark); + } + return size; + } + + public void MergeFrom(ServerArgs other) { + if (other == null) { + return; + } + switch (other.ArgtypeCase) { + case ArgtypeOneofCase.Setup: + Setup = other.Setup; + break; + case ArgtypeOneofCase.Mark: + Mark = other.Mark; + break; + } + + } + + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 10: { + global::Grpc.Testing.ServerConfig subBuilder = new global::Grpc.Testing.ServerConfig(); + if (argtypeCase_ == ArgtypeOneofCase.Setup) { + subBuilder.MergeFrom(Setup); + } + input.ReadMessage(subBuilder); + Setup = subBuilder; + break; + } + case 18: { + global::Grpc.Testing.Mark subBuilder = new global::Grpc.Testing.Mark(); + if (argtypeCase_ == ArgtypeOneofCase.Mark) { + subBuilder.MergeFrom(Mark); + } + input.ReadMessage(subBuilder); + Mark = subBuilder; + break; + } + } + } + } + + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class ServerStatus : pb::IMessage<ServerStatus> { + private static readonly pb::MessageParser<ServerStatus> _parser = new pb::MessageParser<ServerStatus>(() => new ServerStatus()); + public static pb::MessageParser<ServerStatus> Parser { get { return _parser; } } + + public static pbr::MessageDescriptor Descriptor { + get { return global::Grpc.Testing.Control.Descriptor.MessageTypes[13]; } + } + + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + public ServerStatus() { + OnConstruction(); + } + + partial void OnConstruction(); + + public ServerStatus(ServerStatus other) : this() { + Stats = other.stats_ != null ? other.Stats.Clone() : null; + port_ = other.port_; + cores_ = other.cores_; + } + + public ServerStatus Clone() { + return new ServerStatus(this); + } + + public const int StatsFieldNumber = 1; + private global::Grpc.Testing.ServerStats stats_; + public global::Grpc.Testing.ServerStats Stats { + get { return stats_; } + set { + stats_ = value; + } + } + + public const int PortFieldNumber = 2; + private int port_; + public int Port { + get { return port_; } + set { + port_ = value; + } + } + + public const int CoresFieldNumber = 3; + private int cores_; + public int Cores { + get { return cores_; } + set { + cores_ = value; + } + } + + public override bool Equals(object other) { + return Equals(other as ServerStatus); + } + + public bool Equals(ServerStatus other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Stats, other.Stats)) return false; + if (Port != other.Port) return false; + if (Cores != other.Cores) return false; + return true; + } + + public override int GetHashCode() { + int hash = 1; + if (stats_ != null) hash ^= Stats.GetHashCode(); + if (Port != 0) hash ^= Port.GetHashCode(); + if (Cores != 0) hash ^= Cores.GetHashCode(); + return hash; + } + + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); + } + + public void WriteTo(pb::CodedOutputStream output) { + if (stats_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Stats); + } + if (Port != 0) { + output.WriteRawTag(16); + output.WriteInt32(Port); + } + if (Cores != 0) { + output.WriteRawTag(24); + output.WriteInt32(Cores); + } + } + + public int CalculateSize() { + int size = 0; + if (stats_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Stats); + } + if (Port != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Port); + } + if (Cores != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Cores); + } + return size; + } + + public void MergeFrom(ServerStatus other) { + if (other == null) { + return; + } + if (other.stats_ != null) { + if (stats_ == null) { + stats_ = new global::Grpc.Testing.ServerStats(); + } + Stats.MergeFrom(other.Stats); + } + if (other.Port != 0) { + Port = other.Port; + } + if (other.Cores != 0) { + Cores = other.Cores; + } + } + + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 10: { + if (stats_ == null) { + stats_ = new global::Grpc.Testing.ServerStats(); + } + input.ReadMessage(stats_); + break; + } + case 16: { + Port = input.ReadInt32(); + break; + } + case 24: { + Cores = input.ReadInt32(); + break; + } + } + } + } + + } + + #endregion + +} + +#endregion Designer generated code diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj index 2b75305731..012de45524 100644 --- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj +++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj @@ -38,55 +38,46 @@ <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile> </PropertyGroup> <ItemGroup> - <Reference Include="BouncyCastle.Crypto, Version=1.7.4137.9688, Culture=neutral, PublicKeyToken=a4292a325f69b123, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> - <HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath> - </Reference> <Reference Include="CommandLine"> <HintPath>..\packages\CommandLineParser.1.9.71\lib\net45\CommandLine.dll</HintPath> </Reference> - <Reference Include="Google.Apis.Auth, Version=1.9.3.19379, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> + <Reference Include="nunit.framework"> + <HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="System.Interactive.Async"> + <HintPath>..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll</HintPath> + </Reference> + <Reference Include="System.Net" /> + <Reference Include="System.Net.Http" /> + <Reference Include="System.Net.Http.WebRequest" /> + <Reference Include="BouncyCastle.Crypto"> + <HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath> + </Reference> + <Reference Include="Google.Apis.Auth"> <HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.dll</HintPath> </Reference> - <Reference Include="Google.Apis.Auth.PlatformServices, Version=1.9.3.19383, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> + <Reference Include="Google.Apis.Auth.PlatformServices"> <HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath> </Reference> - <Reference Include="Google.Apis.Core, Version=1.9.3.19379, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> + <Reference Include="Google.Apis.Core"> <HintPath>..\packages\Google.Apis.Core.1.9.3\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath> </Reference> - <Reference Include="Google.Protobuf, Version=3.0.0.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> + <Reference Include="Google.Protobuf"> <HintPath>..\packages\Google.Protobuf.3.0.0-alpha4\lib\portable-net45+netcore45+wpa81+wp8\Google.Protobuf.dll</HintPath> </Reference> - <Reference Include="Microsoft.Threading.Tasks, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> + <Reference Include="Microsoft.Threading.Tasks"> <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath> </Reference> - <Reference Include="Microsoft.Threading.Tasks.Extensions, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> + <Reference Include="Microsoft.Threading.Tasks.Extensions"> <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath> </Reference> - <Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop, Version=1.0.168.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> + <Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop"> <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath> </Reference> - <Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> + <Reference Include="Newtonsoft.Json"> <HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath> </Reference> - <Reference Include="nunit.framework"> - <HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath> - </Reference> - <Reference Include="System" /> - <Reference Include="System.Interactive.Async"> - <HintPath>..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll</HintPath> - </Reference> - <Reference Include="System.Net" /> - <Reference Include="System.Net.Http" /> - <Reference Include="System.Net.Http.WebRequest" /> </ItemGroup> <ItemGroup> <Compile Include="..\Grpc.Core\Version.cs"> @@ -104,6 +95,22 @@ <Compile Include="TestGrpc.cs" /> <Compile Include="SslCredentialsTest.cs" /> <Compile Include="Test.cs" /> + <Compile Include="IClientRunner.cs" /> + <Compile Include="ClientRunners.cs" /> + <Compile Include="IServerRunner.cs" /> + <Compile Include="ServerRunners.cs" /> + <Compile Include="RunnerClientServerTest.cs" /> + <Compile Include="Control.cs" /> + <Compile Include="Payloads.cs" /> + <Compile Include="Services.cs" /> + <Compile Include="ServicesGrpc.cs" /> + <Compile Include="Stats.cs" /> + <Compile Include="BenchmarkServiceImpl.cs" /> + <Compile Include="Histogram.cs" /> + <Compile Include="HistogramTest.cs" /> + <Compile Include="WorkerServiceImpl.cs" /> + <Compile Include="QpsWorker.cs" /> + <Compile Include="WallClockStopwatch.cs" /> </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <ItemGroup> diff --git a/src/csharp/Grpc.IntegrationTesting/Histogram.cs b/src/csharp/Grpc.IntegrationTesting/Histogram.cs new file mode 100644 index 0000000000..7e7cb2c4de --- /dev/null +++ b/src/csharp/Grpc.IntegrationTesting/Histogram.cs @@ -0,0 +1,153 @@ +#region Copyright notice and license + +// 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. + +#endregion + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; +using Google.Protobuf; +using Grpc.Core; +using Grpc.Core.Utils; +using NUnit.Framework; +using Grpc.Testing; + +namespace Grpc.IntegrationTesting +{ + /// <summary> + /// Basic implementation of histogram based on grpc/support/histogram.h. + /// </summary> + public class Histogram + { + readonly object myLock = new object(); + readonly double multiplier; + readonly double oneOnLogMultiplier; + readonly double maxPossible; + readonly uint[] buckets; + + int count; + double sum; + double sumOfSquares; + double min; + double max; + + public Histogram(double resolution, double maxPossible) + { + Grpc.Core.Utils.Preconditions.CheckArgument(resolution > 0); + Grpc.Core.Utils.Preconditions.CheckArgument(maxPossible > 0); + this.maxPossible = maxPossible; + this.multiplier = 1.0 + resolution; + this.oneOnLogMultiplier = 1.0 / Math.Log(1.0 + resolution); + this.buckets = new uint[FindBucket(maxPossible) + 1]; + + ResetUnsafe(); + } + + public void AddObservation(double value) + { + lock (myLock) + { + AddObservationUnsafe(value); + } + } + + + /// <summary> + /// Gets snapshot of stats and reset + /// </summary> + public HistogramData GetSnapshot(bool reset = false) + { + lock (myLock) + { + return GetSnapshotUnsafe(reset); + } + } + + /// <summary> + /// Finds bucket index to which given observation should go. + /// </summary> + private int FindBucket(double value) + { + value = Math.Max(value, 1.0); + value = Math.Min(value, this.maxPossible); + return (int)(Math.Log(value) * oneOnLogMultiplier); + } + + private void AddObservationUnsafe(double value) + { + this.count++; + this.sum += value; + this.sumOfSquares += value * value; + this.min = Math.Min(this.min, value); + this.max = Math.Max(this.max, value); + + this.buckets[FindBucket(value)]++; + } + + private HistogramData GetSnapshotUnsafe(bool reset) + { + var data = new HistogramData + { + Count = count, + Sum = sum, + SumOfSquares = sumOfSquares, + MinSeen = min, + MaxSeen = max, + Bucket = { buckets } + }; + + if (reset) + { + ResetUnsafe(); + } + + return data; + } + + private void ResetUnsafe() + { + this.count = 0; + this.sum = 0; + this.sumOfSquares = 0; + this.min = double.PositiveInfinity; + this.max = double.NegativeInfinity; + for (int i = 0; i < this.buckets.Length; i++) + { + this.buckets[i] = 0; + } + } + } +} diff --git a/src/csharp/Grpc.IntegrationTesting/HistogramTest.cs b/src/csharp/Grpc.IntegrationTesting/HistogramTest.cs new file mode 100644 index 0000000000..fa160cbd15 --- /dev/null +++ b/src/csharp/Grpc.IntegrationTesting/HistogramTest.cs @@ -0,0 +1,104 @@ +#region Copyright notice and license + +// 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. + +#endregion + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Grpc.Core; +using Grpc.Core.Utils; +using Grpc.Testing; +using NUnit.Framework; + +namespace Grpc.IntegrationTesting +{ + public class HistogramTest + { + [Test] + public void Simple() + { + var hist = new Histogram(0.01, 60e9); + hist.AddObservation(10000); + hist.AddObservation(10000); + hist.AddObservation(11000); + hist.AddObservation(11000); + + var data = hist.GetSnapshot(); + + Assert.AreEqual(4, data.Count); + Assert.AreEqual(42000.0, data.Sum, 1e-6); + Assert.AreEqual(10000, data.MinSeen); + Assert.AreEqual(11000, data.MaxSeen); + Assert.AreEqual(2.0*10000*10000 + 2.0*11000*11000, data.SumOfSquares, 1e-6); + + // 1.01^925 < 10000 < 1.01^926 + Assert.AreEqual(2, data.Bucket[925]); + Assert.AreEqual(2, data.Bucket[935]); + } + + [Test] + public void ExtremeObservations() + { + var hist = new Histogram(0.01, 60e9); + hist.AddObservation(-0.5); // should be in the first bucket + hist.AddObservation(1e12); // should be in the last bucket + + var data = hist.GetSnapshot(); + Assert.AreEqual(1, data.Bucket[0]); + Assert.AreEqual(1, data.Bucket[data.Bucket.Count - 1]); + } + + [Test] + public void Reset() + { + var hist = new Histogram(0.01, 60e9); + hist.AddObservation(10000); + hist.AddObservation(11000); + + var data = hist.GetSnapshot(true); // snapshot contains data before reset + Assert.AreEqual(2, data.Count); + Assert.AreEqual(10000, data.MinSeen); + Assert.AreEqual(11000, data.MaxSeen); + + data = hist.GetSnapshot(); // snapshot contains state after reset + Assert.AreEqual(0, data.Count); + Assert.AreEqual(double.PositiveInfinity, data.MinSeen); + Assert.AreEqual(double.NegativeInfinity, data.MaxSeen); + Assert.AreEqual(0, data.Sum); + Assert.AreEqual(0, data.SumOfSquares); + CollectionAssert.AreEqual(new uint[data.Bucket.Count], data.Bucket); + } + } +} diff --git a/src/csharp/Grpc.IntegrationTesting/IClientRunner.cs b/src/csharp/Grpc.IntegrationTesting/IClientRunner.cs new file mode 100644 index 0000000000..39b94f1e6d --- /dev/null +++ b/src/csharp/Grpc.IntegrationTesting/IClientRunner.cs @@ -0,0 +1,67 @@ +#region Copyright notice and license + +// 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. + +#endregion + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Google.Protobuf; +using Grpc.Core; +using Grpc.Core.Utils; +using NUnit.Framework; +using Grpc.Testing; + +namespace Grpc.IntegrationTesting +{ + /// <summary> + /// Abstract client runner. + /// </summary> + public interface IClientRunner + { + /// <summary> + /// Gets stats snapshot. + /// </summary> + /// <returns>The stats.</returns> + ClientStats GetStats(bool reset); + + /// <summary> + /// Asynchronously stops the client. + /// </summary> + /// <returns>Task that finishes when client has come to a full stop.</returns> + Task StopAsync(); + } + +} diff --git a/src/csharp/Grpc.IntegrationTesting/IServerRunner.cs b/src/csharp/Grpc.IntegrationTesting/IServerRunner.cs new file mode 100644 index 0000000000..53a62fbf1c --- /dev/null +++ b/src/csharp/Grpc.IntegrationTesting/IServerRunner.cs @@ -0,0 +1,72 @@ +#region Copyright notice and license + +// 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. + +#endregion + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Google.Protobuf; +using Grpc.Core; +using Grpc.Core.Utils; +using NUnit.Framework; +using Grpc.Testing; + +namespace Grpc.IntegrationTesting +{ + /// <summary> + /// Abstract server runner. + /// </summary> + public interface IServerRunner + { + /// <summary> + /// Port on which the server is listening. + /// </summary> + int BoundPort { get; } + + /// <summary> + /// Gets server stats. + /// </summary> + /// <returns>The stats.</returns> + ServerStats GetStats(bool reset); + + /// <summary> + /// Asynchronously stops the server. + /// </summary> + /// <returns>Task that finishes when server has shutdown.</returns> + Task StopAsync(); + } + +} diff --git a/src/csharp/Grpc.IntegrationTesting/Payloads.cs b/src/csharp/Grpc.IntegrationTesting/Payloads.cs new file mode 100644 index 0000000000..a37dd9a685 --- /dev/null +++ b/src/csharp/Grpc.IntegrationTesting/Payloads.cs @@ -0,0 +1,580 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: test/proto/benchmarks/payloads.proto +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; +using scg = global::System.Collections.Generic; +namespace Grpc.Testing { + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public static partial class Payloads { + + #region Descriptor + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static Payloads() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "CiR0ZXN0L3Byb3RvL2JlbmNobWFya3MvcGF5bG9hZHMucHJvdG8SDGdycGMu", + "dGVzdGluZyI3ChBCeXRlQnVmZmVyUGFyYW1zEhAKCHJlcV9zaXplGAEgASgF", + "EhEKCXJlc3Bfc2l6ZRgCIAEoBSI4ChFTaW1wbGVQcm90b1BhcmFtcxIQCghy", + "ZXFfc2l6ZRgBIAEoBRIRCglyZXNwX3NpemUYAiABKAUiFAoSQ29tcGxleFBy", + "b3RvUGFyYW1zIsoBCg1QYXlsb2FkQ29uZmlnEjgKDmJ5dGVidWZfcGFyYW1z", + "GAEgASgLMh4uZ3JwYy50ZXN0aW5nLkJ5dGVCdWZmZXJQYXJhbXNIABI4Cg1z", + "aW1wbGVfcGFyYW1zGAIgASgLMh8uZ3JwYy50ZXN0aW5nLlNpbXBsZVByb3Rv", + "UGFyYW1zSAASOgoOY29tcGxleF9wYXJhbXMYAyABKAsyIC5ncnBjLnRlc3Rp", + "bmcuQ29tcGxleFByb3RvUGFyYW1zSABCCQoHcGF5bG9hZGIGcHJvdG8z")); + descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData, + new pbr::FileDescriptor[] { }, + new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] { + new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ByteBufferParams), new[]{ "ReqSize", "RespSize" }, null, null, null), + new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.SimpleProtoParams), new[]{ "ReqSize", "RespSize" }, null, null, null), + new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ComplexProtoParams), null, null, null, null), + new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.PayloadConfig), new[]{ "BytebufParams", "SimpleParams", "ComplexParams" }, new[]{ "Payload" }, null, null) + })); + } + #endregion + + } + #region Messages + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class ByteBufferParams : pb::IMessage<ByteBufferParams> { + private static readonly pb::MessageParser<ByteBufferParams> _parser = new pb::MessageParser<ByteBufferParams>(() => new ByteBufferParams()); + public static pb::MessageParser<ByteBufferParams> Parser { get { return _parser; } } + + public static pbr::MessageDescriptor Descriptor { + get { return global::Grpc.Testing.Payloads.Descriptor.MessageTypes[0]; } + } + + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + public ByteBufferParams() { + OnConstruction(); + } + + partial void OnConstruction(); + + public ByteBufferParams(ByteBufferParams other) : this() { + reqSize_ = other.reqSize_; + respSize_ = other.respSize_; + } + + public ByteBufferParams Clone() { + return new ByteBufferParams(this); + } + + public const int ReqSizeFieldNumber = 1; + private int reqSize_; + public int ReqSize { + get { return reqSize_; } + set { + reqSize_ = value; + } + } + + public const int RespSizeFieldNumber = 2; + private int respSize_; + public int RespSize { + get { return respSize_; } + set { + respSize_ = value; + } + } + + public override bool Equals(object other) { + return Equals(other as ByteBufferParams); + } + + public bool Equals(ByteBufferParams other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (ReqSize != other.ReqSize) return false; + if (RespSize != other.RespSize) return false; + return true; + } + + public override int GetHashCode() { + int hash = 1; + if (ReqSize != 0) hash ^= ReqSize.GetHashCode(); + if (RespSize != 0) hash ^= RespSize.GetHashCode(); + return hash; + } + + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); + } + + public void WriteTo(pb::CodedOutputStream output) { + if (ReqSize != 0) { + output.WriteRawTag(8); + output.WriteInt32(ReqSize); + } + if (RespSize != 0) { + output.WriteRawTag(16); + output.WriteInt32(RespSize); + } + } + + public int CalculateSize() { + int size = 0; + if (ReqSize != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ReqSize); + } + if (RespSize != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(RespSize); + } + return size; + } + + public void MergeFrom(ByteBufferParams other) { + if (other == null) { + return; + } + if (other.ReqSize != 0) { + ReqSize = other.ReqSize; + } + if (other.RespSize != 0) { + RespSize = other.RespSize; + } + } + + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 8: { + ReqSize = input.ReadInt32(); + break; + } + case 16: { + RespSize = input.ReadInt32(); + break; + } + } + } + } + + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class SimpleProtoParams : pb::IMessage<SimpleProtoParams> { + private static readonly pb::MessageParser<SimpleProtoParams> _parser = new pb::MessageParser<SimpleProtoParams>(() => new SimpleProtoParams()); + public static pb::MessageParser<SimpleProtoParams> Parser { get { return _parser; } } + + public static pbr::MessageDescriptor Descriptor { + get { return global::Grpc.Testing.Payloads.Descriptor.MessageTypes[1]; } + } + + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + public SimpleProtoParams() { + OnConstruction(); + } + + partial void OnConstruction(); + + public SimpleProtoParams(SimpleProtoParams other) : this() { + reqSize_ = other.reqSize_; + respSize_ = other.respSize_; + } + + public SimpleProtoParams Clone() { + return new SimpleProtoParams(this); + } + + public const int ReqSizeFieldNumber = 1; + private int reqSize_; + public int ReqSize { + get { return reqSize_; } + set { + reqSize_ = value; + } + } + + public const int RespSizeFieldNumber = 2; + private int respSize_; + public int RespSize { + get { return respSize_; } + set { + respSize_ = value; + } + } + + public override bool Equals(object other) { + return Equals(other as SimpleProtoParams); + } + + public bool Equals(SimpleProtoParams other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (ReqSize != other.ReqSize) return false; + if (RespSize != other.RespSize) return false; + return true; + } + + public override int GetHashCode() { + int hash = 1; + if (ReqSize != 0) hash ^= ReqSize.GetHashCode(); + if (RespSize != 0) hash ^= RespSize.GetHashCode(); + return hash; + } + + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); + } + + public void WriteTo(pb::CodedOutputStream output) { + if (ReqSize != 0) { + output.WriteRawTag(8); + output.WriteInt32(ReqSize); + } + if (RespSize != 0) { + output.WriteRawTag(16); + output.WriteInt32(RespSize); + } + } + + public int CalculateSize() { + int size = 0; + if (ReqSize != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ReqSize); + } + if (RespSize != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(RespSize); + } + return size; + } + + public void MergeFrom(SimpleProtoParams other) { + if (other == null) { + return; + } + if (other.ReqSize != 0) { + ReqSize = other.ReqSize; + } + if (other.RespSize != 0) { + RespSize = other.RespSize; + } + } + + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 8: { + ReqSize = input.ReadInt32(); + break; + } + case 16: { + RespSize = input.ReadInt32(); + break; + } + } + } + } + + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class ComplexProtoParams : pb::IMessage<ComplexProtoParams> { + private static readonly pb::MessageParser<ComplexProtoParams> _parser = new pb::MessageParser<ComplexProtoParams>(() => new ComplexProtoParams()); + public static pb::MessageParser<ComplexProtoParams> Parser { get { return _parser; } } + + public static pbr::MessageDescriptor Descriptor { + get { return global::Grpc.Testing.Payloads.Descriptor.MessageTypes[2]; } + } + + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + public ComplexProtoParams() { + OnConstruction(); + } + + partial void OnConstruction(); + + public ComplexProtoParams(ComplexProtoParams other) : this() { + } + + public ComplexProtoParams Clone() { + return new ComplexProtoParams(this); + } + + public override bool Equals(object other) { + return Equals(other as ComplexProtoParams); + } + + public bool Equals(ComplexProtoParams other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + return true; + } + + public override int GetHashCode() { + int hash = 1; + return hash; + } + + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); + } + + public void WriteTo(pb::CodedOutputStream output) { + } + + public int CalculateSize() { + int size = 0; + return size; + } + + public void MergeFrom(ComplexProtoParams other) { + if (other == null) { + return; + } + } + + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + } + } + } + + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class PayloadConfig : pb::IMessage<PayloadConfig> { + private static readonly pb::MessageParser<PayloadConfig> _parser = new pb::MessageParser<PayloadConfig>(() => new PayloadConfig()); + public static pb::MessageParser<PayloadConfig> Parser { get { return _parser; } } + + public static pbr::MessageDescriptor Descriptor { + get { return global::Grpc.Testing.Payloads.Descriptor.MessageTypes[3]; } + } + + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + public PayloadConfig() { + OnConstruction(); + } + + partial void OnConstruction(); + + public PayloadConfig(PayloadConfig other) : this() { + switch (other.PayloadCase) { + case PayloadOneofCase.BytebufParams: + BytebufParams = other.BytebufParams.Clone(); + break; + case PayloadOneofCase.SimpleParams: + SimpleParams = other.SimpleParams.Clone(); + break; + case PayloadOneofCase.ComplexParams: + ComplexParams = other.ComplexParams.Clone(); + break; + } + + } + + public PayloadConfig Clone() { + return new PayloadConfig(this); + } + + public const int BytebufParamsFieldNumber = 1; + public global::Grpc.Testing.ByteBufferParams BytebufParams { + get { return payloadCase_ == PayloadOneofCase.BytebufParams ? (global::Grpc.Testing.ByteBufferParams) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.BytebufParams; + } + } + + public const int SimpleParamsFieldNumber = 2; + public global::Grpc.Testing.SimpleProtoParams SimpleParams { + get { return payloadCase_ == PayloadOneofCase.SimpleParams ? (global::Grpc.Testing.SimpleProtoParams) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.SimpleParams; + } + } + + public const int ComplexParamsFieldNumber = 3; + public global::Grpc.Testing.ComplexProtoParams ComplexParams { + get { return payloadCase_ == PayloadOneofCase.ComplexParams ? (global::Grpc.Testing.ComplexProtoParams) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.ComplexParams; + } + } + + private object payload_; + public enum PayloadOneofCase { + None = 0, + BytebufParams = 1, + SimpleParams = 2, + ComplexParams = 3, + } + private PayloadOneofCase payloadCase_ = PayloadOneofCase.None; + public PayloadOneofCase PayloadCase { + get { return payloadCase_; } + } + + public void ClearPayload() { + payloadCase_ = PayloadOneofCase.None; + payload_ = null; + } + + public override bool Equals(object other) { + return Equals(other as PayloadConfig); + } + + public bool Equals(PayloadConfig other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(BytebufParams, other.BytebufParams)) return false; + if (!object.Equals(SimpleParams, other.SimpleParams)) return false; + if (!object.Equals(ComplexParams, other.ComplexParams)) return false; + return true; + } + + public override int GetHashCode() { + int hash = 1; + if (payloadCase_ == PayloadOneofCase.BytebufParams) hash ^= BytebufParams.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.SimpleParams) hash ^= SimpleParams.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.ComplexParams) hash ^= ComplexParams.GetHashCode(); + return hash; + } + + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); + } + + public void WriteTo(pb::CodedOutputStream output) { + if (payloadCase_ == PayloadOneofCase.BytebufParams) { + output.WriteRawTag(10); + output.WriteMessage(BytebufParams); + } + if (payloadCase_ == PayloadOneofCase.SimpleParams) { + output.WriteRawTag(18); + output.WriteMessage(SimpleParams); + } + if (payloadCase_ == PayloadOneofCase.ComplexParams) { + output.WriteRawTag(26); + output.WriteMessage(ComplexParams); + } + } + + public int CalculateSize() { + int size = 0; + if (payloadCase_ == PayloadOneofCase.BytebufParams) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(BytebufParams); + } + if (payloadCase_ == PayloadOneofCase.SimpleParams) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(SimpleParams); + } + if (payloadCase_ == PayloadOneofCase.ComplexParams) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ComplexParams); + } + return size; + } + + public void MergeFrom(PayloadConfig other) { + if (other == null) { + return; + } + switch (other.PayloadCase) { + case PayloadOneofCase.BytebufParams: + BytebufParams = other.BytebufParams; + break; + case PayloadOneofCase.SimpleParams: + SimpleParams = other.SimpleParams; + break; + case PayloadOneofCase.ComplexParams: + ComplexParams = other.ComplexParams; + break; + } + + } + + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 10: { + global::Grpc.Testing.ByteBufferParams subBuilder = new global::Grpc.Testing.ByteBufferParams(); + if (payloadCase_ == PayloadOneofCase.BytebufParams) { + subBuilder.MergeFrom(BytebufParams); + } + input.ReadMessage(subBuilder); + BytebufParams = subBuilder; + break; + } + case 18: { + global::Grpc.Testing.SimpleProtoParams subBuilder = new global::Grpc.Testing.SimpleProtoParams(); + if (payloadCase_ == PayloadOneofCase.SimpleParams) { + subBuilder.MergeFrom(SimpleParams); + } + input.ReadMessage(subBuilder); + SimpleParams = subBuilder; + break; + } + case 26: { + global::Grpc.Testing.ComplexProtoParams subBuilder = new global::Grpc.Testing.ComplexProtoParams(); + if (payloadCase_ == PayloadOneofCase.ComplexParams) { + subBuilder.MergeFrom(ComplexParams); + } + input.ReadMessage(subBuilder); + ComplexParams = subBuilder; + break; + } + } + } + } + + } + + #endregion + +} + +#endregion Designer generated code diff --git a/src/csharp/Grpc.IntegrationTesting/QpsWorker.cs b/src/csharp/Grpc.IntegrationTesting/QpsWorker.cs new file mode 100644 index 0000000000..686b484345 --- /dev/null +++ b/src/csharp/Grpc.IntegrationTesting/QpsWorker.cs @@ -0,0 +1,108 @@ +#region Copyright notice and license + +// 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. + +#endregion + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +using CommandLine; +using CommandLine.Text; +using Grpc.Core; +using Grpc.Core.Utils; +using Grpc.Testing; +using NUnit.Framework; + +namespace Grpc.IntegrationTesting +{ + public class QpsWorker + { + private class ServerOptions + { + [Option("driver_port", DefaultValue = 0)] + public int DriverPort { get; set; } + + [HelpOption] + public string GetUsage() + { + var help = new HelpText + { + Heading = "gRPC C# performance testing worker", + AddDashesToOption = true + }; + help.AddPreOptionsLine("Usage:"); + help.AddOptions(this); + return help; + } + } + + ServerOptions options; + + private QpsWorker(ServerOptions options) + { + this.options = options; + } + + public static void Run(string[] args) + { + var options = new ServerOptions(); + if (!Parser.Default.ParseArguments(args, options)) + { + Environment.Exit(1); + } + + var workerServer = new QpsWorker(options); + workerServer.Run(); + } + + private void Run() + { + string host = "0.0.0.0"; + int port = options.DriverPort; + + var server = new Server + { + Services = { WorkerService.BindService(new WorkerServiceImpl()) }, + Ports = { new ServerPort(host, options.DriverPort, ServerCredentials.Insecure )} + }; + int boundPort = server.Ports.Single().BoundPort; + Console.WriteLine("Running qps worker server on " + string.Format("{0}:{1}", host, boundPort)); + server.Start(); + + server.ShutdownTask.Wait(); + } + } +} diff --git a/src/csharp/Grpc.IntegrationTesting/RunnerClientServerTest.cs b/src/csharp/Grpc.IntegrationTesting/RunnerClientServerTest.cs new file mode 100644 index 0000000000..2b51526c88 --- /dev/null +++ b/src/csharp/Grpc.IntegrationTesting/RunnerClientServerTest.cs @@ -0,0 +1,117 @@ +#region Copyright notice and license + +// 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. + +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Grpc.Core; +using Grpc.Core.Utils; +using Grpc.Testing; +using NUnit.Framework; + +namespace Grpc.IntegrationTesting +{ + /// <summary> + /// Runs performance tests in-process. + /// </summary> + public class RunnerClientServerTest + { + const string Host = "localhost"; + IServerRunner serverRunner; + + [TestFixtureSetUp] + public void Init() + { + var serverConfig = new ServerConfig + { + ServerType = ServerType.ASYNC_SERVER, + Host = Host, + PayloadConfig = new PayloadConfig + { + SimpleParams = new SimpleProtoParams + { + RespSize = 100 + } + } + }; + serverRunner = ServerRunners.CreateStarted(serverConfig); + } + + [TestFixtureTearDown] + public void Cleanup() + { + serverRunner.StopAsync().Wait(); + } + + // Test attribute commented out to prevent running as part of the default test suite. + //[Test] + //[Category("Performance")] + public async Task ClientServerRunner() + { + var config = new ClientConfig + { + ServerTargets = { string.Format("{0}:{1}", Host, serverRunner.BoundPort) }, + RpcType = RpcType.UNARY, + LoadParams = new LoadParams { ClosedLoop = new ClosedLoopParams() }, + PayloadConfig = new PayloadConfig + { + SimpleParams = new SimpleProtoParams + { + ReqSize = 100 + } + }, + HistogramParams = new HistogramParams + { + Resolution = 0.01, + MaxPossible = 60e9 + } + }; + + var runner = ClientRunners.CreateStarted(config); + + System.Console.WriteLine("Warming up"); + await Task.Delay(3000); + runner.GetStats(true); // throw away warm-up data + + System.Console.WriteLine("Benchmarking"); + await Task.Delay(3000); + var stats = runner.GetStats(true); + await runner.StopAsync(); + + System.Console.WriteLine(stats); + System.Console.WriteLine("avg micros/call " + (long) (stats.Latencies.Sum / stats.Latencies.Count / 1000.0)); + } + } +} diff --git a/src/csharp/Grpc.IntegrationTesting/ServerRunners.cs b/src/csharp/Grpc.IntegrationTesting/ServerRunners.cs new file mode 100644 index 0000000000..e8be7758ce --- /dev/null +++ b/src/csharp/Grpc.IntegrationTesting/ServerRunners.cs @@ -0,0 +1,124 @@ +#region Copyright notice and license + +// 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. + +#endregion + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; +using Google.Protobuf; +using Grpc.Core; +using Grpc.Core.Utils; +using NUnit.Framework; +using Grpc.Testing; + +namespace Grpc.IntegrationTesting +{ + /// <summary> + /// Helper methods to start server runners for performance testing. + /// </summary> + public static class ServerRunners + { + /// <summary> + /// Creates a started server runner. + /// </summary> + public static IServerRunner CreateStarted(ServerConfig config) + { + Grpc.Core.Utils.Preconditions.CheckArgument(config.ServerType == ServerType.ASYNC_SERVER); + var credentials = config.SecurityParams != null ? TestCredentials.CreateSslServerCredentials() : ServerCredentials.Insecure; + + // TODO: qps_driver needs to setup payload properly... + int responseSize = config.PayloadConfig != null ? config.PayloadConfig.SimpleParams.RespSize : 0; + var server = new Server + { + Services = { BenchmarkService.BindService(new BenchmarkServiceImpl(responseSize)) }, + Ports = { new ServerPort(config.Host, config.Port, credentials) } + }; + + server.Start(); + return new ServerRunnerImpl(server); + } + } + + /// <summary> + /// Server runner. + /// </summary> + public class ServerRunnerImpl : IServerRunner + { + readonly Server server; + readonly WallClockStopwatch wallClockStopwatch = new WallClockStopwatch(); + + public ServerRunnerImpl(Server server) + { + this.server = Grpc.Core.Utils.Preconditions.CheckNotNull(server); + } + + public int BoundPort + { + get + { + return server.Ports.Single().BoundPort; + } + } + + /// <summary> + /// Gets server stats. + /// </summary> + /// <returns>The stats.</returns> + public ServerStats GetStats(bool reset) + { + var secondsElapsed = wallClockStopwatch.GetElapsedSnapshot(reset).TotalSeconds; + + // TODO: populate user time and system time + return new ServerStats + { + TimeElapsed = secondsElapsed, + TimeUser = 0, + TimeSystem = 0 + }; + } + + /// <summary> + /// Asynchronously stops the server. + /// </summary> + /// <returns>Task that finishes when server has shutdown.</returns> + public Task StopAsync() + { + return server.ShutdownAsync(); + } + } + +} diff --git a/src/csharp/Grpc.IntegrationTesting/Services.cs b/src/csharp/Grpc.IntegrationTesting/Services.cs new file mode 100644 index 0000000000..b648da6734 --- /dev/null +++ b/src/csharp/Grpc.IntegrationTesting/Services.cs @@ -0,0 +1,44 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: test/proto/benchmarks/services.proto +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; +using scg = global::System.Collections.Generic; +namespace Grpc.Testing { + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public static partial class Services { + + #region Descriptor + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static Services() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "CiR0ZXN0L3Byb3RvL2JlbmNobWFya3Mvc2VydmljZXMucHJvdG8SDGdycGMu", + "dGVzdGluZxoZdGVzdC9wcm90by9tZXNzYWdlcy5wcm90bxojdGVzdC9wcm90", + "by9iZW5jaG1hcmtzL2NvbnRyb2wucHJvdG8yqgEKEEJlbmNobWFya1NlcnZp", + "Y2USRgoJVW5hcnlDYWxsEhsuZ3JwYy50ZXN0aW5nLlNpbXBsZVJlcXVlc3Qa", + "HC5ncnBjLnRlc3RpbmcuU2ltcGxlUmVzcG9uc2USTgoNU3RyZWFtaW5nQ2Fs", + "bBIbLmdycGMudGVzdGluZy5TaW1wbGVSZXF1ZXN0GhwuZ3JwYy50ZXN0aW5n", + "LlNpbXBsZVJlc3BvbnNlKAEwATKdAQoNV29ya2VyU2VydmljZRJFCglSdW5T", + "ZXJ2ZXISGC5ncnBjLnRlc3RpbmcuU2VydmVyQXJncxoaLmdycGMudGVzdGlu", + "Zy5TZXJ2ZXJTdGF0dXMoATABEkUKCVJ1bkNsaWVudBIYLmdycGMudGVzdGlu", + "Zy5DbGllbnRBcmdzGhouZ3JwYy50ZXN0aW5nLkNsaWVudFN0YXR1cygBMAFi", + "BnByb3RvMw==")); + descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData, + new pbr::FileDescriptor[] { global::Grpc.Testing.Messages.Descriptor, global::Grpc.Testing.Control.Descriptor, }, + new pbr::GeneratedCodeInfo(null, null)); + } + #endregion + + } +} + +#endregion Designer generated code diff --git a/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs b/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs new file mode 100644 index 0000000000..ce388c6d5c --- /dev/null +++ b/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs @@ -0,0 +1,198 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: test/proto/benchmarks/services.proto +#region Designer generated code + +using System; +using System.Threading; +using System.Threading.Tasks; +using Grpc.Core; + +namespace Grpc.Testing { + public static class BenchmarkService + { + static readonly string __ServiceName = "grpc.testing.BenchmarkService"; + + static readonly Marshaller<global::Grpc.Testing.SimpleRequest> __Marshaller_SimpleRequest = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.SimpleRequest.Parser.ParseFrom); + static readonly Marshaller<global::Grpc.Testing.SimpleResponse> __Marshaller_SimpleResponse = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.SimpleResponse.Parser.ParseFrom); + + static readonly Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> __Method_UnaryCall = new Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse>( + MethodType.Unary, + __ServiceName, + "UnaryCall", + __Marshaller_SimpleRequest, + __Marshaller_SimpleResponse); + + static readonly Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> __Method_StreamingCall = new Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse>( + MethodType.DuplexStreaming, + __ServiceName, + "StreamingCall", + __Marshaller_SimpleRequest, + __Marshaller_SimpleResponse); + + // service descriptor + public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor + { + get { return global::Grpc.Testing.Services.Descriptor.Services[0]; } + } + + // client interface + public interface IBenchmarkServiceClient + { + global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, CallOptions options); + AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, CallOptions options); + AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(CallOptions options); + } + + // server-side interface + public interface IBenchmarkService + { + Task<global::Grpc.Testing.SimpleResponse> UnaryCall(global::Grpc.Testing.SimpleRequest request, ServerCallContext context); + Task StreamingCall(IAsyncStreamReader<global::Grpc.Testing.SimpleRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.SimpleResponse> responseStream, ServerCallContext context); + } + + // client stub + public class BenchmarkServiceClient : ClientBase, IBenchmarkServiceClient + { + public BenchmarkServiceClient(Channel channel) : base(channel) + { + } + public global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) + { + var call = CreateCall(__Method_UnaryCall, new CallOptions(headers, deadline, cancellationToken)); + return Calls.BlockingUnaryCall(call, request); + } + public global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, CallOptions options) + { + var call = CreateCall(__Method_UnaryCall, options); + return Calls.BlockingUnaryCall(call, request); + } + public AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) + { + var call = CreateCall(__Method_UnaryCall, new CallOptions(headers, deadline, cancellationToken)); + return Calls.AsyncUnaryCall(call, request); + } + public AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, CallOptions options) + { + var call = CreateCall(__Method_UnaryCall, options); + return Calls.AsyncUnaryCall(call, request); + } + public AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) + { + var call = CreateCall(__Method_StreamingCall, new CallOptions(headers, deadline, cancellationToken)); + return Calls.AsyncDuplexStreamingCall(call); + } + public AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(CallOptions options) + { + var call = CreateCall(__Method_StreamingCall, options); + return Calls.AsyncDuplexStreamingCall(call); + } + } + + // creates service definition that can be registered with a server + public static ServerServiceDefinition BindService(IBenchmarkService serviceImpl) + { + return ServerServiceDefinition.CreateBuilder(__ServiceName) + .AddMethod(__Method_UnaryCall, serviceImpl.UnaryCall) + .AddMethod(__Method_StreamingCall, serviceImpl.StreamingCall).Build(); + } + + // creates a new client + public static BenchmarkServiceClient NewClient(Channel channel) + { + return new BenchmarkServiceClient(channel); + } + + } + public static class WorkerService + { + static readonly string __ServiceName = "grpc.testing.WorkerService"; + + static readonly Marshaller<global::Grpc.Testing.ServerArgs> __Marshaller_ServerArgs = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ServerArgs.Parser.ParseFrom); + static readonly Marshaller<global::Grpc.Testing.ServerStatus> __Marshaller_ServerStatus = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ServerStatus.Parser.ParseFrom); + static readonly Marshaller<global::Grpc.Testing.ClientArgs> __Marshaller_ClientArgs = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ClientArgs.Parser.ParseFrom); + static readonly Marshaller<global::Grpc.Testing.ClientStatus> __Marshaller_ClientStatus = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ClientStatus.Parser.ParseFrom); + + static readonly Method<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> __Method_RunServer = new Method<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus>( + MethodType.DuplexStreaming, + __ServiceName, + "RunServer", + __Marshaller_ServerArgs, + __Marshaller_ServerStatus); + + static readonly Method<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> __Method_RunClient = new Method<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus>( + MethodType.DuplexStreaming, + __ServiceName, + "RunClient", + __Marshaller_ClientArgs, + __Marshaller_ClientStatus); + + // service descriptor + public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor + { + get { return global::Grpc.Testing.Services.Descriptor.Services[1]; } + } + + // client interface + public interface IWorkerServiceClient + { + AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(CallOptions options); + AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(CallOptions options); + } + + // server-side interface + public interface IWorkerService + { + Task RunServer(IAsyncStreamReader<global::Grpc.Testing.ServerArgs> requestStream, IServerStreamWriter<global::Grpc.Testing.ServerStatus> responseStream, ServerCallContext context); + Task RunClient(IAsyncStreamReader<global::Grpc.Testing.ClientArgs> requestStream, IServerStreamWriter<global::Grpc.Testing.ClientStatus> responseStream, ServerCallContext context); + } + + // client stub + public class WorkerServiceClient : ClientBase, IWorkerServiceClient + { + public WorkerServiceClient(Channel channel) : base(channel) + { + } + public AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) + { + var call = CreateCall(__Method_RunServer, new CallOptions(headers, deadline, cancellationToken)); + return Calls.AsyncDuplexStreamingCall(call); + } + public AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(CallOptions options) + { + var call = CreateCall(__Method_RunServer, options); + return Calls.AsyncDuplexStreamingCall(call); + } + public AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) + { + var call = CreateCall(__Method_RunClient, new CallOptions(headers, deadline, cancellationToken)); + return Calls.AsyncDuplexStreamingCall(call); + } + public AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(CallOptions options) + { + var call = CreateCall(__Method_RunClient, options); + return Calls.AsyncDuplexStreamingCall(call); + } + } + + // creates service definition that can be registered with a server + public static ServerServiceDefinition BindService(IWorkerService serviceImpl) + { + return ServerServiceDefinition.CreateBuilder(__ServiceName) + .AddMethod(__Method_RunServer, serviceImpl.RunServer) + .AddMethod(__Method_RunClient, serviceImpl.RunClient).Build(); + } + + // creates a new client + public static WorkerServiceClient NewClient(Channel channel) + { + return new WorkerServiceClient(channel); + } + + } +} +#endregion diff --git a/src/csharp/Grpc.IntegrationTesting/Settings.StyleCop b/src/csharp/Grpc.IntegrationTesting/Settings.StyleCop index fb99cd4af1..746f2ef5ce 100644 --- a/src/csharp/Grpc.IntegrationTesting/Settings.StyleCop +++ b/src/csharp/Grpc.IntegrationTesting/Settings.StyleCop @@ -1,7 +1,10 @@ <StyleCopSettings Version="105"> <SourceFileList> - <SourceFile>Messages.cs</SourceFile> <SourceFile>Empty.cs</SourceFile> + <SourceFile>Control.cs</SourceFile> + <SourceFile>Messages.cs</SourceFile> + <SourceFile>Payloads.cs</SourceFile> + <SourceFile>Stats.cs</SourceFile> <Settings> <GlobalSettings> <BooleanProperty Name="RulesEnabledByDefault">False</BooleanProperty> diff --git a/src/csharp/Grpc.IntegrationTesting/Stats.cs b/src/csharp/Grpc.IntegrationTesting/Stats.cs new file mode 100644 index 0000000000..4ae66baffa --- /dev/null +++ b/src/csharp/Grpc.IntegrationTesting/Stats.cs @@ -0,0 +1,744 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: test/proto/benchmarks/stats.proto +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; +using scg = global::System.Collections.Generic; +namespace Grpc.Testing { + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public static partial class Stats { + + #region Descriptor + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static Stats() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "CiF0ZXN0L3Byb3RvL2JlbmNobWFya3Mvc3RhdHMucHJvdG8SDGdycGMudGVz", + "dGluZyJLCgtTZXJ2ZXJTdGF0cxIUCgx0aW1lX2VsYXBzZWQYASABKAESEQoJ", + "dGltZV91c2VyGAIgASgBEhMKC3RpbWVfc3lzdGVtGAMgASgBIjsKD0hpc3Rv", + "Z3JhbVBhcmFtcxISCgpyZXNvbHV0aW9uGAEgASgBEhQKDG1heF9wb3NzaWJs", + "ZRgCIAEoASJ3Cg1IaXN0b2dyYW1EYXRhEg4KBmJ1Y2tldBgBIAMoDRIQCght", + "aW5fc2VlbhgCIAEoARIQCghtYXhfc2VlbhgDIAEoARILCgNzdW0YBCABKAES", + "FgoOc3VtX29mX3NxdWFyZXMYBSABKAESDQoFY291bnQYBiABKAEiewoLQ2xp", + "ZW50U3RhdHMSLgoJbGF0ZW5jaWVzGAEgASgLMhsuZ3JwYy50ZXN0aW5nLkhp", + "c3RvZ3JhbURhdGESFAoMdGltZV9lbGFwc2VkGAIgASgBEhEKCXRpbWVfdXNl", + "chgDIAEoARITCgt0aW1lX3N5c3RlbRgEIAEoAWIGcHJvdG8z")); + descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData, + new pbr::FileDescriptor[] { }, + new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] { + new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ServerStats), new[]{ "TimeElapsed", "TimeUser", "TimeSystem" }, null, null, null), + new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.HistogramParams), new[]{ "Resolution", "MaxPossible" }, null, null, null), + new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.HistogramData), new[]{ "Bucket", "MinSeen", "MaxSeen", "Sum", "SumOfSquares", "Count" }, null, null, null), + new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ClientStats), new[]{ "Latencies", "TimeElapsed", "TimeUser", "TimeSystem" }, null, null, null) + })); + } + #endregion + + } + #region Messages + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class ServerStats : pb::IMessage<ServerStats> { + private static readonly pb::MessageParser<ServerStats> _parser = new pb::MessageParser<ServerStats>(() => new ServerStats()); + public static pb::MessageParser<ServerStats> Parser { get { return _parser; } } + + public static pbr::MessageDescriptor Descriptor { + get { return global::Grpc.Testing.Stats.Descriptor.MessageTypes[0]; } + } + + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + public ServerStats() { + OnConstruction(); + } + + partial void OnConstruction(); + + public ServerStats(ServerStats other) : this() { + timeElapsed_ = other.timeElapsed_; + timeUser_ = other.timeUser_; + timeSystem_ = other.timeSystem_; + } + + public ServerStats Clone() { + return new ServerStats(this); + } + + public const int TimeElapsedFieldNumber = 1; + private double timeElapsed_; + public double TimeElapsed { + get { return timeElapsed_; } + set { + timeElapsed_ = value; + } + } + + public const int TimeUserFieldNumber = 2; + private double timeUser_; + public double TimeUser { + get { return timeUser_; } + set { + timeUser_ = value; + } + } + + public const int TimeSystemFieldNumber = 3; + private double timeSystem_; + public double TimeSystem { + get { return timeSystem_; } + set { + timeSystem_ = value; + } + } + + public override bool Equals(object other) { + return Equals(other as ServerStats); + } + + public bool Equals(ServerStats other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (TimeElapsed != other.TimeElapsed) return false; + if (TimeUser != other.TimeUser) return false; + if (TimeSystem != other.TimeSystem) return false; + return true; + } + + public override int GetHashCode() { + int hash = 1; + if (TimeElapsed != 0D) hash ^= TimeElapsed.GetHashCode(); + if (TimeUser != 0D) hash ^= TimeUser.GetHashCode(); + if (TimeSystem != 0D) hash ^= TimeSystem.GetHashCode(); + return hash; + } + + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); + } + + public void WriteTo(pb::CodedOutputStream output) { + if (TimeElapsed != 0D) { + output.WriteRawTag(9); + output.WriteDouble(TimeElapsed); + } + if (TimeUser != 0D) { + output.WriteRawTag(17); + output.WriteDouble(TimeUser); + } + if (TimeSystem != 0D) { + output.WriteRawTag(25); + output.WriteDouble(TimeSystem); + } + } + + public int CalculateSize() { + int size = 0; + if (TimeElapsed != 0D) { + size += 1 + 8; + } + if (TimeUser != 0D) { + size += 1 + 8; + } + if (TimeSystem != 0D) { + size += 1 + 8; + } + return size; + } + + public void MergeFrom(ServerStats other) { + if (other == null) { + return; + } + if (other.TimeElapsed != 0D) { + TimeElapsed = other.TimeElapsed; + } + if (other.TimeUser != 0D) { + TimeUser = other.TimeUser; + } + if (other.TimeSystem != 0D) { + TimeSystem = other.TimeSystem; + } + } + + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 9: { + TimeElapsed = input.ReadDouble(); + break; + } + case 17: { + TimeUser = input.ReadDouble(); + break; + } + case 25: { + TimeSystem = input.ReadDouble(); + break; + } + } + } + } + + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class HistogramParams : pb::IMessage<HistogramParams> { + private static readonly pb::MessageParser<HistogramParams> _parser = new pb::MessageParser<HistogramParams>(() => new HistogramParams()); + public static pb::MessageParser<HistogramParams> Parser { get { return _parser; } } + + public static pbr::MessageDescriptor Descriptor { + get { return global::Grpc.Testing.Stats.Descriptor.MessageTypes[1]; } + } + + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + public HistogramParams() { + OnConstruction(); + } + + partial void OnConstruction(); + + public HistogramParams(HistogramParams other) : this() { + resolution_ = other.resolution_; + maxPossible_ = other.maxPossible_; + } + + public HistogramParams Clone() { + return new HistogramParams(this); + } + + public const int ResolutionFieldNumber = 1; + private double resolution_; + public double Resolution { + get { return resolution_; } + set { + resolution_ = value; + } + } + + public const int MaxPossibleFieldNumber = 2; + private double maxPossible_; + public double MaxPossible { + get { return maxPossible_; } + set { + maxPossible_ = value; + } + } + + public override bool Equals(object other) { + return Equals(other as HistogramParams); + } + + public bool Equals(HistogramParams other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Resolution != other.Resolution) return false; + if (MaxPossible != other.MaxPossible) return false; + return true; + } + + public override int GetHashCode() { + int hash = 1; + if (Resolution != 0D) hash ^= Resolution.GetHashCode(); + if (MaxPossible != 0D) hash ^= MaxPossible.GetHashCode(); + return hash; + } + + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); + } + + public void WriteTo(pb::CodedOutputStream output) { + if (Resolution != 0D) { + output.WriteRawTag(9); + output.WriteDouble(Resolution); + } + if (MaxPossible != 0D) { + output.WriteRawTag(17); + output.WriteDouble(MaxPossible); + } + } + + public int CalculateSize() { + int size = 0; + if (Resolution != 0D) { + size += 1 + 8; + } + if (MaxPossible != 0D) { + size += 1 + 8; + } + return size; + } + + public void MergeFrom(HistogramParams other) { + if (other == null) { + return; + } + if (other.Resolution != 0D) { + Resolution = other.Resolution; + } + if (other.MaxPossible != 0D) { + MaxPossible = other.MaxPossible; + } + } + + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 9: { + Resolution = input.ReadDouble(); + break; + } + case 17: { + MaxPossible = input.ReadDouble(); + break; + } + } + } + } + + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class HistogramData : pb::IMessage<HistogramData> { + private static readonly pb::MessageParser<HistogramData> _parser = new pb::MessageParser<HistogramData>(() => new HistogramData()); + public static pb::MessageParser<HistogramData> Parser { get { return _parser; } } + + public static pbr::MessageDescriptor Descriptor { + get { return global::Grpc.Testing.Stats.Descriptor.MessageTypes[2]; } + } + + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + public HistogramData() { + OnConstruction(); + } + + partial void OnConstruction(); + + public HistogramData(HistogramData other) : this() { + bucket_ = other.bucket_.Clone(); + minSeen_ = other.minSeen_; + maxSeen_ = other.maxSeen_; + sum_ = other.sum_; + sumOfSquares_ = other.sumOfSquares_; + count_ = other.count_; + } + + public HistogramData Clone() { + return new HistogramData(this); + } + + public const int BucketFieldNumber = 1; + private static readonly pb::FieldCodec<uint> _repeated_bucket_codec + = pb::FieldCodec.ForUInt32(10); + private readonly pbc::RepeatedField<uint> bucket_ = new pbc::RepeatedField<uint>(); + public pbc::RepeatedField<uint> Bucket { + get { return bucket_; } + } + + public const int MinSeenFieldNumber = 2; + private double minSeen_; + public double MinSeen { + get { return minSeen_; } + set { + minSeen_ = value; + } + } + + public const int MaxSeenFieldNumber = 3; + private double maxSeen_; + public double MaxSeen { + get { return maxSeen_; } + set { + maxSeen_ = value; + } + } + + public const int SumFieldNumber = 4; + private double sum_; + public double Sum { + get { return sum_; } + set { + sum_ = value; + } + } + + public const int SumOfSquaresFieldNumber = 5; + private double sumOfSquares_; + public double SumOfSquares { + get { return sumOfSquares_; } + set { + sumOfSquares_ = value; + } + } + + public const int CountFieldNumber = 6; + private double count_; + public double Count { + get { return count_; } + set { + count_ = value; + } + } + + public override bool Equals(object other) { + return Equals(other as HistogramData); + } + + public bool Equals(HistogramData other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!bucket_.Equals(other.bucket_)) return false; + if (MinSeen != other.MinSeen) return false; + if (MaxSeen != other.MaxSeen) return false; + if (Sum != other.Sum) return false; + if (SumOfSquares != other.SumOfSquares) return false; + if (Count != other.Count) return false; + return true; + } + + public override int GetHashCode() { + int hash = 1; + hash ^= bucket_.GetHashCode(); + if (MinSeen != 0D) hash ^= MinSeen.GetHashCode(); + if (MaxSeen != 0D) hash ^= MaxSeen.GetHashCode(); + if (Sum != 0D) hash ^= Sum.GetHashCode(); + if (SumOfSquares != 0D) hash ^= SumOfSquares.GetHashCode(); + if (Count != 0D) hash ^= Count.GetHashCode(); + return hash; + } + + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); + } + + public void WriteTo(pb::CodedOutputStream output) { + bucket_.WriteTo(output, _repeated_bucket_codec); + if (MinSeen != 0D) { + output.WriteRawTag(17); + output.WriteDouble(MinSeen); + } + if (MaxSeen != 0D) { + output.WriteRawTag(25); + output.WriteDouble(MaxSeen); + } + if (Sum != 0D) { + output.WriteRawTag(33); + output.WriteDouble(Sum); + } + if (SumOfSquares != 0D) { + output.WriteRawTag(41); + output.WriteDouble(SumOfSquares); + } + if (Count != 0D) { + output.WriteRawTag(49); + output.WriteDouble(Count); + } + } + + public int CalculateSize() { + int size = 0; + size += bucket_.CalculateSize(_repeated_bucket_codec); + if (MinSeen != 0D) { + size += 1 + 8; + } + if (MaxSeen != 0D) { + size += 1 + 8; + } + if (Sum != 0D) { + size += 1 + 8; + } + if (SumOfSquares != 0D) { + size += 1 + 8; + } + if (Count != 0D) { + size += 1 + 8; + } + return size; + } + + public void MergeFrom(HistogramData other) { + if (other == null) { + return; + } + bucket_.Add(other.bucket_); + if (other.MinSeen != 0D) { + MinSeen = other.MinSeen; + } + if (other.MaxSeen != 0D) { + MaxSeen = other.MaxSeen; + } + if (other.Sum != 0D) { + Sum = other.Sum; + } + if (other.SumOfSquares != 0D) { + SumOfSquares = other.SumOfSquares; + } + if (other.Count != 0D) { + Count = other.Count; + } + } + + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 10: + case 8: { + bucket_.AddEntriesFrom(input, _repeated_bucket_codec); + break; + } + case 17: { + MinSeen = input.ReadDouble(); + break; + } + case 25: { + MaxSeen = input.ReadDouble(); + break; + } + case 33: { + Sum = input.ReadDouble(); + break; + } + case 41: { + SumOfSquares = input.ReadDouble(); + break; + } + case 49: { + Count = input.ReadDouble(); + break; + } + } + } + } + + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class ClientStats : pb::IMessage<ClientStats> { + private static readonly pb::MessageParser<ClientStats> _parser = new pb::MessageParser<ClientStats>(() => new ClientStats()); + public static pb::MessageParser<ClientStats> Parser { get { return _parser; } } + + public static pbr::MessageDescriptor Descriptor { + get { return global::Grpc.Testing.Stats.Descriptor.MessageTypes[3]; } + } + + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + public ClientStats() { + OnConstruction(); + } + + partial void OnConstruction(); + + public ClientStats(ClientStats other) : this() { + Latencies = other.latencies_ != null ? other.Latencies.Clone() : null; + timeElapsed_ = other.timeElapsed_; + timeUser_ = other.timeUser_; + timeSystem_ = other.timeSystem_; + } + + public ClientStats Clone() { + return new ClientStats(this); + } + + public const int LatenciesFieldNumber = 1; + private global::Grpc.Testing.HistogramData latencies_; + public global::Grpc.Testing.HistogramData Latencies { + get { return latencies_; } + set { + latencies_ = value; + } + } + + public const int TimeElapsedFieldNumber = 2; + private double timeElapsed_; + public double TimeElapsed { + get { return timeElapsed_; } + set { + timeElapsed_ = value; + } + } + + public const int TimeUserFieldNumber = 3; + private double timeUser_; + public double TimeUser { + get { return timeUser_; } + set { + timeUser_ = value; + } + } + + public const int TimeSystemFieldNumber = 4; + private double timeSystem_; + public double TimeSystem { + get { return timeSystem_; } + set { + timeSystem_ = value; + } + } + + public override bool Equals(object other) { + return Equals(other as ClientStats); + } + + public bool Equals(ClientStats other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Latencies, other.Latencies)) return false; + if (TimeElapsed != other.TimeElapsed) return false; + if (TimeUser != other.TimeUser) return false; + if (TimeSystem != other.TimeSystem) return false; + return true; + } + + public override int GetHashCode() { + int hash = 1; + if (latencies_ != null) hash ^= Latencies.GetHashCode(); + if (TimeElapsed != 0D) hash ^= TimeElapsed.GetHashCode(); + if (TimeUser != 0D) hash ^= TimeUser.GetHashCode(); + if (TimeSystem != 0D) hash ^= TimeSystem.GetHashCode(); + return hash; + } + + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); + } + + public void WriteTo(pb::CodedOutputStream output) { + if (latencies_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Latencies); + } + if (TimeElapsed != 0D) { + output.WriteRawTag(17); + output.WriteDouble(TimeElapsed); + } + if (TimeUser != 0D) { + output.WriteRawTag(25); + output.WriteDouble(TimeUser); + } + if (TimeSystem != 0D) { + output.WriteRawTag(33); + output.WriteDouble(TimeSystem); + } + } + + public int CalculateSize() { + int size = 0; + if (latencies_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Latencies); + } + if (TimeElapsed != 0D) { + size += 1 + 8; + } + if (TimeUser != 0D) { + size += 1 + 8; + } + if (TimeSystem != 0D) { + size += 1 + 8; + } + return size; + } + + public void MergeFrom(ClientStats other) { + if (other == null) { + return; + } + if (other.latencies_ != null) { + if (latencies_ == null) { + latencies_ = new global::Grpc.Testing.HistogramData(); + } + Latencies.MergeFrom(other.Latencies); + } + if (other.TimeElapsed != 0D) { + TimeElapsed = other.TimeElapsed; + } + if (other.TimeUser != 0D) { + TimeUser = other.TimeUser; + } + if (other.TimeSystem != 0D) { + TimeSystem = other.TimeSystem; + } + } + + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 10: { + if (latencies_ == null) { + latencies_ = new global::Grpc.Testing.HistogramData(); + } + input.ReadMessage(latencies_); + break; + } + case 17: { + TimeElapsed = input.ReadDouble(); + break; + } + case 25: { + TimeUser = input.ReadDouble(); + break; + } + case 33: { + TimeSystem = input.ReadDouble(); + break; + } + } + } + } + + } + + #endregion + +} + +#endregion Designer generated code diff --git a/src/csharp/Grpc.IntegrationTesting/WallClockStopwatch.cs b/src/csharp/Grpc.IntegrationTesting/WallClockStopwatch.cs new file mode 100644 index 0000000000..e44ae2a5ff --- /dev/null +++ b/src/csharp/Grpc.IntegrationTesting/WallClockStopwatch.cs @@ -0,0 +1,78 @@ +#region Copyright notice and license + +// 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. + +#endregion + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; +using Google.Protobuf; +using Grpc.Core; +using Grpc.Core.Utils; +using NUnit.Framework; +using Grpc.Testing; + +namespace Grpc.IntegrationTesting +{ + /// <summary> + /// Snapshottable wall clock stopwatch. + /// </summary> + public class WallClockStopwatch + { + long startTicks; + + public WallClockStopwatch() + { + this.startTicks = DateTime.UtcNow.Ticks; + } + + public TimeSpan GetElapsedSnapshot(bool reset) + { + var utcNow = DateTime.UtcNow; + + long oldStartTicks; + if (reset) + { + oldStartTicks = Interlocked.Exchange(ref this.startTicks, utcNow.Ticks); + } + else + { + oldStartTicks = this.startTicks; + } + return utcNow - new DateTime(oldStartTicks, DateTimeKind.Utc); + } + } +} diff --git a/src/csharp/Grpc.IntegrationTesting/WorkerServiceImpl.cs b/src/csharp/Grpc.IntegrationTesting/WorkerServiceImpl.cs new file mode 100644 index 0000000000..bb2918bf46 --- /dev/null +++ b/src/csharp/Grpc.IntegrationTesting/WorkerServiceImpl.cs @@ -0,0 +1,96 @@ +#region Copyright notice and license + +// 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. + +#endregion + +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Google.Protobuf; +using Grpc.Core; +using Grpc.Core.Utils; +using Grpc.IntegrationTesting; + +namespace Grpc.Testing +{ + /// <summary> + /// Implementation of WorkerService server + /// </summary> + public class WorkerServiceImpl : WorkerService.IWorkerService + { + public async Task RunServer(IAsyncStreamReader<ServerArgs> requestStream, IServerStreamWriter<ServerStatus> responseStream, ServerCallContext context) + { + Grpc.Core.Utils.Preconditions.CheckState(await requestStream.MoveNext()); + var serverConfig = requestStream.Current.Setup; + var runner = ServerRunners.CreateStarted(serverConfig); + + await responseStream.WriteAsync(new ServerStatus + { + Stats = runner.GetStats(false), + Port = runner.BoundPort, + Cores = 0, // TODO: set number of cores + }); + + while (await requestStream.MoveNext()) + { + var reset = requestStream.Current.Mark.Reset; + await responseStream.WriteAsync(new ServerStatus + { + Stats = runner.GetStats(reset) + }); + } + await runner.StopAsync(); + } + + public async Task RunClient(IAsyncStreamReader<ClientArgs> requestStream, IServerStreamWriter<ClientStatus> responseStream, ServerCallContext context) + { + Grpc.Core.Utils.Preconditions.CheckState(await requestStream.MoveNext()); + var clientConfig = requestStream.Current.Setup; + var runner = ClientRunners.CreateStarted(clientConfig); + + await responseStream.WriteAsync(new ClientStatus + { + Stats = runner.GetStats(false) + }); + + while (await requestStream.MoveNext()) + { + var reset = requestStream.Current.Mark.Reset; + await responseStream.WriteAsync(new ClientStatus + { + Stats = runner.GetStats(reset) + }); + } + await runner.StopAsync(); + } + } +} diff --git a/src/csharp/Grpc.IntegrationTesting/data/server1.pem b/src/csharp/Grpc.IntegrationTesting/data/server1.pem index 8e582e571f..f3d43fcc5b 100644 --- a/src/csharp/Grpc.IntegrationTesting/data/server1.pem +++ b/src/csharp/Grpc.IntegrationTesting/data/server1.pem @@ -1,16 +1,16 @@ -----BEGIN CERTIFICATE----- -MIICmzCCAgSgAwIBAgIBAzANBgkqhkiG9w0BAQUFADBWMQswCQYDVQQGEwJBVTET -MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ -dHkgTHRkMQ8wDQYDVQQDDAZ0ZXN0Y2EwHhcNMTQwNzIyMDYwMDU3WhcNMjQwNzE5 -MDYwMDU3WjBkMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV -BAcTB0NoaWNhZ28xFDASBgNVBAoTC0dvb2dsZSBJbmMuMRowGAYDVQQDFBEqLnRl -c3QuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4cMVJygs -JUmlgMMzgdi0h1XoCR7+ww1pop04OMMyy7H/i0PJ2W6Y35+b4CM8QrkYeEafUGDO -RYX6yV/cHGGsD/x02ye6ey1UDtkGAD/mpDEx8YCrjAc1Vfvt8Fk6Cn1WVIxV/J30 -3xjBsFgByQ55RBp1OLZfVLo6AleBDSbcxaECAwEAAaNrMGkwCQYDVR0TBAIwADAL -BgNVHQ8EBAMCBeAwTwYDVR0RBEgwRoIQKi50ZXN0Lmdvb2dsZS5mcoIYd2F0ZXJ6 -b29pLnRlc3QuZ29vZ2xlLmJlghIqLnRlc3QueW91dHViZS5jb22HBMCoAQMwDQYJ -KoZIhvcNAQEFBQADgYEAM2Ii0LgTGbJ1j4oqX9bxVcxm+/R5Yf8oi0aZqTJlnLYS -wXcBykxTx181s7WyfJ49WwrYXo78zTDAnf1ma0fPq3e4mpspvyndLh1a+OarHa1e -aT0DIIYk7qeEa1YcVljx2KyLd0r1BBAfrwyGaEPVeJQVYWaOJRU2we/KD4ojf9s= +MIICnDCCAgWgAwIBAgIBBzANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJBVTET +MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ +dHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2EwHhcNMTUxMTA0MDIyMDI0WhcNMjUxMTAx +MDIyMDI0WjBlMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV +BAcTB0NoaWNhZ28xFTATBgNVBAoTDEV4YW1wbGUsIENvLjEaMBgGA1UEAxQRKi50 +ZXN0Lmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOHDFSco +LCVJpYDDM4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1Bg +zkWF+slf3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd +9N8YwbBYAckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAGjazBpMAkGA1UdEwQCMAAw +CwYDVR0PBAQDAgXgME8GA1UdEQRIMEaCECoudGVzdC5nb29nbGUuZnKCGHdhdGVy +em9vaS50ZXN0Lmdvb2dsZS5iZYISKi50ZXN0LnlvdXR1YmUuY29thwTAqAEDMA0G +CSqGSIb3DQEBCwUAA4GBAJFXVifQNub1LUP4JlnX5lXNlo8FxZ2a12AFQs+bzoJ6 +hM044EDjqyxUqSbVePK0ni3w1fHQB5rY9yYC5f8G7aqqTY1QOhoUk8ZTSTRpnkTh +y4jjdvTZeLDVBlueZUTDRmy2feY5aZIU18vFDK08dTG0A87pppuv1LNIR3loveU8 -----END CERTIFICATE----- diff --git a/src/csharp/Grpc.sln b/src/csharp/Grpc.sln index f19f29c6a2..8ff35e8c0d 100644 --- a/src/csharp/Grpc.sln +++ b/src/csharp/Grpc.sln @@ -1,6 +1,6 @@ 
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 2013
+# Visual Studio 2012
VisualStudioVersion = 12.0.31101.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.Examples", "Grpc.Examples\Grpc.Examples.csproj", "{7DC1433E-3225-42C7-B7EA-546D56E27A4B}"
@@ -32,6 +32,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.HealthCheck", "Grpc.He EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.HealthCheck.Tests", "Grpc.HealthCheck.Tests\Grpc.HealthCheck.Tests.csproj", "{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.IntegrationTesting.QpsWorker", "Grpc.IntegrationTesting.QpsWorker\Grpc.IntegrationTesting.QpsWorker.csproj", "{B82B7DFE-7F7B-40EF-B3D6-064FF2B01294}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -39,72 +41,78 @@ Global ReleaseSigned|Any CPU = ReleaseSigned|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|Any CPU.Build.0 = Release|Any CPU
- {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
- {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
- {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|Any CPU.Build.0 = Release|Any CPU
- {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
- {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
- {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|Any CPU.Build.0 = Release|Any CPU
- {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
- {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Release|Any CPU.Build.0 = Release|Any CPU
{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
- {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|Any CPU.Build.0 = Release|Any CPU
- {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
- {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
- {C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {C61154BA-DD4A-4838-8420-0162A28925E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {C61154BA-DD4A-4838-8420-0162A28925E0}.Release|Any CPU.Build.0 = Release|Any CPU
- {C61154BA-DD4A-4838-8420-0162A28925E0}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
- {C61154BA-DD4A-4838-8420-0162A28925E0}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Release|Any CPU.Build.0 = Release|Any CPU
{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
+ {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|Any CPU.Build.0 = Release|Any CPU
+ {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
+ {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
+ {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|Any CPU.Build.0 = Release|Any CPU
{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
- {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|Any CPU.Build.0 = Release|Any CPU
- {BF62FE08-373A-43D6-9D73-41CAA38B7011}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
- {BF62FE08-373A-43D6-9D73-41CAA38B7011}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
- {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|Any CPU.Build.0 = Release|Any CPU
- {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
- {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Release|Any CPU.Build.0 = Release|Any CPU
{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
+ {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
+ {B82B7DFE-7F7B-40EF-B3D6-064FF2B01294}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B82B7DFE-7F7B-40EF-B3D6-064FF2B01294}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B82B7DFE-7F7B-40EF-B3D6-064FF2B01294}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B82B7DFE-7F7B-40EF-B3D6-064FF2B01294}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B82B7DFE-7F7B-40EF-B3D6-064FF2B01294}.ReleaseSigned|Any CPU.ActiveCfg = Release|Any CPU
+ {B82B7DFE-7F7B-40EF-B3D6-064FF2B01294}.ReleaseSigned|Any CPU.Build.0 = Release|Any CPU
+ {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BF62FE08-373A-43D6-9D73-41CAA38B7011}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {BF62FE08-373A-43D6-9D73-41CAA38B7011}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
+ {C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C61154BA-DD4A-4838-8420-0162A28925E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C61154BA-DD4A-4838-8420-0162A28925E0}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C61154BA-DD4A-4838-8420-0162A28925E0}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {C61154BA-DD4A-4838-8420-0162A28925E0}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
+ {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -112,6 +120,8 @@ Global {F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c index 679ca43d74..183931936e 100644 --- a/src/csharp/ext/grpc_csharp_ext.c +++ b/src/csharp/ext/grpc_csharp_ext.c @@ -785,9 +785,10 @@ grpcsharp_call_send_initial_metadata(grpc_call *call, NULL); } -GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_set_credentials(grpc_call *call, - grpc_credentials *creds) { - return grpc_call_set_credentials(call, creds); +GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_set_credentials( + grpc_call *call, + grpc_call_credentials *creds) { + return grpc_call_set_credentials(call, creds); } /* Server */ @@ -834,7 +835,7 @@ grpcsharp_server_request_call(grpc_server *server, grpc_completion_queue *cq, /* Security */ -GPR_EXPORT grpc_credentials *GPR_CALLTYPE +GPR_EXPORT grpc_channel_credentials *GPR_CALLTYPE grpcsharp_ssl_credentials_create(const char *pem_root_certs, const char *key_cert_pair_cert_chain, const char *key_cert_pair_private_key) { @@ -850,12 +851,19 @@ grpcsharp_ssl_credentials_create(const char *pem_root_certs, } } -GPR_EXPORT void GPR_CALLTYPE grpcsharp_credentials_release(grpc_credentials *creds) { - grpc_credentials_release(creds); +GPR_EXPORT void GPR_CALLTYPE grpcsharp_channel_credentials_release( + grpc_channel_credentials *creds) { + grpc_channel_credentials_release(creds); +} + +GPR_EXPORT void GPR_CALLTYPE grpcsharp_call_credentials_release( + grpc_call_credentials *creds) { + grpc_call_credentials_release(creds); } GPR_EXPORT grpc_channel *GPR_CALLTYPE -grpcsharp_secure_channel_create(grpc_credentials *creds, const char *target, +grpcsharp_secure_channel_create(grpc_channel_credentials *creds, + const char *target, const grpc_channel_args *args) { return grpc_secure_channel_create(creds, target, args, NULL); } @@ -897,10 +905,16 @@ grpcsharp_server_add_secure_http2_port(grpc_server *server, const char *addr, return grpc_server_add_secure_http2_port(server, addr, creds); } -GPR_EXPORT grpc_credentials *GPR_CALLTYPE grpcsharp_composite_credentials_create( - grpc_credentials *creds1, - grpc_credentials *creds2) { - return grpc_composite_credentials_create(creds1, creds2, NULL); +GPR_EXPORT grpc_channel_credentials *GPR_CALLTYPE grpcsharp_composite_channel_credentials_create( + grpc_channel_credentials *channel_creds, + grpc_call_credentials *call_creds) { + return grpc_composite_channel_credentials_create(channel_creds, call_creds, NULL); +} + +GPR_EXPORT grpc_call_credentials *GPR_CALLTYPE grpcsharp_composite_call_credentials_create( + grpc_call_credentials *creds1, + grpc_call_credentials *creds2) { + return grpc_composite_call_credentials_create(creds1, creds2, NULL); } /* Metadata credentials plugin */ @@ -929,7 +943,7 @@ static void grpcsharp_metadata_credentials_destroy_handler(void *state) { interceptor(state, NULL, NULL, NULL, 1); } -GPR_EXPORT grpc_credentials *GPR_CALLTYPE grpcsharp_metadata_credentials_create_from_plugin( +GPR_EXPORT grpc_call_credentials *GPR_CALLTYPE grpcsharp_metadata_credentials_create_from_plugin( grpcsharp_metadata_interceptor_func metadata_interceptor) { grpc_metadata_credentials_plugin plugin; plugin.get_metadata = grpcsharp_get_metadata_handler; diff --git a/src/csharp/generate_proto_csharp.sh b/src/csharp/generate_proto_csharp.sh index f879e074aa..92348d1394 100755 --- a/src/csharp/generate_proto_csharp.sh +++ b/src/csharp/generate_proto_csharp.sh @@ -35,14 +35,14 @@ cd $(dirname $0) PROTOC=../../bins/opt/protobuf/protoc PLUGIN=protoc-gen-grpc=../../bins/opt/grpc_csharp_plugin EXAMPLES_DIR=Grpc.Examples -INTEROP_DIR=Grpc.IntegrationTesting +TESTING_DIR=Grpc.IntegrationTesting HEALTHCHECK_DIR=Grpc.HealthCheck $PROTOC --plugin=$PLUGIN --csharp_out=$EXAMPLES_DIR --grpc_out=$EXAMPLES_DIR \ -I $EXAMPLES_DIR/proto $EXAMPLES_DIR/proto/math.proto -$PROTOC --plugin=$PLUGIN --csharp_out=$INTEROP_DIR --grpc_out=$INTEROP_DIR \ - -I ../.. ../../test/proto/*.proto +$PROTOC --plugin=$PLUGIN --csharp_out=$TESTING_DIR --grpc_out=$TESTING_DIR \ + -I ../.. ../../test/proto/*.proto ../../test/proto/benchmarks/*.proto $PROTOC --plugin=$PLUGIN --csharp_out=$HEALTHCHECK_DIR --grpc_out=$HEALTHCHECK_DIR \ -I $HEALTHCHECK_DIR/proto $HEALTHCHECK_DIR/proto/health.proto diff --git a/src/node/ext/call.cc b/src/node/ext/call.cc index fe11905109..a98ae85427 100644 --- a/src/node/ext/call.cc +++ b/src/node/ext/call.cc @@ -757,7 +757,7 @@ NAN_METHOD(Call::SetCredentials) { Call *call = ObjectWrap::Unwrap<Call>(info.This()); CallCredentials *creds_object = ObjectWrap::Unwrap<CallCredentials>( Nan::To<Object>(info[0]).ToLocalChecked()); - grpc_credentials *creds = creds_object->GetWrappedCredentials(); + grpc_call_credentials *creds = creds_object->GetWrappedCredentials(); grpc_call_error error = GRPC_CALL_ERROR; if (creds) { error = grpc_call_set_credentials(call->wrapped_call, creds); diff --git a/src/node/ext/call_credentials.cc b/src/node/ext/call_credentials.cc index ff16a1f122..9c5d9d291b 100644 --- a/src/node/ext/call_credentials.cc +++ b/src/node/ext/call_credentials.cc @@ -64,11 +64,11 @@ using v8::Value; Nan::Callback *CallCredentials::constructor; Persistent<FunctionTemplate> CallCredentials::fun_tpl; -CallCredentials::CallCredentials(grpc_credentials *credentials) +CallCredentials::CallCredentials(grpc_call_credentials *credentials) : wrapped_credentials(credentials) {} CallCredentials::~CallCredentials() { - grpc_credentials_release(wrapped_credentials); + grpc_call_credentials_release(wrapped_credentials); } void CallCredentials::Init(Local<Object> exports) { @@ -91,7 +91,7 @@ bool CallCredentials::HasInstance(Local<Value> val) { return Nan::New(fun_tpl)->HasInstance(val); } -Local<Value> CallCredentials::WrapStruct(grpc_credentials *credentials) { +Local<Value> CallCredentials::WrapStruct(grpc_call_credentials *credentials) { EscapableHandleScope scope; const int argc = 1; if (credentials == NULL) { @@ -108,7 +108,7 @@ Local<Value> CallCredentials::WrapStruct(grpc_credentials *credentials) { } } -grpc_credentials *CallCredentials::GetWrappedCredentials() { +grpc_call_credentials *CallCredentials::GetWrappedCredentials() { return wrapped_credentials; } @@ -119,8 +119,8 @@ NAN_METHOD(CallCredentials::New) { "CallCredentials can only be created with the provided functions"); } Local<External> ext = info[0].As<External>(); - grpc_credentials *creds_value = - reinterpret_cast<grpc_credentials *>(ext->Value()); + grpc_call_credentials *creds_value = + reinterpret_cast<grpc_call_credentials *>(ext->Value()); CallCredentials *credentials = new CallCredentials(creds_value); credentials->Wrap(info.This()); info.GetReturnValue().Set(info.This()); @@ -144,7 +144,7 @@ NAN_METHOD(CallCredentials::Compose) { CallCredentials *self = ObjectWrap::Unwrap<CallCredentials>(info.This()); CallCredentials *other = ObjectWrap::Unwrap<CallCredentials>( Nan::To<Object>(info[0]).ToLocalChecked()); - grpc_credentials *creds = grpc_composite_credentials_create( + grpc_call_credentials *creds = grpc_composite_call_credentials_create( self->wrapped_credentials, other->wrapped_credentials, NULL); info.GetReturnValue().Set(WrapStruct(creds)); } @@ -162,8 +162,8 @@ NAN_METHOD(CallCredentials::CreateFromPlugin) { plugin.get_metadata = plugin_get_metadata; plugin.destroy = plugin_destroy_state; plugin.state = reinterpret_cast<void*>(state); - grpc_credentials *creds = grpc_metadata_credentials_create_from_plugin(plugin, - NULL); + grpc_call_credentials *creds = grpc_metadata_credentials_create_from_plugin( + plugin, NULL); info.GetReturnValue().Set(WrapStruct(creds)); } diff --git a/src/node/ext/call_credentials.h b/src/node/ext/call_credentials.h index 618292d19e..1cd8d8dd5d 100644 --- a/src/node/ext/call_credentials.h +++ b/src/node/ext/call_credentials.h @@ -45,14 +45,14 @@ class CallCredentials : public Nan::ObjectWrap { public: static void Init(v8::Local<v8::Object> exports); static bool HasInstance(v8::Local<v8::Value> val); - /* Wrap a grpc_credentials struct in a javascript object */ - static v8::Local<v8::Value> WrapStruct(grpc_credentials *credentials); + /* Wrap a grpc_call_credentials struct in a javascript object */ + static v8::Local<v8::Value> WrapStruct(grpc_call_credentials *credentials); - /* Returns the grpc_credentials struct that this object wraps */ - grpc_credentials *GetWrappedCredentials(); + /* Returns the grpc_call_credentials struct that this object wraps */ + grpc_call_credentials *GetWrappedCredentials(); private: - explicit CallCredentials(grpc_credentials *credentials); + explicit CallCredentials(grpc_call_credentials *credentials); ~CallCredentials(); // Prevent copying @@ -68,7 +68,7 @@ class CallCredentials : public Nan::ObjectWrap { // Used for typechecking instances of this javascript class static Nan::Persistent<v8::FunctionTemplate> fun_tpl; - grpc_credentials *wrapped_credentials; + grpc_call_credentials *wrapped_credentials; }; /* Auth metadata plugin functionality */ diff --git a/src/node/ext/channel.cc b/src/node/ext/channel.cc index 584a0cf8ab..00fcca6dc8 100644 --- a/src/node/ext/channel.cc +++ b/src/node/ext/channel.cc @@ -82,7 +82,7 @@ bool ParseChannelArgs(Local<Value> args_val, return false; } grpc_channel_args *channel_args = reinterpret_cast<grpc_channel_args*>( - malloc(sizeof(channel_args))); + malloc(sizeof(grpc_channel_args))); *channel_args_ptr = channel_args; Local<Object> args_hash = Nan::To<Object>(args_val).ToLocalChecked(); Local<Array> keys = Nan::GetOwnPropertyNames(args_hash).ToLocalChecked(); @@ -177,7 +177,7 @@ NAN_METHOD(Channel::New) { grpc_channel *wrapped_channel; // Owned by the Channel object Utf8String host(info[0]); - grpc_credentials *creds; + grpc_channel_credentials *creds; if (!ChannelCredentials::HasInstance(info[1])) { return Nan::ThrowTypeError( "Channel's second argument must be a ChannelCredentials"); diff --git a/src/node/ext/channel_credentials.cc b/src/node/ext/channel_credentials.cc index 7ca3b9816c..b77ff80af2 100644 --- a/src/node/ext/channel_credentials.cc +++ b/src/node/ext/channel_credentials.cc @@ -65,11 +65,11 @@ using v8::Value; Nan::Callback *ChannelCredentials::constructor; Persistent<FunctionTemplate> ChannelCredentials::fun_tpl; -ChannelCredentials::ChannelCredentials(grpc_credentials *credentials) +ChannelCredentials::ChannelCredentials(grpc_channel_credentials *credentials) : wrapped_credentials(credentials) {} ChannelCredentials::~ChannelCredentials() { - grpc_credentials_release(wrapped_credentials); + grpc_channel_credentials_release(wrapped_credentials); } void ChannelCredentials::Init(Local<Object> exports) { @@ -95,7 +95,8 @@ bool ChannelCredentials::HasInstance(Local<Value> val) { return Nan::New(fun_tpl)->HasInstance(val); } -Local<Value> ChannelCredentials::WrapStruct(grpc_credentials *credentials) { +Local<Value> ChannelCredentials::WrapStruct( + grpc_channel_credentials *credentials) { EscapableHandleScope scope; const int argc = 1; Local<Value> argv[argc] = { @@ -109,7 +110,7 @@ Local<Value> ChannelCredentials::WrapStruct(grpc_credentials *credentials) { } } -grpc_credentials *ChannelCredentials::GetWrappedCredentials() { +grpc_channel_credentials *ChannelCredentials::GetWrappedCredentials() { return wrapped_credentials; } @@ -120,8 +121,8 @@ NAN_METHOD(ChannelCredentials::New) { "ChannelCredentials can only be created with the provided functions"); } Local<External> ext = info[0].As<External>(); - grpc_credentials *creds_value = - reinterpret_cast<grpc_credentials *>(ext->Value()); + grpc_channel_credentials *creds_value = + reinterpret_cast<grpc_channel_credentials *>(ext->Value()); ChannelCredentials *credentials = new ChannelCredentials(creds_value); credentials->Wrap(info.This()); info.GetReturnValue().Set(info.This()); @@ -153,7 +154,7 @@ NAN_METHOD(ChannelCredentials::CreateSsl) { return Nan::ThrowTypeError( "createSSl's third argument must be a Buffer if provided"); } - grpc_credentials *creds = grpc_ssl_credentials_create( + grpc_channel_credentials *creds = grpc_ssl_credentials_create( root_certs, key_cert_pair.private_key == NULL ? NULL : &key_cert_pair, NULL); if (creds == NULL) { @@ -180,7 +181,7 @@ NAN_METHOD(ChannelCredentials::Compose) { } CallCredentials *other = ObjectWrap::Unwrap<CallCredentials>( Nan::To<Object>(info[0]).ToLocalChecked()); - grpc_credentials *creds = grpc_composite_credentials_create( + grpc_channel_credentials *creds = grpc_composite_channel_credentials_create( self->wrapped_credentials, other->GetWrappedCredentials(), NULL); if (creds == NULL) { info.GetReturnValue().SetNull(); diff --git a/src/node/ext/channel_credentials.h b/src/node/ext/channel_credentials.h index 31ea0987bc..89b115267f 100644 --- a/src/node/ext/channel_credentials.h +++ b/src/node/ext/channel_credentials.h @@ -42,19 +42,19 @@ namespace grpc { namespace node { -/* Wrapper class for grpc_credentials structs */ +/* Wrapper class for grpc_channel_credentials structs */ class ChannelCredentials : public Nan::ObjectWrap { public: static void Init(v8::Local<v8::Object> exports); static bool HasInstance(v8::Local<v8::Value> val); - /* Wrap a grpc_credentials struct in a javascript object */ - static v8::Local<v8::Value> WrapStruct(grpc_credentials *credentials); + /* Wrap a grpc_channel_credentials struct in a javascript object */ + static v8::Local<v8::Value> WrapStruct(grpc_channel_credentials *credentials); - /* Returns the grpc_credentials struct that this object wraps */ - grpc_credentials *GetWrappedCredentials(); + /* Returns the grpc_channel_credentials struct that this object wraps */ + grpc_channel_credentials *GetWrappedCredentials(); private: - explicit ChannelCredentials(grpc_credentials *credentials); + explicit ChannelCredentials(grpc_channel_credentials *credentials); ~ChannelCredentials(); // Prevent copying @@ -70,7 +70,7 @@ class ChannelCredentials : public Nan::ObjectWrap { // Used for typechecking instances of this javascript class static Nan::Persistent<v8::FunctionTemplate> fun_tpl; - grpc_credentials *wrapped_credentials; + grpc_channel_credentials *wrapped_credentials; }; } // namespace node diff --git a/src/node/src/client.js b/src/node/src/client.js index 3cdd550752..d57826781d 100644 --- a/src/node/src/client.js +++ b/src/node/src/client.js @@ -612,7 +612,15 @@ exports.makeClientConstructor = function(methods, serviceName) { if (!options) { options = {}; } - options['grpc.primary_user_agent'] = 'grpc-node/' + version; + /* Append the grpc-node user agent string after the application user agent + * string, and put the combination at the beginning of the user agent string + */ + if (options['grpc.primary_user_agent']) { + options['grpc.primary_user_agent'] += ' '; + } else { + options['grpc.primary_user_agent'] = ''; + } + options['grpc.primary_user_agent'] += 'grpc-node/' + version; /* Private fields use $ as a prefix instead of _ because it is an invalid * prefix of a method name */ this.$channel = new grpc.Channel(address, credentials, options); diff --git a/src/node/test/credentials_test.js b/src/node/test/credentials_test.js index 3e01b62cf4..647f648ca9 100644 --- a/src/node/test/credentials_test.js +++ b/src/node/test/credentials_test.js @@ -71,7 +71,7 @@ var fakeSuccessfulGoogleCredentials = { var fakeFailingGoogleCredentials = { getRequestMetadata: function(service_url, callback) { setTimeout(function() { - callback(new Error('Authorization failure')); + callback(new Error('Authentication failure')); }, 0); } }; @@ -218,6 +218,25 @@ describe('client credentials', function() { done(); }); }); + it('Should not add metadata with just SSL credentials', function(done) { + // Tests idempotency of credentials composition + var metadataUpdater = function(service_url, callback) { + var metadata = new grpc.Metadata(); + metadata.set('plugin_key', 'plugin_value'); + callback(null, metadata); + }; + var creds = grpc.credentials.createFromMetadataGenerator(metadataUpdater); + grpc.credentials.combineChannelCredentials(client_ssl_creds, creds); + var client = new Client('localhost:' + port, client_ssl_creds, + client_options); + var call = client.unary({}, function(err, data) { + assert.ifError(err); + }); + call.on('metadata', function(metadata) { + assert.deepEqual(metadata.get('plugin_key'), []); + done(); + }); + }); it.skip('should get an error from a Google credential', function(done) { var creds = grpc.credentials.createFromGoogleCredential( fakeFailingGoogleCredentials); @@ -227,7 +246,7 @@ describe('client credentials', function() { client_options); client.unary({}, function(err, data) { assert(err); - assert.strictEqual(err.message, 'Authorization failure'); + assert.strictEqual(err.message, 'Authentication failure'); done(); }); }); diff --git a/src/node/test/data/server1.pem b/src/node/test/data/server1.pem index 8e582e571f..f3d43fcc5b 100644 --- a/src/node/test/data/server1.pem +++ b/src/node/test/data/server1.pem @@ -1,16 +1,16 @@ -----BEGIN CERTIFICATE----- -MIICmzCCAgSgAwIBAgIBAzANBgkqhkiG9w0BAQUFADBWMQswCQYDVQQGEwJBVTET -MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ -dHkgTHRkMQ8wDQYDVQQDDAZ0ZXN0Y2EwHhcNMTQwNzIyMDYwMDU3WhcNMjQwNzE5 -MDYwMDU3WjBkMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV -BAcTB0NoaWNhZ28xFDASBgNVBAoTC0dvb2dsZSBJbmMuMRowGAYDVQQDFBEqLnRl -c3QuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4cMVJygs -JUmlgMMzgdi0h1XoCR7+ww1pop04OMMyy7H/i0PJ2W6Y35+b4CM8QrkYeEafUGDO -RYX6yV/cHGGsD/x02ye6ey1UDtkGAD/mpDEx8YCrjAc1Vfvt8Fk6Cn1WVIxV/J30 -3xjBsFgByQ55RBp1OLZfVLo6AleBDSbcxaECAwEAAaNrMGkwCQYDVR0TBAIwADAL -BgNVHQ8EBAMCBeAwTwYDVR0RBEgwRoIQKi50ZXN0Lmdvb2dsZS5mcoIYd2F0ZXJ6 -b29pLnRlc3QuZ29vZ2xlLmJlghIqLnRlc3QueW91dHViZS5jb22HBMCoAQMwDQYJ -KoZIhvcNAQEFBQADgYEAM2Ii0LgTGbJ1j4oqX9bxVcxm+/R5Yf8oi0aZqTJlnLYS -wXcBykxTx181s7WyfJ49WwrYXo78zTDAnf1ma0fPq3e4mpspvyndLh1a+OarHa1e -aT0DIIYk7qeEa1YcVljx2KyLd0r1BBAfrwyGaEPVeJQVYWaOJRU2we/KD4ojf9s= +MIICnDCCAgWgAwIBAgIBBzANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJBVTET +MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ +dHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2EwHhcNMTUxMTA0MDIyMDI0WhcNMjUxMTAx +MDIyMDI0WjBlMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV +BAcTB0NoaWNhZ28xFTATBgNVBAoTDEV4YW1wbGUsIENvLjEaMBgGA1UEAxQRKi50 +ZXN0Lmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOHDFSco +LCVJpYDDM4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1Bg +zkWF+slf3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd +9N8YwbBYAckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAGjazBpMAkGA1UdEwQCMAAw +CwYDVR0PBAQDAgXgME8GA1UdEQRIMEaCECoudGVzdC5nb29nbGUuZnKCGHdhdGVy +em9vaS50ZXN0Lmdvb2dsZS5iZYISKi50ZXN0LnlvdXR1YmUuY29thwTAqAEDMA0G +CSqGSIb3DQEBCwUAA4GBAJFXVifQNub1LUP4JlnX5lXNlo8FxZ2a12AFQs+bzoJ6 +hM044EDjqyxUqSbVePK0ni3w1fHQB5rY9yYC5f8G7aqqTY1QOhoUk8ZTSTRpnkTh +y4jjdvTZeLDVBlueZUTDRmy2feY5aZIU18vFDK08dTG0A87pppuv1LNIR3loveU8 -----END CERTIFICATE----- diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannel.h b/src/objective-c/GRPCClient/private/GRPCSecureChannel.h index 4e0881e5a2..b82b9fe35a 100644 --- a/src/objective-c/GRPCClient/private/GRPCSecureChannel.h +++ b/src/objective-c/GRPCClient/private/GRPCSecureChannel.h @@ -35,7 +35,7 @@ #import "GRPCChannel.h" -struct grpc_credentials; +struct grpc_channel_credentials; @interface GRPCSecureChannel : GRPCChannel - (instancetype)initWithHost:(NSString *)host; @@ -50,6 +50,6 @@ struct grpc_credentials; /** The passed arguments aren't required to be valid beyond the invocation of this initializer. */ - (instancetype)initWithHost:(NSString *)host - credentials:(struct grpc_credentials *)credentials + credentials:(struct grpc_channel_credentials *)credentials args:(grpc_channel_args *)args NS_DESIGNATED_INITIALIZER; @end diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannel.m b/src/objective-c/GRPCClient/private/GRPCSecureChannel.m index ce16655330..a573c171e9 100644 --- a/src/objective-c/GRPCClient/private/GRPCSecureChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCSecureChannel.m @@ -37,7 +37,7 @@ // Returns NULL if the file at path couldn't be read. In that case, if errorPtr isn't NULL, // *errorPtr will be an object describing what went wrong. -static grpc_credentials *CertificatesAtPath(NSString *path, NSError **errorPtr) { +static grpc_channel_credentials *CertificatesAtPath(NSString *path, NSError **errorPtr) { // Files in PEM format can have non-ASCII characters in their comments (e.g. for the name of the // issuer). Load them as UTF8 and produce an ASCII equivalent. NSString *contentInUTF8 = [NSString stringWithContentsOfFile:path @@ -62,7 +62,7 @@ static grpc_credentials *CertificatesAtPath(NSString *path, NSError **errorPtr) pathToCertificates:(NSString *)path hostNameOverride:(NSString *)hostNameOverride { // Load default SSL certificates once. - static grpc_credentials *kDefaultCertificates; + static grpc_channel_credentials *kDefaultCertificates; static dispatch_once_t loading; dispatch_once(&loading, ^{ NSString *defaultPath = @"gRPCCertificates.bundle/roots"; // .pem @@ -79,7 +79,9 @@ static grpc_credentials *CertificatesAtPath(NSString *path, NSError **errorPtr) }); //TODO(jcanizales): Add NSError** parameter to the initializer. - grpc_credentials *certificates = path ? CertificatesAtPath(path, NULL) : kDefaultCertificates; + grpc_channel_credentials *certificates = path + ? CertificatesAtPath(path, NULL) + : kDefaultCertificates; if (!certificates) { return nil; } @@ -99,7 +101,7 @@ static grpc_credentials *CertificatesAtPath(NSString *path, NSError **errorPtr) } - (instancetype)initWithHost:(NSString *)host - credentials:(grpc_credentials *)credentials + credentials:(grpc_channel_credentials *)credentials args:(grpc_channel_args *)args { return (self = [super initWithChannel:grpc_secure_channel_create( diff --git a/src/objective-c/examples/Sample/Podfile b/src/objective-c/examples/Sample/Podfile index 72308c1619..3b2f412569 100644 --- a/src/objective-c/examples/Sample/Podfile +++ b/src/objective-c/examples/Sample/Podfile @@ -1,8 +1,9 @@ source 'https://github.com/CocoaPods/Specs.git' platform :ios, '8.0' +pod 'Protobuf', :path => "../../../../third_party/protobuf" pod 'gRPC', :path => "../../../.." -pod 'RemoteTest', :path => "../../generated_libraries/RemoteTestClient" +pod 'RemoteTest', :path => "../RemoteTestClient" target 'Sample' do end diff --git a/src/objective-c/examples/Sample/Sample/ViewController.m b/src/objective-c/examples/Sample/Sample/ViewController.m index 05bd6fa2db..3d634a340d 100644 --- a/src/objective-c/examples/Sample/Sample/ViewController.m +++ b/src/objective-c/examples/Sample/Sample/ViewController.m @@ -34,7 +34,7 @@ #import "ViewController.h" #import <GRPCClient/GRPCCall.h> -#import <GRPCClient/GRPCMethodName.h> +#import <ProtoRPC/ProtoMethod.h> #import <RemoteTest/Messages.pbobjc.h> #import <RemoteTest/Test.pbrpc.h> #import <RxLibrary/GRXWriter+Immediate.h> @@ -66,14 +66,14 @@ // Same example call using the generic gRPC client library: - GRPCMethodName *method = [[GRPCMethodName alloc] initWithPackage:@"grpc.testing" - interface:@"TestService" - method:@"UnaryCall"]; + ProtoMethod *method = [[ProtoMethod alloc] initWithPackage:@"grpc.testing" + service:@"TestService" + method:@"UnaryCall"]; - id<GRXWriter> requestsWriter = [GRXWriter writerWithValue:[request data]]; + GRXWriter *requestsWriter = [GRXWriter writerWithValue:[request data]]; GRPCCall *call = [[GRPCCall alloc] initWithHost:kRemoteHost - method:method + path:method.HTTPPath requestsWriter:requestsWriter]; id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { diff --git a/src/objective-c/generated_libraries/RouteGuideClient/RouteGuide.podspec b/src/objective-c/generated_libraries/RouteGuideClient/RouteGuide.podspec deleted file mode 100644 index 23ccffe69d..0000000000 --- a/src/objective-c/generated_libraries/RouteGuideClient/RouteGuide.podspec +++ /dev/null @@ -1,31 +0,0 @@ -Pod::Spec.new do |s| - s.name = "RouteGuide" - s.version = "0.0.1" - s.license = "New BSD" - - s.ios.deployment_target = "6.0" - s.osx.deployment_target = "10.8" - - # Run protoc with the Objective-C and gRPC plugins to generate protocol messages and gRPC clients. - s.prepare_command = <<-CMD - BINDIR=../../../../bins/$CONFIG - PROTOC=$BINDIR/protobuf/protoc - PLUGIN=$BINDIR/grpc_objective_c_plugin - $PROTOC --plugin=protoc-gen-grpc=$PLUGIN --objc_out=. --grpc_out=. *.proto - CMD - - s.subspec "Messages" do |ms| - ms.source_files = "*.pbobjc.{h,m}" - ms.header_mappings_dir = "." - ms.requires_arc = false - ms.dependency "Protobuf", "~> 3.0.0-alpha-3" - end - - s.subspec "Services" do |ss| - ss.source_files = "*.pbrpc.{h,m}" - ss.header_mappings_dir = "." - ss.requires_arc = true - ss.dependency "gRPC", "~> 0.5" - ss.dependency "#{s.name}/Messages" - end -end diff --git a/src/objective-c/generated_libraries/RouteGuideClient/route_guide.proto b/src/objective-c/generated_libraries/RouteGuideClient/route_guide.proto deleted file mode 100644 index 19592e2ebd..0000000000 --- a/src/objective-c/generated_libraries/RouteGuideClient/route_guide.proto +++ /dev/null @@ -1,120 +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. - -syntax = "proto3"; - -package routeguide; - -option objc_class_prefix = "RGD"; - -// Interface exported by the server. -service RouteGuide { - // A simple RPC. - // - // Obtains the feature at a given position. - rpc GetFeature(Point) returns (Feature) {} - - // A server-to-client streaming RPC. - // - // Obtains the Features available within the given Rectangle. Results are - // streamed rather than returned at once (e.g. in a response message with a - // repeated field), as the rectangle may cover a large area and contain a - // huge number of features. - rpc ListFeatures(Rectangle) returns (stream Feature) {} - - // A client-to-server streaming RPC. - // - // Accepts a stream of Points on a route being traversed, returning a - // RouteSummary when traversal is completed. - rpc RecordRoute(stream Point) returns (RouteSummary) {} - - // A Bidirectional streaming RPC. - // - // Accepts a stream of RouteNotes sent while a route is being traversed, - // while receiving other RouteNotes (e.g. from other users). - rpc RouteChat(stream RouteNote) returns (stream RouteNote) {} -} - -// Points are represented as latitude-longitude pairs in the E7 representation -// (degrees multiplied by 10**7 and rounded to the nearest integer). -// Latitudes should be in the range +/- 90 degrees and longitude should be in -// the range +/- 180 degrees (inclusive). -message Point { - int32 latitude = 1; - int32 longitude = 2; -} - -// A latitude-longitude rectangle, represented as two diagonally opposite -// points "lo" and "hi". -message Rectangle { - // One corner of the rectangle. - Point lo = 1; - - // The other corner of the rectangle. - Point hi = 2; -} - -// A feature names something at a given point. -// -// If a feature could not be named, the name is empty. -message Feature { - // The name of the feature. - string name = 1; - - // The point where the feature is detected. - Point location = 2; -} - -// A RouteNote is a message sent while at a given point. -message RouteNote { - // The location from which the message is sent. - Point location = 1; - - // The message to be sent. - string message = 2; -} - -// A RouteSummary is received in response to a RecordRoute rpc. -// -// It contains the number of individual points received, the number of -// detected features, and the total distance covered as the cumulative sum of -// the distance between each point. -message RouteSummary { - // The number of points received. - int32 point_count = 1; - - // The number of known features passed while traversing the route. - int32 feature_count = 2; - - // The distance covered in metres. - int32 distance = 3; - - // The duration of the traversal in seconds. - int32 elapsed_time = 4; -} diff --git a/src/objective-c/tests/Podfile b/src/objective-c/tests/Podfile index 2a9b894cf6..cab608d37f 100644 --- a/src/objective-c/tests/Podfile +++ b/src/objective-c/tests/Podfile @@ -3,8 +3,7 @@ platform :ios, '8.0' pod 'Protobuf', :path => "../../../third_party/protobuf" pod 'gRPC', :path => "../../.." -pod 'RemoteTest', :path => "../generated_libraries/RemoteTestClient" -pod 'RouteGuide', :path => "../generated_libraries/RouteGuideClient" +pod 'RemoteTest', :path => "RemoteTestClient" link_with 'AllTests', 'RxLibraryUnitTests', diff --git a/src/objective-c/generated_libraries/RemoteTestClient/RemoteTest.podspec b/src/objective-c/tests/RemoteTestClient/RemoteTest.podspec index 8710753e59..8710753e59 100644 --- a/src/objective-c/generated_libraries/RemoteTestClient/RemoteTest.podspec +++ b/src/objective-c/tests/RemoteTestClient/RemoteTest.podspec diff --git a/src/objective-c/generated_libraries/RemoteTestClient/empty.proto b/src/objective-c/tests/RemoteTestClient/empty.proto index a678048289..a678048289 100644 --- a/src/objective-c/generated_libraries/RemoteTestClient/empty.proto +++ b/src/objective-c/tests/RemoteTestClient/empty.proto diff --git a/src/objective-c/generated_libraries/RemoteTestClient/messages.proto b/src/objective-c/tests/RemoteTestClient/messages.proto index 85d93c2ff9..85d93c2ff9 100644 --- a/src/objective-c/generated_libraries/RemoteTestClient/messages.proto +++ b/src/objective-c/tests/RemoteTestClient/messages.proto diff --git a/src/objective-c/generated_libraries/RemoteTestClient/test.proto b/src/objective-c/tests/RemoteTestClient/test.proto index 514c3b8095..514c3b8095 100644 --- a/src/objective-c/generated_libraries/RemoteTestClient/test.proto +++ b/src/objective-c/tests/RemoteTestClient/test.proto diff --git a/src/php/ext/grpc/call_credentials.c b/src/php/ext/grpc/call_credentials.c new file mode 100644 index 0000000000..17f167befb --- /dev/null +++ b/src/php/ext/grpc/call_credentials.c @@ -0,0 +1,138 @@ +/* + * + * 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 "channel_credentials.h" +#include "call_credentials.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <php.h> +#include <php_ini.h> +#include <ext/standard/info.h> +#include <ext/spl/spl_exceptions.h> +#include "php_grpc.h" + +#include <zend_exceptions.h> +#include <zend_hash.h> + +#include <grpc/grpc.h> +#include <grpc/grpc_security.h> + +zend_class_entry *grpc_ce_call_credentials; + +/* Frees and destroys an instance of wrapped_grpc_call_credentials */ +void free_wrapped_grpc_call_credentials(void *object TSRMLS_DC) { + wrapped_grpc_call_credentials *creds = + (wrapped_grpc_call_credentials *)object; + if (creds->wrapped != NULL) { + grpc_call_credentials_release(creds->wrapped); + } + efree(creds); +} + +/* Initializes an instance of wrapped_grpc_call_credentials to be + * associated with an object of a class specified by class_type */ +zend_object_value create_wrapped_grpc_call_credentials( + zend_class_entry *class_type TSRMLS_DC) { + zend_object_value retval; + wrapped_grpc_call_credentials *intern; + + intern = (wrapped_grpc_call_credentials *)emalloc( + sizeof(wrapped_grpc_call_credentials)); + memset(intern, 0, sizeof(wrapped_grpc_call_credentials)); + + zend_object_std_init(&intern->std, class_type TSRMLS_CC); + object_properties_init(&intern->std, class_type); + retval.handle = zend_objects_store_put( + intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, + free_wrapped_grpc_call_credentials, NULL TSRMLS_CC); + retval.handlers = zend_get_std_object_handlers(); + return retval; +} + +zval *grpc_php_wrap_call_credentials(grpc_call_credentials *wrapped) { + zval *credentials_object; + MAKE_STD_ZVAL(credentials_object); + object_init_ex(credentials_object, grpc_ce_call_credentials); + wrapped_grpc_call_credentials *credentials = + (wrapped_grpc_call_credentials *)zend_object_store_get_object( + credentials_object TSRMLS_CC); + credentials->wrapped = wrapped; + return credentials_object; +} + +/** + * Create composite credentials from two existing credentials. + * @param CallCredentials cred1 The first credential + * @param CallCredentials cred2 The second credential + * @return CallCredentials The new composite credentials object + */ +PHP_METHOD(CallCredentials, createComposite) { + zval *cred1_obj; + zval *cred2_obj; + + /* "OO" == 3 Objects */ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OO", &cred1_obj, + grpc_ce_call_credentials, &cred2_obj, + grpc_ce_call_credentials) == FAILURE) { + zend_throw_exception(spl_ce_InvalidArgumentException, + "createComposite expects 2 CallCredentials", + 1 TSRMLS_CC); + return; + } + wrapped_grpc_call_credentials *cred1 = + (wrapped_grpc_call_credentials *)zend_object_store_get_object( + cred1_obj TSRMLS_CC); + wrapped_grpc_call_credentials *cred2 = + (wrapped_grpc_call_credentials *)zend_object_store_get_object( + cred2_obj TSRMLS_CC); + grpc_call_credentials *creds = + grpc_composite_call_credentials_create(cred1->wrapped, cred2->wrapped, + NULL); + zval *creds_object = grpc_php_wrap_call_credentials(creds); + RETURN_DESTROY_ZVAL(creds_object); +} + +static zend_function_entry call_credentials_methods[] = { + PHP_ME(CallCredentials, createComposite, NULL, + ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) + PHP_FE_END}; + +void grpc_init_call_credentials(TSRMLS_D) { + zend_class_entry ce; + INIT_CLASS_ENTRY(ce, "Grpc\\CallCredentials", call_credentials_methods); + ce.create_object = create_wrapped_grpc_call_credentials; + grpc_ce_call_credentials = zend_register_internal_class(&ce TSRMLS_CC); +} diff --git a/src/php/ext/grpc/credentials.h b/src/php/ext/grpc/call_credentials.h index 86d7ae5b14..8f35ac68bc 100755 --- a/src/php/ext/grpc/credentials.h +++ b/src/php/ext/grpc/call_credentials.h @@ -31,8 +31,8 @@ * */ -#ifndef NET_GRPC_PHP_GRPC_CREDENTIALS_H_ -#define NET_GRPC_PHP_GRPC_CREDENTIALS_H_ +#ifndef NET_GRPC_PHP_GRPC_CALL_CREDENTIALS_H_ +#define NET_GRPC_PHP_GRPC_CALL_CREDENTIALS_H_ #ifdef HAVE_CONFIG_H #include "config.h" @@ -46,18 +46,18 @@ #include "grpc/grpc.h" #include "grpc/grpc_security.h" -/* Class entry for the Credentials PHP class */ -extern zend_class_entry *grpc_ce_credentials; +/* Class entry for the CallCredentials PHP class */ +extern zend_class_entry *grpc_ce_call_credentials; -/* Wrapper struct for grpc_credentials that can be associated with a PHP - * object */ -typedef struct wrapped_grpc_credentials { +/* Wrapper struct for grpc_call_credentials that can be associated + * with a PHP object */ +typedef struct wrapped_grpc_call_credentials { zend_object std; - grpc_credentials *wrapped; -} wrapped_grpc_credentials; + grpc_call_credentials *wrapped; +} wrapped_grpc_call_credentials; -/* Initializes the Credentials PHP class */ -void grpc_init_credentials(TSRMLS_D); +/* Initializes the CallCredentials PHP class */ +void grpc_init_call_credentials(TSRMLS_D); -#endif /* NET_GRPC_PHP_GRPC_CREDENTIALS_H_ */ +#endif /* NET_GRPC_PHP_GRPC_CALL_CREDENTIALS_H_ */ diff --git a/src/php/ext/grpc/channel.c b/src/php/ext/grpc/channel.c index a4313b6bd4..f8c4f0423f 100644 --- a/src/php/ext/grpc/channel.c +++ b/src/php/ext/grpc/channel.c @@ -52,7 +52,7 @@ #include <grpc/grpc_security.h> #include "completion_queue.h" -#include "credentials.h" +#include "channel_credentials.h" #include "server.h" #include "timeval.h" @@ -125,21 +125,22 @@ void php_grpc_read_args_array(zval *args_array, grpc_channel_args *args) { /** * Construct an instance of the Channel class. If the $args array contains a - * "credentials" key mapping to a Credentials object, a secure channel will be - * created with those credentials. + * "credentials" key mapping to a ChannelCredentials object, a secure channel + * will be created with those credentials. * @param string $target The hostname to associate with this channel * @param array $args The arguments to pass to the Channel (optional) */ PHP_METHOD(Channel, __construct) { wrapped_grpc_channel *channel = - (wrapped_grpc_channel *)zend_object_store_get_object(getThis() TSRMLS_CC); + (wrapped_grpc_channel *)zend_object_store_get_object( + getThis() TSRMLS_CC); char *target; int target_length; zval *args_array = NULL; grpc_channel_args args; HashTable *array_hash; zval **creds_obj = NULL; - wrapped_grpc_credentials *creds = NULL; + wrapped_grpc_channel_credentials *creds = NULL; /* "s|a" == 1 string, 1 optional array */ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a", &target, &target_length, &args_array) == FAILURE) { @@ -153,13 +154,14 @@ PHP_METHOD(Channel, __construct) { array_hash = Z_ARRVAL_P(args_array); if (zend_hash_find(array_hash, "credentials", sizeof("credentials"), (void **)&creds_obj) == SUCCESS) { - if (zend_get_class_entry(*creds_obj TSRMLS_CC) != grpc_ce_credentials) { + if (zend_get_class_entry(*creds_obj TSRMLS_CC) != + grpc_ce_channel_credentials) { zend_throw_exception(spl_ce_InvalidArgumentException, - "credentials must be a Credentials object", + "credentials must be a ChannelCredentials object", 1 TSRMLS_CC); return; } - creds = (wrapped_grpc_credentials *)zend_object_store_get_object( + creds = (wrapped_grpc_channel_credentials *)zend_object_store_get_object( *creds_obj TSRMLS_CC); zend_hash_del(array_hash, "credentials", 12); } diff --git a/src/php/ext/grpc/credentials.c b/src/php/ext/grpc/channel_credentials.c index e413070b45..df4a5d5162 100644 --- a/src/php/ext/grpc/credentials.c +++ b/src/php/ext/grpc/channel_credentials.c @@ -31,7 +31,8 @@ * */ -#include "credentials.h" +#include "channel_credentials.h" +#include "call_credentials.h" #ifdef HAVE_CONFIG_H #include "config.h" @@ -49,55 +50,56 @@ #include <grpc/grpc.h> #include <grpc/grpc_security.h> -zend_class_entry *grpc_ce_credentials; +zend_class_entry *grpc_ce_channel_credentials; -/* Frees and destroys an instance of wrapped_grpc_credentials */ -void free_wrapped_grpc_credentials(void *object TSRMLS_DC) { - wrapped_grpc_credentials *creds = (wrapped_grpc_credentials *)object; +/* Frees and destroys an instance of wrapped_grpc_channel_credentials */ +void free_wrapped_grpc_channel_credentials(void *object TSRMLS_DC) { + wrapped_grpc_channel_credentials *creds = + (wrapped_grpc_channel_credentials *)object; if (creds->wrapped != NULL) { - grpc_credentials_release(creds->wrapped); + grpc_channel_credentials_release(creds->wrapped); } efree(creds); } -/* Initializes an instance of wrapped_grpc_credentials to be associated with an - * object of a class specified by class_type */ -zend_object_value create_wrapped_grpc_credentials(zend_class_entry *class_type - TSRMLS_DC) { +/* Initializes an instance of wrapped_grpc_channel_credentials to be + * associated with an object of a class specified by class_type */ +zend_object_value create_wrapped_grpc_channel_credentials( + zend_class_entry *class_type TSRMLS_DC) { zend_object_value retval; - wrapped_grpc_credentials *intern; + wrapped_grpc_channel_credentials *intern; - intern = - (wrapped_grpc_credentials *)emalloc(sizeof(wrapped_grpc_credentials)); - memset(intern, 0, sizeof(wrapped_grpc_credentials)); + intern = (wrapped_grpc_channel_credentials *)emalloc( + sizeof(wrapped_grpc_channel_credentials)); + memset(intern, 0, sizeof(wrapped_grpc_channel_credentials)); zend_object_std_init(&intern->std, class_type TSRMLS_CC); object_properties_init(&intern->std, class_type); retval.handle = zend_objects_store_put( intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, - free_wrapped_grpc_credentials, NULL TSRMLS_CC); + free_wrapped_grpc_channel_credentials, NULL TSRMLS_CC); retval.handlers = zend_get_std_object_handlers(); return retval; } -zval *grpc_php_wrap_credentials(grpc_credentials *wrapped) { +zval *grpc_php_wrap_channel_credentials(grpc_channel_credentials *wrapped) { zval *credentials_object; MAKE_STD_ZVAL(credentials_object); - object_init_ex(credentials_object, grpc_ce_credentials); - wrapped_grpc_credentials *credentials = - (wrapped_grpc_credentials *)zend_object_store_get_object( + object_init_ex(credentials_object, grpc_ce_channel_credentials); + wrapped_grpc_channel_credentials *credentials = + (wrapped_grpc_channel_credentials *)zend_object_store_get_object( credentials_object TSRMLS_CC); credentials->wrapped = wrapped; return credentials_object; } /** - * Create a default credentials object. - * @return Credentials The new default credentials object + * Create a default channel credentials object. + * @return ChannelCredentials The new default channel credentials object */ -PHP_METHOD(Credentials, createDefault) { - grpc_credentials *creds = grpc_google_default_credentials_create(); - zval *creds_object = grpc_php_wrap_credentials(creds); +PHP_METHOD(ChannelCredentials, createDefault) { + grpc_channel_credentials *creds = grpc_google_default_credentials_create(); + zval *creds_object = grpc_php_wrap_channel_credentials(creds); RETURN_DESTROY_ZVAL(creds_object); } @@ -108,9 +110,9 @@ PHP_METHOD(Credentials, createDefault) { * (optional) * @param string pem_cert_chain PEM encoding of the client's certificate chain * (optional) - * @return Credentials The new SSL credentials object + * @return ChannelCredentials The new SSL credentials object */ -PHP_METHOD(Credentials, createSsl) { +PHP_METHOD(ChannelCredentials, createSsl) { char *pem_root_certs = NULL; grpc_ssl_pem_key_cert_pair pem_key_cert_pair; @@ -121,71 +123,65 @@ PHP_METHOD(Credentials, createSsl) { /* "|s!s!s! == 3 optional nullable strings */ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!s!s!", &pem_root_certs, &root_certs_length, - &pem_key_cert_pair.private_key, &private_key_length, + &pem_key_cert_pair.private_key, + &private_key_length, &pem_key_cert_pair.cert_chain, &cert_chain_length) == FAILURE) { zend_throw_exception(spl_ce_InvalidArgumentException, "createSsl expects 3 optional strings", 1 TSRMLS_CC); return; } - grpc_credentials *creds = grpc_ssl_credentials_create( + grpc_channel_credentials *creds = grpc_ssl_credentials_create( pem_root_certs, pem_key_cert_pair.private_key == NULL ? NULL : &pem_key_cert_pair, NULL); - zval *creds_object = grpc_php_wrap_credentials(creds); + zval *creds_object = grpc_php_wrap_channel_credentials(creds); RETURN_DESTROY_ZVAL(creds_object); } /** * Create composite credentials from two existing credentials. - * @param Credentials cred1 The first credential - * @param Credentials cred2 The second credential - * @return Credentials The new composite credentials object + * @param ChannelCredentials cred1 The first credential + * @param CallCredentials cred2 The second credential + * @return ChannelCredentials The new composite credentials object */ -PHP_METHOD(Credentials, createComposite) { +PHP_METHOD(ChannelCredentials, createComposite) { zval *cred1_obj; zval *cred2_obj; /* "OO" == 3 Objects */ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OO", &cred1_obj, - grpc_ce_credentials, &cred2_obj, - grpc_ce_credentials) == FAILURE) { + grpc_ce_channel_credentials, &cred2_obj, + grpc_ce_call_credentials) == FAILURE) { zend_throw_exception(spl_ce_InvalidArgumentException, "createComposite expects 2 Credentials", 1 TSRMLS_CC); return; } - wrapped_grpc_credentials *cred1 = - (wrapped_grpc_credentials *)zend_object_store_get_object( + wrapped_grpc_channel_credentials *cred1 = + (wrapped_grpc_channel_credentials *)zend_object_store_get_object( cred1_obj TSRMLS_CC); - wrapped_grpc_credentials *cred2 = - (wrapped_grpc_credentials *)zend_object_store_get_object( + wrapped_grpc_call_credentials *cred2 = + (wrapped_grpc_call_credentials *)zend_object_store_get_object( cred2_obj TSRMLS_CC); - grpc_credentials *creds = - grpc_composite_credentials_create(cred1->wrapped, cred2->wrapped, NULL); - zval *creds_object = grpc_php_wrap_credentials(creds); + grpc_channel_credentials *creds = + grpc_composite_channel_credentials_create(cred1->wrapped, cred2->wrapped, + NULL); + zval *creds_object = grpc_php_wrap_channel_credentials(creds); RETURN_DESTROY_ZVAL(creds_object); } -/** - * Create Google Compute Engine credentials - * @return Credentials The new GCE credentials object - */ -PHP_METHOD(Credentials, createGce) { - grpc_credentials *creds = grpc_google_compute_engine_credentials_create(NULL); - zval *creds_object = grpc_php_wrap_credentials(creds); - RETURN_DESTROY_ZVAL(creds_object); -} - -static zend_function_entry credentials_methods[] = { - PHP_ME(Credentials, createDefault, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) - PHP_ME(Credentials, createSsl, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) - PHP_ME(Credentials, createComposite, NULL, - ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) - PHP_ME(Credentials, createGce, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) - PHP_FE_END}; +static zend_function_entry channel_credentials_methods[] = { + PHP_ME(ChannelCredentials, createDefault, NULL, + ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) + PHP_ME(ChannelCredentials, createSsl, NULL, + ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) + PHP_ME(ChannelCredentials, createComposite, NULL, + ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) + PHP_FE_END}; -void grpc_init_credentials(TSRMLS_D) { +void grpc_init_channel_credentials(TSRMLS_D) { zend_class_entry ce; - INIT_CLASS_ENTRY(ce, "Grpc\\Credentials", credentials_methods); - ce.create_object = create_wrapped_grpc_credentials; - grpc_ce_credentials = zend_register_internal_class(&ce TSRMLS_CC); + INIT_CLASS_ENTRY(ce, "Grpc\\ChannelCredentials", + channel_credentials_methods); + ce.create_object = create_wrapped_grpc_channel_credentials; + grpc_ce_channel_credentials = zend_register_internal_class(&ce TSRMLS_CC); } diff --git a/src/php/ext/grpc/channel_credentials.h b/src/php/ext/grpc/channel_credentials.h new file mode 100755 index 0000000000..d89984ce60 --- /dev/null +++ b/src/php/ext/grpc/channel_credentials.h @@ -0,0 +1,63 @@ +/* + * + * 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 NET_GRPC_PHP_GRPC_CHANNEL_CREDENTIALS_H_ +#define NET_GRPC_PHP_GRPC_CHANNEL_CREDENTIALS_H_ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" +#include "php_ini.h" +#include "ext/standard/info.h" +#include "php_grpc.h" + +#include "grpc/grpc.h" +#include "grpc/grpc_security.h" + +/* Class entry for the ChannelCredentials PHP class */ +extern zend_class_entry *grpc_ce_channel_credentials; + +/* Wrapper struct for grpc_channel_credentials that can be associated + * with a PHP object */ +typedef struct wrapped_grpc_channel_credentials { + zend_object std; + + grpc_channel_credentials *wrapped; +} wrapped_grpc_channel_credentials; + +/* Initializes the ChannelCredentials PHP class */ +void grpc_init_channel_credentials(TSRMLS_D); + +#endif /* NET_GRPC_PHP_GRPC_CHANNEL_CREDENTIALS_H_ */ diff --git a/src/php/ext/grpc/config.m4 b/src/php/ext/grpc/config.m4 index 8bacdfbfec..7928687943 100755 --- a/src/php/ext/grpc/config.m4 +++ b/src/php/ext/grpc/config.m4 @@ -71,5 +71,7 @@ if test "$PHP_GRPC" != "no"; then PHP_SUBST(GRPC_SHARED_LIBADD) - PHP_NEW_EXTENSION(grpc, byte_buffer.c call.c channel.c completion_queue.c credentials.c timeval.c server.c server_credentials.c php_grpc.c, $ext_shared, , -Wall -Werror -std=c11) + PHP_NEW_EXTENSION(grpc, byte_buffer.c call.c call_credentials.c channel.c \ + channel_credentials.c completion_queue.c timeval.c server.c \ + server_credentials.c php_grpc.c, $ext_shared, , -Wall -Werror -std=c11) fi diff --git a/src/php/ext/grpc/package.xml b/src/php/ext/grpc/package.xml index 921cfc6ae6..a2e3e2826a 100644 --- a/src/php/ext/grpc/package.xml +++ b/src/php/ext/grpc/package.xml @@ -10,8 +10,8 @@ <email>grpc-packages@google.com</email> <active>yes</active> </lead> - <date>2015-10-07</date> - <time>13:40:54</time> + <date>2015-10-21</date> + <time>17:04:32</time> <version> <release>0.6.1</release> <api>0.6.0</api> @@ -30,16 +30,18 @@ <file baseinstalldir="/" md5sum="c8de0f819499c48adfc8d7f472c0196b" name="byte_buffer.h" role="src" /> <file baseinstalldir="/" md5sum="d64c9005993de02abac55664b0b9e0b2" name="call.c" role="src" /> <file baseinstalldir="/" md5sum="26acbf04c30162c2d2aca4688bb2aec8" name="call.h" role="src" /> - <file baseinstalldir="/" md5sum="15e56239b32c803f073e8a2b9f96e8c3" name="channel.c" role="src" /> + <file baseinstalldir="/" md5sum="6fa13d260dfde216f795225644f04e7a" name="call_credentials.c" role="src" /> + <file baseinstalldir="/" md5sum="e45269975f9a30fd349a90daf6b31aa2" name="call_credentials.h" role="src" /> + <file baseinstalldir="/" md5sum="0779db3b196c98081b2260ceec22cd4d" name="channel.c" role="src" /> <file baseinstalldir="/" md5sum="ed4b00c0cf3702b115d0cfa87450dc09" name="channel.h" role="src" /> + <file baseinstalldir="/" md5sum="1b40f50fa6184ad7d24a961ac76151ff" name="channel_credentials.c" role="src" /> + <file baseinstalldir="/" md5sum="a86250e03f610ce6c2c7595a84e08821" name="channel_credentials.h" role="src" /> <file baseinstalldir="/" md5sum="55ab7a42f9dd9bfc7e28a61cfc5fca63" name="completion_queue.c" role="src" /> <file baseinstalldir="/" md5sum="f10b5bb232d74a6878e829e2e76cdaa2" name="completion_queue.h" role="src" /> - <file baseinstalldir="/" md5sum="a22f8eac0164761058cc4d9eb2ceb069" name="config.m4" role="src" /> - <file baseinstalldir="/" md5sum="588752c908f7bc1663f7b8fc922ae661" name="credentials.c" role="src" /> - <file baseinstalldir="/" md5sum="6988d6e97c19c8f8e3eb92371cf8246b" name="credentials.h" role="src" /> + <file baseinstalldir="/" md5sum="c7bba7f0f00d1b1483de457d55311382" name="config.m4" role="src" /> <file baseinstalldir="/" md5sum="38a1bc979d810c36ebc2a52d4b7b5319" name="CREDITS" role="doc" /> <file baseinstalldir="/" md5sum="3f35b472bbdef5a788cd90617d7d0847" name="LICENSE" role="doc" /> - <file baseinstalldir="/" md5sum="b77f1f3941aaf7a21090b493e9f26037" name="php_grpc.c" role="src" /> + <file baseinstalldir="/" md5sum="3131a8af38fe5918e5409016b89d6cdb" name="php_grpc.c" role="src" /> <file baseinstalldir="/" md5sum="673b07859d9f69232f8a754c56780686" name="php_grpc.h" role="src" /> <file baseinstalldir="/" md5sum="7533a6d3ea02c78cad23a9651de0825d" name="README.md" role="doc" /> <file baseinstalldir="/" md5sum="3e4e960454ebb2fc7b78a840493f5315" name="server.c" role="src" /> @@ -122,7 +124,7 @@ Update to wrap gRPC C Core version 0.10.0 <release>beta</release> <api>beta</api> </stability> - <date>2015-10-07</date> + <date>2015-10-21</date> <license>BSD</license> <notes> - fixed undefined constant fatal error when run with apache/nginx #2275 diff --git a/src/php/ext/grpc/php_grpc.c b/src/php/ext/grpc/php_grpc.c index fcd94a6306..762c01385c 100644 --- a/src/php/ext/grpc/php_grpc.c +++ b/src/php/ext/grpc/php_grpc.c @@ -35,7 +35,8 @@ #include "channel.h" #include "server.h" #include "timeval.h" -#include "credentials.h" +#include "channel_credentials.h" +#include "call_credentials.h" #include "server_credentials.h" #include "completion_queue.h" @@ -233,7 +234,8 @@ PHP_MINIT_FUNCTION(grpc) { grpc_init_channel(TSRMLS_C); grpc_init_server(TSRMLS_C); grpc_init_timeval(TSRMLS_C); - grpc_init_credentials(TSRMLS_C); + grpc_init_channel_credentials(TSRMLS_C); + grpc_init_call_credentials(TSRMLS_C); grpc_init_server_credentials(TSRMLS_C); grpc_php_init_completion_queue(TSRMLS_C); return SUCCESS; diff --git a/src/php/lib/Grpc/BaseStub.php b/src/php/lib/Grpc/BaseStub.php index c26be607ff..aa4de349ea 100755 --- a/src/php/lib/Grpc/BaseStub.php +++ b/src/php/lib/Grpc/BaseStub.php @@ -51,6 +51,7 @@ class BaseStub * @param $opts array * - 'update_metadata': (optional) a callback function which takes in a * metadata array, and returns an updated metadata array + * - 'grpc.primary_user_agent': (optional) a user-agent string */ public function __construct($hostname, $opts) { @@ -64,7 +65,12 @@ class BaseStub } $package_config = json_decode( file_get_contents(dirname(__FILE__).'/../../composer.json'), true); - $opts['grpc.primary_user_agent'] = + if (!empty($opts['grpc.primary_user_agent'])) { + $opts['grpc.primary_user_agent'] .= ' '; + } else { + $opts['grpc.primary_user_agent'] = ''; + } + $opts['grpc.primary_user_agent'] .= 'grpc-php/'.$package_config['version']; $this->channel = new Channel($hostname, $opts); } diff --git a/src/php/tests/data/server1.pem b/src/php/tests/data/server1.pem index 8e582e571f..f3d43fcc5b 100755 --- a/src/php/tests/data/server1.pem +++ b/src/php/tests/data/server1.pem @@ -1,16 +1,16 @@ -----BEGIN CERTIFICATE----- -MIICmzCCAgSgAwIBAgIBAzANBgkqhkiG9w0BAQUFADBWMQswCQYDVQQGEwJBVTET -MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ -dHkgTHRkMQ8wDQYDVQQDDAZ0ZXN0Y2EwHhcNMTQwNzIyMDYwMDU3WhcNMjQwNzE5 -MDYwMDU3WjBkMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV -BAcTB0NoaWNhZ28xFDASBgNVBAoTC0dvb2dsZSBJbmMuMRowGAYDVQQDFBEqLnRl -c3QuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4cMVJygs -JUmlgMMzgdi0h1XoCR7+ww1pop04OMMyy7H/i0PJ2W6Y35+b4CM8QrkYeEafUGDO -RYX6yV/cHGGsD/x02ye6ey1UDtkGAD/mpDEx8YCrjAc1Vfvt8Fk6Cn1WVIxV/J30 -3xjBsFgByQ55RBp1OLZfVLo6AleBDSbcxaECAwEAAaNrMGkwCQYDVR0TBAIwADAL -BgNVHQ8EBAMCBeAwTwYDVR0RBEgwRoIQKi50ZXN0Lmdvb2dsZS5mcoIYd2F0ZXJ6 -b29pLnRlc3QuZ29vZ2xlLmJlghIqLnRlc3QueW91dHViZS5jb22HBMCoAQMwDQYJ -KoZIhvcNAQEFBQADgYEAM2Ii0LgTGbJ1j4oqX9bxVcxm+/R5Yf8oi0aZqTJlnLYS -wXcBykxTx181s7WyfJ49WwrYXo78zTDAnf1ma0fPq3e4mpspvyndLh1a+OarHa1e -aT0DIIYk7qeEa1YcVljx2KyLd0r1BBAfrwyGaEPVeJQVYWaOJRU2we/KD4ojf9s= +MIICnDCCAgWgAwIBAgIBBzANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJBVTET +MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ +dHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2EwHhcNMTUxMTA0MDIyMDI0WhcNMjUxMTAx +MDIyMDI0WjBlMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV +BAcTB0NoaWNhZ28xFTATBgNVBAoTDEV4YW1wbGUsIENvLjEaMBgGA1UEAxQRKi50 +ZXN0Lmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOHDFSco +LCVJpYDDM4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1Bg +zkWF+slf3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd +9N8YwbBYAckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAGjazBpMAkGA1UdEwQCMAAw +CwYDVR0PBAQDAgXgME8GA1UdEQRIMEaCECoudGVzdC5nb29nbGUuZnKCGHdhdGVy +em9vaS50ZXN0Lmdvb2dsZS5iZYISKi50ZXN0LnlvdXR1YmUuY29thwTAqAEDMA0G +CSqGSIb3DQEBCwUAA4GBAJFXVifQNub1LUP4JlnX5lXNlo8FxZ2a12AFQs+bzoJ6 +hM044EDjqyxUqSbVePK0ni3w1fHQB5rY9yYC5f8G7aqqTY1QOhoUk8ZTSTRpnkTh +y4jjdvTZeLDVBlueZUTDRmy2feY5aZIU18vFDK08dTG0A87pppuv1LNIR3loveU8 -----END CERTIFICATE----- diff --git a/src/php/tests/interop/interop_client.php b/src/php/tests/interop/interop_client.php index 3019866561..9aab5c966c 100755 --- a/src/php/tests/interop/interop_client.php +++ b/src/php/tests/interop/interop_client.php @@ -423,10 +423,10 @@ $opts = []; if ($use_tls) { if ($use_test_ca) { - $ssl_credentials = Grpc\Credentials::createSsl( - file_get_contents(dirname(__FILE__).'/../data/ca.pem')); + $ssl_credentials = Grpc\ChannelCredentials::createSsl( + file_get_contents(dirname(__FILE__).'/../data/ca.pem')); } else { - $ssl_credentials = Grpc\Credentials::createSsl(); + $ssl_credentials = Grpc\ChannelCredentials::createSsl(); } $opts['credentials'] = $ssl_credentials; $opts['grpc.ssl_target_name_override'] = $host_override; diff --git a/src/php/tests/unit_tests/SecureEndToEndTest.php b/src/php/tests/unit_tests/SecureEndToEndTest.php index e66bde376c..c388ee5031 100755 --- a/src/php/tests/unit_tests/SecureEndToEndTest.php +++ b/src/php/tests/unit_tests/SecureEndToEndTest.php @@ -35,7 +35,7 @@ class SecureEndToEndTest extends PHPUnit_Framework_TestCase { public function setUp() { - $credentials = Grpc\Credentials::createSsl( + $credentials = Grpc\ChannelCredentials::createSsl( file_get_contents(dirname(__FILE__).'/../data/ca.pem')); $server_credentials = Grpc\ServerCredentials::createSsl( null, diff --git a/src/python/grpcio/grpc/_adapter/_c/types.c b/src/python/grpcio/grpc/_adapter/_c/types.c index 8855c32ca6..8dedf5902b 100644 --- a/src/python/grpcio/grpc/_adapter/_c/types.c +++ b/src/python/grpcio/grpc/_adapter/_c/types.c @@ -40,7 +40,8 @@ int pygrpc_module_add_types(PyObject *module) { int i; PyTypeObject *types[] = { - &pygrpc_ClientCredentials_type, + &pygrpc_CallCredentials_type, + &pygrpc_ChannelCredentials_type, &pygrpc_ServerCredentials_type, &pygrpc_CompletionQueue_type, &pygrpc_Call_type, diff --git a/src/python/grpcio/grpc/_adapter/_c/types.h b/src/python/grpcio/grpc/_adapter/_c/types.h index 31fd470d36..9ab415d216 100644 --- a/src/python/grpcio/grpc/_adapter/_c/types.h +++ b/src/python/grpcio/grpc/_adapter/_c/types.h @@ -44,27 +44,35 @@ /* Client-side credentials */ /*=========================*/ -typedef struct ClientCredentials { +typedef struct ChannelCredentials { PyObject_HEAD - grpc_credentials *c_creds; -} ClientCredentials; -void pygrpc_ClientCredentials_dealloc(ClientCredentials *self); -ClientCredentials *pygrpc_ClientCredentials_google_default( + grpc_channel_credentials *c_creds; +} ChannelCredentials; +void pygrpc_ChannelCredentials_dealloc(ChannelCredentials *self); +ChannelCredentials *pygrpc_ChannelCredentials_google_default( PyTypeObject *type, PyObject *ignored); -ClientCredentials *pygrpc_ClientCredentials_ssl( +ChannelCredentials *pygrpc_ChannelCredentials_ssl( PyTypeObject *type, PyObject *args, PyObject *kwargs); -ClientCredentials *pygrpc_ClientCredentials_composite( +ChannelCredentials *pygrpc_ChannelCredentials_composite( PyTypeObject *type, PyObject *args, PyObject *kwargs); -ClientCredentials *pygrpc_ClientCredentials_compute_engine( +extern PyTypeObject pygrpc_ChannelCredentials_type; + +typedef struct CallCredentials { + PyObject_HEAD + grpc_call_credentials *c_creds; +} CallCredentials; +void pygrpc_CallCredentials_dealloc(CallCredentials *self); +CallCredentials *pygrpc_CallCredentials_composite( + PyTypeObject *type, PyObject *args, PyObject *kwargs); +CallCredentials *pygrpc_CallCredentials_compute_engine( PyTypeObject *type, PyObject *ignored); -ClientCredentials *pygrpc_ClientCredentials_jwt( +CallCredentials *pygrpc_CallCredentials_jwt( PyTypeObject *type, PyObject *args, PyObject *kwargs); -ClientCredentials *pygrpc_ClientCredentials_refresh_token( +CallCredentials *pygrpc_CallCredentials_refresh_token( PyTypeObject *type, PyObject *args, PyObject *kwargs); -ClientCredentials *pygrpc_ClientCredentials_iam( +CallCredentials *pygrpc_CallCredentials_iam( PyTypeObject *type, PyObject *args, PyObject *kwargs); -extern PyTypeObject pygrpc_ClientCredentials_type; - +extern PyTypeObject pygrpc_CallCredentials_type; /*=========================*/ /* Server-side credentials */ diff --git a/src/python/grpcio/grpc/_adapter/_c/types/call.c b/src/python/grpcio/grpc/_adapter/_c/types/call.c index 5604aba39d..04ec871880 100644 --- a/src/python/grpcio/grpc/_adapter/_c/types/call.c +++ b/src/python/grpcio/grpc/_adapter/_c/types/call.c @@ -173,12 +173,12 @@ PyObject *pygrpc_Call_peer(Call *self) { } PyObject *pygrpc_Call_set_credentials(Call *self, PyObject *args, PyObject *kwargs) { - ClientCredentials *creds; + CallCredentials *creds; grpc_call_error errcode; static char *keywords[] = {"creds", NULL}; if (!PyArg_ParseTupleAndKeywords( args, kwargs, "O!:set_credentials", keywords, - &pygrpc_ClientCredentials_type, &creds)) { + &pygrpc_CallCredentials_type, &creds)) { return NULL; } errcode = grpc_call_set_credentials(self->c_call, creds->c_creds); diff --git a/src/python/grpcio/grpc/_adapter/_c/types/client_credentials.c b/src/python/grpcio/grpc/_adapter/_c/types/call_credentials.c index 90652b7b47..5a15a6e17d 100644 --- a/src/python/grpcio/grpc/_adapter/_c/types/client_credentials.c +++ b/src/python/grpcio/grpc/_adapter/_c/types/call_credentials.c @@ -39,31 +39,28 @@ #include <grpc/grpc_security.h> -PyMethodDef pygrpc_ClientCredentials_methods[] = { - {"google_default", (PyCFunction)pygrpc_ClientCredentials_google_default, - METH_CLASS|METH_NOARGS, ""}, - {"ssl", (PyCFunction)pygrpc_ClientCredentials_ssl, - METH_CLASS|METH_KEYWORDS, ""}, - {"composite", (PyCFunction)pygrpc_ClientCredentials_composite, +PyMethodDef pygrpc_CallCredentials_methods[] = { + {"composite", (PyCFunction)pygrpc_CallCredentials_composite, METH_CLASS|METH_KEYWORDS, ""}, - {"compute_engine", (PyCFunction)pygrpc_ClientCredentials_compute_engine, + {"compute_engine", (PyCFunction)pygrpc_CallCredentials_compute_engine, METH_CLASS|METH_NOARGS, ""}, - {"jwt", (PyCFunction)pygrpc_ClientCredentials_jwt, + {"jwt", (PyCFunction)pygrpc_CallCredentials_jwt, METH_CLASS|METH_KEYWORDS, ""}, - {"refresh_token", (PyCFunction)pygrpc_ClientCredentials_refresh_token, + {"refresh_token", (PyCFunction)pygrpc_CallCredentials_refresh_token, METH_CLASS|METH_KEYWORDS, ""}, - {"iam", (PyCFunction)pygrpc_ClientCredentials_iam, + {"iam", (PyCFunction)pygrpc_CallCredentials_iam, METH_CLASS|METH_KEYWORDS, ""}, {NULL} }; -const char pygrpc_ClientCredentials_doc[] = ""; -PyTypeObject pygrpc_ClientCredentials_type = { + +const char pygrpc_CallCredentials_doc[] = ""; +PyTypeObject pygrpc_CallCredentials_type = { PyObject_HEAD_INIT(NULL) 0, /* ob_size */ - "ClientCredentials", /* tp_name */ - sizeof(ClientCredentials), /* tp_basicsize */ + "CallCredentials", /* tp_name */ + sizeof(CallCredentials), /* tp_basicsize */ 0, /* tp_itemsize */ - (destructor)pygrpc_ClientCredentials_dealloc, /* tp_dealloc */ + (destructor)pygrpc_CallCredentials_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ @@ -79,14 +76,14 @@ PyTypeObject pygrpc_ClientCredentials_type = { 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - pygrpc_ClientCredentials_doc, /* tp_doc */ + pygrpc_CallCredentials_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ - pygrpc_ClientCredentials_methods, /* tp_methods */ + pygrpc_CallCredentials_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ @@ -99,67 +96,26 @@ PyTypeObject pygrpc_ClientCredentials_type = { 0 /* tp_new */ }; -void pygrpc_ClientCredentials_dealloc(ClientCredentials *self) { - grpc_credentials_release(self->c_creds); +void pygrpc_CallCredentials_dealloc(CallCredentials *self) { + grpc_call_credentials_release(self->c_creds); self->ob_type->tp_free((PyObject *)self); } -ClientCredentials *pygrpc_ClientCredentials_google_default( - PyTypeObject *type, PyObject *ignored) { - ClientCredentials *self = (ClientCredentials *)type->tp_alloc(type, 0); - self->c_creds = grpc_google_default_credentials_create(); - if (!self->c_creds) { - Py_DECREF(self); - PyErr_SetString(PyExc_RuntimeError, - "couldn't create Google default credentials"); - return NULL; - } - return self; -} - -ClientCredentials *pygrpc_ClientCredentials_ssl( - PyTypeObject *type, PyObject *args, PyObject *kwargs) { - ClientCredentials *self; - const char *root_certs; - const char *private_key = NULL; - const char *cert_chain = NULL; - grpc_ssl_pem_key_cert_pair key_cert_pair; - static char *keywords[] = {"root_certs", "private_key", "cert_chain", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "z|zz:ssl", keywords, - &root_certs, &private_key, &cert_chain)) { - return NULL; - } - self = (ClientCredentials *)type->tp_alloc(type, 0); - if (private_key && cert_chain) { - key_cert_pair.private_key = private_key; - key_cert_pair.cert_chain = cert_chain; - self->c_creds = - grpc_ssl_credentials_create(root_certs, &key_cert_pair, NULL); - } else { - self->c_creds = grpc_ssl_credentials_create(root_certs, NULL, NULL); - } - if (!self->c_creds) { - Py_DECREF(self); - PyErr_SetString(PyExc_RuntimeError, "couldn't create ssl credentials"); - return NULL; - } - return self; -} - -ClientCredentials *pygrpc_ClientCredentials_composite( +CallCredentials *pygrpc_CallCredentials_composite( PyTypeObject *type, PyObject *args, PyObject *kwargs) { - ClientCredentials *self; - ClientCredentials *creds1; - ClientCredentials *creds2; + CallCredentials *self; + CallCredentials *creds1; + CallCredentials *creds2; static char *keywords[] = {"creds1", "creds2", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!:composite", keywords, - &pygrpc_ClientCredentials_type, &creds1, - &pygrpc_ClientCredentials_type, &creds2)) { + &pygrpc_CallCredentials_type, &creds1, + &pygrpc_CallCredentials_type, &creds2)) { return NULL; } - self = (ClientCredentials *)type->tp_alloc(type, 0); + self = (CallCredentials *)type->tp_alloc(type, 0); self->c_creds = - grpc_composite_credentials_create(creds1->c_creds, creds2->c_creds, NULL); + grpc_composite_call_credentials_create( + creds1->c_creds, creds2->c_creds, NULL); if (!self->c_creds) { Py_DECREF(self); PyErr_SetString(PyExc_RuntimeError, "couldn't create composite credentials"); @@ -168,9 +124,9 @@ ClientCredentials *pygrpc_ClientCredentials_composite( return self; } -ClientCredentials *pygrpc_ClientCredentials_compute_engine( +CallCredentials *pygrpc_CallCredentials_compute_engine( PyTypeObject *type, PyObject *ignored) { - ClientCredentials *self = (ClientCredentials *)type->tp_alloc(type, 0); + CallCredentials *self = (CallCredentials *)type->tp_alloc(type, 0); self->c_creds = grpc_google_compute_engine_credentials_create(NULL); if (!self->c_creds) { Py_DECREF(self); @@ -182,9 +138,9 @@ ClientCredentials *pygrpc_ClientCredentials_compute_engine( } /* TODO: Rename this credentials to something like service_account_jwt_access */ -ClientCredentials *pygrpc_ClientCredentials_jwt( +CallCredentials *pygrpc_CallCredentials_jwt( PyTypeObject *type, PyObject *args, PyObject *kwargs) { - ClientCredentials *self; + CallCredentials *self; const char *json_key; double lifetime; static char *keywords[] = {"json_key", "token_lifetime", NULL}; @@ -192,7 +148,7 @@ ClientCredentials *pygrpc_ClientCredentials_jwt( &json_key, &lifetime)) { return NULL; } - self = (ClientCredentials *)type->tp_alloc(type, 0); + self = (CallCredentials *)type->tp_alloc(type, 0); self->c_creds = grpc_service_account_jwt_access_credentials_create( json_key, pygrpc_cast_double_to_gpr_timespec(lifetime), NULL); if (!self->c_creds) { @@ -203,16 +159,16 @@ ClientCredentials *pygrpc_ClientCredentials_jwt( return self; } -ClientCredentials *pygrpc_ClientCredentials_refresh_token( +CallCredentials *pygrpc_CallCredentials_refresh_token( PyTypeObject *type, PyObject *args, PyObject *kwargs) { - ClientCredentials *self; + CallCredentials *self; const char *json_refresh_token; static char *keywords[] = {"json_refresh_token", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s:refresh_token", keywords, &json_refresh_token)) { return NULL; } - self = (ClientCredentials *)type->tp_alloc(type, 0); + self = (CallCredentials *)type->tp_alloc(type, 0); self->c_creds = grpc_google_refresh_token_credentials_create(json_refresh_token, NULL); if (!self->c_creds) { @@ -224,9 +180,9 @@ ClientCredentials *pygrpc_ClientCredentials_refresh_token( return self; } -ClientCredentials *pygrpc_ClientCredentials_iam( +CallCredentials *pygrpc_CallCredentials_iam( PyTypeObject *type, PyObject *args, PyObject *kwargs) { - ClientCredentials *self; + CallCredentials *self; const char *authorization_token; const char *authority_selector; static char *keywords[] = {"authorization_token", "authority_selector", NULL}; @@ -234,7 +190,7 @@ ClientCredentials *pygrpc_ClientCredentials_iam( &authorization_token, &authority_selector)) { return NULL; } - self = (ClientCredentials *)type->tp_alloc(type, 0); + self = (CallCredentials *)type->tp_alloc(type, 0); self->c_creds = grpc_google_iam_credentials_create(authorization_token, authority_selector, NULL); if (!self->c_creds) { diff --git a/src/python/grpcio/grpc/_adapter/_c/types/channel.c b/src/python/grpcio/grpc/_adapter/_c/types/channel.c index 79d39c4391..c4db2a0dfd 100644 --- a/src/python/grpcio/grpc/_adapter/_c/types/channel.c +++ b/src/python/grpcio/grpc/_adapter/_c/types/channel.c @@ -94,11 +94,11 @@ Channel *pygrpc_Channel_new( Channel *self; const char *target; PyObject *py_args; - ClientCredentials *creds = NULL; + ChannelCredentials *creds = NULL; grpc_channel_args c_args; char *keywords[] = {"target", "args", "creds", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO|O!:Channel", keywords, - &target, &py_args, &pygrpc_ClientCredentials_type, &creds)) { + &target, &py_args, &pygrpc_ChannelCredentials_type, &creds)) { return NULL; } if (!pygrpc_produce_channel_args(py_args, &c_args)) { diff --git a/src/python/grpcio/grpc/_adapter/_c/types/channel_credentials.c b/src/python/grpcio/grpc/_adapter/_c/types/channel_credentials.c new file mode 100644 index 0000000000..83b1fc0406 --- /dev/null +++ b/src/python/grpcio/grpc/_adapter/_c/types/channel_credentials.c @@ -0,0 +1,165 @@ +/* + * + * 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 "grpc/_adapter/_c/types.h" + +#define PY_SSIZE_T_CLEAN +#include <Python.h> +#include <grpc/grpc.h> +#include <grpc/grpc_security.h> + + +PyMethodDef pygrpc_ChannelCredentials_methods[] = { + {"google_default", (PyCFunction)pygrpc_ChannelCredentials_google_default, + METH_CLASS|METH_NOARGS, ""}, + {"ssl", (PyCFunction)pygrpc_ChannelCredentials_ssl, + METH_CLASS|METH_KEYWORDS, ""}, + {"composite", (PyCFunction)pygrpc_ChannelCredentials_composite, + METH_CLASS|METH_KEYWORDS, ""}, + {NULL} +}; + +const char pygrpc_ChannelCredentials_doc[] = ""; +PyTypeObject pygrpc_ChannelCredentials_type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "ChannelCredentials", /* tp_name */ + sizeof(ChannelCredentials), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)pygrpc_ChannelCredentials_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + pygrpc_ChannelCredentials_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + pygrpc_ChannelCredentials_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0 /* tp_new */ +}; + +void pygrpc_ChannelCredentials_dealloc(ChannelCredentials *self) { + grpc_channel_credentials_release(self->c_creds); + self->ob_type->tp_free((PyObject *)self); +} + +ChannelCredentials *pygrpc_ChannelCredentials_google_default( + PyTypeObject *type, PyObject *ignored) { + ChannelCredentials *self = (ChannelCredentials *)type->tp_alloc(type, 0); + self->c_creds = grpc_google_default_credentials_create(); + if (!self->c_creds) { + Py_DECREF(self); + PyErr_SetString(PyExc_RuntimeError, + "couldn't create Google default credentials"); + return NULL; + } + return self; +} + +ChannelCredentials *pygrpc_ChannelCredentials_ssl( + PyTypeObject *type, PyObject *args, PyObject *kwargs) { + ChannelCredentials *self; + const char *root_certs; + const char *private_key = NULL; + const char *cert_chain = NULL; + grpc_ssl_pem_key_cert_pair key_cert_pair; + static char *keywords[] = {"root_certs", "private_key", "cert_chain", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "z|zz:ssl", keywords, + &root_certs, &private_key, &cert_chain)) { + return NULL; + } + self = (ChannelCredentials *)type->tp_alloc(type, 0); + if (private_key && cert_chain) { + key_cert_pair.private_key = private_key; + key_cert_pair.cert_chain = cert_chain; + self->c_creds = + grpc_ssl_credentials_create(root_certs, &key_cert_pair, NULL); + } else { + self->c_creds = grpc_ssl_credentials_create(root_certs, NULL, NULL); + } + if (!self->c_creds) { + Py_DECREF(self); + PyErr_SetString(PyExc_RuntimeError, "couldn't create ssl credentials"); + return NULL; + } + return self; +} + +ChannelCredentials *pygrpc_ChannelCredentials_composite( + PyTypeObject *type, PyObject *args, PyObject *kwargs) { + ChannelCredentials *self; + ChannelCredentials *creds1; + CallCredentials *creds2; + static char *keywords[] = {"creds1", "creds2", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!:composite", keywords, + &pygrpc_ChannelCredentials_type, &creds1, + &pygrpc_CallCredentials_type, &creds2)) { + return NULL; + } + self = (ChannelCredentials *)type->tp_alloc(type, 0); + self->c_creds = + grpc_composite_channel_credentials_create( + creds1->c_creds, creds2->c_creds, NULL); + if (!self->c_creds) { + Py_DECREF(self); + PyErr_SetString( + PyExc_RuntimeError, "couldn't create composite credentials"); + return NULL; + } + return self; +} + diff --git a/src/python/grpcio/grpc/_adapter/_intermediary_low.py b/src/python/grpcio/grpc/_adapter/_intermediary_low.py index e2feec6ffb..5634c2024d 100644 --- a/src/python/grpcio/grpc/_adapter/_intermediary_low.py +++ b/src/python/grpcio/grpc/_adapter/_intermediary_low.py @@ -253,10 +253,10 @@ class Server(object): class ClientCredentials(object): - """Adapter from old _low.ClientCredentials interface to new _low.ClientCredentials.""" + """Adapter from old _low.ClientCredentials interface to new _low.ChannelCredentials.""" def __init__(self, root_certificates, private_key, certificate_chain): - self._internal = _low.ClientCredentials.ssl(root_certificates, private_key, certificate_chain) + self._internal = _low.ChannelCredentials.ssl(root_certificates, private_key, certificate_chain) class ServerCredentials(object): diff --git a/src/python/grpcio/grpc/_adapter/_low.py b/src/python/grpcio/grpc/_adapter/_low.py index 70ceb2a911..57146aaefe 100644 --- a/src/python/grpcio/grpc/_adapter/_low.py +++ b/src/python/grpcio/grpc/_adapter/_low.py @@ -33,7 +33,8 @@ from grpc._adapter import _types _USER_AGENT = 'Python-gRPC-{}'.format(_grpcio_metadata.__version__) -ClientCredentials = _c.ClientCredentials +ChannelCredentials = _c.ChannelCredentials +CallCredentials = _c.CallCredentials ServerCredentials = _c.ServerCredentials diff --git a/src/python/grpcio/grpc/_adapter/_types.py b/src/python/grpcio/grpc/_adapter/_types.py index 5470d2de4a..ca0fa066bc 100644 --- a/src/python/grpcio/grpc/_adapter/_types.py +++ b/src/python/grpcio/grpc/_adapter/_types.py @@ -323,6 +323,14 @@ class Call: """ return None + def set_credentials(self, creds): + """Set per-call credentials. + + Args: + creds (CallCredentials): Credentials to be set for this call. + """ + return None + class Channel: __metaclass__ = abc.ABCMeta @@ -334,7 +342,7 @@ class Channel: Args: target (str): ... args (sequence of 2-sequence of str, (str|integer)): ... - credentials (ClientCredentials): If None, create an insecure channel, + credentials (ChannelCredentials): If None, create an insecure channel, else create a secure channel using the client credentials. """ diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx b/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx index ed037b660a..51c4668138 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx +++ b/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx @@ -29,6 +29,7 @@ cimport cpython +from grpc._cython._cygrpc cimport credentials from grpc._cython._cygrpc cimport grpc from grpc._cython._cygrpc cimport records @@ -73,6 +74,11 @@ cdef class Call: else: return grpc.grpc_call_cancel(self.c_call, NULL) + def set_credentials( + self, credentials.CallCredentials call_credentials not None): + return grpc.grpc_call_set_credentials( + self.c_call, call_credentials.c_credentials) + def __dealloc__(self): if self.c_call != NULL: grpc.grpc_call_destroy(self.c_call) diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx b/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx index b52ddb6bcd..e25db3e2a4 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx +++ b/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx @@ -37,7 +37,7 @@ from grpc._cython._cygrpc cimport records cdef class Channel: def __cinit__(self, target, records.ChannelArgs arguments=None, - credentials.ClientCredentials client_credentials=None): + credentials.ChannelCredentials channel_credentials=None): cdef grpc.grpc_channel_args *c_arguments = NULL self.c_channel = NULL self.references = [] @@ -49,13 +49,13 @@ cdef class Channel: target = target.encode() else: raise TypeError("expected target to be str or bytes") - if client_credentials is None: + if channel_credentials is None: self.c_channel = grpc.grpc_insecure_channel_create(target, c_arguments, NULL) else: self.c_channel = grpc.grpc_secure_channel_create( - client_credentials.c_credentials, target, c_arguments, NULL) - self.references.append(client_credentials) + channel_credentials.c_credentials, target, c_arguments, NULL) + self.references.append(channel_credentials) self.references.append(target) self.references.append(arguments) diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd index 6b74a267e0..7a9fa7b76d 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd +++ b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd @@ -30,13 +30,19 @@ from grpc._cython._cygrpc cimport grpc -cdef class ClientCredentials: +cdef class ChannelCredentials: - cdef grpc.grpc_credentials *c_credentials + cdef grpc.grpc_channel_credentials *c_credentials cdef grpc.grpc_ssl_pem_key_cert_pair c_ssl_pem_key_cert_pair cdef list references +cdef class CallCredentials: + + cdef grpc.grpc_call_credentials *c_credentials + cdef list references + + cdef class ServerCredentials: cdef grpc.grpc_server_credentials *c_credentials diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx index 608207f0a2..e9836fec2c 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx +++ b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx @@ -31,7 +31,7 @@ from grpc._cython._cygrpc cimport grpc from grpc._cython._cygrpc cimport records -cdef class ClientCredentials: +cdef class ChannelCredentials: def __cinit__(self): self.c_credentials = NULL @@ -47,7 +47,24 @@ cdef class ClientCredentials: def __dealloc__(self): if self.c_credentials != NULL: - grpc.grpc_credentials_release(self.c_credentials) + grpc.grpc_channel_credentials_release(self.c_credentials) + + +cdef class CallCredentials: + + def __cinit__(self): + self.c_credentials = NULL + self.references = [] + + # The object *can* be invalid in Python if we fail to make the credentials + # (and the core thus returns NULL credentials). Used primarily for debugging. + @property + def is_valid(self): + return self.c_credentials != NULL + + def __dealloc__(self): + if self.c_credentials != NULL: + grpc.grpc_call_credentials_release(self.c_credentials) cdef class ServerCredentials: @@ -60,12 +77,12 @@ cdef class ServerCredentials: grpc.grpc_server_credentials_release(self.c_credentials) -def client_credentials_google_default(): - cdef ClientCredentials credentials = ClientCredentials(); +def channel_credentials_google_default(): + cdef ChannelCredentials credentials = ChannelCredentials(); credentials.c_credentials = grpc.grpc_google_default_credentials_create() return credentials -def client_credentials_ssl(pem_root_certificates, +def channel_credentials_ssl(pem_root_certificates, records.SslPemKeyCertPair ssl_pem_key_cert_pair): if pem_root_certificates is None: pass @@ -75,7 +92,7 @@ def client_credentials_ssl(pem_root_certificates, pem_root_certificates = pem_root_certificates.encode() else: raise TypeError("expected str or bytes for pem_root_certificates") - cdef ClientCredentials credentials = ClientCredentials() + cdef ChannelCredentials credentials = ChannelCredentials() cdef const char *c_pem_root_certificates = NULL if pem_root_certificates is not None: c_pem_root_certificates = pem_root_certificates @@ -88,26 +105,38 @@ def client_credentials_ssl(pem_root_certificates, credentials.c_credentials = grpc.grpc_ssl_credentials_create( c_pem_root_certificates, NULL, NULL) -def client_credentials_composite_credentials( - ClientCredentials credentials_1 not None, - ClientCredentials credentials_2 not None): +def channel_credentials_composite( + ChannelCredentials credentials_1 not None, + CallCredentials credentials_2 not None): + if not credentials_1.is_valid or not credentials_2.is_valid: + raise ValueError("passed credentials must both be valid") + cdef ChannelCredentials credentials = ChannelCredentials() + credentials.c_credentials = grpc.grpc_composite_channel_credentials_create( + credentials_1.c_credentials, credentials_2.c_credentials, NULL) + credentials.references.append(credentials_1) + credentials.references.append(credentials_2) + return credentials + +def call_credentials_composite( + CallCredentials credentials_1 not None, + CallCredentials credentials_2 not None): if not credentials_1.is_valid or not credentials_2.is_valid: raise ValueError("passed credentials must both be valid") - cdef ClientCredentials credentials = ClientCredentials() - credentials.c_credentials = grpc.grpc_composite_credentials_create( + cdef CallCredentials credentials = CallCredentials() + credentials.c_credentials = grpc.grpc_composite_call_credentials_create( credentials_1.c_credentials, credentials_2.c_credentials, NULL) credentials.references.append(credentials_1) credentials.references.append(credentials_2) return credentials -def client_credentials_google_compute_engine(): - cdef ClientCredentials credentials = ClientCredentials() +def call_credentials_google_compute_engine(): + cdef CallCredentials credentials = CallCredentials() credentials.c_credentials = ( grpc.grpc_google_compute_engine_credentials_create(NULL)) return credentials #TODO rename to something like client_credentials_service_account_jwt_access. -def client_credentials_service_account_jwt_access( +def call_credentials_service_account_jwt_access( json_key, records.Timespec token_lifetime not None): if isinstance(json_key, bytes): pass @@ -115,27 +144,27 @@ def client_credentials_service_account_jwt_access( json_key = json_key.encode() else: raise TypeError("expected json_key to be str or bytes") - cdef ClientCredentials credentials = ClientCredentials() + cdef CallCredentials credentials = CallCredentials() credentials.c_credentials = ( grpc.grpc_service_account_jwt_access_credentials_create( json_key, token_lifetime.c_time, NULL)) credentials.references.append(json_key) return credentials -def client_credentials_google_refresh_token(json_refresh_token): +def call_credentials_google_refresh_token(json_refresh_token): if isinstance(json_refresh_token, bytes): pass elif isinstance(json_refresh_token, basestring): json_refresh_token = json_refresh_token.encode() else: raise TypeError("expected json_refresh_token to be str or bytes") - cdef ClientCredentials credentials = ClientCredentials() + cdef CallCredentials credentials = CallCredentials() credentials.c_credentials = grpc.grpc_google_refresh_token_credentials_create( json_refresh_token, NULL) credentials.references.append(json_refresh_token) return credentials -def client_credentials_google_iam(authorization_token, authority_selector): +def call_credentials_google_iam(authorization_token, authority_selector): if isinstance(authorization_token, bytes): pass elif isinstance(authorization_token, basestring): @@ -148,7 +177,7 @@ def client_credentials_google_iam(authorization_token, authority_selector): authority_selector = authority_selector.encode() else: raise TypeError("expected authority_selector to be str or bytes") - cdef ClientCredentials credentials = ClientCredentials() + cdef CallCredentials credentials = CallCredentials() credentials.c_credentials = grpc.grpc_google_iam_credentials_create( authorization_token, authority_selector, NULL) credentials.references.append(authorization_token) diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd index 62d40e7a58..36aea81a6c 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd +++ b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd @@ -316,32 +316,40 @@ cdef extern from "grpc/grpc_security.h": const char *private_key const char *certificate_chain "cert_chain" - ctypedef struct grpc_credentials: + ctypedef struct grpc_channel_credentials: # We don't care about the internals (and in fact don't know them) pass - grpc_credentials *grpc_google_default_credentials_create() - grpc_credentials *grpc_ssl_credentials_create( + ctypedef struct grpc_call_credentials: + # We don't care about the internals (and in fact don't know them) + pass + + grpc_channel_credentials *grpc_google_default_credentials_create() + grpc_channel_credentials *grpc_ssl_credentials_create( const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair, void *reserved) + grpc_channel_credentials *grpc_composite_channel_credentials_create( + grpc_channel_credentials *creds1, grpc_call_credentials *creds2, + void *reserved) + void grpc_channel_credentials_release(grpc_channel_credentials *creds) - grpc_credentials *grpc_composite_credentials_create(grpc_credentials *creds1, - grpc_credentials *creds2, - void *reserved) - grpc_credentials *grpc_google_compute_engine_credentials_create( + grpc_call_credentials *grpc_composite_call_credentials_create( + grpc_call_credentials *creds1, grpc_call_credentials *creds2, + void *reserved) + grpc_call_credentials *grpc_google_compute_engine_credentials_create( void *reserved) - grpc_credentials *grpc_service_account_jwt_access_credentials_create( + grpc_call_credentials *grpc_service_account_jwt_access_credentials_create( const char *json_key, gpr_timespec token_lifetime, void *reserved) - grpc_credentials *grpc_google_refresh_token_credentials_create( + grpc_call_credentials *grpc_google_refresh_token_credentials_create( const char *json_refresh_token, void *reserved) - grpc_credentials *grpc_google_iam_credentials_create( + grpc_call_credentials *grpc_google_iam_credentials_create( const char *authorization_token, const char *authority_selector, void *reserved) - void grpc_credentials_release(grpc_credentials *creds) + void grpc_call_credentials_release(grpc_call_credentials *creds) grpc_channel *grpc_secure_channel_create( - grpc_credentials *creds, const char *target, + grpc_channel_credentials *creds, const char *target, const grpc_channel_args *args, void *reserved) ctypedef struct grpc_server_credentials: @@ -358,4 +366,4 @@ cdef extern from "grpc/grpc_security.h": grpc_server_credentials *creds) grpc_call_error grpc_call_set_credentials(grpc_call *call, - grpc_credentials *creds) + grpc_call_credentials *creds) diff --git a/src/python/grpcio/grpc/_cython/cygrpc.pyx b/src/python/grpcio/grpc/_cython/cygrpc.pyx index 1ef2997db5..b20dda8a95 100644 --- a/src/python/grpcio/grpc/_cython/cygrpc.pyx +++ b/src/python/grpcio/grpc/_cython/cygrpc.pyx @@ -70,21 +70,24 @@ operation_receive_close_on_server = records.operation_receive_close_on_server Operations = records.Operations -ClientCredentials = credentials.ClientCredentials +CallCredentials = credentials.CallCredentials +ChannelCredentials = credentials.ChannelCredentials ServerCredentials = credentials.ServerCredentials -client_credentials_google_default = ( - credentials.client_credentials_google_default) -client_credentials_ssl = credentials.client_credentials_ssl -client_credentials_composite_credentials = ( - credentials.client_credentials_composite_credentials) -client_credentials_google_compute_engine = ( - credentials.client_credentials_google_compute_engine) -client_credentials_jwt_access = ( - credentials.client_credentials_service_account_jwt_access) -client_credentials_refresh_token = ( - credentials.client_credentials_google_refresh_token) -client_credentials_google_iam = credentials.client_credentials_google_iam +channel_credentials_google_default = ( + credentials.channel_credentials_google_default) +channel_credentials_ssl = credentials.channel_credentials_ssl +channel_credentials_composite = ( + credentials.channel_credentials_composite) +call_credentials_composite = ( + credentials.call_credentials_composite) +call_credentials_google_compute_engine = ( + credentials.call_credentials_google_compute_engine) +call_credentials_jwt_access = ( + credentials.call_credentials_service_account_jwt_access) +call_credentials_refresh_token = ( + credentials.call_credentials_google_refresh_token) +call_credentials_google_iam = credentials.call_credentials_google_iam server_credentials_ssl = credentials.server_credentials_ssl CompletionQueue = completion_queue.CompletionQueue diff --git a/src/python/grpcio/grpc/beta/interfaces.py b/src/python/grpcio/grpc/beta/interfaces.py index 07c8618f70..d4ca56500f 100644 --- a/src/python/grpcio/grpc/beta/interfaces.py +++ b/src/python/grpcio/grpc/beta/interfaces.py @@ -100,8 +100,11 @@ def grpc_call_options(disable_compression=False, credentials=None): disable_compression: A boolean indicating whether or not compression should be disabled for the request object of the RPC. Only valid for request-unary RPCs. - credentials: A ClientCredentials object to use for the invoked RPC. + credentials: Reserved for gRPC per-call credentials. The type for this does + not exist yet at the Python level. """ + if credentials is not None: + raise ValueError('`credentials` is a reserved argument') return GRPCCallOptions(disable_compression, None, credentials) diff --git a/src/python/grpcio/grpc/framework/interfaces/face/face.py b/src/python/grpcio/grpc/framework/interfaces/face/face.py index bc9a434a76..3b402356d2 100644 --- a/src/python/grpcio/grpc/framework/interfaces/face/face.py +++ b/src/python/grpcio/grpc/framework/interfaces/face/face.py @@ -117,6 +117,10 @@ class AbortionError(Exception): self.code = code self.details = details + def __str__(self): + return '%s(code=%s, details="%s")' % ( + self.__class__.__name__, self.code, self.details) + class CancellationError(AbortionError): """Indicates that an RPC has been cancelled.""" diff --git a/src/python/grpcio/setup.py b/src/python/grpcio/setup.py index 97fa4fe6b3..ec68eb6755 100644 --- a/src/python/grpcio/setup.py +++ b/src/python/grpcio/setup.py @@ -52,7 +52,8 @@ _C_EXTENSION_SOURCES = ( 'grpc/_adapter/_c/module.c', 'grpc/_adapter/_c/types.c', 'grpc/_adapter/_c/utility.c', - 'grpc/_adapter/_c/types/client_credentials.c', + 'grpc/_adapter/_c/types/call_credentials.c', + 'grpc/_adapter/_c/types/channel_credentials.c', 'grpc/_adapter/_c/types/server_credentials.c', 'grpc/_adapter/_c/types/completion_queue.c', 'grpc/_adapter/_c/types/call.c', diff --git a/src/python/grpcio_test/grpc_interop/credentials/server1.pem b/src/python/grpcio_test/grpc_interop/credentials/server1.pem index 8e582e571f..f3d43fcc5b 100755 --- a/src/python/grpcio_test/grpc_interop/credentials/server1.pem +++ b/src/python/grpcio_test/grpc_interop/credentials/server1.pem @@ -1,16 +1,16 @@ -----BEGIN CERTIFICATE----- -MIICmzCCAgSgAwIBAgIBAzANBgkqhkiG9w0BAQUFADBWMQswCQYDVQQGEwJBVTET -MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ -dHkgTHRkMQ8wDQYDVQQDDAZ0ZXN0Y2EwHhcNMTQwNzIyMDYwMDU3WhcNMjQwNzE5 -MDYwMDU3WjBkMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV -BAcTB0NoaWNhZ28xFDASBgNVBAoTC0dvb2dsZSBJbmMuMRowGAYDVQQDFBEqLnRl -c3QuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4cMVJygs -JUmlgMMzgdi0h1XoCR7+ww1pop04OMMyy7H/i0PJ2W6Y35+b4CM8QrkYeEafUGDO -RYX6yV/cHGGsD/x02ye6ey1UDtkGAD/mpDEx8YCrjAc1Vfvt8Fk6Cn1WVIxV/J30 -3xjBsFgByQ55RBp1OLZfVLo6AleBDSbcxaECAwEAAaNrMGkwCQYDVR0TBAIwADAL -BgNVHQ8EBAMCBeAwTwYDVR0RBEgwRoIQKi50ZXN0Lmdvb2dsZS5mcoIYd2F0ZXJ6 -b29pLnRlc3QuZ29vZ2xlLmJlghIqLnRlc3QueW91dHViZS5jb22HBMCoAQMwDQYJ -KoZIhvcNAQEFBQADgYEAM2Ii0LgTGbJ1j4oqX9bxVcxm+/R5Yf8oi0aZqTJlnLYS -wXcBykxTx181s7WyfJ49WwrYXo78zTDAnf1ma0fPq3e4mpspvyndLh1a+OarHa1e -aT0DIIYk7qeEa1YcVljx2KyLd0r1BBAfrwyGaEPVeJQVYWaOJRU2we/KD4ojf9s= +MIICnDCCAgWgAwIBAgIBBzANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJBVTET +MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ +dHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2EwHhcNMTUxMTA0MDIyMDI0WhcNMjUxMTAx +MDIyMDI0WjBlMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV +BAcTB0NoaWNhZ28xFTATBgNVBAoTDEV4YW1wbGUsIENvLjEaMBgGA1UEAxQRKi50 +ZXN0Lmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOHDFSco +LCVJpYDDM4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1Bg +zkWF+slf3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd +9N8YwbBYAckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAGjazBpMAkGA1UdEwQCMAAw +CwYDVR0PBAQDAgXgME8GA1UdEQRIMEaCECoudGVzdC5nb29nbGUuZnKCGHdhdGVy +em9vaS50ZXN0Lmdvb2dsZS5iZYISKi50ZXN0LnlvdXR1YmUuY29thwTAqAEDMA0G +CSqGSIb3DQEBCwUAA4GBAJFXVifQNub1LUP4JlnX5lXNlo8FxZ2a12AFQs+bzoJ6 +hM044EDjqyxUqSbVePK0ni3w1fHQB5rY9yYC5f8G7aqqTY1QOhoUk8ZTSTRpnkTh +y4jjdvTZeLDVBlueZUTDRmy2feY5aZIU18vFDK08dTG0A87pppuv1LNIR3loveU8 -----END CERTIFICATE----- diff --git a/src/python/grpcio_test/grpc_test/beta/_beta_features_test.py b/src/python/grpcio_test/grpc_test/beta/_beta_features_test.py index fad57da9d0..5916a9e3ea 100644 --- a/src/python/grpcio_test/grpc_test/beta/_beta_features_test.py +++ b/src/python/grpcio_test/grpc_test/beta/_beta_features_test.py @@ -181,24 +181,21 @@ class BetaFeaturesTest(unittest.TestCase): self._server.stop(test_constants.SHORT_TIMEOUT).wait() def test_unary_unary(self): - call_options = interfaces.grpc_call_options( - disable_compression=True, credentials=self._client_credentials) + call_options = interfaces.grpc_call_options(disable_compression=True) response = getattr(self._dynamic_stub, _UNARY_UNARY)( _REQUEST, test_constants.LONG_TIMEOUT, protocol_options=call_options) self.assertEqual(_RESPONSE, response) self.assertIsNotNone(self._servicer.peer()) def test_unary_stream(self): - call_options = interfaces.grpc_call_options( - disable_compression=True, credentials=self._client_credentials) + call_options = interfaces.grpc_call_options(disable_compression=True) response_iterator = getattr(self._dynamic_stub, _UNARY_STREAM)( _REQUEST, test_constants.LONG_TIMEOUT, protocol_options=call_options) self._servicer.block_until_serviced() self.assertIsNotNone(self._servicer.peer()) def test_stream_unary(self): - call_options = interfaces.grpc_call_options( - credentials=self._client_credentials) + call_options = interfaces.grpc_call_options() request_iterator = _BlockingIterator(iter((_REQUEST,))) response_future = getattr(self._dynamic_stub, _STREAM_UNARY).future( request_iterator, test_constants.LONG_TIMEOUT, @@ -212,8 +209,7 @@ class BetaFeaturesTest(unittest.TestCase): self.assertEqual(_RESPONSE, response_future.result()) def test_stream_stream(self): - call_options = interfaces.grpc_call_options( - credentials=self._client_credentials) + call_options = interfaces.grpc_call_options() request_iterator = _BlockingIterator(iter((_REQUEST,))) response_iterator = getattr(self._dynamic_stub, _STREAM_STREAM)( request_iterator, test_constants.SHORT_TIMEOUT, diff --git a/src/python/grpcio_test/grpc_test/credentials/server1.pem b/src/python/grpcio_test/grpc_test/credentials/server1.pem index 8e582e571f..f3d43fcc5b 100755 --- a/src/python/grpcio_test/grpc_test/credentials/server1.pem +++ b/src/python/grpcio_test/grpc_test/credentials/server1.pem @@ -1,16 +1,16 @@ -----BEGIN CERTIFICATE----- -MIICmzCCAgSgAwIBAgIBAzANBgkqhkiG9w0BAQUFADBWMQswCQYDVQQGEwJBVTET -MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ -dHkgTHRkMQ8wDQYDVQQDDAZ0ZXN0Y2EwHhcNMTQwNzIyMDYwMDU3WhcNMjQwNzE5 -MDYwMDU3WjBkMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV -BAcTB0NoaWNhZ28xFDASBgNVBAoTC0dvb2dsZSBJbmMuMRowGAYDVQQDFBEqLnRl -c3QuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4cMVJygs -JUmlgMMzgdi0h1XoCR7+ww1pop04OMMyy7H/i0PJ2W6Y35+b4CM8QrkYeEafUGDO -RYX6yV/cHGGsD/x02ye6ey1UDtkGAD/mpDEx8YCrjAc1Vfvt8Fk6Cn1WVIxV/J30 -3xjBsFgByQ55RBp1OLZfVLo6AleBDSbcxaECAwEAAaNrMGkwCQYDVR0TBAIwADAL -BgNVHQ8EBAMCBeAwTwYDVR0RBEgwRoIQKi50ZXN0Lmdvb2dsZS5mcoIYd2F0ZXJ6 -b29pLnRlc3QuZ29vZ2xlLmJlghIqLnRlc3QueW91dHViZS5jb22HBMCoAQMwDQYJ -KoZIhvcNAQEFBQADgYEAM2Ii0LgTGbJ1j4oqX9bxVcxm+/R5Yf8oi0aZqTJlnLYS -wXcBykxTx181s7WyfJ49WwrYXo78zTDAnf1ma0fPq3e4mpspvyndLh1a+OarHa1e -aT0DIIYk7qeEa1YcVljx2KyLd0r1BBAfrwyGaEPVeJQVYWaOJRU2we/KD4ojf9s= +MIICnDCCAgWgAwIBAgIBBzANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJBVTET +MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ +dHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2EwHhcNMTUxMTA0MDIyMDI0WhcNMjUxMTAx +MDIyMDI0WjBlMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV +BAcTB0NoaWNhZ28xFTATBgNVBAoTDEV4YW1wbGUsIENvLjEaMBgGA1UEAxQRKi50 +ZXN0Lmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOHDFSco +LCVJpYDDM4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1Bg +zkWF+slf3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd +9N8YwbBYAckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAGjazBpMAkGA1UdEwQCMAAw +CwYDVR0PBAQDAgXgME8GA1UdEQRIMEaCECoudGVzdC5nb29nbGUuZnKCGHdhdGVy +em9vaS50ZXN0Lmdvb2dsZS5iZYISKi50ZXN0LnlvdXR1YmUuY29thwTAqAEDMA0G +CSqGSIb3DQEBCwUAA4GBAJFXVifQNub1LUP4JlnX5lXNlo8FxZ2a12AFQs+bzoJ6 +hM044EDjqyxUqSbVePK0ni3w1fHQB5rY9yYC5f8G7aqqTY1QOhoUk8ZTSTRpnkTh +y4jjdvTZeLDVBlueZUTDRmy2feY5aZIU18vFDK08dTG0A87pppuv1LNIR3loveU8 -----END CERTIFICATE----- diff --git a/src/ruby/bin/apis/pubsub_demo.rb b/src/ruby/bin/apis/pubsub_demo.rb index a039d036ac..003e91a6b3 100755 --- a/src/ruby/bin/apis/pubsub_demo.rb +++ b/src/ruby/bin/apis/pubsub_demo.rb @@ -66,7 +66,7 @@ end # creates a SSL Credentials from the production certificates. def ssl_creds - GRPC::Core::Credentials.new(load_prod_cert) + GRPC::Core::ChannelCredentials.new(load_prod_cert) end # Builds the metadata authentication update proc. diff --git a/src/ruby/bin/math_client.rb b/src/ruby/bin/math_client.rb index 0ebd26f780..d7e00e4293 100755 --- a/src/ruby/bin/math_client.rb +++ b/src/ruby/bin/math_client.rb @@ -102,7 +102,7 @@ end def test_creds certs = load_test_certs - GRPC::Core::Credentials.new(certs[0]) + GRPC::Core::ChannelCredentials.new(certs[0]) end def main diff --git a/src/ruby/bin/noproto_client.rb b/src/ruby/bin/noproto_client.rb index 390a9c59c3..3aa11870c0 100755 --- a/src/ruby/bin/noproto_client.rb +++ b/src/ruby/bin/noproto_client.rb @@ -68,7 +68,7 @@ end def test_creds certs = load_test_certs - GRPC::Core::Credentials.new(certs[0]) + GRPC::Core::ChannelCredentials.new(certs[0]) end def main diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c index 6b5beb6f5d..40364328ee 100644 --- a/src/ruby/ext/grpc/rb_call.c +++ b/src/ruby/ext/grpc/rb_call.c @@ -139,7 +139,15 @@ static const rb_data_type_t grpc_rb_md_ary_data_type = { {NULL, NULL}}, NULL, NULL, - 0}; +#ifdef RUBY_TYPED_FREE_IMMEDIATELY + /* it is unsafe to specify RUBY_TYPED_FREE_IMMEDIATELY because + * grpc_rb_call_destroy + * touches a hash object. + * TODO(yugui) Directly use st_table and call the free function earlier? + */ + 0, +#endif +}; /* Describes grpc_call struct for RTypedData */ static const rb_data_type_t grpc_call_data_type = { @@ -148,12 +156,15 @@ static const rb_data_type_t grpc_call_data_type = { {NULL, NULL}}, NULL, NULL, +#ifdef RUBY_TYPED_FREE_IMMEDIATELY /* it is unsafe to specify RUBY_TYPED_FREE_IMMEDIATELY because * grpc_rb_call_destroy * touches a hash object. * TODO(yugui) Directly use st_table and call the free function earlier? */ - 0}; + 0, +#endif +}; /* Error code details is a hash containing text strings describing errors */ VALUE rb_error_code_details; diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c index 90afdc3fe1..d5d82421f5 100644 --- a/src/ruby/ext/grpc/rb_channel.c +++ b/src/ruby/ext/grpc/rb_channel.c @@ -41,8 +41,8 @@ #include "rb_grpc.h" #include "rb_call.h" #include "rb_channel_args.h" +#include "rb_channel_credentials.h" #include "rb_completion_queue.h" -#include "rb_credentials.h" #include "rb_server.h" /* id_channel is the name of the hidden ivar that preserves a reference to the @@ -111,7 +111,9 @@ static rb_data_type_t grpc_channel_data_type = { {grpc_rb_channel_mark, grpc_rb_channel_free, GRPC_RB_MEMSIZE_UNAVAILABLE, {NULL, NULL}}, NULL, NULL, +#ifdef RUBY_TYPED_FREE_IMMEDIATELY RUBY_TYPED_FREE_IMMEDIATELY +#endif }; /* Allocates grpc_rb_channel instances. */ @@ -134,8 +136,8 @@ static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) { VALUE credentials = Qnil; VALUE target = Qnil; grpc_rb_channel *wrapper = NULL; - grpc_credentials *creds = NULL; grpc_channel *ch = NULL; + grpc_channel_credentials *creds = NULL; char *target_chars = NULL; grpc_channel_args args; MEMZERO(&args, grpc_channel_args, 1); @@ -149,7 +151,7 @@ static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) { if (credentials == Qnil) { ch = grpc_insecure_channel_create(target_chars, &args, NULL); } else { - creds = grpc_rb_get_wrapped_credentials(credentials); + creds = grpc_rb_get_wrapped_channel_credentials(credentials); ch = grpc_secure_channel_create(creds, target_chars, &args, NULL); } if (args.args != NULL) { diff --git a/src/ruby/ext/grpc/rb_channel_args.c b/src/ruby/ext/grpc/rb_channel_args.c index 1ba30b69aa..37dd981925 100644 --- a/src/ruby/ext/grpc/rb_channel_args.c +++ b/src/ruby/ext/grpc/rb_channel_args.c @@ -44,7 +44,9 @@ static rb_data_type_t grpc_rb_channel_args_data_type = { {GRPC_RB_GC_NOT_MARKED, GRPC_RB_GC_DONT_FREE, GRPC_RB_MEMSIZE_UNAVAILABLE, {NULL, NULL}}, NULL, NULL, +#ifdef RUBY_TYPED_FREE_IMMEDIATELY RUBY_TYPED_FREE_IMMEDIATELY +#endif }; /* A callback the processes the hash key values in channel_args hash */ diff --git a/src/ruby/ext/grpc/rb_credentials.c b/src/ruby/ext/grpc/rb_channel_credentials.c index ae757f6986..072a6f54ab 100644 --- a/src/ruby/ext/grpc/rb_credentials.c +++ b/src/ruby/ext/grpc/rb_channel_credentials.c @@ -31,7 +31,7 @@ * */ -#include "rb_credentials.h" +#include "rb_channel_credentials.h" #include <ruby/ruby.h> @@ -40,32 +40,33 @@ #include "rb_grpc.h" -/* grpc_rb_cCredentials is the ruby class that proxies grpc_credentials. */ -static VALUE grpc_rb_cCredentials = Qnil; +/* grpc_rb_cChannelCredentials is the ruby class that proxies + grpc_channel_credentials. */ +static VALUE grpc_rb_cChannelCredentials = Qnil; -/* grpc_rb_credentials wraps a grpc_credentials. It provides a +/* grpc_rb_channel_credentials wraps a grpc_channel_credentials. It provides a * peer ruby object, 'mark' to minimize copying when a credential is * created from ruby. */ -typedef struct grpc_rb_credentials { +typedef struct grpc_rb_channel_credentials { /* Holder of ruby objects involved in constructing the credentials */ VALUE mark; /* The actual credentials */ - grpc_credentials *wrapped; -} grpc_rb_credentials; + grpc_channel_credentials *wrapped; +} grpc_rb_channel_credentials; /* Destroys the credentials instances. */ -static void grpc_rb_credentials_free(void *p) { - grpc_rb_credentials *wrapper = NULL; +static void grpc_rb_channel_credentials_free(void *p) { + grpc_rb_channel_credentials *wrapper = NULL; if (p == NULL) { return; }; - wrapper = (grpc_rb_credentials *)p; + wrapper = (grpc_rb_channel_credentials *)p; /* Delete the wrapped object if the mark object is Qnil, which indicates that * no other object is the actual owner. */ if (wrapper->wrapped != NULL && wrapper->mark == Qnil) { - grpc_credentials_release(wrapper->wrapped); + grpc_channel_credentials_release(wrapper->wrapped); wrapper->wrapped = NULL; } @@ -73,12 +74,12 @@ static void grpc_rb_credentials_free(void *p) { } /* Protects the mark object from GC */ -static void grpc_rb_credentials_mark(void *p) { - grpc_rb_credentials *wrapper = NULL; +static void grpc_rb_channel_credentials_mark(void *p) { + grpc_rb_channel_credentials *wrapper = NULL; if (p == NULL) { return; } - wrapper = (grpc_rb_credentials *)p; + wrapper = (grpc_rb_channel_credentials *)p; /* If it's not already cleaned up, mark the mark object */ if (wrapper->mark != Qnil) { @@ -86,29 +87,32 @@ static void grpc_rb_credentials_mark(void *p) { } } -static rb_data_type_t grpc_rb_credentials_data_type = { - "grpc_credentials", - {grpc_rb_credentials_mark, grpc_rb_credentials_free, +static rb_data_type_t grpc_rb_channel_credentials_data_type = { + "grpc_channel_credentials", + {grpc_rb_channel_credentials_mark, grpc_rb_channel_credentials_free, GRPC_RB_MEMSIZE_UNAVAILABLE, {NULL, NULL}}, NULL, NULL, - RUBY_TYPED_FREE_IMMEDIATELY}; +#ifdef RUBY_TYPED_FREE_IMMEDIATELY + RUBY_TYPED_FREE_IMMEDIATELY +#endif +}; -/* Allocates Credential instances. +/* Allocates ChannelCredential instances. Provides safe initial defaults for the instance fields. */ -static VALUE grpc_rb_credentials_alloc(VALUE cls) { - grpc_rb_credentials *wrapper = ALLOC(grpc_rb_credentials); +static VALUE grpc_rb_channel_credentials_alloc(VALUE cls) { + grpc_rb_channel_credentials *wrapper = ALLOC(grpc_rb_channel_credentials); wrapper->wrapped = NULL; wrapper->mark = Qnil; - return TypedData_Wrap_Struct(cls, &grpc_rb_credentials_data_type, wrapper); + return TypedData_Wrap_Struct(cls, &grpc_rb_channel_credentials_data_type, wrapper); } -/* Clones Credentials instances. - Gives Credentials a consistent implementation of Ruby's object copy/dup +/* Clones ChannelCredentials instances. + Gives ChannelCredentials a consistent implementation of Ruby's object copy/dup protocol. */ -static VALUE grpc_rb_credentials_init_copy(VALUE copy, VALUE orig) { - grpc_rb_credentials *orig_cred = NULL; - grpc_rb_credentials *copy_cred = NULL; +static VALUE grpc_rb_channel_credentials_init_copy(VALUE copy, VALUE orig) { + grpc_rb_channel_credentials *orig_cred = NULL; + grpc_rb_channel_credentials *copy_cred = NULL; if (copy == orig) { return copy; @@ -116,83 +120,22 @@ static VALUE grpc_rb_credentials_init_copy(VALUE copy, VALUE orig) { /* Raise an error if orig is not a credentials object or a subclass. */ if (TYPE(orig) != T_DATA || - RDATA(orig)->dfree != (RUBY_DATA_FUNC)grpc_rb_credentials_free) { - rb_raise(rb_eTypeError, "not a %s", rb_obj_classname(grpc_rb_cCredentials)); + RDATA(orig)->dfree != (RUBY_DATA_FUNC)grpc_rb_channel_credentials_free) { + rb_raise(rb_eTypeError, "not a %s", + rb_obj_classname(grpc_rb_cChannelCredentials)); } - TypedData_Get_Struct(orig, grpc_rb_credentials, - &grpc_rb_credentials_data_type, orig_cred); - TypedData_Get_Struct(copy, grpc_rb_credentials, - &grpc_rb_credentials_data_type, copy_cred); + TypedData_Get_Struct(orig, grpc_rb_channel_credentials, + &grpc_rb_channel_credentials_data_type, orig_cred); + TypedData_Get_Struct(copy, grpc_rb_channel_credentials, + &grpc_rb_channel_credentials_data_type, copy_cred); /* use ruby's MEMCPY to make a byte-for-byte copy of the credentials * wrapper object. */ - MEMCPY(copy_cred, orig_cred, grpc_rb_credentials, 1); + MEMCPY(copy_cred, orig_cred, grpc_rb_channel_credentials, 1); return copy; } -/* - call-seq: - creds = Credentials.default() - Creates the default credential instances. */ -static VALUE grpc_rb_default_credentials_create(VALUE cls) { - grpc_rb_credentials *wrapper = ALLOC(grpc_rb_credentials); - wrapper->wrapped = grpc_google_default_credentials_create(); - if (wrapper->wrapped == NULL) { - rb_raise(rb_eRuntimeError, - "could not create default credentials, not sure why"); - return Qnil; - } - - wrapper->mark = Qnil; - return TypedData_Wrap_Struct(cls, &grpc_rb_credentials_data_type, wrapper); -} - -/* - call-seq: - creds = Credentials.compute_engine() - Creates the default credential instances. */ -static VALUE grpc_rb_compute_engine_credentials_create(VALUE cls) { - grpc_rb_credentials *wrapper = ALLOC(grpc_rb_credentials); - wrapper->wrapped = grpc_google_compute_engine_credentials_create(NULL); - if (wrapper->wrapped == NULL) { - rb_raise(rb_eRuntimeError, - "could not create composite engine credentials, not sure why"); - return Qnil; - } - - wrapper->mark = Qnil; - return TypedData_Wrap_Struct(cls, &grpc_rb_credentials_data_type, wrapper); -} - -/* - call-seq: - creds1 = ... - creds2 = ... - creds3 = creds1.add(creds2) - Creates the default credential instances. */ -static VALUE grpc_rb_composite_credentials_create(VALUE self, VALUE other) { - grpc_rb_credentials *self_wrapper = NULL; - grpc_rb_credentials *other_wrapper = NULL; - grpc_rb_credentials *wrapper = NULL; - - TypedData_Get_Struct(self, grpc_rb_credentials, - &grpc_rb_credentials_data_type, self_wrapper); - TypedData_Get_Struct(other, grpc_rb_credentials, - &grpc_rb_credentials_data_type, other_wrapper); - wrapper = ALLOC(grpc_rb_credentials); - wrapper->wrapped = grpc_composite_credentials_create( - self_wrapper->wrapped, other_wrapper->wrapped, NULL); - if (wrapper->wrapped == NULL) { - rb_raise(rb_eRuntimeError, - "could not create composite credentials, not sure why"); - return Qnil; - } - - wrapper->mark = Qnil; - return TypedData_Wrap_Struct(grpc_rb_cCredentials, - &grpc_rb_credentials_data_type, wrapper); -} /* The attribute used on the mark object to hold the pem_root_certs. */ static ID id_pem_root_certs; @@ -213,12 +156,12 @@ static ID id_pem_cert_chain; pem_private_key: (optional) PEM encoding of the client's private key pem_cert_chain: (optional) PEM encoding of the client's cert chain Initializes Credential instances. */ -static VALUE grpc_rb_credentials_init(int argc, VALUE *argv, VALUE self) { +static VALUE grpc_rb_channel_credentials_init(int argc, VALUE *argv, VALUE self) { VALUE pem_root_certs = Qnil; VALUE pem_private_key = Qnil; VALUE pem_cert_chain = Qnil; - grpc_rb_credentials *wrapper = NULL; - grpc_credentials *creds = NULL; + grpc_rb_channel_credentials *wrapper = NULL; + grpc_channel_credentials *creds = NULL; grpc_ssl_pem_key_cert_pair key_cert_pair; MEMZERO(&key_cert_pair, grpc_ssl_pem_key_cert_pair, 1); /* TODO: Remove mandatory arg when we support default roots. */ @@ -226,8 +169,8 @@ static VALUE grpc_rb_credentials_init(int argc, VALUE *argv, VALUE self) { rb_scan_args(argc, argv, "12", &pem_root_certs, &pem_private_key, &pem_cert_chain); - TypedData_Get_Struct(self, grpc_rb_credentials, - &grpc_rb_credentials_data_type, wrapper); + TypedData_Get_Struct(self, grpc_rb_channel_credentials, + &grpc_rb_channel_credentials_data_type, wrapper); if (pem_root_certs == Qnil) { rb_raise(rb_eRuntimeError, "could not create a credential: nil pem_root_certs"); @@ -256,39 +199,30 @@ static VALUE grpc_rb_credentials_init(int argc, VALUE *argv, VALUE self) { return self; } -void Init_grpc_credentials() { - grpc_rb_cCredentials = - rb_define_class_under(grpc_rb_mGrpcCore, "Credentials", rb_cObject); +void Init_grpc_channel_credentials() { + grpc_rb_cChannelCredentials = + rb_define_class_under(grpc_rb_mGrpcCore, "ChannelCredentials", rb_cObject); /* Allocates an object managed by the ruby runtime */ - rb_define_alloc_func(grpc_rb_cCredentials, grpc_rb_credentials_alloc); + rb_define_alloc_func(grpc_rb_cChannelCredentials, + grpc_rb_channel_credentials_alloc); /* Provides a ruby constructor and support for dup/clone. */ - rb_define_method(grpc_rb_cCredentials, "initialize", grpc_rb_credentials_init, - -1); - rb_define_method(grpc_rb_cCredentials, "initialize_copy", - grpc_rb_credentials_init_copy, 1); - - /* Provide static funcs that create new special instances. */ - rb_define_singleton_method(grpc_rb_cCredentials, "default", - grpc_rb_default_credentials_create, 0); - - rb_define_singleton_method(grpc_rb_cCredentials, "compute_engine", - grpc_rb_compute_engine_credentials_create, 0); - - /* Provide other methods. */ - rb_define_method(grpc_rb_cCredentials, "compose", - grpc_rb_composite_credentials_create, 1); + rb_define_method(grpc_rb_cChannelCredentials, "initialize", + grpc_rb_channel_credentials_init, -1); + rb_define_method(grpc_rb_cChannelCredentials, "initialize_copy", + grpc_rb_channel_credentials_init_copy, 1); id_pem_cert_chain = rb_intern("__pem_cert_chain"); id_pem_private_key = rb_intern("__pem_private_key"); id_pem_root_certs = rb_intern("__pem_root_certs"); } -/* Gets the wrapped grpc_credentials from the ruby wrapper */ -grpc_credentials *grpc_rb_get_wrapped_credentials(VALUE v) { - grpc_rb_credentials *wrapper = NULL; - TypedData_Get_Struct(v, grpc_rb_credentials, &grpc_rb_credentials_data_type, +/* Gets the wrapped grpc_channel_credentials from the ruby wrapper */ +grpc_channel_credentials *grpc_rb_get_wrapped_channel_credentials(VALUE v) { + grpc_rb_channel_credentials *wrapper = NULL; + TypedData_Get_Struct(v, grpc_rb_channel_credentials, + &grpc_rb_channel_credentials_data_type, wrapper); return wrapper->wrapped; } diff --git a/src/ruby/ext/grpc/rb_credentials.h b/src/ruby/ext/grpc/rb_channel_credentials.h index 840f7d5f9c..15229de932 100644 --- a/src/ruby/ext/grpc/rb_credentials.h +++ b/src/ruby/ext/grpc/rb_channel_credentials.h @@ -38,10 +38,10 @@ #include <grpc/grpc_security.h> -/* Initializes the ruby Credentials class. */ -void Init_grpc_credentials(); +/* Initializes the ruby ChannelCredentials class. */ +void Init_grpc_channel_credentials(); /* Gets the wrapped credentials from the ruby wrapper */ -grpc_credentials* grpc_rb_get_wrapped_credentials(VALUE v); +grpc_channel_credentials* grpc_rb_get_wrapped_channel_credentials(VALUE v); #endif /* GRPC_RB_CREDENTIALS_H_ */ diff --git a/src/ruby/ext/grpc/rb_completion_queue.c b/src/ruby/ext/grpc/rb_completion_queue.c index 0bc9eb2a97..a7de96d718 100644 --- a/src/ruby/ext/grpc/rb_completion_queue.c +++ b/src/ruby/ext/grpc/rb_completion_queue.c @@ -121,9 +121,11 @@ static rb_data_type_t grpc_rb_completion_queue_data_type = { {GRPC_RB_GC_NOT_MARKED, grpc_rb_completion_queue_destroy, GRPC_RB_MEMSIZE_UNAVAILABLE, {NULL, NULL}}, NULL, NULL, +#ifdef RUBY_TYPED_FREE_IMMEDIATELY /* cannot immediately free because grpc_rb_completion_queue_shutdown_drain * calls rb_thread_call_without_gvl. */ - 0 + 0, +#endif }; /* Allocates a completion queue. */ diff --git a/src/ruby/ext/grpc/rb_grpc.c b/src/ruby/ext/grpc/rb_grpc.c index 327fd1a4fc..7c7c2d3440 100644 --- a/src/ruby/ext/grpc/rb_grpc.c +++ b/src/ruby/ext/grpc/rb_grpc.c @@ -42,9 +42,9 @@ #include <grpc/support/time.h> #include "rb_call.h" #include "rb_channel.h" +#include "rb_channel_credentials.h" #include "rb_completion_queue.h" #include "rb_server.h" -#include "rb_credentials.h" #include "rb_server_credentials.h" static VALUE grpc_rb_cTimeVal = Qnil; @@ -55,7 +55,10 @@ static rb_data_type_t grpc_rb_timespec_data_type = { {NULL, NULL}}, NULL, NULL, - RUBY_TYPED_FREE_IMMEDIATELY}; +#ifdef RUBY_TYPED_FREE_IMMEDIATELY + RUBY_TYPED_FREE_IMMEDIATELY +#endif +}; /* Alloc func that blocks allocation of a given object by raising an * exception. */ @@ -262,10 +265,20 @@ static void Init_grpc_time_consts() { id_tv_nsec = rb_intern("tv_nsec"); } +/* + TODO: find an alternative to ruby_vm_at_exit that is ok in Ruby 2.0 where + RUBY_TYPED_FREE_IMMEDIATELY is not defined. + + At the moment, registering a function using ruby_vm_at_exit segfaults in Ruby + 2.0. This is not an issue with the gRPC handler. More likely, this was an + in issue with 2.0 that got resolved in 2.1 and has not been backported. +*/ +#ifdef RUBY_TYPED_FREE_IMMEDIATELY static void grpc_rb_shutdown(ruby_vm_t *vm) { (void)vm; grpc_shutdown(); } +#endif /* Initialize the GRPC module structs */ @@ -285,7 +298,12 @@ VALUE sym_metadata = Qundef; void Init_grpc() { grpc_init(); + +/* TODO: find alternative to ruby_vm_at_exit that is ok in Ruby 2.0 */ +#ifdef RUBY_TYPED_FREE_IMMEDIATELY ruby_vm_at_exit(grpc_rb_shutdown); +#endif + grpc_rb_mGRPC = rb_define_module("GRPC"); grpc_rb_mGrpcCore = rb_define_module_under(grpc_rb_mGRPC, "Core"); grpc_rb_sNewServerRpc = @@ -300,7 +318,7 @@ void Init_grpc() { Init_grpc_channel(); Init_grpc_completion_queue(); Init_grpc_call(); - Init_grpc_credentials(); + Init_grpc_channel_credentials(); Init_grpc_server(); Init_grpc_server_credentials(); Init_grpc_status_codes(); diff --git a/src/ruby/ext/grpc/rb_server.c b/src/ruby/ext/grpc/rb_server.c index 4469658869..ebdd7e1a34 100644 --- a/src/ruby/ext/grpc/rb_server.c +++ b/src/ruby/ext/grpc/rb_server.c @@ -101,11 +101,14 @@ static const rb_data_type_t grpc_rb_server_data_type = { {NULL, NULL}}, NULL, NULL, +#ifdef RUBY_TYPED_FREE_IMMEDIATELY /* It is unsafe to specify RUBY_TYPED_FREE_IMMEDIATELY because the free function would block * and we might want to unlock GVL * TODO(yugui) Unlock GVL? */ - 0}; + 0, +#endif +}; /* Allocates grpc_rb_server instances. */ static VALUE grpc_rb_server_alloc(VALUE cls) { diff --git a/src/ruby/ext/grpc/rb_server_credentials.c b/src/ruby/ext/grpc/rb_server_credentials.c index ea4d0d864e..de57585e0b 100644 --- a/src/ruby/ext/grpc/rb_server_credentials.c +++ b/src/ruby/ext/grpc/rb_server_credentials.c @@ -91,7 +91,9 @@ static const rb_data_type_t grpc_rb_server_credentials_data_type = { {grpc_rb_server_credentials_mark, grpc_rb_server_credentials_free, GRPC_RB_MEMSIZE_UNAVAILABLE, {NULL, NULL}}, NULL, NULL, +#ifdef RUBY_TYPED_FREE_IMMEDIATELY RUBY_TYPED_FREE_IMMEDIATELY +#endif }; /* Allocates ServerCredential instances. diff --git a/src/ruby/lib/grpc/generic/active_call.rb b/src/ruby/lib/grpc/generic/active_call.rb index d9cb924735..e80d24edc9 100644 --- a/src/ruby/lib/grpc/generic/active_call.rb +++ b/src/ruby/lib/grpc/generic/active_call.rb @@ -199,11 +199,7 @@ module GRPC # marshalled. def remote_send(req, marshalled = false) GRPC.logger.debug("sending #{req}, marshalled? #{marshalled}") - if marshalled - payload = req - else - payload = @marshal.call(req) - end + payload = marshalled ? req : @marshal.call(req) @call.run_batch(@cq, self, INFINITE_FUTURE, SEND_MESSAGE => payload) end @@ -417,7 +413,9 @@ module GRPC # @return [Enumerator, nil] a response Enumerator def bidi_streamer(requests, **kw, &blk) start_call(**kw) unless @started - bd = BidiCall.new(@call, @cq, @marshal, @unmarshal) + bd = BidiCall.new(@call, @cq, @marshal, @unmarshal, + metadata_tag: @metadata_tag) + @metadata_tag = nil # run_on_client ensures metadata is read bd.run_on_client(requests, @op_notifier, &blk) end diff --git a/src/ruby/lib/grpc/generic/bidi_call.rb b/src/ruby/lib/grpc/generic/bidi_call.rb index 9dbbb74caf..6b9b785693 100644 --- a/src/ruby/lib/grpc/generic/bidi_call.rb +++ b/src/ruby/lib/grpc/generic/bidi_call.rb @@ -56,7 +56,8 @@ module GRPC # the call # @param marshal [Function] f(obj)->string that marshal requests # @param unmarshal [Function] f(string)->obj that unmarshals responses - def initialize(call, q, marshal, unmarshal) + # @param metadata_tag [Object] tag object used to collect metadata + def initialize(call, q, marshal, unmarshal, metadata_tag: nil) fail(ArgumentError, 'not a call') unless call.is_a? Core::Call unless q.is_a? Core::CompletionQueue fail(ArgumentError, 'not a CompletionQueue') @@ -67,6 +68,7 @@ module GRPC @op_notifier = nil # signals completion on clients @readq = Queue.new @unmarshal = unmarshal + @metadata_tag = metadata_tag end # Begins orchestration of the Bidi stream for a client sending requests. @@ -113,6 +115,18 @@ module GRPC @op_notifier.notify(self) end + # performs a read using @call.run_batch, ensures metadata is set up + def read_using_run_batch + ops = { RECV_MESSAGE => nil } + ops[RECV_INITIAL_METADATA] = nil unless @metadata_tag.nil? + batch_result = @call.run_batch(@cq, self, INFINITE_FUTURE, ops) + unless @metadata_tag.nil? + @call.metadata = batch_result.metadata + @metadata_tag = nil + end + batch_result + end + # each_queued_msg yields each message on this instances readq # # - messages are added to the readq by #read_loop @@ -169,9 +183,7 @@ module GRPC loop do GRPC.logger.debug("bidi-read-loop: #{count}") count += 1 - # TODO: ensure metadata is read if available, currently it's not - batch_result = @call.run_batch(@cq, read_tag, INFINITE_FUTURE, - RECV_MESSAGE => nil) + batch_result = read_using_run_batch # handle the next message if batch_result.message.nil? diff --git a/src/ruby/lib/grpc/generic/client_stub.rb b/src/ruby/lib/grpc/generic/client_stub.rb index b8e33ad295..90aaa026ec 100644 --- a/src/ruby/lib/grpc/generic/client_stub.rb +++ b/src/ruby/lib/grpc/generic/client_stub.rb @@ -51,7 +51,9 @@ module GRPC end kw['grpc.primary_user_agent'] = "grpc-ruby/#{VERSION}" return Core::Channel.new(host, kw) if creds.nil? - fail(TypeError, '!Credentials') unless creds.is_a?(Core::Credentials) + unless creds.is_a?(Core::ChannelCredentials) + fail(TypeError, '!ChannelCredentials') + end Core::Channel.new(host, kw, creds) end @@ -106,7 +108,7 @@ module GRPC # @param q [Core::CompletionQueue] used to wait for events # @param channel_override [Core::Channel] a pre-created channel # @param timeout [Number] the default timeout to use in requests - # @param creds [Core::Credentials] the channel + # @param creds [Core::ChannelCredentials] the channel credentials # @param update_metadata a func that updates metadata as described above # @param kw [KeywordArgs]the channel arguments def initialize(host, q, diff --git a/src/ruby/lib/grpc/generic/rpc_server.rb b/src/ruby/lib/grpc/generic/rpc_server.rb index 228c500672..0e318bd53b 100644 --- a/src/ruby/lib/grpc/generic/rpc_server.rb +++ b/src/ruby/lib/grpc/generic/rpc_server.rb @@ -418,11 +418,11 @@ module GRPC an_rpc = @server.request_call(@cq, loop_tag, INFINITE_FUTURE) break if (!an_rpc.nil?) && an_rpc.call.nil? - c = new_active_server_call(an_rpc) - unless c.nil? - mth = an_rpc.method.to_sym - @pool.schedule(c) do |call| - rpc_descs[mth].run_server_method(call, rpc_handlers[mth]) + active_call = new_active_server_call(an_rpc) + unless active_call.nil? + @pool.schedule(active_call) do |ac| + c, mth = ac + rpc_descs[mth].run_server_method(c, rpc_handlers[mth]) end end rescue Core::CallError, RuntimeError => e @@ -442,6 +442,7 @@ module GRPC # allow the metadata to be accessed from the call handle_call_tag = Object.new an_rpc.call.metadata = an_rpc.metadata # attaches md to call for handlers + GRPC.logger.debug("call md is #{an_rpc.metadata}") connect_md = nil unless @connect_md_proc.nil? connect_md = @connect_md_proc.call(an_rpc.method, an_rpc.metadata) @@ -454,9 +455,11 @@ module GRPC # Create the ActiveCall GRPC.logger.info("deadline is #{an_rpc.deadline}; (now=#{Time.now})") rpc_desc = rpc_descs[an_rpc.method.to_sym] - ActiveCall.new(an_rpc.call, @cq, - rpc_desc.marshal_proc, rpc_desc.unmarshal_proc(:input), - an_rpc.deadline) + c = ActiveCall.new(an_rpc.call, @cq, + rpc_desc.marshal_proc, rpc_desc.unmarshal_proc(:input), + an_rpc.deadline) + mth = an_rpc.method.to_sym + [c, mth] end protected diff --git a/src/ruby/pb/test/client.rb b/src/ruby/pb/test/client.rb index 1388685734..30550d6cc0 100755 --- a/src/ruby/pb/test/client.rb +++ b/src/ruby/pb/test/client.rb @@ -46,6 +46,7 @@ $LOAD_PATH.unshift(pb_dir) unless $LOAD_PATH.include?(pb_dir) $LOAD_PATH.unshift(this_dir) unless $LOAD_PATH.include?(this_dir) require 'optparse' +require 'logger' require 'grpc' require 'googleauth' @@ -59,6 +60,22 @@ require 'signet/ssl_config' AUTH_ENV = Google::Auth::CredentialsLoader::ENV_VAR +# RubyLogger defines a logger for gRPC based on the standard ruby logger. +module RubyLogger + def logger + LOGGER + end + + LOGGER = Logger.new(STDOUT) + LOGGER.level = Logger::INFO +end + +# GRPC is the general RPC module +module GRPC + # Inject the noop #logger if no module-level logger method has been injected. + extend RubyLogger +end + # AssertionError is use to indicate interop test failures. class AssertionError < RuntimeError; end @@ -86,13 +103,13 @@ end # creates SSL Credentials from the test certificates. def test_creds certs = load_test_certs - GRPC::Core::Credentials.new(certs[0]) + GRPC::Core::ChannelCredentials.new(certs[0]) end # creates SSL Credentials from the production certificates. def prod_creds cert_text = load_prod_cert - GRPC::Core::Credentials.new(cert_text) + GRPC::Core::ChannelCredentials.new(cert_text) end # creates the SSL Credentials. diff --git a/src/ruby/pb/test/server.rb b/src/ruby/pb/test/server.rb index 25c1b1e9e6..67877a191f 100755 --- a/src/ruby/pb/test/server.rb +++ b/src/ruby/pb/test/server.rb @@ -45,6 +45,7 @@ $LOAD_PATH.unshift(pb_dir) unless $LOAD_PATH.include?(pb_dir) $LOAD_PATH.unshift(this_dir) unless $LOAD_PATH.include?(this_dir) require 'forwardable' +require 'logger' require 'optparse' require 'grpc' @@ -53,6 +54,60 @@ require 'test/proto/empty' require 'test/proto/messages' require 'test/proto/test_services' +# DebugIsTruncated extends the default Logger to truncate debug messages +class DebugIsTruncated < Logger + def debug(s) + super(truncate(s, 1024)) + end + + # Truncates a given +text+ after a given <tt>length</tt> if +text+ is longer than <tt>length</tt>: + # + # 'Once upon a time in a world far far away'.truncate(27) + # # => "Once upon a time in a wo..." + # + # Pass a string or regexp <tt>:separator</tt> to truncate +text+ at a natural break: + # + # 'Once upon a time in a world far far away'.truncate(27, separator: ' ') + # # => "Once upon a time in a..." + # + # 'Once upon a time in a world far far away'.truncate(27, separator: /\s/) + # # => "Once upon a time in a..." + # + # The last characters will be replaced with the <tt>:omission</tt> string (defaults to "...") + # for a total length not exceeding <tt>length</tt>: + # + # 'And they found that many people were sleeping better.'.truncate(25, omission: '... (continued)') + # # => "And they f... (continued)" + def truncate(s, truncate_at, options = {}) + return s unless s.length > truncate_at + omission = options[:omission] || '...' + with_extra_room = truncate_at - omission.length + stop = \ + if options[:separator] + rindex(options[:separator], with_extra_room) || with_extra_room + else + with_extra_room + end + "#{s[0, stop]}#{omission}" + end +end + +# RubyLogger defines a logger for gRPC based on the standard ruby logger. +module RubyLogger + def logger + LOGGER + end + + LOGGER = DebugIsTruncated.new(STDOUT) + LOGGER.level = Logger::WARN +end + +# GRPC is the general RPC module +module GRPC + # Inject the noop #logger if no module-level logger method has been injected. + extend RubyLogger +end + # loads the certificates by the test server. def load_test_certs this_dir = File.expand_path(File.dirname(__FILE__)) @@ -113,7 +168,7 @@ class TestTarget < Grpc::Testing::TestService::Service def streaming_input_call(call) sizes = call.each_remote_read.map { |x| x.payload.body.length } - sum = sizes.inject { |s, x| s + x } + sum = sizes.inject(0) { |s, x| s + x } StreamingInputCallResponse.new(aggregated_payload_size: sum) end diff --git a/src/ruby/spec/credentials_spec.rb b/src/ruby/spec/channel_credentials_spec.rb index b02219dfdb..b2bdf7032e 100644 --- a/src/ruby/spec/credentials_spec.rb +++ b/src/ruby/spec/channel_credentials_spec.rb @@ -29,8 +29,8 @@ require 'grpc' -describe GRPC::Core::Credentials do - Credentials = GRPC::Core::Credentials +describe GRPC::Core::ChannelCredentials do + ChannelCredentials = GRPC::Core::ChannelCredentials def load_test_certs test_root = File.join(File.dirname(__FILE__), 'testdata') @@ -40,32 +40,24 @@ describe GRPC::Core::Credentials do describe '#new' do it 'can be constructed with fake inputs' do - expect { Credentials.new('root_certs', 'key', 'cert') }.not_to raise_error + blk = proc { ChannelCredentials.new('root_certs', 'key', 'cert') } + expect(&blk).not_to raise_error end it 'it can be constructed using specific test certificates' do certs = load_test_certs - expect { Credentials.new(*certs) }.not_to raise_error + expect { ChannelCredentials.new(*certs) }.not_to raise_error end it 'can be constructed with server roots certs only' do root_cert, _, _ = load_test_certs - expect { Credentials.new(root_cert) }.not_to raise_error + expect { ChannelCredentials.new(root_cert) }.not_to raise_error end it 'cannot be constructed with a nil server roots' do _, client_key, client_chain = load_test_certs - blk = proc { Credentials.new(nil, client_key, client_chain) } + blk = proc { ChannelCredentials.new(nil, client_key, client_chain) } expect(&blk).to raise_error end end - - describe '#compose' do - it 'cannot be completed OK with 2 SSL creds' do - certs = load_test_certs - cred1 = Credentials.new(*certs) - cred2 = Credentials.new(*certs) - expect { cred1.compose(cred2) }.to raise_error - end - end end diff --git a/src/ruby/spec/channel_spec.rb b/src/ruby/spec/channel_spec.rb index 25cefcdfb7..b4d2b94a81 100644 --- a/src/ruby/spec/channel_spec.rb +++ b/src/ruby/spec/channel_spec.rb @@ -40,7 +40,7 @@ describe GRPC::Core::Channel do let(:cq) { GRPC::Core::CompletionQueue.new } def create_test_cert - GRPC::Core::Credentials.new(load_test_certs[0]) + GRPC::Core::ChannelCredentials.new(load_test_certs[0]) end shared_examples '#new' do diff --git a/src/ruby/spec/client_server_spec.rb b/src/ruby/spec/client_server_spec.rb index ad0fb26896..734f176e94 100644 --- a/src/ruby/spec/client_server_spec.rb +++ b/src/ruby/spec/client_server_spec.rb @@ -431,7 +431,7 @@ describe 'the secure http client/server' do @server.start args = { Channel::SSL_TARGET => 'foo.test.google.fr' } @ch = Channel.new("0.0.0.0:#{server_port}", args, - GRPC::Core::Credentials.new(certs[0], nil, nil)) + GRPC::Core::ChannelCredentials.new(certs[0], nil, nil)) end after(:example) do diff --git a/src/ruby/spec/generic/client_stub_spec.rb b/src/ruby/spec/generic/client_stub_spec.rb index c5173aee1d..da5bc6c9e5 100644 --- a/src/ruby/spec/generic/client_stub_spec.rb +++ b/src/ruby/spec/generic/client_stub_spec.rb @@ -113,7 +113,7 @@ describe 'ClientStub' do opts = { GRPC::Core::Channel::SSL_TARGET => 'foo.test.google.fr', a_channel_arg: 'an_arg', - creds: GRPC::Core::Credentials.new(certs[0], nil, nil) + creds: GRPC::Core::ChannelCredentials.new(certs[0], nil, nil) } GRPC::ClientStub.new(fake_host, @cq, **opts) end diff --git a/src/ruby/spec/pb/health/checker_spec.rb b/src/ruby/spec/pb/health/checker_spec.rb index 9bc82638c7..322566b784 100644 --- a/src/ruby/spec/pb/health/checker_spec.rb +++ b/src/ruby/spec/pb/health/checker_spec.rb @@ -31,6 +31,7 @@ require 'grpc' require 'grpc/health/v1alpha/health' require 'grpc/health/checker' require 'open3' +require 'tmpdir' def can_run_codegen_check system('which grpc_ruby_plugin') && system('which protoc') diff --git a/src/ruby/spec/testdata/server1.pem b/src/ruby/spec/testdata/server1.pem index 8e582e571f..f3d43fcc5b 100755 --- a/src/ruby/spec/testdata/server1.pem +++ b/src/ruby/spec/testdata/server1.pem @@ -1,16 +1,16 @@ -----BEGIN CERTIFICATE----- -MIICmzCCAgSgAwIBAgIBAzANBgkqhkiG9w0BAQUFADBWMQswCQYDVQQGEwJBVTET -MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ -dHkgTHRkMQ8wDQYDVQQDDAZ0ZXN0Y2EwHhcNMTQwNzIyMDYwMDU3WhcNMjQwNzE5 -MDYwMDU3WjBkMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV -BAcTB0NoaWNhZ28xFDASBgNVBAoTC0dvb2dsZSBJbmMuMRowGAYDVQQDFBEqLnRl -c3QuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4cMVJygs -JUmlgMMzgdi0h1XoCR7+ww1pop04OMMyy7H/i0PJ2W6Y35+b4CM8QrkYeEafUGDO -RYX6yV/cHGGsD/x02ye6ey1UDtkGAD/mpDEx8YCrjAc1Vfvt8Fk6Cn1WVIxV/J30 -3xjBsFgByQ55RBp1OLZfVLo6AleBDSbcxaECAwEAAaNrMGkwCQYDVR0TBAIwADAL -BgNVHQ8EBAMCBeAwTwYDVR0RBEgwRoIQKi50ZXN0Lmdvb2dsZS5mcoIYd2F0ZXJ6 -b29pLnRlc3QuZ29vZ2xlLmJlghIqLnRlc3QueW91dHViZS5jb22HBMCoAQMwDQYJ -KoZIhvcNAQEFBQADgYEAM2Ii0LgTGbJ1j4oqX9bxVcxm+/R5Yf8oi0aZqTJlnLYS -wXcBykxTx181s7WyfJ49WwrYXo78zTDAnf1ma0fPq3e4mpspvyndLh1a+OarHa1e -aT0DIIYk7qeEa1YcVljx2KyLd0r1BBAfrwyGaEPVeJQVYWaOJRU2we/KD4ojf9s= +MIICnDCCAgWgAwIBAgIBBzANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJBVTET +MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ +dHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2EwHhcNMTUxMTA0MDIyMDI0WhcNMjUxMTAx +MDIyMDI0WjBlMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV +BAcTB0NoaWNhZ28xFTATBgNVBAoTDEV4YW1wbGUsIENvLjEaMBgGA1UEAxQRKi50 +ZXN0Lmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOHDFSco +LCVJpYDDM4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1Bg +zkWF+slf3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd +9N8YwbBYAckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAGjazBpMAkGA1UdEwQCMAAw +CwYDVR0PBAQDAgXgME8GA1UdEQRIMEaCECoudGVzdC5nb29nbGUuZnKCGHdhdGVy +em9vaS50ZXN0Lmdvb2dsZS5iZYISKi50ZXN0LnlvdXR1YmUuY29thwTAqAEDMA0G +CSqGSIb3DQEBCwUAA4GBAJFXVifQNub1LUP4JlnX5lXNlo8FxZ2a12AFQs+bzoJ6 +hM044EDjqyxUqSbVePK0ni3w1fHQB5rY9yYC5f8G7aqqTY1QOhoUk8ZTSTRpnkTh +y4jjdvTZeLDVBlueZUTDRmy2feY5aZIU18vFDK08dTG0A87pppuv1LNIR3loveU8 -----END CERTIFICATE----- |