aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar Craig Tiller <craig.tiller@gmail.com>2015-02-11 18:19:24 -0800
committerGravatar Craig Tiller <craig.tiller@gmail.com>2015-02-11 18:19:24 -0800
commitd9dd8fee0485ee3b3c2c5caa1df39b7c97330ac2 (patch)
treed4bcdc37bbed36b9cdce6d507292add4c72ab4d5 /src
parentbd217574fb7ec65f899103eb4e1f8719b83fa43a (diff)
parentd8b88dec9182705356af8a862445c28c41ab35c8 (diff)
Merge github.com:grpc/grpc into c++api
Diffstat (limited to 'src')
-rw-r--r--src/core/httpcli/httpcli_security_context.c15
-rw-r--r--src/core/iomgr/pollset_multipoller_with_epoll.c197
-rw-r--r--src/core/iomgr/pollset_multipoller_with_poll_posix.c6
-rw-r--r--src/core/iomgr/pollset_posix.c11
-rw-r--r--src/core/iomgr/pollset_posix.h1
-rw-r--r--src/core/security/auth.c130
-rw-r--r--src/core/security/secure_transport_setup.c3
-rw-r--r--src/core/security/security_context.c177
-rw-r--r--src/core/security/security_context.h38
-rw-r--r--src/core/support/cpu_windows.c54
-rw-r--r--src/core/support/file_win32.c2
-rw-r--r--src/core/surface/secure_channel_create.c7
-rw-r--r--src/csharp/GrpcCore/GrpcEnvironment.cs4
-rw-r--r--src/csharp/GrpcCore/Internal/CallSafeHandle.cs36
-rw-r--r--src/csharp/GrpcCore/Internal/ChannelSafeHandle.cs4
-rw-r--r--src/csharp/GrpcCore/Internal/CompletionQueueSafeHandle.cs12
-rw-r--r--src/csharp/GrpcCore/Internal/Enums.cs37
-rw-r--r--src/csharp/GrpcCore/Internal/Event.cs40
-rw-r--r--src/csharp/GrpcCore/Internal/ServerSafeHandle.cs16
-rw-r--r--src/csharp/GrpcCore/Internal/Timespec.cs2
-rw-r--r--src/node/examples/perf_test.js115
-rw-r--r--src/python/src/_adapter/_c_test.py31
-rw-r--r--src/python/src/_adapter/_low_test.py4
-rw-r--r--src/python/src/_adapter/_server.c24
-rw-r--r--src/python/src/_adapter/fore.py2
25 files changed, 782 insertions, 186 deletions
diff --git a/src/core/httpcli/httpcli_security_context.c b/src/core/httpcli/httpcli_security_context.c
index d074e163f1..53e887ccd1 100644
--- a/src/core/httpcli/httpcli_security_context.c
+++ b/src/core/httpcli/httpcli_security_context.c
@@ -73,20 +73,23 @@ static grpc_security_status httpcli_ssl_create_handshaker(
return GRPC_SECURITY_OK;
}
-static grpc_security_status httpcli_ssl_check_peer(
- grpc_security_context *ctx, const tsi_peer *peer,
- grpc_security_check_peer_cb cb, void *user_data) {
+static grpc_security_status httpcli_ssl_check_peer(grpc_security_context *ctx,
+ tsi_peer peer,
+ grpc_security_check_cb cb,
+ void *user_data) {
grpc_httpcli_ssl_channel_security_context *c =
(grpc_httpcli_ssl_channel_security_context *)ctx;
+ grpc_security_status status = GRPC_SECURITY_OK;
/* Check the peer name. */
if (c->secure_peer_name != NULL &&
- !tsi_ssl_peer_matches_name(peer, c->secure_peer_name)) {
+ !tsi_ssl_peer_matches_name(&peer, c->secure_peer_name)) {
gpr_log(GPR_ERROR, "Peer name %s is not in peer certificate",
c->secure_peer_name);
- return GRPC_SECURITY_ERROR;
+ status = GRPC_SECURITY_ERROR;
}
- return GRPC_SECURITY_OK;
+ tsi_peer_destruct(&peer);
+ return status;
}
static grpc_security_context_vtable httpcli_ssl_vtable = {
diff --git a/src/core/iomgr/pollset_multipoller_with_epoll.c b/src/core/iomgr/pollset_multipoller_with_epoll.c
new file mode 100644
index 0000000000..9fb2819506
--- /dev/null
+++ b/src/core/iomgr/pollset_multipoller_with_epoll.c
@@ -0,0 +1,197 @@
+/*
+ *
+ * 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/support/port_platform.h>
+
+#ifdef GPR_LINUX_MULTIPOLL_WITH_EPOLL
+
+#include <errno.h>
+#include <string.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+#include "src/core/iomgr/fd_posix.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+typedef struct {
+ int epoll_fd;
+ grpc_wakeup_fd_info wakeup_fd;
+} pollset_hdr;
+
+static void multipoll_with_epoll_pollset_add_fd(grpc_pollset *pollset,
+ grpc_fd *fd) {
+ pollset_hdr *h = pollset->data.ptr;
+ struct epoll_event ev;
+ int err;
+
+ ev.events = EPOLLIN | EPOLLOUT | EPOLLET;
+ ev.data.ptr = fd;
+ err = epoll_ctl(h->epoll_fd, EPOLL_CTL_ADD, fd->fd, &ev);
+ if (err < 0) {
+ /* FDs may be added to a pollset multiple times, so EEXIST is normal. */
+ if (errno != EEXIST) {
+ gpr_log(GPR_ERROR, "epoll_ctl add for %d failed: %s", fd->fd,
+ strerror(errno));
+ }
+ }
+}
+
+static void multipoll_with_epoll_pollset_del_fd(grpc_pollset *pollset,
+ grpc_fd *fd) {
+ pollset_hdr *h = pollset->data.ptr;
+ int err;
+ /* Note that this can race with concurrent poll, but that should be fine since
+ * at worst it creates a spurious read event on a reused grpc_fd object. */
+ err = epoll_ctl(h->epoll_fd, EPOLL_CTL_DEL, fd->fd, NULL);
+ if (err < 0) {
+ gpr_log(GPR_ERROR, "epoll_ctl del for %d failed: %s", fd->fd,
+ strerror(errno));
+ }
+}
+
+/* TODO(klempner): We probably want to turn this down a bit */
+#define GRPC_EPOLL_MAX_EVENTS 1000
+
+static int multipoll_with_epoll_pollset_maybe_work(
+ grpc_pollset *pollset, gpr_timespec deadline, gpr_timespec now,
+ int allow_synchronous_callback) {
+ struct epoll_event ep_ev[GRPC_EPOLL_MAX_EVENTS];
+ int ep_rv;
+ pollset_hdr *h = pollset->data.ptr;
+ int timeout_ms;
+
+ /* If you want to ignore epoll's ability to sanely handle parallel pollers,
+ * for a more apples-to-apples performance comparison with poll, add a
+ * if (pollset->counter == 0) { return 0 }
+ * here.
+ */
+
+ if (gpr_time_cmp(deadline, gpr_inf_future) == 0) {
+ timeout_ms = -1;
+ } else {
+ timeout_ms = gpr_time_to_millis(gpr_time_sub(deadline, now));
+ if (timeout_ms <= 0) {
+ return 1;
+ }
+ }
+ pollset->counter += 1;
+ gpr_mu_unlock(&pollset->mu);
+
+ do {
+ ep_rv = epoll_wait(h->epoll_fd, ep_ev, GRPC_EPOLL_MAX_EVENTS, timeout_ms);
+ if (ep_rv < 0) {
+ if (errno != EINTR) {
+ gpr_log(GPR_ERROR, "epoll_wait() failed: %s", strerror(errno));
+ }
+ } else {
+ int i;
+ for (i = 0; i < ep_rv; ++i) {
+ if (ep_ev[i].data.ptr == 0) {
+ grpc_wakeup_fd_consume_wakeup(&h->wakeup_fd);
+ } else {
+ grpc_fd *fd = ep_ev[i].data.ptr;
+ /* TODO(klempner): We might want to consider making err and pri
+ * separate events */
+ int cancel = ep_ev[i].events & (EPOLLERR | EPOLLHUP);
+ int read = ep_ev[i].events & (EPOLLIN | EPOLLPRI);
+ int write = ep_ev[i].events & EPOLLOUT;
+ if (read || cancel) {
+ grpc_fd_become_readable(fd, allow_synchronous_callback);
+ }
+ if (write || cancel) {
+ grpc_fd_become_writable(fd, allow_synchronous_callback);
+ }
+ }
+ }
+ }
+ timeout_ms = 0;
+ } while (ep_rv == GRPC_EPOLL_MAX_EVENTS);
+
+ gpr_mu_lock(&pollset->mu);
+ pollset->counter -= 1;
+ /* TODO(klempner): This should signal once per event rather than broadcast,
+ * although it probably doesn't matter because threads will generally be
+ * blocked in epoll_wait rather than being blocked on the cv. */
+ gpr_cv_broadcast(&pollset->cv);
+ return 1;
+}
+
+static void multipoll_with_epoll_pollset_destroy(grpc_pollset *pollset) {
+ pollset_hdr *h = pollset->data.ptr;
+ grpc_wakeup_fd_destroy(&h->wakeup_fd);
+ close(h->epoll_fd);
+ gpr_free(h);
+}
+
+static void epoll_kick(grpc_pollset *pollset) {
+ pollset_hdr *h = pollset->data.ptr;
+ grpc_wakeup_fd_wakeup(&h->wakeup_fd);
+}
+
+static const grpc_pollset_vtable multipoll_with_epoll_pollset = {
+ multipoll_with_epoll_pollset_add_fd, multipoll_with_epoll_pollset_del_fd,
+ multipoll_with_epoll_pollset_maybe_work, epoll_kick,
+ multipoll_with_epoll_pollset_destroy};
+
+void grpc_platform_become_multipoller(grpc_pollset *pollset, grpc_fd **fds,
+ size_t nfds) {
+ size_t i;
+ pollset_hdr *h = gpr_malloc(sizeof(pollset_hdr));
+ struct epoll_event ev;
+ int err;
+
+ pollset->vtable = &multipoll_with_epoll_pollset;
+ pollset->data.ptr = h;
+ h->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
+ if (h->epoll_fd < 0) {
+ /* TODO(klempner): Fall back to poll here, especially on ENOSYS */
+ gpr_log(GPR_ERROR, "epoll_create1 failed: %s", strerror(errno));
+ abort();
+ }
+ for (i = 0; i < nfds; i++) {
+ multipoll_with_epoll_pollset_add_fd(pollset, fds[i]);
+ }
+
+ grpc_wakeup_fd_create(&h->wakeup_fd);
+ ev.events = EPOLLIN;
+ ev.data.ptr = 0;
+ err = epoll_ctl(h->epoll_fd, EPOLL_CTL_ADD,
+ GRPC_WAKEUP_FD_GET_READ_FD(&h->wakeup_fd), &ev);
+ if (err < 0) {
+ gpr_log(GPR_ERROR, "Wakeup fd epoll_ctl failed: %s", strerror(errno));
+ abort();
+ }
+}
+
+#endif /* GPR_LINUX_MULTIPOLL_WITH_EPOLL */
diff --git a/src/core/iomgr/pollset_multipoller_with_poll_posix.c b/src/core/iomgr/pollset_multipoller_with_poll_posix.c
index 3244ae08db..c136ee0b52 100644
--- a/src/core/iomgr/pollset_multipoller_with_poll_posix.c
+++ b/src/core/iomgr/pollset_multipoller_with_poll_posix.c
@@ -200,6 +200,10 @@ static int multipoll_with_poll_pollset_maybe_work(
return 1;
}
+static void multipoll_with_poll_pollset_kick(grpc_pollset *p) {
+ grpc_pollset_kick_kick(&p->kick_state);
+}
+
static void multipoll_with_poll_pollset_destroy(grpc_pollset *pollset) {
size_t i;
pollset_hdr *h = pollset->data.ptr;
@@ -219,7 +223,7 @@ static void multipoll_with_poll_pollset_destroy(grpc_pollset *pollset) {
static const grpc_pollset_vtable multipoll_with_poll_pollset = {
multipoll_with_poll_pollset_add_fd, multipoll_with_poll_pollset_del_fd,
- multipoll_with_poll_pollset_maybe_work,
+ multipoll_with_poll_pollset_maybe_work, multipoll_with_poll_pollset_kick,
multipoll_with_poll_pollset_destroy};
void grpc_platform_become_multipoller(grpc_pollset *pollset, grpc_fd **fds,
diff --git a/src/core/iomgr/pollset_posix.c b/src/core/iomgr/pollset_posix.c
index 2837a0dff3..53c9806fb9 100644
--- a/src/core/iomgr/pollset_posix.c
+++ b/src/core/iomgr/pollset_posix.c
@@ -76,7 +76,7 @@ static void backup_poller(void *p) {
void grpc_pollset_kick(grpc_pollset *p) {
if (p->counter) {
- grpc_pollset_kick_kick(&p->kick_state);
+ p->vtable->kick(p);
}
}
@@ -84,6 +84,10 @@ void grpc_pollset_force_kick(grpc_pollset *p) {
grpc_pollset_kick_kick(&p->kick_state);
}
+static void kick_using_pollset_kick(grpc_pollset *p) {
+ grpc_pollset_kick_kick(&p->kick_state);
+}
+
/* global state management */
grpc_pollset *grpc_backup_pollset(void) { return &g_backup_pollset; }
@@ -186,7 +190,7 @@ static void empty_pollset_destroy(grpc_pollset *pollset) {}
static const grpc_pollset_vtable empty_pollset = {
empty_pollset_add_fd, empty_pollset_del_fd, empty_pollset_maybe_work,
- empty_pollset_destroy};
+ kick_using_pollset_kick, empty_pollset_destroy};
static void become_empty_pollset(grpc_pollset *pollset) {
pollset->vtable = &empty_pollset;
@@ -296,7 +300,8 @@ static void unary_poll_pollset_destroy(grpc_pollset *pollset) {
static const grpc_pollset_vtable unary_poll_pollset = {
unary_poll_pollset_add_fd, unary_poll_pollset_del_fd,
- unary_poll_pollset_maybe_work, unary_poll_pollset_destroy};
+ unary_poll_pollset_maybe_work, kick_using_pollset_kick,
+ unary_poll_pollset_destroy};
static void become_unary_pollset(grpc_pollset *pollset, grpc_fd *fd) {
pollset->vtable = &unary_poll_pollset;
diff --git a/src/core/iomgr/pollset_posix.h b/src/core/iomgr/pollset_posix.h
index cdcb995167..b1a82fccfe 100644
--- a/src/core/iomgr/pollset_posix.h
+++ b/src/core/iomgr/pollset_posix.h
@@ -66,6 +66,7 @@ struct grpc_pollset_vtable {
void (*del_fd)(grpc_pollset *pollset, struct grpc_fd *fd);
int (*maybe_work)(grpc_pollset *pollset, gpr_timespec deadline,
gpr_timespec now, int allow_synchronous_callback);
+ void (*kick)(grpc_pollset *pollset);
void (*destroy)(grpc_pollset *pollset);
};
diff --git a/src/core/security/auth.c b/src/core/security/auth.c
index 9d0c075bc3..18c32f90f4 100644
--- a/src/core/security/auth.c
+++ b/src/core/security/auth.c
@@ -35,22 +35,49 @@
#include <string.h>
-#include "src/core/security/security_context.h"
-#include "src/core/security/credentials.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include "src/core/support/string.h"
+#include "src/core/channel/channel_stack.h"
+#include "src/core/security/security_context.h"
+#include "src/core/security/credentials.h"
+#include "src/core/surface/call.h"
+
/* We can have a per-call credentials. */
typedef struct {
grpc_credentials *creds;
+ grpc_mdstr *host;
grpc_call_op op;
} call_data;
/* We can have a per-channel credentials. */
typedef struct {
grpc_channel_security_context *security_context;
+ grpc_mdctx *md_ctx;
+ grpc_mdstr *authority_string;
+ grpc_mdstr *error_msg_key;
} channel_data;
+static void do_nothing(void *ignored, grpc_op_error error) {}
+
+static void bubbleup_error(grpc_call_element *elem, const char *error_msg) {
+ grpc_call_op finish_op;
+ channel_data *channeld = elem->channel_data;
+
+ gpr_log(GPR_ERROR, "%s", error_msg);
+ finish_op.type = GRPC_RECV_METADATA;
+ finish_op.dir = GRPC_CALL_UP;
+ finish_op.flags = 0;
+ finish_op.data.metadata = grpc_mdelem_from_metadata_strings(
+ channeld->md_ctx, channeld->error_msg_key,
+ grpc_mdstr_from_string(channeld->md_ctx, error_msg));
+ finish_op.done_cb = do_nothing;
+ finish_op.user_data = NULL;
+ grpc_call_next_op(elem, &finish_op);
+ grpc_call_element_send_cancel(elem);
+}
+
static void on_credentials_metadata(void *user_data, grpc_mdelem **md_elems,
size_t num_md,
grpc_credentials_status status) {
@@ -62,6 +89,46 @@ static void on_credentials_metadata(void *user_data, grpc_mdelem **md_elems,
grpc_call_next_op(elem, &((call_data *)elem->call_data)->op);
}
+static void send_security_metadata(grpc_call_element *elem, grpc_call_op *op) {
+ /* grab pointers to our data from the call element */
+ call_data *calld = elem->call_data;
+ channel_data *channeld = elem->channel_data;
+
+ grpc_credentials *channel_creds =
+ channeld->security_context->request_metadata_creds;
+ /* TODO(jboeuf):
+ Decide on the policy in this case:
+ - populate both channel and call?
+ - the call takes precedence over the channel?
+ - leave this decision up to the channel credentials? */
+ if (calld->creds != NULL) {
+ gpr_log(GPR_ERROR, "Ignoring per call credentials for now.");
+ }
+ if (channel_creds != NULL &&
+ grpc_credentials_has_request_metadata(channel_creds)) {
+ calld->op = *op; /* Copy op (originates from the caller's stack). */
+ grpc_credentials_get_request_metadata(channel_creds,
+ on_credentials_metadata, elem);
+ } else {
+ grpc_call_next_op(elem, op);
+ }
+}
+
+static void on_host_checked(void *user_data, grpc_security_status status) {
+ grpc_call_element *elem = (grpc_call_element *)user_data;
+ call_data *calld = elem->call_data;
+
+ if (status == GRPC_SECURITY_OK) {
+ send_security_metadata(elem, &calld->op);
+ } else {
+ char *error_msg;
+ gpr_asprintf(&error_msg, "Invalid host %s set in :authority metadata.",
+ grpc_mdstr_as_c_string(calld->host));
+ bubbleup_error(elem, error_msg);
+ gpr_free(error_msg);
+ }
+}
+
/* Called either:
- in response to an API call (or similar) from above, to send something
- a network event (or similar) from below, to receive something
@@ -74,26 +141,36 @@ static void call_op(grpc_call_element *elem, grpc_call_element *from_elem,
channel_data *channeld = elem->channel_data;
switch (op->type) {
- case GRPC_SEND_START: {
- grpc_credentials *channel_creds =
- channeld->security_context->request_metadata_creds;
- /* TODO(jboeuf):
- Decide on the policy in this case:
- - populate both channel and call?
- - the call takes precedence over the channel?
- - leave this decision up to the channel credentials? */
- if (calld->creds != NULL) {
- gpr_log(GPR_ERROR, "Ignoring per call credentials for now.");
+ case GRPC_SEND_METADATA:
+ /* Pointer comparison is OK for md_elems created from the same context. */
+ if (op->data.metadata->key == channeld->authority_string) {
+ if (calld->host != NULL) grpc_mdstr_unref(calld->host);
+ calld->host = grpc_mdstr_ref(op->data.metadata->value);
}
- if (channel_creds != NULL &&
- grpc_credentials_has_request_metadata(channel_creds)) {
+ grpc_call_next_op(elem, op);
+ break;
+
+ case GRPC_SEND_START:
+ if (calld->host != NULL) {
+ grpc_security_status status;
+ const char *call_host = grpc_mdstr_as_c_string(calld->host);
calld->op = *op; /* Copy op (originates from the caller's stack). */
- grpc_credentials_get_request_metadata(channel_creds,
- on_credentials_metadata, elem);
- break;
+ status = grpc_channel_security_context_check_call_host(
+ channeld->security_context, call_host, on_host_checked, elem);
+ if (status != GRPC_SECURITY_OK) {
+ if (status == GRPC_SECURITY_ERROR) {
+ char *error_msg;
+ gpr_asprintf(&error_msg,
+ "Invalid host %s set in :authority metadata.",
+ call_host);
+ bubbleup_error(elem, error_msg);
+ gpr_free(error_msg);
+ }
+ break;
+ }
}
- /* FALLTHROUGH INTENDED. */
- }
+ send_security_metadata(elem, op);
+ break;
default:
/* pass control up or down the stack depending on op->dir */
@@ -116,6 +193,7 @@ static void init_call_elem(grpc_call_element *elem,
Find a way to pass-in the credentials from the caller here. */
call_data *calld = elem->call_data;
calld->creds = NULL;
+ calld->host = NULL;
}
/* Destructor for call_data */
@@ -124,6 +202,9 @@ static void destroy_call_elem(grpc_call_element *elem) {
if (calld->creds != NULL) {
grpc_credentials_unref(calld->creds);
}
+ if (calld->host != NULL) {
+ grpc_mdstr_unref(calld->host);
+ }
}
/* Constructor for channel_data */
@@ -146,6 +227,11 @@ static void init_channel_elem(grpc_channel_element *elem,
GPR_ASSERT(ctx->is_client_side);
channeld->security_context =
(grpc_channel_security_context *)grpc_security_context_ref(ctx);
+ channeld->md_ctx = metadata_context;
+ channeld->authority_string =
+ grpc_mdstr_from_string(channeld->md_ctx, ":authority");
+ channeld->error_msg_key =
+ grpc_mdstr_from_string(channeld->md_ctx, "grpc-message");
}
/* Destructor for channel data */
@@ -154,6 +240,12 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
channel_data *channeld = elem->channel_data;
grpc_channel_security_context *ctx = channeld->security_context;
if (ctx != NULL) grpc_security_context_unref(&ctx->base);
+ if (channeld->authority_string != NULL) {
+ grpc_mdstr_unref(channeld->authority_string);
+ }
+ if (channeld->error_msg_key != NULL) {
+ grpc_mdstr_unref(channeld->error_msg_key);
+ }
}
const grpc_channel_filter grpc_client_auth_filter = {
diff --git a/src/core/security/secure_transport_setup.c b/src/core/security/secure_transport_setup.c
index 50a6987fbf..59789a7e4d 100644
--- a/src/core/security/secure_transport_setup.c
+++ b/src/core/security/secure_transport_setup.c
@@ -113,8 +113,7 @@ static void check_peer(grpc_secure_transport_setup *s) {
return;
}
peer_status =
- grpc_security_context_check_peer(s->ctx, &peer, on_peer_checked, s);
- tsi_peer_destruct(&peer);
+ grpc_security_context_check_peer(s->ctx, peer, on_peer_checked, s);
if (peer_status == GRPC_SECURITY_ERROR) {
gpr_log(GPR_ERROR, "Peer check failed.");
secure_transport_setup_done(s, 0);
diff --git a/src/core/security/security_context.c b/src/core/security/security_context.c
index 1edec29775..adb0269792 100644
--- a/src/core/security/security_context.c
+++ b/src/core/security/security_context.c
@@ -69,12 +69,22 @@ grpc_security_status grpc_security_context_create_handshaker(
}
grpc_security_status grpc_security_context_check_peer(
- grpc_security_context *ctx, const tsi_peer *peer,
- grpc_security_check_peer_cb cb, void *user_data) {
- if (ctx == NULL) return GRPC_SECURITY_ERROR;
+ grpc_security_context *ctx, tsi_peer peer, grpc_security_check_cb cb,
+ void *user_data) {
+ if (ctx == NULL) {
+ tsi_peer_destruct(&peer);
+ return GRPC_SECURITY_ERROR;
+ }
return ctx->vtable->check_peer(ctx, peer, cb, user_data);
}
+grpc_security_status grpc_channel_security_context_check_call_host(
+ grpc_channel_security_context *ctx, const char *host,
+ grpc_security_check_cb cb, void *user_data) {
+ if (ctx == NULL || ctx->check_call_host == NULL) return GRPC_SECURITY_ERROR;
+ return ctx->check_call_host(ctx, host, cb, user_data);
+}
+
void grpc_security_context_unref(grpc_security_context *ctx) {
if (ctx == NULL) return;
if (gpr_unref(&ctx->refcount)) ctx->vtable->destroy(ctx);
@@ -137,6 +147,11 @@ static int check_request_metadata_creds(grpc_credentials *creds) {
/* -- Fake implementation. -- */
+typedef struct {
+ grpc_channel_security_context base;
+ int call_host_check_is_async;
+} grpc_fake_channel_security_context;
+
static void fake_channel_destroy(grpc_security_context *ctx) {
grpc_channel_security_context *c = (grpc_channel_security_context *)ctx;
grpc_credentials_unref(c->request_metadata_creds);
@@ -158,31 +173,51 @@ static grpc_security_status fake_server_create_handshaker(
}
static grpc_security_status fake_check_peer(grpc_security_context *ctx,
- const tsi_peer *peer,
- grpc_security_check_peer_cb cb,
+ tsi_peer peer,
+ grpc_security_check_cb cb,
void *user_data) {
const char *prop_name;
- if (peer->property_count != 1) {
+ grpc_security_status status = GRPC_SECURITY_OK;
+ if (peer.property_count != 1) {
gpr_log(GPR_ERROR, "Fake peers should only have 1 property.");
- return GRPC_SECURITY_ERROR;
+ status = GRPC_SECURITY_ERROR;
+ goto end;
}
- prop_name = peer->properties[0].name;
+ prop_name = peer.properties[0].name;
if (prop_name == NULL ||
strcmp(prop_name, TSI_CERTIFICATE_TYPE_PEER_PROPERTY)) {
gpr_log(GPR_ERROR, "Unexpected property in fake peer: %s.",
prop_name == NULL ? "<EMPTY>" : prop_name);
- return GRPC_SECURITY_ERROR;
+ status = GRPC_SECURITY_ERROR;
+ goto end;
}
- if (peer->properties[0].type != TSI_PEER_PROPERTY_TYPE_STRING) {
+ if (peer.properties[0].type != TSI_PEER_PROPERTY_TYPE_STRING) {
gpr_log(GPR_ERROR, "Invalid type of cert type property.");
- return GRPC_SECURITY_ERROR;
+ status = GRPC_SECURITY_ERROR;
+ goto end;
}
- if (strncmp(peer->properties[0].value.string.data, TSI_FAKE_CERTIFICATE_TYPE,
- peer->properties[0].value.string.length)) {
+ if (strncmp(peer.properties[0].value.string.data, TSI_FAKE_CERTIFICATE_TYPE,
+ peer.properties[0].value.string.length)) {
gpr_log(GPR_ERROR, "Invalid value for cert type property.");
- return GRPC_SECURITY_ERROR;
+ status = GRPC_SECURITY_ERROR;
+ goto end;
+ }
+end:
+ tsi_peer_destruct(&peer);
+ return status;
+}
+
+static grpc_security_status fake_channel_check_call_host(
+ grpc_channel_security_context *ctx, const char *host,
+ grpc_security_check_cb cb, void *user_data) {
+ grpc_fake_channel_security_context *c =
+ (grpc_fake_channel_security_context *)ctx;
+ if (c->call_host_check_is_async) {
+ cb(user_data, GRPC_SECURITY_OK);
+ return GRPC_SECURITY_PENDING;
+ } else {
+ return GRPC_SECURITY_OK;
}
- return GRPC_SECURITY_OK;
}
static grpc_security_context_vtable fake_channel_vtable = {
@@ -192,15 +227,17 @@ static grpc_security_context_vtable fake_server_vtable = {
fake_server_destroy, fake_server_create_handshaker, fake_check_peer};
grpc_channel_security_context *grpc_fake_channel_security_context_create(
- grpc_credentials *request_metadata_creds) {
- grpc_channel_security_context *c =
- gpr_malloc(sizeof(grpc_channel_security_context));
- gpr_ref_init(&c->base.refcount, 1);
- c->base.is_client_side = 1;
- c->base.vtable = &fake_channel_vtable;
+ grpc_credentials *request_metadata_creds, int call_host_check_is_async) {
+ grpc_fake_channel_security_context *c =
+ gpr_malloc(sizeof(grpc_fake_channel_security_context));
+ gpr_ref_init(&c->base.base.refcount, 1);
+ c->base.base.is_client_side = 1;
+ c->base.base.vtable = &fake_channel_vtable;
GPR_ASSERT(check_request_metadata_creds(request_metadata_creds));
- c->request_metadata_creds = grpc_credentials_ref(request_metadata_creds);
- return c;
+ c->base.request_metadata_creds = grpc_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;
}
grpc_security_context *grpc_fake_server_security_context_create(void) {
@@ -215,7 +252,9 @@ grpc_security_context *grpc_fake_server_security_context_create(void) {
typedef struct {
grpc_channel_security_context base;
tsi_ssl_handshaker_factory *handshaker_factory;
- char *secure_peer_name;
+ char *target_name;
+ char *overridden_target_name;
+ tsi_peer peer;
} grpc_ssl_channel_security_context;
typedef struct {
@@ -230,7 +269,9 @@ static void ssl_channel_destroy(grpc_security_context *ctx) {
if (c->handshaker_factory != NULL) {
tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
}
- if (c->secure_peer_name != NULL) gpr_free(c->secure_peer_name);
+ if (c->target_name != NULL) gpr_free(c->target_name);
+ if (c->overridden_target_name != NULL) gpr_free(c->overridden_target_name);
+ tsi_peer_destruct(&c->peer);
gpr_free(ctx);
}
@@ -244,11 +285,11 @@ static void ssl_server_destroy(grpc_security_context *ctx) {
static grpc_security_status ssl_create_handshaker(
tsi_ssl_handshaker_factory *handshaker_factory, int is_client,
- const char *secure_peer_name, tsi_handshaker **handshaker) {
+ const char *peer_name, tsi_handshaker **handshaker) {
tsi_result result = TSI_OK;
if (handshaker_factory == NULL) return GRPC_SECURITY_ERROR;
result = tsi_ssl_handshaker_factory_create_handshaker(
- handshaker_factory, is_client ? secure_peer_name : NULL, handshaker);
+ handshaker_factory, is_client ? peer_name : NULL, handshaker);
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
tsi_result_to_string(result));
@@ -261,7 +302,10 @@ static grpc_security_status ssl_channel_create_handshaker(
grpc_security_context *ctx, tsi_handshaker **handshaker) {
grpc_ssl_channel_security_context *c =
(grpc_ssl_channel_security_context *)ctx;
- return ssl_create_handshaker(c->handshaker_factory, 1, c->secure_peer_name,
+ return ssl_create_handshaker(c->handshaker_factory, 1,
+ c->overridden_target_name != NULL
+ ? c->overridden_target_name
+ : c->target_name,
handshaker);
}
@@ -271,7 +315,7 @@ static grpc_security_status ssl_server_create_handshaker(
return ssl_create_handshaker(c->handshaker_factory, 0, NULL, handshaker);
}
-static grpc_security_status ssl_check_peer(const char *secure_peer_name,
+static grpc_security_status ssl_check_peer(const char *peer_name,
const tsi_peer *peer) {
/* Check the ALPN. */
const tsi_peer_property *p =
@@ -291,28 +335,54 @@ static grpc_security_status ssl_check_peer(const char *secure_peer_name,
}
/* Check the peer name if specified. */
- if (secure_peer_name != NULL &&
- !tsi_ssl_peer_matches_name(peer, secure_peer_name)) {
- gpr_log(GPR_ERROR, "Peer name %s is not in peer certificate",
- secure_peer_name);
+ if (peer_name != NULL &&
+ !tsi_ssl_peer_matches_name(peer, peer_name)) {
+ gpr_log(GPR_ERROR, "Peer name %s is not in peer certificate", peer_name);
return GRPC_SECURITY_ERROR;
}
return GRPC_SECURITY_OK;
}
-static grpc_security_status ssl_channel_check_peer(
- grpc_security_context *ctx, const tsi_peer *peer,
- grpc_security_check_peer_cb cb, void *user_data) {
+static grpc_security_status ssl_channel_check_peer(grpc_security_context *ctx,
+ tsi_peer peer,
+ grpc_security_check_cb cb,
+ void *user_data) {
grpc_ssl_channel_security_context *c =
(grpc_ssl_channel_security_context *)ctx;
- return ssl_check_peer(c->secure_peer_name, peer);
+ grpc_security_status status = ssl_check_peer(c->overridden_target_name != NULL
+ ? c->overridden_target_name
+ : c->target_name,
+ &peer);
+ c->peer = peer;
+ return status;
+}
+
+static grpc_security_status ssl_server_check_peer(grpc_security_context *ctx,
+ tsi_peer peer,
+ grpc_security_check_cb cb,
+ void *user_data) {
+ /* TODO(jboeuf): Find a way to expose the peer to the authorization layer. */
+ grpc_security_status status = ssl_check_peer(NULL, &peer);
+ tsi_peer_destruct(&peer);
+ return status;
}
-static grpc_security_status ssl_server_check_peer(
- grpc_security_context *ctx, const tsi_peer *peer,
- grpc_security_check_peer_cb cb, void *user_data) {
- /* TODO(jboeuf): Find a way to expose the peer to the authorization layer. */
- return ssl_check_peer(NULL, peer);
+static grpc_security_status ssl_channel_check_call_host(
+ grpc_channel_security_context *ctx, const char *host,
+ grpc_security_check_cb cb, void *user_data) {
+ grpc_ssl_channel_security_context *c =
+ (grpc_ssl_channel_security_context *)ctx;
+
+ if (tsi_ssl_peer_matches_name(&c->peer, host)) return GRPC_SECURITY_OK;
+
+ /* If the target name was overridden, then the original target_name was
+ 'checked' transitively during the previous peer check at the end of the
+ handshake. */
+ if (c->overridden_target_name != NULL && !strcmp(host, c->target_name)) {
+ return GRPC_SECURITY_OK;
+ } else {
+ return GRPC_SECURITY_ERROR;
+ }
}
static grpc_security_context_vtable ssl_channel_vtable = {
@@ -345,7 +415,8 @@ static size_t get_default_pem_roots(const unsigned char **pem_root_certs) {
grpc_security_status grpc_ssl_channel_security_context_create(
grpc_credentials *request_metadata_creds, const grpc_ssl_config *config,
- const char *secure_peer_name, grpc_channel_security_context **ctx) {
+ const char *target_name, const char *overridden_target_name,
+ grpc_channel_security_context **ctx) {
size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions();
const unsigned char **alpn_protocol_strings =
gpr_malloc(sizeof(const char *) * num_alpn_protocols);
@@ -364,8 +435,8 @@ grpc_security_status grpc_ssl_channel_security_context_create(
strlen(grpc_chttp2_get_alpn_version_index(i));
}
- if (config == NULL || secure_peer_name == NULL) {
- gpr_log(GPR_ERROR, "An ssl channel needs a config and a secure name.");
+ if (config == NULL || target_name == NULL) {
+ gpr_log(GPR_ERROR, "An ssl channel needs a config and a target name.");
goto error;
}
if (!check_request_metadata_creds(request_metadata_creds)) {
@@ -379,8 +450,12 @@ grpc_security_status grpc_ssl_channel_security_context_create(
c->base.base.vtable = &ssl_channel_vtable;
c->base.base.is_client_side = 1;
c->base.request_metadata_creds = grpc_credentials_ref(request_metadata_creds);
- if (secure_peer_name != NULL) {
- c->secure_peer_name = gpr_strdup(secure_peer_name);
+ c->base.check_call_host = ssl_channel_check_call_host;
+ if (target_name != NULL) {
+ c->target_name = gpr_strdup(target_name);
+ }
+ if (overridden_target_name != NULL) {
+ c->overridden_target_name = gpr_strdup(overridden_target_name);
}
if (config->pem_root_certs == NULL) {
pem_root_certs_size = get_default_pem_roots(&pem_root_certs);
@@ -478,7 +553,7 @@ grpc_channel *grpc_ssl_channel_create(grpc_credentials *ssl_creds,
grpc_channel *channel = NULL;
grpc_security_status status = GRPC_SECURITY_OK;
size_t i = 0;
- const char *secure_peer_name = target;
+ const char *overridden_target_name = NULL;
grpc_arg arg;
grpc_channel_args *new_args;
@@ -486,13 +561,13 @@ grpc_channel *grpc_ssl_channel_create(grpc_credentials *ssl_creds,
grpc_arg *arg = &args->args[i];
if (!strcmp(arg->key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG) &&
arg->type == GRPC_ARG_STRING) {
- secure_peer_name = arg->value.string;
+ overridden_target_name = arg->value.string;
break;
}
}
status = grpc_ssl_channel_security_context_create(
request_metadata_creds, grpc_ssl_credentials_get_config(ssl_creds),
- secure_peer_name, &ctx);
+ target, overridden_target_name, &ctx);
if (status != GRPC_SECURITY_OK) {
return grpc_lame_client_channel_create();
}
@@ -510,7 +585,7 @@ grpc_channel *grpc_fake_transport_security_channel_create(
grpc_credentials *fake_creds, grpc_credentials *request_metadata_creds,
const char *target, const grpc_channel_args *args) {
grpc_channel_security_context *ctx =
- grpc_fake_channel_security_context_create(request_metadata_creds);
+ grpc_fake_channel_security_context_create(request_metadata_creds, 1);
grpc_channel *channel =
grpc_secure_channel_create_internal(target, args, ctx);
grpc_security_context_unref(&ctx->base);
diff --git a/src/core/security/security_context.h b/src/core/security/security_context.h
index 2caa2d3690..25d467d717 100644
--- a/src/core/security/security_context.h
+++ b/src/core/security/security_context.h
@@ -56,16 +56,15 @@ typedef struct grpc_security_context grpc_security_context;
#define GRPC_SECURITY_CONTEXT_ARG "grpc.security_context"
-typedef void (*grpc_security_check_peer_cb)(void *user_data,
- grpc_security_status status);
+typedef void (*grpc_security_check_cb)(void *user_data,
+ grpc_security_status status);
typedef struct {
void (*destroy)(grpc_security_context *ctx);
grpc_security_status (*create_handshaker)(grpc_security_context *ctx,
tsi_handshaker **handshaker);
- grpc_security_status (*check_peer)(grpc_security_context *ctx,
- const tsi_peer *peer,
- grpc_security_check_peer_cb,
+ grpc_security_status (*check_peer)(grpc_security_context *ctx, tsi_peer peer,
+ grpc_security_check_cb cb,
void *user_data);
} grpc_security_context_vtable;
@@ -87,18 +86,14 @@ grpc_security_status grpc_security_context_create_handshaker(
/* Check the peer.
Implementations can choose to check the peer either synchronously or
- asynchronously. In the first case, a successful will return
+ asynchronously. In the first case, a successful call will return
GRPC_SECURITY_OK. In the asynchronous case, the call will return
GRPC_SECURITY_PENDING unless an error is detected early on.
-
- Note:
- Asynchronous implementations of this interface should make a copy of the
- fields of the peer they want to check as there is no guarantee on the
- lifetime of the peer object beyond this call.
+ Ownership of the peer is transfered.
*/
grpc_security_status grpc_security_context_check_peer(
- grpc_security_context *ctx, const tsi_peer *peer,
- grpc_security_check_peer_cb cb, void *user_data);
+ grpc_security_context *ctx, tsi_peer peer,
+ grpc_security_check_cb cb, void *user_data);
/* Util to encapsulate the context in a channel arg. */
grpc_arg grpc_security_context_to_arg(grpc_security_context *ctx);
@@ -120,14 +115,26 @@ typedef struct grpc_channel_security_context grpc_channel_security_context;
struct grpc_channel_security_context {
grpc_security_context base; /* requires is_client_side to be non 0. */
grpc_credentials *request_metadata_creds;
+ grpc_security_status (*check_call_host)(
+ grpc_channel_security_context *ctx, const char *host,
+ grpc_security_check_cb cb, void *user_data);
};
+/* Checks that the host that will be set for a call is acceptable.
+ Implementations can choose do the check either synchronously or
+ asynchronously. In the first case, a successful call will return
+ GRPC_SECURITY_OK. In the asynchronous case, the call will return
+ GRPC_SECURITY_PENDING unless an error is detected early on. */
+grpc_security_status grpc_channel_security_context_check_call_host(
+ grpc_channel_security_context *ctx, const char *host,
+ grpc_security_check_cb cb, void *user_data);
+
/* --- Creation security contexts. --- */
/* For TESTING ONLY!
Creates a fake context that emulates real channel security. */
grpc_channel_security_context *grpc_fake_channel_security_context_create(
- grpc_credentials *request_metadata_creds);
+ grpc_credentials *request_metadata_creds, int call_host_check_is_async);
/* For TESTING ONLY!
Creates a fake context that emulates real server security. */
@@ -148,7 +155,8 @@ grpc_security_context *grpc_fake_server_security_context_create(void);
*/
grpc_security_status grpc_ssl_channel_security_context_create(
grpc_credentials *request_metadata_creds, const grpc_ssl_config *config,
- const char *secure_peer_name, grpc_channel_security_context **ctx);
+ const char *target_name, const char *overridden_target_name,
+ grpc_channel_security_context **ctx);
/* Creates an SSL server_security_context.
- config is the SSL config to be used for the SSL channel establishment.
diff --git a/src/core/support/cpu_windows.c b/src/core/support/cpu_windows.c
new file mode 100644
index 0000000000..c533f9d554
--- /dev/null
+++ b/src/core/support/cpu_windows.c
@@ -0,0 +1,54 @@
+/*
+*
+* Copyright 2014, 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/support/port_platform.h>
+
+#ifdef GPR_WIN32
+
+#include "src/core/support/cpu.h"
+
+#include <grpc/support/log.h>
+
+unsigned gpr_cpu_num_cores(void) {
+ /* TODO(jtattermusch): implement */
+ gpr_log(GPR_ERROR, "Cannot determine number of CPUs: assuming 1");
+ return 1;
+}
+
+unsigned gpr_cpu_current_cpu(void) {
+ /* TODO(jtattermusch): implement */
+ gpr_log(GPR_ERROR, "Cannot determine current CPU");
+ return 0;
+}
+
+#endif /* GPR_WIN32 */
diff --git a/src/core/support/file_win32.c b/src/core/support/file_win32.c
index af7eebe3de..7749d4553f 100644
--- a/src/core/support/file_win32.c
+++ b/src/core/support/file_win32.c
@@ -76,7 +76,7 @@ end:
*tmp_filename_out = gpr_tchar_to_char(tmp_filename);
}
- gpr_free(tmp_filename);
+ gpr_free(template_string);
return result;
}
diff --git a/src/core/surface/secure_channel_create.c b/src/core/surface/secure_channel_create.c
index defee79766..562e27ff6d 100644
--- a/src/core/surface/secure_channel_create.c
+++ b/src/core/surface/secure_channel_create.c
@@ -189,8 +189,8 @@ static void done_setup(void *sp) {
static grpc_transport_setup_result complete_setup(void *channel_stack,
grpc_transport *transport,
grpc_mdctx *mdctx) {
- static grpc_channel_filter const *extra_filters[] = {&grpc_http_client_filter,
- &grpc_http_filter};
+ static grpc_channel_filter const *extra_filters[] = {
+ &grpc_client_auth_filter, &grpc_http_client_filter, &grpc_http_filter};
return grpc_client_channel_transport_setup_complete(
channel_stack, transport, extra_filters, GPR_ARRAY_SIZE(extra_filters),
mdctx);
@@ -208,7 +208,7 @@ grpc_channel *grpc_secure_channel_create_internal(
grpc_arg context_arg;
grpc_channel_args *args_copy;
grpc_mdctx *mdctx = grpc_mdctx_create();
-#define MAX_FILTERS 4
+#define MAX_FILTERS 3
const grpc_channel_filter *filters[MAX_FILTERS];
int n = 0;
if (grpc_find_security_context_in_args(args) != NULL) {
@@ -222,7 +222,6 @@ grpc_channel *grpc_secure_channel_create_internal(
if (grpc_channel_args_is_census_enabled(args)) {
filters[n++] = &grpc_client_census_filter;
}
- filters[n++] = &grpc_client_auth_filter;
filters[n++] = &grpc_client_channel_filter;
GPR_ASSERT(n <= MAX_FILTERS);
channel = grpc_channel_create_from_filters(filters, n, args_copy, mdctx, 1);
diff --git a/src/csharp/GrpcCore/GrpcEnvironment.cs b/src/csharp/GrpcCore/GrpcEnvironment.cs
index 7a644f4961..201320828b 100644
--- a/src/csharp/GrpcCore/GrpcEnvironment.cs
+++ b/src/csharp/GrpcCore/GrpcEnvironment.cs
@@ -13,10 +13,10 @@ namespace Google.GRPC.Core
{
const int THREAD_POOL_SIZE = 1;
- [DllImport("libgrpc.so")]
+ [DllImport("grpc.dll")]
static extern void grpc_init();
- [DllImport("libgrpc.so")]
+ [DllImport("grpc.dll")]
static extern void grpc_shutdown();
static object staticLock = new object();
diff --git a/src/csharp/GrpcCore/Internal/CallSafeHandle.cs b/src/csharp/GrpcCore/Internal/CallSafeHandle.cs
index 6c9c58a4c3..bbb830b355 100644
--- a/src/csharp/GrpcCore/Internal/CallSafeHandle.cs
+++ b/src/csharp/GrpcCore/Internal/CallSafeHandle.cs
@@ -15,66 +15,66 @@ namespace Google.GRPC.Core.Internal
{
const UInt32 GRPC_WRITE_BUFFER_HINT = 1;
- [DllImport("libgrpc.so")]
+ [DllImport("grpc.dll")]
static extern CallSafeHandle grpc_channel_create_call_old(ChannelSafeHandle channel, string method, string host, Timespec deadline);
- [DllImport("libgrpc.so")]
+ [DllImport("grpc.dll")]
static extern GRPCCallError grpc_call_add_metadata(CallSafeHandle call, IntPtr metadata, UInt32 flags);
- [DllImport("libgrpc.so")]
+ [DllImport("grpc.dll")]
static extern GRPCCallError grpc_call_invoke_old(CallSafeHandle call, CompletionQueueSafeHandle cq, IntPtr metadataReadTag, IntPtr finishedTag, UInt32 flags);
- [DllImport("libgrpc.so", EntryPoint = "grpc_call_invoke_old")]
+ [DllImport("grpc.dll", EntryPoint = "grpc_call_invoke_old")]
static extern GRPCCallError grpc_call_invoke_old_CALLBACK(CallSafeHandle call, CompletionQueueSafeHandle cq,
[MarshalAs(UnmanagedType.FunctionPtr)] EventCallbackDelegate metadataReadCallback,
[MarshalAs(UnmanagedType.FunctionPtr)] EventCallbackDelegate finishedCallback,
UInt32 flags);
- [DllImport("libgrpc.so")]
+ [DllImport("grpc.dll")]
static extern GRPCCallError grpc_call_server_accept_old(CallSafeHandle call, CompletionQueueSafeHandle completionQueue, IntPtr finishedTag);
- [DllImport("libgrpc.so", EntryPoint = "grpc_call_server_accept_old")]
+ [DllImport("grpc.dll", EntryPoint = "grpc_call_server_accept_old")]
static extern GRPCCallError grpc_call_server_accept_old_CALLBACK(CallSafeHandle call, CompletionQueueSafeHandle completionQueue, [MarshalAs(UnmanagedType.FunctionPtr)] EventCallbackDelegate finishedCallback);
- [DllImport("libgrpc.so")]
+ [DllImport("grpc.dll")]
static extern GRPCCallError grpc_call_server_end_initial_metadata_old(CallSafeHandle call, UInt32 flags);
- [DllImport("libgrpc.so")]
+ [DllImport("grpc.dll")]
static extern GRPCCallError grpc_call_cancel(CallSafeHandle call);
- [DllImport("libgrpc.so")]
+ [DllImport("grpc.dll")]
static extern GRPCCallError grpc_call_cancel_with_status(CallSafeHandle call, StatusCode status, string description);
- [DllImport("libgrpc.so")]
+ [DllImport("grpc.dll")]
static extern GRPCCallError grpc_call_start_write_status_old(CallSafeHandle call, StatusCode statusCode, string statusMessage, IntPtr tag);
- [DllImport("libgrpc.so", EntryPoint = "grpc_call_start_write_status_old")]
+ [DllImport("grpc.dll", EntryPoint = "grpc_call_start_write_status_old")]
static extern GRPCCallError grpc_call_start_write_status_old_CALLBACK(CallSafeHandle call, StatusCode statusCode, string statusMessage, [MarshalAs(UnmanagedType.FunctionPtr)] EventCallbackDelegate callback);
- [DllImport("libgrpc.so")]
+ [DllImport("grpc.dll")]
static extern GRPCCallError grpc_call_writes_done_old(CallSafeHandle call, IntPtr tag);
- [DllImport("libgrpc.so", EntryPoint = "grpc_call_writes_done_old")]
+ [DllImport("grpc.dll", EntryPoint = "grpc_call_writes_done_old")]
static extern GRPCCallError grpc_call_writes_done_old_CALLBACK(CallSafeHandle call, [MarshalAs(UnmanagedType.FunctionPtr)] EventCallbackDelegate callback);
- [DllImport("libgrpc.so")]
+ [DllImport("grpc.dll")]
static extern GRPCCallError grpc_call_start_read_old(CallSafeHandle call, IntPtr tag);
- [DllImport("libgrpc.so", EntryPoint = "grpc_call_start_read_old")]
+ [DllImport("grpc.dll", EntryPoint = "grpc_call_start_read_old")]
static extern GRPCCallError grpc_call_start_read_old_CALLBACK(CallSafeHandle call, [MarshalAs(UnmanagedType.FunctionPtr)] EventCallbackDelegate callback);
- [DllImport("libgrpc_csharp_ext.so")]
+ [DllImport("grpc_csharp_ext.dll")]
static extern void grpc_call_start_write_from_copied_buffer(CallSafeHandle call,
byte[] buffer, UIntPtr length,
IntPtr tag, UInt32 flags);
- [DllImport("libgrpc_csharp_ext.so", EntryPoint = "grpc_call_start_write_from_copied_buffer")]
+ [DllImport("grpc_csharp_ext.dll", EntryPoint = "grpc_call_start_write_from_copied_buffer")]
static extern void grpc_call_start_write_from_copied_buffer_CALLBACK(CallSafeHandle call,
byte[] buffer, UIntPtr length,
[MarshalAs(UnmanagedType.FunctionPtr)] EventCallbackDelegate callback,
UInt32 flags);
- [DllImport("libgrpc.so")]
+ [DllImport("grpc.dll")]
static extern void grpc_call_destroy(IntPtr call);
private CallSafeHandle()
diff --git a/src/csharp/GrpcCore/Internal/ChannelSafeHandle.cs b/src/csharp/GrpcCore/Internal/ChannelSafeHandle.cs
index 3a09d8b1b6..0f38d63f98 100644
--- a/src/csharp/GrpcCore/Internal/ChannelSafeHandle.cs
+++ b/src/csharp/GrpcCore/Internal/ChannelSafeHandle.cs
@@ -10,10 +10,10 @@ namespace Google.GRPC.Core.Internal
/// </summary>
internal class ChannelSafeHandle : SafeHandleZeroIsInvalid
{
- [DllImport("libgrpc.so")]
+ [DllImport("grpc.dll")]
static extern ChannelSafeHandle grpc_channel_create(string target, IntPtr channelArgs);
- [DllImport("libgrpc.so")]
+ [DllImport("grpc.dll")]
static extern void grpc_channel_destroy(IntPtr channel);
private ChannelSafeHandle()
diff --git a/src/csharp/GrpcCore/Internal/CompletionQueueSafeHandle.cs b/src/csharp/GrpcCore/Internal/CompletionQueueSafeHandle.cs
index 73dd3edde3..f098de6820 100644
--- a/src/csharp/GrpcCore/Internal/CompletionQueueSafeHandle.cs
+++ b/src/csharp/GrpcCore/Internal/CompletionQueueSafeHandle.cs
@@ -9,22 +9,22 @@ namespace Google.GRPC.Core.Internal
/// </summary>
internal class CompletionQueueSafeHandle : SafeHandleZeroIsInvalid
{
- [DllImport("libgrpc.so")]
+ [DllImport("grpc.dll")]
static extern CompletionQueueSafeHandle grpc_completion_queue_create();
- [DllImport("libgrpc.so")]
+ [DllImport("grpc.dll")]
static extern EventSafeHandle grpc_completion_queue_pluck(CompletionQueueSafeHandle cq, IntPtr tag, Timespec deadline);
- [DllImport("libgrpc.so")]
+ [DllImport("grpc.dll")]
static extern EventSafeHandle grpc_completion_queue_next(CompletionQueueSafeHandle cq, Timespec deadline);
- [DllImport("libgrpc.so")]
+ [DllImport("grpc.dll")]
static extern void grpc_completion_queue_shutdown(CompletionQueueSafeHandle cq);
- [DllImport("libgrpc_csharp_ext.so")]
+ [DllImport("grpc_csharp_ext.dll")]
static extern GRPCCompletionType grpc_completion_queue_next_with_callback(CompletionQueueSafeHandle cq);
- [DllImport("libgrpc.so")]
+ [DllImport("grpc.dll")]
static extern void grpc_completion_queue_destroy(IntPtr cq);
private CompletionQueueSafeHandle()
diff --git a/src/csharp/GrpcCore/Internal/Enums.cs b/src/csharp/GrpcCore/Internal/Enums.cs
index 46e3bca6eb..1151e94899 100644
--- a/src/csharp/GrpcCore/Internal/Enums.cs
+++ b/src/csharp/GrpcCore/Internal/Enums.cs
@@ -36,29 +36,36 @@ namespace Google.GRPC.Core.Internal
/// </summary>
internal enum GRPCCompletionType
{
- GRPC_QUEUE_SHUTDOWN,
/* Shutting down */
- GRPC_READ,
+ GRPC_QUEUE_SHUTDOWN,
+
+ /* operation completion */
+ GRPC_OP_COMPLETE,
+
/* A read has completed */
- GRPC_INVOKE_ACCEPTED,
- /* An invoke call has been accepted by flow
- control */
+ GRPC_READ,
+
+ /* A write has been accepted by flow control */
GRPC_WRITE_ACCEPTED,
- /* A write has been accepted by
- flow control */
- GRPC_FINISH_ACCEPTED,
+
/* writes_done or write_status has been accepted */
+ GRPC_FINISH_ACCEPTED,
+
+ /* The metadata array sent by server received at client */
GRPC_CLIENT_METADATA_READ,
- /* The metadata array sent by server received at
- client */
+
+ /* An RPC has finished. The event contains status.
+ * On the server this will be OK or Cancelled. */
GRPC_FINISHED,
- /* An RPC has finished. The event contains status.
- On the server this will be OK or Cancelled. */
- GRPC_SERVER_RPC_NEW,
+
/* A new RPC has arrived at the server */
+ GRPC_SERVER_RPC_NEW,
+
+ /* The server has finished shutting down */
+ GRPC_SERVER_SHUTDOWN,
+
+ /* must be last, forces users to include a default: case */
GRPC_COMPLETION_DO_NOT_USE
- /* must be last, forces users to include
- a default: case */
}
/// <summary>
diff --git a/src/csharp/GrpcCore/Internal/Event.cs b/src/csharp/GrpcCore/Internal/Event.cs
index 7056005ba6..5853ddd570 100644
--- a/src/csharp/GrpcCore/Internal/Event.cs
+++ b/src/csharp/GrpcCore/Internal/Event.cs
@@ -9,34 +9,34 @@ namespace Google.GRPC.Core.Internal
/// </summary>
internal class EventSafeHandle : SafeHandleZeroIsInvalid
{
- [DllImport("libgrpc.so")]
+ [DllImport("grpc.dll")]
static extern void grpc_event_finish(IntPtr ev);
- [DllImport("libgrpc_csharp_ext.so")]
+ [DllImport("grpc_csharp_ext.dll")]
static extern GRPCCompletionType grpc_event_type(EventSafeHandle ev);
- [DllImport("libgrpc_csharp_ext.so")]
+ [DllImport("grpc_csharp_ext.dll")]
static extern CallSafeHandle grpc_event_call(EventSafeHandle ev);
- [DllImport("libgrpc_csharp_ext.so")]
+ [DllImport("grpc_csharp_ext.dll")]
static extern GRPCOpError grpc_event_write_accepted(EventSafeHandle ev);
- [DllImport("libgrpc_csharp_ext.so")]
+ [DllImport("grpc_csharp_ext.dll")]
static extern GRPCOpError grpc_event_finish_accepted(EventSafeHandle ev);
- [DllImport("libgrpc_csharp_ext.so")]
+ [DllImport("grpc_csharp_ext.dll")]
static extern StatusCode grpc_event_finished_status(EventSafeHandle ev);
- [DllImport("libgrpc_csharp_ext.so")]
+ [DllImport("grpc_csharp_ext.dll")]
static extern IntPtr grpc_event_finished_details(EventSafeHandle ev); // returns const char*
- [DllImport("libgrpc_csharp_ext.so")]
+ [DllImport("grpc_csharp_ext.dll")]
static extern IntPtr grpc_event_read_length(EventSafeHandle ev);
- [DllImport("libgrpc_csharp_ext.so")]
+ [DllImport("grpc_csharp_ext.dll")]
static extern void grpc_event_read_copy_to_buffer(EventSafeHandle ev, byte[] buffer, UIntPtr bufferLen);
- [DllImport("libgrpc_csharp_ext.so")]
+ [DllImport("grpc_csharp_ext.dll")]
static extern IntPtr grpc_event_server_rpc_new_method(EventSafeHandle ev); // returns const char*
public GRPCCompletionType GetCompletionType()
@@ -98,34 +98,34 @@ namespace Google.GRPC.Core.Internal
/// </summary>
internal class EventSafeHandleNotOwned : SafeHandleZeroIsInvalid
{
- [DllImport("libgrpc.so")]
+ [DllImport("grpc.dll")]
static extern void grpc_event_finish(IntPtr ev);
- [DllImport("libgrpc_csharp_ext.so")]
+ [DllImport("grpc_csharp_ext.dll")]
static extern GRPCCompletionType grpc_event_type(EventSafeHandleNotOwned ev);
- [DllImport("libgrpc_csharp_ext.so")]
+ [DllImport("grpc_csharp_ext.dll")]
static extern CallSafeHandle grpc_event_call(EventSafeHandleNotOwned ev);
- [DllImport("libgrpc_csharp_ext.so")]
+ [DllImport("grpc_csharp_ext.dll")]
static extern GRPCOpError grpc_event_write_accepted(EventSafeHandleNotOwned ev);
- [DllImport("libgrpc_csharp_ext.so")]
+ [DllImport("grpc_csharp_ext.dll")]
static extern GRPCOpError grpc_event_finish_accepted(EventSafeHandleNotOwned ev);
- [DllImport("libgrpc_csharp_ext.so")]
+ [DllImport("grpc_csharp_ext.dll")]
static extern StatusCode grpc_event_finished_status(EventSafeHandleNotOwned ev);
- [DllImport("libgrpc_csharp_ext.so")]
+ [DllImport("grpc_csharp_ext.dll")]
static extern IntPtr grpc_event_finished_details(EventSafeHandleNotOwned ev); // returns const char*
- [DllImport("libgrpc_csharp_ext.so")]
+ [DllImport("grpc_csharp_ext.dll")]
static extern IntPtr grpc_event_read_length(EventSafeHandleNotOwned ev);
- [DllImport("libgrpc_csharp_ext.so")]
+ [DllImport("grpc_csharp_ext.dll")]
static extern void grpc_event_read_copy_to_buffer(EventSafeHandleNotOwned ev, byte[] buffer, UIntPtr bufferLen);
- [DllImport("libgrpc_csharp_ext.so")]
+ [DllImport("grpc_csharp_ext.dll")]
static extern IntPtr grpc_event_server_rpc_new_method(EventSafeHandleNotOwned ev); // returns const char*
public EventSafeHandleNotOwned() : base(false)
diff --git a/src/csharp/GrpcCore/Internal/ServerSafeHandle.cs b/src/csharp/GrpcCore/Internal/ServerSafeHandle.cs
index 08d4cf0192..d363b34f0b 100644
--- a/src/csharp/GrpcCore/Internal/ServerSafeHandle.cs
+++ b/src/csharp/GrpcCore/Internal/ServerSafeHandle.cs
@@ -10,30 +10,30 @@ namespace Google.GRPC.Core.Internal
/// </summary>
internal sealed class ServerSafeHandle : SafeHandleZeroIsInvalid
{
- [DllImport("libgrpc.so", EntryPoint = "grpc_server_request_call_old")]
+ [DllImport("grpc.dll", EntryPoint = "grpc_server_request_call_old")]
static extern GRPCCallError grpc_server_request_call_old_CALLBACK(ServerSafeHandle server, [MarshalAs(UnmanagedType.FunctionPtr)] EventCallbackDelegate callback);
- [DllImport("libgrpc.so")]
+ [DllImport("grpc.dll")]
static extern ServerSafeHandle grpc_server_create(CompletionQueueSafeHandle cq, IntPtr args);
// TODO: check int representation size
- [DllImport("libgrpc.so")]
+ [DllImport("grpc.dll")]
static extern int grpc_server_add_http2_port(ServerSafeHandle server, string addr);
// TODO: check int representation size
- [DllImport("libgrpc.so")]
+ [DllImport("grpc.dll")]
static extern int grpc_server_add_secure_http2_port(ServerSafeHandle server, string addr);
- [DllImport("libgrpc.so")]
+ [DllImport("grpc.dll")]
static extern void grpc_server_start(ServerSafeHandle server);
- [DllImport("libgrpc.so")]
+ [DllImport("grpc.dll")]
static extern void grpc_server_shutdown(ServerSafeHandle server);
- [DllImport("libgrpc.so", EntryPoint = "grpc_server_shutdown_and_notify")]
+ [DllImport("grpc.dll", EntryPoint = "grpc_server_shutdown_and_notify")]
static extern void grpc_server_shutdown_and_notify_CALLBACK(ServerSafeHandle server, [MarshalAs(UnmanagedType.FunctionPtr)] EventCallbackDelegate callback);
- [DllImport("libgrpc.so")]
+ [DllImport("grpc.dll")]
static extern void grpc_server_destroy(IntPtr server);
private ServerSafeHandle()
diff --git a/src/csharp/GrpcCore/Internal/Timespec.cs b/src/csharp/GrpcCore/Internal/Timespec.cs
index 8ffaf70bbf..5a197e121c 100644
--- a/src/csharp/GrpcCore/Internal/Timespec.cs
+++ b/src/csharp/GrpcCore/Internal/Timespec.cs
@@ -13,7 +13,7 @@ namespace Google.GRPC.Core.Internal
const int nanosPerSecond = 1000 * 1000 * 1000;
const int nanosPerTick = 100;
- [DllImport("libgpr.so")]
+ [DllImport("gpr.dll")]
static extern Timespec gpr_now();
// TODO: this only works on 64bit linux, can we autoselect the right size of ints?
diff --git a/src/node/examples/perf_test.js b/src/node/examples/perf_test.js
new file mode 100644
index 0000000000..c5e2872736
--- /dev/null
+++ b/src/node/examples/perf_test.js
@@ -0,0 +1,115 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+var grpc = require('..');
+var testProto = grpc.load(__dirname + '/../interop/test.proto').grpc.testing;
+var _ = require('underscore');
+var interop_server = require('../interop/interop_server.js');
+
+function runTest(iterations, callback) {
+ var testServer = interop_server.getServer(0, false);
+ testServer.server.listen();
+ var client = new testProto.TestService('localhost:' + testServer.port);
+
+ function runIterations(finish) {
+ var start = process.hrtime();
+ var intervals = [];
+ var pending = iterations;
+ function next(i) {
+ if (i >= iterations) {
+ testServer.server.shutdown();
+ var totalDiff = process.hrtime(start);
+ finish({
+ total: totalDiff[0] * 1000000 + totalDiff[1] / 1000,
+ intervals: intervals
+ });
+ } else{
+ var deadline = new Date();
+ deadline.setSeconds(deadline.getSeconds() + 3);
+ var startTime = process.hrtime();
+ client.emptyCall({}, function(err, resp) {
+ var timeDiff = process.hrtime(startTime);
+ intervals[i] = timeDiff[0] * 1000000 + timeDiff[1] / 1000;
+ next(i+1);
+ }, {}, deadline);
+ }
+ }
+ next(0);
+ }
+
+ function warmUp(num) {
+ var pending = num;
+ for (var i = 0; i < num; i++) {
+ (function(i) {
+ client.emptyCall({}, function(err, resp) {
+ pending--;
+ if (pending === 0) {
+ runIterations(callback);
+ }
+ });
+ })(i);
+ }
+ }
+ warmUp(100);
+}
+
+function percentile(arr, percentile) {
+ if (percentile > 99) {
+ percentile = 99;
+ }
+ if (percentile < 0) {
+ percentile = 0;
+ }
+ return arr[(arr.length * percentile / 100)|0];
+}
+
+if (require.main === module) {
+ var count;
+ if (process.argv.length >= 3) {
+ count = process.argv[2];
+ } else {
+ count = 100;
+ }
+ runTest(count, function(results) {
+ var sorted_intervals = _.sortBy(results.intervals, _.identity);
+ console.log('count:', count);
+ console.log('total time:', results.total, 'us');
+ console.log('median:', percentile(sorted_intervals, 50), 'us');
+ console.log('90th percentile:', percentile(sorted_intervals, 90), 'us');
+ console.log('95th percentile:', percentile(sorted_intervals, 95), 'us');
+ console.log('99th percentile:', percentile(sorted_intervals, 99), 'us');
+ console.log('QPS:', (count / results.total) * 1000000);
+ });
+}
+
+module.exports = runTest;
diff --git a/src/python/src/_adapter/_c_test.py b/src/python/src/_adapter/_c_test.py
index 19c91ffe01..210ac1fff7 100644
--- a/src/python/src/_adapter/_c_test.py
+++ b/src/python/src/_adapter/_c_test.py
@@ -92,7 +92,7 @@ class _CTest(unittest.TestCase):
_c.init()
completion_queue = _c.CompletionQueue()
- server = _c.Server(completion_queue)
+ server = _c.Server(completion_queue, None)
server.add_http2_addr('[::]:0')
server.start()
server.stop()
@@ -102,7 +102,7 @@ class _CTest(unittest.TestCase):
service_tag = object()
completion_queue = _c.CompletionQueue()
- server = _c.Server(completion_queue)
+ server = _c.Server(completion_queue, None)
server.add_http2_addr('[::]:0')
server.start()
server.service(service_tag)
@@ -119,7 +119,7 @@ class _CTest(unittest.TestCase):
del completion_queue
completion_queue = _c.CompletionQueue()
- server = _c.Server(completion_queue)
+ server = _c.Server(completion_queue, None)
server.add_http2_addr('[::]:0')
server.start()
thread = threading.Thread(target=completion_queue.get, args=(_FUTURE,))
@@ -162,6 +162,31 @@ class _CTest(unittest.TestCase):
_c.shut_down()
+ @unittest.skip('TODO(nathaniel): find and use real-enough test credentials')
+ def test_secure_server(self):
+ _c.init()
+
+ server_credentials = _c.ServerCredentials(
+ 'root certificate', (('private key', 'certificate chain'),))
+
+ completion_queue = _c.CompletionQueue()
+ server = _c.Server(completion_queue, server_credentials)
+ server.add_http2_addr('[::]:0')
+ server.start()
+ thread = threading.Thread(target=completion_queue.get, args=(_FUTURE,))
+ thread.start()
+ time.sleep(1)
+ server.stop()
+ completion_queue.stop()
+ for _ in range(_IDEMPOTENCE_DEMONSTRATION):
+ event = completion_queue.get(time.time() + _TIMEOUT)
+ self.assertIs(event.kind, _datatypes.Event.Kind.STOP)
+ thread.join()
+ del server
+ del completion_queue
+
+ _c.shut_down()
+
if __name__ == '__main__':
unittest.main()
diff --git a/src/python/src/_adapter/_low_test.py b/src/python/src/_adapter/_low_test.py
index 57b3be66a0..899ccf53c8 100644
--- a/src/python/src/_adapter/_low_test.py
+++ b/src/python/src/_adapter/_low_test.py
@@ -82,7 +82,7 @@ class EchoTest(unittest.TestCase):
self.host = 'localhost'
self.server_completion_queue = _low.CompletionQueue()
- self.server = _low.Server(self.server_completion_queue)
+ self.server = _low.Server(self.server_completion_queue, None)
port = self.server.add_http2_addr('[::]:0')
self.server.start()
@@ -260,7 +260,7 @@ class CancellationTest(unittest.TestCase):
self.host = 'localhost'
self.server_completion_queue = _low.CompletionQueue()
- self.server = _low.Server(self.server_completion_queue)
+ self.server = _low.Server(self.server_completion_queue, None)
port = self.server.add_http2_addr('[::]:0')
self.server.start()
diff --git a/src/python/src/_adapter/_server.c b/src/python/src/_adapter/_server.c
index d2730d9ae8..503be61ab4 100644
--- a/src/python/src/_adapter/_server.c
+++ b/src/python/src/_adapter/_server.c
@@ -38,18 +38,30 @@
#include "_adapter/_completion_queue.h"
#include "_adapter/_error.h"
+#include "_adapter/_server_credentials.h"
static int pygrpc_server_init(Server *self, PyObject *args, PyObject *kwds) {
const PyObject *completion_queue;
- if (!(PyArg_ParseTuple(args, "O!", &pygrpc_CompletionQueueType,
- &completion_queue))) {
+ PyObject *server_credentials;
+ if (!(PyArg_ParseTuple(args, "O!O", &pygrpc_CompletionQueueType,
+ &completion_queue, &server_credentials))) {
+ self->c_server = NULL;
+ return -1;
+ }
+ if (server_credentials == Py_None) {
+ self->c_server = grpc_server_create(
+ ((CompletionQueue *)completion_queue)->c_completion_queue, NULL);
+ return 0;
+ } else if (PyObject_TypeCheck(server_credentials,
+ &pygrpc_ServerCredentialsType)) {
+ self->c_server = grpc_secure_server_create(
+ ((ServerCredentials *)server_credentials)->c_server_credentials,
+ ((CompletionQueue *)completion_queue)->c_completion_queue, NULL);
+ return 0;
+ } else {
self->c_server = NULL;
return -1;
}
-
- self->c_server = grpc_server_create(
- ((CompletionQueue *)completion_queue)->c_completion_queue, NULL);
- return 0;
}
static void pygrpc_server_dealloc(Server *self) {
diff --git a/src/python/src/_adapter/fore.py b/src/python/src/_adapter/fore.py
index c307e7ce63..2f102751f2 100644
--- a/src/python/src/_adapter/fore.py
+++ b/src/python/src/_adapter/fore.py
@@ -265,7 +265,7 @@ class ForeLink(ticket_interfaces.ForeLink):
"""
with self._condition:
self._completion_queue = _low.CompletionQueue()
- self._server = _low.Server(self._completion_queue)
+ self._server = _low.Server(self._completion_queue, None)
port = self._server.add_http2_addr(
'[::]:%d' % (0 if self._port is None else self._port))
self._server.start()