Merge github.com:google/grpc into buffer

pull/384/head
Craig Tiller 10 years ago
commit 62d424a1a4
  1. 82
      Makefile
  2. 33
      build.json
  3. 3
      include/grpc++/credentials.h
  4. 6
      include/grpc/grpc_security.h
  5. 6
      include/grpc/support/port_platform.h
  6. 5
      src/core/channel/client_channel.c
  7. 41
      src/core/iomgr/pollset_kick.c
  8. 6
      src/core/security/credentials.c
  9. 46
      src/core/security/security_context.c
  10. 2
      src/core/statistics/census_rpc_stats.c
  11. 94
      src/core/statistics/census_tracing.c
  12. 39
      src/core/statistics/census_tracing.h
  13. 60
      src/core/support/env.h
  14. 61
      src/core/support/env_linux.c
  15. 56
      src/core/support/env_posix.c
  16. 61
      src/core/support/env_win32.c
  17. 89
      src/core/support/file.c
  18. 61
      src/core/support/file.h
  19. 97
      src/core/support/file_posix.c
  20. 83
      src/core/support/file_win32.c
  21. 29
      src/core/support/string_win32.c
  22. 49
      src/core/support/string_win32.h
  23. 12
      src/core/surface/byte_buffer_queue.c
  24. 14
      src/core/surface/call.c
  25. 11
      src/core/surface/channel.c
  26. 2
      src/core/surface/channel.h
  27. 3
      src/core/surface/client.c
  28. 3
      src/core/surface/lame_client.c
  29. 2
      src/core/surface/server.c
  30. 18
      src/csharp/GrpcCore/Call.cs
  31. 5
      src/csharp/GrpcCore/GrpcCore.csproj
  32. 31
      src/csharp/GrpcCore/IMarshaller.cs
  33. 8
      src/csharp/GrpcCore/Internal/AsyncCall.cs
  34. 9
      src/csharp/GrpcCore/Internal/ServerSafeHandle.cs
  35. 38
      src/csharp/GrpcCore/Internal/ServerWritingObserver.cs
  36. 2
      src/csharp/GrpcCore/Internal/StreamingInputObserver.cs
  37. 64
      src/csharp/GrpcCore/Method.cs
  38. 89
      src/csharp/GrpcCore/Server.cs
  39. 93
      src/csharp/GrpcCore/ServerCallHandler.cs
  40. 25
      src/csharp/GrpcCore/ServerCalls.cs
  41. 39
      src/csharp/GrpcCoreTests/ClientServerTest.cs
  42. 2
      src/csharp/GrpcCoreTests/ServerTest.cs
  43. 28
      src/csharp/README.md
  44. 21
      test/core/end2end/fixtures/chttp2_simple_ssl_fullstack.c
  45. 71
      test/core/statistics/trace_test.c
  46. 64
      test/core/support/env_test.c
  47. 159
      test/core/support/file_test.c
  48. 4
      test/cpp/util/create_test_channel.cc
  49. 2
      tools/dockerfile/grpc_cxx/Dockerfile
  50. 29
      tools/gce_setup/builder.sh
  51. 4
      tools/gce_setup/cloud_prod_runner.sh
  52. 22
      tools/gce_setup/grpc_docker.sh
  53. 42
      tools/gce_setup/interop_test_runner.sh
  54. 12
      tools/gce_setup/post.html
  55. 14
      tools/gce_setup/pre.html
  56. 1
      tools/gce_setup/shared_startup_funcs.sh
  57. 8
      tools/run_tests/tests.json
  58. 16
      vsprojects/vs2013/build_and_run_tests.bat
  59. 15
      vsprojects/vs2013/gpr.vcxproj
  60. 27
      vsprojects/vs2013/gpr.vcxproj.filters

File diff suppressed because one or more lines are too long

@ -227,8 +227,11 @@
],
"headers": [
"src/core/support/cpu.h",
"src/core/support/env.h",
"src/core/support/file.h",
"src/core/support/murmur_hash.h",
"src/core/support/string.h",
"src/core/support/string_win32.h",
"src/core/support/thd_internal.h"
],
"src": [
@ -237,6 +240,12 @@
"src/core/support/cmdline.c",
"src/core/support/cpu_linux.c",
"src/core/support/cpu_posix.c",
"src/core/support/env_linux.c",
"src/core/support/env_posix.c",
"src/core/support/env_win32.c",
"src/core/support/file.c",
"src/core/support/file_posix.c",
"src/core/support/file_win32.c",
"src/core/support/histogram.c",
"src/core/support/host_port.c",
"src/core/support/log.c",
@ -923,6 +932,30 @@
"gpr"
]
},
{
"name": "gpr_file_test",
"build": "test",
"language": "c",
"src": [
"test/core/support/file_test.c"
],
"deps": [
"gpr_test_util",
"gpr"
]
},
{
"name": "gpr_env_test",
"build": "test",
"language": "c",
"src": [
"test/core/support/env_test.c"
],
"deps": [
"gpr_test_util",
"gpr"
]
},
{
"name": "gpr_slice_buffer_test",
"build": "test",

@ -66,14 +66,13 @@ class Credentials final {
// Options used to build SslCredentials
// pem_roots_cert is the buffer containing the PEM encoding of the server root
// certificates. This parameter cannot be empty.
// certificates. If this parameter is empty, the default roots will be used.
// pem_private_key is the buffer containing the PEM encoding of the client's
// private key. This parameter can be empty if the client does not have a
// private key.
// pem_cert_chain is the buffer containing the PEM encoding of the client's
// certificate chain. This parameter can be empty if the client does not have
// a certificate chain.
// TODO(jboeuf) Change it to point to a file.
struct SslCredentialsOptions {
grpc::string pem_root_certs;
grpc::string pem_private_key;

@ -54,6 +54,12 @@ void grpc_credentials_release(grpc_credentials *creds);
/* Creates default credentials. */
grpc_credentials *grpc_default_credentials_create(void);
/* Environment variable that points to the default SSL roots file. This file
must be a PEM encoded file with all the roots such as the one that can be
downloaded from https://pki.google.com/roots.pem. */
#define GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR \
"GRPC_DEFAULT_SSL_ROOTS_FILE_PATH"
/* Object that holds a private key / certificate chain pair in PEM format. */
typedef struct {
/* private_key is the NULL-terminated string containing the PEM encoding of

@ -61,6 +61,8 @@
#define GPR_POSIX_SOCKET 1
#define GPR_POSIX_SOCKETADDR 1
#define GPR_POSIX_SOCKETUTILS 1
#define GPR_POSIX_ENV 1
#define GPR_POSIX_FILE 1
#define GPR_POSIX_STRING 1
#define GPR_POSIX_SYNC 1
#define GPR_POSIX_TIME 1
@ -74,6 +76,8 @@
#define GPR_LINUX_EVENTFD 1
#define GPR_POSIX_SOCKET 1
#define GPR_POSIX_SOCKETADDR 1
#define GPR_LINUX_ENV 1
#define GPR_POSIX_FILE 1
#define GPR_POSIX_STRING 1
#define GPR_POSIX_SYNC 1
#define GPR_POSIX_TIME 1
@ -93,6 +97,8 @@
#define GPR_POSIX_SOCKET 1
#define GPR_POSIX_SOCKETADDR 1
#define GPR_POSIX_SOCKETUTILS 1
#define GPR_POSIX_ENV 1
#define GPR_POSIX_FILE 1
#define GPR_POSIX_STRING 1
#define GPR_POSIX_SYNC 1
#define GPR_POSIX_TIME 1

@ -298,6 +298,7 @@ static void channel_op(grpc_channel_element *elem,
grpc_channel_element *from_elem, grpc_channel_op *op) {
channel_data *chand = elem->channel_data;
grpc_child_channel *child_channel;
grpc_channel_op rop;
GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
switch (op->type) {
@ -323,6 +324,10 @@ static void channel_op(grpc_channel_element *elem,
if (child_channel) {
grpc_child_channel_destroy(child_channel, 1);
}
/* fake a transport closed to satisfy the refcounting in client */
rop.type = GRPC_TRANSPORT_CLOSED;
rop.dir = GRPC_CALL_UP;
grpc_channel_next_op(elem, &rop);
break;
case GRPC_TRANSPORT_GOAWAY:
/* receiving goaway: if it's from our active child, drop the active child;

@ -48,49 +48,49 @@
/* This implementation is based on a freelist of wakeup fds, with extra logic to
* handle kicks while there is no attached fd. */
/* TODO(klempner): Autosize this, and consider providing a way to disable the
* cap entirely on systems with large fd limits */
#define GRPC_MAX_CACHED_WFDS 50
#define GRPC_WFD_LOW_WATERMARK 25
static grpc_kick_fd_info *fd_freelist = NULL;
static int fd_freelist_count = 0;
static gpr_mu fd_freelist_mu;
static grpc_kick_fd_info *allocate_wfd(void) {
grpc_kick_fd_info *info;
grpc_kick_fd_info *info = NULL;
gpr_mu_lock(&fd_freelist_mu);
if (fd_freelist != NULL) {
info = fd_freelist;
fd_freelist = fd_freelist->next;
--fd_freelist_count;
} else {
}
gpr_mu_unlock(&fd_freelist_mu);
if (info == NULL) {
info = gpr_malloc(sizeof(*info));
grpc_wakeup_fd_create(&info->wakeup_fd);
info->next = NULL;
}
gpr_mu_unlock(&fd_freelist_mu);
return info;
}
static void destroy_wfd(void) {
/* assumes fd_freelist_mu is held */
grpc_kick_fd_info *current = fd_freelist;
fd_freelist = fd_freelist->next;
fd_freelist_count--;
grpc_wakeup_fd_destroy(&current->wakeup_fd);
gpr_free(current);
static void destroy_wfd(grpc_kick_fd_info* wfd) {
grpc_wakeup_fd_destroy(&wfd->wakeup_fd);
gpr_free(wfd);
}
static void free_wfd(grpc_kick_fd_info *fd_info) {
gpr_mu_lock(&fd_freelist_mu);
fd_info->next = fd_freelist;
fd_freelist = fd_info;
fd_freelist_count++;
if (fd_freelist_count > GRPC_MAX_CACHED_WFDS) {
while (fd_freelist_count > GRPC_WFD_LOW_WATERMARK) {
destroy_wfd();
}
if (fd_freelist_count < GRPC_MAX_CACHED_WFDS) {
fd_info->next = fd_freelist;
fd_freelist = fd_info;
fd_freelist_count++;
fd_info = NULL;
}
gpr_mu_unlock(&fd_freelist_mu);
if (fd_info) {
destroy_wfd(fd_info);
}
}
void grpc_pollset_kick_init(grpc_pollset_kick_state *kick_state) {
@ -148,6 +148,11 @@ void grpc_pollset_kick_global_init(void) {
}
void grpc_pollset_kick_global_destroy(void) {
while (fd_freelist != NULL) {
grpc_kick_fd_info *current = fd_freelist;
fd_freelist = fd_freelist->next;
destroy_wfd(current);
}
grpc_wakeup_fd_global_destroy();
gpr_mu_destroy(&fd_freelist_mu);
}

@ -216,14 +216,10 @@ static void ssl_copy_key_material(const char *input, unsigned char **output,
static void ssl_build_config(const char *pem_root_certs,
grpc_ssl_pem_key_cert_pair *pem_key_cert_pair,
grpc_ssl_config *config) {
if (pem_root_certs == NULL) {
/* TODO(jboeuf): Get them from the environment. */
gpr_log(GPR_ERROR, "Default SSL roots not yet implemented.");
} else {
if (pem_root_certs != NULL) {
ssl_copy_key_material(pem_root_certs, &config->pem_root_certs,
&config->pem_root_certs_size);
}
if (pem_key_cert_pair != NULL) {
GPR_ASSERT(pem_key_cert_pair->private_key != NULL);
GPR_ASSERT(pem_key_cert_pair->cert_chain != NULL);

@ -39,6 +39,8 @@
#include "src/core/channel/http_client_filter.h"
#include "src/core/security/credentials.h"
#include "src/core/security/secure_endpoint.h"
#include "src/core/support/env.h"
#include "src/core/support/file.h"
#include "src/core/support/string.h"
#include "src/core/surface/lame_client.h"
#include "src/core/transport/chttp2/alpn.h"
@ -319,6 +321,28 @@ static grpc_security_context_vtable ssl_channel_vtable = {
static grpc_security_context_vtable ssl_server_vtable = {
ssl_server_destroy, ssl_server_create_handshaker, ssl_server_check_peer};
static gpr_slice default_pem_root_certs;
static void init_default_pem_root_certs(void) {
char *default_root_certs_path =
gpr_getenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR);
if (default_root_certs_path == NULL) {
default_pem_root_certs = gpr_empty_slice();
} else {
default_pem_root_certs = gpr_load_file(default_root_certs_path, NULL);
gpr_free(default_root_certs_path);
}
}
static size_t get_default_pem_roots(const unsigned char **pem_root_certs) {
/* TODO(jboeuf@google.com): Maybe revisit the approach which consists in
loading all the roots once for the lifetime of the process. */
static gpr_once once = GPR_ONCE_INIT;
gpr_once_init(&once, init_default_pem_root_certs);
*pem_root_certs = GPR_SLICE_START_PTR(default_pem_root_certs);
return GPR_SLICE_LENGTH(default_pem_root_certs);
}
grpc_security_status grpc_ssl_channel_security_context_create(
grpc_credentials *request_metadata_creds, const grpc_ssl_config *config,
const char *secure_peer_name, grpc_channel_security_context **ctx) {
@ -330,6 +354,8 @@ grpc_security_status grpc_ssl_channel_security_context_create(
tsi_result result = TSI_OK;
grpc_ssl_channel_security_context *c;
size_t i;
const unsigned char *pem_root_certs;
size_t pem_root_certs_size;
for (i = 0; i < num_alpn_protocols; i++) {
alpn_protocol_strings[i] =
@ -338,9 +364,8 @@ grpc_security_status grpc_ssl_channel_security_context_create(
strlen(grpc_chttp2_get_alpn_version_index(i));
}
if (config == NULL || secure_peer_name == NULL ||
config->pem_root_certs == NULL) {
gpr_log(GPR_ERROR, "An ssl channel needs a secure name and root certs.");
if (config == NULL || secure_peer_name == NULL) {
gpr_log(GPR_ERROR, "An ssl channel needs a config and a secure name.");
goto error;
}
if (!check_request_metadata_creds(request_metadata_creds)) {
@ -357,11 +382,20 @@ grpc_security_status grpc_ssl_channel_security_context_create(
if (secure_peer_name != NULL) {
c->secure_peer_name = gpr_strdup(secure_peer_name);
}
if (config->pem_root_certs == NULL) {
pem_root_certs_size = get_default_pem_roots(&pem_root_certs);
if (pem_root_certs == NULL || pem_root_certs_size == 0) {
gpr_log(GPR_ERROR, "Could not get default pem root certs.");
goto error;
}
} else {
pem_root_certs = config->pem_root_certs;
pem_root_certs_size = config->pem_root_certs_size;
}
result = tsi_create_ssl_client_handshaker_factory(
config->pem_private_key, config->pem_private_key_size,
config->pem_cert_chain, config->pem_cert_chain_size,
config->pem_root_certs, config->pem_root_certs_size,
GRPC_SSL_CIPHER_SUITES, alpn_protocol_strings,
config->pem_cert_chain, config->pem_cert_chain_size, pem_root_certs,
pem_root_certs_size, GRPC_SSL_CIPHER_SUITES, alpn_protocol_strings,
alpn_protocol_string_lengths, num_alpn_protocols, &c->handshaker_factory);
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",

@ -141,7 +141,7 @@ static void record_stats(census_ht* store, census_op_id op_id,
const census_rpc_stats* stats) {
gpr_mu_lock(&g_mu);
if (store != NULL) {
trace_obj* trace = NULL;
census_trace_obj* trace = NULL;
census_internal_lock_trace_store();
trace = census_get_trace_obj_locked(op_id);
if (trace != NULL) {

@ -32,38 +32,22 @@
*/
#include "src/core/statistics/census_interface.h"
#include "src/core/statistics/census_tracing.h"
#include <stdio.h>
#include <string.h>
#include "src/core/statistics/census_rpc_stats.h"
#include "src/core/statistics/hash_table.h"
#include "src/core/support/string.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/port_platform.h>
#include <grpc/support/sync.h>
#include <grpc/support/time.h>
/* Struct for a trace annotation. */
typedef struct annotation {
gpr_timespec ts; /* timestamp of the annotation */
char txt[CENSUS_MAX_ANNOTATION_LENGTH + 1]; /* actual txt annotation */
struct annotation* next;
} annotation;
typedef struct trace_obj {
census_op_id id;
gpr_timespec ts;
census_rpc_stats rpc_stats;
char* method;
annotation* annotations;
} trace_obj;
static void trace_obj_destroy(trace_obj* obj) {
annotation* p = obj->annotations;
void census_trace_obj_destroy(census_trace_obj* obj) {
census_trace_annotation* p = obj->annotations;
while (p != NULL) {
annotation* next = p->next;
census_trace_annotation* next = p->next;
gpr_free(p);
p = next;
}
@ -71,7 +55,9 @@ static void trace_obj_destroy(trace_obj* obj) {
gpr_free(obj);
}
static void delete_trace_obj(void* obj) { trace_obj_destroy((trace_obj*)obj); }
static void delete_trace_obj(void* obj) {
census_trace_obj_destroy((census_trace_obj*)obj);
}
static const census_ht_option ht_opt = {
CENSUS_HT_UINT64 /* key type*/, 571 /* n_of_buckets */, NULL /* hash */,
@ -103,8 +89,8 @@ static void init_mutex_once(void) {
census_op_id census_tracing_start_op(void) {
gpr_mu_lock(&g_mu);
{
trace_obj* ret = (trace_obj*)gpr_malloc(sizeof(trace_obj));
memset(ret, 0, sizeof(trace_obj));
census_trace_obj* ret = gpr_malloc(sizeof(census_trace_obj));
memset(ret, 0, sizeof(census_trace_obj));
g_id++;
memcpy(&ret->id, &g_id, sizeof(census_op_id));
ret->rpc_stats.cnt = 1;
@ -118,7 +104,7 @@ census_op_id census_tracing_start_op(void) {
int census_add_method_tag(census_op_id op_id, const char* method) {
int ret = 0;
trace_obj* trace = NULL;
census_trace_obj* trace = NULL;
gpr_mu_lock(&g_mu);
trace = census_ht_find(g_trace_store, op_id_as_key(&op_id));
if (trace == NULL) {
@ -131,11 +117,11 @@ int census_add_method_tag(census_op_id op_id, const char* method) {
}
void census_tracing_print(census_op_id op_id, const char* anno_txt) {
trace_obj* trace = NULL;
census_trace_obj* trace = NULL;
gpr_mu_lock(&g_mu);
trace = census_ht_find(g_trace_store, op_id_as_key(&op_id));
if (trace != NULL) {
annotation* anno = gpr_malloc(sizeof(annotation));
census_trace_annotation* anno = gpr_malloc(sizeof(census_trace_annotation));
anno->ts = gpr_now();
{
char* d = anno->txt;
@ -153,7 +139,7 @@ void census_tracing_print(census_op_id op_id, const char* anno_txt) {
}
void census_tracing_end_op(census_op_id op_id) {
trace_obj* trace = NULL;
census_trace_obj* trace = NULL;
gpr_mu_lock(&g_mu);
trace = census_ht_find(g_trace_store, op_id_as_key(&op_id));
if (trace != NULL) {
@ -196,14 +182,58 @@ void census_internal_lock_trace_store(void) { gpr_mu_lock(&g_mu); }
void census_internal_unlock_trace_store(void) { gpr_mu_unlock(&g_mu); }
trace_obj* census_get_trace_obj_locked(census_op_id op_id) {
census_trace_obj* census_get_trace_obj_locked(census_op_id op_id) {
if (g_trace_store == NULL) {
gpr_log(GPR_ERROR, "Census trace store is not initialized.");
return NULL;
}
return (trace_obj*)census_ht_find(g_trace_store, op_id_as_key(&op_id));
return (census_trace_obj*)census_ht_find(g_trace_store, op_id_as_key(&op_id));
}
const char* census_get_trace_method_name(const trace_obj* trace) {
return (const char*)trace->method;
const char* census_get_trace_method_name(const census_trace_obj* trace) {
return trace->method;
}
static census_trace_annotation* dup_annotation_chain(
census_trace_annotation* from) {
census_trace_annotation *ret = NULL;
census_trace_annotation **to = &ret;
for (; from != NULL; from = from->next) {
*to = gpr_malloc(sizeof(census_trace_annotation));
memcpy(*to, from, sizeof(census_trace_annotation));
to = &(*to)->next;
}
return ret;
}
static census_trace_obj* trace_obj_dup(census_trace_obj* from) {
census_trace_obj* to = NULL;
GPR_ASSERT(from != NULL);
to = gpr_malloc(sizeof(census_trace_obj));
to->id = from->id;
to->ts = from->ts;
to->rpc_stats = from->rpc_stats;
to->method = gpr_strdup(from->method);
to->annotations = dup_annotation_chain(from->annotations);
return to;
}
census_trace_obj** census_get_active_ops(int* num_active_ops) {
census_trace_obj** ret = NULL;
gpr_mu_lock(&g_mu);
if (g_trace_store != NULL) {
size_t n = 0;
census_ht_kv* all_kvs = census_ht_get_all_elements(g_trace_store, &n);
*num_active_ops = (int)n;
if (n != 0 ) {
size_t i = 0;
ret = gpr_malloc(sizeof(census_trace_obj *) * n);
for (i = 0; i < n; i++) {
ret[i] = trace_obj_dup((census_trace_obj*)all_kvs[i].v);
}
}
gpr_free(all_kvs);
}
gpr_mu_unlock(&g_mu);
return ret;
}

@ -34,12 +34,35 @@
#ifndef __GRPC_INTERNAL_STATISTICS_CENSUS_TRACING_H_
#define __GRPC_INTERNAL_STATISTICS_CENSUS_TRACING_H_
#include <grpc/support/time.h>
#include "src/core/statistics/census_rpc_stats.h"
/* WARNING: The data structures and APIs provided by this file are for GRPC
library's internal use ONLY. They might be changed in backward-incompatible
ways and are not subject to any deprecation policy.
They are not recommended for external use.
*/
#ifdef __cplusplus
extern "C" {
#endif
/* Opaque structure for trace object */
typedef struct trace_obj trace_obj;
/* Struct for a trace annotation. */
typedef struct census_trace_annotation {
gpr_timespec ts; /* timestamp of the annotation */
char txt[CENSUS_MAX_ANNOTATION_LENGTH + 1]; /* actual txt annotation */
struct census_trace_annotation* next;
} census_trace_annotation;
typedef struct census_trace_obj {
census_op_id id;
gpr_timespec ts;
census_rpc_stats rpc_stats;
char* method;
census_trace_annotation* annotations;
} census_trace_obj;
/* Deletes trace object. */
void census_trace_obj_destroy(census_trace_obj* obj);
/* Initializes trace store. This function is thread safe. */
void census_tracing_init(void);
@ -50,15 +73,21 @@ void census_tracing_shutdown(void);
/* Gets trace obj corresponding to the input op_id. Returns NULL if trace store
is not initialized or trace obj is not found. Requires trace store being
locked before calling this function. */
trace_obj* census_get_trace_obj_locked(census_op_id op_id);
census_trace_obj* census_get_trace_obj_locked(census_op_id op_id);
/* The following two functions acquire and release the trace store global lock.
They are for census internal use only. */
void census_internal_lock_trace_store(void);
void census_internal_unlock_trace_store(void);
/* Gets method tag name associated with the input trace object. */
const char* census_get_trace_method_name(const trace_obj* trace);
/* Gets method name associated with the input trace object. */
const char* census_get_trace_method_name(const census_trace_obj* trace);
/* Returns an array of pointers to trace objects of currently active operations
and fills in number of active operations. Returns NULL if there are no active
operations.
Caller owns the returned objects. */
census_trace_obj** census_get_active_ops(int* num_active_ops);
#ifdef __cplusplus
}

@ -0,0 +1,60 @@
/*
*
* Copyright 2014, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef __GRPC_SUPPORT_ENV_H__
#define __GRPC_SUPPORT_ENV_H__
#include <stdio.h>
#include <grpc/support/slice.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Env utility functions */
/* Gets the environment variable value with the specified name.
Returns a newly allocated string. It is the responsability of the caller to
gpr_free the return value if not NULL (which means that the environment
variable exists). */
char *gpr_getenv(const char *name);
/* Sets the the environment with the specified name to the specified value. */
void gpr_setenv(const char *name, const char *value);
#ifdef __cplusplus
}
#endif
#endif /* __GRPC_SUPPORT_ENV_H__ */

@ -0,0 +1,61 @@
/*
*
* Copyright 2014, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/* for secure_getenv. */
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <grpc/support/port_platform.h>
#ifdef GPR_LINUX_ENV
#include "src/core/support/env.h"
#include <stdlib.h>
#include <grpc/support/log.h>
#include "src/core/support/string.h"
char *gpr_getenv(const char *name) {
char *result = secure_getenv(name);
return result == NULL ? result : gpr_strdup(result);
}
void gpr_setenv(const char *name, const char *value) {
int res = setenv(name, value, 1);
GPR_ASSERT(res == 0);
}
#endif /* GPR_LINUX_ENV */

@ -0,0 +1,56 @@
/*
*
* Copyright 2014, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <grpc/support/port_platform.h>
#ifdef GPR_POSIX_ENV
#include "src/core/support/env.h"
#include <stdlib.h>
#include <grpc/support/log.h>
#include "src/core/support/string.h"
char *gpr_getenv(const char *name) {
char *result = getenv(name);
return result == NULL ? result : gpr_strdup(result);
}
void gpr_setenv(const char *name, const char *value) {
int res = setenv(name, value, 1);
GPR_ASSERT(res == 0);
}
#endif /* GPR_POSIX_ENV */

@ -0,0 +1,61 @@
/*
*
* Copyright 2014, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <grpc/support/port_platform.h>
#ifdef GPR_WIN32
#include "src/core/support/env.h"
#include <stdlib.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
char *gpr_getenv(const char *name) {
size_t required_size;
char *result = NULL;
getenv_s(&required_size, NULL, 0, name);
if (required_size == 0) return NULL;
result = gpr_malloc(required_size);
getenv_s(&required_size, result, required_size, name);
return result;
}
void gpr_setenv(const char *name, const char *value) {
errno_t res = _putenv_s(name, value);
GPR_ASSERT(res == 0);
}
#endif /* GPR_WIN32 */

@ -0,0 +1,89 @@
/*
*
* Copyright 2014, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "src/core/support/file.h"
#include <errno.h>
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include "src/core/support/string.h"
gpr_slice gpr_load_file(const char *filename, int *success) {
unsigned char *contents = NULL;
size_t contents_size = 0;
unsigned char buf[4096];
char *error_msg = NULL;
gpr_slice result = gpr_empty_slice();
FILE *file = fopen(filename, "rb");
if (file == NULL) {
gpr_asprintf(&error_msg, "Could not open file %s (error = %s).", filename,
strerror(errno));
GPR_ASSERT(error_msg != NULL);
goto end;
}
while (1) {
size_t bytes_read = fread(buf, 1, sizeof(buf), file);
if (bytes_read > 0) {
contents = gpr_realloc(contents, contents_size + bytes_read);
memcpy(contents + contents_size, buf, bytes_read);
contents_size += bytes_read;
}
if (bytes_read < sizeof(buf)) {
if (ferror(file)) {
gpr_asprintf(&error_msg, "Error %s occured while reading file %s.",
strerror(errno), filename);
GPR_ASSERT(error_msg != NULL);
goto end;
} else {
GPR_ASSERT(feof(file));
break;
}
}
}
if (success != NULL) *success = 1;
result = gpr_slice_new(contents, contents_size, gpr_free);
end:
if (error_msg != NULL) {
gpr_log(GPR_ERROR, "%s", error_msg);
gpr_free(error_msg);
if (success != NULL) *success = 0;
}
if (file != NULL) fclose(file);
return result;
}

@ -0,0 +1,61 @@
/*
*
* Copyright 2014, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef __GRPC_SUPPORT_FILE_H__
#define __GRPC_SUPPORT_FILE_H__
#include <stdio.h>
#include <grpc/support/slice.h>
#ifdef __cplusplus
extern "C" {
#endif
/* File utility functions */
/* Loads the content of a file into a slice. The success parameter, if not NULL,
will be set to 1 in case of success and 0 in case of failure. */
gpr_slice gpr_load_file(const char *filename, int *success);
/* Creates a temporary file from a prefix.
If tmp_filename is not NULL, *tmp_filename is assigned the name of the
created file and it is the responsibility of the caller to gpr_free it
unless an error occurs in which case it will be set to NULL. */
FILE *gpr_tmpfile(const char *prefix, char **tmp_filename);
#ifdef __cplusplus
}
#endif
#endif /* __GRPC_SUPPORT_FILE_H__ */

@ -0,0 +1,97 @@
/*
*
* Copyright 2014, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/* Posix code for gpr fdopen and mkstemp support. */
#if !defined _POSIX_C_SOURCE || _POSIX_C_SOURCE < 200112L
#undef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 200112L
#endif
/* Don't know why I have to do this for mkstemp, looks like _POSIX_C_SOURCE
should be enough... */
#ifndef _BSD_SOURCE
#define _BSD_SOURCE
#endif
#include <grpc/support/port_platform.h>
#ifdef GPR_POSIX_FILE
#include "src/core/support/file.h"
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include "src/core/support/string.h"
FILE *gpr_tmpfile(const char *prefix, char **tmp_filename) {
FILE *result = NULL;
char *template;
int fd;
if (tmp_filename != NULL) *tmp_filename = NULL;
gpr_asprintf(&template, "/tmp/%s_XXXXXX", prefix);
GPR_ASSERT(template != NULL);
fd = mkstemp(template);
if (fd == -1) {
gpr_log(GPR_ERROR, "mkstemp failed for template %s with error %s.",
template, strerror(errno));
goto end;
}
result = fdopen(fd, "w+");
if (result == NULL) {
gpr_log(GPR_ERROR, "Could not open file %s from fd %d (error = %s).",
template, fd, strerror(errno));
unlink(template);
close(fd);
goto end;
}
end:
if (result != NULL && tmp_filename != NULL) {
*tmp_filename = template;
} else {
gpr_free(template);
}
return result;
}
#endif /* GPR_POSIX_FILE */

@ -0,0 +1,83 @@
/*
*
* Copyright 2014, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <grpc/support/port_platform.h>
#ifdef GPR_WIN32
#include <io.h>
#include <stdio.h>
#include <string.h>
#include <tchar.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include "src/core/support/file.h"
#include "src/core/support/string_win32.h"
FILE *gpr_tmpfile(const char *prefix, char **tmp_filename_out) {
FILE *result = NULL;
LPTSTR template_string = NULL;
TCHAR tmp_path[MAX_PATH];
TCHAR tmp_filename[MAX_PATH];
DWORD status;
UINT success;
if (tmp_filename_out != NULL) *tmp_filename_out = NULL;
/* Convert our prefix to TCHAR. */
template_string = gpr_char_to_tchar(prefix);
GPR_ASSERT(template_string);
/* Get the path to the best temporary folder available. */
status = GetTempPath(MAX_PATH, tmp_path);
if (status == 0 || status > MAX_PATH) goto end;
/* Generate a unique filename with our template + temporary path. */
success = GetTempFileName(tmp_path, template_string, 0, tmp_filename);
if (!success) goto end;
/* Open a file there. */
if (_tfopen_s(&result, tmp_filename, TEXT("wb+")) != 0) goto end;
end:
if (result && tmp_filename) {
*tmp_filename_out = gpr_tchar_to_char(tmp_filename);
}
gpr_free(tmp_filename);
return result;
}
#endif /* GPR_WIN32 */

@ -37,6 +37,7 @@
#ifdef GPR_WIN32
#include <windows.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
@ -78,4 +79,32 @@ int gpr_asprintf(char **strp, const char *format, ...) {
return -1;
}
#if defined UNICODE || defined _UNICODE
LPTSTR gpr_char_to_tchar(LPCSTR input) {
LPTSTR ret;
int needed = MultiByteToWideChar(CP_UTF8, 0, input, -1, NULL, 0);
if (needed == 0) return NULL;
ret = gpr_malloc(needed * sizeof(TCHAR));
MultiByteToWideChar(CP_UTF8, 0, input, -1, ret, needed);
return ret;
}
LPSTR gpr_tchar_to_char(LPCTSTR input) {
LPSTR ret;
int needed = WideCharToMultiByte(CP_UTF8, 0, input, -1, NULL, 0, NULL, NULL);
if (needed == 0) return NULL;
ret = gpr_malloc(needed);
WideCharToMultiByte(CP_UTF8, 0, input, -1, ret, needed, NULL, NULL);
return ret;
}
#else
char *gpr_tchar_to_char(LPTSTR input) {
return gpr_strdup(input);
}
char *gpr_char_to_tchar(LPTSTR input) {
return gpr_strdup(input);
}
#endif
#endif /* GPR_WIN32 */

@ -0,0 +1,49 @@
/*
*
* Copyright 2014, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef __GRPC_SUPPORT_STRING_WIN32_H__
#define __GRPC_SUPPORT_STRING_WIN32_H__
#include <grpc/support/port_platform.h>
#ifdef GPR_WIN32
#include <windows.h>
/* These allocate new strings using gpr_malloc to convert from and to utf-8. */
LPTSTR gpr_char_to_tchar(LPCSTR input);
LPSTR gpr_tchar_to_char(LPCTSTR input);
#endif /* GPR_WIN32 */
#endif /* __GRPC_SUPPORT_STRING_WIN32_H__ */

@ -35,7 +35,13 @@
#include <grpc/support/alloc.h>
#include <grpc/support/useful.h>
static void bba_destroy(grpc_bbq_array *array) { gpr_free(array->data); }
static void bba_destroy(grpc_bbq_array *array, size_t start_pos) {
size_t i;
for (i = start_pos; i < array->count; i++) {
grpc_byte_buffer_destroy(array->data[i]);
}
gpr_free(array->data);
}
/* Append an operation to an array, expanding as needed */
static void bba_push(grpc_bbq_array *a, grpc_byte_buffer *buffer) {
@ -47,8 +53,8 @@ static void bba_push(grpc_bbq_array *a, grpc_byte_buffer *buffer) {
}
void grpc_bbq_destroy(grpc_byte_buffer_queue *q) {
bba_destroy(&q->filling);
bba_destroy(&q->draining);
bba_destroy(&q->filling, 0);
bba_destroy(&q->draining, q->drain_pos);
}
int grpc_bbq_empty(grpc_byte_buffer_queue *q) {

@ -275,6 +275,7 @@ static void destroy_call(void *call, int ignored_success) {
if (c->legacy_state) {
destroy_legacy_state(c->legacy_state);
}
grpc_bbq_destroy(&c->incoming_queue);
gpr_free(c);
}
@ -335,8 +336,10 @@ static void unlock(grpc_call *call) {
send_action sa = SEND_NOTHING;
completed_request completed_requests[GRPC_IOREQ_OP_COUNT];
int num_completed_requests = call->num_completed_requests;
int need_more_data = call->need_more_data &&
!is_op_live(call, GRPC_IOREQ_SEND_INITIAL_METADATA);
int need_more_data =
call->need_more_data &&
!call->sending &&
call->write_state >= WRITE_STATE_STARTED;
int i;
if (need_more_data) {
@ -960,6 +963,8 @@ struct legacy_state {
char *details;
grpc_status_code status;
char *send_details;
size_t msg_in_read_idx;
grpc_byte_buffer *msg_in;
@ -985,6 +990,8 @@ static void destroy_legacy_state(legacy_state *ls) {
}
gpr_free(ls->initial_md_in.metadata);
gpr_free(ls->trailing_md_in.metadata);
gpr_free(ls->details);
gpr_free(ls->send_details);
gpr_free(ls);
}
@ -1233,8 +1240,7 @@ grpc_call_error grpc_call_start_write_status_old(grpc_call *call,
reqs[0].data.send_metadata.metadata = ls->md_out[ls->md_out_buffer];
reqs[1].op = GRPC_IOREQ_SEND_STATUS;
reqs[1].data.send_status.code = status;
/* MEMLEAK */
reqs[1].data.send_status.details = gpr_strdup(details);
reqs[1].data.send_status.details = ls->send_details = gpr_strdup(details);
reqs[2].op = GRPC_IOREQ_SEND_CLOSE;
err = start_ioreq(call, reqs, 3, finish_finish, tag);
unlock(call);

@ -52,6 +52,9 @@ struct grpc_channel {
};
#define CHANNEL_STACK_FROM_CHANNEL(c) ((grpc_channel_stack *)((c)+1))
#define CHANNEL_FROM_CHANNEL_STACK(channel_stack) (((grpc_channel *)(channel_stack)) - 1)
#define CHANNEL_FROM_TOP_ELEM(top_elem) \
CHANNEL_FROM_CHANNEL_STACK(grpc_channel_stack_from_top_element(top_elem))
grpc_channel *grpc_channel_create_from_filters(
const grpc_channel_filter **filters, size_t num_filters,
@ -60,8 +63,8 @@ grpc_channel *grpc_channel_create_from_filters(
sizeof(grpc_channel) + grpc_channel_stack_size(filters, num_filters);
grpc_channel *channel = gpr_malloc(size);
channel->is_client = is_client;
/* decremented by grpc_channel_destroy */
gpr_ref_init(&channel->refs, 1);
/* decremented by grpc_channel_destroy, and grpc_client_channel_closed if is_client */
gpr_ref_init(&channel->refs, 1 + is_client);
channel->metadata_context = mdctx;
channel->grpc_status_string = grpc_mdstr_from_string(mdctx, "grpc-status");
channel->grpc_message_string = grpc_mdstr_from_string(mdctx, "grpc-message");
@ -158,6 +161,10 @@ void grpc_channel_destroy(grpc_channel *channel) {
grpc_channel_internal_unref(channel);
}
void grpc_client_channel_closed(grpc_channel_element *elem) {
grpc_channel_internal_unref(CHANNEL_FROM_TOP_ELEM(elem));
}
grpc_channel_stack *grpc_channel_get_channel_stack(grpc_channel *channel) {
return CHANNEL_STACK_FROM_CHANNEL(channel);
}

@ -45,6 +45,8 @@ grpc_mdctx *grpc_channel_get_metadata_context(grpc_channel *channel);
grpc_mdstr *grpc_channel_get_status_string(grpc_channel *channel);
grpc_mdstr *grpc_channel_get_message_string(grpc_channel *channel);
void grpc_client_channel_closed(grpc_channel_element *elem);
void grpc_channel_internal_ref(grpc_channel *channel);
void grpc_channel_internal_unref(grpc_channel *channel);

@ -34,6 +34,7 @@
#include "src/core/surface/client.h"
#include "src/core/surface/call.h"
#include "src/core/surface/channel.h"
#include "src/core/support/string.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
@ -87,7 +88,7 @@ static void channel_op(grpc_channel_element *elem,
gpr_log(GPR_ERROR, "Client cannot accept new calls");
break;
case GRPC_TRANSPORT_CLOSED:
gpr_log(GPR_ERROR, "Transport closed");
grpc_client_channel_closed(elem);
break;
case GRPC_TRANSPORT_GOAWAY:
gpr_slice_unref(op->data.goaway.message);

@ -76,6 +76,9 @@ static void channel_op(grpc_channel_element *elem,
case GRPC_CHANNEL_GOAWAY:
gpr_slice_unref(op->data.goaway.message);
break;
case GRPC_CHANNEL_DISCONNECT:
grpc_client_channel_closed(elem);
break;
default:
break;
}

@ -258,7 +258,6 @@ static void stream_closed(grpc_call_element *elem) {
gpr_mu_lock(&chand->server->mu);
switch (calld->state) {
case ACTIVATED:
grpc_call_stream_closed(elem);
break;
case PENDING:
call_list_remove(chand->server, calld, PENDING_START);
@ -271,6 +270,7 @@ static void stream_closed(grpc_call_element *elem) {
break;
}
gpr_mu_unlock(&chand->server->mu);
grpc_call_stream_closed(elem);
}
static void read_closed(grpc_call_element *elem) {

@ -8,10 +8,8 @@ namespace Google.GRPC.Core
readonly string methodName;
readonly Func<TRequest, byte[]> requestSerializer;
readonly Func<byte[], TResponse> responseDeserializer;
readonly TimeSpan timeout;
readonly Channel channel;
// TODO: channel param should be removed in the future.
public Call(string methodName,
Func<TRequest, byte[]> requestSerializer,
Func<byte[], TResponse> responseDeserializer,
@ -20,24 +18,22 @@ namespace Google.GRPC.Core
this.methodName = methodName;
this.requestSerializer = requestSerializer;
this.responseDeserializer = responseDeserializer;
this.timeout = timeout;
this.channel = channel;
}
public Channel Channel
public Call(Method<TRequest, TResponse> method, Channel channel)
{
get
{
return this.channel;
}
this.methodName = method.Name;
this.requestSerializer = method.RequestMarshaller.Serialize;
this.responseDeserializer = method.ResponseMarshaller.Deserialize;
this.channel = channel;
}
public TimeSpan Timeout
public Channel Channel
{
get
{
return this.timeout;
return this.channel;
}
}

@ -54,6 +54,11 @@
<Compile Include="Internal\AsyncCall.cs" />
<Compile Include="Internal\ServerSafeHandle.cs" />
<Compile Include="Internal\StreamingInputObserver.cs" />
<Compile Include="Method.cs" />
<Compile Include="IMarshaller.cs" />
<Compile Include="ServerCalls.cs" />
<Compile Include="ServerCallHandler.cs" />
<Compile Include="Internal\ServerWritingObserver.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>

@ -0,0 +1,31 @@
using System;
namespace Google.GRPC.Core
{
/// <summary>
/// For serializing and deserializing messages.
/// </summary>
public interface IMarshaller<T>
{
byte[] Serialize(T value);
T Deserialize(byte[] payload);
}
/// <summary>
/// UTF-8 Marshalling for string. Useful for testing.
/// </summary>
internal class StringMarshaller : IMarshaller<string> {
public byte[] Serialize(string value)
{
return System.Text.Encoding.UTF8.GetBytes(value);
}
public string Deserialize(byte[] payload)
{
return System.Text.Encoding.UTF8.GetString(payload);
}
}
}

@ -86,6 +86,14 @@ namespace Google.GRPC.Core.Internal
return StartRead().Task;
}
public Task Halfclosed
{
get
{
return halfcloseTcs.Task;
}
}
public Task<Status> Finished
{
get

@ -30,8 +30,8 @@ namespace Google.GRPC.Core.Internal
[DllImport("libgrpc.so")]
static extern void grpc_server_shutdown(ServerSafeHandle server);
[DllImport("libgrpc.so")]
static extern void grpc_server_shutdown_and_notify(ServerSafeHandle server, IntPtr tag);
[DllImport("libgrpc.so", EntryPoint = "grpc_server_shutdown_and_notify")]
static extern void grpc_server_shutdown_and_notify_CALLBACK(ServerSafeHandle server, [MarshalAs(UnmanagedType.FunctionPtr)] EventCallbackDelegate callback);
[DllImport("libgrpc.so")]
static extern void grpc_server_destroy(IntPtr server);
@ -62,6 +62,11 @@ namespace Google.GRPC.Core.Internal
grpc_server_shutdown(this);
}
public void ShutdownAndNotify(EventCallbackDelegate callback)
{
grpc_server_shutdown_and_notify_CALLBACK(this, callback);
}
public GRPCCallError RequestCall(EventCallbackDelegate callback)
{
return grpc_server_request_call_old_CALLBACK(this, callback);

@ -0,0 +1,38 @@
using System;
using Google.GRPC.Core.Internal;
namespace Google.GRPC.Core.Internal
{
/// <summary>
/// Observer that writes all arriving messages to a call abstraction (in blocking fashion)
/// and then halfcloses the call. Used for server-side call handling.
/// </summary>
internal class ServerWritingObserver<TWrite, TRead> : IObserver<TWrite>
{
readonly AsyncCall<TWrite, TRead> call;
public ServerWritingObserver(AsyncCall<TWrite, TRead> call)
{
this.call = call;
}
public void OnCompleted()
{
// TODO: how bad is the Wait here?
call.WriteStatusAsync(new Status(StatusCode.GRPC_STATUS_OK, "")).Wait();
}
public void OnError(Exception error)
{
// TODO: handle this...
throw new InvalidOperationException("This should never be called.");
}
public void OnNext(TWrite value)
{
// TODO: how bad is the Wait here?
call.WriteAsync(value).Wait();
}
}
}

@ -1,7 +1,7 @@
using System;
using Google.GRPC.Core.Internal;
namespace Google.GRPC.Core
namespace Google.GRPC.Core.Internal
{
internal class StreamingInputObserver<TWrite, TRead> : IObserver<TWrite>
{

@ -0,0 +1,64 @@
using System;
namespace Google.GRPC.Core
{
public enum MethodType
{
Unary,
ClientStreaming,
ServerStreaming,
DuplexStreaming
}
/// <summary>
/// A description of a service method.
/// </summary>
public class Method<TRequest, TResponse>
{
readonly MethodType type;
readonly string name;
readonly IMarshaller<TRequest> requestMarshaller;
readonly IMarshaller<TResponse> responseMarshaller;
public Method(MethodType type, string name, IMarshaller<TRequest> requestMarshaller, IMarshaller<TResponse> responseMarshaller)
{
this.type = type;
this.name = name;
this.requestMarshaller = requestMarshaller;
this.responseMarshaller = responseMarshaller;
}
public MethodType Type
{
get
{
return this.type;
}
}
public string Name
{
get
{
return this.name;
}
}
public IMarshaller<TRequest> RequestMarshaller
{
get
{
return this.requestMarshaller;
}
}
public IMarshaller<TResponse> ResponseMarshaller
{
get
{
return this.responseMarshaller;
}
}
}
}

@ -1,7 +1,9 @@
using System;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Collections.Concurrent;
using System.Collections.Generic;
using Google.GRPC.Core.Internal;
namespace Google.GRPC.Core
@ -15,10 +17,15 @@ namespace Google.GRPC.Core
// TODO: make sure the delegate doesn't get garbage collected while
// native callbacks are in the completion queue.
readonly EventCallbackDelegate newRpcHandler;
readonly EventCallbackDelegate serverShutdownHandler;
readonly BlockingCollection<NewRpcInfo> newRpcQueue = new BlockingCollection<NewRpcInfo>();
readonly ServerSafeHandle handle;
readonly Dictionary<string, IServerCallHandler> callHandlers = new Dictionary<string, IServerCallHandler>();
readonly TaskCompletionSource<object> shutdownTcs = new TaskCompletionSource<object>();
static Server() {
GrpcEnvironment.EnsureInitialized();
}
@ -28,8 +35,14 @@ namespace Google.GRPC.Core
// TODO: what is the tag for server shutdown?
this.handle = ServerSafeHandle.NewServer(GetCompletionQueue(), IntPtr.Zero);
this.newRpcHandler = HandleNewRpc;
this.serverShutdownHandler = HandleServerShutdown;
}
// only call before Start(), this will be in server builder in the future.
internal void AddCallHandler(string methodName, IServerCallHandler handler) {
callHandlers.Add(methodName, handler);
}
// only call before Start()
public int AddPort(string addr) {
return handle.AddPort(addr);
}
@ -37,49 +50,57 @@ namespace Google.GRPC.Core
public void Start()
{
handle.Start();
// TODO: this basically means the server is single threaded....
StartHandlingRpcs();
}
public void RunRpc()
/// <summary>
/// Requests and handles single RPC call.
/// </summary>
internal void RunRpc()
{
AllowOneRpc();
try {
var rpcInfo = newRpcQueue.Take();
Console.WriteLine("Server received RPC " + rpcInfo.Method);
AsyncCall<byte[], byte[]> asyncCall = new AsyncCall<byte[], byte[]>(
(payload) => payload, (payload) => payload);
asyncCall.InitializeServer(rpcInfo.Call);
try
{
var rpcInfo = newRpcQueue.Take();
asyncCall.Accept(GetCompletionQueue());
Console.WriteLine("Server received RPC " + rpcInfo.Method);
while(true) {
byte[] payload = asyncCall.ReadAsync().Result;
if (payload == null)
IServerCallHandler callHandler;
if (!callHandlers.TryGetValue(rpcInfo.Method, out callHandler))
{
break;
}
callHandler = new NoSuchMethodCallHandler();
}
callHandler.StartCall(rpcInfo.Method, rpcInfo.Call, GetCompletionQueue());
}
asyncCall.WriteAsync(new byte[] { }).Wait();
// TODO: what should be the details?
asyncCall.WriteStatusAsync(new Status(StatusCode.GRPC_STATUS_OK, "")).Wait();
asyncCall.Finished.Wait();
} catch(Exception e) {
catch(Exception e)
{
Console.WriteLine("Exception while handling RPC: " + e);
}
}
// TODO: implement disposal properly...
public void Shutdown() {
handle.Shutdown();
/// <summary>
/// Requests server shutdown and when there are no more calls being serviced,
/// cleans up used resources.
/// </summary>
/// <returns>The async.</returns>
public async Task ShutdownAsync() {
handle.ShutdownAndNotify(serverShutdownHandler);
await shutdownTcs.Task;
handle.Dispose();
}
public void Kill() {
handle.Dispose();
}
//handle.Dispose();
private async Task StartHandlingRpcs() {
while (true)
{
await Task.Factory.StartNew(RunRpc);
}
}
private void AllowOneRpc()
@ -100,6 +121,18 @@ namespace Google.GRPC.Core
}
}
private void HandleServerShutdown(IntPtr eventPtr)
{
try
{
shutdownTcs.SetResult(null);
}
catch (Exception e)
{
Console.WriteLine("Caught exception in a native handler: " + e);
}
}
private static void AssertCallOk(GRPCCallError callError)
{
Trace.Assert(callError == GRPCCallError.GRPC_CALL_OK, "Status not GRPC_CALL_OK");

@ -0,0 +1,93 @@
using System;
using Google.GRPC.Core.Internal;
namespace Google.GRPC.Core
{
internal interface IServerCallHandler
{
void StartCall(string methodName, CallSafeHandle call, CompletionQueueSafeHandle cq);
}
internal class UnaryRequestServerCallHandler<TRequest, TResponse> : IServerCallHandler
{
readonly Method<TRequest, TResponse> method;
readonly UnaryRequestServerMethod<TRequest, TResponse> handler;
public UnaryRequestServerCallHandler(Method<TRequest, TResponse> method, UnaryRequestServerMethod<TRequest, TResponse> handler)
{
this.method = method;
this.handler = handler;
}
public void StartCall(string methodName, CallSafeHandle call, CompletionQueueSafeHandle cq)
{
var asyncCall = new AsyncCall<TResponse, TRequest>(
(msg) => method.ResponseMarshaller.Serialize(msg),
(payload) => method.RequestMarshaller.Deserialize(payload));
asyncCall.InitializeServer(call);
asyncCall.Accept(cq);
var request = asyncCall.ReadAsync().Result;
var responseObserver = new ServerWritingObserver<TResponse, TRequest>(asyncCall);
handler(request, responseObserver);
asyncCall.Halfclosed.Wait();
// TODO: wait until writing is finished
asyncCall.WriteStatusAsync(new Status(StatusCode.GRPC_STATUS_OK, "")).Wait();
asyncCall.Finished.Wait();
}
}
internal class StreamingRequestServerCallHandler<TRequest, TResponse> : IServerCallHandler
{
readonly Method<TRequest, TResponse> method;
readonly StreamingRequestServerMethod<TRequest, TResponse> handler;
public StreamingRequestServerCallHandler(Method<TRequest, TResponse> method, StreamingRequestServerMethod<TRequest, TResponse> handler)
{
this.method = method;
this.handler = handler;
}
public void StartCall(string methodName, CallSafeHandle call, CompletionQueueSafeHandle cq)
{
var asyncCall = new AsyncCall<TResponse, TRequest>(
(msg) => method.ResponseMarshaller.Serialize(msg),
(payload) => method.RequestMarshaller.Deserialize(payload));
asyncCall.InitializeServer(call);
asyncCall.Accept(cq);
var responseObserver = new ServerWritingObserver<TResponse, TRequest>(asyncCall);
var requestObserver = handler(responseObserver);
// feed the requests
asyncCall.StartReadingToStream(requestObserver);
asyncCall.Halfclosed.Wait();
asyncCall.WriteStatusAsync(new Status(StatusCode.GRPC_STATUS_OK, "")).Wait();
asyncCall.Finished.Wait();
}
}
internal class NoSuchMethodCallHandler : IServerCallHandler
{
public void StartCall(string methodName, CallSafeHandle call, CompletionQueueSafeHandle cq)
{
// We don't care about the payload type here.
AsyncCall<byte[], byte[]> asyncCall = new AsyncCall<byte[], byte[]>(
(payload) => payload, (payload) => payload);
asyncCall.InitializeServer(call);
asyncCall.Accept(cq);
asyncCall.WriteStatusAsync(new Status(StatusCode.GRPC_STATUS_UNIMPLEMENTED, "No such method.")).Wait();
asyncCall.Finished.Wait();
}
}
}

@ -0,0 +1,25 @@
using System;
namespace Google.GRPC.Core
{
// TODO: perhaps add also serverSideStreaming and clientSideStreaming
public delegate void UnaryRequestServerMethod<TRequest, TResponse> (TRequest request, IObserver<TResponse> responseObserver);
public delegate IObserver<TRequest> StreamingRequestServerMethod<TRequest, TResponse> (IObserver<TResponse> responseObserver);
internal static class ServerCalls {
public static IServerCallHandler UnaryRequestCall<TRequest, TResponse>(Method<TRequest, TResponse> method, UnaryRequestServerMethod<TRequest, TResponse> handler)
{
return new UnaryRequestServerCallHandler<TRequest, TResponse>(method, handler);
}
public static IServerCallHandler StreamingRequestCall<TRequest, TResponse>(Method<TRequest, TResponse> method, StreamingRequestServerMethod<TRequest, TResponse> handler)
{
return new StreamingRequestServerCallHandler<TRequest, TResponse>(method, handler);
}
}
}

@ -8,41 +8,48 @@ namespace Google.GRPC.Core.Tests
{
public class ClientServerTest
{
string request = "REQUEST";
string serverAddr = "localhost:" + Utils.PickUnusedPort();
private Method<string, string> unaryEchoStringMethod = new Method<string, string>(
MethodType.Unary,
"/tests.Test/UnaryEchoString",
new StringMarshaller(),
new StringMarshaller());
[Test]
public void EmptyCall()
{
Server server = new Server();
server.AddCallHandler(unaryEchoStringMethod.Name,
ServerCalls.UnaryRequestCall(unaryEchoStringMethod, HandleUnaryEchoString));
server.AddPort(serverAddr);
server.Start();
Task.Factory.StartNew(
() => {
server.RunRpc();
}
);
using (Channel channel = new Channel(serverAddr))
{
CreateCall(channel);
string response = Calls.BlockingUnaryCall(CreateCall(channel), request, default(CancellationToken));
Console.WriteLine("Received response: " + response);
var call = CreateUnaryEchoStringCall(channel);
Assert.AreEqual("ABC", Calls.BlockingUnaryCall(call, "ABC", default(CancellationToken)));
Assert.AreEqual("abcdef", Calls.BlockingUnaryCall(call, "abcdef", default(CancellationToken)));
}
server.Shutdown();
server.ShutdownAsync().Wait();
GrpcEnvironment.Shutdown();
}
private Call<string, string> CreateCall(Channel channel)
private Call<string, string> CreateUnaryEchoStringCall(Channel channel)
{
return new Call<string, string>("/tests.Test/EmptyCall",
(s) => System.Text.Encoding.ASCII.GetBytes(s),
(b) => System.Text.Encoding.ASCII.GetString(b),
Timeout.InfiniteTimeSpan, channel);
return new Call<string, string>(unaryEchoStringMethod, channel);
}
private void HandleUnaryEchoString(string request, IObserver<string> responseObserver) {
responseObserver.OnNext(request);
responseObserver.OnCompleted();
}
}
}

@ -12,7 +12,7 @@ namespace Google.GRPC.Core.Tests
Server server = new Server();
server.AddPort("localhost:" + Utils.PickUnusedPort());
server.Start();
server.Shutdown();
server.ShutdownAsync().Wait();
GrpcEnvironment.Shutdown();
}

@ -14,6 +14,34 @@ EXPERIMENTAL ONLY
- It is very possible that some parts of the code will be heavily refactored or
completely rewritten.
INSTALLATION AND USAGE
----------------------
- Compile and install the gRPC C Core library
```
make shared_c
sudo make install
```
- Prerequisites for development: Mono framework, MonoDevelop (IDE)
```
sudo apt-get install mono-devel
sudo apt-get install monodevelop monodevelop-nunit
sudo apt-get install nunit nunit-console
```
- Use MonoDevelop to open the solution Grpc.sln (you can also run unit tests
from there).
- After building the solution with MonoDevelop, you can use
nunit-console to run the unit tests (currently only running one by
one will make them pass.
```
nunit-console GrpcCoreTests.dll
```
CONTENTS
--------

@ -39,6 +39,9 @@
#include "src/core/channel/channel_args.h"
#include "src/core/security/credentials.h"
#include "src/core/security/security_context.h"
#include "src/core/support/env.h"
#include "src/core/support/file.h"
#include "src/core/support/string.h"
#include <grpc/support/alloc.h>
#include <grpc/support/host_port.h>
#include <grpc/support/log.h>
@ -99,7 +102,7 @@ void chttp2_tear_down_secure_fullstack(grpc_end2end_test_fixture *f) {
static void chttp2_init_client_simple_ssl_secure_fullstack(
grpc_end2end_test_fixture *f, grpc_channel_args *client_args) {
grpc_credentials *ssl_creds =
grpc_ssl_credentials_create(test_root_cert, NULL);
grpc_ssl_credentials_create(NULL, NULL);
grpc_arg ssl_name_override = {GRPC_ARG_STRING,
GRPC_SSL_TARGET_NAME_OVERRIDE_ARG,
{"foo.test.google.com"}};
@ -129,8 +132,20 @@ static grpc_end2end_test_config configs[] = {
int main(int argc, char **argv) {
size_t i;
FILE *roots_file;
size_t roots_size = strlen(test_root_cert);
char *roots_filename;
grpc_test_init(argc, argv);
/* Set the SSL roots env var. */
roots_file = gpr_tmpfile("chttp2_simple_ssl_fullstack_test", &roots_filename);
GPR_ASSERT(roots_filename != NULL);
GPR_ASSERT(roots_file != NULL);
GPR_ASSERT(fwrite(test_root_cert, 1, roots_size, roots_file) == roots_size);
fclose(roots_file);
gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, roots_filename);
grpc_init();
for (i = 0; i < sizeof(configs) / sizeof(*configs); i++) {
@ -139,5 +154,9 @@ int main(int argc, char **argv) {
grpc_shutdown();
/* Cleanup. */
remove(roots_filename);
gpr_free(roots_filename);
return 0;
}

@ -32,10 +32,12 @@
*/
#include <string.h>
#include <stdio.h>
#include "src/core/statistics/census_interface.h"
#include "src/core/statistics/census_tracing.h"
#include "src/core/statistics/census_tracing.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/port_platform.h>
#include <grpc/support/sync.h>
@ -172,6 +174,74 @@ static void test_trace_print(void) {
census_tracing_shutdown();
}
/* Returns 1 if two ids are equal, otherwise returns 0. */
static int ids_equal(census_op_id id1, census_op_id id2) {
return (id1.upper == id2.upper) && (id1.lower == id2.lower);
}
static void test_get_active_ops(void) {
census_op_id id_1, id_2, id_3;
census_trace_obj** active_ops;
const char* annotation_txt[] = {"annotation 1", "a2"};
int i = 0;
int n = 0;
gpr_log(GPR_INFO, "test_get_active_ops");
census_tracing_init();
/* No active ops before calling start_op(). */
active_ops = census_get_active_ops(&n);
GPR_ASSERT(active_ops == NULL);
GPR_ASSERT(n == 0);
/* Starts one op */
id_1 = census_tracing_start_op();
census_add_method_tag(id_1, "foo_1");
active_ops = census_get_active_ops(&n);
GPR_ASSERT(active_ops != NULL);
GPR_ASSERT(n == 1);
GPR_ASSERT(ids_equal(active_ops[0]->id, id_1));
census_trace_obj_destroy(active_ops[0]);
gpr_free(active_ops);
active_ops = NULL;
/* Start the second and the third ops */
id_2 = census_tracing_start_op();
census_add_method_tag(id_2, "foo_2");
id_3 = census_tracing_start_op();
census_add_method_tag(id_3, "foo_3");
active_ops = census_get_active_ops(&n);
GPR_ASSERT(n == 3);
for (i = 0; i < 3; i++) {
census_trace_obj_destroy(active_ops[i]);
}
gpr_free(active_ops);
active_ops = NULL;
/* End the second op and add annotations to the third ops*/
census_tracing_end_op(id_2);
census_tracing_print(id_3, annotation_txt[0]);
census_tracing_print(id_3, annotation_txt[1]);
active_ops = census_get_active_ops(&n);
GPR_ASSERT(active_ops != NULL);
GPR_ASSERT(n == 2);
for (i = 0; i < 2; i++) {
census_trace_obj_destroy(active_ops[i]);
}
gpr_free(active_ops);
active_ops = NULL;
/* End all ops. */
census_tracing_end_op(id_1);
census_tracing_end_op(id_3);
active_ops = census_get_active_ops(&n);
GPR_ASSERT(active_ops == NULL);
GPR_ASSERT(n == 0);
census_tracing_shutdown();
}
int main(int argc, char** argv) {
grpc_test_init(argc, argv);
test_init_shutdown();
@ -180,5 +250,6 @@ int main(int argc, char** argv) {
test_concurrency();
test_add_method_tag_to_unknown_op_id();
test_trace_print();
test_get_active_ops();
return 0;
}

@ -0,0 +1,64 @@
/*
*
* Copyright 2014, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <stdio.h>
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include "src/core/support/env.h"
#include "src/core/support/string.h"
#include "test/core/util/test_config.h"
#define LOG_TEST_NAME() gpr_log(GPR_INFO, "%s", __FUNCTION__)
static void test_setenv_getenv(void) {
const char *name = "FOO";
const char *value = "BAR";
char *retrieved_value;
LOG_TEST_NAME();
gpr_setenv(name, value);
retrieved_value = gpr_getenv(name);
GPR_ASSERT(retrieved_value != NULL);
GPR_ASSERT(!strcmp(value, retrieved_value));
gpr_free(retrieved_value);
}
int main(int argc, char **argv) {
grpc_test_init(argc, argv);
test_setenv_getenv();
return 0;
}

@ -0,0 +1,159 @@
/*
*
* Copyright 2014, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <stdio.h>
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/slice.h>
#include "src/core/support/file.h"
#include "src/core/support/string.h"
#include "test/core/util/test_config.h"
#define LOG_TEST_NAME() gpr_log(GPR_INFO, "%s", __FUNCTION__)
static const char prefix[] = "file_test";
static void test_load_empty_file(void) {
FILE *tmp = NULL;
gpr_slice slice;
int success;
char *tmp_name;
LOG_TEST_NAME();
tmp = gpr_tmpfile(prefix, &tmp_name);
GPR_ASSERT(tmp_name != NULL);
GPR_ASSERT(tmp != NULL);
fclose(tmp);
slice = gpr_load_file(tmp_name, &success);
GPR_ASSERT(success == 1);
GPR_ASSERT(GPR_SLICE_LENGTH(slice) == 0);
remove(tmp_name);
gpr_free(tmp_name);
gpr_slice_unref(slice);
}
static void test_load_failure(void) {
FILE *tmp = NULL;
gpr_slice slice;
int success;
char *tmp_name;
LOG_TEST_NAME();
tmp = gpr_tmpfile(prefix, &tmp_name);
GPR_ASSERT(tmp_name != NULL);
GPR_ASSERT(tmp != NULL);
fclose(tmp);
remove(tmp_name);
slice = gpr_load_file(tmp_name, &success);
GPR_ASSERT(success == 0);
GPR_ASSERT(GPR_SLICE_LENGTH(slice) == 0);
gpr_free(tmp_name);
gpr_slice_unref(slice);
}
static void test_load_small_file(void) {
FILE *tmp = NULL;
gpr_slice slice;
int success;
char *tmp_name;
const char *blah = "blah";
LOG_TEST_NAME();
tmp = gpr_tmpfile(prefix, &tmp_name);
GPR_ASSERT(tmp_name != NULL);
GPR_ASSERT(tmp != NULL);
GPR_ASSERT(fwrite(blah, 1, strlen(blah), tmp) == strlen(blah));
fclose(tmp);
slice = gpr_load_file(tmp_name, &success);
GPR_ASSERT(success == 1);
GPR_ASSERT(GPR_SLICE_LENGTH(slice) == strlen(blah));
GPR_ASSERT(!memcmp(GPR_SLICE_START_PTR(slice), blah, strlen(blah)));
remove(tmp_name);
gpr_free(tmp_name);
gpr_slice_unref(slice);
}
static void test_load_big_file(void) {
FILE *tmp = NULL;
gpr_slice slice;
int success;
char *tmp_name;
unsigned char buffer[124631];
unsigned char *current;
size_t i;
LOG_TEST_NAME();
for (i = 0; i < sizeof(buffer); i++) {
buffer[i] = 42;
}
tmp = gpr_tmpfile(prefix, &tmp_name);
GPR_ASSERT(tmp != NULL);
GPR_ASSERT(tmp_name != NULL);
GPR_ASSERT(fwrite(buffer, 1, sizeof(buffer), tmp) == sizeof(buffer));
fclose(tmp);
slice = gpr_load_file(tmp_name, &success);
GPR_ASSERT(success == 1);
GPR_ASSERT(GPR_SLICE_LENGTH(slice) == sizeof(buffer));
current = GPR_SLICE_START_PTR(slice);
for (i = 0; i < sizeof(buffer); i++) {
GPR_ASSERT(current[i] == 42);
}
remove(tmp_name);
gpr_free(tmp_name);
gpr_slice_unref(slice);
}
int main(int argc, char **argv) {
grpc_test_init(argc, argv);
test_load_empty_file();
test_load_failure();
test_load_small_file();
test_load_big_file();
return 0;
}

@ -45,6 +45,8 @@ namespace grpc {
// override_hostname is provided.
// When ssl is not enabled, override_hostname is ignored.
// Set use_prod_root to true to use the SSL root for connecting to google.
// In this case, path to the roots pem file must be set via environment variable
// GRPC_DEFAULT_SSL_ROOTS_FILE_PATH.
// Otherwise, root for test SSL cert will be used.
// creds will be used to create a channel when enable_ssl is true.
// Use examples:
@ -60,7 +62,7 @@ std::shared_ptr<ChannelInterface> CreateTestChannel(
ChannelArguments channel_args;
if (enable_ssl) {
const char* roots_certs =
use_prod_roots ? prod_roots_certs : test_root_cert;
use_prod_roots ? "" : test_root_cert;
SslCredentialsOptions ssl_opts = {roots_certs, "", ""};
std::unique_ptr<Credentials> channel_creds =

@ -22,5 +22,7 @@ RUN cd /var/local/git/grpc && ls \
&& make interop_server
ADD service_account service_account
ADD cacerts cacerts
ENV GRPC_DEFAULT_SSL_ROOTS_FILE_PATH /cacerts/roots.pem
CMD ["/var/local/git/grpc/bins/opt/interop_server", "--enable_ssl", "--port=8010"]

@ -0,0 +1,29 @@
#!/bin/bash
main() {
# restart builder vm and wait for images to sync to it
source grpc_docker.sh
./new_grpc_docker_builder.sh -igrpc-docker-builder-alt-2 -anone
cd ../../
sleep 3600
# build images for all languages
languages=(cxx java go ruby node)
for lan in "${languages[@]}"
do
grpc_update_image $lan
done
# restart client and server vm and wait for images to sync to them
cd tools/gce_setup
./new_grpc_docker_builder.sh -igrpc-docker-testclients -anone
./new_grpc_docker_builder.sh -igrpc-docker-server -anone
sleep 3600
# launch images for all languages on server
grpc_launch_servers grpc-docker-server
}
set -x
main "$@"

@ -2,8 +2,8 @@
main() {
source grpc_docker.sh
test_cases=(large_unary empty_unary client_streaming server_streaming)
clients=(cxx java go ruby)
test_cases=(large_unary empty_unary ping_pong client_streaming server_streaming)
clients=(cxx java go ruby node)
for test_case in "${test_cases[@]}"
do
for client in "${clients[@]}"

@ -762,7 +762,16 @@ grpc_interop_test() {
echo " $ssh_cmd"
echo "on $host"
[[ $dry_run == 1 ]] && return 0 # don't run the command on a dry run
gcloud compute $project_opt ssh $zone_opt $host --command "$cmd"
gcloud compute $project_opt ssh $zone_opt $host --command "$cmd" &
PID=$!
sleep 10
echo "pid is $PID"
if ps -p $PID
then
kill $PID
return 1
fi
}
# Runs a test command on a docker instance.
@ -808,7 +817,16 @@ grpc_cloud_prod_test() {
echo " $ssh_cmd"
echo "on $host"
[[ $dry_run == 1 ]] && return 0 # don't run the command on a dry run
gcloud compute $project_opt ssh $zone_opt $host --command "$cmd"
gcloud compute $project_opt ssh $zone_opt $host --command "$cmd" &
PID=$!
sleep 10
echo "pid is $PID"
if ps -p $PID
then
kill $PID
return 1
fi
}
# Runs a test command on a docker instance.

@ -1,33 +1,8 @@
#!/bin/bash
thisfile=$(readlink -ne "${BASH_SOURCE[0]}")
run_test() {
local test_case=$1
shift
local client=$1
shift
local server=$1
if grpc_interop_test $test_case grpc-docker-testclients $client grpc-docker-server $server
then
echo "$test_case $client $server passed" >> /tmp/interop_result.txt
else
echo "$test_case $client $server failed" >> /tmp/interop_result.txt
fi
}
time_out() {
local test_case=$1
shift
local client=$1
shift
local server=$1
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
if ! timeout 20s bash -l -c "source $thisfile && run_test $test_case $client $server"
then
echo "$test_case $client $server timed out" >> /tmp/interop_result.txt
fi
fi
}
current_time=$(date "+%Y-%m-%d-%H-%M-%S")
result_file_name=interop_result.$current_time.html
echo $result_file_name
main() {
source grpc_docker.sh
@ -40,13 +15,22 @@ main() {
do
for server in "${servers[@]}"
do
time_out $test_case $client $server
if grpc_interop_test $test_case grpc-docker-testclients $client grpc-docker-server $server
then
echo " ['$test_case', '$client', '$server', true]," >> /tmp/interop_result.txt
else
echo " ['$test_case', '$client', '$server', false]," >> /tmp/interop_result.txt
fi
done
done
done
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
cat pre.html /tmp/interop_result.txt post.html > /tmp/interop_result.html
gsutil cp /tmp/interop_result.txt gs://stoked-keyword-656-output/interop_result.txt
gsutil cp /tmp/interop_result.html gs://stoked-keyword-656-output/interop_result.html
gsutil cp /tmp/interop_result.html gs://stoked-keyword-656-output/result_history/$result_file_name
rm /tmp/interop_result.txt
rm /tmp/interop_result.html
fi
}

@ -0,0 +1,12 @@
]);
var table = new google.visualization.Table(document.getElementById('table_div'));
table.draw(data, {showRowNumber: true});
}
</script>
</head>
<body>
<div id="table_div"></div>
</body>
</html>

@ -0,0 +1,14 @@
<html>
<head>
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript">
google.load("visualization", "1", {packages:["table"]});
google.setOnLoadCallback(drawTable);
function drawTable() {
var data = new google.visualization.DataTable();
data.addColumn('string', 'TestCase');
data.addColumn('string', 'Client');
data.addColumn('string', 'Server');
data.addColumn('boolean', 'Pass');
data.addRows([

@ -389,6 +389,7 @@ grpc_dockerfile_install() {
grpc_docker_sync_service_account $dockerfile_dir/service_account || return 1;
}
[[ $image_label == "grpc/cxx" ]] && {
grpc_docker_sync_roots_pem $dockerfile_dir/cacerts || return 1;
grpc_docker_sync_service_account $dockerfile_dir/service_account || return 1;
}

@ -109,6 +109,14 @@
"language": "c",
"name": "gpr_log_test"
},
{
"language": "c",
"name": "gpr_file_test"
},
{
"language": "c",
"name": "gpr_env_test"
},
{
"language": "c",
"name": "gpr_slice_buffer_test"

@ -49,6 +49,22 @@ echo Running test gpr_log_test
test_bin\gpr_log_test.exe || echo TEST FAILED: gpr_log_test && exit /b
echo(
echo Building test gpr_file_test
cl.exe /c /I..\.. /I..\..\include /nologo /ZI /W3 /WX- /sdl /D WIN32 /D _LIB /D _USE_32BIT_TIME_T /D _UNICODE /D UNICODE /Gm /EHsc /RTC1 /MDd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Gd /TC /analyze- /Fo:test_bin\ ..\..\test\core\support\file_test.c
link.exe /OUT:"test_bin\gpr_file_test.exe" /INCREMENTAL /NOLOGO /SUBSYSTEM:CONSOLE /TLBID:1 /DYNAMICBASE /NXCOMPAT /MACHINE:X86 Debug\gpr_test_util.lib Debug\gpr.lib test_bin\file_test.obj
echo(
echo Running test gpr_file_test
test_bin\gpr_file_test.exe || echo TEST FAILED: gpr_file_test && exit /b
echo(
echo Building test gpr_env_test
cl.exe /c /I..\.. /I..\..\include /nologo /ZI /W3 /WX- /sdl /D WIN32 /D _LIB /D _USE_32BIT_TIME_T /D _UNICODE /D UNICODE /Gm /EHsc /RTC1 /MDd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Gd /TC /analyze- /Fo:test_bin\ ..\..\test\core\support\env_test.c
link.exe /OUT:"test_bin\gpr_env_test.exe" /INCREMENTAL /NOLOGO /SUBSYSTEM:CONSOLE /TLBID:1 /DYNAMICBASE /NXCOMPAT /MACHINE:X86 Debug\gpr_test_util.lib Debug\gpr.lib test_bin\env_test.obj
echo(
echo Running test gpr_env_test
test_bin\gpr_env_test.exe || echo TEST FAILED: gpr_env_test && exit /b
echo(
echo Building test gpr_slice_buffer_test
cl.exe /c /I..\.. /I..\..\include /nologo /ZI /W3 /WX- /sdl /D WIN32 /D _LIB /D _USE_32BIT_TIME_T /D _UNICODE /D UNICODE /Gm /EHsc /RTC1 /MDd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Gd /TC /analyze- /Fo:test_bin\ ..\..\test\core\support\slice_buffer_test.c
link.exe /OUT:"test_bin\gpr_slice_buffer_test.exe" /INCREMENTAL /NOLOGO /SUBSYSTEM:CONSOLE /TLBID:1 /DYNAMICBASE /NXCOMPAT /MACHINE:X86 Debug\gpr_test_util.lib Debug\gpr.lib test_bin\slice_buffer_test.obj

@ -96,8 +96,11 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\core\support\cpu.h" />
<ClInclude Include="..\..\src\core\support\env.h" />
<ClInclude Include="..\..\src\core\support\file.h" />
<ClInclude Include="..\..\src\core\support\murmur_hash.h" />
<ClInclude Include="..\..\src\core\support\string.h" />
<ClInclude Include="..\..\src\core\support\string_win32.h" />
<ClInclude Include="..\..\src\core\support\thd_internal.h" />
</ItemGroup>
<ItemGroup>
@ -111,6 +114,18 @@
</ClCompile>
<ClCompile Include="..\..\src\core\support\cpu_posix.c">
</ClCompile>
<ClCompile Include="..\..\src\core\support\env_linux.c">
</ClCompile>
<ClCompile Include="..\..\src\core\support\env_posix.c">
</ClCompile>
<ClCompile Include="..\..\src\core\support\env_win32.c">
</ClCompile>
<ClCompile Include="..\..\src\core\support\file.c">
</ClCompile>
<ClCompile Include="..\..\src\core\support\file_posix.c">
</ClCompile>
<ClCompile Include="..\..\src\core\support\file_win32.c">
</ClCompile>
<ClCompile Include="..\..\src\core\support\histogram.c">
</ClCompile>
<ClCompile Include="..\..\src\core\support\host_port.c">

@ -16,6 +16,24 @@
<ClCompile Include="..\..\src\core\support\cpu_posix.c">
<Filter>src\core\support</Filter>
</ClCompile>
<ClCompile Include="..\..\src\core\support\env_linux.c">
<Filter>src\core\support</Filter>
</ClCompile>
<ClCompile Include="..\..\src\core\support\env_posix.c">
<Filter>src\core\support</Filter>
</ClCompile>
<ClCompile Include="..\..\src\core\support\env_win32.c">
<Filter>src\core\support</Filter>
</ClCompile>
<ClCompile Include="..\..\src\core\support\file.c">
<Filter>src\core\support</Filter>
</ClCompile>
<ClCompile Include="..\..\src\core\support\file_posix.c">
<Filter>src\core\support</Filter>
</ClCompile>
<ClCompile Include="..\..\src\core\support\file_win32.c">
<Filter>src\core\support</Filter>
</ClCompile>
<ClCompile Include="..\..\src\core\support\histogram.c">
<Filter>src\core\support</Filter>
</ClCompile>
@ -146,12 +164,21 @@
<ClInclude Include="..\..\src\core\support\cpu.h">
<Filter>src\core\support</Filter>
</ClInclude>
<ClInclude Include="..\..\src\core\support\env.h">
<Filter>src\core\support</Filter>
</ClInclude>
<ClInclude Include="..\..\src\core\support\file.h">
<Filter>src\core\support</Filter>
</ClInclude>
<ClInclude Include="..\..\src\core\support\murmur_hash.h">
<Filter>src\core\support</Filter>
</ClInclude>
<ClInclude Include="..\..\src\core\support\string.h">
<Filter>src\core\support</Filter>
</ClInclude>
<ClInclude Include="..\..\src\core\support\string_win32.h">
<Filter>src\core\support</Filter>
</ClInclude>
<ClInclude Include="..\..\src\core\support\thd_internal.h">
<Filter>src\core\support</Filter>
</ClInclude>

Loading…
Cancel
Save