Merge branch 'master' of github.com:google/grpc into docker_python

pull/733/head
Donna Dionne 10 years ago
commit 2c77f75b74
  1. 92
      Makefile
  2. 17
      build.json
  3. 8
      include/grpc/grpc_security.h
  4. 5
      include/grpc/support/host_port.h
  5. 2
      src/core/debug/trace.c
  6. 4
      src/core/iomgr/pollset_multipoller_with_poll_posix.c
  7. 8
      src/core/iomgr/pollset_posix.c
  8. 69
      src/core/iomgr/resolve_address_posix.c
  9. 166
      src/core/iomgr/resolve_address_windows.c
  10. 5
      src/core/iomgr/tcp_client_windows.c
  11. 5
      src/core/iomgr/tcp_server_windows.c
  12. 32
      src/core/security/auth.c
  13. 158
      src/core/security/credentials.c
  14. 3
      src/core/security/credentials.h
  15. 34
      src/core/security/json_token.c
  16. 13
      src/core/security/json_token.h
  17. 4
      src/core/security/security_context.c
  18. 6
      src/core/security/security_context.h
  19. 2
      src/core/support/cpu_windows.c
  20. 58
      src/core/support/host_port.c
  21. 2
      src/core/surface/init.c
  22. 2
      src/core/surface/server.c
  23. 4
      src/core/transport/chttp2_transport.c
  24. 43
      templates/Makefile.template
  25. 110
      test/core/security/create_jwt.c
  26. 136
      test/core/security/credentials_test.c
  27. 4
      test/core/security/fetch_oauth2.c
  28. 77
      test/core/security/json_token_test.c
  29. 8
      vsprojects/vs2013/Grpc.mak
  30. 4
      vsprojects/vs2013/grpc.vcxproj
  31. 5
      vsprojects/vs2013/grpc.vcxproj.filters
  32. 4
      vsprojects/vs2013/grpc_shared.vcxproj
  33. 5
      vsprojects/vs2013/grpc_shared.vcxproj.filters
  34. 4
      vsprojects/vs2013/grpc_unsecure.vcxproj
  35. 5
      vsprojects/vs2013/grpc_unsecure.vcxproj.filters

@ -234,6 +234,7 @@ OPENSSL_ALPN_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o /dev/null test/build/ope
ZLIB_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o /dev/null test/build/zlib.c -lz $(LDFLAGS) ZLIB_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o /dev/null test/build/zlib.c -lz $(LDFLAGS)
PERFTOOLS_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o /dev/null test/build/perftools.c -lprofiler $(LDFLAGS) PERFTOOLS_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o /dev/null test/build/perftools.c -lprofiler $(LDFLAGS)
PROTOBUF_CHECK_CMD = $(CXX) $(CXXFLAGS) $(CPPFLAGS) -o /dev/null test/build/protobuf.cc -lprotobuf $(LDFLAGS) PROTOBUF_CHECK_CMD = $(CXX) $(CXXFLAGS) $(CPPFLAGS) -o /dev/null test/build/protobuf.cc -lprotobuf $(LDFLAGS)
PROTOC_CMD = which protoc
PROTOC_CHECK_CMD = protoc --version | grep -q libprotoc.3 PROTOC_CHECK_CMD = protoc --version | grep -q libprotoc.3
ifndef REQUIRE_CUSTOM_LIBRARIES_$(CONFIG) ifndef REQUIRE_CUSTOM_LIBRARIES_$(CONFIG)
@ -244,10 +245,11 @@ LIBS += profiler
endif endif
endif endif
HAS_SYSTEM_PROTOBUF_VERIFY = $(shell $(PROTOBUF_CHECK_CMD) 2> /dev/null && echo true || echo false)
ifndef REQUIRE_CUSTOM_LIBRARIES_$(CONFIG) ifndef REQUIRE_CUSTOM_LIBRARIES_$(CONFIG)
HAS_SYSTEM_OPENSSL_ALPN = $(shell $(OPENSSL_ALPN_CHECK_CMD) 2> /dev/null && echo true || echo false) HAS_SYSTEM_OPENSSL_ALPN = $(shell $(OPENSSL_ALPN_CHECK_CMD) 2> /dev/null && echo true || echo false)
HAS_SYSTEM_ZLIB = $(shell $(ZLIB_CHECK_CMD) 2> /dev/null && echo true || echo false) HAS_SYSTEM_ZLIB = $(shell $(ZLIB_CHECK_CMD) 2> /dev/null && echo true || echo false)
HAS_SYSTEM_PROTOBUF = $(shell $(PROTOBUF_CHECK_CMD) 2> /dev/null && echo true || echo false) HAS_SYSTEM_PROTOBUF = $(HAS_SYSTEM_PROTOBUF_VERIFY)
else else
# override system libraries if the config requires a custom compiled library # override system libraries if the config requires a custom compiled library
HAS_SYSTEM_OPENSSL_ALPN = false HAS_SYSTEM_OPENSSL_ALPN = false
@ -255,7 +257,12 @@ HAS_SYSTEM_ZLIB = false
HAS_SYSTEM_PROTOBUF = false HAS_SYSTEM_PROTOBUF = false
endif endif
HAS_PROTOC = $(shell $(PROTOC_CMD) && echo true || echo false)
ifeq ($(HAS_PROTOC),true)
HAS_VALID_PROTOC = $(shell $(PROTOC_CHECK_CMD) 2> /dev/null && echo true || echo false) HAS_VALID_PROTOC = $(shell $(PROTOC_CHECK_CMD) 2> /dev/null && echo true || echo false)
else
HAS_VALID_PROTOC = false
endif
ifeq ($(wildcard third_party/openssl/ssl/ssl.h),) ifeq ($(wildcard third_party/openssl/ssl/ssl.h),)
HAS_EMBEDDED_OPENSSL_ALPN = false HAS_EMBEDDED_OPENSSL_ALPN = false
@ -308,8 +315,8 @@ LDLIBS_SECURE += $(addprefix -l, $(LIBS_SECURE))
ifeq ($(HAS_SYSTEM_PROTOBUF),false) ifeq ($(HAS_SYSTEM_PROTOBUF),false)
ifeq ($(HAS_EMBEDDED_PROTOBUF),true) ifeq ($(HAS_EMBEDDED_PROTOBUF),true)
PROTOBUF_DEP = $(LIBDIR)/$(CONFIG)/protobuf/libprotobuf.a PROTOBUF_DEP = $(LIBDIR)/$(CONFIG)/protobuf/libprotobuf.a
CPPFLAGS += -Ithird_party/protobuf/src CPPFLAGS := -Ithird_party/protobuf/src $(CPPFLAGS)
LDFLAGS += -L$(LIBDIR)/$(CONFIG)/protobuf LDFLAGS := -L$(LIBDIR)/$(CONFIG)/protobuf $(LDFLAGS)
PROTOC = $(BINDIR)/$(CONFIG)/protobuf/protoc PROTOC = $(BINDIR)/$(CONFIG)/protobuf/protoc
else else
NO_PROTOBUF = true NO_PROTOBUF = true
@ -327,6 +334,13 @@ ifeq ($(MAKECMDGOALS),clean)
NO_DEPS = true NO_DEPS = true
endif endif
INSTALL_OK = false
ifeq ($(HAS_VALID_PROTOC),true)
ifeq ($(HAS_SYSTEM_PROTOBUF_VERIFY),true)
INSTALL_OK = true
endif
endif
.SECONDARY = %.pb.h %.pb.cc .SECONDARY = %.pb.h %.pb.cc
PROTOC_PLUGINS = $(BINDIR)/$(CONFIG)/grpc_cpp_plugin $(BINDIR)/$(CONFIG)/grpc_python_plugin $(BINDIR)/$(CONFIG)/grpc_ruby_plugin PROTOC_PLUGINS = $(BINDIR)/$(CONFIG)/grpc_cpp_plugin $(BINDIR)/$(CONFIG)/grpc_python_plugin $(BINDIR)/$(CONFIG)/grpc_ruby_plugin
@ -463,6 +477,7 @@ grpc_byte_buffer_reader_test: $(BINDIR)/$(CONFIG)/grpc_byte_buffer_reader_test
grpc_channel_stack_test: $(BINDIR)/$(CONFIG)/grpc_channel_stack_test grpc_channel_stack_test: $(BINDIR)/$(CONFIG)/grpc_channel_stack_test
grpc_completion_queue_benchmark: $(BINDIR)/$(CONFIG)/grpc_completion_queue_benchmark grpc_completion_queue_benchmark: $(BINDIR)/$(CONFIG)/grpc_completion_queue_benchmark
grpc_completion_queue_test: $(BINDIR)/$(CONFIG)/grpc_completion_queue_test grpc_completion_queue_test: $(BINDIR)/$(CONFIG)/grpc_completion_queue_test
grpc_create_jwt: $(BINDIR)/$(CONFIG)/grpc_create_jwt
grpc_credentials_test: $(BINDIR)/$(CONFIG)/grpc_credentials_test grpc_credentials_test: $(BINDIR)/$(CONFIG)/grpc_credentials_test
grpc_fetch_oauth2: $(BINDIR)/$(CONFIG)/grpc_fetch_oauth2 grpc_fetch_oauth2: $(BINDIR)/$(CONFIG)/grpc_fetch_oauth2
grpc_json_token_test: $(BINDIR)/$(CONFIG)/grpc_json_token_test grpc_json_token_test: $(BINDIR)/$(CONFIG)/grpc_json_token_test
@ -880,7 +895,7 @@ third_party/protobuf/configure:
$(LIBDIR)/$(CONFIG)/protobuf/libprotobuf.a: third_party/protobuf/configure $(LIBDIR)/$(CONFIG)/protobuf/libprotobuf.a: third_party/protobuf/configure
$(E) "[MAKE] Building protobuf" $(E) "[MAKE] Building protobuf"
$(Q)(cd third_party/protobuf ; CC="$(CC)" CPPFLAGS="-fPIC" CXX="$(CXX)" LDFLAGS="$(LDFLAGS_$(CONFIG)) -g" CXXFLAGS="-DLANG_CXX11 -std=c++11" CPPFLAGS="$(CPPFLAGS_$(CONFIG)) -g" ./configure --disable-shared --enable-static) $(Q)(cd third_party/protobuf ; CC="$(CC)" CXX="$(CXX)" LDFLAGS="$(LDFLAGS_$(CONFIG)) -g" CXXFLAGS="-DLANG_CXX11 -std=c++11" CPPFLAGS="-fPIC $(CPPFLAGS_$(CONFIG)) -g" ./configure --disable-shared --enable-static)
$(Q)$(MAKE) -C third_party/protobuf clean $(Q)$(MAKE) -C third_party/protobuf clean
$(Q)$(MAKE) -C third_party/protobuf $(Q)$(MAKE) -C third_party/protobuf
$(Q)mkdir -p $(LIBDIR)/$(CONFIG)/protobuf $(Q)mkdir -p $(LIBDIR)/$(CONFIG)/protobuf
@ -1748,7 +1763,7 @@ test_cxx: buildtests_cxx
$(Q) $(BINDIR)/$(CONFIG)/thread_pool_test || ( echo test thread_pool_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/thread_pool_test || ( echo test thread_pool_test failed ; exit 1 )
tools: privatelibs $(BINDIR)/$(CONFIG)/gen_hpack_tables $(BINDIR)/$(CONFIG)/grpc_fetch_oauth2 tools: privatelibs $(BINDIR)/$(CONFIG)/gen_hpack_tables $(BINDIR)/$(CONFIG)/grpc_create_jwt $(BINDIR)/$(CONFIG)/grpc_fetch_oauth2
buildbenchmarks: privatelibs $(BINDIR)/$(CONFIG)/grpc_completion_queue_benchmark $(BINDIR)/$(CONFIG)/low_level_ping_pong_benchmark buildbenchmarks: privatelibs $(BINDIR)/$(CONFIG)/grpc_completion_queue_benchmark $(BINDIR)/$(CONFIG)/low_level_ping_pong_benchmark
@ -1915,7 +1930,7 @@ $(OBJDIR)/$(CONFIG)/%.o : %.cc
$(Q) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -MMD -MF $(addsuffix .dep, $(basename $@)) -c -o $@ $< $(Q) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -MMD -MF $(addsuffix .dep, $(basename $@)) -c -o $@ $<
install: install_c install_cxx install-plugins install: install_c install_cxx install-plugins verify-install
install_c: install-headers_c install-static_c install-shared_c install_c: install-headers_c install-static_c install-shared_c
@ -2059,6 +2074,25 @@ else
$(Q) $(INSTALL) $(BINDIR)/$(CONFIG)/grpc_ruby_plugin $(prefix)/bin/grpc_ruby_plugin $(Q) $(INSTALL) $(BINDIR)/$(CONFIG)/grpc_ruby_plugin $(prefix)/bin/grpc_ruby_plugin
endif endif
verify-install:
ifeq ($(SYSTEM_OK),true)
@echo "Your system looks ready to go."
@echo
else
@echo "Your system doesn't have protoc 3.0.0+ installed. While this"
@echo "won't prevent grpc from working, you won't be able to compile"
@echo "and run any meaningful code with it."
@echo
@echo
@echo "Please download and install protobuf 3.0.0+ from:"
@echo
@echo " https://github.com/google/protobuf/releases"
@echo
@echo "Once you've done so, you can re-run this check by doing:"
@echo
@echo " make verify-install"
endif
clean: clean:
$(E) "[CLEAN] Cleaning build directories." $(E) "[CLEAN] Cleaning build directories."
$(Q) $(RM) -rf $(OBJDIR) $(LIBDIR) $(BINDIR) $(GENDIR) $(Q) $(RM) -rf $(OBJDIR) $(LIBDIR) $(BINDIR) $(GENDIR)
@ -2290,7 +2324,8 @@ LIBGRPC_SRC = \
src/core/iomgr/pollset_multipoller_with_poll_posix.c \ src/core/iomgr/pollset_multipoller_with_poll_posix.c \
src/core/iomgr/pollset_posix.c \ src/core/iomgr/pollset_posix.c \
src/core/iomgr/pollset_windows.c \ src/core/iomgr/pollset_windows.c \
src/core/iomgr/resolve_address.c \ src/core/iomgr/resolve_address_posix.c \
src/core/iomgr/resolve_address_windows.c \
src/core/iomgr/sockaddr_utils.c \ src/core/iomgr/sockaddr_utils.c \
src/core/iomgr/socket_utils_common_posix.c \ src/core/iomgr/socket_utils_common_posix.c \
src/core/iomgr/socket_utils_linux.c \ src/core/iomgr/socket_utils_linux.c \
@ -2430,7 +2465,8 @@ src/core/iomgr/pollset_multipoller_with_epoll.c: $(OPENSSL_DEP)
src/core/iomgr/pollset_multipoller_with_poll_posix.c: $(OPENSSL_DEP) src/core/iomgr/pollset_multipoller_with_poll_posix.c: $(OPENSSL_DEP)
src/core/iomgr/pollset_posix.c: $(OPENSSL_DEP) src/core/iomgr/pollset_posix.c: $(OPENSSL_DEP)
src/core/iomgr/pollset_windows.c: $(OPENSSL_DEP) src/core/iomgr/pollset_windows.c: $(OPENSSL_DEP)
src/core/iomgr/resolve_address.c: $(OPENSSL_DEP) src/core/iomgr/resolve_address_posix.c: $(OPENSSL_DEP)
src/core/iomgr/resolve_address_windows.c: $(OPENSSL_DEP)
src/core/iomgr/sockaddr_utils.c: $(OPENSSL_DEP) src/core/iomgr/sockaddr_utils.c: $(OPENSSL_DEP)
src/core/iomgr/socket_utils_common_posix.c: $(OPENSSL_DEP) src/core/iomgr/socket_utils_common_posix.c: $(OPENSSL_DEP)
src/core/iomgr/socket_utils_linux.c: $(OPENSSL_DEP) src/core/iomgr/socket_utils_linux.c: $(OPENSSL_DEP)
@ -2587,7 +2623,8 @@ $(OBJDIR)/$(CONFIG)/src/core/iomgr/pollset_multipoller_with_epoll.o:
$(OBJDIR)/$(CONFIG)/src/core/iomgr/pollset_multipoller_with_poll_posix.o: $(OBJDIR)/$(CONFIG)/src/core/iomgr/pollset_multipoller_with_poll_posix.o:
$(OBJDIR)/$(CONFIG)/src/core/iomgr/pollset_posix.o: $(OBJDIR)/$(CONFIG)/src/core/iomgr/pollset_posix.o:
$(OBJDIR)/$(CONFIG)/src/core/iomgr/pollset_windows.o: $(OBJDIR)/$(CONFIG)/src/core/iomgr/pollset_windows.o:
$(OBJDIR)/$(CONFIG)/src/core/iomgr/resolve_address.o: $(OBJDIR)/$(CONFIG)/src/core/iomgr/resolve_address_posix.o:
$(OBJDIR)/$(CONFIG)/src/core/iomgr/resolve_address_windows.o:
$(OBJDIR)/$(CONFIG)/src/core/iomgr/sockaddr_utils.o: $(OBJDIR)/$(CONFIG)/src/core/iomgr/sockaddr_utils.o:
$(OBJDIR)/$(CONFIG)/src/core/iomgr/socket_utils_common_posix.o: $(OBJDIR)/$(CONFIG)/src/core/iomgr/socket_utils_common_posix.o:
$(OBJDIR)/$(CONFIG)/src/core/iomgr/socket_utils_linux.o: $(OBJDIR)/$(CONFIG)/src/core/iomgr/socket_utils_linux.o:
@ -2759,7 +2796,8 @@ LIBGRPC_UNSECURE_SRC = \
src/core/iomgr/pollset_multipoller_with_poll_posix.c \ src/core/iomgr/pollset_multipoller_with_poll_posix.c \
src/core/iomgr/pollset_posix.c \ src/core/iomgr/pollset_posix.c \
src/core/iomgr/pollset_windows.c \ src/core/iomgr/pollset_windows.c \
src/core/iomgr/resolve_address.c \ src/core/iomgr/resolve_address_posix.c \
src/core/iomgr/resolve_address_windows.c \
src/core/iomgr/sockaddr_utils.c \ src/core/iomgr/sockaddr_utils.c \
src/core/iomgr/socket_utils_common_posix.c \ src/core/iomgr/socket_utils_common_posix.c \
src/core/iomgr/socket_utils_linux.c \ src/core/iomgr/socket_utils_linux.c \
@ -2894,7 +2932,8 @@ $(OBJDIR)/$(CONFIG)/src/core/iomgr/pollset_multipoller_with_epoll.o:
$(OBJDIR)/$(CONFIG)/src/core/iomgr/pollset_multipoller_with_poll_posix.o: $(OBJDIR)/$(CONFIG)/src/core/iomgr/pollset_multipoller_with_poll_posix.o:
$(OBJDIR)/$(CONFIG)/src/core/iomgr/pollset_posix.o: $(OBJDIR)/$(CONFIG)/src/core/iomgr/pollset_posix.o:
$(OBJDIR)/$(CONFIG)/src/core/iomgr/pollset_windows.o: $(OBJDIR)/$(CONFIG)/src/core/iomgr/pollset_windows.o:
$(OBJDIR)/$(CONFIG)/src/core/iomgr/resolve_address.o: $(OBJDIR)/$(CONFIG)/src/core/iomgr/resolve_address_posix.o:
$(OBJDIR)/$(CONFIG)/src/core/iomgr/resolve_address_windows.o:
$(OBJDIR)/$(CONFIG)/src/core/iomgr/sockaddr_utils.o: $(OBJDIR)/$(CONFIG)/src/core/iomgr/sockaddr_utils.o:
$(OBJDIR)/$(CONFIG)/src/core/iomgr/socket_utils_common_posix.o: $(OBJDIR)/$(CONFIG)/src/core/iomgr/socket_utils_common_posix.o:
$(OBJDIR)/$(CONFIG)/src/core/iomgr/socket_utils_linux.o: $(OBJDIR)/$(CONFIG)/src/core/iomgr/socket_utils_linux.o:
@ -6383,6 +6422,37 @@ endif
endif endif
GRPC_CREATE_JWT_SRC = \
test/core/security/create_jwt.c \
GRPC_CREATE_JWT_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GRPC_CREATE_JWT_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL with ALPN.
$(BINDIR)/$(CONFIG)/grpc_create_jwt: openssl_dep_error
else
$(BINDIR)/$(CONFIG)/grpc_create_jwt: $(GRPC_CREATE_JWT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LD) $(LDFLAGS) $(GRPC_CREATE_JWT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/grpc_create_jwt
endif
$(OBJDIR)/$(CONFIG)/test/core/security/create_jwt.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_grpc_create_jwt: $(GRPC_CREATE_JWT_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(GRPC_CREATE_JWT_OBJS:.o=.dep)
endif
endif
GRPC_CREDENTIALS_TEST_SRC = \ GRPC_CREDENTIALS_TEST_SRC = \
test/core/security/credentials_test.c \ test/core/security/credentials_test.c \

@ -136,7 +136,8 @@
"src/core/iomgr/pollset_multipoller_with_poll_posix.c", "src/core/iomgr/pollset_multipoller_with_poll_posix.c",
"src/core/iomgr/pollset_posix.c", "src/core/iomgr/pollset_posix.c",
"src/core/iomgr/pollset_windows.c", "src/core/iomgr/pollset_windows.c",
"src/core/iomgr/resolve_address.c", "src/core/iomgr/resolve_address_posix.c",
"src/core/iomgr/resolve_address_windows.c",
"src/core/iomgr/sockaddr_utils.c", "src/core/iomgr/sockaddr_utils.c",
"src/core/iomgr/socket_utils_common_posix.c", "src/core/iomgr/socket_utils_common_posix.c",
"src/core/iomgr/socket_utils_linux.c", "src/core/iomgr/socket_utils_linux.c",
@ -1129,6 +1130,20 @@
"gpr" "gpr"
] ]
}, },
{
"name": "grpc_create_jwt",
"build": "tool",
"language": "c",
"src": [
"test/core/security/create_jwt.c"
],
"deps": [
"grpc_test_util",
"grpc",
"gpr_test_util",
"gpr"
]
},
{ {
"name": "grpc_credentials_test", "name": "grpc_credentials_test",
"build": "test", "build": "test",

@ -100,6 +100,14 @@ extern const gpr_timespec grpc_max_auth_token_lifetime;
grpc_credentials *grpc_service_account_credentials_create( grpc_credentials *grpc_service_account_credentials_create(
const char *json_key, const char *scope, gpr_timespec token_lifetime); const char *json_key, const char *scope, gpr_timespec token_lifetime);
/* Creates a JWT credentials object. May return NULL if the input is invalid.
- json_key is the JSON key string containing the client's private key.
- token_lifetime is the lifetime of each Json Web Token (JWT) created with
this credentials. It should not exceed grpc_max_auth_token_lifetime or
will be cropped to this value. */
grpc_credentials *grpc_jwt_credentials_create(const char *json_key,
gpr_timespec token_lifetime);
/* Creates a fake transport security credentials object for testing. */ /* Creates a fake transport security credentials object for testing. */
grpc_credentials *grpc_fake_transport_security_credentials_create(void); grpc_credentials *grpc_fake_transport_security_credentials_create(void);

@ -50,6 +50,11 @@ extern "C" {
In the unlikely event of an error, returns -1 and sets *out to NULL. */ In the unlikely event of an error, returns -1 and sets *out to NULL. */
int gpr_join_host_port(char **out, const char *host, int port); int gpr_join_host_port(char **out, const char *host, int port);
/* Given a name in the form "host:port" or "[ho:st]:port", split into hostname
and port number, into newly allocated strings, which must later be
destroyed using gpr_free(). */
void gpr_split_host_port(const char *name, char **host, char **port);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

@ -40,7 +40,7 @@
#include "src/core/support/env.h" #include "src/core/support/env.h"
#if GRPC_ENABLE_TRACING #if GRPC_ENABLE_TRACING
gpr_uint32 grpc_trace_bits; gpr_uint32 grpc_trace_bits = 0;
static void add(const char *beg, const char *end, char ***ss, size_t *ns) { static void add(const char *beg, const char *end, char ***ss, size_t *ns) {
size_t n = *ns; size_t n = *ns;

@ -183,10 +183,10 @@ static int multipoll_with_poll_pollset_maybe_work(
grpc_pollset_kick_consume(&pollset->kick_state); grpc_pollset_kick_consume(&pollset->kick_state);
} }
for (i = 1; i < np; i++) { for (i = 1; i < np; i++) {
if (h->pfds[i].revents & POLLIN) { if (h->pfds[i].revents & (POLLIN | POLLHUP | POLLERR)) {
grpc_fd_become_readable(h->watchers[i].fd, allow_synchronous_callback); grpc_fd_become_readable(h->watchers[i].fd, allow_synchronous_callback);
} }
if (h->pfds[i].revents & POLLOUT) { if (h->pfds[i].revents & (POLLOUT | POLLHUP | POLLERR)) {
grpc_fd_become_writable(h->watchers[i].fd, allow_synchronous_callback); grpc_fd_become_writable(h->watchers[i].fd, allow_synchronous_callback);
} }
} }

@ -63,9 +63,9 @@ static void backup_poller(void *p) {
gpr_mu_lock(&g_backup_pollset.mu); gpr_mu_lock(&g_backup_pollset.mu);
while (g_shutdown_backup_poller == 0) { while (g_shutdown_backup_poller == 0) {
gpr_timespec next_poll = gpr_time_add(last_poll, delta); gpr_timespec next_poll = gpr_time_add(last_poll, delta);
grpc_pollset_work(&g_backup_pollset, next_poll); grpc_pollset_work(&g_backup_pollset, gpr_time_add(gpr_now(), gpr_time_from_seconds(1)));
gpr_mu_unlock(&g_backup_pollset.mu); gpr_mu_unlock(&g_backup_pollset.mu);
gpr_sleep_until(next_poll); /*gpr_sleep_until(next_poll);*/
gpr_mu_lock(&g_backup_pollset.mu); gpr_mu_lock(&g_backup_pollset.mu);
last_poll = next_poll; last_poll = next_poll;
} }
@ -277,10 +277,10 @@ static int unary_poll_pollset_maybe_work(grpc_pollset *pollset,
if (pfd[0].revents & POLLIN) { if (pfd[0].revents & POLLIN) {
grpc_pollset_kick_consume(&pollset->kick_state); grpc_pollset_kick_consume(&pollset->kick_state);
} }
if (pfd[1].revents & POLLIN) { if (pfd[1].revents & (POLLIN | POLLHUP | POLLERR)) {
grpc_fd_become_readable(fd, allow_synchronous_callback); grpc_fd_become_readable(fd, allow_synchronous_callback);
} }
if (pfd[1].revents & POLLOUT) { if (pfd[1].revents & (POLLOUT | POLLHUP | POLLERR)) {
grpc_fd_become_writable(fd, allow_synchronous_callback); grpc_fd_become_writable(fd, allow_synchronous_callback);
} }
} }

@ -31,9 +31,8 @@
* *
*/ */
#ifndef _POSIX_SOURCE #include <grpc/support/port_platform.h>
#define _POSIX_SOURCE #ifdef GPR_POSIX_SOCKET
#endif
#include "src/core/iomgr/sockaddr.h" #include "src/core/iomgr/sockaddr.h"
#include "src/core/iomgr/resolve_address.h" #include "src/core/iomgr/resolve_address.h"
@ -46,6 +45,7 @@
#include "src/core/iomgr/sockaddr_utils.h" #include "src/core/iomgr/sockaddr_utils.h"
#include "src/core/support/string.h" #include "src/core/support/string.h"
#include <grpc/support/alloc.h> #include <grpc/support/alloc.h>
#include <grpc/support/host_port.h>
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include <grpc/support/thd.h> #include <grpc/support/thd.h>
#include <grpc/support/time.h> #include <grpc/support/time.h>
@ -57,63 +57,6 @@ typedef struct {
void *arg; void *arg;
} request; } request;
static void split_host_port(const char *name, char **host, char **port) {
const char *host_start;
size_t host_len;
const char *port_start;
*host = NULL;
*port = NULL;
if (name[0] == '[') {
/* Parse a bracketed host, typically an IPv6 literal. */
const char *rbracket = strchr(name, ']');
if (rbracket == NULL) {
/* Unmatched [ */
return;
}
if (rbracket[1] == '\0') {
/* ]<end> */
port_start = NULL;
} else if (rbracket[1] == ':') {
/* ]:<port?> */
port_start = rbracket + 2;
} else {
/* ]<invalid> */
return;
}
host_start = name + 1;
host_len = rbracket - host_start;
if (memchr(host_start, ':', host_len) == NULL) {
/* Require all bracketed hosts to contain a colon, because a hostname or
IPv4 address should never use brackets. */
return;
}
} else {
const char *colon = strchr(name, ':');
if (colon != NULL && strchr(colon + 1, ':') == NULL) {
/* Exactly 1 colon. Split into host:port. */
host_start = name;
host_len = colon - name;
port_start = colon + 1;
} else {
/* 0 or 2+ colons. Bare hostname or IPv6 litearal. */
host_start = name;
host_len = strlen(name);
port_start = NULL;
}
}
/* Allocate return values. */
*host = gpr_malloc(host_len + 1);
memcpy(*host, host_start, host_len);
(*host)[host_len] = '\0';
if (port_start != NULL) {
*port = gpr_strdup(port_start);
}
}
grpc_resolved_addresses *grpc_blocking_resolve_address( grpc_resolved_addresses *grpc_blocking_resolve_address(
const char *name, const char *default_port) { const char *name, const char *default_port) {
struct addrinfo hints; struct addrinfo hints;
@ -134,12 +77,12 @@ grpc_resolved_addresses *grpc_blocking_resolve_address(
un = (struct sockaddr_un *)addrs->addrs->addr; un = (struct sockaddr_un *)addrs->addrs->addr;
un->sun_family = AF_UNIX; un->sun_family = AF_UNIX;
strcpy(un->sun_path, name + 5); strcpy(un->sun_path, name + 5);
addrs->addrs->len = strlen(un->sun_path) + sizeof(un->sun_family); addrs->addrs->len = strlen(un->sun_path) + sizeof(un->sun_family) + 1;
return addrs; return addrs;
} }
/* parse name, splitting it into host and port parts */ /* parse name, splitting it into host and port parts */
split_host_port(name, &host, &port); gpr_split_host_port(name, &host, &port);
if (host == NULL) { if (host == NULL) {
gpr_log(GPR_ERROR, "unparseable host:port: '%s'", name); gpr_log(GPR_ERROR, "unparseable host:port: '%s'", name);
goto done; goto done;
@ -233,3 +176,5 @@ void grpc_resolve_address(const char *name, const char *default_port,
r->arg = arg; r->arg = arg;
gpr_thd_new(&id, do_request, r, NULL); gpr_thd_new(&id, do_request, r, NULL);
} }
#endif

@ -0,0 +1,166 @@
/*
*
* 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_WINSOCK_SOCKET
#include "src/core/iomgr/sockaddr.h"
#include "src/core/iomgr/resolve_address.h"
#include <sys/types.h>
#include <string.h>
#include "src/core/iomgr/iomgr_internal.h"
#include "src/core/iomgr/sockaddr_utils.h"
#include "src/core/support/string.h"
#include <grpc/support/alloc.h>
#include <grpc/support/host_port.h>
#include <grpc/support/log.h>
#include <grpc/support/thd.h>
#include <grpc/support/time.h>
typedef struct {
char *name;
char *default_port;
grpc_resolve_cb cb;
void *arg;
} request;
grpc_resolved_addresses *grpc_blocking_resolve_address(
const char *name, const char *default_port) {
struct addrinfo hints;
struct addrinfo *result = NULL, *resp;
char *host;
char *port;
int s;
size_t i;
grpc_resolved_addresses *addrs = NULL;
const gpr_timespec start_time = gpr_now();
/* parse name, splitting it into host and port parts */
gpr_split_host_port(name, &host, &port);
if (host == NULL) {
gpr_log(GPR_ERROR, "unparseable host:port: '%s'", name);
goto done;
}
if (port == NULL) {
if (default_port == NULL) {
gpr_log(GPR_ERROR, "no port in name '%s'", name);
goto done;
}
port = gpr_strdup(default_port);
}
/* Call getaddrinfo */
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; /* ipv4 or ipv6 */
hints.ai_socktype = SOCK_STREAM; /* stream socket */
hints.ai_flags = AI_PASSIVE; /* for wildcard IP address */
s = getaddrinfo(host, port, &hints, &result);
if (s != 0) {
gpr_log(GPR_ERROR, "getaddrinfo: %s", gai_strerror(s));
goto done;
}
/* Success path: set addrs non-NULL, fill it in */
addrs = gpr_malloc(sizeof(grpc_resolved_addresses));
addrs->naddrs = 0;
for (resp = result; resp != NULL; resp = resp->ai_next) {
addrs->naddrs++;
}
addrs->addrs = gpr_malloc(sizeof(grpc_resolved_address) * addrs->naddrs);
i = 0;
for (resp = result; resp != NULL; resp = resp->ai_next) {
memcpy(&addrs->addrs[i].addr, resp->ai_addr, resp->ai_addrlen);
addrs->addrs[i].len = resp->ai_addrlen;
i++;
}
/* Temporary logging, to help identify flakiness in dualstack_socket_test. */
{
const gpr_timespec delay = gpr_time_sub(gpr_now(), start_time);
const int delay_ms =
delay.tv_sec * GPR_MS_PER_SEC + delay.tv_nsec / GPR_NS_PER_MS;
gpr_log(GPR_INFO, "logspam: getaddrinfo(%s, %s) resolved %d addrs in %dms:",
host, port, addrs->naddrs, delay_ms);
for (i = 0; i < addrs->naddrs; i++) {
char *buf;
grpc_sockaddr_to_string(&buf, (struct sockaddr *)&addrs->addrs[i].addr,
0);
gpr_log(GPR_INFO, "logspam: [%d] %s", i, buf);
gpr_free(buf);
}
}
done:
gpr_free(host);
gpr_free(port);
if (result) {
freeaddrinfo(result);
}
return addrs;
}
/* Thread function to asynch-ify grpc_blocking_resolve_address */
static void do_request(void *rp) {
request *r = rp;
grpc_resolved_addresses *resolved =
grpc_blocking_resolve_address(r->name, r->default_port);
void *arg = r->arg;
grpc_resolve_cb cb = r->cb;
gpr_free(r->name);
gpr_free(r->default_port);
gpr_free(r);
cb(arg, resolved);
grpc_iomgr_unref();
}
void grpc_resolved_addresses_destroy(grpc_resolved_addresses *addrs) {
gpr_free(addrs->addrs);
gpr_free(addrs);
}
void grpc_resolve_address(const char *name, const char *default_port,
grpc_resolve_cb cb, void *arg) {
request *r = gpr_malloc(sizeof(request));
gpr_thd_id id;
grpc_iomgr_ref();
r->name = gpr_strdup(name);
r->default_port = gpr_strdup(default_port);
r->cb = cb;
r->arg = arg;
gpr_thd_new(&id, do_request, r, NULL);
}
#endif

@ -43,12 +43,13 @@
#include <grpc/support/slice_buffer.h> #include <grpc/support/slice_buffer.h>
#include <grpc/support/useful.h> #include <grpc/support/useful.h>
#include "src/core/iomgr/alarm.h"
#include "src/core/iomgr/iocp_windows.h"
#include "src/core/iomgr/tcp_client.h" #include "src/core/iomgr/tcp_client.h"
#include "src/core/iomgr/tcp_windows.h" #include "src/core/iomgr/tcp_windows.h"
#include "src/core/iomgr/socket_windows.h"
#include "src/core/iomgr/alarm.h"
#include "src/core/iomgr/sockaddr.h" #include "src/core/iomgr/sockaddr.h"
#include "src/core/iomgr/sockaddr_utils.h" #include "src/core/iomgr/sockaddr_utils.h"
#include "src/core/iomgr/socket_windows.h"
typedef struct { typedef struct {
void(*cb)(void *arg, grpc_endpoint *tcp); void(*cb)(void *arg, grpc_endpoint *tcp);

@ -355,8 +355,9 @@ SOCKET grpc_tcp_server_get_socket(grpc_tcp_server *s, unsigned index) {
return (index < s->nports) ? s->ports[index].socket->socket : INVALID_SOCKET; return (index < s->nports) ? s->ports[index].socket->socket : INVALID_SOCKET;
} }
void grpc_tcp_server_start(grpc_tcp_server *s, grpc_pollset *pollset, void grpc_tcp_server_start(grpc_tcp_server *s, grpc_pollset **pollset,
grpc_tcp_server_cb cb, void *cb_arg) { size_t pollset_count, grpc_tcp_server_cb cb,
void *cb_arg) {
size_t i; size_t i;
GPR_ASSERT(cb); GPR_ASSERT(cb);
gpr_mu_lock(&s->mu); gpr_mu_lock(&s->mu);

@ -48,6 +48,7 @@
typedef struct { typedef struct {
grpc_credentials *creds; grpc_credentials *creds;
grpc_mdstr *host; grpc_mdstr *host;
grpc_mdstr *method;
grpc_call_op op; grpc_call_op op;
} call_data; } call_data;
@ -56,6 +57,7 @@ typedef struct {
grpc_channel_security_context *security_context; grpc_channel_security_context *security_context;
grpc_mdctx *md_ctx; grpc_mdctx *md_ctx;
grpc_mdstr *authority_string; grpc_mdstr *authority_string;
grpc_mdstr *path_string;
grpc_mdstr *error_msg_key; grpc_mdstr *error_msg_key;
} channel_data; } channel_data;
@ -89,6 +91,26 @@ static void on_credentials_metadata(void *user_data, grpc_mdelem **md_elems,
grpc_call_next_op(elem, &((call_data *)elem->call_data)->op); grpc_call_next_op(elem, &((call_data *)elem->call_data)->op);
} }
static char *build_service_url(const char *url_scheme, call_data *calld) {
char *service_url;
char *service = gpr_strdup(grpc_mdstr_as_c_string(calld->method));
char *last_slash = strrchr(service, '/');
if (last_slash == NULL) {
gpr_log(GPR_ERROR, "No '/' found in fully qualified method name");
service[0] = '\0';
} else if (last_slash == service) {
/* No service part in fully qualified method name: will just be "/". */
service[1] = '\0';
} else {
*last_slash = '\0';
}
if (url_scheme == NULL) url_scheme = "";
gpr_asprintf(&service_url, "%s://%s%s", url_scheme,
grpc_mdstr_as_c_string(calld->host), service);
gpr_free(service);
return service_url;
}
static void send_security_metadata(grpc_call_element *elem, grpc_call_op *op) { static void send_security_metadata(grpc_call_element *elem, grpc_call_op *op) {
/* grab pointers to our data from the call element */ /* grab pointers to our data from the call element */
call_data *calld = elem->call_data; call_data *calld = elem->call_data;
@ -106,9 +128,12 @@ static void send_security_metadata(grpc_call_element *elem, grpc_call_op *op) {
} }
if (channel_creds != NULL && if (channel_creds != NULL &&
grpc_credentials_has_request_metadata(channel_creds)) { grpc_credentials_has_request_metadata(channel_creds)) {
char *service_url =
build_service_url(channeld->security_context->base.url_scheme, calld);
calld->op = *op; /* Copy op (originates from the caller's stack). */ calld->op = *op; /* Copy op (originates from the caller's stack). */
grpc_credentials_get_request_metadata(channel_creds, grpc_credentials_get_request_metadata(channel_creds, service_url,
on_credentials_metadata, elem); on_credentials_metadata, elem);
gpr_free(service_url);
} else { } else {
grpc_call_next_op(elem, op); grpc_call_next_op(elem, op);
} }
@ -146,6 +171,9 @@ static void call_op(grpc_call_element *elem, grpc_call_element *from_elem,
if (op->data.metadata->key == channeld->authority_string) { if (op->data.metadata->key == channeld->authority_string) {
if (calld->host != NULL) grpc_mdstr_unref(calld->host); if (calld->host != NULL) grpc_mdstr_unref(calld->host);
calld->host = grpc_mdstr_ref(op->data.metadata->value); calld->host = grpc_mdstr_ref(op->data.metadata->value);
} else if (op->data.metadata->key == channeld->path_string) {
if (calld->method != NULL) grpc_mdstr_unref(calld->method);
calld->method = grpc_mdstr_ref(op->data.metadata->value);
} }
grpc_call_next_op(elem, op); grpc_call_next_op(elem, op);
break; break;
@ -194,6 +222,7 @@ static void init_call_elem(grpc_call_element *elem,
call_data *calld = elem->call_data; call_data *calld = elem->call_data;
calld->creds = NULL; calld->creds = NULL;
calld->host = NULL; calld->host = NULL;
calld->method = NULL;
} }
/* Destructor for call_data */ /* Destructor for call_data */
@ -230,6 +259,7 @@ static void init_channel_elem(grpc_channel_element *elem,
channeld->md_ctx = metadata_context; channeld->md_ctx = metadata_context;
channeld->authority_string = channeld->authority_string =
grpc_mdstr_from_string(channeld->md_ctx, ":authority"); grpc_mdstr_from_string(channeld->md_ctx, ":authority");
channeld->path_string = grpc_mdstr_from_string(channeld->md_ctx, ":path");
channeld->error_msg_key = channeld->error_msg_key =
grpc_mdstr_from_string(channeld->md_ctx, "grpc-message"); grpc_mdstr_from_string(channeld->md_ctx, "grpc-message");
} }

@ -33,6 +33,10 @@
#include "src/core/security/credentials.h" #include "src/core/security/credentials.h"
#include <string.h>
#include <stdio.h>
#include "src/core/json/json.h"
#include "src/core/httpcli/httpcli.h" #include "src/core/httpcli/httpcli.h"
#include "src/core/iomgr/iomgr.h" #include "src/core/iomgr/iomgr.h"
#include "src/core/security/json_token.h" #include "src/core/security/json_token.h"
@ -42,14 +46,9 @@
#include <grpc/support/sync.h> #include <grpc/support/sync.h>
#include <grpc/support/time.h> #include <grpc/support/time.h>
#include "src/core/json/json.h"
#include <string.h>
#include <stdio.h>
/* -- Constants. -- */ /* -- Constants. -- */
#define GRPC_OAUTH2_TOKEN_REFRESH_THRESHOLD_SECS 60 #define GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS 60
#define GRPC_COMPUTE_ENGINE_METADATA_HOST "metadata" #define GRPC_COMPUTE_ENGINE_METADATA_HOST "metadata"
#define GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH \ #define GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH \
@ -113,6 +112,7 @@ int grpc_credentials_has_request_metadata_only(grpc_credentials *creds) {
} }
void grpc_credentials_get_request_metadata(grpc_credentials *creds, void grpc_credentials_get_request_metadata(grpc_credentials *creds,
const char *service_url,
grpc_credentials_metadata_cb cb, grpc_credentials_metadata_cb cb,
void *user_data) { void *user_data) {
if (creds == NULL || !grpc_credentials_has_request_metadata(creds) || if (creds == NULL || !grpc_credentials_has_request_metadata(creds) ||
@ -122,7 +122,7 @@ void grpc_credentials_get_request_metadata(grpc_credentials *creds,
} }
return; return;
} }
creds->vtable->get_request_metadata(creds, cb, user_data); creds->vtable->get_request_metadata(creds, service_url, cb, user_data);
} }
void grpc_server_credentials_release(grpc_server_credentials *creds) { void grpc_server_credentials_release(grpc_server_credentials *creds) {
@ -288,6 +288,128 @@ grpc_server_credentials *grpc_ssl_server_credentials_create(
return &c->base; return &c->base;
} }
/* -- Jwt credentials -- */
typedef struct {
grpc_credentials base;
grpc_mdctx *md_ctx;
/* 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. */
gpr_mu cache_mu;
struct {
grpc_mdelem *jwt_md;
char *service_url;
gpr_timespec jwt_expiration;
} cached;
grpc_auth_json_key key;
gpr_timespec jwt_lifetime;
} grpc_jwt_credentials;
static void jwt_reset_cache(grpc_jwt_credentials *c) {
if (c->cached.jwt_md != NULL) {
grpc_mdelem_unref(c->cached.jwt_md);
c->cached.jwt_md = NULL;
}
if (c->cached.service_url != NULL) {
gpr_free(c->cached.service_url);
c->cached.service_url = NULL;
}
c->cached.jwt_expiration = gpr_inf_past;
}
static void jwt_destroy(grpc_credentials *creds) {
grpc_jwt_credentials *c = (grpc_jwt_credentials *)creds;
grpc_auth_json_key_destruct(&c->key);
jwt_reset_cache(c);
gpr_mu_destroy(&c->cache_mu);
grpc_mdctx_unref(c->md_ctx);
gpr_free(c);
}
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_credentials *creds,
const char *service_url,
grpc_credentials_metadata_cb cb,
void *user_data) {
grpc_jwt_credentials *c = (grpc_jwt_credentials *)creds;
gpr_timespec refresh_threshold = {GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS,
0};
/* See if we can return a cached jwt. */
grpc_mdelem *jwt_md = NULL;
{
gpr_mu_lock(&c->cache_mu);
if (c->cached.service_url != NULL &&
!strcmp(c->cached.service_url, service_url) &&
c->cached.jwt_md != NULL &&
(gpr_time_cmp(gpr_time_sub(c->cached.jwt_expiration, gpr_now()),
refresh_threshold) > 0)) {
jwt_md = grpc_mdelem_ref(c->cached.jwt_md);
}
gpr_mu_unlock(&c->cache_mu);
}
if (jwt_md == NULL) {
char *jwt = NULL;
/* Generate a new jwt. */
gpr_mu_lock(&c->cache_mu);
jwt_reset_cache(c);
jwt = grpc_jwt_encode_and_sign(&c->key, service_url, c->jwt_lifetime, NULL);
if (jwt != NULL) {
char *md_value;
gpr_asprintf(&md_value, "Bearer %s", jwt);
gpr_free(jwt);
c->cached.jwt_expiration = gpr_time_add(gpr_now(), c->jwt_lifetime);
c->cached.service_url = gpr_strdup(service_url);
c->cached.jwt_md = grpc_mdelem_from_strings(
c->md_ctx, GRPC_AUTHORIZATION_METADATA_KEY, md_value);
gpr_free(md_value);
jwt_md = grpc_mdelem_ref(c->cached.jwt_md);
}
gpr_mu_unlock(&c->cache_mu);
}
if (jwt_md != NULL) {
cb(user_data, &jwt_md, 1, GRPC_CREDENTIALS_OK);
grpc_mdelem_unref(jwt_md);
} else {
cb(user_data, NULL, 0, GRPC_CREDENTIALS_ERROR);
}
}
static grpc_credentials_vtable jwt_vtable = {
jwt_destroy, jwt_has_request_metadata, jwt_has_request_metadata_only,
jwt_get_request_metadata};
grpc_credentials *grpc_jwt_credentials_create(const char *json_key,
gpr_timespec token_lifetime) {
grpc_jwt_credentials *c;
grpc_auth_json_key key = grpc_auth_json_key_create_from_string(json_key);
if (!grpc_auth_json_key_is_valid(&key)) {
gpr_log(GPR_ERROR, "Invalid input for jwt credentials creation");
return NULL;
}
c = gpr_malloc(sizeof(grpc_jwt_credentials));
memset(c, 0, sizeof(grpc_jwt_credentials));
c->base.type = GRPC_CREDENTIALS_TYPE_JWT;
gpr_ref_init(&c->base.refcount, 1);
c->base.vtable = &jwt_vtable;
c->md_ctx = grpc_mdctx_create();
c->key = key;
c->jwt_lifetime = token_lifetime;
gpr_mu_init(&c->cache_mu);
jwt_reset_cache(c);
return &c->base;
}
/* -- Oauth2TokenFetcher credentials -- */ /* -- Oauth2TokenFetcher credentials -- */
/* This object is a base for credentials that need to acquire an oauth2 token /* This object is a base for credentials that need to acquire an oauth2 token
@ -439,10 +561,11 @@ static void on_oauth2_token_fetcher_http_response(
} }
static void oauth2_token_fetcher_get_request_metadata( static void oauth2_token_fetcher_get_request_metadata(
grpc_credentials *creds, grpc_credentials_metadata_cb cb, void *user_data) { grpc_credentials *creds, const char *service_url,
grpc_credentials_metadata_cb cb, void *user_data) {
grpc_oauth2_token_fetcher_credentials *c = grpc_oauth2_token_fetcher_credentials *c =
(grpc_oauth2_token_fetcher_credentials *)creds; (grpc_oauth2_token_fetcher_credentials *)creds;
gpr_timespec refresh_threshold = {GRPC_OAUTH2_TOKEN_REFRESH_THRESHOLD_SECS, gpr_timespec refresh_threshold = {GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS,
0}; 0};
grpc_mdelem *cached_access_token_md = NULL; grpc_mdelem *cached_access_token_md = NULL;
{ {
@ -535,7 +658,8 @@ static void service_account_fetch_oauth2(
"application/x-www-form-urlencoded"}; "application/x-www-form-urlencoded"};
grpc_httpcli_request request; grpc_httpcli_request request;
char *body = NULL; char *body = NULL;
char *jwt = grpc_jwt_encode_and_sign(&c->key, c->scope, c->token_lifetime); char *jwt = grpc_jwt_encode_and_sign(&c->key, GRPC_JWT_OAUTH2_AUDIENCE,
c->token_lifetime, c->scope);
if (jwt == NULL) { if (jwt == NULL) {
grpc_httpcli_response response; grpc_httpcli_response response;
memset(&response, 0, sizeof(grpc_httpcli_response)); memset(&response, 0, sizeof(grpc_httpcli_response));
@ -616,6 +740,7 @@ void on_simulated_token_fetch_done(void *user_data, int success) {
} }
static void fake_oauth2_get_request_metadata(grpc_credentials *creds, static void fake_oauth2_get_request_metadata(grpc_credentials *creds,
const char *service_url,
grpc_credentials_metadata_cb cb, grpc_credentials_metadata_cb cb,
void *user_data) { void *user_data) {
grpc_fake_oauth2_credentials *c = (grpc_fake_oauth2_credentials *)creds; grpc_fake_oauth2_credentials *c = (grpc_fake_oauth2_credentials *)creds;
@ -709,6 +834,7 @@ typedef struct {
size_t creds_index; size_t creds_index;
grpc_mdelem **md_elems; grpc_mdelem **md_elems;
size_t num_md; size_t num_md;
char *service_url;
void *user_data; void *user_data;
grpc_credentials_metadata_cb cb; grpc_credentials_metadata_cb cb;
} grpc_composite_credentials_metadata_context; } grpc_composite_credentials_metadata_context;
@ -754,6 +880,7 @@ static void composite_md_context_destroy(
grpc_mdelem_unref(ctx->md_elems[i]); grpc_mdelem_unref(ctx->md_elems[i]);
} }
gpr_free(ctx->md_elems); gpr_free(ctx->md_elems);
if (ctx->service_url != NULL) gpr_free(ctx->service_url);
gpr_free(ctx); gpr_free(ctx);
} }
@ -783,8 +910,8 @@ static void composite_metadata_cb(void *user_data, grpc_mdelem **md_elems,
grpc_credentials *inner_creds = grpc_credentials *inner_creds =
ctx->composite_creds->inner.creds_array[ctx->creds_index++]; ctx->composite_creds->inner.creds_array[ctx->creds_index++];
if (grpc_credentials_has_request_metadata(inner_creds)) { if (grpc_credentials_has_request_metadata(inner_creds)) {
grpc_credentials_get_request_metadata(inner_creds, composite_metadata_cb, grpc_credentials_get_request_metadata(inner_creds, ctx->service_url,
ctx); composite_metadata_cb, ctx);
return; return;
} }
} }
@ -795,6 +922,7 @@ static void composite_metadata_cb(void *user_data, grpc_mdelem **md_elems,
} }
static void composite_get_request_metadata(grpc_credentials *creds, static void composite_get_request_metadata(grpc_credentials *creds,
const char *service_url,
grpc_credentials_metadata_cb cb, grpc_credentials_metadata_cb cb,
void *user_data) { void *user_data) {
grpc_composite_credentials *c = (grpc_composite_credentials *)creds; grpc_composite_credentials *c = (grpc_composite_credentials *)creds;
@ -805,14 +933,15 @@ static void composite_get_request_metadata(grpc_credentials *creds,
} }
ctx = gpr_malloc(sizeof(grpc_composite_credentials_metadata_context)); ctx = gpr_malloc(sizeof(grpc_composite_credentials_metadata_context));
memset(ctx, 0, sizeof(grpc_composite_credentials_metadata_context)); memset(ctx, 0, sizeof(grpc_composite_credentials_metadata_context));
ctx->service_url = gpr_strdup(service_url);
ctx->user_data = user_data; ctx->user_data = user_data;
ctx->cb = cb; ctx->cb = cb;
ctx->composite_creds = c; ctx->composite_creds = c;
while (ctx->creds_index < c->inner.num_creds) { while (ctx->creds_index < c->inner.num_creds) {
grpc_credentials *inner_creds = c->inner.creds_array[ctx->creds_index++]; grpc_credentials *inner_creds = c->inner.creds_array[ctx->creds_index++];
if (grpc_credentials_has_request_metadata(inner_creds)) { if (grpc_credentials_has_request_metadata(inner_creds)) {
grpc_credentials_get_request_metadata(inner_creds, composite_metadata_cb, grpc_credentials_get_request_metadata(inner_creds, service_url,
ctx); composite_metadata_cb, ctx);
return; return;
} }
} }
@ -916,6 +1045,7 @@ static int iam_has_request_metadata_only(const grpc_credentials *creds) {
} }
static void iam_get_request_metadata(grpc_credentials *creds, static void iam_get_request_metadata(grpc_credentials *creds,
const char *service_url,
grpc_credentials_metadata_cb cb, grpc_credentials_metadata_cb cb,
void *user_data) { void *user_data) {
grpc_iam_credentials *c = (grpc_iam_credentials *)creds; grpc_iam_credentials *c = (grpc_iam_credentials *)creds;

@ -50,6 +50,7 @@ typedef enum {
#define GRPC_CREDENTIALS_TYPE_SSL "Ssl" #define GRPC_CREDENTIALS_TYPE_SSL "Ssl"
#define GRPC_CREDENTIALS_TYPE_OAUTH2 "Oauth2" #define GRPC_CREDENTIALS_TYPE_OAUTH2 "Oauth2"
#define GRPC_CREDENTIALS_TYPE_JWT "Jwt"
#define GRPC_CREDENTIALS_TYPE_IAM "Iam" #define GRPC_CREDENTIALS_TYPE_IAM "Iam"
#define GRPC_CREDENTIALS_TYPE_COMPOSITE "Composite" #define GRPC_CREDENTIALS_TYPE_COMPOSITE "Composite"
#define GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY "FakeTransportSecurity" #define GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY "FakeTransportSecurity"
@ -71,6 +72,7 @@ typedef struct {
int (*has_request_metadata)(const grpc_credentials *c); int (*has_request_metadata)(const grpc_credentials *c);
int (*has_request_metadata_only)(const grpc_credentials *c); int (*has_request_metadata_only)(const grpc_credentials *c);
void (*get_request_metadata)(grpc_credentials *c, void (*get_request_metadata)(grpc_credentials *c,
const char *service_url,
grpc_credentials_metadata_cb cb, grpc_credentials_metadata_cb cb,
void *user_data); void *user_data);
} grpc_credentials_vtable; } grpc_credentials_vtable;
@ -86,6 +88,7 @@ void grpc_credentials_unref(grpc_credentials *creds);
int grpc_credentials_has_request_metadata(grpc_credentials *creds); int grpc_credentials_has_request_metadata(grpc_credentials *creds);
int grpc_credentials_has_request_metadata_only(grpc_credentials *creds); int grpc_credentials_has_request_metadata_only(grpc_credentials *creds);
void grpc_credentials_get_request_metadata(grpc_credentials *creds, void grpc_credentials_get_request_metadata(grpc_credentials *creds,
const char *service_url,
grpc_credentials_metadata_cb cb, grpc_credentials_metadata_cb cb,
void *user_data); void *user_data);
typedef struct { typedef struct {

@ -55,7 +55,6 @@ const gpr_timespec grpc_max_auth_token_lifetime = {3600, 0};
#define GRPC_AUTH_JSON_KEY_TYPE_INVALID "invalid" #define GRPC_AUTH_JSON_KEY_TYPE_INVALID "invalid"
#define GRPC_AUTH_JSON_KEY_TYPE_SERVICE_ACCOUNT "service_account" #define GRPC_AUTH_JSON_KEY_TYPE_SERVICE_ACCOUNT "service_account"
#define GRPC_JWT_AUDIENCE "https://www.googleapis.com/oauth2/v3/token"
#define GRPC_JWT_RSA_SHA256_ALGORITHM "RS256" #define GRPC_JWT_RSA_SHA256_ALGORITHM "RS256"
#define GRPC_JWT_TYPE "JWT" #define GRPC_JWT_TYPE "JWT"
@ -171,8 +170,8 @@ void grpc_auth_json_key_destruct(grpc_auth_json_key *json_key) {
/* --- jwt encoding and signature. --- */ /* --- jwt encoding and signature. --- */
static grpc_json *create_child(grpc_json *brother, grpc_json *parent, static grpc_json *create_child(grpc_json *brother, grpc_json *parent,
const char *key, const char *value, const char *key, const char *value,
grpc_json_type type) { grpc_json_type type) {
grpc_json *child = grpc_json_create(type); grpc_json *child = grpc_json_create(type);
if (brother) brother->next = child; if (brother) brother->next = child;
if (!parent->child) parent->child = child; if (!parent->child) parent->child = child;
@ -182,14 +181,15 @@ static grpc_json *create_child(grpc_json *brother, grpc_json *parent,
return child; return child;
} }
static char *encoded_jwt_header(const char *algorithm) { static char *encoded_jwt_header(const char *key_id, const char *algorithm) {
grpc_json *json = grpc_json_create(GRPC_JSON_OBJECT); grpc_json *json = grpc_json_create(GRPC_JSON_OBJECT);
grpc_json *child = NULL; grpc_json *child = NULL;
char *json_str = NULL; char *json_str = NULL;
char *result = NULL; char *result = NULL;
child = create_child(NULL, json, "alg", algorithm, GRPC_JSON_STRING); child = create_child(NULL, json, "alg", algorithm, GRPC_JSON_STRING);
create_child(child, json, "typ", GRPC_JWT_TYPE, GRPC_JSON_STRING); child = create_child(child, json, "typ", GRPC_JWT_TYPE, GRPC_JSON_STRING);
create_child(child, json, "kid", key_id, GRPC_JSON_STRING);
json_str = grpc_json_dump_to_string(json, 0); json_str = grpc_json_dump_to_string(json, 0);
result = grpc_base64_encode(json_str, strlen(json_str), 1, 0); result = grpc_base64_encode(json_str, strlen(json_str), 1, 0);
@ -199,7 +199,8 @@ static char *encoded_jwt_header(const char *algorithm) {
} }
static char *encoded_jwt_claim(const grpc_auth_json_key *json_key, static char *encoded_jwt_claim(const grpc_auth_json_key *json_key,
const char *scope, gpr_timespec token_lifetime) { const char *audience,
gpr_timespec token_lifetime, const char *scope) {
grpc_json *json = grpc_json_create(GRPC_JSON_OBJECT); grpc_json *json = grpc_json_create(GRPC_JSON_OBJECT);
grpc_json *child = NULL; grpc_json *child = NULL;
char *json_str = NULL; char *json_str = NULL;
@ -217,8 +218,15 @@ static char *encoded_jwt_claim(const grpc_auth_json_key *json_key,
child = create_child(NULL, json, "iss", json_key->client_email, child = create_child(NULL, json, "iss", json_key->client_email,
GRPC_JSON_STRING); GRPC_JSON_STRING);
child = create_child(child, json, "scope", scope, GRPC_JSON_STRING); if (scope != NULL) {
child = create_child(child, json, "aud", GRPC_JWT_AUDIENCE, GRPC_JSON_STRING); child = create_child(child, json, "scope", scope, GRPC_JSON_STRING);
} else {
/* Unscoped JWTs need a sub field. */
child = create_child(child, json, "sub", json_key->client_email,
GRPC_JSON_STRING);
}
child = create_child(child, json, "aud", audience, GRPC_JSON_STRING);
child = create_child(child, json, "iat", now_str, GRPC_JSON_NUMBER); child = create_child(child, json, "iat", now_str, GRPC_JSON_NUMBER);
create_child(child, json, "exp", expiration_str, GRPC_JSON_NUMBER); create_child(child, json, "exp", expiration_str, GRPC_JSON_NUMBER);
@ -300,14 +308,16 @@ end:
} }
char *grpc_jwt_encode_and_sign(const grpc_auth_json_key *json_key, char *grpc_jwt_encode_and_sign(const grpc_auth_json_key *json_key,
const char *scope, gpr_timespec token_lifetime) { const char *audience,
gpr_timespec token_lifetime, const char *scope) {
if (g_jwt_encode_and_sign_override != NULL) { if (g_jwt_encode_and_sign_override != NULL) {
return g_jwt_encode_and_sign_override(json_key, scope, token_lifetime); return g_jwt_encode_and_sign_override(json_key, audience, token_lifetime,
scope);
} else { } else {
const char *sig_algo = GRPC_JWT_RSA_SHA256_ALGORITHM; const char *sig_algo = GRPC_JWT_RSA_SHA256_ALGORITHM;
char *to_sign = dot_concat_and_free_strings( char *to_sign = dot_concat_and_free_strings(
encoded_jwt_header(sig_algo), encoded_jwt_header(json_key->private_key_id, sig_algo),
encoded_jwt_claim(json_key, scope, token_lifetime)); encoded_jwt_claim(json_key, audience, token_lifetime, scope));
char *sig = compute_and_encode_signature(json_key, sig_algo, to_sign); char *sig = compute_and_encode_signature(json_key, sig_algo, to_sign);
if (sig == NULL) { if (sig == NULL) {
gpr_free(to_sign); gpr_free(to_sign);

@ -37,6 +37,10 @@
#include <grpc/support/slice.h> #include <grpc/support/slice.h>
#include <openssl/rsa.h> #include <openssl/rsa.h>
/* --- Constants. --- */
#define GRPC_JWT_OAUTH2_AUDIENCE "https://www.googleapis.com/oauth2/v3/token"
/* --- auth_json_key parsing. --- */ /* --- auth_json_key parsing. --- */
typedef struct { typedef struct {
@ -61,14 +65,15 @@ void grpc_auth_json_key_destruct(grpc_auth_json_key *json_key);
/* --- json token encoding and signing. --- */ /* --- json token encoding and signing. --- */
/* Caller is responsible for calling gpr_free on the returned value. May return /* Caller is responsible for calling gpr_free on the returned value. May return
NULL on invalid input. */ NULL on invalid input. The scope parameter may be NULL. */
char *grpc_jwt_encode_and_sign(const grpc_auth_json_key *json_key, char *grpc_jwt_encode_and_sign(const grpc_auth_json_key *json_key,
const char *scope, gpr_timespec token_lifetime); const char *audience,
gpr_timespec token_lifetime, const char *scope);
/* Override encode_and_sign function for testing. */ /* Override encode_and_sign function for testing. */
typedef char *(*grpc_jwt_encode_and_sign_override)( typedef char *(*grpc_jwt_encode_and_sign_override)(
const grpc_auth_json_key *json_key, const char *scope, const grpc_auth_json_key *json_key, const char *audience,
gpr_timespec token_lifetime); gpr_timespec token_lifetime, const char *scope);
/* Set a custom encode_and_sign override for testing. */ /* Set a custom encode_and_sign override for testing. */
void grpc_jwt_encode_and_sign_set_override( void grpc_jwt_encode_and_sign_set_override(

@ -238,6 +238,7 @@ grpc_channel_security_context *grpc_fake_channel_security_context_create(
gpr_malloc(sizeof(grpc_fake_channel_security_context)); gpr_malloc(sizeof(grpc_fake_channel_security_context));
gpr_ref_init(&c->base.base.refcount, 1); gpr_ref_init(&c->base.base.refcount, 1);
c->base.base.is_client_side = 1; c->base.base.is_client_side = 1;
c->base.base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
c->base.base.vtable = &fake_channel_vtable; c->base.base.vtable = &fake_channel_vtable;
GPR_ASSERT(check_request_metadata_creds(request_metadata_creds)); 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_credentials_ref(request_metadata_creds);
@ -250,6 +251,7 @@ grpc_security_context *grpc_fake_server_security_context_create(void) {
grpc_security_context *c = gpr_malloc(sizeof(grpc_security_context)); grpc_security_context *c = gpr_malloc(sizeof(grpc_security_context));
gpr_ref_init(&c->refcount, 1); gpr_ref_init(&c->refcount, 1);
c->vtable = &fake_server_vtable; c->vtable = &fake_server_vtable;
c->url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
return c; return c;
} }
@ -458,6 +460,7 @@ grpc_security_status grpc_ssl_channel_security_context_create(
gpr_ref_init(&c->base.base.refcount, 1); gpr_ref_init(&c->base.base.refcount, 1);
c->base.base.vtable = &ssl_channel_vtable; c->base.base.vtable = &ssl_channel_vtable;
c->base.base.is_client_side = 1; 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_credentials_ref(request_metadata_creds);
c->base.check_call_host = ssl_channel_check_call_host; c->base.check_call_host = ssl_channel_check_call_host;
if (target_name != NULL) { if (target_name != NULL) {
@ -525,6 +528,7 @@ grpc_security_status grpc_ssl_server_security_context_create(
memset(c, 0, sizeof(grpc_ssl_server_security_context)); memset(c, 0, sizeof(grpc_ssl_server_security_context));
gpr_ref_init(&c->base.refcount, 1); gpr_ref_init(&c->base.refcount, 1);
c->base.url_scheme = GRPC_SSL_URL_SCHEME;
c->base.vtable = &ssl_server_vtable; c->base.vtable = &ssl_server_vtable;
result = tsi_create_ssl_server_handshaker_factory( result = tsi_create_ssl_server_handshaker_factory(
(const unsigned char **)config->pem_private_keys, (const unsigned char **)config->pem_private_keys,

@ -47,6 +47,11 @@ typedef enum {
GRPC_SECURITY_ERROR GRPC_SECURITY_ERROR
} grpc_security_status; } grpc_security_status;
/* --- URL schemes. --- */
#define GRPC_SSL_URL_SCHEME "https"
#define GRPC_FAKE_SECURITY_URL_SCHEME "http+fake_security"
/* --- security_context object. --- /* --- security_context object. ---
A security context object represents away to configure the underlying A security context object represents away to configure the underlying
@ -72,6 +77,7 @@ struct grpc_security_context {
const grpc_security_context_vtable *vtable; const grpc_security_context_vtable *vtable;
gpr_refcount refcount; gpr_refcount refcount;
int is_client_side; int is_client_side;
const char *url_scheme;
}; };
/* Increments the refcount. */ /* Increments the refcount. */

@ -35,8 +35,6 @@
#ifdef GPR_WIN32 #ifdef GPR_WIN32
#include "src/core/support/cpu.h"
#include <grpc/support/log.h> #include <grpc/support/log.h>
unsigned gpr_cpu_num_cores(void) { unsigned gpr_cpu_num_cores(void) {

@ -36,6 +36,7 @@
#include <string.h> #include <string.h>
#include "src/core/support/string.h" #include "src/core/support/string.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h> #include <grpc/support/log.h>
int gpr_join_host_port(char **out, const char *host, int port) { int gpr_join_host_port(char **out, const char *host, int port) {
@ -47,3 +48,60 @@ int gpr_join_host_port(char **out, const char *host, int port) {
return gpr_asprintf(out, "%s:%d", host, port); return gpr_asprintf(out, "%s:%d", host, port);
} }
} }
void gpr_split_host_port(const char *name, char **host, char **port) {
const char *host_start;
size_t host_len;
const char *port_start;
*host = NULL;
*port = NULL;
if (name[0] == '[') {
/* Parse a bracketed host, typically an IPv6 literal. */
const char *rbracket = strchr(name, ']');
if (rbracket == NULL) {
/* Unmatched [ */
return;
}
if (rbracket[1] == '\0') {
/* ]<end> */
port_start = NULL;
} else if (rbracket[1] == ':') {
/* ]:<port?> */
port_start = rbracket + 2;
} else {
/* ]<invalid> */
return;
}
host_start = name + 1;
host_len = rbracket - host_start;
if (memchr(host_start, ':', host_len) == NULL) {
/* Require all bracketed hosts to contain a colon, because a hostname or
IPv4 address should never use brackets. */
return;
}
} else {
const char *colon = strchr(name, ':');
if (colon != NULL && strchr(colon + 1, ':') == NULL) {
/* Exactly 1 colon. Split into host:port. */
host_start = name;
host_len = colon - name;
port_start = colon + 1;
} else {
/* 0 or 2+ colons. Bare hostname or IPv6 litearal. */
host_start = name;
host_len = strlen(name);
port_start = NULL;
}
}
/* Allocate return values. */
*host = gpr_malloc(host_len + 1);
memcpy(*host, host_start, host_len);
(*host)[host_len] = '\0';
if (port_start != NULL) {
*port = gpr_strdup(port_start);
}
}

@ -40,7 +40,7 @@ static gpr_once g_init = GPR_ONCE_INIT;
static gpr_mu g_init_mu; static gpr_mu g_init_mu;
static int g_initializations; static int g_initializations;
static void do_init() { static void do_init(void) {
gpr_mu_init(&g_init_mu); gpr_mu_init(&g_init_mu);
g_initializations = 0; g_initializations = 0;
} }

@ -291,7 +291,7 @@ static void orphan_channel(channel_data *chand) {
static void finish_destroy_channel(void *cd, int success) { static void finish_destroy_channel(void *cd, int success) {
channel_data *chand = cd; channel_data *chand = cd;
grpc_server *server = chand->server; grpc_server *server = chand->server;
grpc_channel_destroy(chand->channel); grpc_channel_internal_unref(chand->channel);
server_unref(server); server_unref(server);
} }

@ -191,6 +191,7 @@ struct transport {
gpr_uint8 writing; gpr_uint8 writing;
gpr_uint8 calling_back; gpr_uint8 calling_back;
gpr_uint8 destroying; gpr_uint8 destroying;
gpr_uint8 closed;
error_state error_state; error_state error_state;
/* stream indexing */ /* stream indexing */
@ -416,6 +417,7 @@ static void init_transport(transport *t, grpc_transport_setup_callback setup,
t->next_stream_id = is_client ? 1 : 2; t->next_stream_id = is_client ? 1 : 2;
t->last_incoming_stream_id = 0; t->last_incoming_stream_id = 0;
t->destroying = 0; t->destroying = 0;
t->closed = 0;
t->is_client = is_client; t->is_client = is_client;
t->outgoing_window = DEFAULT_WINDOW; t->outgoing_window = DEFAULT_WINDOW;
t->incoming_window = DEFAULT_WINDOW; t->incoming_window = DEFAULT_WINDOW;
@ -521,6 +523,8 @@ static void destroy_transport(grpc_transport *gt) {
static void close_transport(grpc_transport *gt) { static void close_transport(grpc_transport *gt) {
transport *t = (transport *)gt; transport *t = (transport *)gt;
gpr_mu_lock(&t->mu); gpr_mu_lock(&t->mu);
GPR_ASSERT(!t->closed);
t->closed = 1;
if (t->ep) { if (t->ep) {
grpc_endpoint_shutdown(t->ep); grpc_endpoint_shutdown(t->ep);
} }

@ -251,6 +251,7 @@ OPENSSL_ALPN_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o /dev/null test/build/ope
ZLIB_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o /dev/null test/build/zlib.c -lz $(LDFLAGS) ZLIB_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o /dev/null test/build/zlib.c -lz $(LDFLAGS)
PERFTOOLS_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o /dev/null test/build/perftools.c -lprofiler $(LDFLAGS) PERFTOOLS_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o /dev/null test/build/perftools.c -lprofiler $(LDFLAGS)
PROTOBUF_CHECK_CMD = $(CXX) $(CXXFLAGS) $(CPPFLAGS) -o /dev/null test/build/protobuf.cc -lprotobuf $(LDFLAGS) PROTOBUF_CHECK_CMD = $(CXX) $(CXXFLAGS) $(CPPFLAGS) -o /dev/null test/build/protobuf.cc -lprotobuf $(LDFLAGS)
PROTOC_CMD = which protoc
PROTOC_CHECK_CMD = protoc --version | grep -q libprotoc.3 PROTOC_CHECK_CMD = protoc --version | grep -q libprotoc.3
ifndef REQUIRE_CUSTOM_LIBRARIES_$(CONFIG) ifndef REQUIRE_CUSTOM_LIBRARIES_$(CONFIG)
@ -261,10 +262,11 @@ LIBS += profiler
endif endif
endif endif
HAS_SYSTEM_PROTOBUF_VERIFY = $(shell $(PROTOBUF_CHECK_CMD) 2> /dev/null && echo true || echo false)
ifndef REQUIRE_CUSTOM_LIBRARIES_$(CONFIG) ifndef REQUIRE_CUSTOM_LIBRARIES_$(CONFIG)
HAS_SYSTEM_OPENSSL_ALPN = $(shell $(OPENSSL_ALPN_CHECK_CMD) 2> /dev/null && echo true || echo false) HAS_SYSTEM_OPENSSL_ALPN = $(shell $(OPENSSL_ALPN_CHECK_CMD) 2> /dev/null && echo true || echo false)
HAS_SYSTEM_ZLIB = $(shell $(ZLIB_CHECK_CMD) 2> /dev/null && echo true || echo false) HAS_SYSTEM_ZLIB = $(shell $(ZLIB_CHECK_CMD) 2> /dev/null && echo true || echo false)
HAS_SYSTEM_PROTOBUF = $(shell $(PROTOBUF_CHECK_CMD) 2> /dev/null && echo true || echo false) HAS_SYSTEM_PROTOBUF = $(HAS_SYSTEM_PROTOBUF_VERIFY)
else else
# override system libraries if the config requires a custom compiled library # override system libraries if the config requires a custom compiled library
HAS_SYSTEM_OPENSSL_ALPN = false HAS_SYSTEM_OPENSSL_ALPN = false
@ -272,7 +274,12 @@ HAS_SYSTEM_ZLIB = false
HAS_SYSTEM_PROTOBUF = false HAS_SYSTEM_PROTOBUF = false
endif endif
HAS_PROTOC = $(shell $(PROTOC_CMD) && echo true || echo false)
ifeq ($(HAS_PROTOC),true)
HAS_VALID_PROTOC = $(shell $(PROTOC_CHECK_CMD) 2> /dev/null && echo true || echo false) HAS_VALID_PROTOC = $(shell $(PROTOC_CHECK_CMD) 2> /dev/null && echo true || echo false)
else
HAS_VALID_PROTOC = false
endif
ifeq ($(wildcard third_party/openssl/ssl/ssl.h),) ifeq ($(wildcard third_party/openssl/ssl/ssl.h),)
HAS_EMBEDDED_OPENSSL_ALPN = false HAS_EMBEDDED_OPENSSL_ALPN = false
@ -325,8 +332,8 @@ LDLIBS_SECURE += $(addprefix -l, $(LIBS_SECURE))
ifeq ($(HAS_SYSTEM_PROTOBUF),false) ifeq ($(HAS_SYSTEM_PROTOBUF),false)
ifeq ($(HAS_EMBEDDED_PROTOBUF),true) ifeq ($(HAS_EMBEDDED_PROTOBUF),true)
PROTOBUF_DEP = $(LIBDIR)/$(CONFIG)/protobuf/libprotobuf.a PROTOBUF_DEP = $(LIBDIR)/$(CONFIG)/protobuf/libprotobuf.a
CPPFLAGS += -Ithird_party/protobuf/src CPPFLAGS := -Ithird_party/protobuf/src $(CPPFLAGS)
LDFLAGS += -L$(LIBDIR)/$(CONFIG)/protobuf LDFLAGS := -L$(LIBDIR)/$(CONFIG)/protobuf $(LDFLAGS)
PROTOC = $(BINDIR)/$(CONFIG)/protobuf/protoc PROTOC = $(BINDIR)/$(CONFIG)/protobuf/protoc
else else
NO_PROTOBUF = true NO_PROTOBUF = true
@ -344,6 +351,13 @@ ifeq ($(MAKECMDGOALS),clean)
NO_DEPS = true NO_DEPS = true
endif endif
INSTALL_OK = false
ifeq ($(HAS_VALID_PROTOC),true)
ifeq ($(HAS_SYSTEM_PROTOBUF_VERIFY),true)
INSTALL_OK = true
endif
endif
.SECONDARY = %.pb.h %.pb.cc .SECONDARY = %.pb.h %.pb.cc
PROTOC_PLUGINS =\ PROTOC_PLUGINS =\
@ -481,7 +495,7 @@ third_party/protobuf/configure:
$(LIBDIR)/$(CONFIG)/protobuf/libprotobuf.a: third_party/protobuf/configure $(LIBDIR)/$(CONFIG)/protobuf/libprotobuf.a: third_party/protobuf/configure
$(E) "[MAKE] Building protobuf" $(E) "[MAKE] Building protobuf"
$(Q)(cd third_party/protobuf ; CC="$(CC)" CPPFLAGS="-fPIC" CXX="$(CXX)" LDFLAGS="$(LDFLAGS_$(CONFIG)) -g" CXXFLAGS="-DLANG_CXX11 -std=c++11" CPPFLAGS="$(CPPFLAGS_$(CONFIG)) -g" ./configure --disable-shared --enable-static) $(Q)(cd third_party/protobuf ; CC="$(CC)" CXX="$(CXX)" LDFLAGS="$(LDFLAGS_$(CONFIG)) -g" CXXFLAGS="-DLANG_CXX11 -std=c++11" CPPFLAGS="-fPIC $(CPPFLAGS_$(CONFIG)) -g" ./configure --disable-shared --enable-static)
$(Q)$(MAKE) -C third_party/protobuf clean $(Q)$(MAKE) -C third_party/protobuf clean
$(Q)$(MAKE) -C third_party/protobuf $(Q)$(MAKE) -C third_party/protobuf
$(Q)mkdir -p $(LIBDIR)/$(CONFIG)/protobuf $(Q)mkdir -p $(LIBDIR)/$(CONFIG)/protobuf
@ -715,7 +729,7 @@ $(OBJDIR)/$(CONFIG)/%.o : %.cc
$(Q) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -MMD -MF $(addsuffix .dep, $(basename $@)) -c -o $@ $< $(Q) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -MMD -MF $(addsuffix .dep, $(basename $@)) -c -o $@ $<
install: install_c install_cxx install-plugins install: install_c install_cxx install-plugins verify-install
install_c: install-headers_c install-static_c install-shared_c install_c: install-headers_c install-static_c install-shared_c
@ -810,6 +824,25 @@ else
% endfor % endfor
endif endif
verify-install:
ifeq ($(SYSTEM_OK),true)
@echo "Your system looks ready to go."
@echo
else
@echo "Your system doesn't have protoc 3.0.0+ installed. While this"
@echo "won't prevent grpc from working, you won't be able to compile"
@echo "and run any meaningful code with it."
@echo
@echo
@echo "Please download and install protobuf 3.0.0+ from:"
@echo
@echo " https://github.com/google/protobuf/releases"
@echo
@echo "Once you've done so, you can re-run this check by doing:"
@echo
@echo " make verify-install"
endif
clean: clean:
$(E) "[CLEAN] Cleaning build directories." $(E) "[CLEAN] Cleaning build directories."
$(Q) $(RM) -rf $(OBJDIR) $(LIBDIR) $(BINDIR) $(GENDIR) $(Q) $(RM) -rf $(OBJDIR) $(LIBDIR) $(BINDIR) $(GENDIR)

@ -0,0 +1,110 @@
/*
*
* 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 <stdio.h>
#include <string.h>
#include "src/core/security/credentials.h"
#include "src/core/security/json_token.h"
#include "src/core/support/file.h"
#include <grpc/support/alloc.h>
#include <grpc/support/cmdline.h>
#include <grpc/support/log.h>
#include <grpc/support/slice.h>
void create_jwt(const char *json_key_file_path, const char *service_url,
const char *scope) {
grpc_auth_json_key key;
int ok = 0;
char *jwt;
gpr_slice json_key_data = gpr_load_file(json_key_file_path, &ok);
if (!ok) {
fprintf(stderr, "Could not read %s.\n", json_key_file_path);
exit(1);
}
key = grpc_auth_json_key_create_from_string(
(const char *)GPR_SLICE_START_PTR(json_key_data));
gpr_slice_unref(json_key_data);
if (!grpc_auth_json_key_is_valid(&key)) {
fprintf(stderr, "Could not parse json key.\n");
exit(1);
}
jwt = grpc_jwt_encode_and_sign(
&key, service_url == NULL ? GRPC_JWT_OAUTH2_AUDIENCE : service_url,
grpc_max_auth_token_lifetime, scope);
grpc_auth_json_key_destruct(&key);
if (jwt == NULL) {
fprintf(stderr, "Could not create JWT.\n");
exit(1);
}
fprintf(stdout, "%s\n", jwt);
gpr_free(jwt);
}
int main(int argc, char **argv) {
char *scope = NULL;
char *json_key_file_path = NULL;
char *service_url = NULL;
gpr_cmdline *cl = gpr_cmdline_create("create_jwt");
gpr_cmdline_add_string(cl, "json_key", "File path of the json key.",
&json_key_file_path);
gpr_cmdline_add_string(cl, "scope",
"OPTIONAL Space delimited permissions. Mutually "
"exclusive with service_url",
&scope);
gpr_cmdline_add_string(cl, "service_url",
"OPTIONAL service URL. Mutually exclusive with scope.",
&service_url);
gpr_cmdline_parse(cl, argc, argv);
if (json_key_file_path == NULL) {
fprintf(stderr, "Missing --json_key option.\n");
exit(1);
}
if (scope != NULL) {
if (service_url != NULL) {
fprintf(stderr,
"Options --scope and --service_url are mutually exclusive.\n");
exit(1);
}
} else if (service_url == NULL) {
fprintf(stderr, "Need one of --service_url or --scope options.\n");
exit(1);
}
create_jwt(json_key_file_path, service_url, scope);
gpr_cmdline_destroy(cl);
return 0;
}

@ -89,12 +89,17 @@ static const char test_user_data[] = "user data";
static const char test_scope[] = "perm1 perm2"; static const char test_scope[] = "perm1 perm2";
static const char test_signed_jwt[] = "signed jwt"; static const char test_signed_jwt[] =
"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImY0OTRkN2M1YWU2MGRmOTcyNmM4YW"
"U0MDcyZTViYTdmZDkwODg2YzcifQ";
static const char expected_service_account_http_body_prefix[] = static const char expected_service_account_http_body_prefix[] =
"grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&" "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&"
"assertion="; "assertion=";
static const char test_service_url[] = "https://foo.com/foo.v1";
static const char other_test_service_url[] = "https://bar.com/bar.v1";
static char *test_json_key_str(void) { static char *test_json_key_str(void) {
size_t result_len = strlen(test_json_key_str_part1) + size_t result_len = strlen(test_json_key_str_part1) +
strlen(test_json_key_str_part2) + strlen(test_json_key_str_part2) +
@ -259,7 +264,8 @@ static void test_iam_creds(void) {
test_iam_authorization_token, test_iam_authority_selector); test_iam_authorization_token, test_iam_authority_selector);
GPR_ASSERT(grpc_credentials_has_request_metadata(creds)); GPR_ASSERT(grpc_credentials_has_request_metadata(creds));
GPR_ASSERT(grpc_credentials_has_request_metadata_only(creds)); GPR_ASSERT(grpc_credentials_has_request_metadata_only(creds));
grpc_credentials_get_request_metadata(creds, check_iam_metadata, creds); grpc_credentials_get_request_metadata(creds, test_service_url,
check_iam_metadata, creds);
} }
static void check_ssl_oauth2_composite_metadata( static void check_ssl_oauth2_composite_metadata(
@ -293,8 +299,9 @@ static void test_ssl_oauth2_composite_creds(void) {
!strcmp(creds_array->creds_array[0]->type, GRPC_CREDENTIALS_TYPE_SSL)); !strcmp(creds_array->creds_array[0]->type, GRPC_CREDENTIALS_TYPE_SSL));
GPR_ASSERT( GPR_ASSERT(
!strcmp(creds_array->creds_array[1]->type, GRPC_CREDENTIALS_TYPE_OAUTH2)); !strcmp(creds_array->creds_array[1]->type, GRPC_CREDENTIALS_TYPE_OAUTH2));
grpc_credentials_get_request_metadata( grpc_credentials_get_request_metadata(composite_creds, test_service_url,
composite_creds, check_ssl_oauth2_composite_metadata, composite_creds); check_ssl_oauth2_composite_metadata,
composite_creds);
} }
static void check_ssl_oauth2_iam_composite_metadata( static void check_ssl_oauth2_iam_composite_metadata(
@ -338,7 +345,7 @@ static void test_ssl_oauth2_iam_composite_creds(void) {
!strcmp(creds_array->creds_array[1]->type, GRPC_CREDENTIALS_TYPE_OAUTH2)); !strcmp(creds_array->creds_array[1]->type, GRPC_CREDENTIALS_TYPE_OAUTH2));
GPR_ASSERT( GPR_ASSERT(
!strcmp(creds_array->creds_array[2]->type, GRPC_CREDENTIALS_TYPE_IAM)); !strcmp(creds_array->creds_array[2]->type, GRPC_CREDENTIALS_TYPE_IAM));
grpc_credentials_get_request_metadata(composite_creds, grpc_credentials_get_request_metadata(composite_creds, test_service_url,
check_ssl_oauth2_iam_composite_metadata, check_ssl_oauth2_iam_composite_metadata,
composite_creds); composite_creds);
} }
@ -420,14 +427,14 @@ static void test_compute_engine_creds_success(void) {
/* First request: http get should be called. */ /* First request: http get should be called. */
grpc_httpcli_set_override(compute_engine_httpcli_get_success_override, grpc_httpcli_set_override(compute_engine_httpcli_get_success_override,
httpcli_post_should_not_be_called); httpcli_post_should_not_be_called);
grpc_credentials_get_request_metadata(compute_engine_creds, grpc_credentials_get_request_metadata(compute_engine_creds, test_service_url,
on_oauth2_creds_get_metadata_success, on_oauth2_creds_get_metadata_success,
(void *)test_user_data); (void *)test_user_data);
/* Second request: the cached token should be served directly. */ /* Second request: the cached token should be served directly. */
grpc_httpcli_set_override(httpcli_get_should_not_be_called, grpc_httpcli_set_override(httpcli_get_should_not_be_called,
httpcli_post_should_not_be_called); httpcli_post_should_not_be_called);
grpc_credentials_get_request_metadata(compute_engine_creds, grpc_credentials_get_request_metadata(compute_engine_creds, test_service_url,
on_oauth2_creds_get_metadata_success, on_oauth2_creds_get_metadata_success,
(void *)test_user_data); (void *)test_user_data);
@ -442,7 +449,7 @@ static void test_compute_engine_creds_failure(void) {
httpcli_post_should_not_be_called); httpcli_post_should_not_be_called);
GPR_ASSERT(grpc_credentials_has_request_metadata(compute_engine_creds)); GPR_ASSERT(grpc_credentials_has_request_metadata(compute_engine_creds));
GPR_ASSERT(grpc_credentials_has_request_metadata_only(compute_engine_creds)); GPR_ASSERT(grpc_credentials_has_request_metadata_only(compute_engine_creds));
grpc_credentials_get_request_metadata(compute_engine_creds, grpc_credentials_get_request_metadata(compute_engine_creds, test_service_url,
on_oauth2_creds_get_metadata_failure, on_oauth2_creds_get_metadata_failure,
(void *)test_user_data); (void *)test_user_data);
grpc_credentials_unref(compute_engine_creds); grpc_credentials_unref(compute_engine_creds);
@ -468,27 +475,29 @@ static void validate_jwt_encode_and_sign_params(
!strcmp(json_key->client_email, !strcmp(json_key->client_email,
"777-abaslkan11hlb6nmim3bpspl31ud@developer." "777-abaslkan11hlb6nmim3bpspl31ud@developer."
"gserviceaccount.com")); "gserviceaccount.com"));
GPR_ASSERT(!strcmp(scope, test_scope)); if (scope != NULL) GPR_ASSERT(!strcmp(scope, test_scope));
GPR_ASSERT(!gpr_time_cmp(token_lifetime, grpc_max_auth_token_lifetime)); GPR_ASSERT(!gpr_time_cmp(token_lifetime, grpc_max_auth_token_lifetime));
} }
static char *encode_and_sign_jwt_success(const grpc_auth_json_key *json_key, static char *encode_and_sign_jwt_success(const grpc_auth_json_key *json_key,
const char *scope, const char *audience,
gpr_timespec token_lifetime) { gpr_timespec token_lifetime,
const char *scope) {
validate_jwt_encode_and_sign_params(json_key, scope, token_lifetime); validate_jwt_encode_and_sign_params(json_key, scope, token_lifetime);
return gpr_strdup(test_signed_jwt); return gpr_strdup(test_signed_jwt);
} }
static char *encode_and_sign_jwt_failure(const grpc_auth_json_key *json_key, static char *encode_and_sign_jwt_failure(const grpc_auth_json_key *json_key,
const char *scope, const char *audience,
gpr_timespec token_lifetime) { gpr_timespec token_lifetime,
const char *scope) {
validate_jwt_encode_and_sign_params(json_key, scope, token_lifetime); validate_jwt_encode_and_sign_params(json_key, scope, token_lifetime);
return NULL; return NULL;
} }
static char *encode_and_sign_jwt_should_not_be_called( static char *encode_and_sign_jwt_should_not_be_called(
const grpc_auth_json_key *json_key, const char *scope, const grpc_auth_json_key *json_key, const char *audience,
gpr_timespec token_lifetime) { gpr_timespec token_lifetime, const char *scope) {
GPR_ASSERT("grpc_jwt_encode_and_sign should not be called" == NULL); GPR_ASSERT("grpc_jwt_encode_and_sign should not be called" == NULL);
} }
@ -533,7 +542,7 @@ static int service_account_httpcli_post_failure(
return 1; return 1;
} }
static void test_service_accounts_creds_success(void) { static void test_service_account_creds_success(void) {
char *json_key_string = test_json_key_str(); char *json_key_string = test_json_key_str();
grpc_credentials *service_account_creds = grpc_credentials *service_account_creds =
grpc_service_account_credentials_create(json_key_string, test_scope, grpc_service_account_credentials_create(json_key_string, test_scope,
@ -545,7 +554,7 @@ static void test_service_accounts_creds_success(void) {
grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_success); grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_success);
grpc_httpcli_set_override(httpcli_get_should_not_be_called, grpc_httpcli_set_override(httpcli_get_should_not_be_called,
service_account_httpcli_post_success); service_account_httpcli_post_success);
grpc_credentials_get_request_metadata(service_account_creds, grpc_credentials_get_request_metadata(service_account_creds, test_service_url,
on_oauth2_creds_get_metadata_success, on_oauth2_creds_get_metadata_success,
(void *)test_user_data); (void *)test_user_data);
@ -554,7 +563,7 @@ static void test_service_accounts_creds_success(void) {
encode_and_sign_jwt_should_not_be_called); encode_and_sign_jwt_should_not_be_called);
grpc_httpcli_set_override(httpcli_get_should_not_be_called, grpc_httpcli_set_override(httpcli_get_should_not_be_called,
httpcli_post_should_not_be_called); httpcli_post_should_not_be_called);
grpc_credentials_get_request_metadata(service_account_creds, grpc_credentials_get_request_metadata(service_account_creds, test_service_url,
on_oauth2_creds_get_metadata_success, on_oauth2_creds_get_metadata_success,
(void *)test_user_data); (void *)test_user_data);
@ -564,7 +573,7 @@ static void test_service_accounts_creds_success(void) {
grpc_httpcli_set_override(NULL, NULL); grpc_httpcli_set_override(NULL, NULL);
} }
static void test_service_accounts_creds_http_failure(void) { static void test_service_account_creds_http_failure(void) {
char *json_key_string = test_json_key_str(); char *json_key_string = test_json_key_str();
grpc_credentials *service_account_creds = grpc_credentials *service_account_creds =
grpc_service_account_credentials_create(json_key_string, test_scope, grpc_service_account_credentials_create(json_key_string, test_scope,
@ -575,7 +584,7 @@ static void test_service_accounts_creds_http_failure(void) {
grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_success); grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_success);
grpc_httpcli_set_override(httpcli_get_should_not_be_called, grpc_httpcli_set_override(httpcli_get_should_not_be_called,
service_account_httpcli_post_failure); service_account_httpcli_post_failure);
grpc_credentials_get_request_metadata(service_account_creds, grpc_credentials_get_request_metadata(service_account_creds, test_service_url,
on_oauth2_creds_get_metadata_failure, on_oauth2_creds_get_metadata_failure,
(void *)test_user_data); (void *)test_user_data);
@ -584,7 +593,7 @@ static void test_service_accounts_creds_http_failure(void) {
grpc_httpcli_set_override(NULL, NULL); grpc_httpcli_set_override(NULL, NULL);
} }
static void test_service_accounts_creds_signing_failure(void) { static void test_service_account_creds_signing_failure(void) {
char *json_key_string = test_json_key_str(); char *json_key_string = test_json_key_str();
grpc_credentials *service_account_creds = grpc_credentials *service_account_creds =
grpc_service_account_credentials_create(json_key_string, test_scope, grpc_service_account_credentials_create(json_key_string, test_scope,
@ -595,13 +604,88 @@ static void test_service_accounts_creds_signing_failure(void) {
grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_failure); grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_failure);
grpc_httpcli_set_override(httpcli_get_should_not_be_called, grpc_httpcli_set_override(httpcli_get_should_not_be_called,
httpcli_post_should_not_be_called); httpcli_post_should_not_be_called);
grpc_credentials_get_request_metadata(service_account_creds, grpc_credentials_get_request_metadata(service_account_creds, test_service_url,
on_oauth2_creds_get_metadata_failure, on_oauth2_creds_get_metadata_failure,
(void *)test_user_data); (void *)test_user_data);
gpr_free(json_key_string); gpr_free(json_key_string);
grpc_credentials_unref(service_account_creds); grpc_credentials_unref(service_account_creds);
grpc_httpcli_set_override(NULL, NULL); grpc_httpcli_set_override(NULL, NULL);
grpc_jwt_encode_and_sign_set_override(NULL);
}
static void on_jwt_creds_get_metadata_success(
void *user_data, grpc_mdelem **md_elems, size_t num_md,
grpc_credentials_status status) {
char *expected_md_value;
gpr_asprintf(&expected_md_value, "Bearer %s", test_signed_jwt);
GPR_ASSERT(status == GRPC_CREDENTIALS_OK);
GPR_ASSERT(num_md == 1);
GPR_ASSERT(
!strcmp(grpc_mdstr_as_c_string(md_elems[0]->key), "Authorization"));
GPR_ASSERT(
!strcmp(grpc_mdstr_as_c_string(md_elems[0]->value), expected_md_value));
GPR_ASSERT(user_data != NULL);
GPR_ASSERT(!strcmp((const char *)user_data, test_user_data));
gpr_free(expected_md_value);
}
static void on_jwt_creds_get_metadata_failure(
void *user_data, grpc_mdelem **md_elems, size_t num_md,
grpc_credentials_status status) {
GPR_ASSERT(status == GRPC_CREDENTIALS_ERROR);
GPR_ASSERT(num_md == 0);
GPR_ASSERT(user_data != NULL);
GPR_ASSERT(!strcmp((const char *)user_data, test_user_data));
}
static void test_jwt_creds_success(void) {
char *json_key_string = test_json_key_str();
grpc_credentials *jwt_creds = grpc_jwt_credentials_create(
json_key_string, grpc_max_auth_token_lifetime);
GPR_ASSERT(grpc_credentials_has_request_metadata(jwt_creds));
GPR_ASSERT(grpc_credentials_has_request_metadata_only(jwt_creds));
/* First request: jwt_encode_and_sign should be called. */
grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_success);
grpc_credentials_get_request_metadata(jwt_creds, test_service_url,
on_jwt_creds_get_metadata_success,
(void *)test_user_data);
/* Second request: the cached token should be served directly. */
grpc_jwt_encode_and_sign_set_override(
encode_and_sign_jwt_should_not_be_called);
grpc_credentials_get_request_metadata(jwt_creds, test_service_url,
on_jwt_creds_get_metadata_success,
(void *)test_user_data);
/* Third request: Different service url so jwt_encode_and_sign should be
called again (no caching). */
grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_success);
grpc_credentials_get_request_metadata(jwt_creds, other_test_service_url,
on_jwt_creds_get_metadata_success,
(void *)test_user_data);
gpr_free(json_key_string);
grpc_credentials_unref(jwt_creds);
grpc_jwt_encode_and_sign_set_override(NULL);
}
static void test_jwt_creds_signing_failure(void) {
char *json_key_string = test_json_key_str();
grpc_credentials *jwt_creds = grpc_jwt_credentials_create(
json_key_string, grpc_max_auth_token_lifetime);
GPR_ASSERT(grpc_credentials_has_request_metadata(jwt_creds));
GPR_ASSERT(grpc_credentials_has_request_metadata_only(jwt_creds));
grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_failure);
grpc_credentials_get_request_metadata(jwt_creds, test_service_url,
on_jwt_creds_get_metadata_failure,
(void *)test_user_data);
gpr_free(json_key_string);
grpc_credentials_unref(jwt_creds);
grpc_jwt_encode_and_sign_set_override(NULL);
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
@ -618,8 +702,10 @@ int main(int argc, char **argv) {
test_ssl_oauth2_iam_composite_creds(); test_ssl_oauth2_iam_composite_creds();
test_compute_engine_creds_success(); test_compute_engine_creds_success();
test_compute_engine_creds_failure(); test_compute_engine_creds_failure();
test_service_accounts_creds_success(); test_service_account_creds_success();
test_service_accounts_creds_http_failure(); test_service_account_creds_http_failure();
test_service_accounts_creds_signing_failure(); test_service_account_creds_signing_failure();
test_jwt_creds_success();
test_jwt_creds_signing_failure();
return 0; return 0;
} }

@ -139,7 +139,7 @@ int main(int argc, char **argv) {
} }
} else { } else {
if (json_key_file_path == NULL) { if (json_key_file_path == NULL) {
gpr_log(GPR_ERROR, "missing --json_key option."); gpr_log(GPR_ERROR, "Missing --json_key option.");
exit(1); exit(1);
} }
if (scope == NULL) { if (scope == NULL) {
@ -162,7 +162,7 @@ int main(int argc, char **argv) {
gpr_cv_init(&sync.cv); gpr_cv_init(&sync.cv);
sync.is_done = 0; sync.is_done = 0;
grpc_credentials_get_request_metadata(creds, on_oauth2_response, &sync); grpc_credentials_get_request_metadata(creds, "", on_oauth2_response, &sync);
gpr_mu_lock(&sync.mu); gpr_mu_lock(&sync.mu);
while (!sync.is_done) gpr_cv_wait(&sync.cv, &sync.mu, gpr_inf_future); while (!sync.is_done) gpr_cv_wait(&sync.cv, &sync.mu, gpr_inf_future);

@ -76,6 +76,8 @@ static const char test_json_key_str_part3[] =
static const char test_scope[] = "myperm1 myperm2"; static const char test_scope[] = "myperm1 myperm2";
static const char test_service_url[] = "https://foo.com/foo.v1";
static char *test_json_key_str(const char *bad_part3) { static char *test_json_key_str(const char *bad_part3) {
const char *part3 = bad_part3 != NULL ? bad_part3 : test_json_key_str_part3; const char *part3 = bad_part3 != NULL ? bad_part3 : test_json_key_str_part3;
size_t result_len = strlen(test_json_key_str_part1) + size_t result_len = strlen(test_json_key_str_part1) +
@ -229,12 +231,15 @@ static void check_jwt_header(grpc_json *header) {
grpc_json *ptr; grpc_json *ptr;
grpc_json *alg = NULL; grpc_json *alg = NULL;
grpc_json *typ = NULL; grpc_json *typ = NULL;
grpc_json *kid = NULL;
for (ptr = header->child; ptr; ptr = ptr->next) { for (ptr = header->child; ptr; ptr = ptr->next) {
if (strcmp(ptr->key, "alg") == 0) { if (strcmp(ptr->key, "alg") == 0) {
alg = ptr; alg = ptr;
} else if (strcmp(ptr->key, "typ") == 0) { } else if (strcmp(ptr->key, "typ") == 0) {
typ = ptr; typ = ptr;
} else if (strcmp(ptr->key, "kid") == 0) {
kid = ptr;
} }
} }
GPR_ASSERT(alg != NULL); GPR_ASSERT(alg != NULL);
@ -244,9 +249,14 @@ static void check_jwt_header(grpc_json *header) {
GPR_ASSERT(typ != NULL); GPR_ASSERT(typ != NULL);
GPR_ASSERT(typ->type == GRPC_JSON_STRING); GPR_ASSERT(typ->type == GRPC_JSON_STRING);
GPR_ASSERT(!strcmp(typ->value, "JWT")); GPR_ASSERT(!strcmp(typ->value, "JWT"));
GPR_ASSERT(kid != NULL);
GPR_ASSERT(kid->type == GRPC_JSON_STRING);
GPR_ASSERT(!strcmp(kid->value, "e6b5137873db8d2ef81e06a47289e6434ec8a165"));
} }
static void check_jwt_claim(grpc_json *claim) { static void check_jwt_claim(grpc_json *claim, const char *expected_audience,
const char *expected_scope) {
gpr_timespec expiration = {0, 0}; gpr_timespec expiration = {0, 0};
gpr_timespec issue_time = {0, 0}; gpr_timespec issue_time = {0, 0};
gpr_timespec parsed_lifetime; gpr_timespec parsed_lifetime;
@ -255,11 +265,14 @@ static void check_jwt_claim(grpc_json *claim) {
grpc_json *aud = NULL; grpc_json *aud = NULL;
grpc_json *exp = NULL; grpc_json *exp = NULL;
grpc_json *iat = NULL; grpc_json *iat = NULL;
grpc_json *sub = NULL;
grpc_json *ptr; grpc_json *ptr;
for (ptr = claim->child; ptr; ptr = ptr->next) { for (ptr = claim->child; ptr; ptr = ptr->next) {
if (strcmp(ptr->key, "iss") == 0) { if (strcmp(ptr->key, "iss") == 0) {
iss = ptr; iss = ptr;
} else if (strcmp(ptr->key, "sub") == 0) {
sub = ptr;
} else if (strcmp(ptr->key, "scope") == 0) { } else if (strcmp(ptr->key, "scope") == 0) {
scope = ptr; scope = ptr;
} else if (strcmp(ptr->key, "aud") == 0) { } else if (strcmp(ptr->key, "aud") == 0) {
@ -278,14 +291,22 @@ static void check_jwt_claim(grpc_json *claim) {
iss->value, iss->value,
"777-abaslkan11hlb6nmim3bpspl31ud@developer.gserviceaccount.com")); "777-abaslkan11hlb6nmim3bpspl31ud@developer.gserviceaccount.com"));
GPR_ASSERT(scope != NULL); if (expected_scope != NULL) {
GPR_ASSERT(scope->type == GRPC_JSON_STRING); GPR_ASSERT(scope != NULL);
GPR_ASSERT(!strcmp(scope->value, test_scope)); GPR_ASSERT(sub == NULL);
GPR_ASSERT(scope->type == GRPC_JSON_STRING);
GPR_ASSERT(!strcmp(scope->value, expected_scope));
} else {
/* Claims without scope must have a sub. */
GPR_ASSERT(scope == NULL);
GPR_ASSERT(sub != NULL);
GPR_ASSERT(sub->type == GRPC_JSON_STRING);
GPR_ASSERT(!strcmp(iss->value, sub->value));
}
GPR_ASSERT(aud != NULL); GPR_ASSERT(aud != NULL);
GPR_ASSERT(aud->type == GRPC_JSON_STRING); GPR_ASSERT(aud->type == GRPC_JSON_STRING);
GPR_ASSERT(!strcmp(aud->value, GPR_ASSERT(!strcmp(aud->value, expected_audience));
"https://www.googleapis.com/oauth2/v3/token"));
GPR_ASSERT(exp != NULL); GPR_ASSERT(exp != NULL);
GPR_ASSERT(exp->type == GRPC_JSON_NUMBER); GPR_ASSERT(exp->type == GRPC_JSON_NUMBER);
@ -324,7 +345,28 @@ static void check_jwt_signature(const char *b64_signature, RSA *rsa_key,
if (md_ctx != NULL) EVP_MD_CTX_destroy(md_ctx); if (md_ctx != NULL) EVP_MD_CTX_destroy(md_ctx);
} }
static void test_jwt_encode_and_sign(void) { static char *service_account_creds_jwt_encode_and_sign(
const grpc_auth_json_key *key) {
return grpc_jwt_encode_and_sign(key, GRPC_JWT_OAUTH2_AUDIENCE,
grpc_max_auth_token_lifetime, test_scope);
}
static char *jwt_creds_jwt_encode_and_sign(const grpc_auth_json_key *key) {
return grpc_jwt_encode_and_sign(key, test_service_url,
grpc_max_auth_token_lifetime, NULL);
}
static void service_account_creds_check_jwt_claim(grpc_json *claim) {
check_jwt_claim(claim, GRPC_JWT_OAUTH2_AUDIENCE, test_scope);
}
static void jwt_creds_check_jwt_claim(grpc_json *claim) {
check_jwt_claim(claim, test_service_url, NULL);
}
static void test_jwt_encode_and_sign(
char *(*jwt_encode_and_sign_func)(const grpc_auth_json_key *),
void (*check_jwt_claim_func)(grpc_json *)) {
char *json_string = test_json_key_str(NULL); char *json_string = test_json_key_str(NULL);
grpc_json *parsed_header = NULL; grpc_json *parsed_header = NULL;
grpc_json *parsed_claim = NULL; grpc_json *parsed_claim = NULL;
@ -333,8 +375,7 @@ static void test_jwt_encode_and_sign(void) {
grpc_auth_json_key_create_from_string(json_string); grpc_auth_json_key_create_from_string(json_string);
const char *b64_signature; const char *b64_signature;
size_t offset = 0; size_t offset = 0;
char *jwt = grpc_jwt_encode_and_sign(&json_key, test_scope, char *jwt = jwt_encode_and_sign_func(&json_key);
grpc_max_auth_token_lifetime);
const char *dot = strchr(jwt, '.'); const char *dot = strchr(jwt, '.');
GPR_ASSERT(dot != NULL); GPR_ASSERT(dot != NULL);
parsed_header = parse_json_part_from_jwt(jwt, dot - jwt, &scratchpad); parsed_header = parse_json_part_from_jwt(jwt, dot - jwt, &scratchpad);
@ -346,9 +387,10 @@ static void test_jwt_encode_and_sign(void) {
dot = strchr(jwt + offset, '.'); dot = strchr(jwt + offset, '.');
GPR_ASSERT(dot != NULL); GPR_ASSERT(dot != NULL);
parsed_claim = parse_json_part_from_jwt(jwt + offset, dot - (jwt + offset), &scratchpad); parsed_claim =
parse_json_part_from_jwt(jwt + offset, dot - (jwt + offset), &scratchpad);
GPR_ASSERT(parsed_claim != NULL); GPR_ASSERT(parsed_claim != NULL);
check_jwt_claim(parsed_claim); check_jwt_claim_func(parsed_claim);
offset = dot - jwt + 1; offset = dot - jwt + 1;
grpc_json_destroy(parsed_claim); grpc_json_destroy(parsed_claim);
gpr_free(scratchpad); gpr_free(scratchpad);
@ -363,6 +405,16 @@ static void test_jwt_encode_and_sign(void) {
gpr_free(jwt); gpr_free(jwt);
} }
static void test_service_account_creds_jwt_encode_and_sign(void) {
test_jwt_encode_and_sign(service_account_creds_jwt_encode_and_sign,
service_account_creds_check_jwt_claim);
}
static void test_jwt_creds_jwt_encode_and_sign(void) {
test_jwt_encode_and_sign(jwt_creds_jwt_encode_and_sign,
jwt_creds_check_jwt_claim);
}
int main(int argc, char **argv) { int main(int argc, char **argv) {
grpc_test_init(argc, argv); grpc_test_init(argc, argv);
test_parse_json_key_success(); test_parse_json_key_success();
@ -372,6 +424,7 @@ int main(int argc, char **argv) {
test_parse_json_key_failure_no_client_email(); test_parse_json_key_failure_no_client_email();
test_parse_json_key_failure_no_private_key_id(); test_parse_json_key_failure_no_private_key_id();
test_parse_json_key_failure_no_private_key(); test_parse_json_key_failure_no_private_key();
test_jwt_encode_and_sign(); test_service_account_creds_jwt_encode_and_sign();
test_jwt_creds_jwt_encode_and_sign();
return 0; return 0;
} }

@ -418,6 +418,14 @@ grpc_completion_queue_test: grpc_completion_queue_test.exe
echo Running grpc_completion_queue_test echo Running grpc_completion_queue_test
$(OUT_DIR)\grpc_completion_queue_test.exe $(OUT_DIR)\grpc_completion_queue_test.exe
grpc_create_jwt.exe: grpc_test_util
echo Building grpc_create_jwt
$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\security\create_jwt.c
$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\grpc_create_jwt.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\create_jwt.obj
grpc_create_jwt: grpc_create_jwt.exe
echo Running grpc_create_jwt
$(OUT_DIR)\grpc_create_jwt.exe
grpc_credentials_test.exe: grpc_test_util grpc_credentials_test.exe: grpc_test_util
echo Building grpc_credentials_test echo Building grpc_credentials_test
$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\security\credentials_test.c $(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\security\credentials_test.c

@ -283,7 +283,9 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\core\iomgr\pollset_windows.c"> <ClCompile Include="..\..\src\core\iomgr\pollset_windows.c">
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\core\iomgr\resolve_address.c"> <ClCompile Include="..\..\src\core\iomgr\resolve_address_posix.c">
</ClCompile>
<ClCompile Include="..\..\src\core\iomgr\resolve_address_windows.c">
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\core\iomgr\sockaddr_utils.c"> <ClCompile Include="..\..\src\core\iomgr\sockaddr_utils.c">
</ClCompile> </ClCompile>

@ -145,7 +145,10 @@
<ClCompile Include="..\..\src\core\iomgr\pollset_windows.c"> <ClCompile Include="..\..\src\core\iomgr\pollset_windows.c">
<Filter>src\core\iomgr</Filter> <Filter>src\core\iomgr</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\core\iomgr\resolve_address.c"> <ClCompile Include="..\..\src\core\iomgr\resolve_address_posix.c">
<Filter>src\core\iomgr</Filter>
</ClCompile>
<ClCompile Include="..\..\src\core\iomgr\resolve_address_windows.c">
<Filter>src\core\iomgr</Filter> <Filter>src\core\iomgr</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\core\iomgr\sockaddr_utils.c"> <ClCompile Include="..\..\src\core\iomgr\sockaddr_utils.c">

@ -287,7 +287,9 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\core\iomgr\pollset_windows.c"> <ClCompile Include="..\..\src\core\iomgr\pollset_windows.c">
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\core\iomgr\resolve_address.c"> <ClCompile Include="..\..\src\core\iomgr\resolve_address_posix.c">
</ClCompile>
<ClCompile Include="..\..\src\core\iomgr\resolve_address_windows.c">
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\core\iomgr\sockaddr_utils.c"> <ClCompile Include="..\..\src\core\iomgr\sockaddr_utils.c">
</ClCompile> </ClCompile>

@ -145,7 +145,10 @@
<ClCompile Include="..\..\src\core\iomgr\pollset_windows.c"> <ClCompile Include="..\..\src\core\iomgr\pollset_windows.c">
<Filter>src\core\iomgr</Filter> <Filter>src\core\iomgr</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\core\iomgr\resolve_address.c"> <ClCompile Include="..\..\src\core\iomgr\resolve_address_posix.c">
<Filter>src\core\iomgr</Filter>
</ClCompile>
<ClCompile Include="..\..\src\core\iomgr\resolve_address_windows.c">
<Filter>src\core\iomgr</Filter> <Filter>src\core\iomgr</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\core\iomgr\sockaddr_utils.c"> <ClCompile Include="..\..\src\core\iomgr\sockaddr_utils.c">

@ -232,7 +232,9 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\core\iomgr\pollset_windows.c"> <ClCompile Include="..\..\src\core\iomgr\pollset_windows.c">
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\core\iomgr\resolve_address.c"> <ClCompile Include="..\..\src\core\iomgr\resolve_address_posix.c">
</ClCompile>
<ClCompile Include="..\..\src\core\iomgr\resolve_address_windows.c">
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\core\iomgr\sockaddr_utils.c"> <ClCompile Include="..\..\src\core\iomgr\sockaddr_utils.c">
</ClCompile> </ClCompile>

@ -91,7 +91,10 @@
<ClCompile Include="..\..\src\core\iomgr\pollset_windows.c"> <ClCompile Include="..\..\src\core\iomgr\pollset_windows.c">
<Filter>src\core\iomgr</Filter> <Filter>src\core\iomgr</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\core\iomgr\resolve_address.c"> <ClCompile Include="..\..\src\core\iomgr\resolve_address_posix.c">
<Filter>src\core\iomgr</Filter>
</ClCompile>
<ClCompile Include="..\..\src\core\iomgr\resolve_address_windows.c">
<Filter>src\core\iomgr</Filter> <Filter>src\core\iomgr</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\core\iomgr\sockaddr_utils.c"> <ClCompile Include="..\..\src\core\iomgr\sockaddr_utils.c">

Loading…
Cancel
Save