mirror of https://github.com/grpc/grpc.git
parent
0e905e63db
commit
b7ebd3b8c6
392 changed files with 77465 additions and 0 deletions
@ -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. |
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…
Reference in new issue