Initial import.

pull/1/merge
Nicolas Noble 10 years ago
parent 0e905e63db
commit b7ebd3b8c6
  1. 28
      LICENSE
  2. 4656
      Makefile
  3. 1012
      build.json
  4. 70
      include/grpc++/async_server.h
  5. 93
      include/grpc++/async_server_context.h
  6. 68
      include/grpc++/channel_interface.h
  7. 85
      include/grpc++/client_context.h
  8. 87
      include/grpc++/completion_queue.h
  9. 45
      include/grpc++/config.h
  10. 53
      include/grpc++/create_channel.h
  11. 95
      include/grpc++/credentials.h
  12. 111
      include/grpc++/server.h
  13. 75
      include/grpc++/server_builder.h
  14. 65
      include/grpc++/status.h
  15. 199
      include/grpc++/status_code_enum.h
  16. 178
      include/grpc++/stream.h
  17. 64
      include/grpc++/stream_context_interface.h
  18. 52
      include/grpc++/thread_pool_interface.h
  19. 50
      include/grpc/byte_buffer.h
  20. 49
      include/grpc/byte_buffer_reader.h
  21. 421
      include/grpc/grpc.h
  22. 143
      include/grpc/grpc_security.h
  23. 203
      include/grpc/status.h
  24. 58
      include/grpc/support/alloc.h
  25. 92
      include/grpc/support/atm.h
  26. 69
      include/grpc/support/atm_gcc_atomic.h
  27. 69
      include/grpc/support/atm_gcc_sync.h
  28. 94
      include/grpc/support/atm_win32.h
  29. 56
      include/grpc/support/cancellable_platform.h
  30. 95
      include/grpc/support/cmdline.h
  31. 66
      include/grpc/support/histogram.h
  32. 57
      include/grpc/support/host_port.h
  33. 91
      include/grpc/support/log.h
  34. 132
      include/grpc/support/port_platform.h
  35. 175
      include/grpc/support/slice.h
  36. 84
      include/grpc/support/slice_buffer.h
  37. 76
      include/grpc/support/string.h
  38. 348
      include/grpc/support/sync.h
  39. 55
      include/grpc/support/sync_generic.h
  40. 48
      include/grpc/support/sync_posix.h
  41. 52
      include/grpc/support/sync_win32.h
  42. 79
      include/grpc/support/thd.h
  43. 42
      include/grpc/support/thd_posix.h
  44. 44
      include/grpc/support/thd_win32.h
  45. 109
      include/grpc/support/time.h
  46. 43
      include/grpc/support/time_posix.h
  47. 46
      include/grpc/support/time_win32.h
  48. 45
      include/grpc/support/useful.h
  49. 155
      src/core/channel/call_op_string.c
  50. 189
      src/core/channel/census_filter.c
  51. 44
      src/core/channel/census_filter.h
  52. 112
      src/core/channel/channel_args.c
  53. 54
      src/core/channel/channel_args.h
  54. 223
      src/core/channel/channel_stack.c
  55. 288
      src/core/channel/channel_stack.h
  56. 641
      src/core/channel/client_channel.c
  57. 62
      src/core/channel/client_channel.h
  58. 239
      src/core/channel/client_setup.c
  59. 68
      src/core/channel/client_setup.h
  60. 501
      src/core/channel/connected_channel.c
  61. 49
      src/core/channel/connected_channel.h
  62. 143
      src/core/channel/http_client_filter.c
  63. 42
      src/core/channel/http_client_filter.h
  64. 139
      src/core/channel/http_filter.c
  65. 43
      src/core/channel/http_filter.h
  66. 150
      src/core/channel/http_server_filter.c
  67. 42
      src/core/channel/http_server_filter.h
  68. 198
      src/core/channel/metadata_buffer.c
  69. 70
      src/core/channel/metadata_buffer.h
  70. 138
      src/core/channel/noop_filter.c
  71. 44
      src/core/channel/noop_filter.h
  72. 49
      src/core/compression/algorithm.c
  73. 49
      src/core/compression/algorithm.h
  74. 193
      src/core/compression/message_compress.c
  75. 52
      src/core/compression/message_compress.h
  76. 49
      src/core/endpoint/endpoint.c
  77. 99
      src/core/endpoint/endpoint.h
  78. 195
      src/core/endpoint/resolve_address.c
  79. 67
      src/core/endpoint/resolve_address.h
  80. 335
      src/core/endpoint/secure_endpoint.c
  81. 47
      src/core/endpoint/secure_endpoint.h
  82. 105
      src/core/endpoint/socket_utils.c
  83. 58
      src/core/endpoint/socket_utils.h
  84. 52
      src/core/endpoint/socket_utils_linux.c
  85. 61
      src/core/endpoint/socket_utils_posix.c
  86. 570
      src/core/endpoint/tcp.c
  87. 55
      src/core/endpoint/tcp.h
  88. 170
      src/core/endpoint/tcp_client.c
  89. 50
      src/core/endpoint/tcp_client.h
  90. 282
      src/core/endpoint/tcp_server.c
  91. 64
      src/core/endpoint/tcp_server.h
  92. 664
      src/core/eventmanager/em.c
  93. 350
      src/core/eventmanager/em.h
  94. 56
      src/core/eventmanager/em_posix.c
  95. 38
      src/core/eventmanager/em_win32.c
  96. 121
      src/core/httpcli/format_request.c
  97. 45
      src/core/httpcli/format_request.h
  98. 259
      src/core/httpcli/httpcli.c
  99. 104
      src/core/httpcli/httpcli.h
  100. 128
      src/core/httpcli/httpcli_security_context.c
  101. Some files were not shown because too many files have changed in this diff Show More

@ -0,0 +1,28 @@
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.

4656
Makefile

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

@ -0,0 +1,70 @@
/*
*
* 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 __GRPCPP_ASYNC_SERVER_H__
#define __GRPCPP_ASYNC_SERVER_H__
#include <mutex>
#include <grpc++/config.h>
struct grpc_server;
namespace grpc {
class CompletionQueue;
class AsyncServer {
public:
explicit AsyncServer(CompletionQueue* cc);
~AsyncServer();
void AddPort(const grpc::string& addr);
void Start();
// The user has to call this to get one new rpc on the completion
// queue.
void RequestOneRpc();
void Shutdown();
private:
bool started_;
std::mutex shutdown_mu_;
bool shutdown_;
grpc_server* server_;
};
} // namespace grpc
#endif // __GRPCPP_ASYNC_SERVER_H__

@ -0,0 +1,93 @@
/*
*
* 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 __GRPCPP_ASYNC_SERVER_CONTEXT_H__
#define __GRPCPP_ASYNC_SERVER_CONTEXT_H__
#include <chrono>
#include <grpc++/config.h>
struct grpc_byte_buffer;
struct grpc_call;
struct grpc_completion_queue;
namespace google {
namespace protobuf {
class Message;
}
}
using std::chrono::system_clock;
namespace grpc {
class Status;
// TODO(rocking): wrap grpc c structures.
class AsyncServerContext {
public:
AsyncServerContext(grpc_call* call, const grpc::string& method,
const grpc::string& host,
system_clock::time_point absolute_deadline);
~AsyncServerContext();
// Accept this rpc, bind it to a completion queue.
void Accept(grpc_completion_queue* cq);
// Read and write calls, all async. Return true for success.
bool StartRead(google::protobuf::Message* request);
bool StartWrite(const google::protobuf::Message& response, int flags);
bool StartWriteStatus(const Status& status);
bool ParseRead(grpc_byte_buffer* read_buffer);
grpc::string method() const { return method_; }
grpc::string host() const { return host_; }
system_clock::time_point absolute_deadline() { return absolute_deadline_; }
private:
AsyncServerContext(const AsyncServerContext&);
AsyncServerContext& operator=(const AsyncServerContext&);
// These properties may be moved to a ServerContext class.
const grpc::string method_;
const grpc::string host_;
system_clock::time_point absolute_deadline_;
google::protobuf::Message* request_; // not owned
grpc_call* call_; // owned
};
} // namespace grpc
#endif // __GRPCPP_ASYNC_SERVER_CONTEXT_H__

@ -0,0 +1,68 @@
/*
*
* 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 __GRPCPP_CHANNEL_INTERFACE_H__
#define __GRPCPP_CHANNEL_INTERFACE_H__
#include <grpc++/status.h>
namespace google {
namespace protobuf {
class Message;
}
}
namespace grpc {
class ClientContext;
class RpcMethod;
class StreamContextInterface;
class ChannelInterface {
public:
virtual ~ChannelInterface() {}
virtual Status StartBlockingRpc(const RpcMethod& method,
ClientContext* context,
const google::protobuf::Message& request,
google::protobuf::Message* result) = 0;
virtual StreamContextInterface* CreateStream(const RpcMethod& method,
ClientContext* context,
const google::protobuf::Message* request,
google::protobuf::Message* result) = 0;
};
} // namespace grpc
#endif // __GRPCPP_CHANNEL_INTERFACE_H__

@ -0,0 +1,85 @@
/*
*
* 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 __GRPCPP_CLIENT_CONTEXT_H__
#define __GRPCPP_CLIENT_CONTEXT_H__
#include <chrono>
#include <string>
#include <vector>
#include <grpc++/config.h>
using std::chrono::system_clock;
struct grpc_call;
struct grpc_completion_queue;
namespace grpc {
class ClientContext {
public:
ClientContext();
~ClientContext();
void AddMetadata(const grpc::string &meta_key,
const grpc::string &meta_value);
void set_absolute_deadline(const system_clock::time_point &deadline);
system_clock::time_point absolute_deadline();
void StartCancel();
private:
// Disallow copy and assign.
ClientContext(const ClientContext &);
ClientContext &operator=(const ClientContext &);
friend class Channel;
friend class StreamContext;
grpc_call *call() { return call_; }
void set_call(grpc_call *call) { call_ = call; }
grpc_completion_queue *cq() { return cq_; }
void set_cq(grpc_completion_queue *cq) { cq_ = cq; }
grpc_call *call_;
grpc_completion_queue *cq_;
system_clock::time_point absolute_deadline_;
std::vector<std::pair<grpc::string, grpc::string> > metadata_;
};
} // namespace grpc
#endif // __GRPCPP_CLIENT_CONTEXT_H__

@ -0,0 +1,87 @@
/*
*
* 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 __GRPCPP_COMPLETION_QUEUE_H__
#define __GRPCPP_COMPLETION_QUEUE_H__
struct grpc_completion_queue;
namespace grpc {
// grpc_completion_queue wrapper class
class CompletionQueue {
public:
CompletionQueue();
~CompletionQueue();
enum CompletionType {
QUEUE_CLOSED = 0, // Shutting down.
RPC_END = 1, // An RPC finished. Either at client or server.
CLIENT_READ_OK = 2, // A client-side read has finished successfully.
CLIENT_READ_ERROR = 3, // A client-side read has finished with error.
CLIENT_WRITE_OK = 4,
CLIENT_WRITE_ERROR = 5,
SERVER_RPC_NEW = 6, // A new RPC just arrived at the server.
SERVER_READ_OK = 7, // A server-side read has finished successfully.
SERVER_READ_ERROR = 8, // A server-side read has finished with error.
SERVER_WRITE_OK = 9,
SERVER_WRITE_ERROR = 10,
// Client or server has sent half close successfully.
HALFCLOSE_OK = 11,
// New CompletionTypes may be added in the future, so user code should
// always
// handle the default case of a CompletionType that appears after such code
// was
// written.
DO_NOT_USE = 20,
};
// Blocking read from queue.
// For QUEUE_CLOSED, *tag is not changed.
// For SERVER_RPC_NEW, *tag will be a newly allocated AsyncServerContext.
// For others, *tag will be the AsyncServerContext of this rpc.
CompletionType Next(void** tag);
// Shutdown has to be called, and the CompletionQueue can only be
// destructed when the QUEUE_CLOSED message has been read with Next().
void Shutdown();
grpc_completion_queue* cq() { return cq_; }
private:
grpc_completion_queue* cq_; // owned
};
} // namespace grpc
#endif // __GRPCPP_COMPLETION_QUEUE_H__

@ -0,0 +1,45 @@
/*
*
* 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 __GRPCPP_CONFIG_H__
#define __GRPCPP_CONFIG_H__
#include <string>
namespace grpc {
typedef std::string string;
}
#endif // __GRPCPP_CONFIG_H__

@ -0,0 +1,53 @@
/*
*
* 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 __GRPCPP_CREATE_CHANNEL_H__
#define __GRPCPP_CREATE_CHANNEL_H__
#include <memory>
#include <grpc++/config.h>
#include <grpc++/credentials.h>
namespace grpc {
class ChannelInterface;
std::shared_ptr<ChannelInterface> CreateChannel(const grpc::string& target);
std::shared_ptr<ChannelInterface> CreateChannel(
const grpc::string& target,
const std::unique_ptr<grpc::Credentials>& creds);
} // namespace grpc
#endif // __GRPCPP_CREATE_CHANNEL_H__

@ -0,0 +1,95 @@
/*
*
* 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 __GRPCPP_CREDENTIALS_H_
#define __GRPCPP_CREDENTIALS_H_
#include <memory>
#include <grpc++/config.h>
struct grpc_credentials;
namespace grpc {
// grpc_credentials wrapper class. Typical use in C++ applications is limited
// to creating an instance using CredentialsFactory, and passing it down
// during channel construction.
class Credentials final {
public:
~Credentials();
// TODO(abhikumar): Specify a plugin API here to be implemented by
// credentials that do not have a corresponding implementation in C.
protected:
explicit Credentials(grpc_credentials*);
private:
grpc_credentials* GetRawCreds();
friend class CredentialsFactory;
grpc_credentials* creds_;
};
// Options used to build SslCredentials
struct SslCredentialsOptions {
grpc::string pem_root_certs;
grpc::string pem_private_key;
grpc::string pem_cert_chain;
};
// Factory for building different types of Credentials
class CredentialsFactory {
public:
// Builds credentials with reasonable defaults.
static std::unique_ptr<Credentials> DefaultCredentials();
// Builds SSL Credentials given SSL specific options
static std::unique_ptr<Credentials> SslCredentials(
const SslCredentialsOptions& options);
// Builds credentials for use when running in GCE
static std::unique_ptr<Credentials> ComputeEngineCredentials();
// Combines two credentials objects into a composite credentials
static std::unique_ptr<Credentials> ComposeCredentials(
const std::unique_ptr<Credentials>& creds1,
const std::unique_ptr<Credentials>& creds2);
};
} // namespace grpc
#endif // __GRPCPP_CREDENTIALS_H_

@ -0,0 +1,111 @@
/*
*
* 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 __GRPCPP_SERVER_H__
#define __GRPCPP_SERVER_H__
#include <condition_variable>
#include <map>
#include <memory>
#include <mutex>
#include <grpc++/completion_queue.h>
#include <grpc++/config.h>
#include <grpc++/status.h>
struct grpc_server;
namespace google {
namespace protobuf {
class Message;
}
}
namespace grpc {
class AsyncServerContext;
class RpcService;
class RpcServiceMethod;
class ThreadPoolInterface;
// Currently it only supports handling rpcs in a single thread.
class Server {
public:
~Server();
// Shutdown the server, block until all rpc processing finishes.
void Shutdown();
private:
friend class ServerBuilder;
// ServerBuilder use only
explicit Server(ThreadPoolInterface* thread_pool);
Server();
// Register a service. This call does not take ownership of the service.
// The service must exist for the lifetime of the Server instance.
void RegisterService(RpcService* service);
// Add a listening port. Can be called multiple times.
void AddPort(const grpc::string& addr);
// Start the server.
void Start();
void AllowOneRpc();
void HandleQueueClosed();
void RunRpc();
void ScheduleCallback();
// Completion queue.
CompletionQueue cq_;
// Sever status
std::mutex mu_;
bool started_;
bool shutdown_;
// The number of threads which are running callbacks.
int num_running_cb_;
std::condition_variable callback_cv_;
// Pointer to the c grpc server.
grpc_server* server_;
// A map for all method information.
std::map<grpc::string, RpcServiceMethod*> method_map_;
ThreadPoolInterface* thread_pool_;
// Whether the thread pool is created and owned by the server.
bool thread_pool_owned_;
};
} // namespace grpc
#endif // __GRPCPP_SERVER_H__

@ -0,0 +1,75 @@
/*
*
* 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 __GRPCPP_SERVER_BUILDER_H__
#define __GRPCPP_SERVER_BUILDER_H__
#include <memory>
#include <vector>
#include <grpc++/config.h>
namespace grpc {
class RpcService;
class Server;
class ThreadPoolInterface;
class ServerBuilder {
public:
ServerBuilder();
// Register a service. This call does not take ownership of the service.
// The service must exist for the lifetime of the Server instance returned by
// BuildAndStart().
void RegisterService(RpcService* service);
// Add a listening port. Can be called multiple times.
void AddPort(const grpc::string& addr);
// Set the thread pool used for running appliation rpc handlers.
// Does not take ownership.
void SetThreadPool(ThreadPoolInterface* thread_pool);
// Return a running server which is ready for processing rpcs.
std::unique_ptr<Server> BuildAndStart();
private:
std::vector<RpcService*> services_;
std::vector<grpc::string> ports_;
ThreadPoolInterface* thread_pool_;
};
} // namespace grpc
#endif // __GRPCPP_SERVER_BUILDER_H__

@ -0,0 +1,65 @@
/*
*
* 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 __GRPCPP_STATUS_H__
#define __GRPCPP_STATUS_H__
#include <grpc++/status_code_enum.h>
#include <grpc++/config.h>
namespace grpc {
class Status {
public:
Status() : code_(StatusCode::OK) {}
explicit Status(StatusCode code) : code_(code) {}
Status(StatusCode code, const grpc::string& details)
: code_(code), details_(details) {}
// Pre-defined special status objects.
static const Status& OK;
static const Status& Cancelled;
StatusCode code() const { return code_; }
grpc::string details() const { return details_; }
bool IsOk() const { return code_ == StatusCode::OK; }
private:
StatusCode code_;
grpc::string details_;
};
} // namespace grpc
#endif // __GRPCPP_STATUS_H__

@ -0,0 +1,199 @@
/*
*
* 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 __GRPCPP_STATUS_CODE_ENUM_H__
#define __GRPCPP_STATUS_CODE_ENUM_H__
namespace grpc {
enum StatusCode {
/* Not an error; returned on success
HTTP Mapping: 200 OK */
OK = 0,
/* The operation was cancelled (typically by the caller).
HTTP Mapping: 499 Client Closed Request */
CANCELLED = 1,
/* Unknown error. An example of where this error may be returned is
if a Status value received from another address space belongs to
an error-space that is not known in this address space. Also
errors raised by APIs that do not return enough error information
may be converted to this error.
HTTP Mapping: 500 Internal Server Error */
UNKNOWN = 2,
/* Client specified an invalid argument. Note that this differs
from FAILED_PRECONDITION. INVALID_ARGUMENT indicates arguments
that are problematic regardless of the state of the system
(e.g., a malformed file name).
HTTP Mapping: 400 Bad Request */
INVALID_ARGUMENT = 3,
/* Deadline expired before operation could complete. For operations
that change the state of the system, this error may be returned
even if the operation has completed successfully. For example, a
successful response from a server could have been delayed long
enough for the deadline to expire.
HTTP Mapping: 504 Gateway Timeout */
DEADLINE_EXCEEDED = 4,
/* Some requested entity (e.g., file or directory) was not found.
HTTP Mapping: 404 Not Found */
NOT_FOUND = 5,
/* Some entity that we attempted to create (e.g., file or directory)
already exists.
HTTP Mapping: 409 Conflict */
ALREADY_EXISTS = 6,
/* The caller does not have permission to execute the specified
operation. PERMISSION_DENIED must not be used for rejections
caused by exhausting some resource (use RESOURCE_EXHAUSTED
instead for those errors). PERMISSION_DENIED must not be
used if the caller can not be identified (use UNAUTHENTICATED
instead for those errors).
HTTP Mapping: 403 Forbidden */
PERMISSION_DENIED = 7,
/* The request does not have valid authentication credentials for the
operation.
HTTP Mapping: 401 Unauthorized */
UNAUTHENTICATED = 16,
/* Some resource has been exhausted, perhaps a per-user quota, or
perhaps the entire file system is out of space.
HTTP Mapping: 429 Too Many Requests */
RESOURCE_EXHAUSTED = 8,
/* Operation was rejected because the system is not in a state
required for the operation's execution. For example, directory
to be deleted may be non-empty, an rmdir operation is applied to
a non-directory, etc.
A litmus test that may help a service implementor in deciding
between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE:
(a) Use UNAVAILABLE if the client can retry just the failing call.
(b) Use ABORTED if the client should retry at a higher-level
(e.g., restarting a read-modify-write sequence).
(c) Use FAILED_PRECONDITION if the client should not retry until
the system state has been explicitly fixed. E.g., if an "rmdir"
fails because the directory is non-empty, FAILED_PRECONDITION
should be returned since the client should not retry unless
they have first fixed up the directory by deleting files from it.
(d) Use FAILED_PRECONDITION if the client performs conditional
REST Get/Update/Delete on a resource and the resource on the
server does not match the condition. E.g., conflicting
read-modify-write on the same resource.
HTTP Mapping: 400 Bad Request
NOTE: HTTP spec says 412 Precondition Failed should only be used if
the request contains Etag related headers. So if the server does see
Etag related headers in the request, it may choose to return 412
instead of 400 for this error code. */
FAILED_PRECONDITION = 9,
/* The operation was aborted, typically due to a concurrency issue
like sequencer check failures, transaction aborts, etc.
See litmus test above for deciding between FAILED_PRECONDITION,
ABORTED, and UNAVAILABLE.
HTTP Mapping: 409 Conflict */
ABORTED = 10,
/* Operation was attempted past the valid range. E.g., seeking or
reading past end of file.
Unlike INVALID_ARGUMENT, this error indicates a problem that may
be fixed if the system state changes. For example, a 32-bit file
system will generate INVALID_ARGUMENT if asked to read at an
offset that is not in the range [0,2^32-1], but it will generate
OUT_OF_RANGE if asked to read from an offset past the current
file size.
There is a fair bit of overlap between FAILED_PRECONDITION and
OUT_OF_RANGE. We recommend using OUT_OF_RANGE (the more specific
error) when it applies so that callers who are iterating through
a space can easily look for an OUT_OF_RANGE error to detect when
they are done.
HTTP Mapping: 400 Bad Request */
OUT_OF_RANGE = 11,
/* Operation is not implemented or not supported/enabled in this service.
HTTP Mapping: 501 Not Implemented */
UNIMPLEMENTED = 12,
/* Internal errors. Means some invariants expected by underlying
system has been broken. If you see one of these errors,
something is very broken.
HTTP Mapping: 500 Internal Server Error */
INTERNAL = 13,
/* The service is currently unavailable. This is a most likely a
transient condition and may be corrected by retrying with
a backoff.
See litmus test above for deciding between FAILED_PRECONDITION,
ABORTED, and UNAVAILABLE.
HTTP Mapping: 503 Service Unavailable */
UNAVAILABLE = 14,
/* Unrecoverable data loss or corruption.
HTTP Mapping: 500 Internal Server Error */
DATA_LOSS = 15,
/* Force users to include a default branch: */
DO_NOT_USE = -1
};
} // namespace grpc
#endif // __GRPCPP_STATUS_CODE_ENUM_H_

@ -0,0 +1,178 @@
/*
*
* 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 __GRPCPP_STREAM_H__
#define __GRPCPP_STREAM_H__
#include <grpc++/stream_context_interface.h>
#include <grpc++/status.h>
#include <grpc/support/log.h>
namespace grpc {
// Common interface for all client side streaming.
class ClientStreamingInterface {
public:
virtual ~ClientStreamingInterface() {}
// Try to cancel the stream. Wait() still needs to be called to get the final
// status. Cancelling after the stream has finished has no effects.
virtual void Cancel() = 0;
// Wait until the stream finishes, and return the final status. When the
// client side declares it has no more message to send, either implicitly or
// by calling WritesDone, it needs to make sure there is no more message to
// be received from the server, either implicitly or by getting a false from
// a Read(). Otherwise, this implicitly cancels the stream.
virtual const Status& Wait() = 0;
};
// An interface that yields a sequence of R messages.
template <class R>
class ReaderInterface {
public:
virtual ~ReaderInterface() {}
// Blocking read a message and parse to msg. Returns true on success.
// The method returns false when there will be no more incoming messages,
// either because the other side has called WritesDone or the stream has
// failed (or been cancelled).
virtual bool Read(R* msg) = 0;
};
// An interface that can be fed a sequence of W messages.
template <class W>
class WriterInterface {
public:
virtual ~WriterInterface() {}
// Blocking write msg to the stream. Returns true on success.
// Returns false when the stream has been closed.
virtual bool Write(const W& msg) = 0;
};
template <class R>
class ClientReader : public ClientStreamingInterface,
public ReaderInterface<R> {
public:
// Blocking create a stream and write the first request out.
explicit ClientReader(StreamContextInterface* context) : context_(context) {
GPR_ASSERT(context_);
context_->Start(true);
context_->Write(context_->request(), true);
}
~ClientReader() { delete context_; }
virtual bool Read(R* msg) { return context_->Read(msg); }
virtual void Cancel() { context_->FinishStream(Status::Cancelled, true); }
virtual const Status& Wait() { return context_->Wait(); }
private:
StreamContextInterface* const context_;
};
template <class W>
class ClientWriter : public ClientStreamingInterface,
public WriterInterface<W> {
public:
// Blocking create a stream.
explicit ClientWriter(StreamContextInterface* context) : context_(context) {
GPR_ASSERT(context_);
context_->Start(false);
}
~ClientWriter() { delete context_; }
virtual bool Write(const W& msg) {
return context_->Write(const_cast<W*>(&msg), false);
}
virtual void WritesDone() { context_->Write(nullptr, true); }
virtual void Cancel() { context_->FinishStream(Status::Cancelled, true); }
// Read the final response and wait for the final status.
virtual const Status& Wait() {
bool success = context_->Read(context_->response());
if (!success) {
Cancel();
} else {
success = context_->Read(nullptr);
if (success) {
Cancel();
}
}
return context_->Wait();
}
private:
StreamContextInterface* const context_;
};
// Client-side interface for bi-directional streaming.
template <class W, class R>
class ClientReaderWriter : public ClientStreamingInterface,
public WriterInterface<W>,
public ReaderInterface<R> {
public:
// Blocking create a stream.
explicit ClientReaderWriter(StreamContextInterface* context)
: context_(context) {
GPR_ASSERT(context_);
context_->Start(false);
}
~ClientReaderWriter() { delete context_; }
virtual bool Read(R* msg) { return context_->Read(msg); }
virtual bool Write(const W& msg) {
return context_->Write(const_cast<W*>(&msg), false);
}
virtual void WritesDone() { context_->Write(nullptr, true); }
virtual void Cancel() { context_->FinishStream(Status::Cancelled, true); }
virtual const Status& Wait() { return context_->Wait(); }
private:
StreamContextInterface* const context_;
};
} // namespace grpc
#endif // __GRPCPP_STREAM_H__

@ -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.
*
*/
#ifndef __GRPCPP_STREAM_CONTEXT_INTERFACE_H__
#define __GRPCPP_STREAM_CONTEXT_INTERFACE_H__
namespace google {
namespace protobuf {
class Message;
}
}
namespace grpc {
class Status;
// An interface to avoid dependency on internal implementation.
class StreamContextInterface {
public:
virtual ~StreamContextInterface() {}
virtual void Start(bool buffered) = 0;
virtual bool Read(google::protobuf::Message* msg) = 0;
virtual bool Write(const google::protobuf::Message* msg, bool is_last) = 0;
virtual const Status& Wait() = 0;
virtual void FinishStream(const Status& status, bool send) = 0;
virtual const google::protobuf::Message* request() = 0;
virtual google::protobuf::Message* response() = 0;
};
} // namespace grpc
#endif // __GRPCPP_STREAM_CONTEXT_INTERFACE_H__

@ -0,0 +1,52 @@
/*
*
* 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 __GRPCPP_THREAD_POOL_INTERFACE_H__
#define __GRPCPP_THREAD_POOL_INTERFACE_H__
#include <functional>
namespace grpc {
// A thread pool interface for running callbacks.
class ThreadPoolInterface {
public:
virtual ~ThreadPoolInterface() {}
// Schedule the given callback for execution.
virtual void ScheduleCallback(const std::function<void()>& callback) = 0;
};
} // namespace grpc
#endif // __GRPCPP_THREAD_POOL_INTERFACE_H__

@ -0,0 +1,50 @@
/*
*
* 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_BYTE_BUFFER_H__
#define __GRPC_BYTE_BUFFER_H__
#include <grpc/grpc.h>
#include <grpc/support/slice_buffer.h>
typedef enum { GRPC_BB_SLICE_BUFFER } grpc_byte_buffer_type;
/* byte buffers are what meesages are passed in as from the public api's */
struct grpc_byte_buffer {
grpc_byte_buffer_type type;
union {
gpr_slice_buffer slice_buffer;
} data;
};
#endif /* __GRPC_BYTE_BUFFER_H__ */

@ -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_BYTE_BUFFER_READER_H__
#define __GRPC_BYTE_BUFFER_READER_H__
#include <grpc/grpc.h>
#include <grpc/byte_buffer.h>
struct grpc_byte_buffer_reader {
grpc_byte_buffer *buffer;
/* Different current objects correspond to different types of byte buffers */
union {
/* Index into a slice buffer's array of slices */
int index;
} current;
};
#endif /* __GRPC_BYTE_BUFFER_READER_H__ */

@ -0,0 +1,421 @@
/*
*
* 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_GRPC_H__
#define __GRPC_GRPC_H__
#include <grpc/status.h>
#include <stddef.h>
#include <grpc/support/slice.h>
#include <grpc/support/time.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Completion Channels enable notification of the completion of asynchronous
actions. */
typedef struct grpc_completion_queue grpc_completion_queue;
/* The Channel interface allows creation of Call objects. */
typedef struct grpc_channel grpc_channel;
/* A server listens to some port and responds to request calls */
typedef struct grpc_server grpc_server;
/* A Call represents an RPC. When created, it is in a configuration state
allowing properties to be set until it is invoked. After invoke, the Call
can have messages written to it and read from it. */
typedef struct grpc_call grpc_call;
/* Type specifier for grpc_arg */
typedef enum {
GRPC_ARG_STRING,
GRPC_ARG_INTEGER,
GRPC_ARG_POINTER
} grpc_arg_type;
/* A single argument... each argument has a key and a value
A note on naming keys:
Keys are namespaced into groups, usually grouped by library, and are
keys for module XYZ are named XYZ.key1, XYZ.key2, etc. Module names must
be restricted to the regex [A-Za-z][_A-Za-z0-9]{,15}.
Key names must be restricted to the regex [A-Za-z][_A-Za-z0-9]{,47}.
GRPC core library keys are prefixed by grpc.
Library authors are strongly encouraged to #define symbolic constants for
their keys so that it's possible to change them in the future. */
typedef struct {
grpc_arg_type type;
char *key;
union {
char *string;
int integer;
struct {
void *p;
void *(*copy)(void *p);
void (*destroy)(void *p);
} pointer;
} value;
} grpc_arg;
/* An array of arguments that can be passed around */
typedef struct {
size_t num_args;
grpc_arg *args;
} grpc_channel_args;
/* Channel argument keys: */
/* Enable census for tracing and stats collection */
#define GRPC_ARG_ENABLE_CENSUS "grpc.census"
/* Maximum number of concurrent incoming streams to allow on a http2
connection */
#define GRPC_ARG_MAX_CONCURRENT_STREAMS "grpc.max_concurrent_streams"
/* Maximum message length that the channel can receive */
#define GRPC_ARG_MAX_MESSAGE_LENGTH "grpc.max_message_length"
/* Status of a completed call */
typedef struct grpc_status {
grpc_status_code code;
char *details;
} grpc_status;
/* Result of a grpc call. If the caller satisfies the prerequisites of a
particular operation, the grpc_call_error returned will be GRPC_CALL_OK.
Receiving any other value listed here is an indication of a bug in the
caller. */
typedef enum grpc_call_error {
/* everything went ok */
GRPC_CALL_OK = 0,
/* something failed, we don't know what */
GRPC_CALL_ERROR,
/* this method is not available on the server */
GRPC_CALL_ERROR_NOT_ON_SERVER,
/* this method is not available on the client */
GRPC_CALL_ERROR_NOT_ON_CLIENT,
/* this method must be called before invoke */
GRPC_CALL_ERROR_ALREADY_INVOKED,
/* this method must be called after invoke */
GRPC_CALL_ERROR_NOT_INVOKED,
/* this call is already finished
(writes_done or write_status has already been called) */
GRPC_CALL_ERROR_ALREADY_FINISHED,
/* there is already an outstanding read/write operation on the call */
GRPC_CALL_ERROR_TOO_MANY_OPERATIONS,
/* the flags value was illegal for this call */
GRPC_CALL_ERROR_INVALID_FLAGS
} grpc_call_error;
/* Result of a grpc operation */
typedef enum grpc_op_error {
/* everything went ok */
GRPC_OP_OK = 0,
/* something failed, we don't know what */
GRPC_OP_ERROR
} grpc_op_error;
/* Write Flags: */
/* Hint that the write may be buffered and need not go out on the wire
immediately. GRPC is free to buffer the message until the next non-buffered
write, or until writes_done, but it need not buffer completely or at all. */
#define GRPC_WRITE_BUFFER_HINT (0x00000001u)
/* Force compression to be disabled for a particular write
(start_write/add_metadata). Illegal on invoke/accept. */
#define GRPC_WRITE_NO_COMPRESS (0x00000002u)
/* A buffer of bytes */
struct grpc_byte_buffer;
typedef struct grpc_byte_buffer grpc_byte_buffer;
/* Sample helpers to obtain byte buffers (these will certainly move place */
grpc_byte_buffer *grpc_byte_buffer_create(gpr_slice *slices, size_t nslices);
size_t grpc_byte_buffer_length(grpc_byte_buffer *bb);
void grpc_byte_buffer_destroy(grpc_byte_buffer *byte_buffer);
/* Reader for byte buffers. Iterates over slices in the byte buffer */
struct grpc_byte_buffer_reader;
typedef struct grpc_byte_buffer_reader grpc_byte_buffer_reader;
grpc_byte_buffer_reader *grpc_byte_buffer_reader_create(
grpc_byte_buffer *buffer);
/* At the end of the stream, returns 0. Otherwise, returns 1 and sets slice to
be the returned slice. Caller is responsible for calling gpr_slice_unref on
the result. */
int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader *reader,
gpr_slice *slice);
void grpc_byte_buffer_reader_destroy(grpc_byte_buffer_reader *reader);
/* A single metadata element */
typedef struct grpc_metadata {
char *key;
char *value;
size_t value_length;
} grpc_metadata;
typedef enum grpc_completion_type {
GRPC_QUEUE_SHUTDOWN, /* Shutting down */
GRPC_READ, /* A read has completed */
GRPC_INVOKE_ACCEPTED, /* An invoke call has been accepted by flow
control */
GRPC_WRITE_ACCEPTED, /* A write has been accepted by
flow control */
GRPC_FINISH_ACCEPTED, /* writes_done or write_status has been accepted */
GRPC_CLIENT_METADATA_READ, /* The metadata array sent by server received at
client */
GRPC_FINISHED, /* An RPC has finished. The event contains status.
On the server this will be OK or Cancelled. */
GRPC_SERVER_RPC_NEW, /* A new RPC has arrived at the server */
GRPC_COMPLETION_DO_NOT_USE /* must be last, forces users to include
a default: case */
} grpc_completion_type;
typedef struct grpc_event {
grpc_completion_type type;
void *tag;
grpc_call *call;
/* Data associated with the completion type. Field names match the type of
completion as listed in grpc_completion_type. */
union {
/* Contains a pointer to the buffer that was read, or NULL at the end of a
stream. */
grpc_byte_buffer *read;
grpc_op_error write_accepted;
grpc_op_error finish_accepted;
grpc_op_error invoke_accepted;
struct {
size_t count;
grpc_metadata *elements;
} client_metadata_read;
grpc_status finished;
struct {
const char *method;
const char *host;
gpr_timespec deadline;
size_t metadata_count;
grpc_metadata *metadata_elements;
} server_rpc_new;
} data;
} grpc_event;
/* Initialize the grpc library */
void grpc_init();
/* Shutdown the grpc library */
void grpc_shutdown();
grpc_completion_queue *grpc_completion_queue_create();
/* Blocks until an event is available, the completion queue is being shutdown,
or deadline is reached. Returns NULL on timeout, otherwise the event that
occurred. Callers should call grpc_event_finish once they have processed
the event.
Callers must not call grpc_completion_queue_next and
grpc_completion_queue_pluck simultaneously on the same completion queue. */
grpc_event *grpc_completion_queue_next(grpc_completion_queue *cq,
gpr_timespec deadline);
/* Blocks until an event with tag 'tag' is available, the completion queue is
being shutdown or deadline is reached. Returns NULL on timeout, or a pointer
to the event that occurred. Callers should call grpc_event_finish once they
have processed the event.
Callers must not call grpc_completion_queue_next and
grpc_completion_queue_pluck simultaneously on the same completion queue. */
grpc_event *grpc_completion_queue_pluck(grpc_completion_queue *cq, void *tag,
gpr_timespec deadline);
/* Cleanup any data owned by the event */
void grpc_event_finish(grpc_event *event);
/* Begin destruction of a completion queue. Once all possible events are
drained it's safe to call grpc_completion_queue_destroy. */
void grpc_completion_queue_shutdown(grpc_completion_queue *cq);
/* Destroy a completion queue. The caller must ensure that the queue is
drained and no threads are executing grpc_completion_queue_next */
void grpc_completion_queue_destroy(grpc_completion_queue *cq);
/* Create a call given a grpc_channel, in order to call 'method'. The request
is not sent until grpc_call_invoke is called. All completions are sent to
'completion_queue'. */
grpc_call *grpc_channel_create_call(grpc_channel *channel, const char *method,
const char *host, gpr_timespec deadline);
/* Create a client channel */
grpc_channel *grpc_channel_create(const char *target,
const grpc_channel_args *args);
/* Close and destroy a grpc channel */
void grpc_channel_destroy(grpc_channel *channel);
/* THREAD-SAFETY for grpc_call
The following functions are thread-compatible for any given call:
grpc_call_add_metadata
grpc_call_invoke
grpc_call_start_write
grpc_call_writes_done
grpc_call_start_read
grpc_call_destroy
The function grpc_call_cancel is thread-safe, and can be called at any
point before grpc_call_destroy is called. */
/* Error handling for grpc_call
Most grpc_call functions return a grpc_error. If the error is not GRPC_OK
then the operation failed due to some unsatisfied precondition.
If a grpc_call fails, it's guaranteed that no change to the call state
has been made. */
/* Add a single metadata element to the call, to be sent upon invocation.
flags is a bit-field combination of the write flags defined above.
REQUIRES: grpc_call_start_invoke/grpc_call_accept have not been called on
this call.
Produces no events. */
grpc_call_error grpc_call_add_metadata(grpc_call *call, grpc_metadata *metadata,
gpr_uint32 flags);
/* Invoke the RPC. Starts sending metadata and request headers on the wire.
flags is a bit-field combination of the write flags defined above.
REQUIRES: Can be called at most once per call.
Can only be called on the client.
Produces a GRPC_INVOKE_ACCEPTED event with invoke_accepted_tag when the
call has been invoked (meaning bytes can start flowing to the wire).
Produces a GRPC_CLIENT_METADATA_READ event with metadata_read_tag when
the servers initial metadata has been read.
Produces a GRPC_FINISHED event with finished_tag when the call has been
completed (there may be other events for the call pending at this
time) */
grpc_call_error grpc_call_start_invoke(grpc_call *call,
grpc_completion_queue *cq,
void *invoke_accepted_tag,
void *metadata_read_tag,
void *finished_tag, gpr_uint32 flags);
/* Accept an incoming RPC, binding a completion queue to it.
To be called after adding metadata to the call, but before sending
messages.
flags is a bit-field combination of the write flags defined above.
REQUIRES: Can be called at most once per call.
Can only be called on the server.
Produces a GRPC_FINISHED event with finished_tag when the call has been
completed (there may be other events for the call pending at this
time) */
grpc_call_error grpc_call_accept(grpc_call *call, grpc_completion_queue *cq,
void *finished_tag, gpr_uint32 flags);
/* Called by clients to cancel an RPC on the server.
Can be called multiple times, from any thread. */
grpc_call_error grpc_call_cancel(grpc_call *call);
/* Queue a byte buffer for writing.
flags is a bit-field combination of the write flags defined above.
A write with byte_buffer null is allowed, and will not send any bytes on the
wire. If this is performed without GRPC_WRITE_BUFFER_HINT flag it provides
a mechanism to flush any previously buffered writes to outgoing flow control.
REQUIRES: No other writes are pending on the call. It is only safe to
start the next write after the corresponding write_accepted event
is received.
GRPC_INVOKE_ACCEPTED must have been received by the application
prior to calling this on the client. On the server,
grpc_call_accept must have been called successfully.
Produces a GRPC_WRITE_ACCEPTED event. */
grpc_call_error grpc_call_start_write(grpc_call *call,
grpc_byte_buffer *byte_buffer, void *tag,
gpr_uint32 flags);
/* Queue a status for writing.
REQUIRES: No other writes are pending on the call.
grpc_call_accept must have been called on the call prior to calling
this.
Only callable on the server.
Produces a GRPC_FINISH_ACCEPTED event when the status is sent. */
grpc_call_error grpc_call_start_write_status(grpc_call *call,
grpc_status status, void *tag);
/* No more messages to send.
REQUIRES: No other writes are pending on the call.
Only callable on the client.
Produces a GRPC_FINISH_ACCEPTED event when all bytes for the call have passed
outgoing flow control. */
grpc_call_error grpc_call_writes_done(grpc_call *call, void *tag);
/* Initiate a read on a call. Output event contains a byte buffer with the
result of the read.
REQUIRES: No other reads are pending on the call. It is only safe to start
the next read after the corresponding read event is received.
GRPC_INVOKE_ACCEPTED must have been received by the application
prior to calling this.
Produces a single GRPC_READ event. */
grpc_call_error grpc_call_start_read(grpc_call *call, void *tag);
/* Destroy a call. */
void grpc_call_destroy(grpc_call *call);
/* Request a call on a server.
Allows the server to create a single GRPC_SERVER_RPC_NEW event, with tag
tag_new.
If the call is subsequently cancelled, the cancellation will occur with tag
tag_cancel.
REQUIRES: Server must not have been shutdown.
NOTE: calling this is the only way to obtain GRPC_SERVER_RPC_NEW events. */
grpc_call_error grpc_server_request_call(grpc_server *server, void *tag_new);
/* Create a server */
grpc_server *grpc_server_create(grpc_completion_queue *cq,
const grpc_channel_args *args);
/* Add a http2 over tcp listener; returns 1 on success, 0 on failure
REQUIRES: server not started */
int grpc_server_add_http2_port(grpc_server *server, const char *addr);
/* Add a secure port to server; returns 1 on success, 0 on failure
REQUIRES: server not started */
int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr);
/* Start a server - tells all listeners to start listening */
void grpc_server_start(grpc_server *server);
/* Begin shutting down a server. */
void grpc_server_shutdown(grpc_server *server);
/* Destroy a server */
void grpc_server_destroy(grpc_server *server);
#ifdef __cplusplus
}
#endif
#endif /* __GRPC_GRPC_H__ */

@ -0,0 +1,143 @@
/*
*
* 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_SECURITY_H_
#define GRPC_SECURITY_H_
#include "grpc.h"
#include "status.h"
/* --- grpc_credentials object. ---
A credentials object represents a way to authenticate a client. */
typedef struct grpc_credentials grpc_credentials;
/* Releases a credentials object.
The creator of the credentials object is responsible for its release. */
void grpc_credentials_release(grpc_credentials *creds);
/* Creates default credentials. */
grpc_credentials *grpc_default_credentials_create(void);
/* Creates an SSL credentials object.
- pem_roots_cert is the buffer containing the PEM encoding of the server
root certificates. This parameter cannot be NULL.
- pem_roots_cert_size is the size of the associated buffer.
- pem_private_key is the buffer containing the PEM encoding of the client's
private key. This parameter can be NULL if the client does not have a
private key.
- pem_private_key_size is the size of the associated buffer.
- pem_cert_chain is the buffer containing the PEM encoding of the client's
certificate chain. This parameter can be NULL if the client does not have
a certificate chain.
- pem_cert_chain_size is the size of the associated buffer. */
grpc_credentials *grpc_ssl_credentials_create(
const unsigned char *pem_root_certs, size_t pem_root_certs_size,
const unsigned char *pem_private_key, size_t pem_private_key_size,
const unsigned char *pem_cert_chain, size_t pem_cert_chain_size);
/* Creates a composite credentials object. */
grpc_credentials *grpc_composite_credentials_create(grpc_credentials *creds1,
grpc_credentials *creds2);
/* Creates a compute engine credentials object. */
grpc_credentials *grpc_compute_engine_credentials_create(void);
/* Creates a fake transport security credentials object for testing. */
grpc_credentials *grpc_fake_transport_security_credentials_create(void);
/* --- Secure channel creation. --- */
/* The caller of the secure_channel_create functions may override the target
name used for SSL host name checking using this channel argument which is of
type GRPC_ARG_STRING. This *should* be used for testing only.
If this argument is not specified, the name used for SSL host name checking
will be the target parameter (assuming that the secure channel is an SSL
channel). If this parameter is specified and the underlying is not an SSL
channel, it will just be ignored. */
#define GRPC_SSL_TARGET_NAME_OVERRIDE_ARG "grpc.ssl_target_name_override"
/* Creates a default secure channel using the default credentials object using
the environment. */
grpc_channel *grpc_default_secure_channel_create(const char *target,
const grpc_channel_args *args);
/* Creates a secure channel using the passed-in credentials. */
grpc_channel *grpc_secure_channel_create(grpc_credentials *creds,
const char *target,
const grpc_channel_args *args);
/* --- grpc_server_credentials object. ---
A server credentials object represents a way to authenticate a server. */
typedef struct grpc_server_credentials grpc_server_credentials;
/* Releases a server_credentials object.
The creator of the server_credentials object is responsible for its release.
*/
void grpc_server_credentials_release(grpc_server_credentials *creds);
/* Creates an SSL server_credentials object.
TODO(jboeuf): Change the constructor so that it can support multiple
key/cert pairs.
- pem_roots_cert is the buffer containing the PEM encoding of the server
root certificates. This parameter may be NULL if the server does not want
the client to be authenticated with SSL.
- pem_roots_cert_size is the size of the associated buffer.
- pem_private_key is the buffer containing the PEM encoding of the client's
private key. This parameter cannot be NULL.
- pem_private_key_size is the size of the associated buffer.
- pem_cert_chain is the buffer containing the PEM encoding of the client's
certificate chain. This parameter cannot be NULL.
- pem_cert_chain_size is the size of the associated buffer. */
grpc_server_credentials *grpc_ssl_server_credentials_create(
const unsigned char *pem_root_certs, size_t pem_root_certs_size,
const unsigned char *pem_private_key, size_t pem_private_key_size,
const unsigned char *pem_cert_chain, size_t pem_cert_chain_size);
/* Creates a fake server transport security credentials object for testing. */
grpc_server_credentials *grpc_fake_transport_security_server_credentials_create(
void);
/* --- Secure server creation. --- */
/* Creates a secure server using the passed-in server credentials. */
grpc_server *grpc_secure_server_create(grpc_server_credentials *creds,
grpc_completion_queue *cq,
const grpc_channel_args *args);
#endif /* GRPC_SECURITY_H_ */

@ -0,0 +1,203 @@
/*
*
* 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_STATUS_H__
#define __GRPC_STATUS_H__
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
/* Not an error; returned on success
HTTP Mapping: 200 OK */
GRPC_STATUS_OK = 0,
/* The operation was cancelled (typically by the caller).
HTTP Mapping: 499 Client Closed Request */
GRPC_STATUS_CANCELLED = 1,
/* Unknown error. An example of where this error may be returned is
if a Status value received from another address space belongs to
an error-space that is not known in this address space. Also
errors raised by APIs that do not return enough error information
may be converted to this error.
HTTP Mapping: 500 Internal Server Error */
GRPC_STATUS_UNKNOWN = 2,
/* Client specified an invalid argument. Note that this differs
from FAILED_PRECONDITION. INVALID_ARGUMENT indicates arguments
that are problematic regardless of the state of the system
(e.g., a malformed file name).
HTTP Mapping: 400 Bad Request */
GRPC_STATUS_INVALID_ARGUMENT = 3,
/* Deadline expired before operation could complete. For operations
that change the state of the system, this error may be returned
even if the operation has completed successfully. For example, a
successful response from a server could have been delayed long
enough for the deadline to expire.
HTTP Mapping: 504 Gateway Timeout */
GRPC_STATUS_DEADLINE_EXCEEDED = 4,
/* Some requested entity (e.g., file or directory) was not found.
HTTP Mapping: 404 Not Found */
GRPC_STATUS_NOT_FOUND = 5,
/* Some entity that we attempted to create (e.g., file or directory)
already exists.
HTTP Mapping: 409 Conflict */
GRPC_STATUS_ALREADY_EXISTS = 6,
/* The caller does not have permission to execute the specified
operation. PERMISSION_DENIED must not be used for rejections
caused by exhausting some resource (use RESOURCE_EXHAUSTED
instead for those errors). PERMISSION_DENIED must not be
used if the caller can not be identified (use UNAUTHENTICATED
instead for those errors).
HTTP Mapping: 403 Forbidden */
GRPC_STATUS_PERMISSION_DENIED = 7,
/* The request does not have valid authentication credentials for the
operation.
HTTP Mapping: 401 Unauthorized */
GRPC_STATUS_UNAUTHENTICATED = 16,
/* Some resource has been exhausted, perhaps a per-user quota, or
perhaps the entire file system is out of space.
HTTP Mapping: 429 Too Many Requests */
GRPC_STATUS_RESOURCE_EXHAUSTED = 8,
/* Operation was rejected because the system is not in a state
required for the operation's execution. For example, directory
to be deleted may be non-empty, an rmdir operation is applied to
a non-directory, etc.
A litmus test that may help a service implementor in deciding
between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE:
(a) Use UNAVAILABLE if the client can retry just the failing call.
(b) Use ABORTED if the client should retry at a higher-level
(e.g., restarting a read-modify-write sequence).
(c) Use FAILED_PRECONDITION if the client should not retry until
the system state has been explicitly fixed. E.g., if an "rmdir"
fails because the directory is non-empty, FAILED_PRECONDITION
should be returned since the client should not retry unless
they have first fixed up the directory by deleting files from it.
(d) Use FAILED_PRECONDITION if the client performs conditional
REST Get/Update/Delete on a resource and the resource on the
server does not match the condition. E.g., conflicting
read-modify-write on the same resource.
HTTP Mapping: 400 Bad Request
NOTE: HTTP spec says 412 Precondition Failed should only be used if
the request contains Etag related headers. So if the server does see
Etag related headers in the request, it may choose to return 412
instead of 400 for this error code. */
GRPC_STATUS_FAILED_PRECONDITION = 9,
/* The operation was aborted, typically due to a concurrency issue
like sequencer check failures, transaction aborts, etc.
See litmus test above for deciding between FAILED_PRECONDITION,
ABORTED, and UNAVAILABLE.
HTTP Mapping: 409 Conflict */
GRPC_STATUS_ABORTED = 10,
/* Operation was attempted past the valid range. E.g., seeking or
reading past end of file.
Unlike INVALID_ARGUMENT, this error indicates a problem that may
be fixed if the system state changes. For example, a 32-bit file
system will generate INVALID_ARGUMENT if asked to read at an
offset that is not in the range [0,2^32-1], but it will generate
OUT_OF_RANGE if asked to read from an offset past the current
file size.
There is a fair bit of overlap between FAILED_PRECONDITION and
OUT_OF_RANGE. We recommend using OUT_OF_RANGE (the more specific
error) when it applies so that callers who are iterating through
a space can easily look for an OUT_OF_RANGE error to detect when
they are done.
HTTP Mapping: 400 Bad Request */
GRPC_STATUS_OUT_OF_RANGE = 11,
/* Operation is not implemented or not supported/enabled in this service.
HTTP Mapping: 501 Not Implemented */
GRPC_STATUS_UNIMPLEMENTED = 12,
/* Internal errors. Means some invariants expected by underlying
system has been broken. If you see one of these errors,
something is very broken.
HTTP Mapping: 500 Internal Server Error */
GRPC_STATUS_INTERNAL = 13,
/* The service is currently unavailable. This is a most likely a
transient condition and may be corrected by retrying with
a backoff.
See litmus test above for deciding between FAILED_PRECONDITION,
ABORTED, and UNAVAILABLE.
HTTP Mapping: 503 Service Unavailable */
GRPC_STATUS_UNAVAILABLE = 14,
/* Unrecoverable data loss or corruption.
HTTP Mapping: 500 Internal Server Error */
GRPC_STATUS_DATA_LOSS = 15,
/* Force users to include a default branch: */
GRPC_STATUS__DO_NOT_USE = -1
} grpc_status_code;
#ifdef __cplusplus
}
#endif
#endif /* __GRPC_STATUS_H__ */

@ -0,0 +1,58 @@
/*
*
* 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_ALLOC_H__
#define __GRPC_SUPPORT_ALLOC_H__
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/* malloc, never returns NULL */
void *gpr_malloc(size_t size);
/* free */
void gpr_free(void *ptr);
/* realloc, never returns NULL */
void *gpr_realloc(void *p, size_t size);
/* aligned malloc, never returns NULL, alignment must be power of 2 */
void *gpr_malloc_aligned(size_t size, size_t alignment);
/* free memory allocated by gpr_malloc_aligned */
void gpr_free_aligned(void *ptr);
#ifdef __cplusplus
}
#endif
#endif /* __GRPC_SUPPORT_ALLOC_H__ */

@ -0,0 +1,92 @@
/*
*
* 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_ATM_H__
#define __GRPC_SUPPORT_ATM_H__
/* This interface provides atomic operations and barriers.
It is internal to gpr support code and should not be used outside it.
If an operation with acquire semantics precedes another memory access by the
same thread, the operation will precede that other access as seen by other
threads.
If an operation with release semantics follows another memory access by the
same thread, the operation will follow that other access as seen by other
threads.
Routines with "acq" or "full" in the name have acquire semantics. Routines
with "rel" or "full" in the name have release semantics. Routines with
"no_barrier" in the name have neither acquire not release semantics.
The routines may be implemented as macros.
// Atomic operations acton an intergral_type gpr_atm that is guaranteed to
// be the same size as a pointer.
typedef gpr_intptr gpr_atm;
// A memory barrier, providing both acquire and release semantics, but not
// otherwise acting no memory.
void gpr_atm_full_barrier(void);
// Atomically return *p, with acquire semantics.
gpr_atm gpr_atm_acq_load(gpr_atm *p);
// Atomically set *p = value, with release semantics.
void gpr_atm_rel_store(gpr_atm *p, gpr_atm value);
// Atomically add delta to *p, and return the old value of *p, with
// the barriers specified.
gpr_atm gpr_atm_no_barrier_fetch_add(gpr_atm *p, gpr_atm delta);
gpr_atm gpr_atm_full_fetch_add(gpr_atm *p, gpr_atm delta);
// Atomically, if *p==o, set *p=n and return non-zero otherwise return 0,
// with the barriers specified if the operation succeeds.
int gpr_atm_no_barrier_cas(gpr_atm *p, gpr_atm o, gpr_atm n);
int gpr_atm_acq_cas(gpr_atm *p, gpr_atm o, gpr_atm n);
int gpr_atm_rel_cas(gpr_atm *p, gpr_atm o, gpr_atm n);
*/
#include <grpc/support/port_platform.h>
#if defined(GPR_GCC_ATOMIC)
#include <grpc/support/atm_gcc_atomic.h>
#elif defined(GPR_GCC_SYNC)
#include <grpc/support/atm_gcc_sync.h>
#elif defined(GPR_WIN32)
#include <grpc/support/atm_win32.h>
#else
#error could not determine platform for atm
#endif
#endif /* __GRPC_SUPPORT_ATM_H__ */

@ -0,0 +1,69 @@
/*
*
* 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_ATM_GCC_ATOMIC_H__
#define __GRPC_SUPPORT_ATM_GCC_ATOMIC_H__
/* atm_platform.h for gcc and gcc-like compilers with the
__atomic_* interface. */
#include <grpc/support/port_platform.h>
typedef gpr_intptr gpr_atm;
#define gpr_atm_full_barrier() (__atomic_thread_fence(__ATOMIC_SEQ_CST))
#define gpr_atm_acq_load(p) (__atomic_load_n((p), __ATOMIC_ACQUIRE))
#define gpr_atm_rel_store(p, value) \
(__atomic_store_n((p), (gpr_intptr)(value), __ATOMIC_RELEASE))
#define gpr_atm_no_barrier_fetch_add(p, delta) \
(__atomic_fetch_add((p), (gpr_intptr)(delta), __ATOMIC_RELAXED))
#define gpr_atm_full_fetch_add(p, delta) \
(__atomic_fetch_add((p), (gpr_intptr)(delta), __ATOMIC_ACQ_REL))
static __inline int gpr_atm_no_barrier_cas(gpr_atm *p, gpr_atm o, gpr_atm n) {
return __atomic_compare_exchange_n(p, &o, n, 0, __ATOMIC_RELAXED,
__ATOMIC_RELAXED);
}
static __inline int gpr_atm_acq_cas(gpr_atm *p, gpr_atm o, gpr_atm n) {
return __atomic_compare_exchange_n(p, &o, n, 0, __ATOMIC_ACQUIRE,
__ATOMIC_RELAXED);
}
static __inline int gpr_atm_rel_cas(gpr_atm *p, gpr_atm o, gpr_atm n) {
return __atomic_compare_exchange_n(p, &o, n, 0, __ATOMIC_RELEASE,
__ATOMIC_RELAXED);
}
#endif /* __GRPC_SUPPORT_ATM_GCC_ATOMIC_H__ */

@ -0,0 +1,69 @@
/*
*
* 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_ATM_GCC_SYNC_H__
#define __GRPC_SUPPORT_ATM_GCC_SYNC_H__
/* atm_platform.h for gcc and gcc-like compilers with the
__atomic_* interface. */
#include <grpc/support/port_platform.h>
typedef gpr_intptr gpr_atm;
#define gpr_atm_full_barrier() (__atomic_thread_fence(__ATOMIC_SEQ_CST))
#define gpr_atm_acq_load(p) (__atomic_load_n((p), __ATOMIC_ACQUIRE))
#define gpr_atm_rel_store(p, value) \
(__atomic_store_n((p), (gpr_intptr)(value), __ATOMIC_RELEASE))
#define gpr_atm_no_barrier_fetch_add(p, delta) \
(__atomic_fetch_add((p), (gpr_intptr)(delta), __ATOMIC_RELAXED))
#define gpr_atm_full_fetch_add(p, delta) \
(__atomic_fetch_add((p), (gpr_intptr)(delta), __ATOMIC_ACQ_REL))
static __inline int gpr_atm_no_barrier_cas(gpr_atm *p, gpr_atm o, gpr_atm n) {
return __atomic_compare_exchange_n(p, &o, n, 0, __ATOMIC_RELAXED,
__ATOMIC_RELAXED);
}
static __inline int gpr_atm_acq_cas(gpr_atm *p, gpr_atm o, gpr_atm n) {
return __atomic_compare_exchange_n(p, &o, n, 0, __ATOMIC_ACQUIRE,
__ATOMIC_RELAXED);
}
static __inline int gpr_atm_rel_cas(gpr_atm *p, gpr_atm o, gpr_atm n) {
return __atomic_compare_exchange_n(p, &o, n, 0, __ATOMIC_RELEASE,
__ATOMIC_RELAXED);
}
#endif /* __GRPC_SUPPORT_ATM_GCC_SYNC_H__ */

@ -0,0 +1,94 @@
/*
*
* 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_ATM_WIN32_H__
#define __GRPC_SUPPORT_ATM_WIN32_H__
/* Win32 variant of atm_platform.h */
#include <grpc/support/port_platform.h>
#include <windows.h>
typedef gpr_intptr gpr_atm;
#define gpr_atm_full_barrier MemoryBarrier
static __inline gpr_atm gpr_atm_acq_load(const gpr_atm *p) {
gpr_atm result = *p;
gpr_atm_full_barrier();
return result;
}
static __inline void gpr_atm_rel_store(gpr_atm *p, gpr_atm value) {
gpr_atm_full_barrier();
*p = value;
}
static __inline int gpr_atm_no_barrier_cas(gpr_atm *p, gpr_atm o, gpr_atm n) {
/* InterlockedCompareExchangePointerNoFence() not available on vista or
windows7 */
return o == (gpr_atm)InterlockedCompareExchangePointerAcquire(p, (void *)n,
(void *)o);
}
static __inline int gpr_atm_acq_cas(gpr_atm *p, gpr_atm o, gpr_atm n) {
return o == (gpr_atm)InterlockedCompareExchangePointerAcquire(p, (void *)n,
(void *)o);
}
static __inline int gpr_atm_rel_cas(gpr_atm *p, gpr_atm o, gpr_atm n) {
return o == (gpr_atm)InterlockedCompareExchangePointerRelease(p, (void *)n,
(void *)o);
}
static __inline gpr_atm gpr_atm_no_barrier_fetch_add(gpr_atm *p,
gpr_atm delta) {
/* Use the CAS operation to get pointer-sized fetch and add */
gpr_atm old;
do {
old = *p;
} while (!gpr_atm_no_barrier_cas(p, old, old + delta));
return old;
}
static __inline gpr_atm gpr_atm_full_fetch_add(gpr_atm *p, gpr_atm delta) {
/* Use a CAS operation to get pointer-sized fetch and add */
gpr_atm old;
do {
old = *p;
} while (old != (gpr_atm)InterlockedCompareExchangePointer(
p, (void *)(old + delta), (void *)old));
return old;
}
#endif /* __GRPC_SUPPORT_ATM_WIN32_H__ */

@ -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.
*
*/
#ifndef __GRPC_SUPPORT_CANCELLABLE_PLATFORM_H__
#define __GRPC_SUPPORT_CANCELLABLE_PLATFORM_H__
#include <grpc/support/atm.h>
#include <grpc/support/sync.h>
struct gpr_cancellable_list_ {
/* a doubly-linked list on cancellable's waiters queue */
struct gpr_cancellable_list_ *next;
struct gpr_cancellable_list_ *prev;
/* The following two fields are arguments to gpr_cv_cancellable_wait() */
gpr_mu *mu;
gpr_cv *cv;
};
/* Internal definition of gpr_cancellable. */
typedef struct {
gpr_mu mu; /* protects waiters and modifications to cancelled */
gpr_atm cancelled;
struct gpr_cancellable_list_ waiters;
} gpr_cancellable;
#endif /* __GRPC_SUPPORT_CANCELLABLE_PLATFORM_H__ */

@ -0,0 +1,95 @@
/*
*
* 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_CMDLINE_H__
#define __GRPC_SUPPORT_CMDLINE_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Simple command line parser.
Supports flags that can be specified as -foo, --foo, --no-foo, -no-foo, etc
And integers, strings that can be specified as -foo=4, -foo blah, etc
No support for short command line options (but we may get that in the
future.)
Usage (for a program with a single flag argument 'foo'):
int main(int argc, char **argv) {
gpr_cmdline *cl;
int verbose = 0;
cl = gpr_cmdline_create("My cool tool");
gpr_cmdline_add_int(cl, "verbose", "Produce verbose output?", &verbose);
gpr_cmdline_parse(cl, argc, argv);
gpr_cmdline_destroy(cl);
if (verbose) {
gpr_log(GPR_INFO, "Goodbye cruel world!");
}
return 0;
} */
typedef struct gpr_cmdline gpr_cmdline;
/* Construct a command line parser: takes a short description of the tool
doing the parsing */
gpr_cmdline *gpr_cmdline_create(const char *description);
/* Add an integer parameter, with a name (used on the command line) and some
helpful text (used in the command usage) */
void gpr_cmdline_add_int(gpr_cmdline *cl, const char *name, const char *help,
int *value);
/* The same, for a boolean flag */
void gpr_cmdline_add_flag(gpr_cmdline *cl, const char *name, const char *help,
int *value);
/* And for a string */
void gpr_cmdline_add_string(gpr_cmdline *cl, const char *name, const char *help,
char **value);
/* Set a callback for non-named arguments */
void gpr_cmdline_on_extra_arg(
gpr_cmdline *cl, const char *name, const char *help,
void (*on_extra_arg)(void *user_data, const char *arg), void *user_data);
/* Parse the command line */
void gpr_cmdline_parse(gpr_cmdline *cl, int argc, char **argv);
/* Destroy the parser */
void gpr_cmdline_destroy(gpr_cmdline *cl);
#ifdef __cplusplus
}
#endif
#endif /* __GRPC_SUPPORT_CMDLINE_H__ */

@ -0,0 +1,66 @@
/*
*
* 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_HISTOGRAM_H__
#define __GRPC_SUPPORT_HISTOGRAM_H__
#ifdef __cplusplus
extern "C" {
#endif
typedef struct gpr_histogram gpr_histogram;
gpr_histogram *gpr_histogram_create(double resolution, double max_bucket_start);
void gpr_histogram_destroy(gpr_histogram *h);
void gpr_histogram_add(gpr_histogram *h, double x);
/* The following merges the second histogram into the first. It only works
if they have the same buckets and resolution. Returns 0 on failure, 1
on success */
int gpr_histogram_merge(gpr_histogram *dst, gpr_histogram *src);
double gpr_histogram_percentile(gpr_histogram *histogram, double percentile);
double gpr_histogram_mean(gpr_histogram *histogram);
double gpr_histogram_stddev(gpr_histogram *histogram);
double gpr_histogram_variance(gpr_histogram *histogram);
double gpr_histogram_maximum(gpr_histogram *histogram);
double gpr_histogram_minimum(gpr_histogram *histogram);
double gpr_histogram_count(gpr_histogram *histogram);
double gpr_histogram_sum(gpr_histogram *histogram);
double gpr_histogram_sum_of_squares(gpr_histogram *histogram);
#ifdef __cplusplus
}
#endif
#endif /* __GRPC_SUPPORT_HISTOGRAM_H__ */

@ -0,0 +1,57 @@
/*
*
* 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_HOST_PORT_H__
#define __GRPC_SUPPORT_HOST_PORT_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Given a host and port, creates a newly-allocated string of the form
"host:port" or "[ho:st]:port", depending on whether the host contains colons
like an IPv6 literal. If the host is already bracketed, then additional
brackets will not be added.
Usage is similar to gpr_asprintf: returns the number of bytes written
(excluding the final '\0'), and *out points to a string which must later be
destroyed using gpr_free().
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);
#ifdef __cplusplus
}
#endif
#endif /* __GRPC_SUPPORT_HOST_PORT_H__ */

@ -0,0 +1,91 @@
/*
*
* 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_LOG_H__
#define __GRPC_SUPPORT_LOG_H__
#include <stdlib.h> /* for abort() */
#ifdef __cplusplus
extern "C" {
#endif
/* GPR log API.
Usage (within grpc):
int argument1 = 3;
char* argument2 = "hello";
gpr_log(GPR_DEBUG, "format string %d", argument1);
gpr_log(GPR_INFO, "hello world");
gpr_log(GPR_ERROR, "%d %s!!", argument1, argument2); */
/* The severity of a log message - use the #defines below when calling into
gpr_log to additionally supply file and line data */
typedef enum gpr_log_severity {
GPR_LOG_SEVERITY_DEBUG,
GPR_LOG_SEVERITY_INFO,
GPR_LOG_SEVERITY_ERROR
} gpr_log_severity;
/* Returns a string representation of the log severity */
const char *gpr_log_severity_string(gpr_log_severity severity);
/* Macros to build log contexts at various severity levels */
#define GPR_DEBUG __FILE__, __LINE__, GPR_LOG_SEVERITY_DEBUG
#define GPR_INFO __FILE__, __LINE__, GPR_LOG_SEVERITY_INFO
#define GPR_ERROR __FILE__, __LINE__, GPR_LOG_SEVERITY_ERROR
/* Log a message. It's advised to use GPR_xxx above to generate the context
* for each message */
void gpr_log(const char *file, int line, gpr_log_severity severity,
const char *format, ...);
/* abort() the process if x is zero, having written a line to the log.
Intended for internal invariants. If the error can be recovered from,
without the possibility of corruption, or might best be reflected via
an exception in a higher-level language, consider returning error code. */
#define GPR_ASSERT(x) \
do { \
if (!(x)) { \
gpr_log(GPR_ERROR, "assertion failed: %s", #x); \
abort(); \
} \
} while (0)
#ifdef __cplusplus
}
#endif
#endif /* __GRPC_SUPPORT_LOG_H__ */

@ -0,0 +1,132 @@
/*
*
* 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_PORT_PLATFORM_H__
#define __GRPC_SUPPORT_PORT_PLATFORM_H__
/* Override this file with one for your platform if you need to redefine
things. */
/* For a common case, assume that the platform has a C99-like stdint.h */
#include <stdint.h>
#if !defined(GPR_NO_AUTODETECT_PLATFORM)
#if defined(_WIN64) || defined(WIN64)
#define GPR_WIN32 1
#define GPR_ARCH_64 1
#define GPR_POSIX_SOCKETUTILS 1
#elif defined(_WIN32) || defined(WIN32)
#define GPR_WIN32 1
#define GPR_ARCH_32 1
#define GPR_POSIX_SOCKETUTILS 1
#elif defined(ANDROID) || defined(__ANDROID__)
#define GPR_POSIX_TIME 1
#define GPR_POSIX_SYNC 1
#define GPR_POSIX_SOCKETUTILS 1
#define GPR_ANDROID 1
#define GPR_GCC_SYNC 1
#define GPR_ARCH_32 1
#elif defined(__linux__)
#define GPR_POSIX_TIME 1
#define GPR_POSIX_SYNC 1
#define GPR_LINUX 1
#define GPR_GCC_ATOMIC 1
#ifdef _LP64
#define GPR_ARCH_64 1
#else /* _LP64 */
#define GPR_ARCH_32 1
#endif /* _LP64 */
#elif defined(__APPLE__)
#define GPR_POSIX_TIME 1
#define GPR_POSIX_SYNC 1
#define GPR_POSIX_LOG 1
#define GPR_POSIX_SOCKETUTILS 1
#define GPR_GCC_ATOMIC 1
#ifdef _LP64
#define GPR_ARCH_64 1
#else /* _LP64 */
#define GPR_ARCH_32 1
#endif /* _LP64 */
#else
#error Could not auto-detect platform
#endif
#endif /* GPR_NO_AUTODETECT_PLATFORM */
/* Cache line alignment */
#ifndef GPR_CACHELINE_SIZE
#if defined(__i386__) || defined(__x86_64__)
#define GPR_CACHELINE_SIZE 64
#endif
#ifndef GPR_CACHELINE_SIZE
/* A reasonable default guess. Note that overestimates tend to waste more
space, while underestimates tend to waste more time. */
#define GPR_CACHELINE_SIZE 64
#endif /* GPR_CACHELINE_SIZE */
#endif /* GPR_CACHELINE_SIZE */
/* scrub GCC_ATOMIC if it's not available on this compiler */
#if defined(GPR_GCC_ATOMIC) && !defined(__ATOMIC_RELAXED)
#undef GPR_GCC_ATOMIC
#define GPR_GCC_SYNC 1
#endif
/* Validate platform combinations */
#if defined(GPR_GCC_ATOMIC) + defined(GPR_GCC_SYNC) + defined(GPR_WIN32) != 1
#error Must define exactly one of GPR_GCC_ATOMIC, GPR_GCC_SYNC, GPR_WIN32
#endif
#if defined(GPR_ARCH_32) + defined(GPR_ARCH_64) != 1
#error Must define exactly one of GPR_ARCH_32, GPR_ARCH_64
#endif
typedef int16_t gpr_int16;
typedef int32_t gpr_int32;
typedef int64_t gpr_int64;
typedef uint8_t gpr_uint8;
typedef uint16_t gpr_uint16;
typedef uint32_t gpr_uint32;
typedef uint64_t gpr_uint64;
typedef intmax_t gpr_intmax;
typedef intptr_t gpr_intptr;
typedef uintmax_t gpr_uintmax;
typedef uintptr_t gpr_uintptr;
/* INT64_MAX is unavailable on some platforms. */
#define GPR_INT64_MAX (~(gpr_uint64)0 >> 1)
/* maximum alignment needed for any type on this platform, rounded up to a
power of two */
#define GPR_MAX_ALIGNMENT 16
#endif /* __GRPC_SUPPORT_PORT_PLATFORM_H__ */

@ -0,0 +1,175 @@
/*
*
* 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_SLICE_H__
#define __GRPC_SUPPORT_SLICE_H__
#include <grpc/support/sync.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Slice API
A slice represents a contiguous reference counted array of bytes.
It is cheap to take references to a slice, and it is cheap to create a
slice pointing to a subset of another slice.
The data-structure for slices is exposed here to allow non-gpr code to
build slices from whatever data they have available.
When defining interfaces that handle slices, care should be taken to define
reference ownership semantics (who should call unref?) and mutability
constraints (is the callee allowed to modify the slice?) */
/* Reference count container for gpr_slice. Contains function pointers to
increment and decrement reference counts. Implementations should cleanup
when the reference count drops to zero.
Typically client code should not touch this, and use gpr_slice_malloc,
gpr_slice_new, or gpr_slice_new_with_len instead. */
typedef struct gpr_slice_refcount {
void (*ref)(void *);
void (*unref)(void *);
} gpr_slice_refcount;
#define GPR_SLICE_INLINED_SIZE (sizeof(size_t) + sizeof(gpr_uint8 *) - 1)
/* A gpr_slice s, if initialized, represents the byte range
s.bytes[0..s.length-1].
It can have an associated ref count which has a destruction routine to be run
when the ref count reaches zero (see gpr_slice_new() and grp_slice_unref()).
Multiple gpr_slice values may share a ref count.
If the slice does not have a refcount, it represents an inlined small piece
of data that is copied by value. */
typedef struct gpr_slice {
struct gpr_slice_refcount *refcount;
union {
struct {
gpr_uint8 *bytes;
size_t length;
} refcounted;
struct {
gpr_uint8 length;
gpr_uint8 bytes[GPR_SLICE_INLINED_SIZE];
} inlined;
} data;
} gpr_slice;
#define GPR_SLICE_START_PTR(slice) \
((slice).refcount ? (slice).data.refcounted.bytes \
: (slice).data.inlined.bytes)
#define GPR_SLICE_LENGTH(slice) \
((slice).refcount ? (slice).data.refcounted.length \
: (slice).data.inlined.length)
#define GPR_SLICE_SET_LENGTH(slice, newlen) \
((slice).refcount ? ((slice).data.refcounted.length = (newlen)) \
: ((slice).data.inlined.length = (newlen)))
#define GPR_SLICE_END_PTR(slice) \
GPR_SLICE_START_PTR(slice) + GPR_SLICE_LENGTH(slice)
/* Increment the refcount of s. Requires slice is initialized.
Returns s. */
gpr_slice gpr_slice_ref(gpr_slice s);
/* Decrement the ref count of s. If the ref count of s reaches zero, all
slices sharing the ref count are destroyed, and considered no longer
initialized. If s is ultimately derived from a call to gpr_slice_new(start,
len, dest) where dest!=NULL , then (*dest)(start, len) is called. Requires
s initialized. */
void gpr_slice_unref(gpr_slice s);
/* Create a slice pointing at some data. Calls malloc to allocate a refcount
for the object, and arranges that destroy will be called with the pointer
passed in at destruction. */
gpr_slice gpr_slice_new(void *p, size_t len, void (*destroy)(void *));
/* Equivalent to gpr_slice_new, but with a two argument destroy function that
also takes the slice length. */
gpr_slice gpr_slice_new_with_len(void *p, size_t len,
void (*destroy)(void *, size_t));
/* Equivalent to gpr_slice_new(malloc(len), len, free), but saves one malloc()
call.
Aborts if malloc() fails. */
gpr_slice gpr_slice_malloc(size_t length);
/* Create a slice by copying a string.
Does not preserve null terminators.
Equivalent to:
size_t len = strlen(source);
gpr_slice slice = gpr_slice_malloc(len);
memcpy(slice->data, source, len); */
gpr_slice gpr_slice_from_copied_string(const char *source);
/* Create a slice by copying a buffer.
Equivalent to:
gpr_slice slice = gpr_slice_malloc(len);
memcpy(slice->data, source, len); */
gpr_slice gpr_slice_from_copied_buffer(const char *source, size_t len);
/* Return a result slice derived from s, which shares a ref count with s, where
result.data==s.data+begin, and result.length==end-begin.
The ref count of s is increased by one.
Requires s initialized, begin <= end, begin <= s.length, and
end <= source->length. */
gpr_slice gpr_slice_sub(gpr_slice s, size_t begin, size_t end);
/* The same as gpr_slice_sub, but without altering the ref count */
gpr_slice gpr_slice_sub_no_ref(gpr_slice s, size_t begin, size_t end);
/* Splits s into two: modifies s to be s[0:split], and returns a new slice,
sharing a refcount with s, that contains s[split:s.length].
Requires s intialized, split <= s.length */
gpr_slice gpr_slice_split_tail(gpr_slice *s, size_t split);
/* Splits s into two: modifies s to be s[split:s.length], and returns a new
slice, sharing a refcount with s, that contains s[0:split].
Requires s intialized, split <= s.length */
gpr_slice gpr_slice_split_head(gpr_slice *s, size_t split);
gpr_slice gpr_empty_slice();
/* Returns <0 if a < b, ==0 if a == b, >0 if a > b */
int gpr_slice_cmp(gpr_slice a, gpr_slice b);
int gpr_slice_str_cmp(gpr_slice a, const char *b);
#ifdef __cplusplus
}
#endif
#endif /* __GRPC_SUPPORT_SLICE_H__ */

@ -0,0 +1,84 @@
/*
*
* 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_SLICE_BUFFER_H__
#define __GRPC_SUPPORT_SLICE_BUFFER_H__
#include <grpc/support/slice.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Represents an expandable array of slices, to be interpreted as a single item
TODO(ctiller): inline some small number of elements into the struct, to
avoid per-call allocations */
typedef struct {
/* slices in the array */
gpr_slice *slices;
/* the number of slices in the array */
size_t count;
/* the number of slices allocated in the array */
size_t capacity;
/* the combined length of all slices in the array */
size_t length;
} gpr_slice_buffer;
/* initialize a slice buffer */
void gpr_slice_buffer_init(gpr_slice_buffer *sb);
/* destroy a slice buffer - unrefs any held elements */
void gpr_slice_buffer_destroy(gpr_slice_buffer *sb);
/* Add an element to a slice buffer - takes ownership of the slice.
This function is allowed to concatenate the passed in slice to the end of
some other slice if desired by the slice buffer. */
void gpr_slice_buffer_add(gpr_slice_buffer *sb, gpr_slice slice);
/* add an element to a slice buffer - takes ownership of the slice and returns
the index of the slice.
Guarantees that the slice will not be concatenated at the end of another
slice (i.e. the data for this slice will begin at the first byte of the
slice at the returned index in sb->slices)
The implementation MAY decide to concatenate data at the end of a small
slice added in this fashion. */
size_t gpr_slice_buffer_add_indexed(gpr_slice_buffer *sb, gpr_slice slice);
void gpr_slice_buffer_addn(gpr_slice_buffer *sb, gpr_slice *slices, size_t n);
/* add a very small (less than 8 bytes) amount of data to the end of a slice
buffer: returns a pointer into which to add the data */
gpr_uint8 *gpr_slice_buffer_tiny_add(gpr_slice_buffer *sb, int len);
/* clear a slice buffer, unref all elements */
void gpr_slice_buffer_reset_and_unref(gpr_slice_buffer *sb);
#ifdef __cplusplus
}
#endif
#endif /* __GRPC_SUPPORT_SLICE_BUFFER_H__ */

@ -0,0 +1,76 @@
/*
*
* 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_H__
#define __GRPC_SUPPORT_STRING_H__
#include <stddef.h>
#include <grpc/support/port_platform.h>
#ifdef __cplusplus
extern "C" {
#endif
/* String utility functions */
/* Returns a copy of src that can be passed to gpr_free().
If allocation fails or if src is NULL, returns NULL. */
char *gpr_strdup(const char *src);
/* flag to include plaintext after a hexdump */
#define GPR_HEXDUMP_PLAINTEXT 0x00000001
/* Converts array buf, of length len, into a hexadecimal dump. Result should
be freed with gpr_free() */
char *gpr_hexdump(const char *buf, size_t len, gpr_uint32 flags);
/* Parses an array of bytes into an integer (base 10). Returns 1 on success,
0 on failure. */
int gpr_parse_bytes_to_uint32(const char *data, size_t length,
gpr_uint32 *result);
/* printf to a newly-allocated string. The set of supported formats may vary
between platforms.
On success, returns the number of bytes printed (excluding the final '\0'),
and *strp points to a string which must later be destroyed with gpr_free().
On error, returns -1 and sets *strp to NULL. */
int gpr_asprintf(char **strp, const char *format, ...);
#ifdef __cplusplus
}
#endif
#endif /* __GRPC_SUPPORT_STRING_H__ */

@ -0,0 +1,348 @@
/*
*
* 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_SYNC_H__
#define __GRPC_SUPPORT_SYNC_H__
/* Synchronization primitives for GPR.
The type gpr_mu provides a non-reentrant mutex (lock).
The type gpr_cv provides a condition variable.
The type gpr_once provides for one-time initialization.
The type gpr_event provides one-time-setting, reading, and
waiting of a void*, with memory barriers.
The type gpr_refcount provides an object reference counter,
with memory barriers suitable to control
object lifetimes.
The type gpr_stats_counter provides an atomic statistics counter. It
provides no memory barriers.
*/
/* Platform-specific type declarations of gpr_mu and gpr_cv. */
#include <grpc/support/port_platform.h>
#include <grpc/support/sync_generic.h>
#if defined(GPR_POSIX_SYNC)
#include <grpc/support/sync_posix.h>
#elif defined(GPR_WIN32)
#include <grpc/support/sync_win32.h>
#else
#error Unable to determine platform for sync
#endif
#include <grpc/support/time.h> /* for gpr_timespec */
#include <grpc/support/cancellable_platform.h>
#ifdef __cplusplus
extern "C" {
#endif
/* --- Mutex interface ---
At most one thread may hold an exclusive lock on a mutex at any given time.
Actions taken by a thread that holds a mutex exclusively happen after
actions taken by all previous holders of the mutex. Variables of type
gpr_mu are uninitialized when first declared. */
/* Initialize *mu. Requires: *mu uninitialized. */
void gpr_mu_init(gpr_mu *mu);
/* Cause *mu no longer to be initialized, freeing any memory in use. Requires:
*mu initialized; no other concurrent operation on *mu. */
void gpr_mu_destroy(gpr_mu *mu);
/* Wait until no thread has a lock on *mu, cause the calling thread to own an
exclusive lock on *mu, then return. May block indefinitely or crash if the
calling thread has a lock on *mu. Requires: *mu initialized. */
void gpr_mu_lock(gpr_mu *mu);
/* Release an exclusive lock on *mu held by the calling thread. Requires: *mu
initialized; the calling thread holds an exclusive lock on *mu. */
void gpr_mu_unlock(gpr_mu *mu);
/* Without blocking, attempt to acquire an exclusive lock on *mu for the
calling thread, then return non-zero iff success. Fail, if any thread holds
the lock; succeeds with high probability if no thread holds the lock.
Requires: *mu initialized. */
int gpr_mu_trylock(gpr_mu *mu);
/* --- Condition variable interface ---
A while-loop should be used with gpr_cv_wait() when waiting for conditions
to become true. See the example below. Variables of type gpr_cv are
uninitialized when first declared. */
/* Initialize *cv. Requires: *cv uninitialized. */
void gpr_cv_init(gpr_cv *cv);
/* Cause *cv no longer to be initialized, freeing any memory in use. Requires:
*cv initialized; no other concurrent operation on *cv.*/
void gpr_cv_destroy(gpr_cv *cv);
/* Atomically release *mu and wait on *cv. When the calling thread is woken
from *cv or the deadline abs_deadline is exceeded, execute gpr_mu_lock(mu)
and return whether the deadline was exceeded. Use
abs_deadline==gpr_inf_future for no deadline. May return even when not
woken explicitly. Requires: *mu and *cv initialized; the calling thread
holds an exclusive lock on *mu. */
int gpr_cv_wait(gpr_cv *cv, gpr_mu *mu, gpr_timespec abs_deadline);
/* Behave like gpr_cv_wait(cv, mu, abs_deadline), except behave as though
the deadline has expired if *c is cancelled. */
int gpr_cv_cancellable_wait(gpr_cv *cv, gpr_mu *mu, gpr_timespec abs_deadline,
gpr_cancellable *c);
/* If any threads are waiting on *cv, wake at least one.
Clients may treat this as an optimization of gpr_cv_broadcast()
for use in the case where waking more than one waiter is not useful.
Requires: *cv initialized. */
void gpr_cv_signal(gpr_cv *cv);
/* Wake all threads waiting on *cv. Requires: *cv initialized. */
void gpr_cv_broadcast(gpr_cv *cv);
/* --- Cancellation ---
A gpr_cancellable can be used with gpr_cv_cancellable_wait()
or gpr_event_cancellable_wait() cancel pending waits. */
/* Initialize *c. */
void gpr_cancellable_init(gpr_cancellable *c);
/* Cause *c no longer to be initialized, freeing any memory in use. Requires:
*c initialized; no other concurrent operation on *c. */
void gpr_cancellable_destroy(gpr_cancellable *c);
/* Return non-zero iff *c has been cancelled. Requires *c initialized.
This call is faster than acquiring a mutex on most platforms. */
int gpr_cancellable_is_cancelled(gpr_cancellable *c);
/* Cancel *c. If *c was not previously cancelled, cause
gpr_cancellable_init() to return non-zero, and outstanding and future
calls to gpr_cv_cancellable_wait() and gpr_event_cancellable_wait() to
return immediately indicating a timeout has occurred; otherwise do nothing.
Requires *c initialized.*/
void gpr_cancellable_cancel(gpr_cancellable *c);
/* --- One-time initialization ---
gpr_once must be declared with static storage class, and initialized with
GPR_ONCE_INIT. e.g.,
static gpr_once once_var = GPR_ONCE_INIT; */
/* Ensure that (*init_routine)() has been called exactly once (for the
specified gpr_once instance) and then return.
If multiple threads call gpr_once() on the same gpr_once instance, one of
them will call (*init_routine)(), and the others will block until that call
finishes.*/
void gpr_once_init(gpr_once *once, void (*init_routine)(void));
/* --- One-time event notification ---
These operations act on a gpr_event, which should be initialized with
gpr_ev_init(), or with GPR_EVENT_INIT if static, e.g.,
static gpr_event event_var = GPR_EVENT_INIT;
It requires no destruction. */
/* Initialize *ev. */
void gpr_event_init(gpr_event *ev);
/* Set *ev so that gpr_event_get() and gpr_event_wait() will return value.
Requires: *ev initialized; value != NULL; no prior or concurrent calls to
gpr_event_set(ev, ...) since initialization. */
void gpr_event_set(gpr_event *ev, void *value);
/* Return the value set by gpr_event_set(ev, ...), or NULL if no such call has
completed. If the result is non-NULL, all operations that occurred prior to
the gpr_event_set(ev, ...) set will be visible after this call returns.
Requires: *ev initialized. This operation is faster than acquiring a mutex
on most platforms. */
void *gpr_event_get(gpr_event *ev);
/* Wait until *ev is set by gpr_event_set(ev, ...), or abs_deadline is
exceeded, then return gpr_event_get(ev). Requires: *ev initialized. Use
abs_deadline==gpr_inf_future for no deadline. When the event has been
signalled before the call, this operation is faster than acquiring a mutex
on most platforms. */
void *gpr_event_wait(gpr_event *ev, gpr_timespec abs_deadline);
/* Behave like gpr_event_wait(ev, abs_deadline), except behave as though
the deadline has expired if *c is cancelled. */
void *gpr_event_cancellable_wait(gpr_event *ev, gpr_timespec abs_deadline,
gpr_cancellable *c);
/* --- Reference counting ---
These calls act on the type gpr_refcount. It requires no desctruction. */
/* Initialize *r to value n. */
void gpr_ref_init(gpr_refcount *r, int n);
/* Increment the reference count *r. Requires *r initialized. */
void gpr_ref(gpr_refcount *r);
/* Increment the reference count *r by n. Requires *r initialized, n > 0. */
void gpr_refn(gpr_refcount *r, int n);
/* Decrement the reference count *r and return non-zero iff it has reached
zero. . Requires *r initialized. */
int gpr_unref(gpr_refcount *r);
/* --- Stats counters ---
These calls act on the integral type gpr_stats_counter. It requires no
destruction. Static instances may be initialized with
gpr_stats_counter c = GPR_STATS_INIT;
Beware: These operations do not imply memory barriers. Do not use them to
synchronize other events. */
/* Initialize *c to the value n. */
void gpr_stats_init(gpr_stats_counter *c, gpr_intptr n);
/* *c += inc. Requires: *c initialized. */
void gpr_stats_inc(gpr_stats_counter *c, gpr_intptr inc);
/* Return *c. Requires: *c initialized. */
gpr_intptr gpr_stats_read(const gpr_stats_counter *c);
/* ==================Example use of interface===================
A producer-consumer queue of up to N integers,
illustrating the use of the calls in this interface. */
#if 0
#define N 4
typedef struct queue {
gpr_cv non_empty; /* Signalled when length becomes non-zero. */
gpr_cv non_full; /* Signalled when length becomes non-N. */
gpr_mu mu; /* Protects all fields below.
(That is, except during initialization or
destruction, the fields below should be accessed
only by a thread that holds mu.) */
int head; /* Index of head of queue 0..N-1. */
int length; /* Number of valid elements in queue 0..N. */
int elem[N]; /* elem[head .. head+length-1] are queue elements. */
} queue;
/* Initialize *q. */
void queue_init(queue *q) {
gpr_mu_init(&q->mu);
gpr_cv_init(&q->non_empty);
gpr_cv_init(&q->non_full);
q->head = 0;
q->length = 0;
}
/* Free storage associated with *q. */
void queue_destroy(queue *q) {
gpr_mu_destroy(&q->mu);
gpr_cv_destroy(&q->non_empty);
gpr_cv_destroy(&q->non_full);
}
/* Wait until there is room in *q, then append x to *q. */
void queue_append(queue *q, int x) {
gpr_mu_lock(&q->mu);
/* To wait for a predicate without a deadline, loop on the negation of the
predicate, and use gpr_cv_wait(..., gpr_inf_future) inside the loop
to release the lock, wait, and reacquire on each iteration. Code that
makes the condition true should use gpr_cv_broadcast() on the
corresponding condition variable. The predicate must be on state
protected by the lock. */
while (q->length == N) {
gpr_cv_wait(&q->non_full, &q->mu, gpr_inf_future);
}
if (q->length == 0) { /* Wake threads blocked in queue_remove(). */
/* It's normal to use gpr_cv_broadcast() or gpr_signal() while
holding the lock. */
gpr_cv_broadcast(&q->non_empty);
}
q->elem[(q->head + q->length) % N] = x;
q->length++;
gpr_mu_unlock(&q->mu);
}
/* If it can be done without blocking, append x to *q and return non-zero.
Otherwise return 0. */
int queue_try_append(queue *q, int x) {
int result = 0;
if (gpr_mu_trylock(&q->mu)) {
if (q->length != N) {
if (q->length == 0) { /* Wake threads blocked in queue_remove(). */
gpr_cv_broadcast(&q->non_empty);
}
q->elem[(q->head + q->length) % N] = x;
q->length++;
result = 1;
}
gpr_mu_unlock(&q->mu);
}
return result;
}
/* Wait until the *q is non-empty or deadline abs_deadline passes. If the
queue is non-empty, remove its head entry, place it in *head, and return
non-zero. Otherwise return 0. */
int queue_remove(queue *q, int *head, gpr_timespec abs_deadline) {
int result = 0;
gpr_mu_lock(&q->mu);
/* To wait for a predicate with a deadline, loop on the negation of the
predicate or until gpr_cv_wait() returns true. Code that makes
the condition true should use gpr_cv_broadcast() on the corresponding
condition variable. The predicate must be on state protected by the
lock. */
while (q->length == 0 &&
!gpr_cv_wait(&q->non_empty, &q->mu, abs_deadline)) {
}
if (q->length != 0) { /* Queue is non-empty. */
result = 1;
if (q->length == N) { /* Wake threads blocked in queue_append(). */
gpr_cv_broadcast(&q->non_full);
}
*head = q->elem[q->head];
q->head = (q->head + 1) % N;
q->length--;
} /* else deadline exceeded */
gpr_mu_unlock(&q->mu);
return result;
}
#endif /* 0 */
#ifdef __cplusplus
}
#endif
#endif /* __GRPC_SUPPORT_SYNC_H__ */

@ -0,0 +1,55 @@
/*
*
* 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_SYNC_GENERIC_H__
#define __GRPC_SUPPORT_SYNC_GENERIC_H__
/* Generic type defintions for gpr_sync. */
#include <grpc/support/atm.h>
/* gpr_event */
typedef struct { gpr_atm state; } gpr_event;
#define GPR_EVENT_INIT \
{ 0 }
/* gpr_refcount */
typedef struct { gpr_atm count; } gpr_refcount;
/* gpr_stats_counter */
typedef struct { gpr_atm value; } gpr_stats_counter;
#define GPR_STATS_INIT \
{ 0 }
#endif /* __GRPC_SUPPORT_SYNC_GENERIC_H__ */

@ -0,0 +1,48 @@
/*
*
* 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_SYNC_POSIX_H__
#define __GRPC_SUPPORT_SYNC_POSIX_H__
#include <grpc/support/sync_generic.h>
/* Posix variant of gpr_sync_platform.h */
#include <pthread.h>
typedef pthread_mutex_t gpr_mu;
typedef pthread_cond_t gpr_cv;
typedef pthread_once_t gpr_once;
#define GPR_ONCE_INIT PTHREAD_ONCE_INIT
#endif /* __GRPC_SUPPORT_SYNC_POSIX_H__ */

@ -0,0 +1,52 @@
/*
*
* 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_SYNC_WIN32_H__
#define __GRPC_SUPPORT_SYNC_WIN32_H__
#include <grpc/support/sync_generic.h>
/* Win32 variant of gpr_sync_platform.h */
#include <windows.h>
typedef struct {
CRITICAL_SECTION cs; /* Not an SRWLock until Vista is unsupported */
int locked;
} gpr_mu;
typedef CONDITION_VARIABLE gpr_cv;
typedef INIT_ONCE gpr_once;
#define GPR_ONCE_INIT INIT_ONCE_STATIC_INIT
#endif /* __GRPC_SUPPORT_SYNC_WIN32_H__ */

@ -0,0 +1,79 @@
/*
*
* 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_THD_H__
#define __GRPC_SUPPORT_THD_H__
/* Thread interface for GPR.
Types
gpr_thd_id a thread identifier.
(Currently no calls take a thread identifier.
It exists for future extensibility.)
gpr_thd_options options used when creating a thread
*/
#include <grpc/support/port_platform.h>
#if defined(GPR_POSIX_SYNC)
#include <grpc/support/thd_posix.h>
#elif defined(GPR_WIN32)
#include <grpc/support/thd_win32.h>
#else
#error could not determine platform for thd
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* Thread creation options. */
typedef struct {
int flags; /* Flags below can be set here. Default value 0. */
} gpr_thd_options;
/* No flags are currently defined. */
/* Create a new thread running (*thd_body)(arg) and place its thread identifier
in *t, and return true. If there are insufficient resources, return false.
If options==NULL, default options are used.
The thread is immediately runnable, and exits when (*thd_body)() returns. */
int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg,
const gpr_thd_options *options);
/* Return a gpr_thd_options struct with all fields set to defaults. */
gpr_thd_options gpr_thd_options_default(void);
#ifdef __cplusplus
}
#endif
#endif /* __GRPC_SUPPORT_THD_H__ */

@ -0,0 +1,42 @@
/*
*
* 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_THD_POSIX_H__
#define __GRPC_SUPPORT_THD_POSIX_H__
/* Posix variant of gpr_thd_platform.h. */
#include <pthread.h>
typedef pthread_t gpr_thd_id;
#endif /* __GRPC_SUPPORT_THD_POSIX_H__ */

@ -0,0 +1,44 @@
/*
*
* 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_THD_WIN32_H__
#define __GRPC_SUPPORT_THD_WIN32_H__
/* Win32 variant of gpr_thd_platform.h */
#include <windows.h>
#include <grpc/support/atm.h>
typedef int gpr_thd_id;
#endif /* __GRPC_SUPPORT_THD_WIN32_H__ */

@ -0,0 +1,109 @@
/*
*
* 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_TIME_H__
#define __GRPC_SUPPORT_TIME_H__
/* Time support.
We use gpr_timespec, which is typedefed to struct timespec on platforms which
have it. On some machines, absolute times may be in local time. */
/* Platform specific header declares gpr_timespec.
gpr_timespec contains:
time_t tv_sec; // seconds since start of 1970
int tv_nsec; // nanoseconds; always in 0..999999999; never negative.
*/
#include <grpc/support/port_platform.h>
#if defined(GPR_POSIX_TIME)
#include <grpc/support/time_posix.h>
#elif defined(GPR_WIN32)
#include <grpc/support/time_win32.h>
#else
#error could not determine platform for time
#endif
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Time constants. */
extern const gpr_timespec gpr_time_0; /* The zero time interval. */
extern const gpr_timespec gpr_inf_future; /* The far future */
extern const gpr_timespec gpr_inf_past; /* The far past. */
#define GPR_MS_PER_SEC 1000
#define GPR_US_PER_SEC 1000000
#define GPR_NS_PER_SEC 1000000000
#define GPR_NS_PER_MS 1000000
#define GPR_NS_PER_US 1000
#define GPR_US_PER_MS 1000
/* Return the current time measured from the system's default epoch. */
gpr_timespec gpr_now(void);
/* Return -ve, 0, or +ve according to whether a < b, a == b, or a > b
respectively. */
int gpr_time_cmp(gpr_timespec a, gpr_timespec b);
/* Add and subtract times. Calculations saturate at infinities. */
gpr_timespec gpr_time_add(gpr_timespec a, gpr_timespec b);
gpr_timespec gpr_time_sub(gpr_timespec a, gpr_timespec b);
/* Return a timespec representing a given number of microseconds. LONG_MIN is
interpreted as gpr_inf_past, and LONG_MAX as gpr_inf_future. */
gpr_timespec gpr_time_from_micros(long x);
gpr_timespec gpr_time_from_nanos(long x);
gpr_timespec gpr_time_from_millis(long x);
gpr_timespec gpr_time_from_seconds(long x);
gpr_timespec gpr_time_from_minutes(long x);
gpr_timespec gpr_time_from_hours(long x);
/* Return 1 if two times are equal or within threshold of each other,
0 otherwise */
int gpr_time_similar(gpr_timespec a, gpr_timespec b, gpr_timespec threshold);
/* Sleep until at least 'until' - an absolute timeout */
void gpr_sleep_until(gpr_timespec until);
struct timeval gpr_timeval_from_timespec(gpr_timespec t);
gpr_timespec gpr_timespec_from_timeval(struct timeval t);
#ifdef __cplusplus
}
#endif
#endif /* __GRPC_SUPPORT_TIME_H__ */

@ -0,0 +1,43 @@
/*
*
* 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_TIME_POSIX_H__
#define __GRPC_SUPPORT_TIME_POSIX_H__
/* Posix variant of gpr_time_platform.h */
#include <sys/time.h>
#include <time.h>
typedef struct timespec gpr_timespec;
#endif /* __GRPC_SUPPORT_TIME_POSIX_H__ */

@ -0,0 +1,46 @@
/*
*
* 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_TIME_WIN32_H__
#define __GRPC_SUPPORT_TIME_WIN32_H__
/* Win32 variant of gpr_time_platform.h */
#include <Winsock.h>
#include <time.h>
typedef struct gpr_timespec {
time_t tv_sec;
long tv_nsec;
} gpr_timespec;
#endif /* __GRPC_SUPPORT_TIME_WIN32_H__ */

@ -0,0 +1,45 @@
/*
*
* 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_USEFUL_H__
#define __GRPC_SUPPORT_USEFUL_H__
/* useful macros that don't belong anywhere else */
#define GPR_MIN(a, b) ((a) < (b) ? (a) : (b))
#define GPR_MAX(a, b) ((a) > (b) ? (a) : (b))
#define GPR_CLAMP(a, min, max) ((a) < (min) ? (min) : (a) > (max) ? (max) : (a))
#define GPR_ARRAY_SIZE(array) (sizeof(array) / sizeof(*(array)))
#endif /* __GRPC_SUPPORT_USEFUL_H__ */

@ -0,0 +1,155 @@
/*
*
* 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/channel/channel_stack.h"
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/string.h>
#include <grpc/support/useful.h>
#define MAX_APPEND 1024
typedef struct {
size_t cap;
size_t len;
char *buffer;
} buf;
static void bprintf(buf *b, const char *fmt, ...) {
va_list arg;
if (b->len + MAX_APPEND > b->cap) {
b->cap = GPR_MAX(b->len + MAX_APPEND, b->cap * 3 / 2);
b->buffer = gpr_realloc(b->buffer, b->cap);
}
va_start(arg, fmt);
b->len += vsprintf(b->buffer + b->len, fmt, arg);
va_end(arg);
}
static void bputs(buf *b, const char *s) {
size_t slen = strlen(s);
if (b->len + slen + 1 > b->cap) {
b->cap = GPR_MAX(b->len + slen + 1, b->cap * 3 / 2);
b->buffer = gpr_realloc(b->buffer, b->cap);
}
strcat(b->buffer, s);
b->len += slen;
}
static void put_metadata(buf *b, grpc_mdelem *md) {
char *txt;
txt = gpr_hexdump((char *)GPR_SLICE_START_PTR(md->key->slice),
GPR_SLICE_LENGTH(md->key->slice), GPR_HEXDUMP_PLAINTEXT);
bputs(b, " key=");
bputs(b, txt);
gpr_free(txt);
txt = gpr_hexdump((char *)GPR_SLICE_START_PTR(md->value->slice),
GPR_SLICE_LENGTH(md->value->slice), GPR_HEXDUMP_PLAINTEXT);
bputs(b, " value=");
bputs(b, txt);
gpr_free(txt);
}
char *grpc_call_op_string(grpc_call_op *op) {
buf b = {0, 0, 0};
switch (op->dir) {
case GRPC_CALL_DOWN:
bprintf(&b, ">");
break;
case GRPC_CALL_UP:
bprintf(&b, "<");
break;
}
switch (op->type) {
case GRPC_SEND_METADATA:
bprintf(&b, "SEND_METADATA");
put_metadata(&b, op->data.metadata);
break;
case GRPC_SEND_DEADLINE:
bprintf(&b, "SEND_DEADLINE %d.%09d", op->data.deadline.tv_sec,
op->data.deadline.tv_nsec);
break;
case GRPC_SEND_START:
bprintf(&b, "SEND_START");
break;
case GRPC_SEND_MESSAGE:
bprintf(&b, "SEND_MESSAGE");
break;
case GRPC_SEND_FINISH:
bprintf(&b, "SEND_FINISH");
break;
case GRPC_REQUEST_DATA:
bprintf(&b, "REQUEST_DATA");
break;
case GRPC_RECV_METADATA:
bprintf(&b, "RECV_METADATA");
put_metadata(&b, op->data.metadata);
break;
case GRPC_RECV_DEADLINE:
bprintf(&b, "RECV_DEADLINE %d.%09d", op->data.deadline.tv_sec,
op->data.deadline.tv_nsec);
break;
case GRPC_RECV_END_OF_INITIAL_METADATA:
bprintf(&b, "RECV_END_OF_INITIAL_METADATA");
break;
case GRPC_RECV_MESSAGE:
bprintf(&b, "RECV_MESSAGE");
break;
case GRPC_RECV_HALF_CLOSE:
bprintf(&b, "RECV_HALF_CLOSE");
break;
case GRPC_RECV_FINISH:
bprintf(&b, "RECV_FINISH");
break;
case GRPC_CANCEL_OP:
bprintf(&b, "CANCEL_OP");
break;
}
bprintf(&b, " flags=0x%08x", op->flags);
return b.buffer;
}
void grpc_call_log_op(char *file, int line, gpr_log_severity severity,
grpc_call_element *elem, grpc_call_op *op) {
char *str = grpc_call_op_string(op);
gpr_log(file, line, severity, "OP[%s:%p]: %s", elem->filter->name, elem, str);
gpr_free(str);
}

@ -0,0 +1,189 @@
/*
*
* 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/channel/census_filter.h"
#include <stdio.h>
#include <string.h>
#include "src/core/channel/channel_stack.h"
#include "src/core/channel/noop_filter.h"
#include "src/core/statistics/census_interface.h"
#include "src/core/statistics/census_rpc_stats.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/slice.h>
#include <grpc/support/time.h>
typedef struct call_data {
census_op_id op_id;
census_rpc_stats stats;
gpr_timespec start_ts;
} call_data;
typedef struct channel_data {
grpc_mdstr* path_str; /* pointer to meta data str with key == ":path" */
} channel_data;
static void init_rpc_stats(census_rpc_stats* stats) {
memset(stats, 0, sizeof(census_rpc_stats));
stats->cnt = 1;
}
static double gpr_timespec_to_micros(gpr_timespec t) {
return t.tv_sec * GPR_US_PER_SEC + t.tv_nsec * 1e-3;
}
static void extract_and_annotate_method_tag(grpc_call_op* op, call_data* calld,
channel_data* chand) {
if (op->data.metadata->key == chand->path_str) {
census_add_method_tag(calld->op_id, (const char*)GPR_SLICE_START_PTR(
op->data.metadata->value->slice));
}
}
static void client_call_op(grpc_call_element* elem, grpc_call_op* op) {
call_data* calld = elem->call_data;
channel_data* chand = elem->channel_data;
GPR_ASSERT(calld != NULL);
GPR_ASSERT(chand != NULL);
GPR_ASSERT((calld->op_id.upper != 0) && (calld->op_id.lower != 0));
switch (op->type) {
case GRPC_SEND_METADATA:
extract_and_annotate_method_tag(op, calld, chand);
break;
case GRPC_RECV_FINISH:
/* Should we stop timing the rpc here? */
break;
default:
break;
}
/* Always pass control up or down the stack depending on op->dir */
grpc_call_next_op(elem, op);
}
static void server_call_op(grpc_call_element* elem, grpc_call_op* op) {
call_data* calld = elem->call_data;
channel_data* chand = elem->channel_data;
GPR_ASSERT(calld != NULL);
GPR_ASSERT(chand != NULL);
GPR_ASSERT((calld->op_id.upper != 0) && (calld->op_id.lower != 0));
switch (op->type) {
case GRPC_RECV_METADATA:
extract_and_annotate_method_tag(op, calld, chand);
break;
case GRPC_SEND_FINISH:
/* Should we stop timing the rpc here? */
break;
default:
break;
}
/* Always pass control up or down the stack depending on op->dir */
grpc_call_next_op(elem, op);
}
static void channel_op(grpc_channel_element* elem, grpc_channel_op* op) {
switch (op->type) {
case GRPC_TRANSPORT_CLOSED:
/* TODO(hongyu): Annotate trace information for all calls of the channel
*/
break;
default:
break;
}
grpc_channel_next_op(elem, op);
}
static void client_init_call_elem(grpc_call_element* elem,
const void* server_transport_data) {
call_data* d = elem->call_data;
GPR_ASSERT(d != NULL);
init_rpc_stats(&d->stats);
d->start_ts = gpr_now();
d->op_id = census_tracing_start_op();
}
static void client_destroy_call_elem(grpc_call_element* elem) {
call_data* d = elem->call_data;
GPR_ASSERT(d != NULL);
census_record_rpc_client_stats(d->op_id, &d->stats);
census_tracing_end_op(d->op_id);
}
static void server_init_call_elem(grpc_call_element* elem,
const void* server_transport_data) {
call_data* d = elem->call_data;
GPR_ASSERT(d != NULL);
init_rpc_stats(&d->stats);
d->start_ts = gpr_now();
d->op_id = census_tracing_start_op();
}
static void server_destroy_call_elem(grpc_call_element* elem) {
call_data* d = elem->call_data;
GPR_ASSERT(d != NULL);
d->stats.elapsed_time_ms =
gpr_timespec_to_micros(gpr_time_sub(gpr_now(), d->start_ts));
census_record_rpc_server_stats(d->op_id, &d->stats);
census_tracing_end_op(d->op_id);
}
static void init_channel_elem(grpc_channel_element* elem,
const grpc_channel_args* args, grpc_mdctx* mdctx,
int is_first, int is_last) {
channel_data* chand = elem->channel_data;
GPR_ASSERT(chand != NULL);
GPR_ASSERT(!is_first);
GPR_ASSERT(!is_last);
chand->path_str = grpc_mdstr_from_string(mdctx, ":path");
}
static void destroy_channel_elem(grpc_channel_element* elem) {}
const grpc_channel_filter grpc_client_census_filter = {
client_call_op, channel_op,
sizeof(call_data), client_init_call_elem, client_destroy_call_elem,
sizeof(channel_data), init_channel_elem, destroy_channel_elem,
"census-client"};
const grpc_channel_filter grpc_server_census_filter = {
server_call_op, channel_op,
sizeof(call_data), server_init_call_elem, server_destroy_call_elem,
sizeof(channel_data), init_channel_elem, destroy_channel_elem,
"census-server"};

@ -0,0 +1,44 @@
/*
*
* 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_INTERNAL_CHANNEL_CENSUS_FILTER_H__
#define __GRPC_INTERNAL_CHANNEL_CENSUS_FILTER_H__
#include "src/core/channel/channel_stack.h"
/* Census filters: provides tracing and stats collection functionalities. It
needs to reside right below the surface filter in the channel stack. */
extern const grpc_channel_filter grpc_client_census_filter;
extern const grpc_channel_filter grpc_server_census_filter;
#endif /* __GRPC_INTERNAL_CHANNEL_CENSUS_FILTER_H__ */

@ -0,0 +1,112 @@
/*
*
* 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/grpc.h>
#include "src/core/channel/channel_args.h"
#include <grpc/support/alloc.h>
#include <grpc/support/string.h>
#include <string.h>
static grpc_arg copy_arg(const grpc_arg *src) {
grpc_arg dst;
dst.type = src->type;
dst.key = gpr_strdup(src->key);
switch (dst.type) {
case GRPC_ARG_STRING:
dst.value.string = gpr_strdup(src->value.string);
break;
case GRPC_ARG_INTEGER:
dst.value.integer = src->value.integer;
break;
case GRPC_ARG_POINTER:
dst.value.pointer = src->value.pointer;
dst.value.pointer.p = src->value.pointer.copy(src->value.pointer.p);
break;
}
return dst;
}
grpc_channel_args *grpc_channel_args_copy_and_add(const grpc_channel_args *src,
const grpc_arg *to_add) {
grpc_channel_args *dst = gpr_malloc(sizeof(grpc_channel_args));
size_t i;
size_t src_num_args = (src == NULL) ? 0 : src->num_args;
if (!src && !to_add) {
dst->num_args = 0;
dst->args = NULL;
return dst;
}
dst->num_args = src_num_args + ((to_add == NULL) ? 0 : 1);
dst->args = gpr_malloc(sizeof(grpc_arg) * dst->num_args);
for (i = 0; i < src_num_args; i++) {
dst->args[i] = copy_arg(&src->args[i]);
}
if (to_add != NULL) dst->args[src_num_args] = copy_arg(to_add);
return dst;
}
grpc_channel_args *grpc_channel_args_copy(const grpc_channel_args *src) {
return grpc_channel_args_copy_and_add(src, NULL);
}
void grpc_channel_args_destroy(grpc_channel_args *a) {
size_t i;
for (i = 0; i < a->num_args; i++) {
switch (a->args[i].type) {
case GRPC_ARG_STRING:
gpr_free(a->args[i].value.string);
break;
case GRPC_ARG_INTEGER:
break;
case GRPC_ARG_POINTER:
a->args[i].value.pointer.destroy(a->args[i].value.pointer.p);
break;
}
gpr_free(a->args[i].key);
}
gpr_free(a->args);
gpr_free(a);
}
int grpc_channel_args_is_census_enabled(const grpc_channel_args *a) {
int i;
if (a == NULL) return 0;
for (i = 0; i < a->num_args; i++) {
if (0 == strcmp(a->args[i].key, GRPC_ARG_ENABLE_CENSUS)) {
return a->args[i].value.integer != 0;
}
}
return 0;
}

@ -0,0 +1,54 @@
/*
*
* Copyright 2014, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef __GRPC_INTERNAL_CHANNEL_CHANNEL_ARGS_H__
#define __GRPC_INTERNAL_CHANNEL_CHANNEL_ARGS_H__
#include <grpc/grpc.h>
/* Copy some arguments */
grpc_channel_args *grpc_channel_args_copy(const grpc_channel_args *src);
/* Copy some arguments and add the to_add parameter in the end.
If to_add is NULL, it is equivalent to call grpc_channel_args_copy. */
grpc_channel_args *grpc_channel_args_copy_and_add(const grpc_channel_args *src,
const grpc_arg *to_add);
/* Destroy arguments created by grpc_channel_args_copy */
void grpc_channel_args_destroy(grpc_channel_args *a);
/* Reads census_enabled settings from channel args. Returns 1 if census_enabled
is specified in channel args, otherwise returns 0. */
int grpc_channel_args_is_census_enabled(const grpc_channel_args *a);
#endif /* __GRPC_INTERNAL_CHANNEL_CHANNEL_ARGS_H__ */

@ -0,0 +1,223 @@
/*
*
* 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/channel/channel_stack.h"
#include <grpc/support/log.h>
#include <stdlib.h>
/* Memory layouts.
Channel stack is laid out as: {
grpc_channel_stack stk;
padding to GPR_MAX_ALIGNMENT
grpc_channel_element[stk.count];
per-filter memory, aligned to GPR_MAX_ALIGNMENT
}
Call stack is laid out as: {
grpc_call_stack stk;
padding to GPR_MAX_ALIGNMENT
grpc_call_element[stk.count];
per-filter memory, aligned to GPR_MAX_ALIGNMENT
} */
/* Given a size, round up to the next multiple of sizeof(void*) */
#define ROUND_UP_TO_ALIGNMENT_SIZE(x) \
(((x)+GPR_MAX_ALIGNMENT - 1) & ~(GPR_MAX_ALIGNMENT - 1))
size_t grpc_channel_stack_size(const grpc_channel_filter **filters,
size_t filter_count) {
/* always need the header, and size for the channel elements */
size_t size =
ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_channel_stack)) +
ROUND_UP_TO_ALIGNMENT_SIZE(filter_count * sizeof(grpc_channel_element));
size_t i;
GPR_ASSERT((GPR_MAX_ALIGNMENT & (GPR_MAX_ALIGNMENT - 1)) == 0 &&
"GPR_MAX_ALIGNMENT must be a power of two");
/* add the size for each filter */
for (i = 0; i < filter_count; i++) {
size += ROUND_UP_TO_ALIGNMENT_SIZE(filters[i]->sizeof_channel_data);
}
return size;
}
#define CHANNEL_ELEMS_FROM_STACK(stk) \
((grpc_channel_element *)((char *)(stk) + ROUND_UP_TO_ALIGNMENT_SIZE( \
sizeof(grpc_channel_stack))))
#define CALL_ELEMS_FROM_STACK(stk) \
((grpc_call_element *)((char *)(stk) + \
ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call_stack))))
grpc_channel_element *grpc_channel_stack_element(
grpc_channel_stack *channel_stack, size_t index) {
return CHANNEL_ELEMS_FROM_STACK(channel_stack) + index;
}
grpc_channel_element *grpc_channel_stack_last_element(
grpc_channel_stack *channel_stack) {
return grpc_channel_stack_element(channel_stack, channel_stack->count - 1);
}
grpc_call_element *grpc_call_stack_element(grpc_call_stack *call_stack,
size_t index) {
return CALL_ELEMS_FROM_STACK(call_stack) + index;
}
void grpc_channel_stack_init(const grpc_channel_filter **filters,
size_t filter_count, const grpc_channel_args *args,
grpc_mdctx *metadata_context,
grpc_channel_stack *stack) {
size_t call_size =
ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call_stack)) +
ROUND_UP_TO_ALIGNMENT_SIZE(filter_count * sizeof(grpc_call_element));
grpc_channel_element *elems;
char *user_data;
size_t i;
stack->count = filter_count;
elems = CHANNEL_ELEMS_FROM_STACK(stack);
user_data =
((char *)elems) +
ROUND_UP_TO_ALIGNMENT_SIZE(filter_count * sizeof(grpc_channel_element));
/* init per-filter data */
for (i = 0; i < filter_count; i++) {
elems[i].filter = filters[i];
elems[i].channel_data = user_data;
elems[i].filter->init_channel_elem(&elems[i], args, metadata_context,
i == 0, i == (filter_count - 1));
user_data += ROUND_UP_TO_ALIGNMENT_SIZE(filters[i]->sizeof_channel_data);
call_size += ROUND_UP_TO_ALIGNMENT_SIZE(filters[i]->sizeof_call_data);
}
GPR_ASSERT(user_data - (char *)stack ==
grpc_channel_stack_size(filters, filter_count));
stack->call_stack_size = call_size;
}
void grpc_channel_stack_destroy(grpc_channel_stack *stack) {
grpc_channel_element *channel_elems = CHANNEL_ELEMS_FROM_STACK(stack);
size_t count = stack->count;
size_t i;
/* destroy per-filter data */
for (i = 0; i < count; i++) {
channel_elems[i].filter->destroy_channel_elem(&channel_elems[i]);
}
}
void grpc_call_stack_init(grpc_channel_stack *channel_stack,
const void *transport_server_data,
grpc_call_stack *call_stack) {
grpc_channel_element *channel_elems = CHANNEL_ELEMS_FROM_STACK(channel_stack);
size_t count = channel_stack->count;
grpc_call_element *call_elems;
char *user_data;
size_t i;
call_stack->count = count;
call_elems = CALL_ELEMS_FROM_STACK(call_stack);
user_data = ((char *)call_elems) +
ROUND_UP_TO_ALIGNMENT_SIZE(count * sizeof(grpc_call_element));
/* init per-filter data */
for (i = 0; i < count; i++) {
call_elems[i].filter = channel_elems[i].filter;
call_elems[i].channel_data = channel_elems[i].channel_data;
call_elems[i].call_data = user_data;
call_elems[i].filter->init_call_elem(&call_elems[i], transport_server_data);
user_data +=
ROUND_UP_TO_ALIGNMENT_SIZE(call_elems[i].filter->sizeof_call_data);
}
}
void grpc_call_stack_destroy(grpc_call_stack *stack) {
grpc_call_element *elems = CALL_ELEMS_FROM_STACK(stack);
size_t count = stack->count;
size_t i;
/* destroy per-filter data */
for (i = 0; i < count; i++) {
elems[i].filter->destroy_call_elem(&elems[i]);
}
}
void grpc_call_next_op(grpc_call_element *elem, grpc_call_op *op) {
grpc_call_element *next_elem = elem + op->dir;
next_elem->filter->call_op(next_elem, op);
}
void grpc_channel_next_op(grpc_channel_element *elem, grpc_channel_op *op) {
grpc_channel_element *next_elem = elem + op->dir;
next_elem->filter->channel_op(next_elem, op);
}
grpc_channel_stack *grpc_channel_stack_from_top_element(
grpc_channel_element *elem) {
return (grpc_channel_stack *)((char *)(elem) -
ROUND_UP_TO_ALIGNMENT_SIZE(
sizeof(grpc_channel_stack)));
}
grpc_call_stack *grpc_call_stack_from_top_element(grpc_call_element *elem) {
return (grpc_call_stack *)((char *)(elem) - ROUND_UP_TO_ALIGNMENT_SIZE(
sizeof(grpc_call_stack)));
}
static void do_nothing(void *user_data, grpc_op_error error) {}
void grpc_call_element_send_metadata(grpc_call_element *cur_elem,
grpc_mdelem *mdelem) {
grpc_call_op metadata_op;
metadata_op.type = GRPC_SEND_METADATA;
metadata_op.dir = GRPC_CALL_DOWN;
metadata_op.done_cb = do_nothing;
metadata_op.user_data = NULL;
metadata_op.data.metadata = grpc_mdelem_ref(mdelem);
grpc_call_next_op(cur_elem, &metadata_op);
}
void grpc_call_element_send_cancel(grpc_call_element *cur_elem) {
grpc_call_op cancel_op;
cancel_op.type = GRPC_CANCEL_OP;
cancel_op.dir = GRPC_CALL_DOWN;
cancel_op.done_cb = do_nothing;
cancel_op.user_data = NULL;
grpc_call_next_op(cur_elem, &cancel_op);
}

@ -0,0 +1,288 @@
/*
*
* 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_INTERNAL_CHANNEL_CHANNEL_STACK_H__
#define __GRPC_INTERNAL_CHANNEL_CHANNEL_STACK_H__
/* A channel filter defines how operations on a channel are implemented.
Channel filters are chained together to create full channels, and if those
chains are linear, then channel stacks provide a mechanism to minimize
allocations for that chain.
Call stacks are created by channel stacks and represent the per-call data
for that stack. */
#include <stddef.h>
#include <grpc/grpc.h>
#include <grpc/support/log.h>
#include "src/core/transport/transport.h"
/* #define GRPC_CHANNEL_STACK_TRACE 1 */
typedef struct grpc_channel_element grpc_channel_element;
typedef struct grpc_call_element grpc_call_element;
/* Call operations - things that can be sent and received.
Threading:
SEND, RECV, and CANCEL ops can be active on a call at the same time, but
only one SEND, one RECV, and one CANCEL can be active at a time.
If state is shared between send/receive/cancel operations, it is up to
filters to provide their own protection around that. */
typedef enum {
/* send metadata to the channels peer */
GRPC_SEND_METADATA,
/* send a deadline */
GRPC_SEND_DEADLINE,
/* start a connection (corresponds to start_invoke/accept) */
GRPC_SEND_START,
/* send a message to the channels peer */
GRPC_SEND_MESSAGE,
/* send half-close to the channels peer */
GRPC_SEND_FINISH,
/* request that more data be allowed through flow control */
GRPC_REQUEST_DATA,
/* metadata was received from the channels peer */
GRPC_RECV_METADATA,
/* receive a deadline */
GRPC_RECV_DEADLINE,
/* the end of the first batch of metadata was received */
GRPC_RECV_END_OF_INITIAL_METADATA,
/* a message was received from the channels peer */
GRPC_RECV_MESSAGE,
/* half-close was received from the channels peer */
GRPC_RECV_HALF_CLOSE,
/* full close was received from the channels peer */
GRPC_RECV_FINISH,
/* the call has been abnormally terminated */
GRPC_CANCEL_OP
} grpc_call_op_type;
/* The direction of the call.
The values of the enums (1, -1) matter here - they are used to increment
or decrement a pointer to find the next element to call */
typedef enum { GRPC_CALL_DOWN = 1, GRPC_CALL_UP = -1 } grpc_call_dir;
/* A single filterable operation to be performed on a call */
typedef struct {
/* The type of operation we're performing */
grpc_call_op_type type;
/* The directionality of this call - does the operation begin at the bottom
of the stack and flow up, or does the operation start at the top of the
stack and flow down through the filters. */
grpc_call_dir dir;
/* Flags associated with this call: see GRPC_WRITE_* in grpc.h */
gpr_uint32 flags;
/* Argument data, matching up with grpc_call_op_type names */
union {
grpc_byte_buffer *message;
grpc_mdelem *metadata;
gpr_timespec deadline;
} data;
/* Must be called when processing of this call-op is complete.
Signature chosen to match transport flow control callbacks */
void (*done_cb)(void *user_data, grpc_op_error error);
/* User data to be passed into done_cb */
void *user_data;
} grpc_call_op;
/* returns a string representation of op, that can be destroyed with gpr_free */
char *grpc_call_op_string(grpc_call_op *op);
typedef enum {
GRPC_CHANNEL_SHUTDOWN,
GRPC_ACCEPT_CALL,
GRPC_TRANSPORT_CLOSED
} grpc_channel_op_type;
/* A single filterable operation to be performed on a channel */
typedef struct {
/* The type of operation we're performing */
grpc_channel_op_type type;
/* The directionality of this call - is it bubbling up the stack, or down? */
grpc_call_dir dir;
/* Argument data, matching up with grpc_channel_op_type names */
union {
struct {
grpc_transport *transport;
const void *transport_server_data;
} accept_call;
} data;
} grpc_channel_op;
/* Channel filters specify:
1. the amount of memory needed in the channel & call (via the sizeof_XXX
members)
2. functions to initialize and destroy channel & call data
(init_XXX, destroy_XXX)
3. functions to implement call operations and channel operations (call_op,
channel_op)
4. a name, which is useful when debugging
Members are laid out in approximate frequency of use order. */
typedef struct {
/* Called to eg. send/receive data on a call.
See grpc_call_next_op on how to call the next element in the stack */
void (*call_op)(grpc_call_element *elem, grpc_call_op *op);
/* Called to handle channel level operations - e.g. new calls, or transport
closure.
See grpc_channel_next_op on how to call the next element in the stack */
void (*channel_op)(grpc_channel_element *elem, grpc_channel_op *op);
/* sizeof(per call data) */
size_t sizeof_call_data;
/* Initialize per call data.
elem is initialized at the start of the call, and elem->call_data is what
needs initializing.
The filter does not need to do any chaining.
server_transport_data is an opaque pointer. If it is NULL, this call is
on a client; if it is non-NULL, then it points to memory owned by the
transport and is on the server. Most filters want to ignore this
argument.*/
void (*init_call_elem)(grpc_call_element *elem,
const void *server_transport_data);
/* Destroy per call data.
The filter does not need to do any chaining */
void (*destroy_call_elem)(grpc_call_element *elem);
/* sizeof(per channel data) */
size_t sizeof_channel_data;
/* Initialize per-channel data.
elem is initialized at the start of the call, and elem->channel_data is
what needs initializing.
is_first, is_last designate this elements position in the stack, and are
useful for asserting correct configuration by upper layer code.
The filter does not need to do any chaining */
void (*init_channel_elem)(grpc_channel_element *elem,
const grpc_channel_args *args,
grpc_mdctx *metadata_context, int is_first,
int is_last);
/* Destroy per channel data.
The filter does not need to do any chaining */
void (*destroy_channel_elem)(grpc_channel_element *elem);
/* The name of this filter */
const char *name;
} grpc_channel_filter;
/* A channel_element tracks its filter and the filter requested memory within
a channel allocation */
struct grpc_channel_element {
const grpc_channel_filter *filter;
void *channel_data;
};
/* A call_element tracks its filter, the filter requested memory within
a channel allocation, and the filter requested memory within a call
allocation */
struct grpc_call_element {
const grpc_channel_filter *filter;
void *channel_data;
void *call_data;
};
/* A channel stack tracks a set of related filters for one channel, and
guarantees they live within a single malloc() allocation */
typedef struct {
size_t count;
/* Memory required for a call stack (computed at channel stack
initialization) */
size_t call_stack_size;
} grpc_channel_stack;
/* A call stack tracks a set of related filters for one call, and guarantees
they live within a single malloc() allocation */
typedef struct { size_t count; } grpc_call_stack;
/* Get a channel element given a channel stack and its index */
grpc_channel_element *grpc_channel_stack_element(grpc_channel_stack *stack,
size_t i);
/* Get the last channel element in a channel stack */
grpc_channel_element *grpc_channel_stack_last_element(
grpc_channel_stack *stack);
/* Get a call stack element given a call stack and an index */
grpc_call_element *grpc_call_stack_element(grpc_call_stack *stack, size_t i);
/* Determine memory required for a channel stack containing a set of filters */
size_t grpc_channel_stack_size(const grpc_channel_filter **filters,
size_t filter_count);
/* Initialize a channel stack given some filters */
void grpc_channel_stack_init(const grpc_channel_filter **filters,
size_t filter_count, const grpc_channel_args *args,
grpc_mdctx *metadata_context,
grpc_channel_stack *stack);
/* Destroy a channel stack */
void grpc_channel_stack_destroy(grpc_channel_stack *stack);
/* Initialize a call stack given a channel stack. transport_server_data is
expected to be NULL on a client, or an opaque transport owned pointer on the
server. */
void grpc_call_stack_init(grpc_channel_stack *channel_stack,
const void *transport_server_data,
grpc_call_stack *call_stack);
/* Destroy a call stack */
void grpc_call_stack_destroy(grpc_call_stack *stack);
/* Call the next operation (depending on call directionality) in a call stack */
void grpc_call_next_op(grpc_call_element *elem, grpc_call_op *op);
/* Call the next operation (depending on call directionality) in a channel
stack */
void grpc_channel_next_op(grpc_channel_element *elem, grpc_channel_op *op);
/* Given the top element of a channel stack, get the channel stack itself */
grpc_channel_stack *grpc_channel_stack_from_top_element(
grpc_channel_element *elem);
/* Given the top element of a call stack, get the call stack itself */
grpc_call_stack *grpc_call_stack_from_top_element(grpc_call_element *elem);
void grpc_call_log_op(char *file, int line, gpr_log_severity severity,
grpc_call_element *elem, grpc_call_op *op);
void grpc_call_element_send_metadata(grpc_call_element *cur_elem,
grpc_mdelem *elem);
void grpc_call_element_send_cancel(grpc_call_element *cur_elem);
#ifdef GRPC_CHANNEL_STACK_TRACE
#define GRPC_CALL_LOG_OP(sev, elem, op) grpc_call_log_op(sev, elem, op)
#else
#define GRPC_CALL_LOG_OP(sev, elem, op) \
do { \
} while (0)
#endif
#endif /* __GRPC_INTERNAL_CHANNEL_CHANNEL_STACK_H__ */

@ -0,0 +1,641 @@
/*
*
* 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/channel/client_channel.h"
#include <stdio.h>
#include "src/core/channel/channel_args.h"
#include "src/core/channel/connected_channel.h"
#include "src/core/channel/metadata_buffer.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string.h>
#include <grpc/support/sync.h>
#include <grpc/support/useful.h>
/* Link back filter: passes up calls to the client channel, pushes down calls
down */
typedef struct { grpc_channel_element *back; } lb_channel_data;
typedef struct { grpc_call_element *back; } lb_call_data;
static void lb_call_op(grpc_call_element *elem, grpc_call_op *op) {
lb_call_data *calld = elem->call_data;
switch (op->dir) {
case GRPC_CALL_UP:
calld->back->filter->call_op(calld->back, op);
break;
case GRPC_CALL_DOWN:
grpc_call_next_op(elem, op);
break;
}
}
/* Currently we assume all channel operations should just be pushed up. */
static void lb_channel_op(grpc_channel_element *elem, grpc_channel_op *op) {
lb_channel_data *chand = elem->channel_data;
switch (op->dir) {
case GRPC_CALL_UP:
chand->back->filter->channel_op(chand->back, op);
break;
case GRPC_CALL_DOWN:
grpc_channel_next_op(elem, op);
break;
}
}
/* Constructor for call_data */
static void lb_init_call_elem(grpc_call_element *elem,
const void *server_transport_data) {}
/* Destructor for call_data */
static void lb_destroy_call_elem(grpc_call_element *elem) {}
/* Constructor for channel_data */
static void lb_init_channel_elem(grpc_channel_element *elem,
const grpc_channel_args *args,
grpc_mdctx *metadata_context, int is_first,
int is_last) {
GPR_ASSERT(is_first);
GPR_ASSERT(!is_last);
}
/* Destructor for channel_data */
static void lb_destroy_channel_elem(grpc_channel_element *elem) {}
static const grpc_channel_filter link_back_filter = {
lb_call_op, lb_channel_op,
sizeof(lb_call_data), lb_init_call_elem, lb_destroy_call_elem,
sizeof(lb_channel_data), lb_init_channel_elem, lb_destroy_channel_elem,
"clientchannel.linkback",
};
/* Client channel implementation */
typedef struct {
size_t inflight_requests;
grpc_channel_stack *channel_stack;
} child_entry;
typedef struct call_data call_data;
typedef struct {
/* protects children, child_count, child_capacity, active_child,
transport_setup_initiated
does not protect channel stacks held by children
transport_setup is assumed to be set once during construction */
gpr_mu mu;
/* the sending child (points somewhere in children, or NULL) */
child_entry *active_child;
/* vector of child channels */
child_entry *children;
size_t child_count;
size_t child_capacity;
/* calls waiting for a channel to be ready */
call_data **waiting_children;
size_t waiting_child_count;
size_t waiting_child_capacity;
/* transport setup for this channel */
grpc_transport_setup *transport_setup;
int transport_setup_initiated;
grpc_channel_args *args;
/* metadata cache */
grpc_mdelem *cancel_status;
} channel_data;
typedef enum {
CALL_CREATED,
CALL_WAITING,
CALL_ACTIVE,
CALL_CANCELLED
} call_state;
struct call_data {
/* owning element */
grpc_call_element *elem;
call_state state;
grpc_metadata_buffer pending_metadata;
gpr_timespec deadline;
union {
struct {
/* our child call stack */
grpc_call_stack *child_stack;
/* ... and the channel stack associated with it */
grpc_channel_stack *using_stack;
} active;
struct {
void (*on_complete)(void *user_data, grpc_op_error error);
void *on_complete_user_data;
gpr_uint32 start_flags;
} waiting;
} s;
};
static int prepare_activate(call_data *calld, child_entry *on_child) {
grpc_call_element *child_elem;
grpc_channel_stack *use_stack = on_child->channel_stack;
if (calld->state == CALL_CANCELLED) return 0;
on_child->inflight_requests++;
/* no more access to calld->s.waiting allowed */
GPR_ASSERT(calld->state == CALL_WAITING);
calld->state = CALL_ACTIVE;
/* create a child stack, and record that we're using a particular channel
stack */
calld->s.active.child_stack = gpr_malloc(use_stack->call_stack_size);
calld->s.active.using_stack = use_stack;
grpc_call_stack_init(use_stack, NULL, calld->s.active.child_stack);
/* initialize the top level link back element */
child_elem = grpc_call_stack_element(calld->s.active.child_stack, 0);
GPR_ASSERT(child_elem->filter == &link_back_filter);
((lb_call_data *)child_elem->call_data)->back = calld->elem;
return 1;
}
static void do_nothing(void *ignored, grpc_op_error error) {}
static void complete_activate(call_data *calld, child_entry *on_child,
grpc_call_op *op) {
grpc_call_element *child_elem =
grpc_call_stack_element(calld->s.active.child_stack, 0);
GPR_ASSERT(calld->state == CALL_ACTIVE);
/* sending buffered metadata down the stack before the start call */
grpc_metadata_buffer_flush(&calld->pending_metadata, child_elem);
if (gpr_time_cmp(calld->deadline, gpr_inf_future) != 0) {
grpc_call_op dop;
dop.type = GRPC_SEND_DEADLINE;
dop.dir = GRPC_CALL_DOWN;
dop.flags = 0;
dop.data.deadline = calld->deadline;
dop.done_cb = do_nothing;
dop.user_data = NULL;
child_elem->filter->call_op(child_elem, &dop);
}
/* continue the start call down the stack, this nees to happen after metadata
are flushed*/
child_elem->filter->call_op(child_elem, op);
}
static void start_rpc(call_data *calld, channel_data *chand, grpc_call_op *op) {
gpr_mu_lock(&chand->mu);
if (calld->state == CALL_CANCELLED) {
gpr_mu_unlock(&chand->mu);
op->done_cb(op->user_data, GRPC_OP_ERROR);
return;
}
GPR_ASSERT(calld->state == CALL_CREATED);
calld->state = CALL_WAITING;
if (chand->active_child) {
/* channel is connected - use the connected stack */
if (prepare_activate(calld, chand->active_child)) {
gpr_mu_unlock(&chand->mu);
/* activate the request (pass it down) outside the lock */
complete_activate(calld, chand->active_child, op);
} else {
gpr_mu_unlock(&chand->mu);
}
} else {
/* check to see if we should initiate a connection (if we're not already),
but don't do so until outside the lock to avoid re-entrancy problems if
the callback is immediate */
int initiate_transport_setup = 0;
if (!chand->transport_setup_initiated) {
chand->transport_setup_initiated = 1;
initiate_transport_setup = 1;
}
/* add this call to the waiting set to be resumed once we have a child
channel stack, growing the waiting set if needed */
if (chand->waiting_child_count == chand->waiting_child_capacity) {
chand->waiting_child_capacity =
GPR_MAX(chand->waiting_child_capacity * 2, 8);
chand->waiting_children =
gpr_realloc(chand->waiting_children,
chand->waiting_child_capacity * sizeof(call_data *));
}
calld->s.waiting.on_complete = op->done_cb;
calld->s.waiting.on_complete_user_data = op->user_data;
calld->s.waiting.start_flags = op->flags;
chand->waiting_children[chand->waiting_child_count++] = calld;
gpr_mu_unlock(&chand->mu);
/* finally initiate transport setup if needed */
if (initiate_transport_setup) {
grpc_transport_setup_initiate(chand->transport_setup);
}
}
}
static void remove_waiting_child(channel_data *chand, call_data *calld) {
size_t new_count;
size_t i;
for (i = 0, new_count = 0; i < chand->waiting_child_count; i++) {
if (chand->waiting_children[i] == calld) continue;
chand->waiting_children[new_count++] = chand->waiting_children[i];
}
GPR_ASSERT(new_count == chand->waiting_child_count - 1 ||
new_count == chand->waiting_child_count);
chand->waiting_child_count = new_count;
}
static void cancel_rpc(grpc_call_element *elem, grpc_call_op *op) {
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
grpc_call_element *child_elem;
grpc_call_op finish_op;
gpr_mu_lock(&chand->mu);
switch (calld->state) {
case CALL_ACTIVE:
child_elem = grpc_call_stack_element(calld->s.active.child_stack, 0);
gpr_mu_unlock(&chand->mu);
child_elem->filter->call_op(child_elem, op);
return; /* early out */
case CALL_WAITING:
remove_waiting_child(chand, calld);
calld->s.waiting.on_complete(calld->s.waiting.on_complete_user_data,
GRPC_OP_ERROR);
/* fallthrough intended */
case CALL_CREATED:
calld->state = CALL_CANCELLED;
gpr_mu_unlock(&chand->mu);
/* send up a synthesized status */
finish_op.type = GRPC_RECV_METADATA;
finish_op.dir = GRPC_CALL_UP;
finish_op.flags = 0;
finish_op.data.metadata = grpc_mdelem_ref(chand->cancel_status);
finish_op.done_cb = do_nothing;
finish_op.user_data = NULL;
grpc_call_next_op(elem, &finish_op);
/* send up a finish */
finish_op.type = GRPC_RECV_FINISH;
finish_op.dir = GRPC_CALL_UP;
finish_op.flags = 0;
finish_op.done_cb = do_nothing;
finish_op.user_data = NULL;
grpc_call_next_op(elem, &finish_op);
return; /* early out */
case CALL_CANCELLED:
gpr_mu_unlock(&chand->mu);
return; /* early out */
}
gpr_log(GPR_ERROR, "should never reach here");
abort();
}
static void call_op(grpc_call_element *elem, grpc_call_op *op) {
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
grpc_call_element *child_elem;
GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
switch (op->type) {
case GRPC_SEND_METADATA:
grpc_metadata_buffer_queue(&calld->pending_metadata, op);
break;
case GRPC_SEND_DEADLINE:
calld->deadline = op->data.deadline;
op->done_cb(op->user_data, GRPC_OP_OK);
break;
case GRPC_SEND_START:
/* filter out the start event to find which child to send on */
start_rpc(calld, chand, op);
break;
case GRPC_CANCEL_OP:
cancel_rpc(elem, op);
break;
default:
switch (op->dir) {
case GRPC_CALL_UP:
grpc_call_next_op(elem, op);
break;
case GRPC_CALL_DOWN:
child_elem = grpc_call_stack_element(calld->s.active.child_stack, 0);
GPR_ASSERT(calld->state == CALL_ACTIVE);
child_elem->filter->call_op(child_elem, op);
break;
}
break;
}
}
static void broadcast_channel_op_down(grpc_channel_element *elem,
grpc_channel_op *op) {
channel_data *chand = elem->channel_data;
grpc_channel_element *child_elem;
grpc_channel_stack **children;
size_t child_count;
size_t i;
/* copy the current set of children, and mark them all as having an inflight
request */
gpr_mu_lock(&chand->mu);
child_count = chand->child_count;
children = gpr_malloc(sizeof(grpc_channel_stack *) * child_count);
for (i = 0; i < child_count; i++) {
children[i] = chand->children[i].channel_stack;
chand->children[i].inflight_requests++;
}
gpr_mu_unlock(&chand->mu);
/* send the message down */
for (i = 0; i < child_count; i++) {
child_elem = grpc_channel_stack_element(children[i], 0);
child_elem->filter->channel_op(child_elem, op);
}
/* unmark the inflight requests */
gpr_mu_lock(&chand->mu);
for (i = 0; i < child_count; i++) {
chand->children[i].inflight_requests--;
}
gpr_mu_unlock(&chand->mu);
gpr_free(children);
}
static void channel_op(grpc_channel_element *elem, grpc_channel_op *op) {
GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
switch (op->type) {
default:
switch (op->dir) {
case GRPC_CALL_UP:
grpc_channel_next_op(elem, op);
break;
case GRPC_CALL_DOWN:
broadcast_channel_op_down(elem, op);
break;
}
break;
}
}
static void error_bad_on_complete(void *arg, grpc_op_error error) {
gpr_log(GPR_ERROR,
"Waiting finished but not started? Bad on_complete callback");
abort();
}
/* Constructor for call_data */
static void init_call_elem(grpc_call_element *elem,
const void *server_transport_data) {
call_data *calld = elem->call_data;
GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
GPR_ASSERT(server_transport_data == NULL);
calld->elem = elem;
calld->state = CALL_CREATED;
calld->deadline = gpr_inf_future;
calld->s.waiting.on_complete = error_bad_on_complete;
calld->s.waiting.on_complete_user_data = NULL;
grpc_metadata_buffer_init(&calld->pending_metadata);
}
/* Destructor for call_data */
static void destroy_call_elem(grpc_call_element *elem) {
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
size_t i;
/* if the metadata buffer is not flushed, destroy it here. */
grpc_metadata_buffer_destroy(&calld->pending_metadata, GRPC_OP_OK);
/* if the call got activated, we need to destroy the child stack also, and
remove it from the in-flight requests tracked by the child_entry we
picked */
if (calld->state == CALL_ACTIVE) {
grpc_call_stack_destroy(calld->s.active.child_stack);
gpr_free(calld->s.active.child_stack);
gpr_mu_lock(&chand->mu);
for (i = 0; i < chand->child_count; i++) {
if (chand->children[i].channel_stack == calld->s.active.using_stack) {
chand->children[i].inflight_requests--;
/* TODO(ctiller): garbage collect channels that are not active
and have no inflight requests */
}
}
gpr_mu_unlock(&chand->mu);
}
}
/* Constructor for channel_data */
static void init_channel_elem(grpc_channel_element *elem,
const grpc_channel_args *args,
grpc_mdctx *metadata_context, int is_first,
int is_last) {
channel_data *chand = elem->channel_data;
char temp[16];
GPR_ASSERT(!is_first);
GPR_ASSERT(is_last);
GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
gpr_mu_init(&chand->mu);
chand->active_child = NULL;
chand->children = NULL;
chand->child_count = 0;
chand->child_capacity = 0;
chand->waiting_children = NULL;
chand->waiting_child_count = 0;
chand->waiting_child_capacity = 0;
chand->transport_setup = NULL;
chand->transport_setup_initiated = 0;
chand->args = grpc_channel_args_copy(args);
sprintf(temp, "%d", GRPC_STATUS_CANCELLED);
chand->cancel_status =
grpc_mdelem_from_strings(metadata_context, "grpc-status", temp);
}
/* Destructor for channel_data */
static void destroy_channel_elem(grpc_channel_element *elem) {
channel_data *chand = elem->channel_data;
size_t i;
grpc_transport_setup_cancel(chand->transport_setup);
for (i = 0; i < chand->child_count; i++) {
GPR_ASSERT(chand->children[i].inflight_requests == 0);
grpc_channel_stack_destroy(chand->children[i].channel_stack);
gpr_free(chand->children[i].channel_stack);
}
grpc_channel_args_destroy(chand->args);
grpc_mdelem_unref(chand->cancel_status);
gpr_mu_destroy(&chand->mu);
GPR_ASSERT(chand->waiting_child_count == 0);
gpr_free(chand->waiting_children);
gpr_free(chand->children);
}
const grpc_channel_filter grpc_client_channel_filter = {
call_op, channel_op,
sizeof(call_data), init_call_elem, destroy_call_elem,
sizeof(channel_data), init_channel_elem, destroy_channel_elem,
"clientchannel",
};
grpc_transport_setup_result grpc_client_channel_transport_setup_complete(
grpc_channel_stack *channel_stack, grpc_transport *transport,
grpc_channel_filter const **channel_filters, size_t num_channel_filters,
grpc_mdctx *mdctx) {
/* we just got a new transport: lets create a child channel stack for it */
grpc_channel_element *elem = grpc_channel_stack_last_element(channel_stack);
channel_data *chand = elem->channel_data;
grpc_channel_element *lb_elem;
grpc_channel_stack *child_stack;
size_t num_child_filters = 2 + num_channel_filters;
grpc_channel_filter const **child_filters;
grpc_transport_setup_result result;
child_entry *child_ent;
call_data **waiting_children;
size_t waiting_child_count;
size_t i;
grpc_call_op *call_ops;
/* build the child filter stack */
child_filters = gpr_malloc(sizeof(grpc_channel_filter *) * num_child_filters);
/* we always need a link back filter to get back to the connected channel */
child_filters[0] = &link_back_filter;
for (i = 0; i < num_channel_filters; i++) {
child_filters[i + 1] = channel_filters[i];
}
/* and we always need a connected channel to talk to the transport */
child_filters[num_child_filters - 1] = &grpc_connected_channel_filter;
GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
/* BEGIN LOCKING CHANNEL */
gpr_mu_lock(&chand->mu);
chand->transport_setup_initiated = 0;
if (chand->child_count == chand->child_capacity) {
/* realloc will invalidate chand->active_child, but it's reset in the next
stanza anyway */
chand->child_capacity =
GPR_MAX(2 * chand->child_capacity, chand->child_capacity + 2);
chand->children = gpr_realloc(chand->children,
sizeof(child_entry) * chand->child_capacity);
}
/* build up the child stack */
child_stack =
gpr_malloc(grpc_channel_stack_size(child_filters, num_child_filters));
grpc_channel_stack_init(child_filters, num_child_filters, chand->args, mdctx,
child_stack);
lb_elem = grpc_channel_stack_element(child_stack, 0);
GPR_ASSERT(lb_elem->filter == &link_back_filter);
((lb_channel_data *)lb_elem->channel_data)->back = elem;
result = grpc_connected_channel_bind_transport(child_stack, transport);
child_ent = &chand->children[chand->child_count++];
child_ent->channel_stack = child_stack;
child_ent->inflight_requests = 0;
chand->active_child = child_ent;
/* capture the waiting children - we'll activate them outside the lock
to avoid re-entrancy problems */
waiting_children = chand->waiting_children;
waiting_child_count = chand->waiting_child_count;
/* bumping up inflight_requests here avoids taking a lock per rpc below */
chand->waiting_children = NULL;
chand->waiting_child_count = 0;
chand->waiting_child_capacity = 0;
call_ops = gpr_malloc(sizeof(grpc_call_op) * waiting_child_count);
for (i = 0; i < waiting_child_count; i++) {
call_ops[i].type = GRPC_SEND_START;
call_ops[i].dir = GRPC_CALL_DOWN;
call_ops[i].flags = waiting_children[i]->s.waiting.start_flags;
call_ops[i].done_cb = waiting_children[i]->s.waiting.on_complete;
call_ops[i].user_data =
waiting_children[i]->s.waiting.on_complete_user_data;
if (!prepare_activate(waiting_children[i], child_ent)) {
waiting_children[i] = NULL;
call_ops[i].done_cb(call_ops[i].user_data, GRPC_OP_ERROR);
}
}
/* END LOCKING CHANNEL */
gpr_mu_unlock(&chand->mu);
/* activate any pending operations - this is safe to do as we guarantee one
and only one write operation per request at the surface api - if we lose
that guarantee we need to do some curly locking here */
for (i = 0; i < waiting_child_count; i++) {
if (waiting_children[i]) {
complete_activate(waiting_children[i], child_ent, &call_ops[i]);
}
}
gpr_free(waiting_children);
gpr_free(call_ops);
gpr_free(child_filters);
return result;
}
void grpc_client_channel_set_transport_setup(grpc_channel_stack *channel_stack,
grpc_transport_setup *setup) {
/* post construction initialization: set the transport setup pointer */
grpc_channel_element *elem = grpc_channel_stack_last_element(channel_stack);
channel_data *chand = elem->channel_data;
GPR_ASSERT(!chand->transport_setup);
chand->transport_setup = setup;
}

@ -0,0 +1,62 @@
/*
*
* 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_INTERNAL_CHANNEL_CLIENT_CHANNEL_H__
#define __GRPC_INTERNAL_CHANNEL_CLIENT_CHANNEL_H__
#include "src/core/channel/channel_stack.h"
/* A client channel is a channel that begins disconnected, and can connect
to some endpoint on demand. If that endpoint disconnects, it will be
connected to again later.
Calls on a disconnected client channel are queued until a connection is
established. */
extern const grpc_channel_filter grpc_client_channel_filter;
/* post-construction initializer to let the client channel know which
transport setup it should cancel upon destruction, or initiate when it needs
a connection */
void grpc_client_channel_set_transport_setup(grpc_channel_stack *channel_stack,
grpc_transport_setup *setup);
/* grpc_transport_setup_callback for binding new transports into a client
channel - user_data should be the channel stack containing the client
channel */
grpc_transport_setup_result grpc_client_channel_transport_setup_complete(
grpc_channel_stack *channel_stack, grpc_transport *transport,
grpc_channel_filter const **channel_filters, size_t num_channel_filters,
grpc_mdctx *mdctx);
#endif /* __GRPC_INTERNAL_CHANNEL_CLIENT_CHANNEL_H__ */

@ -0,0 +1,239 @@
/*
*
* 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/channel/client_setup.h"
#include "src/core/channel/channel_args.h"
#include "src/core/channel/channel_stack.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/time.h>
struct grpc_client_setup {
grpc_transport_setup base; /* must be first */
void (*initiate)(void *user_data, grpc_client_setup_request *request);
void (*done)(void *user_data);
void *user_data;
grpc_channel_args *args;
grpc_mdctx *mdctx;
grpc_em *em;
grpc_em_alarm backoff_alarm;
gpr_timespec current_backoff_interval;
int in_alarm;
gpr_mu mu;
grpc_client_setup_request *active_request;
int refs;
};
struct grpc_client_setup_request {
/* pointer back to the setup object */
grpc_client_setup *setup;
gpr_timespec deadline;
};
gpr_timespec grpc_client_setup_request_deadline(grpc_client_setup_request *r) {
return r->deadline;
}
static void destroy_setup(grpc_client_setup *s) {
gpr_mu_destroy(&s->mu);
s->done(s->user_data);
grpc_channel_args_destroy(s->args);
gpr_free(s);
}
/* initiate handshaking */
static void setup_initiate(grpc_transport_setup *sp) {
grpc_client_setup *s = (grpc_client_setup *)sp;
grpc_client_setup_request *r = gpr_malloc(sizeof(grpc_client_setup_request));
int in_alarm = 0;
r->setup = s;
/* TODO(klempner): Actually set a deadline */
r->deadline = gpr_inf_future;
gpr_mu_lock(&s->mu);
GPR_ASSERT(s->refs > 0);
/* there might be more than one request outstanding if the caller calls
initiate in some kind of rapid-fire way: we try to connect each time,
and keep track of the latest request (which is the only one that gets
to finish) */
if (!s->in_alarm) {
s->active_request = r;
s->refs++;
} else {
/* TODO(klempner): Maybe do something more clever here */
in_alarm = 1;
}
gpr_mu_unlock(&s->mu);
if (!in_alarm) {
s->initiate(s->user_data, r);
} else {
gpr_free(r);
}
}
/* cancel handshaking: cancel all requests, and shutdown (the caller promises
not to initiate again) */
static void setup_cancel(grpc_transport_setup *sp) {
grpc_client_setup *s = (grpc_client_setup *)sp;
void *ignored;
gpr_mu_lock(&s->mu);
GPR_ASSERT(s->refs > 0);
/* effectively cancels the current request (if any) */
s->active_request = NULL;
if (s->in_alarm) {
grpc_em_alarm_cancel(&s->backoff_alarm, &ignored);
}
if (--s->refs == 0) {
gpr_mu_unlock(&s->mu);
destroy_setup(s);
} else {
gpr_mu_unlock(&s->mu);
}
}
/* vtable for transport setup */
static const grpc_transport_setup_vtable setup_vtable = {setup_initiate,
setup_cancel};
void grpc_client_setup_create_and_attach(
grpc_channel_stack *newly_minted_channel, const grpc_channel_args *args,
grpc_mdctx *mdctx,
void (*initiate)(void *user_data, grpc_client_setup_request *request),
void (*done)(void *user_data), void *user_data, grpc_em *em) {
grpc_client_setup *s = gpr_malloc(sizeof(grpc_client_setup));
s->base.vtable = &setup_vtable;
gpr_mu_init(&s->mu);
s->refs = 1;
s->mdctx = mdctx;
s->initiate = initiate;
s->done = done;
s->user_data = user_data;
s->em = em;
s->active_request = NULL;
s->args = grpc_channel_args_copy(args);
s->current_backoff_interval = gpr_time_from_micros(1000000);
s->in_alarm = 0;
grpc_client_channel_set_transport_setup(newly_minted_channel, &s->base);
}
int grpc_client_setup_request_should_continue(grpc_client_setup_request *r) {
int result;
if (gpr_time_cmp(gpr_now(), r->deadline) > 0) {
return 0;
}
gpr_mu_lock(&r->setup->mu);
result = r->setup->active_request == r;
gpr_mu_unlock(&r->setup->mu);
return result;
}
static void backoff_alarm_done(void *arg /* grpc_client_setup */,
grpc_em_cb_status status) {
grpc_client_setup *s = arg;
grpc_client_setup_request *r = gpr_malloc(sizeof(grpc_client_setup_request));
r->setup = s;
/* TODO(klempner): Set this to something useful */
r->deadline = gpr_inf_future;
/* Handle status cancelled? */
gpr_mu_lock(&s->mu);
s->active_request = r;
s->in_alarm = 0;
if (status != GRPC_CALLBACK_SUCCESS) {
if (0 == --s->refs) {
gpr_mu_unlock(&s->mu);
destroy_setup(s);
gpr_free(r);
return;
} else {
gpr_mu_unlock(&s->mu);
return;
}
}
gpr_mu_unlock(&s->mu);
s->initiate(s->user_data, r);
}
void grpc_client_setup_request_finish(grpc_client_setup_request *r,
int was_successful) {
int retry = !was_successful;
grpc_client_setup *s = r->setup;
gpr_mu_lock(&s->mu);
if (s->active_request == r) {
s->active_request = NULL;
} else {
retry = 0;
}
if (!retry && 0 == --s->refs) {
gpr_mu_unlock(&s->mu);
destroy_setup(s);
gpr_free(r);
return;
}
gpr_free(r);
if (retry) {
/* TODO(klempner): Replace these values with further consideration. 2x is
probably too aggressive of a backoff. */
gpr_timespec max_backoff = gpr_time_from_micros(120000000);
GPR_ASSERT(!s->in_alarm);
s->in_alarm = 1;
grpc_em_alarm_init(&s->backoff_alarm, s->em, backoff_alarm_done, s);
grpc_em_alarm_add(&s->backoff_alarm,
gpr_time_add(s->current_backoff_interval, gpr_now()));
s->current_backoff_interval =
gpr_time_add(s->current_backoff_interval, s->current_backoff_interval);
if (gpr_time_cmp(s->current_backoff_interval, max_backoff) > 0) {
s->current_backoff_interval = max_backoff;
}
}
gpr_mu_unlock(&s->mu);
}
const grpc_channel_args *grpc_client_setup_get_channel_args(
grpc_client_setup_request *r) {
return r->setup->args;
}
grpc_mdctx *grpc_client_setup_get_mdctx(grpc_client_setup_request *r) {
return r->setup->mdctx;
}

@ -0,0 +1,68 @@
/*
*
* 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_INTERNAL_CHANNEL_CLIENT_SETUP_H__
#define __GRPC_INTERNAL_CHANNEL_CLIENT_SETUP_H__
#include "src/core/channel/client_channel.h"
#include "src/core/eventmanager/em.h"
#include "src/core/transport/metadata.h"
#include <grpc/support/time.h>
/* Convenience API's to simplify transport setup */
typedef struct grpc_client_setup grpc_client_setup;
typedef struct grpc_client_setup_request grpc_client_setup_request;
void grpc_client_setup_create_and_attach(
grpc_channel_stack *newly_minted_channel, const grpc_channel_args *args,
grpc_mdctx *mdctx,
void (*initiate)(void *user_data, grpc_client_setup_request *request),
void (*done)(void *user_data), void *user_data, grpc_em *em);
/* Check that r is the active request: needs to be performed at each callback.
If this races, we'll have two connection attempts running at once and the
old one will get cleaned up in due course, which is fine. */
int grpc_client_setup_request_should_continue(grpc_client_setup_request *r);
void grpc_client_setup_request_finish(grpc_client_setup_request *r,
int was_successful);
const grpc_channel_args *grpc_client_setup_get_channel_args(
grpc_client_setup_request *r);
/* Get the deadline for a request passed in to initiate. Implementations should
make a best effort to honor this deadline. */
gpr_timespec grpc_client_setup_request_deadline(grpc_client_setup_request *r);
grpc_mdctx *grpc_client_setup_get_mdctx(grpc_client_setup_request *r);
#endif /* __GRPC_INTERNAL_CHANNEL_CLIENT_SETUP_H__ */

@ -0,0 +1,501 @@
/*
*
* 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/channel/connected_channel.h"
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include "src/core/transport/transport.h"
#include <grpc/byte_buffer.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/slice_buffer.h>
#include <grpc/support/string.h>
#define MAX_BUFFER_LENGTH 8192
/* the protobuf library will (by default) start warning at 100megs */
#define DEFAULT_MAX_MESSAGE_LENGTH (100 * 1024 * 1024)
typedef struct {
grpc_transport *transport;
gpr_uint32 max_message_length;
} channel_data;
typedef struct {
grpc_call_element *elem;
grpc_stream_op_buffer outgoing_sopb;
gpr_uint32 max_message_length;
gpr_uint32 incoming_message_length;
gpr_uint8 reading_message;
gpr_uint8 got_metadata_boundary;
gpr_uint8 got_read_close;
gpr_slice_buffer incoming_message;
gpr_uint32 outgoing_buffer_length_estimate;
} call_data;
/* We perform a small hack to locate transport data alongside the connected
channel data in call allocations, to allow everything to be pulled in minimal
cache line requests */
#define TRANSPORT_STREAM_FROM_CALL_DATA(calld) ((grpc_stream *)((calld)+1))
#define CALL_DATA_FROM_TRANSPORT_STREAM(transport_stream) \
(((call_data *)(transport_stream)) - 1)
/* Copy the contents of a byte buffer into stream ops */
static void copy_byte_buffer_to_stream_ops(grpc_byte_buffer *byte_buffer,
grpc_stream_op_buffer *sopb) {
size_t i;
switch (byte_buffer->type) {
case GRPC_BB_SLICE_BUFFER:
for (i = 0; i < byte_buffer->data.slice_buffer.count; i++) {
gpr_slice slice = byte_buffer->data.slice_buffer.slices[i];
gpr_slice_ref(slice);
grpc_sopb_add_slice(sopb, slice);
}
break;
}
}
/* Flush queued stream operations onto the transport */
static void end_bufferable_op(grpc_call_op *op, channel_data *chand,
call_data *calld, int is_last) {
size_t nops;
if (op->flags & GRPC_WRITE_BUFFER_HINT) {
if (calld->outgoing_buffer_length_estimate < MAX_BUFFER_LENGTH) {
op->done_cb(op->user_data, GRPC_OP_OK);
return;
}
}
calld->outgoing_buffer_length_estimate = 0;
grpc_sopb_add_flow_ctl_cb(&calld->outgoing_sopb, op->done_cb, op->user_data);
nops = calld->outgoing_sopb.nops;
calld->outgoing_sopb.nops = 0;
grpc_transport_send_batch(chand->transport,
TRANSPORT_STREAM_FROM_CALL_DATA(calld),
calld->outgoing_sopb.ops, nops, is_last);
}
/* Intercept a call operation and either push it directly up or translate it
into transport stream operations */
static void call_op(grpc_call_element *elem, grpc_call_op *op) {
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
switch (op->type) {
case GRPC_SEND_METADATA:
grpc_sopb_add_metadata(&calld->outgoing_sopb, op->data.metadata);
grpc_sopb_add_flow_ctl_cb(&calld->outgoing_sopb, op->done_cb,
op->user_data);
break;
case GRPC_SEND_DEADLINE:
grpc_sopb_add_deadline(&calld->outgoing_sopb, op->data.deadline);
grpc_sopb_add_flow_ctl_cb(&calld->outgoing_sopb, op->done_cb,
op->user_data);
break;
case GRPC_SEND_START:
grpc_sopb_add_metadata_boundary(&calld->outgoing_sopb);
end_bufferable_op(op, chand, calld, 0);
break;
case GRPC_SEND_MESSAGE:
grpc_sopb_add_begin_message(&calld->outgoing_sopb,
grpc_byte_buffer_length(op->data.message),
op->flags);
copy_byte_buffer_to_stream_ops(op->data.message, &calld->outgoing_sopb);
calld->outgoing_buffer_length_estimate +=
(5 + grpc_byte_buffer_length(op->data.message));
end_bufferable_op(op, chand, calld, 0);
break;
case GRPC_SEND_FINISH:
end_bufferable_op(op, chand, calld, 1);
break;
case GRPC_REQUEST_DATA:
/* re-arm window updates if they were disarmed by finish_message */
grpc_transport_set_allow_window_updates(
chand->transport, TRANSPORT_STREAM_FROM_CALL_DATA(calld), 1);
break;
case GRPC_CANCEL_OP:
grpc_transport_abort_stream(chand->transport,
TRANSPORT_STREAM_FROM_CALL_DATA(calld),
GRPC_STATUS_CANCELLED);
break;
default:
GPR_ASSERT(op->dir == GRPC_CALL_UP);
grpc_call_next_op(elem, op);
break;
}
}
/* Currently we assume all channel operations should just be pushed up. */
static void channel_op(grpc_channel_element *elem, grpc_channel_op *op) {
channel_data *chand = elem->channel_data;
GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
switch (op->type) {
case GRPC_CHANNEL_SHUTDOWN:
grpc_transport_close(chand->transport);
break;
default:
GPR_ASSERT(op->dir == GRPC_CALL_UP);
grpc_channel_next_op(elem, op);
break;
}
}
/* Constructor for call_data */
static void init_call_elem(grpc_call_element *elem,
const void *server_transport_data) {
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
int r;
GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
calld->elem = elem;
grpc_sopb_init(&calld->outgoing_sopb);
calld->reading_message = 0;
calld->got_metadata_boundary = 0;
calld->got_read_close = 0;
calld->outgoing_buffer_length_estimate = 0;
calld->max_message_length = chand->max_message_length;
gpr_slice_buffer_init(&calld->incoming_message);
r = grpc_transport_init_stream(chand->transport,
TRANSPORT_STREAM_FROM_CALL_DATA(calld),
server_transport_data);
GPR_ASSERT(r == 0);
}
/* Destructor for call_data */
static void destroy_call_elem(grpc_call_element *elem) {
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
grpc_sopb_destroy(&calld->outgoing_sopb);
gpr_slice_buffer_destroy(&calld->incoming_message);
grpc_transport_destroy_stream(chand->transport,
TRANSPORT_STREAM_FROM_CALL_DATA(calld));
}
/* Constructor for channel_data */
static void init_channel_elem(grpc_channel_element *elem,
const grpc_channel_args *args, grpc_mdctx *mdctx,
int is_first, int is_last) {
channel_data *cd = (channel_data *)elem->channel_data;
size_t i;
GPR_ASSERT(!is_first);
GPR_ASSERT(is_last);
GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
cd->transport = NULL;
cd->max_message_length = DEFAULT_MAX_MESSAGE_LENGTH;
if (args) {
for (i = 0; i < args->num_args; i++) {
if (0 == strcmp(args->args[i].key, GRPC_ARG_MAX_MESSAGE_LENGTH)) {
if (args->args[i].type != GRPC_ARG_INTEGER) {
gpr_log(GPR_ERROR, "%s ignored: it must be an integer",
GRPC_ARG_MAX_MESSAGE_LENGTH);
} else if (args->args[i].value.integer < 0) {
gpr_log(GPR_ERROR, "%s ignored: it must be >= 0",
GRPC_ARG_MAX_MESSAGE_LENGTH);
} else {
cd->max_message_length = args->args[i].value.integer;
}
}
}
}
}
/* Destructor for channel_data */
static void destroy_channel_elem(grpc_channel_element *elem) {
channel_data *cd = (channel_data *)elem->channel_data;
GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
grpc_transport_destroy(cd->transport);
}
const grpc_channel_filter grpc_connected_channel_filter = {
call_op, channel_op,
sizeof(call_data), init_call_elem, destroy_call_elem,
sizeof(channel_data), init_channel_elem, destroy_channel_elem,
"connected",
};
static gpr_slice alloc_recv_buffer(void *user_data, grpc_transport *transport,
grpc_stream *stream, size_t size_hint) {
return gpr_slice_malloc(size_hint);
}
/* Transport callback to accept a new stream... calls up to handle it */
static void accept_stream(void *user_data, grpc_transport *transport,
const void *transport_server_data) {
grpc_channel_element *elem = user_data;
channel_data *chand = elem->channel_data;
grpc_channel_op op;
GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
GPR_ASSERT(chand->transport == transport);
op.type = GRPC_ACCEPT_CALL;
op.dir = GRPC_CALL_UP;
op.data.accept_call.transport = transport;
op.data.accept_call.transport_server_data = transport_server_data;
channel_op(elem, &op);
}
static void recv_error(channel_data *chand, call_data *calld, int line,
const char *fmt, ...) {
char msg[512];
va_list a;
va_start(a, fmt);
vsprintf(msg, fmt, a);
va_end(a);
gpr_log(__FILE__, line, GPR_LOG_SEVERITY_ERROR, "%s", msg);
if (chand->transport) {
grpc_transport_abort_stream(chand->transport,
TRANSPORT_STREAM_FROM_CALL_DATA(calld),
GRPC_STATUS_INVALID_ARGUMENT);
}
}
static void do_nothing(void *calldata, grpc_op_error error) {}
static void done_message(void *user_data, grpc_op_error error) {
grpc_byte_buffer_destroy(user_data);
}
static void finish_message(channel_data *chand, call_data *calld) {
grpc_call_element *elem = calld->elem;
grpc_call_op call_op;
call_op.dir = GRPC_CALL_UP;
call_op.flags = 0;
/* if we got all the bytes for this message, call up the stack */
call_op.type = GRPC_RECV_MESSAGE;
call_op.done_cb = done_message;
/* TODO(ctiller): this could be a lot faster if coded directly */
call_op.user_data = call_op.data.message = grpc_byte_buffer_create(
calld->incoming_message.slices, calld->incoming_message.count);
gpr_slice_buffer_reset_and_unref(&calld->incoming_message);
/* disable window updates until we get a request more from above */
grpc_transport_set_allow_window_updates(
chand->transport, TRANSPORT_STREAM_FROM_CALL_DATA(calld), 0);
GPR_ASSERT(calld->incoming_message.count == 0);
calld->reading_message = 0;
grpc_call_next_op(elem, &call_op);
}
/* Handle incoming stream ops from the transport, translating them into
call_ops to pass up the call stack */
static void recv_batch(void *user_data, grpc_transport *transport,
grpc_stream *stream, grpc_stream_op *ops,
size_t ops_count, grpc_stream_state final_state) {
call_data *calld = CALL_DATA_FROM_TRANSPORT_STREAM(stream);
grpc_call_element *elem = calld->elem;
channel_data *chand = elem->channel_data;
grpc_stream_op *stream_op;
grpc_call_op call_op;
size_t i;
gpr_uint32 length;
GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
for (i = 0; i < ops_count; i++) {
stream_op = ops + i;
switch (stream_op->type) {
case GRPC_OP_FLOW_CTL_CB:
gpr_log(GPR_ERROR,
"should not receive flow control ops from transport");
abort();
break;
case GRPC_NO_OP:
break;
case GRPC_OP_METADATA:
call_op.type = GRPC_RECV_METADATA;
call_op.dir = GRPC_CALL_UP;
call_op.flags = 0;
call_op.data.metadata = stream_op->data.metadata;
call_op.done_cb = do_nothing;
call_op.user_data = NULL;
grpc_call_next_op(elem, &call_op);
break;
case GRPC_OP_DEADLINE:
call_op.type = GRPC_RECV_DEADLINE;
call_op.dir = GRPC_CALL_UP;
call_op.flags = 0;
call_op.data.deadline = stream_op->data.deadline;
call_op.done_cb = do_nothing;
call_op.user_data = NULL;
grpc_call_next_op(elem, &call_op);
break;
case GRPC_OP_METADATA_BOUNDARY:
if (!calld->got_metadata_boundary) {
calld->got_metadata_boundary = 1;
call_op.type = GRPC_RECV_END_OF_INITIAL_METADATA;
call_op.dir = GRPC_CALL_UP;
call_op.flags = 0;
call_op.done_cb = do_nothing;
call_op.user_data = NULL;
grpc_call_next_op(elem, &call_op);
}
break;
case GRPC_OP_BEGIN_MESSAGE:
/* can't begin a message when we're still reading a message */
if (calld->reading_message) {
recv_error(chand, calld, __LINE__,
"Message terminated early; read %d bytes, expected %d",
calld->incoming_message.length,
calld->incoming_message_length);
return;
}
/* stash away parameters, and prepare for incoming slices */
length = stream_op->data.begin_message.length;
if (length > calld->max_message_length) {
recv_error(
chand, calld, __LINE__,
"Maximum message length of %d exceeded by a message of length %d",
calld->max_message_length, length);
} else if (length > 0) {
calld->reading_message = 1;
calld->incoming_message_length = length;
} else {
finish_message(chand, calld);
}
break;
case GRPC_OP_SLICE:
if (GPR_SLICE_LENGTH(stream_op->data.slice) == 0) {
gpr_slice_unref(stream_op->data.slice);
break;
}
/* we have to be reading a message to know what to do here */
if (!calld->reading_message) {
recv_error(chand, calld, __LINE__,
"Received payload data while not reading a message");
return;
}
/* append the slice to the incoming buffer */
gpr_slice_buffer_add(&calld->incoming_message, stream_op->data.slice);
if (calld->incoming_message.length > calld->incoming_message_length) {
/* if we got too many bytes, complain */
recv_error(chand, calld, __LINE__,
"Receiving message overflow; read %d bytes, expected %d",
calld->incoming_message.length,
calld->incoming_message_length);
return;
} else if (calld->incoming_message.length ==
calld->incoming_message_length) {
finish_message(chand, calld);
}
}
}
/* if the stream closed, then call up the stack to let it know */
if (!calld->got_read_close && (final_state == GRPC_STREAM_RECV_CLOSED ||
final_state == GRPC_STREAM_CLOSED)) {
calld->got_read_close = 1;
if (calld->reading_message) {
recv_error(chand, calld, __LINE__,
"Last message truncated; read %d bytes, expected %d",
calld->incoming_message.length,
calld->incoming_message_length);
return;
}
call_op.type = GRPC_RECV_HALF_CLOSE;
call_op.dir = GRPC_CALL_UP;
call_op.flags = 0;
call_op.done_cb = do_nothing;
call_op.user_data = NULL;
grpc_call_next_op(elem, &call_op);
}
if (final_state == GRPC_STREAM_CLOSED) {
call_op.type = GRPC_RECV_FINISH;
call_op.dir = GRPC_CALL_UP;
call_op.flags = 0;
call_op.done_cb = do_nothing;
call_op.user_data = NULL;
grpc_call_next_op(elem, &call_op);
}
}
static void transport_closed(void *user_data, grpc_transport *transport) {
/* transport was closed ==> call up and handle it */
grpc_channel_element *elem = user_data;
channel_data *chand = elem->channel_data;
grpc_channel_op op;
GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
GPR_ASSERT(chand->transport == transport);
op.type = GRPC_TRANSPORT_CLOSED;
op.dir = GRPC_CALL_UP;
channel_op(elem, &op);
}
const grpc_transport_callbacks connected_channel_transport_callbacks = {
alloc_recv_buffer, accept_stream, recv_batch, transport_closed,
};
grpc_transport_setup_result grpc_connected_channel_bind_transport(
grpc_channel_stack *channel_stack, grpc_transport *transport) {
/* Assumes that the connected channel filter is always the last filter
in a channel stack */
grpc_channel_element *elem = grpc_channel_stack_last_element(channel_stack);
channel_data *cd = (channel_data *)elem->channel_data;
grpc_transport_setup_result ret;
GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
GPR_ASSERT(cd->transport == NULL);
cd->transport = transport;
/* HACK(ctiller): increase call stack size for the channel to make space
for channel data. We need a cleaner (but performant) way to do this,
and I'm not sure what that is yet.
This is only "safe" because call stacks place no additional data after
the last call element, and the last call element MUST be the connected
channel. */
channel_stack->call_stack_size += grpc_transport_stream_size(transport);
ret.user_data = elem;
ret.callbacks = &connected_channel_transport_callbacks;
return ret;
}

@ -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_INTERNAL_CHANNEL_CONNECTED_CHANNEL_H__
#define __GRPC_INTERNAL_CHANNEL_CONNECTED_CHANNEL_H__
#include "src/core/channel/channel_stack.h"
/* A channel filter representing a channel that is on a connected transport.
This filter performs actual sending and receiving of messages. */
extern const grpc_channel_filter grpc_connected_channel_filter;
/* Post construction fixup: set the transport in the connected channel.
Must be called before any call stack using this filter is used. */
grpc_transport_setup_result grpc_connected_channel_bind_transport(
grpc_channel_stack *channel_stack, grpc_transport *transport);
#endif /* __GRPC_INTERNAL_CHANNEL_CONNECTED_CHANNEL_H__ */

@ -0,0 +1,143 @@
/*
*
* 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/channel/http_client_filter.h"
#include <grpc/support/log.h>
typedef struct call_data {
int unused; /* C89 requires at least one struct element */
} call_data;
typedef struct channel_data { grpc_mdelem *te_trailers; } channel_data;
/* used to silence 'variable not used' warnings */
static void ignore_unused(void *ignored) {}
/* Called either:
- in response to an API call (or similar) from above, to send something
- a network event (or similar) from below, to receive something
op contains type and call direction information, in addition to the data
that is being sent or received. */
static void call_op(grpc_call_element *elem, grpc_call_op *op) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
channel_data *channeld = elem->channel_data;
GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
ignore_unused(calld);
switch (op->type) {
case GRPC_SEND_START:
/* just prior to starting, add a te: trailers header */
grpc_call_element_send_metadata(elem, channeld->te_trailers);
grpc_call_next_op(elem, op);
break;
default:
/* pass control up or down the stack depending on op->dir */
grpc_call_next_op(elem, op);
break;
}
}
/* Called on special channel events, such as disconnection or new incoming
calls on the server */
static void channel_op(grpc_channel_element *elem, grpc_channel_op *op) {
/* grab pointers to our data from the channel element */
channel_data *channeld = elem->channel_data;
ignore_unused(channeld);
switch (op->type) {
default:
/* pass control up or down the stack depending on op->dir */
grpc_channel_next_op(elem, op);
break;
}
}
/* Constructor for call_data */
static void init_call_elem(grpc_call_element *elem,
const void *server_transport_data) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
channel_data *channeld = elem->channel_data;
ignore_unused(channeld);
/* initialize members */
calld->unused = 0;
}
/* Destructor for call_data */
static void destroy_call_elem(grpc_call_element *elem) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
channel_data *channeld = elem->channel_data;
ignore_unused(calld);
ignore_unused(channeld);
}
/* Constructor for channel_data */
static void init_channel_elem(grpc_channel_element *elem,
const grpc_channel_args *args, grpc_mdctx *mdctx,
int is_first, int is_last) {
/* grab pointers to our data from the channel element */
channel_data *channeld = elem->channel_data;
/* The first and the last filters tend to be implemented differently to
handle the case that there's no 'next' filter to call on the up or down
path */
GPR_ASSERT(!is_first);
GPR_ASSERT(!is_last);
/* initialize members */
channeld->te_trailers = grpc_mdelem_from_strings(mdctx, "te", "trailers");
}
/* Destructor for channel data */
static void destroy_channel_elem(grpc_channel_element *elem) {
/* grab pointers to our data from the channel element */
channel_data *channeld = elem->channel_data;
grpc_mdelem_unref(channeld->te_trailers);
}
const grpc_channel_filter grpc_http_client_filter = {
call_op, channel_op,
sizeof(call_data), init_call_elem, destroy_call_elem,
sizeof(channel_data), init_channel_elem, destroy_channel_elem,
"http-client"};

@ -0,0 +1,42 @@
/*
*
* 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_INTERNAL_CHANNEL_HTTP_CLIENT_FILTER_H__
#define __GRPC_INTERNAL_CHANNEL_HTTP_CLIENT_FILTER_H__
#include "src/core/channel/channel_stack.h"
/* Processes metadata on the client side for HTTP2 transports */
extern const grpc_channel_filter grpc_http_client_filter;
#endif /* __GRPC_INTERNAL_CHANNEL_HTTP_CLIENT_FILTER_H__ */

@ -0,0 +1,139 @@
/*
*
* 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/channel/http_filter.h"
#include <grpc/support/log.h>
typedef struct call_data {
int unused; /* C89 requires at least one struct element */
} call_data;
typedef struct channel_data {
int unused; /* C89 requires at least one struct element */
} channel_data;
/* used to silence 'variable not used' warnings */
static void ignore_unused(void *ignored) {}
/* Called either:
- in response to an API call (or similar) from above, to send something
- a network event (or similar) from below, to receive something
op contains type and call direction information, in addition to the data
that is being sent or received. */
static void call_op(grpc_call_element *elem, grpc_call_op *op) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
channel_data *channeld = elem->channel_data;
GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
ignore_unused(calld);
ignore_unused(channeld);
switch (op->type) {
default:
/* pass control up or down the stack depending on op->dir */
grpc_call_next_op(elem, op);
break;
}
}
/* Called on special channel events, such as disconnection or new incoming
calls on the server */
static void channel_op(grpc_channel_element *elem, grpc_channel_op *op) {
/* grab pointers to our data from the channel element */
channel_data *channeld = elem->channel_data;
ignore_unused(channeld);
switch (op->type) {
default:
/* pass control up or down the stack depending on op->dir */
grpc_channel_next_op(elem, op);
break;
}
}
/* Constructor for call_data */
static void init_call_elem(grpc_call_element *elem,
const void *server_transport_data) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
channel_data *channeld = elem->channel_data;
/* initialize members */
calld->unused = channeld->unused;
}
/* Destructor for call_data */
static void destroy_call_elem(grpc_call_element *elem) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
channel_data *channeld = elem->channel_data;
ignore_unused(calld);
ignore_unused(channeld);
}
/* Constructor for channel_data */
static void init_channel_elem(grpc_channel_element *elem,
const grpc_channel_args *args, grpc_mdctx *mdctx,
int is_first, int is_last) {
/* grab pointers to our data from the channel element */
channel_data *channeld = elem->channel_data;
/* The first and the last filters tend to be implemented differently to
handle the case that there's no 'next' filter to call on the up or down
path */
GPR_ASSERT(!is_first);
GPR_ASSERT(!is_last);
/* initialize members */
channeld->unused = 0;
}
/* Destructor for channel data */
static void destroy_channel_elem(grpc_channel_element *elem) {
/* grab pointers to our data from the channel element */
channel_data *channeld = elem->channel_data;
ignore_unused(channeld);
}
const grpc_channel_filter grpc_http_filter = {
call_op, channel_op,
sizeof(call_data), init_call_elem, destroy_call_elem,
sizeof(channel_data), init_channel_elem, destroy_channel_elem,
"http"};

@ -0,0 +1,43 @@
/*
*
* 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_INTERNAL_CHANNEL_HTTP_FILTER_H__
#define __GRPC_INTERNAL_CHANNEL_HTTP_FILTER_H__
#include "src/core/channel/channel_stack.h"
/* Processes metadata that is common to both client and server for HTTP2
transports. */
extern const grpc_channel_filter grpc_http_filter;
#endif /* __GRPC_INTERNAL_CHANNEL_HTTP_FILTER_H__ */

@ -0,0 +1,150 @@
/*
*
* 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/channel/http_server_filter.h"
#include <grpc/support/log.h>
typedef struct call_data {
int unused; /* C89 requires at least one struct element */
} call_data;
typedef struct channel_data { grpc_mdelem *te_trailers; } channel_data;
/* used to silence 'variable not used' warnings */
static void ignore_unused(void *ignored) {}
/* Called either:
- in response to an API call (or similar) from above, to send something
- a network event (or similar) from below, to receive something
op contains type and call direction information, in addition to the data
that is being sent or received. */
static void call_op(grpc_call_element *elem, grpc_call_op *op) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
channel_data *channeld = elem->channel_data;
GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
ignore_unused(calld);
ignore_unused(channeld);
switch (op->type) {
case GRPC_RECV_METADATA:
/* check if it's a te: trailers header */
if (op->data.metadata == channeld->te_trailers) {
/* swallow it */
grpc_mdelem_unref(op->data.metadata);
op->done_cb(op->user_data, GRPC_OP_OK);
} else {
/* pass the event up */
grpc_call_next_op(elem, op);
}
break;
default:
/* pass control up or down the stack depending on op->dir */
grpc_call_next_op(elem, op);
break;
}
}
/* Called on special channel events, such as disconnection or new incoming
calls on the server */
static void channel_op(grpc_channel_element *elem, grpc_channel_op *op) {
/* grab pointers to our data from the channel element */
channel_data *channeld = elem->channel_data;
ignore_unused(channeld);
switch (op->type) {
default:
/* pass control up or down the stack depending on op->dir */
grpc_channel_next_op(elem, op);
break;
}
}
/* Constructor for call_data */
static void init_call_elem(grpc_call_element *elem,
const void *server_transport_data) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
channel_data *channeld = elem->channel_data;
ignore_unused(channeld);
/* initialize members */
calld->unused = 0;
}
/* Destructor for call_data */
static void destroy_call_elem(grpc_call_element *elem) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
channel_data *channeld = elem->channel_data;
ignore_unused(calld);
ignore_unused(channeld);
}
/* Constructor for channel_data */
static void init_channel_elem(grpc_channel_element *elem,
const grpc_channel_args *args, grpc_mdctx *mdctx,
int is_first, int is_last) {
/* grab pointers to our data from the channel element */
channel_data *channeld = elem->channel_data;
/* The first and the last filters tend to be implemented differently to
handle the case that there's no 'next' filter to call on the up or down
path */
GPR_ASSERT(!is_first);
GPR_ASSERT(!is_last);
/* initialize members */
channeld->te_trailers = grpc_mdelem_from_strings(mdctx, "te", "trailers");
}
/* Destructor for channel data */
static void destroy_channel_elem(grpc_channel_element *elem) {
/* grab pointers to our data from the channel element */
channel_data *channeld = elem->channel_data;
grpc_mdelem_unref(channeld->te_trailers);
}
const grpc_channel_filter grpc_http_server_filter = {
call_op, channel_op,
sizeof(call_data), init_call_elem, destroy_call_elem,
sizeof(channel_data), init_channel_elem, destroy_channel_elem,
"http-server"};

@ -0,0 +1,42 @@
/*
*
* 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_INTERNAL_CHANNEL_HTTP_SERVER_FILTER_H__
#define __GRPC_INTERNAL_CHANNEL_HTTP_SERVER_FILTER_H__
#include "src/core/channel/channel_stack.h"
/* Processes metadata on the client side for HTTP2 transports */
extern const grpc_channel_filter grpc_http_server_filter;
#endif /* __GRPC_INTERNAL_CHANNEL_HTTP_SERVER_FILTER_H__ */

@ -0,0 +1,198 @@
/*
*
* 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/channel/metadata_buffer.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/useful.h>
#include <string.h>
#define INITIAL_ELEM_CAP 8
/* One queued call; we track offsets to string data in a shared buffer to
reduce allocations. See grpc_metadata_buffer_impl for the memory use
strategy */
typedef struct {
grpc_mdelem *md;
void (*cb)(void *user_data, grpc_op_error error);
void *user_data;
gpr_uint32 flags;
} qelem;
/* Memory layout:
grpc_metadata_buffer_impl
followed by an array of qelem */
struct grpc_metadata_buffer_impl {
/* number of elements in q */
size_t elems;
/* capacity of q */
size_t elem_cap;
};
#define ELEMS(buffer) ((qelem *)((buffer)+1))
void grpc_metadata_buffer_init(grpc_metadata_buffer *buffer) {
/* start buffer as NULL, indicating no elements */
*buffer = NULL;
}
void grpc_metadata_buffer_destroy(grpc_metadata_buffer *buffer,
grpc_op_error error) {
size_t i;
qelem *qe;
if (*buffer) {
for (i = 0; i < (*buffer)->elems; i++) {
qe = &ELEMS(*buffer)[i];
grpc_mdelem_unref(qe->md);
qe->cb(qe->user_data, error);
}
gpr_free(*buffer);
}
}
void grpc_metadata_buffer_queue(grpc_metadata_buffer *buffer,
grpc_call_op *op) {
grpc_metadata_buffer_impl *impl = *buffer;
qelem *qe;
size_t bytes;
GPR_ASSERT(op->type == GRPC_SEND_METADATA || op->type == GRPC_RECV_METADATA);
if (!impl) {
/* this is the first element: allocate enough space to hold the
header object and the initial element capacity of qelems */
bytes =
sizeof(grpc_metadata_buffer_impl) + INITIAL_ELEM_CAP * sizeof(qelem);
impl = gpr_malloc(bytes);
/* initialize the header object */
impl->elems = 0;
impl->elem_cap = INITIAL_ELEM_CAP;
} else if (impl->elems == impl->elem_cap) {
/* more qelems than what we can deal with: grow by doubling size */
impl->elem_cap *= 2;
bytes = sizeof(grpc_metadata_buffer_impl) + impl->elem_cap * sizeof(qelem);
impl = gpr_realloc(impl, bytes);
}
/* append an element to the queue */
qe = &ELEMS(impl)[impl->elems];
impl->elems++;
qe->md = op->data.metadata;
qe->cb = op->done_cb;
qe->user_data = op->user_data;
qe->flags = op->flags;
/* header object may have changed location: store it back */
*buffer = impl;
}
void grpc_metadata_buffer_flush(grpc_metadata_buffer *buffer,
grpc_call_element *elem) {
grpc_metadata_buffer_impl *impl = *buffer;
grpc_call_op op;
qelem *qe;
size_t i;
if (!impl) {
/* nothing to send */
return;
}
/* construct call_op's, and push them down the stack */
op.type = GRPC_SEND_METADATA;
op.dir = GRPC_CALL_DOWN;
for (i = 0; i < impl->elems; i++) {
qe = &ELEMS(impl)[i];
op.done_cb = qe->cb;
op.user_data = qe->user_data;
op.flags = qe->flags;
op.data.metadata = qe->md;
grpc_call_next_op(elem, &op);
}
/* free data structures and reset to NULL: we can only flush once */
gpr_free(impl);
*buffer = NULL;
}
size_t grpc_metadata_buffer_count(const grpc_metadata_buffer *buffer) {
return *buffer ? (*buffer)->elems : 0;
}
typedef struct { grpc_metadata_buffer_impl *impl; } elems_hdr;
grpc_metadata *grpc_metadata_buffer_extract_elements(
grpc_metadata_buffer *buffer) {
grpc_metadata_buffer_impl *impl;
elems_hdr *hdr;
qelem *src;
grpc_metadata *out;
size_t i;
impl = *buffer;
if (!impl) {
return NULL;
}
hdr = gpr_malloc(sizeof(elems_hdr) + impl->elems * sizeof(grpc_metadata));
src = ELEMS(impl);
out = (grpc_metadata *)(hdr + 1);
hdr->impl = impl;
for (i = 0; i < impl->elems; i++) {
out[i].key = (char *)grpc_mdstr_as_c_string(src[i].md->key);
out[i].value = (char *)grpc_mdstr_as_c_string(src[i].md->value);
out[i].value_length = GPR_SLICE_LENGTH(src[i].md->value->slice);
}
/* clear out buffer (it's not possible to extract elements twice */
*buffer = NULL;
return out;
}
void grpc_metadata_buffer_cleanup_elements(void *elements,
grpc_op_error error) {
elems_hdr *hdr = ((elems_hdr *)elements) - 1;
if (!elements) {
return;
}
grpc_metadata_buffer_destroy(&hdr->impl, error);
gpr_free(hdr);
}

@ -0,0 +1,70 @@
/*
*
* 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_INTERNAL_CHANNEL_METADATA_BUFFER_H__
#define __GRPC_INTERNAL_CHANNEL_METADATA_BUFFER_H__
#include "src/core/channel/channel_stack.h"
/* Utility code to buffer GRPC_SEND_METADATA calls and pass them down the stack
all at once at some otherwise-determined time. Useful for implementing
filters that want to queue metadata until a START event chooses some
underlying filter stack to send an rpc on. */
/* Clients should declare a member of grpc_metadata_buffer. This may at some
point become a typedef for a struct, but for now a pointer suffices */
typedef struct grpc_metadata_buffer_impl grpc_metadata_buffer_impl;
typedef grpc_metadata_buffer_impl *grpc_metadata_buffer;
/* Initializes the metadata buffer. Allocates no memory. */
void grpc_metadata_buffer_init(grpc_metadata_buffer *buffer);
/* Destroy the metadata buffer. */
void grpc_metadata_buffer_destroy(grpc_metadata_buffer *buffer,
grpc_op_error error);
/* Append a call to the end of a metadata buffer: may allocate memory */
void grpc_metadata_buffer_queue(grpc_metadata_buffer *buffer, grpc_call_op *op);
/* Flush all queued operations from the metadata buffer to the element below
self */
void grpc_metadata_buffer_flush(grpc_metadata_buffer *buffer,
grpc_call_element *self);
/* Count the number of queued elements in the buffer. */
size_t grpc_metadata_buffer_count(const grpc_metadata_buffer *buffer);
/* Extract elements as a grpc_metadata*, for presentation to applications.
The returned buffer must be freed with
grpc_metadata_buffer_cleanup_elements.
Clears the metadata buffer (this is a one-shot operation) */
grpc_metadata *grpc_metadata_buffer_extract_elements(
grpc_metadata_buffer *buffer);
void grpc_metadata_buffer_cleanup_elements(void *elements, grpc_op_error error);
#endif /* __GRPC_INTERNAL_CHANNEL_METADATA_BUFFER_H__ */

@ -0,0 +1,138 @@
/*
*
* 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/channel/noop_filter.h"
#include <grpc/support/log.h>
typedef struct call_data {
int unused; /* C89 requires at least one struct element */
} call_data;
typedef struct channel_data {
int unused; /* C89 requires at least one struct element */
} channel_data;
/* used to silence 'variable not used' warnings */
static void ignore_unused(void *ignored) {}
/* Called either:
- in response to an API call (or similar) from above, to send something
- a network event (or similar) from below, to receive something
op contains type and call direction information, in addition to the data
that is being sent or received. */
static void call_op(grpc_call_element *elem, grpc_call_op *op) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
channel_data *channeld = elem->channel_data;
ignore_unused(calld);
ignore_unused(channeld);
switch (op->type) {
default:
/* pass control up or down the stack depending on op->dir */
grpc_call_next_op(elem, op);
break;
}
}
/* Called on special channel events, such as disconnection or new incoming
calls on the server */
static void channel_op(grpc_channel_element *elem, grpc_channel_op *op) {
/* grab pointers to our data from the channel element */
channel_data *channeld = elem->channel_data;
ignore_unused(channeld);
switch (op->type) {
default:
/* pass control up or down the stack depending on op->dir */
grpc_channel_next_op(elem, op);
break;
}
}
/* Constructor for call_data */
static void init_call_elem(grpc_call_element *elem,
const void *server_transport_data) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
channel_data *channeld = elem->channel_data;
/* initialize members */
calld->unused = channeld->unused;
}
/* Destructor for call_data */
static void destroy_call_elem(grpc_call_element *elem) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
channel_data *channeld = elem->channel_data;
ignore_unused(calld);
ignore_unused(channeld);
}
/* Constructor for channel_data */
static void init_channel_elem(grpc_channel_element *elem,
const grpc_channel_args *args, grpc_mdctx *mdctx,
int is_first, int is_last) {
/* grab pointers to our data from the channel element */
channel_data *channeld = elem->channel_data;
/* The first and the last filters tend to be implemented differently to
handle the case that there's no 'next' filter to call on the up or down
path */
GPR_ASSERT(!is_first);
GPR_ASSERT(!is_last);
/* initialize members */
channeld->unused = 0;
}
/* Destructor for channel data */
static void destroy_channel_elem(grpc_channel_element *elem) {
/* grab pointers to our data from the channel element */
channel_data *channeld = elem->channel_data;
ignore_unused(channeld);
}
const grpc_channel_filter grpc_no_op_filter = {
call_op, channel_op,
sizeof(call_data), init_call_elem, destroy_call_elem,
sizeof(channel_data), init_channel_elem, destroy_channel_elem,
"no-op"};

@ -0,0 +1,44 @@
/*
*
* 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_INTERNAL_CHANNEL_NOOP_FILTER_H__
#define __GRPC_INTERNAL_CHANNEL_NOOP_FILTER_H__
#include "src/core/channel/channel_stack.h"
/* No-op filter: simply takes everything it's given, and passes it on to the
next filter. Exists simply as a starting point that others can take and
customize for their own filters */
extern const grpc_channel_filter grpc_no_op_filter;
#endif /* __GRPC_INTERNAL_CHANNEL_NOOP_FILTER_H__ */

@ -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.
*
*/
#include "src/core/compression/algorithm.h"
const char *grpc_compression_algorithm_name(
grpc_compression_algorithm algorithm) {
switch (algorithm) {
case GRPC_COMPRESS_NONE:
return "none";
case GRPC_COMPRESS_DEFLATE:
return "deflate";
case GRPC_COMPRESS_GZIP:
return "gzip";
case GRPC_COMPRESS_ALGORITHMS_COUNT:
return "error";
}
return "error";
}

@ -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_INTERNAL_COMPRESSION_ALGORITHM_H__
#define __GRPC_INTERNAL_COMPRESSION_ALGORITHM_H__
/* The various compression algorithms supported by GRPC */
typedef enum {
GRPC_COMPRESS_NONE = 0,
GRPC_COMPRESS_DEFLATE,
GRPC_COMPRESS_GZIP,
/* TODO(ctiller): snappy */
GRPC_COMPRESS_ALGORITHMS_COUNT
} grpc_compression_algorithm;
const char *grpc_compression_algorithm_name(
grpc_compression_algorithm algorithm);
#endif /* __GRPC_INTERNAL_COMPRESSION_ALGORITHM_H__ */

@ -0,0 +1,193 @@
/*
*
* 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/compression/message_compress.h"
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <zlib.h>
#define OUTPUT_BLOCK_SIZE 1024
static int zlib_body(z_stream *zs, gpr_slice_buffer *input,
gpr_slice_buffer *output,
int (*flate)(z_stream *zs, int flush)) {
int r;
int flush;
size_t i;
size_t output_bytes = 0;
gpr_slice outbuf = gpr_slice_malloc(OUTPUT_BLOCK_SIZE);
zs->avail_out = GPR_SLICE_LENGTH(outbuf);
zs->next_out = GPR_SLICE_START_PTR(outbuf);
flush = Z_NO_FLUSH;
for (i = 0; i < input->count; i++) {
if (i == input->count - 1) flush = Z_FINISH;
zs->avail_in = GPR_SLICE_LENGTH(input->slices[i]);
zs->next_in = GPR_SLICE_START_PTR(input->slices[i]);
do {
if (zs->avail_out == 0) {
output_bytes += GPR_SLICE_LENGTH(outbuf);
gpr_slice_buffer_add_indexed(output, outbuf);
outbuf = gpr_slice_malloc(OUTPUT_BLOCK_SIZE);
zs->avail_out = GPR_SLICE_LENGTH(outbuf);
zs->next_out = GPR_SLICE_START_PTR(outbuf);
}
r = flate(zs, flush);
if (r == Z_STREAM_ERROR) {
gpr_log(GPR_INFO, "zlib: stream error");
goto error;
}
} while (zs->avail_out == 0);
if (zs->avail_in) {
gpr_log(GPR_INFO, "zlib: not all input consumed");
goto error;
}
}
GPR_ASSERT(outbuf.refcount);
outbuf.data.refcounted.length -= zs->avail_out;
output_bytes += GPR_SLICE_LENGTH(outbuf);
gpr_slice_buffer_add_indexed(output, outbuf);
return 1;
error:
gpr_slice_unref(outbuf);
return 0;
}
static int zlib_compress(gpr_slice_buffer *input, gpr_slice_buffer *output,
int gzip) {
z_stream zs;
int r;
size_t i;
size_t count_before = output->count;
size_t length_before = output->length;
memset(&zs, 0, sizeof(zs));
r = deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 | (gzip ? 16 : 0),
8, Z_DEFAULT_STRATEGY);
if (r != Z_OK) {
gpr_log(GPR_ERROR, "deflateInit2 returns %d", r);
return 0;
}
r = zlib_body(&zs, input, output, deflate) && output->length < input->length;
if (!r) {
for (i = count_before; i < output->count; i++) {
gpr_slice_unref(output->slices[i]);
}
output->count = count_before;
output->length = length_before;
}
deflateEnd(&zs);
return r;
}
static int zlib_decompress(gpr_slice_buffer *input, gpr_slice_buffer *output,
int gzip) {
z_stream zs;
int r;
size_t i;
size_t count_before = output->count;
size_t length_before = output->length;
memset(&zs, 0, sizeof(zs));
r = inflateInit2(&zs, 15 | (gzip ? 16 : 0));
if (r != Z_OK) {
gpr_log(GPR_ERROR, "inflateInit2 returns %d", r);
return 0;
}
r = zlib_body(&zs, input, output, inflate);
if (!r) {
for (i = count_before; i < output->count; i++) {
gpr_slice_unref(output->slices[i]);
}
output->count = count_before;
output->length = length_before;
}
inflateEnd(&zs);
return r;
}
static int copy(gpr_slice_buffer *input, gpr_slice_buffer *output) {
size_t i;
for (i = 0; i < input->count; i++) {
gpr_slice_buffer_add(output, gpr_slice_ref(input->slices[i]));
}
return 1;
}
int compress_inner(grpc_compression_algorithm algorithm,
gpr_slice_buffer *input, gpr_slice_buffer *output) {
switch (algorithm) {
case GRPC_COMPRESS_NONE:
/* the fallback path always needs to be send uncompressed: we simply
rely on that here */
return 0;
case GRPC_COMPRESS_DEFLATE:
return zlib_compress(input, output, 0);
case GRPC_COMPRESS_GZIP:
return zlib_compress(input, output, 1);
case GRPC_COMPRESS_ALGORITHMS_COUNT:
break;
}
gpr_log(GPR_ERROR, "invalid compression algorithm %d", algorithm);
return 0;
}
int grpc_msg_compress(grpc_compression_algorithm algorithm,
gpr_slice_buffer *input, gpr_slice_buffer *output) {
if (!compress_inner(algorithm, input, output)) {
copy(input, output);
return 0;
}
return 1;
}
int grpc_msg_decompress(grpc_compression_algorithm algorithm,
gpr_slice_buffer *input, gpr_slice_buffer *output) {
switch (algorithm) {
case GRPC_COMPRESS_NONE:
return copy(input, output);
case GRPC_COMPRESS_DEFLATE:
return zlib_decompress(input, output, 0);
case GRPC_COMPRESS_GZIP:
return zlib_decompress(input, output, 1);
case GRPC_COMPRESS_ALGORITHMS_COUNT:
break;
}
gpr_log(GPR_ERROR, "invalid compression algorithm %d", algorithm);
return 0;
}

@ -0,0 +1,52 @@
/*
*
* 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_INTERNAL_COMPRESSION_MESSAGE_COMPRESS_H__
#define __GRPC_INTERNAL_COMPRESSION_MESSAGE_COMPRESS_H__
#include "src/core/compression/algorithm.h"
#include <grpc/support/slice_buffer.h>
/* compress 'input' to 'output' using 'algorithm'.
On success, appends compressed slices to output and returns 1.
On failure, appends uncompressed slices to output and returns 0. */
int grpc_msg_compress(grpc_compression_algorithm algorithm,
gpr_slice_buffer *input, gpr_slice_buffer *output);
/* decompress 'input' to 'output' using 'algorithm'.
On success, appends slices to output and returns 1.
On failure, output is unchanged, and returns 0. */
int grpc_msg_decompress(grpc_compression_algorithm algorithm,
gpr_slice_buffer *input, gpr_slice_buffer *output);
#endif /* __GRPC_INTERNAL_COMPRESSION_MESSAGE_COMPRESS_H__ */

@ -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.
*
*/
#include "src/core/endpoint/endpoint.h"
void grpc_endpoint_notify_on_read(grpc_endpoint *ep, grpc_endpoint_read_cb cb,
void *user_data, gpr_timespec deadline) {
ep->vtable->notify_on_read(ep, cb, user_data, deadline);
}
grpc_endpoint_write_status grpc_endpoint_write(
grpc_endpoint *ep, gpr_slice *slices, size_t nslices,
grpc_endpoint_write_cb cb, void *user_data, gpr_timespec deadline) {
return ep->vtable->write(ep, slices, nslices, cb, user_data, deadline);
}
void grpc_endpoint_shutdown(grpc_endpoint *ep) { ep->vtable->shutdown(ep); }
void grpc_endpoint_destroy(grpc_endpoint *ep) { ep->vtable->destroy(ep); }

@ -0,0 +1,99 @@
/*
*
* 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_INTERNAL_ENDPOINT_ENDPOINT_H__
#define __GRPC_INTERNAL_ENDPOINT_ENDPOINT_H__
#include <grpc/support/slice.h>
#include <grpc/support/time.h>
/* An endpoint caps a streaming channel between two communicating processes.
Examples may be: a tcp socket, <stdin+stdout>, or some shared memory. */
typedef struct grpc_endpoint grpc_endpoint;
typedef struct grpc_endpoint_vtable grpc_endpoint_vtable;
typedef enum grpc_endpoint_cb_status {
GRPC_ENDPOINT_CB_OK = 0, /* Call completed successfully */
GRPC_ENDPOINT_CB_EOF, /* Call completed successfully, end of file reached */
GRPC_ENDPOINT_CB_SHUTDOWN, /* Call interrupted by shutdown */
GRPC_ENDPOINT_CB_ERROR, /* Call interrupted by socket error */
GRPC_ENDPOINT_CB_TIMED_OUT /* Call timed out */
} grpc_endpoint_cb_status;
typedef enum grpc_endpoint_write_status {
GRPC_ENDPOINT_WRITE_DONE, /* completed immediately, cb won't be called */
GRPC_ENDPOINT_WRITE_PENDING, /* cb will be called when completed */
GRPC_ENDPOINT_WRITE_ERROR /* write errored out, cb won't be called */
} grpc_endpoint_write_status;
typedef void (*grpc_endpoint_read_cb)(void *user_data, gpr_slice *slices,
size_t nslices,
grpc_endpoint_cb_status error);
typedef void (*grpc_endpoint_write_cb)(void *user_data,
grpc_endpoint_cb_status error);
struct grpc_endpoint_vtable {
void (*notify_on_read)(grpc_endpoint *ep, grpc_endpoint_read_cb cb,
void *user_data, gpr_timespec deadline);
grpc_endpoint_write_status (*write)(grpc_endpoint *ep, gpr_slice *slices,
size_t nslices, grpc_endpoint_write_cb cb,
void *user_data, gpr_timespec deadline);
void (*shutdown)(grpc_endpoint *ep);
void (*destroy)(grpc_endpoint *ep);
};
/* When data is available on the connection, calls the callback with slices. */
void grpc_endpoint_notify_on_read(grpc_endpoint *ep, grpc_endpoint_read_cb cb,
void *user_data, gpr_timespec deadline);
/* Write slices out to the socket.
If the connection is ready for more data after the end of the call, it
returns GRPC_ENDPOINT_WRITE_DONE.
Otherwise it returns GRPC_ENDPOINT_WRITE_PENDING and calls cb when the
connection is ready for more data. */
grpc_endpoint_write_status grpc_endpoint_write(
grpc_endpoint *ep, gpr_slice *slices, size_t nslices,
grpc_endpoint_write_cb cb, void *user_data, gpr_timespec deadline);
/* Causes any pending read/write callbacks to run immediately with
GRPC_ENDPOINT_CB_SHUTDOWN status */
void grpc_endpoint_shutdown(grpc_endpoint *ep);
void grpc_endpoint_destroy(grpc_endpoint *ep);
struct grpc_endpoint {
const grpc_endpoint_vtable *vtable;
};
#endif /* __GRPC_INTERNAL_ENDPOINT_ENDPOINT_H__ */

@ -0,0 +1,195 @@
/*
*
* 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.
*
*/
#define _POSIX_SOURCE
#include "src/core/endpoint/resolve_address.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/string.h>
#include <grpc/support/log.h>
#include <grpc/support/thd.h>
typedef struct {
char *name;
char *default_port;
grpc_resolve_cb cb;
void *arg;
} 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(
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;
/* parse name, splitting it into host and port parts */
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++;
}
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;
r->cb(r->arg, grpc_blocking_resolve_address(r->name, r->default_port));
gpr_free(r->name);
gpr_free(r->default_port);
gpr_free(r);
}
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;
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);
}

@ -0,0 +1,67 @@
/*
*
* 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_INTERNAL_ENDPOINT_RESOLVE_ADDRESS_H__
#define __GRPC_INTERNAL_ENDPOINT_RESOLVE_ADDRESS_H__
#include <sys/socket.h>
typedef struct {
struct sockaddr_storage addr;
int len;
} grpc_resolved_address;
typedef struct {
size_t naddrs;
grpc_resolved_address *addrs;
} grpc_resolved_addresses;
/* Async result callback:
On success: addresses is the result, and the callee must call
grpc_resolved_addresses_destroy when it's done with them
On failure: addresses is NULL */
typedef void (*grpc_resolve_cb)(void *arg, grpc_resolved_addresses *addresses);
/* Asynchronously resolve addr. Use default_port if a port isn't designated
in addr, otherwise use the port in addr. */
/* TODO(ctiller): add a timeout here */
void grpc_resolve_address(const char *addr, const char *default_port,
grpc_resolve_cb cb, void *arg);
/* Destroy resolved addresses */
void grpc_resolved_addresses_destroy(grpc_resolved_addresses *addresses);
/* Resolve addr in a blocking fashion. Returns NULL on failure. On success,
result must be freed with grpc_resolved_addresses_destroy. */
grpc_resolved_addresses *grpc_blocking_resolve_address(
const char *addr, const char *default_port);
#endif /* __GRPC_INTERNAL_ENDPOINT_RESOLVE_ADDRESS_H__ */

@ -0,0 +1,335 @@
/*
*
* 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/endpoint/secure_endpoint.h"
#include "src/core/tsi/transport_security_interface.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/slice.h>
#include <grpc/support/slice_buffer.h>
#include <grpc/support/string.h>
#include <grpc/support/sync.h>
#define STAGING_BUFFER_SIZE 8192
typedef struct {
grpc_endpoint base;
grpc_endpoint *wrapped_ep;
struct tsi_frame_protector *protector;
gpr_mu protector_mu;
/* saved upper level callbacks and user_data. */
grpc_endpoint_read_cb read_cb;
void *read_user_data;
/* saved handshaker leftover data to unprotect. */
gpr_slice_buffer leftover_bytes;
/* buffers for read and write */
gpr_slice read_staging_buffer;
gpr_slice_buffer input_buffer;
gpr_slice write_staging_buffer;
gpr_slice_buffer output_buffer;
gpr_refcount ref;
} secure_endpoint;
static void secure_endpoint_ref(secure_endpoint *ep) { gpr_ref(&ep->ref); }
static void destroy(secure_endpoint *secure_ep) {
secure_endpoint *ep = (secure_endpoint *)secure_ep;
grpc_endpoint_destroy(ep->wrapped_ep);
tsi_frame_protector_destroy(ep->protector);
gpr_slice_buffer_destroy(&ep->leftover_bytes);
gpr_slice_unref(ep->read_staging_buffer);
gpr_slice_buffer_destroy(&ep->input_buffer);
gpr_slice_unref(ep->write_staging_buffer);
gpr_slice_buffer_destroy(&ep->output_buffer);
gpr_mu_destroy(&ep->protector_mu);
gpr_free(ep);
}
static void secure_endpoint_unref(secure_endpoint *ep) {
if (gpr_unref(&ep->ref)) {
destroy(ep);
}
}
static void flush_read_staging_buffer(secure_endpoint *ep, gpr_uint8 **cur,
gpr_uint8 **end) {
gpr_slice_buffer_add(&ep->input_buffer, ep->read_staging_buffer);
ep->read_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE);
*cur = GPR_SLICE_START_PTR(ep->read_staging_buffer);
*end = GPR_SLICE_END_PTR(ep->read_staging_buffer);
}
static void call_read_cb(secure_endpoint *ep, gpr_slice *slices, size_t nslices,
grpc_endpoint_cb_status error) {
#ifdef GRPC_TRACE_SECURE_TRANSPORT
size_t i;
for (i = 0; i < nslices; i++) {
char *data =
gpr_hexdump((char*)GPR_SLICE_START_PTR(slices[i]),
GPR_SLICE_LENGTH(slices[i]), GPR_HEXDUMP_PLAINTEXT);
gpr_log(GPR_DEBUG, "READ %p: %s", ep, data);
gpr_free(data);
}
#endif
ep->read_cb(ep->read_user_data, slices, nslices, error);
secure_endpoint_unref(ep);
}
static void on_read(void *user_data, gpr_slice *slices, size_t nslices,
grpc_endpoint_cb_status error) {
int i = 0;
gpr_uint8 keep_looping = 0;
int input_buffer_count = 0;
tsi_result result = TSI_OK;
secure_endpoint *ep = (secure_endpoint *)user_data;
gpr_uint8 *cur = GPR_SLICE_START_PTR(ep->read_staging_buffer);
gpr_uint8 *end = GPR_SLICE_END_PTR(ep->read_staging_buffer);
/* TODO(yangg) check error, maybe bail out early */
for (i = 0; i < nslices; i++) {
gpr_slice encrypted = slices[i];
gpr_uint8 *message_bytes = GPR_SLICE_START_PTR(encrypted);
size_t message_size = GPR_SLICE_LENGTH(encrypted);
while (message_size > 0 || keep_looping) {
gpr_uint32 unprotected_buffer_size_written = end - cur;
gpr_uint32 processed_message_size = message_size;
gpr_mu_lock(&ep->protector_mu);
result = tsi_frame_protector_unprotect(ep->protector, message_bytes,
&processed_message_size, cur,
&unprotected_buffer_size_written);
gpr_mu_unlock(&ep->protector_mu);
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Decryption error: %s",
tsi_result_to_string(result));
break;
}
message_bytes += processed_message_size;
message_size -= processed_message_size;
cur += unprotected_buffer_size_written;
if (cur == end) {
flush_read_staging_buffer(ep, &cur, &end);
/* Force to enter the loop again to extract buffered bytes in protector.
The bytes could be buffered because of running out of staging_buffer.
If this happens at the end of all slices, doing another unprotect
avoids leaving data in the protector. */
keep_looping = 1;
} else if (unprotected_buffer_size_written > 0) {
keep_looping = 1;
} else {
keep_looping = 0;
}
}
if (result != TSI_OK) break;
}
if (cur != GPR_SLICE_START_PTR(ep->read_staging_buffer)) {
gpr_slice_buffer_add(
&ep->input_buffer,
gpr_slice_split_head(
&ep->read_staging_buffer,
cur - GPR_SLICE_START_PTR(ep->read_staging_buffer)));
}
/* TODO(yangg) experiment with moving this block after read_cb to see if it
helps latency */
for (i = 0; i < nslices; i++) {
gpr_slice_unref(slices[i]);
}
if (result != TSI_OK) {
gpr_slice_buffer_reset_and_unref(&ep->input_buffer);
call_read_cb(ep, NULL, 0, GRPC_ENDPOINT_CB_ERROR);
return;
}
/* The upper level will unref the slices. */
input_buffer_count = ep->input_buffer.count;
ep->input_buffer.count = 0;
call_read_cb(ep, ep->input_buffer.slices, input_buffer_count, error);
}
static void notify_on_read(grpc_endpoint *secure_ep, grpc_endpoint_read_cb cb,
void *user_data, gpr_timespec deadline) {
secure_endpoint *ep = (secure_endpoint *)secure_ep;
ep->read_cb = cb;
ep->read_user_data = user_data;
secure_endpoint_ref(ep);
if (ep->leftover_bytes.count) {
size_t leftover_nslices = ep->leftover_bytes.count;
ep->leftover_bytes.count = 0;
on_read(ep, ep->leftover_bytes.slices, leftover_nslices,
GRPC_ENDPOINT_CB_OK);
return;
}
grpc_endpoint_notify_on_read(ep->wrapped_ep, on_read, ep, deadline);
}
static void flush_write_staging_buffer(secure_endpoint *ep, gpr_uint8 **cur,
gpr_uint8 **end) {
gpr_slice_buffer_add(&ep->output_buffer, ep->write_staging_buffer);
ep->write_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE);
*cur = GPR_SLICE_START_PTR(ep->write_staging_buffer);
*end = GPR_SLICE_END_PTR(ep->write_staging_buffer);
}
static grpc_endpoint_write_status write(grpc_endpoint *secure_ep,
gpr_slice *slices, size_t nslices,
grpc_endpoint_write_cb cb,
void *user_data,
gpr_timespec deadline) {
int i = 0;
int output_buffer_count = 0;
tsi_result result = TSI_OK;
secure_endpoint *ep = (secure_endpoint *)secure_ep;
gpr_uint8 *cur = GPR_SLICE_START_PTR(ep->write_staging_buffer);
gpr_uint8 *end = GPR_SLICE_END_PTR(ep->write_staging_buffer);
GPR_ASSERT(ep->output_buffer.count == 0);
#ifdef GRPC_TRACE_SECURE_TRANSPORT
for (i = 0; i < nslices; i++) {
char *data =
gpr_hexdump((char*)GPR_SLICE_START_PTR(slices[i]),
GPR_SLICE_LENGTH(slices[i]), GPR_HEXDUMP_PLAINTEXT);
gpr_log(GPR_DEBUG, "WRITE %p: %s", ep, data);
gpr_free(data);
}
#endif
for (i = 0; i < nslices; i++) {
gpr_slice plain = slices[i];
gpr_uint8 *message_bytes = GPR_SLICE_START_PTR(plain);
size_t message_size = GPR_SLICE_LENGTH(plain);
while (message_size > 0) {
gpr_uint32 protected_buffer_size_to_send = end - cur;
gpr_uint32 processed_message_size = message_size;
gpr_mu_lock(&ep->protector_mu);
result = tsi_frame_protector_protect(ep->protector, message_bytes,
&processed_message_size, cur,
&protected_buffer_size_to_send);
gpr_mu_unlock(&ep->protector_mu);
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Encryption error: %s",
tsi_result_to_string(result));
break;
}
message_bytes += processed_message_size;
message_size -= processed_message_size;
cur += protected_buffer_size_to_send;
if (cur == end) {
flush_write_staging_buffer(ep, &cur, &end);
}
}
if (result != TSI_OK) break;
}
if (result == TSI_OK) {
gpr_uint32 still_pending_size;
do {
gpr_uint32 protected_buffer_size_to_send = end - cur;
gpr_mu_lock(&ep->protector_mu);
result = tsi_frame_protector_protect_flush(ep->protector, cur,
&protected_buffer_size_to_send,
&still_pending_size);
gpr_mu_unlock(&ep->protector_mu);
if (result != TSI_OK) break;
cur += protected_buffer_size_to_send;
if (cur == end) {
flush_write_staging_buffer(ep, &cur, &end);
}
} while (still_pending_size > 0);
if (cur != GPR_SLICE_START_PTR(ep->write_staging_buffer)) {
gpr_slice_buffer_add(
&ep->output_buffer,
gpr_slice_split_head(
&ep->write_staging_buffer,
cur - GPR_SLICE_START_PTR(ep->write_staging_buffer)));
}
}
for (i = 0; i < nslices; i++) {
gpr_slice_unref(slices[i]);
}
if (result != TSI_OK) {
/* TODO(yangg) do different things according to the error type? */
gpr_slice_buffer_reset_and_unref(&ep->output_buffer);
return GRPC_ENDPOINT_WRITE_ERROR;
}
/* clear output_buffer and let the lower level handle its slices. */
output_buffer_count = ep->output_buffer.count;
ep->output_buffer.count = 0;
return grpc_endpoint_write(ep->wrapped_ep, ep->output_buffer.slices,
output_buffer_count, cb, user_data, deadline);
}
static void shutdown(grpc_endpoint *secure_ep) {
secure_endpoint *ep = (secure_endpoint *)secure_ep;
grpc_endpoint_shutdown(ep->wrapped_ep);
}
static void unref(grpc_endpoint *secure_ep) {
secure_endpoint *ep = (secure_endpoint *)secure_ep;
secure_endpoint_unref(ep);
}
static const grpc_endpoint_vtable vtable = {notify_on_read, write, shutdown,
unref};
grpc_endpoint *grpc_secure_endpoint_create(
struct tsi_frame_protector *protector, grpc_endpoint *transport,
gpr_slice *leftover_slices, size_t leftover_nslices) {
size_t i;
secure_endpoint *ep = (secure_endpoint *)gpr_malloc(sizeof(secure_endpoint));
ep->base.vtable = &vtable;
ep->wrapped_ep = transport;
ep->protector = protector;
gpr_slice_buffer_init(&ep->leftover_bytes);
for (i = 0; i < leftover_nslices; i++) {
gpr_slice_buffer_add(&ep->leftover_bytes,
gpr_slice_ref(leftover_slices[i]));
}
ep->write_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE);
ep->read_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE);
gpr_slice_buffer_init(&ep->input_buffer);
gpr_slice_buffer_init(&ep->output_buffer);
gpr_mu_init(&ep->protector_mu);
gpr_ref_init(&ep->ref, 1);
return &ep->base;
}

@ -0,0 +1,47 @@
/*
*
* 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_INTERNAL_ENDPOINT_SECURE_ENDPOINT_H__
#define __GRPC_INTERNAL_ENDPOINT_SECURE_ENDPOINT_H__
#include <grpc/support/slice.h>
#include "src/core/endpoint/endpoint.h"
struct tsi_frame_protector;
/* Takes ownership of protector and to_wrap, and refs leftover_slices. */
grpc_endpoint *grpc_secure_endpoint_create(
struct tsi_frame_protector *protector, grpc_endpoint *to_wrap,
gpr_slice *leftover_slices, size_t leftover_nslices);
#endif /* __GRPC_INTERNAL_ENDPOINT_SECURE_ENDPOINT_H__ */

@ -0,0 +1,105 @@
/*
*
* 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/endpoint/socket_utils.h"
#include <limits.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
/* set a socket to non blocking mode */
int grpc_set_socket_nonblocking(int fd, int non_blocking) {
int oldflags = fcntl(fd, F_GETFL, 0);
if (oldflags < 0) {
return 0;
}
if (non_blocking) {
oldflags |= O_NONBLOCK;
} else {
oldflags &= ~O_NONBLOCK;
}
if (fcntl(fd, F_SETFL, oldflags) != 0) {
return 0;
}
return 1;
}
/* set a socket to close on exec */
int grpc_set_socket_cloexec(int fd, int close_on_exec) {
int oldflags = fcntl(fd, F_GETFD, 0);
if (oldflags < 0) {
return 0;
}
if (close_on_exec) {
oldflags |= FD_CLOEXEC;
} else {
oldflags &= ~FD_CLOEXEC;
}
if (fcntl(fd, F_SETFD, oldflags) != 0) {
return 0;
}
return 1;
}
/* set a socket to reuse old addresses */
int grpc_set_socket_reuse_addr(int fd, int reuse) {
int val = (reuse != 0);
int newval;
socklen_t intlen = sizeof(newval);
return 0 == setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) &&
0 == getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &newval, &intlen) &&
newval == val;
}
/* disable nagle */
int grpc_set_socket_low_latency(int fd, int low_latency) {
int val = (low_latency != 0);
int newval;
socklen_t intlen = sizeof(newval);
return 0 == setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) &&
0 == getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &newval, &intlen) &&
newval == val;
}

@ -0,0 +1,58 @@
/*
*
* 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_INTERNAL_ENDPOINT_SOCKET_UTILS_H__
#define __GRPC_INTERNAL_ENDPOINT_SOCKET_UTILS_H__
#include <unistd.h>
#include <sys/socket.h>
struct sockaddr;
/* a wrapper for accept or accept4 */
int grpc_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen,
int nonblock, int cloexec);
/* set a socket to non blocking mode */
int grpc_set_socket_nonblocking(int fd, int non_blocking);
/* set a socket to close on exec */
int grpc_set_socket_cloexec(int fd, int close_on_exec);
/* set a socket to reuse old addresses */
int grpc_set_socket_reuse_addr(int fd, int reuse);
/* disable nagle */
int grpc_set_socket_low_latency(int fd, int low_latency);
#endif /* __GRPC_INTERNAL_ENDPOINT_SOCKET_UTILS_H__ */

@ -0,0 +1,52 @@
/*
*
* 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.
*
*/
#define _GNU_SOURCE
#include <grpc/support/port_platform.h>
#ifdef GPR_LINUX
#include "src/core/endpoint/socket_utils.h"
#include <sys/types.h>
#include <sys/socket.h>
int grpc_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen,
int nonblock, int cloexec) {
int flags = 0;
flags |= nonblock ? SOCK_NONBLOCK : 0;
flags |= cloexec ? SOCK_CLOEXEC : 0;
return accept4(sockfd, addr, addrlen, flags);
}
#endif

@ -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_POSIX_SOCKETUTILS
#define _BSD_SOURCE
#include "src/core/endpoint/socket_utils.h"
#include <fcntl.h>
#include <sys/socket.h>
#include <unistd.h>
#include <grpc/support/log.h>
int grpc_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen,
int nonblock, int cloexec) {
int fd, flags;
fd = accept(sockfd, addr, addrlen);
if (fd >= 0) {
flags = fcntl(fd, F_GETFL, 0);
flags |= nonblock ? O_NONBLOCK : 0;
flags |= cloexec ? FD_CLOEXEC : 0;
GPR_ASSERT(fcntl(fd, F_SETFL, flags) == 0);
}
return fd;
}
#endif /* GPR_POSIX_SOCKETUTILS */

@ -0,0 +1,570 @@
/*
*
* 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/endpoint/tcp.h"
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include "src/core/eventmanager/em.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/slice.h>
#include <grpc/support/string.h>
#include <grpc/support/sync.h>
#include <grpc/support/time.h>
/* Holds a slice array and associated state. */
typedef struct grpc_tcp_slice_state {
gpr_slice *slices; /* Array of slices */
size_t nslices; /* Size of slices array. */
ssize_t first_slice; /* First valid slice in array */
ssize_t last_slice; /* Last valid slice in array */
gpr_slice working_slice; /* pointer to original final slice */
int working_slice_valid; /* True if there is a working slice */
int memory_owned; /* True if slices array is owned */
} grpc_tcp_slice_state;
static void slice_state_init(grpc_tcp_slice_state *state, gpr_slice *slices,
size_t nslices, size_t valid_slices) {
state->slices = slices;
state->nslices = nslices;
if (valid_slices == 0) {
state->first_slice = -1;
} else {
state->first_slice = 0;
}
state->last_slice = valid_slices - 1;
state->working_slice_valid = 0;
state->memory_owned = 0;
}
/* Returns true if there is still available data */
static int slice_state_has_available(grpc_tcp_slice_state *state) {
return state->first_slice != -1 && state->last_slice >= state->first_slice;
}
static ssize_t slice_state_slices_allocated(grpc_tcp_slice_state *state) {
if (state->first_slice == -1) {
return 0;
} else {
return state->last_slice - state->first_slice + 1;
}
}
static void slice_state_realloc(grpc_tcp_slice_state *state, size_t new_size) {
/* TODO(klempner): use realloc instead when first_slice is 0 */
/* TODO(klempner): Avoid a realloc in cases where it is unnecessary */
gpr_slice *slices = state->slices;
size_t original_size = slice_state_slices_allocated(state);
size_t i;
gpr_slice *new_slices = gpr_malloc(sizeof(gpr_slice) * new_size);
for (i = 0; i < original_size; ++i) {
new_slices[i] = slices[i + state->first_slice];
}
state->slices = new_slices;
state->last_slice = original_size - 1;
if (original_size > 0) {
state->first_slice = 0;
} else {
state->first_slice = -1;
}
state->nslices = new_size;
if (state->memory_owned) {
gpr_free(slices);
}
state->memory_owned = 1;
}
static void slice_state_remove_prefix(grpc_tcp_slice_state *state,
size_t prefix_bytes) {
gpr_slice *current_slice = &state->slices[state->first_slice];
size_t current_slice_size;
while (slice_state_has_available(state)) {
current_slice_size = GPR_SLICE_LENGTH(*current_slice);
if (current_slice_size > prefix_bytes) {
/* TODO(klempner): Get rid of the extra refcount created here by adding a
native "trim the first N bytes" operation to splice */
/* TODO(klempner): This really shouldn't be modifying the current slice
unless we own the slices array. */
*current_slice = gpr_slice_split_tail(current_slice, prefix_bytes);
gpr_slice_unref(*current_slice);
return;
} else {
gpr_slice_unref(*current_slice);
++state->first_slice;
++current_slice;
prefix_bytes -= current_slice_size;
}
}
}
static void slice_state_destroy(grpc_tcp_slice_state *state) {
while (slice_state_has_available(state)) {
gpr_slice_unref(state->slices[state->first_slice]);
++state->first_slice;
}
if (state->memory_owned) {
gpr_free(state->slices);
state->memory_owned = 0;
}
}
void slice_state_transfer_ownership(grpc_tcp_slice_state *state,
gpr_slice **slices, size_t *nslices) {
*slices = state->slices + state->first_slice;
*nslices = state->last_slice - state->first_slice + 1;
state->first_slice = -1;
state->last_slice = -1;
}
/* Fills iov with the first min(iov_size, available) slices, returns number
filled */
static size_t slice_state_to_iovec(grpc_tcp_slice_state *state,
struct iovec *iov, size_t iov_size) {
size_t nslices = state->last_slice - state->first_slice + 1;
gpr_slice *slices = state->slices + state->first_slice;
size_t i;
if (nslices < iov_size) {
iov_size = nslices;
}
for (i = 0; i < iov_size; ++i) {
iov[i].iov_base = GPR_SLICE_START_PTR(slices[i]);
iov[i].iov_len = GPR_SLICE_LENGTH(slices[i]);
}
return iov_size;
}
/* Makes n blocks available at the end of state, writes them into iov, and
returns the number of bytes allocated */
static size_t slice_state_append_blocks_into_iovec(grpc_tcp_slice_state *state,
struct iovec *iov, size_t n,
size_t slice_size) {
size_t target_size;
size_t i;
size_t allocated_bytes;
ssize_t allocated_slices = slice_state_slices_allocated(state);
if (n - state->working_slice_valid >= state->nslices - state->last_slice) {
/* Need to grow the slice array */
target_size = state->nslices;
do {
target_size = target_size * 2;
} while (target_size < allocated_slices + n - state->working_slice_valid);
/* TODO(klempner): If this ever needs to support both prefix removal and
append, we should be smarter about the growth logic here */
slice_state_realloc(state, target_size);
}
i = 0;
allocated_bytes = 0;
if (state->working_slice_valid) {
iov[0].iov_base = GPR_SLICE_END_PTR(state->slices[state->last_slice]);
iov[0].iov_len = GPR_SLICE_LENGTH(state->working_slice) -
GPR_SLICE_LENGTH(state->slices[state->last_slice]);
allocated_bytes += iov[0].iov_len;
++i;
state->slices[state->last_slice] = state->working_slice;
state->working_slice_valid = 0;
}
for (; i < n; ++i) {
++state->last_slice;
state->slices[state->last_slice] = gpr_slice_malloc(slice_size);
iov[i].iov_base = GPR_SLICE_START_PTR(state->slices[state->last_slice]);
iov[i].iov_len = slice_size;
allocated_bytes += slice_size;
}
if (state->first_slice == -1) {
state->first_slice = 0;
}
return allocated_bytes;
}
/* Remove the last n bytes from state */
/* TODO(klempner): Consider having this defer actual deletion until later */
static void slice_state_remove_last(grpc_tcp_slice_state *state, size_t bytes) {
while (bytes > 0 && slice_state_has_available(state)) {
if (GPR_SLICE_LENGTH(state->slices[state->last_slice]) > bytes) {
state->working_slice = state->slices[state->last_slice];
state->working_slice_valid = 1;
/* TODO(klempner): Combine these into a single operation that doesn't need
to refcount */
gpr_slice_unref(gpr_slice_split_tail(
&state->slices[state->last_slice],
GPR_SLICE_LENGTH(state->slices[state->last_slice]) - bytes));
bytes = 0;
} else {
bytes -= GPR_SLICE_LENGTH(state->slices[state->last_slice]);
gpr_slice_unref(state->slices[state->last_slice]);
--state->last_slice;
if (state->last_slice == -1) {
state->first_slice = -1;
}
}
}
}
typedef struct {
grpc_endpoint base;
grpc_em *em;
grpc_em_fd em_fd;
int fd;
size_t slice_size;
gpr_refcount refcount;
grpc_endpoint_read_cb read_cb;
void *read_user_data;
gpr_timespec read_deadline;
grpc_endpoint_write_cb write_cb;
void *write_user_data;
gpr_timespec write_deadline;
grpc_tcp_slice_state write_state;
} grpc_tcp;
static void grpc_tcp_handle_read(void *arg /* grpc_tcp */,
grpc_em_cb_status status);
static void grpc_tcp_handle_write(void *arg /* grpc_tcp */,
grpc_em_cb_status status);
#define DEFAULT_SLICE_SIZE 8192
grpc_endpoint *grpc_tcp_create(int fd, grpc_em *em) {
return grpc_tcp_create_dbg(fd, em, DEFAULT_SLICE_SIZE);
}
static void grpc_tcp_shutdown(grpc_endpoint *ep) {
grpc_tcp *tcp = (grpc_tcp *)ep;
grpc_em_fd_shutdown(&tcp->em_fd);
}
static void grpc_tcp_unref(grpc_tcp *tcp) {
int refcount_zero = gpr_unref(&tcp->refcount);
if (refcount_zero) {
grpc_em_fd_destroy(&tcp->em_fd);
close(tcp->fd);
gpr_free(tcp);
}
}
static void grpc_tcp_destroy(grpc_endpoint *ep) {
grpc_tcp *tcp = (grpc_tcp *)ep;
grpc_tcp_unref(tcp);
}
static void call_read_cb(grpc_tcp *tcp, gpr_slice *slices, size_t nslices,
grpc_endpoint_cb_status status) {
grpc_endpoint_read_cb cb = tcp->read_cb;
#ifdef GRPC_TRACE_TCP
size_t i;
gpr_log(GPR_DEBUG, "read: status=%d", status);
for (i = 0; i < nslices; i++) {
char *dump =
gpr_hexdump((char *)GPR_SLICE_START_PTR(slices[i]),
GPR_SLICE_LENGTH(slices[i]), GPR_HEXDUMP_PLAINTEXT);
gpr_log(GPR_DEBUG, "READ: %s", dump);
gpr_free(dump);
}
#endif
tcp->read_cb = NULL;
cb(tcp->read_user_data, slices, nslices, status);
}
#define INLINE_SLICE_BUFFER_SIZE 8
#define MAX_READ_IOVEC 4
static void grpc_tcp_handle_read(void *arg /* grpc_tcp */,
grpc_em_cb_status status) {
grpc_tcp *tcp = (grpc_tcp *)arg;
int iov_size = 1;
gpr_slice static_read_slices[INLINE_SLICE_BUFFER_SIZE];
struct msghdr msg;
struct iovec iov[MAX_READ_IOVEC];
ssize_t read_bytes;
ssize_t allocated_bytes;
struct grpc_tcp_slice_state read_state;
gpr_slice *final_slices;
size_t final_nslices;
slice_state_init(&read_state, static_read_slices, INLINE_SLICE_BUFFER_SIZE,
0);
if (status == GRPC_CALLBACK_CANCELLED) {
call_read_cb(tcp, NULL, 0, GRPC_ENDPOINT_CB_SHUTDOWN);
grpc_tcp_unref(tcp);
return;
}
if (status == GRPC_CALLBACK_TIMED_OUT) {
call_read_cb(tcp, NULL, 0, GRPC_ENDPOINT_CB_TIMED_OUT);
grpc_tcp_unref(tcp);
return;
}
/* TODO(klempner): Limit the amount we read at once. */
for (;;) {
allocated_bytes = slice_state_append_blocks_into_iovec(
&read_state, iov, iov_size, tcp->slice_size);
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = iov;
msg.msg_iovlen = iov_size;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = 0;
do {
read_bytes = recvmsg(tcp->fd, &msg, 0);
} while (read_bytes < 0 && errno == EINTR);
if (read_bytes < allocated_bytes) {
/* TODO(klempner): Consider a second read first, in hopes of getting a
* quick EAGAIN and saving a bunch of allocations. */
slice_state_remove_last(&read_state, read_bytes < 0
? allocated_bytes
: allocated_bytes - read_bytes);
}
if (read_bytes < 0) {
/* NB: After calling the user_cb a parallel call of the read handler may
* be running. */
if (errno == EAGAIN) {
if (slice_state_has_available(&read_state)) {
/* TODO(klempner): We should probably do the call into the application
without all this junk on the stack */
/* FIXME(klempner): Refcount properly */
slice_state_transfer_ownership(&read_state, &final_slices,
&final_nslices);
call_read_cb(tcp, final_slices, final_nslices, GRPC_ENDPOINT_CB_OK);
slice_state_destroy(&read_state);
grpc_tcp_unref(tcp);
} else {
/* Spurious read event, consume it here */
slice_state_destroy(&read_state);
grpc_em_fd_notify_on_read(&tcp->em_fd, grpc_tcp_handle_read, tcp,
tcp->read_deadline);
}
} else {
/* TODO(klempner): Log interesting errors */
call_read_cb(tcp, NULL, 0, GRPC_ENDPOINT_CB_ERROR);
slice_state_destroy(&read_state);
grpc_tcp_unref(tcp);
}
return;
} else if (read_bytes == 0) {
/* 0 read size ==> end of stream */
if (slice_state_has_available(&read_state)) {
/* there were bytes already read: pass them up to the application */
slice_state_transfer_ownership(&read_state, &final_slices,
&final_nslices);
call_read_cb(tcp, final_slices, final_nslices, GRPC_ENDPOINT_CB_EOF);
} else {
call_read_cb(tcp, NULL, 0, GRPC_ENDPOINT_CB_EOF);
}
slice_state_destroy(&read_state);
grpc_tcp_unref(tcp);
return;
} else if (iov_size < MAX_READ_IOVEC) {
++iov_size;
}
}
}
static void grpc_tcp_notify_on_read(grpc_endpoint *ep, grpc_endpoint_read_cb cb,
void *user_data, gpr_timespec deadline) {
grpc_tcp *tcp = (grpc_tcp *)ep;
GPR_ASSERT(tcp->read_cb == NULL);
tcp->read_cb = cb;
tcp->read_user_data = user_data;
tcp->read_deadline = deadline;
gpr_ref(&tcp->refcount);
grpc_em_fd_notify_on_read(&tcp->em_fd, grpc_tcp_handle_read, tcp, deadline);
}
#define MAX_WRITE_IOVEC 16
static grpc_endpoint_write_status grpc_tcp_flush(grpc_tcp *tcp) {
struct msghdr msg;
struct iovec iov[MAX_WRITE_IOVEC];
int iov_size;
ssize_t sent_length;
grpc_tcp_slice_state *state = &tcp->write_state;
for (;;) {
iov_size = slice_state_to_iovec(state, iov, MAX_WRITE_IOVEC);
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = iov;
msg.msg_iovlen = iov_size;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = 0;
do {
/* TODO(klempner): Cork if this is a partial write */
sent_length = sendmsg(tcp->fd, &msg, 0);
} while (sent_length < 0 && errno == EINTR);
if (sent_length < 0) {
if (errno == EAGAIN) {
return GRPC_ENDPOINT_WRITE_PENDING;
} else {
/* TODO(klempner): Log some of these */
slice_state_destroy(state);
return GRPC_ENDPOINT_WRITE_ERROR;
}
}
/* TODO(klempner): Probably better to batch this after we finish flushing */
slice_state_remove_prefix(state, sent_length);
if (!slice_state_has_available(state)) {
return GRPC_ENDPOINT_WRITE_DONE;
}
};
}
static void grpc_tcp_handle_write(void *arg /* grpc_tcp */,
grpc_em_cb_status status) {
grpc_tcp *tcp = (grpc_tcp *)arg;
grpc_endpoint_write_status write_status;
grpc_endpoint_cb_status cb_status;
grpc_endpoint_write_cb cb;
cb_status = GRPC_ENDPOINT_CB_OK;
if (status == GRPC_CALLBACK_CANCELLED) {
cb_status = GRPC_ENDPOINT_CB_SHUTDOWN;
} else if (status == GRPC_CALLBACK_TIMED_OUT) {
cb_status = GRPC_ENDPOINT_CB_TIMED_OUT;
}
if (cb_status != GRPC_ENDPOINT_CB_OK) {
slice_state_destroy(&tcp->write_state);
cb = tcp->write_cb;
tcp->write_cb = NULL;
cb(tcp->write_user_data, cb_status);
grpc_tcp_unref(tcp);
return;
}
write_status = grpc_tcp_flush(tcp);
if (write_status == GRPC_ENDPOINT_WRITE_PENDING) {
grpc_em_fd_notify_on_write(&tcp->em_fd, grpc_tcp_handle_write, tcp,
tcp->write_deadline);
} else {
slice_state_destroy(&tcp->write_state);
if (write_status == GRPC_ENDPOINT_WRITE_DONE) {
cb_status = GRPC_ENDPOINT_CB_OK;
} else {
cb_status = GRPC_ENDPOINT_CB_ERROR;
}
cb = tcp->write_cb;
tcp->write_cb = NULL;
cb(tcp->write_user_data, cb_status);
grpc_tcp_unref(tcp);
}
}
static grpc_endpoint_write_status grpc_tcp_write(
grpc_endpoint *ep, gpr_slice *slices, size_t nslices,
grpc_endpoint_write_cb cb, void *user_data, gpr_timespec deadline) {
grpc_tcp *tcp = (grpc_tcp *)ep;
grpc_endpoint_write_status status;
#ifdef GRPC_TRACE_TCP
size_t i;
for (i = 0; i < nslices; i++) {
char *data =
gpr_hexdump((char *)GPR_SLICE_START_PTR(slices[i]),
GPR_SLICE_LENGTH(slices[i]), GPR_HEXDUMP_PLAINTEXT);
gpr_log(GPR_DEBUG, "WRITE %p: %s", tcp, data);
gpr_free(data);
}
#endif
GPR_ASSERT(tcp->write_cb == NULL);
slice_state_init(&tcp->write_state, slices, nslices, nslices);
status = grpc_tcp_flush(tcp);
if (status == GRPC_ENDPOINT_WRITE_PENDING) {
/* TODO(klempner): Consider inlining rather than malloc for small nslices */
slice_state_realloc(&tcp->write_state, nslices);
gpr_ref(&tcp->refcount);
tcp->write_cb = cb;
tcp->write_user_data = user_data;
tcp->write_deadline = deadline;
grpc_em_fd_notify_on_write(&tcp->em_fd, grpc_tcp_handle_write, tcp,
tcp->write_deadline);
}
return status;
}
static const grpc_endpoint_vtable vtable = {grpc_tcp_notify_on_read,
grpc_tcp_write, grpc_tcp_shutdown,
grpc_tcp_destroy};
grpc_endpoint *grpc_tcp_create_dbg(int fd, grpc_em *em, size_t slice_size) {
grpc_tcp *tcp = (grpc_tcp *)gpr_malloc(sizeof(grpc_tcp));
tcp->base.vtable = &vtable;
tcp->fd = fd;
tcp->em = em;
tcp->read_cb = NULL;
tcp->write_cb = NULL;
tcp->read_user_data = NULL;
tcp->write_user_data = NULL;
tcp->slice_size = slice_size;
tcp->read_deadline = gpr_inf_future;
tcp->write_deadline = gpr_inf_future;
slice_state_init(&tcp->write_state, NULL, 0, 0);
/* paired with unref in grpc_tcp_destroy */
gpr_ref_init(&tcp->refcount, 1);
grpc_em_fd_init(&tcp->em_fd, tcp->em, fd);
return &tcp->base;
}

@ -0,0 +1,55 @@
/*
*
* 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_INTERNAL_ENDPOINT_TCP_H__
#define __GRPC_INTERNAL_ENDPOINT_TCP_H__
/*
Low level TCP "bottom half" implementation, for use by transports built on
top of a TCP connection.
Note that this file does not (yet) include APIs for creating the socket in
the first place.
All calls passing slice transfer ownership of a slice refcount unless
otherwise specified.
*/
#include "src/core/endpoint/endpoint.h"
#include "src/core/eventmanager/em.h"
/* Create a tcp from an already connected file descriptor. */
grpc_endpoint *grpc_tcp_create(int fd, grpc_em *em);
/* Special version for debugging slice changes */
grpc_endpoint *grpc_tcp_create_dbg(int fd, grpc_em *em, size_t slice_size);
#endif /* __GRPC_INTERNAL_ENDPOINT_TCP_H__ */

@ -0,0 +1,170 @@
/*
*
* 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/endpoint/tcp_client.h"
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include "src/core/endpoint/socket_utils.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/time.h>
typedef struct {
void (*cb)(void *arg, grpc_endpoint *tcp);
void *cb_arg;
grpc_em_fd fd;
gpr_timespec deadline;
} async_connect;
static int create_fd(int address_family) {
int fd = socket(address_family, SOCK_STREAM, 0);
if (fd < 0) {
gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno));
goto error;
}
if (!grpc_set_socket_nonblocking(fd, 1) || !grpc_set_socket_cloexec(fd, 1) ||
!grpc_set_socket_low_latency(fd, 1)) {
gpr_log(GPR_ERROR, "Unable to configure socket %d: %s", fd,
strerror(errno));
goto error;
}
return fd;
error:
if (fd >= 0) {
close(fd);
}
return -1;
}
static void on_writable(void *acp, grpc_em_cb_status status) {
async_connect *ac = acp;
int so_error = 0;
socklen_t so_error_size;
int err;
int fd = grpc_em_fd_get(&ac->fd);
grpc_em *em = grpc_em_fd_get_em(&ac->fd);
if (status == GRPC_CALLBACK_SUCCESS) {
do {
so_error_size = sizeof(so_error);
err = getsockopt(fd, SOL_SOCKET, SO_ERROR, &so_error, &so_error_size);
} while (err < 0 && errno == EINTR);
if (err < 0) {
gpr_log(GPR_ERROR, "getsockopt(ERROR): %s", strerror(errno));
goto error;
} else if (so_error != 0) {
if (so_error == ENOBUFS) {
/* We will get one of these errors if we have run out of
memory in the kernel for the data structures allocated
when you connect a socket. If this happens it is very
likely that if we wait a little bit then try again the
connection will work (since other programs or this
program will close their network connections and free up
memory). This does _not_ indicate that there is anything
wrong with the server we are connecting to, this is a
local problem.
If you are looking at this code, then chances are that
your program or another program on the same computer
opened too many network connections. The "easy" fix:
don't do that! */
gpr_log(GPR_ERROR, "kernel out of buffers");
grpc_em_fd_notify_on_write(&ac->fd, on_writable, ac, ac->deadline);
return;
} else {
goto error;
}
} else {
goto great_success;
}
} else {
gpr_log(GPR_ERROR, "on_writable failed during connect: status=%d", status);
goto error;
}
abort();
error:
ac->cb(ac->cb_arg, NULL);
grpc_em_fd_destroy(&ac->fd);
gpr_free(ac);
close(fd);
return;
great_success:
grpc_em_fd_destroy(&ac->fd);
ac->cb(ac->cb_arg, grpc_tcp_create(fd, em));
gpr_free(ac);
}
void grpc_tcp_client_connect(void (*cb)(void *arg, grpc_endpoint *ep),
void *arg, grpc_em *em, struct sockaddr *addr,
int len, gpr_timespec deadline) {
int fd = create_fd(addr->sa_family);
int err;
async_connect *ac;
if (fd < 0) {
cb(arg, NULL);
return;
}
do {
err = connect(fd, addr, len);
} while (err < 0 && errno == EINTR);
if (err >= 0) {
cb(arg, grpc_tcp_create(fd, em));
return;
}
if (errno != EWOULDBLOCK && errno != EINPROGRESS) {
gpr_log(GPR_ERROR, "connect error: %s", strerror(errno));
close(fd);
cb(arg, NULL);
return;
}
ac = gpr_malloc(sizeof(async_connect));
ac->cb = cb;
ac->cb_arg = arg;
ac->deadline = deadline;
grpc_em_fd_init(&ac->fd, em, fd);
grpc_em_fd_notify_on_write(&ac->fd, on_writable, ac, deadline);
}

@ -0,0 +1,50 @@
/*
*
* 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_INTERNAL_ENDPOINT_TCP_CLIENT_H__
#define __GRPC_INTERNAL_ENDPOINT_TCP_CLIENT_H__
#include "src/core/endpoint/tcp.h"
#include <grpc/support/time.h>
#include <sys/types.h>
#include <sys/socket.h>
/* Asynchronously connect to an address (specified as (addr, len)), and call
cb with arg and the completed connection when done (or call cb with arg and
NULL on failure) */
void grpc_tcp_client_connect(void (*cb)(void *arg, grpc_endpoint *tcp),
void *arg, grpc_em *em, struct sockaddr *addr,
int len, gpr_timespec deadline);
#endif /* __GRPC_INTERNAL_ENDPOINT_TCP_CLIENT_H__ */

@ -0,0 +1,282 @@
/*
*
* 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.
*
*/
#define _GNU_SOURCE
#include "src/core/endpoint/tcp_server.h"
#include <limits.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include "src/core/endpoint/socket_utils.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
#include <grpc/support/time.h>
#define INIT_PORT_CAP 2
#define MIN_SAFE_ACCEPT_QUEUE_SIZE 100
static gpr_once s_init_max_accept_queue_size;
static int s_max_accept_queue_size;
/* one listening port */
typedef struct {
int fd;
grpc_em_fd *emfd;
grpc_tcp_server *server;
} server_port;
/* the overall server */
struct grpc_tcp_server {
grpc_em *em;
grpc_tcp_server_cb cb;
void *cb_arg;
gpr_mu mu;
gpr_cv cv;
/* active port count: how many ports are actually still listening */
int active_ports;
/* all listening ports */
server_port *ports;
size_t nports;
size_t port_capacity;
};
grpc_tcp_server *grpc_tcp_server_create(grpc_em *em) {
grpc_tcp_server *s = gpr_malloc(sizeof(grpc_tcp_server));
gpr_mu_init(&s->mu);
gpr_cv_init(&s->cv);
s->active_ports = 0;
s->em = em;
s->cb = NULL;
s->cb_arg = NULL;
s->ports = gpr_malloc(sizeof(server_port) * INIT_PORT_CAP);
s->nports = 0;
s->port_capacity = INIT_PORT_CAP;
return s;
}
void grpc_tcp_server_destroy(grpc_tcp_server *s) {
size_t i;
gpr_mu_lock(&s->mu);
/* shutdown all fd's */
for (i = 0; i < s->nports; i++) {
grpc_em_fd_shutdown(s->ports[i].emfd);
}
/* wait while that happens */
while (s->active_ports) {
gpr_cv_wait(&s->cv, &s->mu, gpr_inf_future);
}
gpr_mu_unlock(&s->mu);
/* delete ALL the things */
for (i = 0; i < s->nports; i++) {
server_port *sp = &s->ports[i];
grpc_em_fd_destroy(sp->emfd);
gpr_free(sp->emfd);
close(sp->fd);
}
gpr_free(s->ports);
gpr_free(s);
}
/* get max listen queue size on linux */
static void init_max_accept_queue_size() {
int n = SOMAXCONN;
char buf[64];
FILE *fp = fopen("/proc/sys/net/core/somaxconn", "r");
if (fp == NULL) {
/* 2.4 kernel. */
s_max_accept_queue_size = SOMAXCONN;
return;
}
if (fgets(buf, sizeof buf, fp)) {
char *end;
long i = strtol(buf, &end, 10);
if (i > 0 && i <= INT_MAX && end && *end == 0) {
n = i;
}
}
fclose(fp);
s_max_accept_queue_size = n;
if (s_max_accept_queue_size < MIN_SAFE_ACCEPT_QUEUE_SIZE) {
gpr_log(GPR_INFO,
"Suspiciously small accept queue (%d) will probably lead to "
"connection drops",
s_max_accept_queue_size);
}
}
static int get_max_accept_queue_size() {
gpr_once_init(&s_init_max_accept_queue_size, init_max_accept_queue_size);
return s_max_accept_queue_size;
}
/* create a socket to listen with */
static int create_listening_socket(struct sockaddr *port, int len) {
int fd = socket(port->sa_family, SOCK_STREAM, 0);
if (fd < 0) {
gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno));
goto error;
}
if (!grpc_set_socket_nonblocking(fd, 1) || !grpc_set_socket_cloexec(fd, 1) ||
!grpc_set_socket_low_latency(fd, 1) ||
!grpc_set_socket_reuse_addr(fd, 1)) {
gpr_log(GPR_ERROR, "Unable to configure socket %d: %s", fd,
strerror(errno));
goto error;
}
if (bind(fd, port, len) < 0) {
gpr_log(GPR_ERROR, "bind: %s", strerror(errno));
goto error;
}
if (listen(fd, get_max_accept_queue_size()) < 0) {
gpr_log(GPR_ERROR, "listen: %s", strerror(errno));
goto error;
}
return fd;
error:
if (fd >= 0) {
close(fd);
}
return -1;
}
/* event manager callback when reads are ready */
static void on_read(void *arg, grpc_em_cb_status status) {
server_port *sp = arg;
if (status != GRPC_CALLBACK_SUCCESS) {
goto error;
}
/* loop until accept4 returns EAGAIN, and then re-arm notification */
for (;;) {
struct sockaddr_storage addr;
socklen_t addrlen = sizeof(addr);
int fd = grpc_accept4(sp->fd, (struct sockaddr *)&addr, &addrlen, 1, 1);
if (fd < 0) {
switch (errno) {
case EINTR:
continue;
case EAGAIN:
if (GRPC_EM_OK != grpc_em_fd_notify_on_read(sp->emfd, on_read, sp,
gpr_inf_future)) {
gpr_log(GPR_ERROR, "Failed to register read request with em");
goto error;
}
return;
default:
gpr_log(GPR_ERROR, "Failed accept4: %s", strerror(errno));
goto error;
}
}
sp->server->cb(sp->server->cb_arg, grpc_tcp_create(fd, sp->server->em));
}
abort();
error:
gpr_mu_lock(&sp->server->mu);
if (0 == --sp->server->active_ports) {
gpr_cv_broadcast(&sp->server->cv);
}
gpr_mu_unlock(&sp->server->mu);
}
int grpc_tcp_server_add_port(grpc_tcp_server *s, struct sockaddr *port,
int len) {
server_port *sp;
/* create a socket */
int fd = create_listening_socket(port, len);
if (fd < 0) {
return -1;
}
gpr_mu_lock(&s->mu);
GPR_ASSERT(!s->cb && "must add ports before starting server");
/* append it to the list under a lock */
if (s->nports == s->port_capacity) {
s->port_capacity *= 2;
s->ports = gpr_realloc(s->ports, sizeof(server_port *) * s->port_capacity);
}
sp = &s->ports[s->nports++];
sp->emfd = gpr_malloc(sizeof(grpc_em_fd));
sp->fd = fd;
sp->server = s;
/* initialize the em desc */
if (GRPC_EM_OK != grpc_em_fd_init(sp->emfd, s->em, fd)) {
grpc_em_fd_destroy(sp->emfd);
gpr_free(sp->emfd);
s->nports--;
gpr_mu_unlock(&s->mu);
return -1;
}
gpr_mu_unlock(&s->mu);
return fd;
}
void grpc_tcp_server_start(grpc_tcp_server *s, grpc_tcp_server_cb cb,
void *cb_arg) {
size_t i;
GPR_ASSERT(cb);
gpr_mu_lock(&s->mu);
GPR_ASSERT(!s->cb);
GPR_ASSERT(s->active_ports == 0);
s->cb = cb;
s->cb_arg = cb_arg;
for (i = 0; i < s->nports; i++) {
grpc_em_fd_notify_on_read(s->ports[i].emfd, on_read, &s->ports[i],
gpr_inf_future);
s->active_ports++;
}
gpr_mu_unlock(&s->mu);
}

@ -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.
*
*/
#ifndef __GRPC_INTERNAL_ENDPOINT_TCP_SERVER_H__
#define __GRPC_INTERNAL_ENDPOINT_TCP_SERVER_H__
#include <sys/types.h>
#include <sys/socket.h>
#include "src/core/endpoint/tcp.h"
#include "src/core/eventmanager/em.h"
/* Forward decl of grpc_tcp_server */
typedef struct grpc_tcp_server grpc_tcp_server;
/* New server callback: tcp is the newly connected tcp connection */
typedef void (*grpc_tcp_server_cb)(void *arg, grpc_endpoint *ep);
/* Create a server, initially not bound to any ports */
grpc_tcp_server *grpc_tcp_server_create(grpc_em *em);
/* Start listening to bound ports */
void grpc_tcp_server_start(grpc_tcp_server *server, grpc_tcp_server_cb cb,
void *cb_arg);
/* Add a port to the server, returns a file descriptor on success, or <0 on
failure; the file descriptor remains owned by the server and will be cleaned
up when grpc_tcp_server_destroy is called */
int grpc_tcp_server_add_port(grpc_tcp_server *server, struct sockaddr *port,
int len);
void grpc_tcp_server_destroy(grpc_tcp_server *server);
#endif /* __GRPC_INTERNAL_ENDPOINT_TCP_SERVER_H__ */

@ -0,0 +1,664 @@
/*
*
* 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/eventmanager/em.h"
#include <unistd.h>
#include <fcntl.h>
#include <grpc/support/atm.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
#include <grpc/support/time.h>
#include <event2/event.h>
#include <event2/thread.h>
int evthread_use_threads(void);
#define ALARM_TRIGGER_INIT ((gpr_atm)0)
#define ALARM_TRIGGER_INCREMENT ((gpr_atm)1)
#define DONE_SHUTDOWN ((void *)1)
#define POLLER_ID_INVALID ((gpr_atm)-1)
/* ================== grpc_em implementation ===================== */
/* If anything is in the work queue, process one item and return 1.
Return 0 if there were no work items to complete.
Requires em->mu locked, may unlock and relock during the call. */
static int maybe_do_queue_work(grpc_em *em) {
grpc_em_activation_data *work = em->q;
if (work == NULL) return 0;
if (work->next == work) {
em->q = NULL;
} else {
em->q = work->next;
em->q->prev = work->prev;
em->q->next->prev = em->q->prev->next = em->q;
}
work->next = work->prev = NULL;
gpr_mu_unlock(&em->mu);
work->cb(work->arg, work->status);
gpr_mu_lock(&em->mu);
return 1;
}
/* Break out of the event loop on timeout */
static void timer_callback(int fd, short events, void *context) {
event_base_loopbreak((struct event_base *)context);
}
/* Spend some time polling if no other thread is.
Returns 1 if polling was performed, 0 otherwise.
Requires em->mu locked, may unlock and relock during the call. */
static int maybe_do_polling_work(grpc_em *em, struct timeval delay) {
int status;
if (em->num_pollers) return 0;
em->num_pollers = 1;
gpr_mu_unlock(&em->mu);
event_add(em->timeout_ev, &delay);
status = event_base_loop(em->event_base, EVLOOP_ONCE);
if (status < 0) {
gpr_log(GPR_ERROR, "event polling loop stops with error status %d", status);
}
event_del(em->timeout_ev);
gpr_mu_lock(&em->mu);
em->num_pollers = 0;
gpr_cv_broadcast(&em->cv);
return 1;
}
int grpc_em_work(grpc_em *em, gpr_timespec deadline) {
gpr_timespec delay_timespec = gpr_time_sub(deadline, gpr_now());
/* poll for no longer than one second */
gpr_timespec max_delay = {1, 0};
struct timeval delay;
GPR_ASSERT(em);
if (gpr_time_cmp(delay_timespec, gpr_time_0) <= 0) {
return 0;
}
if (gpr_time_cmp(delay_timespec, max_delay) > 0) {
delay_timespec = max_delay;
}
delay = gpr_timeval_from_timespec(delay_timespec);
if (maybe_do_queue_work(em) || maybe_do_polling_work(em, delay)) {
em->last_poll_completed = gpr_now();
return 1;
}
return 0;
}
static void backup_poller_thread(void *p) {
grpc_em *em = p;
int backup_poller_engaged = 0;
/* allow no pollers for 100 milliseconds, then engage backup polling */
gpr_timespec allow_no_pollers = gpr_time_from_micros(100 * 1000);
gpr_mu_lock(&em->mu);
while (!em->shutdown_backup_poller) {
if (em->num_pollers == 0) {
gpr_timespec now = gpr_now();
gpr_timespec time_until_engage = gpr_time_sub(
allow_no_pollers, gpr_time_sub(now, em->last_poll_completed));
if (gpr_time_cmp(time_until_engage, gpr_time_0) <= 0) {
if (!backup_poller_engaged) {
gpr_log(GPR_DEBUG, "No pollers for a while - engaging backup poller");
backup_poller_engaged = 1;
}
if (!maybe_do_queue_work(em)) {
struct timeval tv = {1, 0};
maybe_do_polling_work(em, tv);
}
} else {
if (backup_poller_engaged) {
gpr_log(GPR_DEBUG, "Backup poller disengaged");
backup_poller_engaged = 0;
}
gpr_mu_unlock(&em->mu);
gpr_sleep_until(gpr_time_add(now, time_until_engage));
gpr_mu_lock(&em->mu);
}
} else {
if (backup_poller_engaged) {
gpr_log(GPR_DEBUG, "Backup poller disengaged");
backup_poller_engaged = 0;
}
gpr_cv_wait(&em->cv, &em->mu, gpr_inf_future);
}
}
gpr_mu_unlock(&em->mu);
gpr_event_set(&em->backup_poller_done, (void *)1);
}
grpc_em_error grpc_em_init(grpc_em *em) {
gpr_thd_id backup_poller_id;
if (evthread_use_threads() != 0) {
gpr_log(GPR_ERROR, "Failed to initialize libevent thread support!");
return GRPC_EM_ERROR;
}
gpr_mu_init(&em->mu);
gpr_cv_init(&em->cv);
em->q = NULL;
em->num_pollers = 0;
em->num_fds = 0;
em->last_poll_completed = gpr_now();
em->shutdown_backup_poller = 0;
gpr_event_init(&em->backup_poller_done);
em->event_base = NULL;
em->timeout_ev = NULL;
em->event_base = event_base_new();
if (!em->event_base) {
gpr_log(GPR_ERROR, "Failed to create the event base");
return GRPC_EM_ERROR;
}
if (evthread_make_base_notifiable(em->event_base) != 0) {
gpr_log(GPR_ERROR, "Couldn't make event base notifiable cross threads!");
return GRPC_EM_ERROR;
}
em->timeout_ev = evtimer_new(em->event_base, timer_callback, em->event_base);
gpr_thd_new(&backup_poller_id, backup_poller_thread, em, NULL);
return GRPC_EM_OK;
}
grpc_em_error grpc_em_destroy(grpc_em *em) {
gpr_timespec fd_shutdown_deadline =
gpr_time_add(gpr_now(), gpr_time_from_micros(10 * 1000 * 1000));
/* broadcast shutdown */
gpr_mu_lock(&em->mu);
while (em->num_fds) {
gpr_log(GPR_INFO,
"waiting for %d fds to be destroyed before closing event manager",
em->num_fds);
if (gpr_cv_wait(&em->cv, &em->mu, fd_shutdown_deadline)) {
gpr_log(GPR_ERROR,
"not all fds destroyed before shutdown deadline: memory leaks "
"are likely");
break;
} else if (em->num_fds == 0) {
gpr_log(GPR_INFO, "all fds closed");
}
}
em->shutdown_backup_poller = 1;
gpr_cv_broadcast(&em->cv);
gpr_mu_unlock(&em->mu);
gpr_event_wait(&em->backup_poller_done, gpr_inf_future);
/* drain pending work */
gpr_mu_lock(&em->mu);
while (maybe_do_queue_work(em))
;
gpr_mu_unlock(&em->mu);
/* complete shutdown */
gpr_mu_destroy(&em->mu);
gpr_cv_destroy(&em->cv);
if (em->timeout_ev != NULL) {
event_free(em->timeout_ev);
}
if (em->event_base != NULL) {
event_base_free(em->event_base);
em->event_base = NULL;
}
return GRPC_EM_OK;
}
static void add_task(grpc_em *em, grpc_em_activation_data *adata) {
gpr_mu_lock(&em->mu);
if (em->q) {
adata->next = em->q;
adata->prev = adata->next->prev;
adata->next->prev = adata->prev->next = adata;
} else {
em->q = adata;
adata->next = adata->prev = adata;
}
gpr_cv_broadcast(&em->cv);
gpr_mu_unlock(&em->mu);
}
/* ===============grpc_em_alarm implementation==================== */
/* The following function frees up the alarm's libevent structure and
should always be invoked just before calling the alarm's callback */
static void alarm_ev_destroy(grpc_em_alarm *alarm) {
grpc_em_activation_data *adata = &alarm->task.activation[GRPC_EM_TA_ONLY];
if (adata->ev != NULL) {
event_free(adata->ev);
adata->ev = NULL;
}
}
/* Proxy callback triggered by alarm->ev to call alarm->cb */
static void libevent_alarm_cb(int fd, short what, void *arg /*=alarm*/) {
grpc_em_alarm *alarm = arg;
grpc_em_activation_data *adata = &alarm->task.activation[GRPC_EM_TA_ONLY];
int trigger_old;
/* First check if this alarm has been canceled, atomically */
trigger_old =
gpr_atm_full_fetch_add(&alarm->triggered, ALARM_TRIGGER_INCREMENT);
if (trigger_old == ALARM_TRIGGER_INIT) {
/* Before invoking user callback, destroy the libevent structure */
alarm_ev_destroy(alarm);
adata->status = GRPC_CALLBACK_SUCCESS;
add_task(alarm->task.em, adata);
}
}
grpc_em_error grpc_em_alarm_init(grpc_em_alarm *alarm, grpc_em *em,
grpc_em_cb_func alarm_cb, void *alarm_cb_arg) {
grpc_em_activation_data *adata = &alarm->task.activation[GRPC_EM_TA_ONLY];
alarm->task.type = GRPC_EM_TASK_ALARM;
alarm->task.em = em;
gpr_atm_rel_store(&alarm->triggered, ALARM_TRIGGER_INIT);
adata->cb = alarm_cb;
adata->arg = alarm_cb_arg;
adata->prev = NULL;
adata->next = NULL;
adata->ev = NULL;
return GRPC_EM_OK;
}
grpc_em_error grpc_em_alarm_add(grpc_em_alarm *alarm, gpr_timespec deadline) {
grpc_em_activation_data *adata = &alarm->task.activation[GRPC_EM_TA_ONLY];
gpr_timespec delay_timespec = gpr_time_sub(deadline, gpr_now());
struct timeval delay = gpr_timeval_from_timespec(delay_timespec);
if (adata->ev) {
event_free(adata->ev);
gpr_log(GPR_INFO, "Adding an alarm that already has an event.");
adata->ev = NULL;
}
adata->ev = evtimer_new(alarm->task.em->event_base, libevent_alarm_cb, alarm);
/* Set the trigger field to untriggered. Do this as the last store since
it is a release of previous stores. */
gpr_atm_rel_store(&alarm->triggered, ALARM_TRIGGER_INIT);
if (adata->ev != NULL && evtimer_add(adata->ev, &delay) == 0) {
return GRPC_EM_OK;
} else {
return GRPC_EM_ERROR;
}
}
grpc_em_error grpc_em_alarm_cancel(grpc_em_alarm *alarm, void **arg) {
grpc_em_activation_data *adata = &alarm->task.activation[GRPC_EM_TA_ONLY];
int trigger_old;
*arg = adata->arg;
/* First check if this alarm has been triggered, atomically */
trigger_old =
gpr_atm_full_fetch_add(&alarm->triggered, ALARM_TRIGGER_INCREMENT);
if (trigger_old == ALARM_TRIGGER_INIT) {
/* We need to make sure that we only invoke the callback if it hasn't
already been invoked */
/* First remove this event from libevent. This returns success even if the
event has gone active or invoked its callback. */
if (evtimer_del(adata->ev) != 0) {
/* The delete was unsuccessful for some reason. */
gpr_log(GPR_ERROR, "Attempt to delete alarm event was unsuccessful");
return GRPC_EM_ERROR;
}
/* Free up the event structure before invoking callback */
alarm_ev_destroy(alarm);
adata->status = GRPC_CALLBACK_CANCELLED;
add_task(alarm->task.em, adata);
}
return GRPC_EM_OK;
}
/* ==================== grpc_em_fd implementation =================== */
/* Proxy callback to call a gRPC read/write callback */
static void em_fd_cb(int fd, short what, void *arg /*=em_fd*/) {
grpc_em_fd *em_fd = arg;
grpc_em_cb_status status = GRPC_CALLBACK_SUCCESS;
int run_read_cb = 0;
int run_write_cb = 0;
grpc_em_activation_data *rdata, *wdata;
gpr_mu_lock(&em_fd->mu);
/* TODO(klempner): We need to delete the event here too so we avoid spurious
shutdowns. */
if (em_fd->shutdown_started) {
status = GRPC_CALLBACK_CANCELLED;
} else if (status == GRPC_CALLBACK_SUCCESS && (what & EV_TIMEOUT)) {
status = GRPC_CALLBACK_TIMED_OUT;
/* TODO(klempner): This is broken if we are monitoring both read and write
events on the same fd -- generating a spurious event is okay, but
generating a spurious timeout is not. */
what |= (EV_READ | EV_WRITE);
}
if (what & EV_READ) {
switch (em_fd->read_state) {
case GRPC_EM_FD_WAITING:
run_read_cb = 1;
em_fd->read_state = GRPC_EM_FD_IDLE;
break;
case GRPC_EM_FD_IDLE:
case GRPC_EM_FD_CACHED:
em_fd->read_state = GRPC_EM_FD_CACHED;
}
}
if (what & EV_WRITE) {
switch (em_fd->write_state) {
case GRPC_EM_FD_WAITING:
run_write_cb = 1;
em_fd->write_state = GRPC_EM_FD_IDLE;
break;
case GRPC_EM_FD_IDLE:
case GRPC_EM_FD_CACHED:
em_fd->write_state = GRPC_EM_FD_CACHED;
}
}
if (run_read_cb) {
rdata = &(em_fd->task.activation[GRPC_EM_TA_READ]);
rdata->status = status;
add_task(em_fd->task.em, rdata);
} else if (run_write_cb) {
wdata = &(em_fd->task.activation[GRPC_EM_TA_WRITE]);
wdata->status = status;
add_task(em_fd->task.em, wdata);
}
gpr_mu_unlock(&em_fd->mu);
}
static void em_fd_shutdown_cb(int fd, short what, void *arg /*=em_fd*/) {
/* TODO(klempner): This could just run directly in the calling thread, except
that libevent's handling of event_active() on an event which is already in
flight on a different thread is racy and easily triggers TSAN.
*/
grpc_em_fd *em_fd = arg;
gpr_mu_lock(&em_fd->mu);
em_fd->shutdown_started = 1;
if (em_fd->read_state == GRPC_EM_FD_WAITING) {
event_active(em_fd->task.activation[GRPC_EM_TA_READ].ev, EV_READ, 1);
}
if (em_fd->write_state == GRPC_EM_FD_WAITING) {
event_active(em_fd->task.activation[GRPC_EM_TA_WRITE].ev, EV_WRITE, 1);
}
gpr_mu_unlock(&em_fd->mu);
}
grpc_em_error grpc_em_fd_init(grpc_em_fd *em_fd, grpc_em *em, int fd) {
int flags;
grpc_em_activation_data *rdata, *wdata;
gpr_mu_lock(&em->mu);
em->num_fds++;
gpr_mu_unlock(&em->mu);
em_fd->shutdown_ev = NULL;
gpr_mu_init(&em_fd->mu);
flags = fcntl(fd, F_GETFL, 0);
if ((flags & O_NONBLOCK) == 0) {
gpr_log(GPR_ERROR, "File descriptor %d is blocking", fd);
return GRPC_EM_INVALID_ARGUMENTS;
}
em_fd->task.type = GRPC_EM_TASK_FD;
em_fd->task.em = em;
em_fd->fd = fd;
rdata = &(em_fd->task.activation[GRPC_EM_TA_READ]);
rdata->ev = NULL;
rdata->cb = NULL;
rdata->arg = NULL;
rdata->status = GRPC_CALLBACK_SUCCESS;
rdata->prev = NULL;
rdata->next = NULL;
wdata = &(em_fd->task.activation[GRPC_EM_TA_WRITE]);
wdata->ev = NULL;
wdata->cb = NULL;
wdata->arg = NULL;
wdata->status = GRPC_CALLBACK_SUCCESS;
wdata->prev = NULL;
wdata->next = NULL;
em_fd->read_state = GRPC_EM_FD_IDLE;
em_fd->write_state = GRPC_EM_FD_IDLE;
/* TODO(chenw): detect platforms where only level trigger is supported,
and set the event to non-persist. */
rdata->ev = event_new(em->event_base, em_fd->fd, EV_ET | EV_PERSIST | EV_READ,
em_fd_cb, em_fd);
if (!rdata->ev) {
gpr_log(GPR_ERROR, "Failed to create read event");
return GRPC_EM_ERROR;
}
wdata->ev = event_new(em->event_base, em_fd->fd,
EV_ET | EV_PERSIST | EV_WRITE, em_fd_cb, em_fd);
if (!wdata->ev) {
gpr_log(GPR_ERROR, "Failed to create write event");
return GRPC_EM_ERROR;
}
em_fd->shutdown_ev =
event_new(em->event_base, -1, EV_READ, em_fd_shutdown_cb, em_fd);
if (!em_fd->shutdown_ev) {
gpr_log(GPR_ERROR, "Failed to create shutdown event");
return GRPC_EM_ERROR;
}
em_fd->shutdown_started = 0;
return GRPC_EM_OK;
}
void grpc_em_fd_destroy(grpc_em_fd *em_fd) {
grpc_em_task_activity_type type;
grpc_em_activation_data *adata;
grpc_em *em = em_fd->task.em;
/* ensure anyone holding the lock has left - it's the callers responsibility
to ensure that no new users enter */
gpr_mu_lock(&em_fd->mu);
gpr_mu_unlock(&em_fd->mu);
for (type = GRPC_EM_TA_READ; type < GRPC_EM_TA_COUNT; type++) {
adata = &(em_fd->task.activation[type]);
GPR_ASSERT(adata->next == NULL);
if (adata->ev != NULL) {
event_free(adata->ev);
adata->ev = NULL;
}
}
if (em_fd->shutdown_ev != NULL) {
event_free(em_fd->shutdown_ev);
em_fd->shutdown_ev = NULL;
}
gpr_mu_destroy(&em_fd->mu);
gpr_mu_lock(&em->mu);
em->num_fds--;
gpr_cv_broadcast(&em->cv);
gpr_mu_unlock(&em->mu);
}
int grpc_em_fd_get(struct grpc_em_fd *em_fd) { return em_fd->fd; }
/* Returns the event manager associated with *em_fd. */
grpc_em *grpc_em_fd_get_em(grpc_em_fd *em_fd) { return em_fd->task.em; }
/* TODO(chenw): should we enforce the contract that notify_on_read cannot be
called when the previously registered callback has not been called yet. */
grpc_em_error grpc_em_fd_notify_on_read(grpc_em_fd *em_fd,
grpc_em_cb_func read_cb,
void *read_cb_arg,
gpr_timespec deadline) {
int force_event = 0;
grpc_em_activation_data *rdata;
grpc_em_error result = GRPC_EM_OK;
gpr_timespec delay_timespec = gpr_time_sub(deadline, gpr_now());
struct timeval delay = gpr_timeval_from_timespec(delay_timespec);
struct timeval *delayp =
gpr_time_cmp(deadline, gpr_inf_future) ? &delay : NULL;
rdata = &em_fd->task.activation[GRPC_EM_TA_READ];
gpr_mu_lock(&em_fd->mu);
rdata->cb = read_cb;
rdata->arg = read_cb_arg;
force_event =
(em_fd->shutdown_started || em_fd->read_state == GRPC_EM_FD_CACHED);
em_fd->read_state = GRPC_EM_FD_WAITING;
if (force_event) {
event_active(rdata->ev, EV_READ, 1);
} else if (event_add(rdata->ev, delayp) == -1) {
result = GRPC_EM_ERROR;
}
gpr_mu_unlock(&em_fd->mu);
return result;
}
grpc_em_error grpc_em_fd_notify_on_write(grpc_em_fd *em_fd,
grpc_em_cb_func write_cb,
void *write_cb_arg,
gpr_timespec deadline) {
int force_event = 0;
grpc_em_activation_data *wdata;
grpc_em_error result = GRPC_EM_OK;
gpr_timespec delay_timespec = gpr_time_sub(deadline, gpr_now());
struct timeval delay = gpr_timeval_from_timespec(delay_timespec);
struct timeval *delayp =
gpr_time_cmp(deadline, gpr_inf_future) ? &delay : NULL;
wdata = &em_fd->task.activation[GRPC_EM_TA_WRITE];
gpr_mu_lock(&em_fd->mu);
wdata->cb = write_cb;
wdata->arg = write_cb_arg;
force_event =
(em_fd->shutdown_started || em_fd->write_state == GRPC_EM_FD_CACHED);
em_fd->write_state = GRPC_EM_FD_WAITING;
if (force_event) {
event_active(wdata->ev, EV_WRITE, 1);
} else if (event_add(wdata->ev, delayp) == -1) {
result = GRPC_EM_ERROR;
}
gpr_mu_unlock(&em_fd->mu);
return result;
}
void grpc_em_fd_shutdown(grpc_em_fd *em_fd) {
event_active(em_fd->shutdown_ev, EV_READ, 1);
}
/*====================== Other callback functions ======================*/
/* Sometimes we want a followup callback: something to be added from the
current callback for the EM to invoke once this callback is complete.
This is implemented by inserting an entry into an EM queue. */
/* The following structure holds the field needed for adding the
followup callback. These are the argument for the followup callback,
the function to use for the followup callback, and the
activation data pointer used for the queues (to free in the CB) */
struct followup_callback_arg {
grpc_em_cb_func func;
void *cb_arg;
grpc_em_activation_data adata;
};
static void followup_proxy_callback(void *cb_arg, grpc_em_cb_status status) {
struct followup_callback_arg *fcb_arg = cb_arg;
/* Invoke the function */
fcb_arg->func(fcb_arg->cb_arg, status);
gpr_free(fcb_arg);
}
grpc_em_error grpc_em_add_callback(grpc_em *em, grpc_em_cb_func cb,
void *cb_arg) {
grpc_em_activation_data *adptr;
struct followup_callback_arg *fcb_arg;
fcb_arg = gpr_malloc(sizeof(*fcb_arg));
if (fcb_arg == NULL) {
return GRPC_EM_ERROR;
}
/* Set up the activation data and followup callback argument structures */
adptr = &fcb_arg->adata;
adptr->ev = NULL;
adptr->cb = followup_proxy_callback;
adptr->arg = fcb_arg;
adptr->status = GRPC_CALLBACK_SUCCESS;
adptr->prev = NULL;
adptr->next = NULL;
fcb_arg->func = cb;
fcb_arg->cb_arg = cb_arg;
/* Insert an activation data for the specified em */
add_task(em, adptr);
return GRPC_EM_OK;
}

@ -0,0 +1,350 @@
/*
*
* 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_INTERNAL_EVENTMANAGER_EM_H__
#define __GRPC_INTERNAL_EVENTMANAGER_EM_H__
/* grpc_em is an event manager wrapping event loop with multithread support.
It executes a callback function when a specific event occurs on a file
descriptor or after a timeout has passed.
All methods are threadsafe and can be called from any thread.
To use the event manager, a grpc_em instance needs to be initialized to
maintains the internal states. The grpc_em instance can be used to
initialize file descriptor instance of grpc_em_fd, or alarm instance of
grpc_em_alarm. The former is used to register a callback with a IO event.
The later is used to schedule an alarm.
Instantiating any of these data structures requires including em_internal.h
A typical usage example is shown in the end of that header file. */
#include <grpc/support/atm.h>
#include <grpc/support/sync.h>
#include <grpc/support/thd.h>
#include <grpc/support/time.h>
/* =============== Enums used in GRPC event manager API ==================== */
/* Result of a grpc_em operation */
typedef enum grpc_em_error {
GRPC_EM_OK = 0, /* everything went ok */
GRPC_EM_ERROR, /* internal errors not caused by the caller */
GRPC_EM_INVALID_ARGUMENTS /* invalid arguments from the caller */
} grpc_em_error;
/* Status passed to callbacks for grpc_em_fd_notify_on_read and
grpc_em_fd_notify_on_write. */
typedef enum grpc_em_cb_status {
GRPC_CALLBACK_SUCCESS = 0,
GRPC_CALLBACK_TIMED_OUT,
GRPC_CALLBACK_CANCELLED,
GRPC_CALLBACK_DO_NOT_USE
} grpc_em_cb_status;
/* ======= Useful forward struct typedefs for GRPC event manager API ======= */
struct grpc_em;
struct grpc_em_alarm;
struct grpc_fd;
typedef struct grpc_em grpc_em;
typedef struct grpc_em_alarm grpc_em_alarm;
typedef struct grpc_em_fd grpc_em_fd;
/* gRPC Callback definition */
typedef void (*grpc_em_cb_func)(void *arg, grpc_em_cb_status status);
/* ============================ grpc_em =============================== */
/* Initialize *em and start polling, return GRPC_EM_OK on success, return
GRPC_EM_ERROR on failure. Upon failure, caller should call grpc_em_destroy()
to clean partially initialized *em.
Requires: *em uninitialized. */
grpc_em_error grpc_em_init(grpc_em *em);
/* Stop polling and cause *em no longer to be initialized.
Return GRPC_EM_OK if event polling is cleanly stopped.
Otherwise, return GRPC_EM_ERROR if polling is shutdown with errors.
Requires: *em initialized; no other concurrent operation on *em. */
grpc_em_error grpc_em_destroy(grpc_em *em);
/* do some work; assumes em->mu locked; may unlock and relock em->mu */
int grpc_em_work(grpc_em *em, gpr_timespec deadline);
/* =========================== grpc_em_am ============================== */
/* Initialize *alarm. When expired or canceled, alarm_cb will be called with
*alarm_cb_arg and status to indicate if it expired (SUCCESS) or was
canceled (CANCELLED). alarm_cb is guaranteed to be called exactly once,
and application code should check the status to determine how it was
invoked. The application callback is also responsible for maintaining
information about when to free up any user-level state. */
grpc_em_error grpc_em_alarm_init(grpc_em_alarm *alarm, grpc_em *em,
grpc_em_cb_func alarm_cb, void *alarm_cb_arg);
/* Note that there is no alarm destroy function. This is because the
alarm is a one-time occurrence with a guarantee that the callback will
be called exactly once, either at expiration or cancellation. Thus, all
the internal alarm event management state is destroyed just before
that callback is invoked. If the user has additional state associated with
the alarm, the user is responsible for determining when it is safe to
destroy that state. */
/* Schedule *alarm to expire at deadline. If *alarm is
re-added before expiration, the *delay is simply reset to the new value.
Return GRPC_EM_OK on success, or GRPC_EM_ERROR on failure.
Upon failure, caller should abort further operations on *alarm */
grpc_em_error grpc_em_alarm_add(grpc_em_alarm *alarm, gpr_timespec deadline);
/* Cancel an *alarm.
There are three cases:
1. We normally cancel the alarm
2. The alarm has already run
3. We can't cancel the alarm because it is "in flight".
In all of these cases, the cancellation is still considered successful.
They are essentially distinguished in that the alarm_cb will be run
exactly once from either the cancellation (with status CANCELLED)
or from the activation (with status SUCCESS)
Requires: cancel() must happen after add() on a given alarm */
grpc_em_error grpc_em_alarm_cancel(grpc_em_alarm *alarm, void **arg);
/* ========================== grpc_em_fd ============================= */
/* Initialize *em_fd, return GRPM_EM_OK on success, GRPC_EM_ERROR on internal
errors, or GRPC_EM_INVALID_ARGUMENTS if fd is a blocking file descriptor.
Upon failure, caller should call grpc_em_fd_destroy() to clean partially
initialized *em_fd.
fd is a non-blocking file descriptor.
Requires: *em_fd uninitialized. fd is a non-blocking file descriptor. */
grpc_em_error grpc_em_fd_init(grpc_em_fd *em_fd, grpc_em *em, int fd);
/* Cause *em_fd no longer to be initialized.
Requires: *em_fd initialized; no outstanding notify_on_read or
notify_on_write. */
void grpc_em_fd_destroy(grpc_em_fd *em_fd);
/* Returns the file descriptor associated with *em_fd. */
int grpc_em_fd_get(grpc_em_fd *em_fd);
/* Returns the event manager associated with *em_fd. */
grpc_em *grpc_em_fd_get_em(grpc_em_fd *em_fd);
/* Register read interest, causing read_cb to be called once when em_fd becomes
readable, on deadline specified by deadline, or on shutdown triggered by
grpc_em_fd_shutdown.
Return GRPC_EM_OK on success, or GRPC_EM_ERROR on failure.
Upon Failure, caller should abort further operations on *em_fd except
grpc_em_fd_shutdown().
read_cb will be called with read_cb_arg when *em_fd becomes readable.
read_cb is Called with status of GRPC_CALLBACK_SUCCESS if readable,
GRPC_CALLBACK_TIMED_OUT if the call timed out,
and CANCELLED if the call was cancelled.
Requires:This method must not be called before the read_cb for any previous
call runs. Edge triggered events are used whenever they are supported by the
underlying platform. This means that users must drain em_fd in read_cb before
calling notify_on_read again. Users are also expected to handle spurious
events, i.e read_cb is called while nothing can be readable from em_fd */
grpc_em_error grpc_em_fd_notify_on_read(grpc_em_fd *em_fd,
grpc_em_cb_func read_cb,
void *read_cb_arg,
gpr_timespec deadline);
/* Exactly the same semantics as above, except based on writable events. */
grpc_em_error grpc_em_fd_notify_on_write(grpc_em_fd *fd,
grpc_em_cb_func write_cb,
void *write_cb_arg,
gpr_timespec deadline);
/* Cause any current and all future read/write callbacks to error out with
GRPC_CALLBACK_CANCELLED. */
void grpc_em_fd_shutdown(grpc_em_fd *em_fd);
/* ================== Other functions =================== */
/* This function is called from within a callback or from anywhere else
and causes the invocation of a callback at some point in the future */
grpc_em_error grpc_em_add_callback(grpc_em *em, grpc_em_cb_func cb,
void *cb_arg);
/* ========== Declarations related to queue management (non-API) =========== */
/* Forward declarations */
struct grpc_em_activation_data;
/* ================== Actual structure definitions ========================= */
/* gRPC event manager handle.
The handle is used to initialize both grpc_em_alarm and grpc_em_fd. */
struct em_thread_arg;
struct grpc_em {
struct event_base *event_base;
gpr_mu mu;
gpr_cv cv;
struct grpc_em_activation_data *q;
int num_pollers;
int num_fds;
gpr_timespec last_poll_completed;
int shutdown_backup_poller;
gpr_event backup_poller_done;
struct event *timeout_ev; /* activated to break out of the event loop early */
};
/* gRPC event manager task "base class". This is pretend-inheritance in C89.
This should be the first member of any actual grpc_em task type.
Memory warning: expanding this will increase memory usage in any derived
class, so be careful.
For generality, this base can be on multiple task queues and can have
multiple event callbacks registered. Not all "derived classes" will use
this feature. */
typedef enum grpc_em_task_type {
GRPC_EM_TASK_ALARM,
GRPC_EM_TASK_FD,
GRPC_EM_TASK_DO_NOT_USE
} grpc_em_task_type;
/* Different activity types to shape the callback and queueing arrays */
typedef enum grpc_em_task_activity_type {
GRPC_EM_TA_READ, /* use this also for single-type events */
GRPC_EM_TA_WRITE,
GRPC_EM_TA_COUNT
} grpc_em_task_activity_type;
/* Include the following #define for convenience for tasks like alarms that
only have a single type */
#define GRPC_EM_TA_ONLY GRPC_EM_TA_READ
typedef struct grpc_em_activation_data {
struct event *ev; /* event activated on this callback type */
grpc_em_cb_func cb; /* function pointer for callback */
void *arg; /* argument passed to cb */
/* Hold the status associated with the callback when queued */
grpc_em_cb_status status;
/* Now set up to link activations into scheduler queues */
struct grpc_em_activation_data *prev;
struct grpc_em_activation_data *next;
} grpc_em_activation_data;
typedef struct grpc_em_task {
grpc_em_task_type type;
grpc_em *em;
/* Now have an array of activation data elements: one for each activity
type that could get activated */
grpc_em_activation_data activation[GRPC_EM_TA_COUNT];
} grpc_em_task;
/* gRPC alarm handle.
The handle is used to add an alarm which expires after specified timeout. */
struct grpc_em_alarm {
grpc_em_task task; /* Include the base class */
gpr_atm triggered; /* To be used atomically if alarm triggered */
};
/* =================== Event caching ===================
In order to not miss or double-return edges in the context of edge triggering
and multithreading, we need a per-fd caching layer in the eventmanager itself
to cache relevant events.
There are two types of events we care about: calls to notify_on_[read|write]
and readable/writable events for the socket from eventfd. There are separate
event caches for read and write.
There are three states:
0. "waiting" -- There's been a call to notify_on_[read|write] which has not
had a corresponding event. In other words, we're waiting for an event so we
can run the callback.
1. "idle" -- We are neither waiting nor have a cached event.
2. "cached" -- There has been a read/write event without a waiting callback,
so we want to run the event next time the application calls
notify_on_[read|write].
The high level state diagram:
+--------------------------------------------------------------------+
| WAITING | IDLE | CACHED |
| | | |
| 1. --*-> 2. --+-> 3. --+\
| | | <--+/
| | | |
x+-- 6. 5. <-+-- 4. <-*-- |
| | | |
+--------------------------------------------------------------------+
Transitions right occur on read|write events. Transitions left occur on
notify_on_[read|write] events.
State transitions:
1. Read|Write event while waiting -> run the callback and transition to idle.
2. Read|Write event while idle -> transition to cached.
3. Read|Write event with one already cached -> still cached.
4. notify_on_[read|write] with event cached: run callback and transition to
idle.
5. notify_on_[read|write] when idle: Store callback and transition to
waiting.
6. notify_on_[read|write] when waiting: invalid. */
typedef enum grpc_em_fd_state {
GRPC_EM_FD_WAITING = 0,
GRPC_EM_FD_IDLE = 1,
GRPC_EM_FD_CACHED = 2
} grpc_em_fd_state;
/* gRPC file descriptor handle.
The handle is used to register read/write callbacks to a file descriptor */
struct grpc_em_fd {
grpc_em_task task; /* Base class, callbacks, queues, etc */
int fd; /* File descriptor */
/* Note that the shutdown event is only needed as a workaround for libevent
not properly handling event_active on an in flight event. */
struct event *shutdown_ev; /* activated to trigger shutdown */
/* protect shutdown_started|read_state|write_state and ensure barriers
between notify_on_[read|write] and read|write callbacks */
gpr_mu mu;
int shutdown_started; /* 0 -> shutdown not started, 1 -> started */
grpc_em_fd_state read_state;
grpc_em_fd_state write_state;
/* activated after some timeout to activate shutdown_ev */
};
#endif /* __GRPC_INTERNAL_EVENTMANAGER_EM_H__ */

@ -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.
*
*/
/* Posix grpc event manager support code. */
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
#include <event2/thread.h>
static int error_code = 0;
static gpr_once threads_once = GPR_ONCE_INIT;
static void evthread_threads_initialize(void) {
error_code = evthread_use_pthreads();
if (error_code) {
gpr_log(GPR_ERROR, "Failed to initialize libevent thread support!");
}
}
/* Notify LibEvent that Posix pthread is used. */
int evthread_use_threads() {
gpr_once_init(&threads_once, &evthread_threads_initialize);
/* For Pthreads or Windows threads, Libevent provides simple APIs to set
mutexes and conditional variables to support cross thread operations.
For other platforms, LibEvent provide callback APIs to hook mutexes and
conditional variables. */
return error_code;
}

@ -0,0 +1,38 @@
/*
*
* 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.
*
*/
/* Windows event manager support code. */
#include <event2/thread.h>
/* Notify LibEvent that Windows thread is used. */
int evthread_use_threads() { return evthread_use_windows_threads(); }

@ -0,0 +1,121 @@
/*
*
* 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/httpcli/format_request.h"
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/slice.h>
#include <grpc/support/useful.h>
typedef struct {
size_t length;
size_t capacity;
char *data;
} sbuf;
static void sbuf_append(sbuf *buf, const char *bytes, size_t len) {
if (buf->length + len > buf->capacity) {
buf->capacity = GPR_MAX(buf->length + len, buf->capacity * 3 / 2);
buf->data = gpr_realloc(buf->data, buf->capacity);
}
memcpy(buf->data + buf->length, bytes, len);
buf->length += len;
}
static void sbprintf(sbuf *buf, const char *fmt, ...) {
char temp[GRPC_HTTPCLI_MAX_HEADER_LENGTH];
size_t len;
va_list args;
va_start(args, fmt);
len = vsprintf(temp, fmt, args);
va_end(args);
sbuf_append(buf, temp, len);
}
static void fill_common_header(const grpc_httpcli_request *request, sbuf *buf) {
size_t i;
sbprintf(buf, "%s HTTP/1.0\r\n", request->path);
/* just in case some crazy server really expects HTTP/1.1 */
sbprintf(buf, "Host: %s\r\n", request->host);
sbprintf(buf, "Connection: close\r\n");
sbprintf(buf, "User-Agent: %s\r\n", GRPC_HTTPCLI_USER_AGENT);
/* user supplied headers */
for (i = 0; i < request->hdr_count; i++) {
sbprintf(buf, "%s: %s\r\n", request->hdrs[i].key, request->hdrs[i].value);
}
}
gpr_slice grpc_httpcli_format_get_request(const grpc_httpcli_request *request) {
sbuf out = {0, 0, NULL};
sbprintf(&out, "GET ");
fill_common_header(request, &out);
sbprintf(&out, "\r\n");
return gpr_slice_new(out.data, out.length, gpr_free);
}
gpr_slice grpc_httpcli_format_post_request(const grpc_httpcli_request *request,
const char *body_bytes,
size_t body_size) {
sbuf out = {0, 0, NULL};
size_t i;
sbprintf(&out, "POST ");
fill_common_header(request, &out);
if (body_bytes) {
gpr_uint8 has_content_type = 0;
for (i = 0; i < request->hdr_count; i++) {
if (strcmp(request->hdrs[i].key, "Content-Type") == 0) {
has_content_type = 1;
break;
}
}
if (!has_content_type) {
sbprintf(&out, "Content-Type: text/plain\r\n");
}
sbprintf(&out, "Content-Length: %lu\r\n", (unsigned long)body_size);
}
sbprintf(&out, "\r\n");
if (body_bytes) {
sbuf_append(&out, body_bytes, body_size);
}
return gpr_slice_new(out.data, out.length, gpr_free);
}

@ -0,0 +1,45 @@
/*
*
* 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_INTERNAL_HTTPCLI_FORMAT_REQUEST_H__
#define __GRPC_INTERNAL_HTTPCLI_FORMAT_REQUEST_H__
#include "src/core/httpcli/httpcli.h"
#include <grpc/support/slice.h>
gpr_slice grpc_httpcli_format_get_request(const grpc_httpcli_request *request);
gpr_slice grpc_httpcli_format_post_request(const grpc_httpcli_request *request,
const char *body_bytes,
size_t body_size);
#endif /* __GRPC_INTERNAL_HTTPCLI_FORMAT_REQUEST_H__ */

@ -0,0 +1,259 @@
/*
*
* 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/httpcli/httpcli.h"
#include <string.h>
#include "src/core/endpoint/endpoint.h"
#include "src/core/endpoint/resolve_address.h"
#include "src/core/endpoint/tcp_client.h"
#include "src/core/httpcli/format_request.h"
#include "src/core/httpcli/httpcli_security_context.h"
#include "src/core/httpcli/parser.h"
#include "src/core/security/security_context.h"
#include "src/core/security/google_root_certs.h"
#include "src/core/security/secure_transport_setup.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string.h>
typedef struct {
gpr_slice request_text;
grpc_httpcli_parser parser;
grpc_resolved_addresses *addresses;
size_t next_address;
grpc_endpoint *ep;
grpc_em *em;
char *host;
gpr_timespec deadline;
int have_read_byte;
int use_ssl;
grpc_httpcli_response_cb on_response;
void *user_data;
} internal_request;
static void next_address(internal_request *req);
static void finish(internal_request *req, int success) {
gpr_log(GPR_DEBUG, "%s", __FUNCTION__);
req->on_response(req->user_data, success ? &req->parser.r : NULL);
grpc_httpcli_parser_destroy(&req->parser);
if (req->addresses != NULL) {
grpc_resolved_addresses_destroy(req->addresses);
}
if (req->ep != NULL) {
grpc_endpoint_destroy(req->ep);
}
gpr_slice_unref(req->request_text);
gpr_free(req->host);
gpr_free(req);
}
static void on_read(void *user_data, gpr_slice *slices, size_t nslices,
grpc_endpoint_cb_status status) {
internal_request *req = user_data;
size_t i;
gpr_log(GPR_DEBUG, "%s nslices=%d status=%d", __FUNCTION__, nslices, status);
for (i = 0; i < nslices; i++) {
if (GPR_SLICE_LENGTH(slices[i])) {
req->have_read_byte = 1;
if (!grpc_httpcli_parser_parse(&req->parser, slices[i])) {
finish(req, 0);
goto done;
}
}
}
switch (status) {
case GRPC_ENDPOINT_CB_OK:
grpc_endpoint_notify_on_read(req->ep, on_read, req, gpr_inf_future);
break;
case GRPC_ENDPOINT_CB_EOF:
case GRPC_ENDPOINT_CB_ERROR:
case GRPC_ENDPOINT_CB_SHUTDOWN:
case GRPC_ENDPOINT_CB_TIMED_OUT:
if (!req->have_read_byte) {
next_address(req);
} else {
finish(req, grpc_httpcli_parser_eof(&req->parser));
}
break;
}
done:
for (i = 0; i < nslices; i++) {
gpr_slice_unref(slices[i]);
}
}
static void on_written(internal_request *req) {
gpr_log(GPR_DEBUG, "%s", __FUNCTION__);
grpc_endpoint_notify_on_read(req->ep, on_read, req, gpr_inf_future);
}
static void done_write(void *arg, grpc_endpoint_cb_status status) {
internal_request *req = arg;
gpr_log(GPR_DEBUG, "%s", __FUNCTION__);
switch (status) {
case GRPC_ENDPOINT_CB_OK:
on_written(req);
break;
case GRPC_ENDPOINT_CB_EOF:
case GRPC_ENDPOINT_CB_SHUTDOWN:
case GRPC_ENDPOINT_CB_ERROR:
case GRPC_ENDPOINT_CB_TIMED_OUT:
next_address(req);
break;
}
}
static void start_write(internal_request *req) {
gpr_slice_ref(req->request_text);
gpr_log(GPR_DEBUG, "%s", __FUNCTION__);
switch (grpc_endpoint_write(req->ep, &req->request_text, 1, done_write, req,
gpr_inf_future)) {
case GRPC_ENDPOINT_WRITE_DONE:
on_written(req);
break;
case GRPC_ENDPOINT_WRITE_PENDING:
break;
case GRPC_ENDPOINT_WRITE_ERROR:
finish(req, 0);
break;
}
}
static void on_secure_transport_setup_done(void *rp,
grpc_security_status status,
grpc_endpoint *secure_endpoint) {
internal_request *req = rp;
gpr_log(GPR_DEBUG, "%s", __FUNCTION__);
if (status != GRPC_SECURITY_OK) {
gpr_log(GPR_ERROR, "Secure transport setup failed with error %d.", status);
finish(req, 0);
} else {
req->ep = secure_endpoint;
start_write(req);
}
}
static void on_connected(void *arg, grpc_endpoint *tcp) {
internal_request *req = arg;
gpr_log(GPR_DEBUG, "%s", __FUNCTION__);
if (!tcp) {
next_address(req);
return;
}
req->ep = tcp;
if (req->use_ssl) {
grpc_channel_security_context *ctx = NULL;
GPR_ASSERT(grpc_httpcli_ssl_channel_security_context_create(
grpc_google_root_certs, grpc_google_root_certs_size,
req->host, &ctx) == GRPC_SECURITY_OK);
grpc_setup_secure_transport(&ctx->base, tcp, on_secure_transport_setup_done,
req);
grpc_security_context_unref(&ctx->base);
} else {
start_write(req);
}
}
static void next_address(internal_request *req) {
grpc_resolved_address *addr;
gpr_log(GPR_DEBUG, "%s", __FUNCTION__);
if (req->next_address == req->addresses->naddrs) {
finish(req, 0);
return;
}
addr = &req->addresses->addrs[req->next_address++];
grpc_tcp_client_connect(on_connected, req, req->em,
(struct sockaddr *)&addr->addr, addr->len,
req->deadline);
}
static void on_resolved(void *arg, grpc_resolved_addresses *addresses) {
internal_request *req = arg;
gpr_log(GPR_DEBUG, "%s", __FUNCTION__);
if (!addresses) {
finish(req, 0);
}
req->addresses = addresses;
req->next_address = 0;
next_address(req);
}
void grpc_httpcli_get(const grpc_httpcli_request *request,
gpr_timespec deadline, grpc_em *em,
grpc_httpcli_response_cb on_response, void *user_data) {
internal_request *req = gpr_malloc(sizeof(internal_request));
memset(req, 0, sizeof(*req));
req->request_text = grpc_httpcli_format_get_request(request);
grpc_httpcli_parser_init(&req->parser);
req->on_response = on_response;
req->user_data = user_data;
req->em = em;
req->deadline = deadline;
req->use_ssl = request->use_ssl;
if (req->use_ssl) {
req->host = gpr_strdup(request->host);
}
grpc_resolve_address(request->host, req->use_ssl ? "https" : "http",
on_resolved, req);
}
void grpc_httpcli_post(const grpc_httpcli_request *request,
const char *body_bytes, size_t body_size,
gpr_timespec deadline, grpc_em *em,
grpc_httpcli_response_cb on_response, void *user_data) {
internal_request *req = gpr_malloc(sizeof(internal_request));
memset(req, 0, sizeof(*req));
req->request_text =
grpc_httpcli_format_post_request(request, body_bytes, body_size);
grpc_httpcli_parser_init(&req->parser);
req->on_response = on_response;
req->user_data = user_data;
req->em = em;
req->deadline = deadline;
req->use_ssl = request->use_ssl;
if (req->use_ssl) {
req->host = gpr_strdup(request->host);
}
grpc_resolve_address(request->host, req->use_ssl ? "https" : "http",
on_resolved, req);
}

@ -0,0 +1,104 @@
/*
*
* 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_INTERNAL_HTTPCLI_HTTPCLI_H__
#define __GRPC_INTERNAL_HTTPCLI_HTTPCLI_H__
#include <stddef.h>
#include "src/core/eventmanager/em.h"
#include <grpc/support/time.h>
/* User agent this library reports */
#define GRPC_HTTPCLI_USER_AGENT "grpc-httpcli/0.0"
/* Maximum length of a header string of the form 'Key: Value\r\n' */
#define GRPC_HTTPCLI_MAX_HEADER_LENGTH 4096
/* A single header to be passed in a request */
typedef struct grpc_httpcli_header {
char *key;
char *value;
} grpc_httpcli_header;
/* A request */
typedef struct grpc_httpcli_request {
/* The host name to connect to */
char *host;
/* The path of the resource to fetch */
char *path;
/* Additional headers: count and key/values; the following are supplied
automatically and MUST NOT be set here:
Host, Connection, User-Agent */
size_t hdr_count;
grpc_httpcli_header *hdrs;
/* whether to use ssl for the request */
int use_ssl;
} grpc_httpcli_request;
/* A response */
typedef struct grpc_httpcli_response {
/* HTTP status code */
int status;
/* Headers: count and key/values */
size_t hdr_count;
grpc_httpcli_header *hdrs;
/* Body: length and contents; contents are NOT null-terminated */
size_t body_length;
char *body;
} grpc_httpcli_response;
/* Callback for grpc_httpcli_get */
typedef void (*grpc_httpcli_response_cb)(void *user_data,
const grpc_httpcli_response *response);
/* Asynchronously perform a HTTP GET.
'request' contains request parameters - these are caller owned and can be
destroyed once the call returns
'deadline' contains a deadline for the request (or gpr_inf_future)
'em' points to a caller owned event manager that must be alive for the
lifetime of the request
'on_response' is a callback to report results to (and 'user_data' is a user
supplied pointer to pass to said call) */
void grpc_httpcli_get(const grpc_httpcli_request *request,
gpr_timespec deadline, grpc_em *em,
grpc_httpcli_response_cb on_response, void *user_data);
/* Asynchronously perform a HTTP POST.
When there is no body, pass in NULL as body_bytes.
Does not support ?var1=val1&var2=val2 in the path. */
void grpc_httpcli_post(const grpc_httpcli_request *request,
const char *body_bytes, size_t body_size,
gpr_timespec deadline, grpc_em *em,
grpc_httpcli_response_cb on_response, void *user_data);
#endif /* __GRPC_INTERNAL_HTTPCLI_HTTPCLI_H__ */

@ -0,0 +1,128 @@
/*
*
* 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/httpcli/httpcli_security_context.h"
#include <string.h>
#include "src/core/security/secure_transport_setup.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string.h>
#include "src/core/tsi/ssl_transport_security.h"
typedef struct {
grpc_channel_security_context base;
tsi_ssl_handshaker_factory *handshaker_factory;
char *secure_peer_name;
} grpc_httpcli_ssl_channel_security_context;
static void httpcli_ssl_destroy(grpc_security_context *ctx) {
grpc_httpcli_ssl_channel_security_context *c =
(grpc_httpcli_ssl_channel_security_context *)ctx;
if (c->handshaker_factory != NULL) {
tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
}
if (c->secure_peer_name != NULL) gpr_free(c->secure_peer_name);
gpr_free(ctx);
}
static grpc_security_status httpcli_ssl_create_handshaker(
grpc_security_context *ctx, tsi_handshaker **handshaker) {
grpc_httpcli_ssl_channel_security_context *c =
(grpc_httpcli_ssl_channel_security_context *)ctx;
tsi_result result = TSI_OK;
if (c->handshaker_factory == NULL) return GRPC_SECURITY_ERROR;
result = tsi_ssl_handshaker_factory_create_handshaker(
c->handshaker_factory, c->secure_peer_name, handshaker);
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
tsi_result_to_string(result));
return GRPC_SECURITY_ERROR;
}
return GRPC_SECURITY_OK;
}
static grpc_security_status httpcli_ssl_check_peer(
grpc_security_context *ctx, const tsi_peer *peer,
grpc_security_check_peer_cb cb, void *user_data) {
grpc_httpcli_ssl_channel_security_context *c =
(grpc_httpcli_ssl_channel_security_context *)ctx;
/* Check the peer name. */
if (c->secure_peer_name != NULL &&
!tsi_ssl_peer_matches_name(peer, c->secure_peer_name)) {
gpr_log(GPR_ERROR, "Peer name %s is not in peer certificate",
c->secure_peer_name);
return GRPC_SECURITY_ERROR;
}
return GRPC_SECURITY_OK;
}
static grpc_security_context_vtable httpcli_ssl_vtable = {
httpcli_ssl_destroy, httpcli_ssl_create_handshaker, httpcli_ssl_check_peer};
grpc_security_status grpc_httpcli_ssl_channel_security_context_create(
const unsigned char *pem_root_certs, size_t pem_root_certs_size,
const char *secure_peer_name, grpc_channel_security_context **ctx) {
tsi_result result = TSI_OK;
grpc_httpcli_ssl_channel_security_context *c;
if (secure_peer_name != NULL && pem_root_certs == NULL) {
gpr_log(GPR_ERROR,
"Cannot assert a secure peer name without a trust root.");
return GRPC_SECURITY_ERROR;
}
c = gpr_malloc(sizeof(grpc_httpcli_ssl_channel_security_context));
memset(c, 0, sizeof(grpc_httpcli_ssl_channel_security_context));
gpr_ref_init(&c->base.base.refcount, 1);
c->base.base.is_client_side = 1;
c->base.base.vtable = &httpcli_ssl_vtable;
if (secure_peer_name != NULL) {
c->secure_peer_name = gpr_strdup(secure_peer_name);
}
result = tsi_create_ssl_client_handshaker_factory(
NULL, 0, NULL, 0, pem_root_certs, pem_root_certs_size, NULL, NULL, NULL,
0, &c->handshaker_factory);
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
tsi_result_to_string(result));
httpcli_ssl_destroy(&c->base.base);
*ctx = NULL;
return GRPC_SECURITY_ERROR;
}
*ctx = &c->base;
return GRPC_SECURITY_OK;
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save