http://git-wip-us.apache.org/repos/asf/ignite/blob/ed658597/modules/platforms/cpp/thin-client/src/impl/message.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/thin-client/src/impl/message.h b/modules/platforms/cpp/thin-client/src/impl/message.h new file mode 100644 index 0000000..2f839c0 --- /dev/null +++ b/modules/platforms/cpp/thin-client/src/impl/message.h @@ -0,0 +1,820 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _IGNITE_IMPL_THIN_MESSAGE +#define _IGNITE_IMPL_THIN_MESSAGE + +#include <stdint.h> +#include <string> +#include <vector> + +#include <ignite/impl/binary/binary_writer_impl.h> +#include <ignite/impl/binary/binary_reader_impl.h> + +#include <ignite/impl/thin/writable.h> +#include <ignite/impl/thin/readable.h> + +#include "impl/connectable_node_partitions.h" +#include "impl/protocol_version.h" + +namespace ignite +{ + namespace impl + { + namespace thin + { + /* Forward declaration. */ + class Readable; + + /* Forward declaration. */ + class Writable; + + struct ClientType + { + enum Type + { + THIN_CLIENT = 2 + }; + }; + + struct RequestType + { + enum Type + { + /** Resource close. */ + RESOURCE_CLOSE = 0, + + /** Handshake. */ + HANDSHAKE = 1, + + /** Cache get. */ + CACHE_GET = 1000, + + /** Cache put. */ + CACHE_PUT = 1001, + + /** Cache put if absent. */ + CACHE_PUT_IF_ABSENT = 1002, + + /** Get all. */ + CACHE_GET_ALL = 1003, + + /** Put all. */ + CACHE_PUT_ALL = 1004, + + /** Cache get and put. */ + CACHE_GET_AND_PUT = 1005, + + /** Cache get and replace. */ + CACHE_GET_AND_REPLACE = 1006, + + /** Cache get and remove. */ + CACHE_GET_AND_REMOVE = 1007, + + /** Cache get and put if absent. */ + CACHE_GET_AND_PUT_IF_ABSENT = 1008, + + /** Cache replace. */ + CACHE_REPLACE = 1009, + + /** Cache replace if equals. */ + CACHE_REPLACE_IF_EQUALS = 1010, + + /** Cache contains key. */ + CACHE_CONTAINS_KEY = 1011, + + /** Cache contains keys. */ + CACHE_CONTAINS_KEYS = 1012, + + /** Cache clear. */ + CACHE_CLEAR = 1013, + + /** Cache clear key. */ + CACHE_CLEAR_KEY = 1014, + + /** Cache clear keys. */ + CACHE_CLEAR_KEYS = 1015, + + /** Cache remove key. */ + CACHE_REMOVE_KEY = 1016, + + /** Cache remove if equals. */ + CACHE_REMOVE_IF_EQUALS = 1017, + + /** Cache remove keys. */ + CACHE_REMOVE_KEYS = 1018, + + /** Cache remove all. */ + CACHE_REMOVE_ALL = 1019, + + /** Get size. */ + CACHE_GET_SIZE = 1020, + + /** Local peek. */ + CACHE_LOCAL_PEEK = 1021, + + /** Cache get names. */ + CACHE_GET_NAMES = 1050, + + /** Cache create with name. */ + CACHE_CREATE_WITH_NAME = 1051, + + /** Cache get or create with name. */ + CACHE_GET_OR_CREATE_WITH_NAME = 1052, + + /** Cache destroy. */ + CACHE_DESTROY = 1056, + + /** Cache nodes and partitions request. */ + CACHE_NODE_PARTITIONS = 1100, + + /** Get binary type info. */ + GET_BINARY_TYPE = 3002, + + /** Put binary type info. */ + PUT_BINARY_TYPE = 3003, + }; + }; + + /** + * Request. + * + * @tparam OpCode Operation code. + */ + template<int32_t OpCode> + class Request + { + public: + /** + * Destructor. + */ + virtual ~Request() + { + // No-op. + } + + /** + * Get operation code. + * + * @return Operation code. + */ + static int32_t GetOperationCode() + { + return OpCode; + } + + /** + * Write request using provided writer. + * @param writer Writer. + * @param ver Version. + */ + virtual void Write(binary::BinaryWriterImpl& writer, const ProtocolVersion& ver) const + { + // No-op. + } + }; + + /** + * Get or create cache request. + */ + class GetOrCreateCacheWithNameRequest : public Request<RequestType::CACHE_GET_OR_CREATE_WITH_NAME> + { + public: + /** + * Constructor. + * + * @param name Cache name. + */ + GetOrCreateCacheWithNameRequest(const std::string& name); + + /** + * Destructor. + */ + virtual ~GetOrCreateCacheWithNameRequest() + { + // No-op. + } + + /** + * Write request using provided writer. + * @param writer Writer. + * @param ver Version. + */ + virtual void Write(binary::BinaryWriterImpl& writer, const ProtocolVersion& ver) const; + + private: + /** Name. */ + std::string name; + }; + + /** + * Get or create cache request. + */ + class CreateCacheWithNameRequest : public Request<RequestType::CACHE_CREATE_WITH_NAME> + { + public: + /** + * Constructor. + * + * @param name Cache name. + */ + CreateCacheWithNameRequest(const std::string& name); + + /** + * Destructor. + */ + virtual ~CreateCacheWithNameRequest() + { + // No-op. + } + + /** + * Write request using provided writer. + * @param writer Writer. + * @param ver Version. + */ + virtual void Write(binary::BinaryWriterImpl& writer, const ProtocolVersion& ver) const; + + private: + /** Name. */ + std::string name; + }; + + /** + * Destroy cache request. + */ + class DestroyCacheRequest : public Request<RequestType::CACHE_DESTROY> + { + public: + /** + * Constructor. + * + * @param cacheId Cache ID. + */ + DestroyCacheRequest(int32_t cacheId) : + cacheId(cacheId) + { + // No-op. + } + + /** + * Destructor. + */ + virtual ~DestroyCacheRequest() + { + // No-op. + } + + /** + * Write request using provided writer. + * @param writer Writer. + * @param ver Version. + */ + virtual void Write(binary::BinaryWriterImpl& writer, const ProtocolVersion& ver) const; + + private: + /** Cache ID. */ + int32_t cacheId; + }; + + /** + * Cache request. + * + * Request to cache. + */ + template<int32_t OpCode> + class CacheRequest : public Request<OpCode> + { + public: + /** + * Constructor. + * + * @param cacheId Cache ID. + * @param binary Binary cache flag. + */ + CacheRequest(int32_t cacheId, bool binary) : + cacheId(cacheId), + binary(binary) + { + // No-op. + } + + /** + * Destructor. + */ + virtual ~CacheRequest() + { + // No-op. + } + + /** + * Write request using provided writer. + * @param writer Writer. + */ + virtual void Write(binary::BinaryWriterImpl& writer, const ProtocolVersion&) const + { + writer.WriteInt32(cacheId); + writer.WriteBool(binary); + } + + private: + /** Cache ID. */ + int32_t cacheId; + + /** Binary flag. */ + bool binary; + }; + + /** + * Cache get size request. + */ + class CacheGetSizeRequest : public CacheRequest<RequestType::CACHE_GET_SIZE> + { + public: + /** + * Constructor. + * + * @param cacheId Cache ID. + * @param binary Binary cache flag. + * @param peekModes Peek modes. + */ + CacheGetSizeRequest(int32_t cacheId, bool binary, int32_t peekModes); + + /** + * Destructor. + */ + virtual ~CacheGetSizeRequest() + { + // No-op. + } + + /** + * Write request using provided writer. + * @param writer Writer. + * @param ver Version. + */ + virtual void Write(binary::BinaryWriterImpl& writer, const ProtocolVersion& ver) const; + + private: + /** Peek modes. */ + int32_t peekModes; + }; + + /** + * Cache key request. + * + * Request to cache containing single key. + */ + template<int32_t OpCode> + class CacheKeyRequest : public CacheRequest<OpCode> + { + public: + /** + * Constructor. + * + * @param cacheId Cache ID. + * @param binary Binary cache flag. + * @param key Key. + */ + CacheKeyRequest(int32_t cacheId, bool binary, const Writable& key) : + CacheRequest<OpCode>(cacheId, binary), + key(key) + { + // No-op. + } + + /** + * Destructor. + */ + virtual ~CacheKeyRequest() + { + // No-op. + } + + /** + * Write request using provided writer. + * @param writer Writer. + * @param ver Version. + */ + virtual void Write(binary::BinaryWriterImpl& writer, const ProtocolVersion& ver) const + { + CacheRequest<OpCode>::Write(writer, ver); + + key.Write(writer); + } + + private: + /** Key. */ + const Writable& key; + }; + + /** + * Cache put request. + */ + class CachePutRequest : public CacheKeyRequest<RequestType::CACHE_PUT> + { + public: + /** + * Constructor. + * + * @param cacheId Cache ID. + * @param binary Binary cache flag. + * @param key Key. + * @param value Value. + */ + CachePutRequest(int32_t cacheId, bool binary, const Writable& key, const Writable& value); + + /** + * Destructor. + */ + virtual ~CachePutRequest() + { + // No-op. + } + + /** + * Write request using provided writer. + * @param writer Writer. + * @param ver Version. + */ + virtual void Write(binary::BinaryWriterImpl& writer, const ProtocolVersion& ver) const; + + private: + /** Value. */ + const Writable& value; + }; + + /** + * Cache get binary type request. + */ + class BinaryTypeGetRequest : public Request<RequestType::GET_BINARY_TYPE> + { + public: + /** + * Constructor. + * + * @param typeId Type ID. + */ + BinaryTypeGetRequest(int32_t typeId) : + typeId(typeId) + { + // No-op. + } + + /** + * Destructor. + */ + virtual ~BinaryTypeGetRequest() + { + // No-op. + } + + /** + * Write request using provided writer. + * @param writer Writer. + * @param ver Version. + */ + virtual void Write(binary::BinaryWriterImpl& writer, const ProtocolVersion& ver) const; + + private: + /** Cache ID. */ + int32_t typeId; + }; + + /** + * Cache put binary type request. + */ + class BinaryTypePutRequest : public Request<RequestType::PUT_BINARY_TYPE> + { + public: + /** + * Constructor. + * + * @param snapshot Type snapshot. + */ + BinaryTypePutRequest(const binary::Snap& snapshot) : + snapshot(snapshot) + { + // No-op. + } + + /** + * Destructor. + */ + virtual ~BinaryTypePutRequest() + { + // No-op. + } + + /** + * Write request using provided writer. + * @param writer Writer. + * @param ver Version. + */ + virtual void Write(binary::BinaryWriterImpl& writer, const ProtocolVersion& ver) const; + + private: + /** Cache ID. */ + const binary::Snap& snapshot; + }; + + /** + * General response. + */ + class Response + { + public: + /** + * Constructor. + */ + Response(); + + /** + * Destructor. + */ + virtual ~Response(); + + /** + * Read response using provided reader. + * @param reader Reader. + * @param ver Protocol version. + */ + void Read(binary::BinaryReaderImpl& reader, const ProtocolVersion& ver); + + /** + * Get request processing status. + * @return Status. + */ + int32_t GetStatus() const + { + return status; + } + + /** + * Get resulting error. + * @return Error. + */ + const std::string& GetError() const + { + return error; + } + + protected: + /** + * Read data if response status is ResponseStatus::SUCCESS. + */ + virtual void ReadOnSuccess(binary::BinaryReaderImpl&, const ProtocolVersion&) + { + // No-op. + } + + private: + /** Request processing status. */ + int32_t status; + + /** Error message. */ + std::string error; + }; + + /** + * Cache node list request. + */ + class ClientCacheNodePartitionsResponse : public Response + { + public: + /** + * Constructor. + * + * @param nodeParts Node partitions. + */ + ClientCacheNodePartitionsResponse(std::vector<ConnectableNodePartitions>& nodeParts); + + /** + * Destructor. + */ + virtual ~ClientCacheNodePartitionsResponse(); + + /** + * Read data if response status is ResponseStatus::SUCCESS. + * + * @param reader Reader. + */ + virtual void ReadOnSuccess(binary::BinaryReaderImpl& reader, const ProtocolVersion&); + + private: + /** Node partitions. */ + std::vector<ConnectableNodePartitions>& nodeParts; + }; + + /** + * Cache get response. + */ + class CacheGetResponse : public Response + { + public: + /** + * Constructor. + * + * @param value Value. + */ + CacheGetResponse(Readable& value); + + /** + * Destructor. + */ + virtual ~CacheGetResponse(); + + /** + * Read data if response status is ResponseStatus::SUCCESS. + * + * @param reader Reader. + */ + virtual void ReadOnSuccess(binary::BinaryReaderImpl& reader, const ProtocolVersion&); + + private: + /** Value. */ + Readable& value; + }; + + /** + * Cache put response. + */ + class BinaryTypeGetResponse : public Response + { + public: + /** + * Constructor. + * + * @param snapshot Type snapshot. + */ + BinaryTypeGetResponse(binary::SPSnap& snapshot) : + snapshot(snapshot) + { + // No-op. + } + + /** + * Destructor. + */ + virtual ~BinaryTypeGetResponse() + { + // No-op. + } + + /** + * Read data if response status is ResponseStatus::SUCCESS. + * + * @param reader Reader. + */ + virtual void ReadOnSuccess(binary::BinaryReaderImpl& reader, const ProtocolVersion&); + + private: + /** Cache ID. */ + binary::SPSnap& snapshot; + }; + + /** + * Get cache names response. + */ + class GetCacheNamesResponse : public Response + { + public: + /** + * Constructor. + * + * @param cacheNames Cache names. + */ + GetCacheNamesResponse(std::vector<std::string>& cacheNames) : + cacheNames(cacheNames) + { + // No-op. + } + + /** + * Destructor. + */ + virtual ~GetCacheNamesResponse() + { + // No-op. + } + + /** + * Read data if response status is ResponseStatus::SUCCESS. + * + * @param reader Reader. + */ + virtual void ReadOnSuccess(binary::BinaryReaderImpl& reader, const ProtocolVersion&); + + private: + /** Cache ID. */ + std::vector<std::string>& cacheNames; + }; + + /** + * Get cache names response. + */ + class BoolResponse : public Response + { + public: + /** + * Constructor. + */ + BoolResponse() : + value(false) + { + // No-op. + } + + /** + * Destructor. + */ + virtual ~BoolResponse() + { + // No-op. + } + + /** + * Get received value. + * + * @return Received bool value. + */ + bool GetValue() const + { + return value; + } + + /** + * Read data if response status is ResponseStatus::SUCCESS. + * + * @param reader Reader. + */ + virtual void ReadOnSuccess(binary::BinaryReaderImpl& reader, const ProtocolVersion&); + + private: + /** Value. */ + bool value; + }; + + /** + * Get cache names response. + */ + class Int64Response : public Response + { + public: + /** + * Constructor. + */ + Int64Response() : + value(0) + { + // No-op. + } + + /** + * Destructor. + */ + virtual ~Int64Response() + { + // No-op. + } + + /** + * Get received value. + * + * @return Received bool value. + */ + int64_t GetValue() const + { + return value; + } + + /** + * Read data if response status is ResponseStatus::SUCCESS. + * + * @param reader Reader. + */ + virtual void ReadOnSuccess(binary::BinaryReaderImpl& reader, const ProtocolVersion&); + + private: + /** Value. */ + int64_t value; + }; + } + } +} + +#endif //_IGNITE_IMPL_THIN_MESSAGE
http://git-wip-us.apache.org/repos/asf/ignite/blob/ed658597/modules/platforms/cpp/thin-client/src/impl/net/end_point.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/thin-client/src/impl/net/end_point.h b/modules/platforms/cpp/thin-client/src/impl/net/end_point.h new file mode 100644 index 0000000..a7dbf18 --- /dev/null +++ b/modules/platforms/cpp/thin-client/src/impl/net/end_point.h @@ -0,0 +1,161 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _IGNITE_IMPL_THIN_NET_END_POINT +#define _IGNITE_IMPL_THIN_NET_END_POINT + +#include <stdint.h> +#include <string> + +namespace ignite +{ + namespace impl + { + namespace thin + { + namespace net + { + /** + * Connection end point structure. + */ + struct EndPoint + { + /** + * Default constructor. + */ + EndPoint() : + port(0) + { + // No-op. + } + + /** + * Constructor. + * + * @param host Host. + * @param port Port. + */ + EndPoint(const std::string& host, uint16_t port) : + host(host), + port(port) + { + // No-op. + } + + /** + * Compare to another instance. + * + * @param other Another instance. + * @return Negative value if less, positive if larger and + * zero, if equals another instance. + */ + int Compare(const EndPoint& other) const + { + if (port < other.port) + return -1; + + if (port > other.port) + return 1; + + return host.compare(other.host); + } + + /** + * Comparison operator. + * + * @param val1 First value. + * @param val2 Second value. + * @return True if equal. + */ + friend bool operator==(const EndPoint& val1, const EndPoint& val2) + { + return val1.port == val2.port && val1.host == val2.host; + } + + + /** + * Comparison operator. + * + * @param val1 First value. + * @param val2 Second value. + * @return True if not equal. + */ + friend bool operator!=(const EndPoint& val1, const EndPoint& val2) + { + return !(val1 == val2); + } + + /** + * Comparison operator. + * + * @param val1 First value. + * @param val2 Second value. + * @return True if less. + */ + friend bool operator<(const EndPoint& val1, const EndPoint& val2) + { + return val1.Compare(val2) < 0; + } + + /** + * Comparison operator. + * + * @param val1 First value. + * @param val2 Second value. + * @return True if less or equal. + */ + friend bool operator<=(const EndPoint& val1, const EndPoint& val2) + { + return val1.Compare(val2) <= 0; + } + + /** + * Comparison operator. + * + * @param val1 First value. + * @param val2 Second value. + * @return True if gretter. + */ + friend bool operator>(const EndPoint& val1, const EndPoint& val2) + { + return val1.Compare(val2) > 0; + } + + /** + * Comparison operator. + * + * @param val1 First value. + * @param val2 Second value. + * @return True if gretter or equal. + */ + friend bool operator>=(const EndPoint& val1, const EndPoint& val2) + { + return val1.Compare(val2) >= 0; + } + + /** Remote host. */ + std::string host; + + /** TCP port. */ + uint16_t port; + }; + } + } + } +} + +#endif //_IGNITE_IMPL_THIN_NET_END_POINT \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/ed658597/modules/platforms/cpp/thin-client/src/impl/net/net_utils.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/thin-client/src/impl/net/net_utils.h b/modules/platforms/cpp/thin-client/src/impl/net/net_utils.h new file mode 100644 index 0000000..73ee6e3 --- /dev/null +++ b/modules/platforms/cpp/thin-client/src/impl/net/net_utils.h @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _IGNITE_IMPL_THIN_NET_NET_UTILS +#define _IGNITE_IMPL_THIN_NET_NET_UTILS + +#include <set> +#include <string> + +namespace ignite +{ + namespace impl + { + namespace thin + { + namespace net + { + namespace net_utils + { + /** + * Get set of local addresses. + * + * @param addrs Addresses set. + */ + void GetLocalAddresses(std::set<std::string>& addrs); + } + } + } + } +} + +#endif //_IGNITE_IMPL_THIN_NET_NET_UTILS \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/ed658597/modules/platforms/cpp/thin-client/src/impl/net/remote_type_updater.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/thin-client/src/impl/net/remote_type_updater.cpp b/modules/platforms/cpp/thin-client/src/impl/net/remote_type_updater.cpp new file mode 100644 index 0000000..9d05ae6 --- /dev/null +++ b/modules/platforms/cpp/thin-client/src/impl/net/remote_type_updater.cpp @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "impl/data_router.h" + +#include "impl/message.h" +#include "impl/net/remote_type_updater.h" + +namespace ignite +{ + namespace impl + { + namespace thin + { + namespace net + { + RemoteTypeUpdater::RemoteTypeUpdater(DataRouter& router): + router(router) + { + // No-op. + } + + RemoteTypeUpdater::~RemoteTypeUpdater() + { + // No-op. + } + + bool RemoteTypeUpdater::Update(const binary::Snap& snapshot, IgniteError& err) + { + BinaryTypePutRequest req(snapshot); + Response rsp; + + try + { + router.SyncMessageNoMetaUpdate(req, rsp); + } + catch(const IgniteError& e) + { + err = e; + + return false; + } + + return true; + } + + binary::SPSnap RemoteTypeUpdater::GetMeta(int32_t typeId, IgniteError& err) + { + binary::SPSnap snap; + + BinaryTypeGetRequest req(typeId); + BinaryTypeGetResponse rsp(snap); + + try + { + router.SyncMessageNoMetaUpdate(req, rsp); + } + catch(const IgniteError& e) + { + err = e; + + return binary::SPSnap(); + } + + return snap; + } + } + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/ed658597/modules/platforms/cpp/thin-client/src/impl/net/remote_type_updater.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/thin-client/src/impl/net/remote_type_updater.h b/modules/platforms/cpp/thin-client/src/impl/net/remote_type_updater.h new file mode 100644 index 0000000..51872ba --- /dev/null +++ b/modules/platforms/cpp/thin-client/src/impl/net/remote_type_updater.h @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _IGNITE_IMPL_THIN_REMOTE_TYPE_UPDATER +#define _IGNITE_IMPL_THIN_REMOTE_TYPE_UPDATER + +#include <ignite/ignite_error.h> +#include <ignite/impl/binary/binary_type_snapshot.h> +#include <ignite/impl/binary/binary_type_updater.h> + +namespace ignite +{ + namespace impl + { + namespace thin + { + /* Forward declaration. */ + class DataRouter; + + namespace net + { + /** + * Remote type updater. + */ + class RemoteTypeUpdater : public binary::BinaryTypeUpdater + { + public: + /** + * Constructor. + * + * @param router Data router. + */ + RemoteTypeUpdater(DataRouter& router); + + /** + * Destructor. + */ + virtual ~RemoteTypeUpdater(); + + /** + * Update type using provided snapshot. + * + * @param snapshot Snapshot. + * @param err Error. + * @return True on success. + */ + virtual bool Update(const binary::Snap& snapshot, IgniteError& err); + + /** + * Get schema for type. + * + * @param typeId Type ID. + * @param err Error. + * @return Result. + */ + virtual binary::SPSnap GetMeta(int32_t typeId, IgniteError& err); + + private: + /** Data router. */ + DataRouter& router; + }; + } + } + } +} + +#endif //_IGNITE_IMPL_THIN_REMOTE_TYPE_UPDATER \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/ed658597/modules/platforms/cpp/thin-client/src/impl/net/tcp_range.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/thin-client/src/impl/net/tcp_range.h b/modules/platforms/cpp/thin-client/src/impl/net/tcp_range.h new file mode 100644 index 0000000..18c162f --- /dev/null +++ b/modules/platforms/cpp/thin-client/src/impl/net/tcp_range.h @@ -0,0 +1,177 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _IGNITE_IMPL_THIN_NET_TCP_RANGE +#define _IGNITE_IMPL_THIN_NET_TCP_RANGE + +#include <stdint.h> +#include <string> + +namespace ignite +{ + namespace impl + { + namespace thin + { + namespace net + { + /** + * TCP port range. + */ + struct TcpRange + { + /** + * Default constructor. + */ + TcpRange() : + port(0), + range(0) + { + // No-op. + } + + /** + * Constructor. + * + * @param host Host. + * @param port Port. + * @param range Number of ports after the @c port that + * should be tried if the previous are unavailable. + */ + TcpRange(const std::string& host, uint16_t port, uint16_t range = 0) : + host(host), + port(port), + range(range) + { + // No-op. + } + + /** + * Compare to another instance. + * + * @param other Another instance. + * @return Negative value if less, positive if larger and + * zero, if equals another instance. + */ + int Compare(const TcpRange& other) const + { + if (port < other.port) + return -1; + + if (port > other.port) + return 1; + + if (range < other.range) + return -1; + + if (range > other.range) + return 1; + + return host.compare(other.host); + } + + /** + * Comparison operator. + * + * @param val1 First value. + * @param val2 Second value. + * @return True if equal. + */ + friend bool operator==(const TcpRange& val1, const TcpRange& val2) + { + return val1.port == val2.port && val1.range == val2.range && val1.host == val2.host; + } + + + /** + * Comparison operator. + * + * @param val1 First value. + * @param val2 Second value. + * @return True if not equal. + */ + friend bool operator!=(const TcpRange& val1, const TcpRange& val2) + { + return !(val1 == val2); + } + + /** + * Comparison operator. + * + * @param val1 First value. + * @param val2 Second value. + * @return True if less. + */ + friend bool operator<(const TcpRange& val1, const TcpRange& val2) + { + return val1.Compare(val2) < 0; + } + + /** + * Comparison operator. + * + * @param val1 First value. + * @param val2 Second value. + * @return True if less or equal. + */ + friend bool operator<=(const TcpRange& val1, const TcpRange& val2) + { + return val1.Compare(val2) <= 0; + } + + /** + * Comparison operator. + * + * @param val1 First value. + * @param val2 Second value. + * @return True if gretter. + */ + friend bool operator>(const TcpRange& val1, const TcpRange& val2) + { + return val1.Compare(val2) > 0; + } + + /** + * Comparison operator. + * + * @param val1 First value. + * @param val2 Second value. + * @return True if gretter or equal. + */ + friend bool operator>=(const TcpRange& val1, const TcpRange& val2) + { + return val1.Compare(val2) >= 0; + } + + /** Remote host. */ + std::string host; + + /** TCP port. */ + uint16_t port; + + /** + * Number of ports after the port that should be tried if + * the previous are unavailable. + */ + uint16_t range; + }; + } + } + } +} + +#endif //_IGNITE_IMPL_THIN_NET_TCP_RANGE \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/ed658597/modules/platforms/cpp/thin-client/src/impl/net/tcp_socket_client.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/thin-client/src/impl/net/tcp_socket_client.h b/modules/platforms/cpp/thin-client/src/impl/net/tcp_socket_client.h new file mode 100644 index 0000000..dc9263f --- /dev/null +++ b/modules/platforms/cpp/thin-client/src/impl/net/tcp_socket_client.h @@ -0,0 +1,157 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _IGNITE_IMPL_THIN_NET_TCP_SOCKET_CLIENT +#define _IGNITE_IMPL_THIN_NET_TCP_SOCKET_CLIENT + +#include <stdint.h> + +#include <ignite/common/common.h> + +#include "impl/socket_client.h" + +namespace ignite +{ + namespace impl + { + namespace thin + { + namespace net + { + /** + * Socket client implementation. + */ + class TcpSocketClient : public SocketClient + { + public: + /** Buffers size */ + enum { BUFFER_SIZE = 0x10000 }; + + /** The time in seconds the connection needs to remain idle before starts sending keepalive probes. */ + enum { KEEP_ALIVE_IDLE_TIME = 60 }; + + /** The time in seconds between individual keepalive probes. */ + enum { KEEP_ALIVE_PROBES_PERIOD = 1 }; + + /** + * Constructor. + */ + TcpSocketClient(); + + /** + * Destructor. + */ + virtual ~TcpSocketClient(); + + /** + * Establish connection with remote TCP service. + * + * @param hostname Remote host name. + * @param port TCP service port. + * @param timeout Timeout. + * @return True on success. + */ + virtual bool Connect(const char* hostname, uint16_t port, int32_t timeout); + + /** + * Close established connection. + */ + virtual void Close(); + + /** + * Send data by established connection. + * + * @param data Pointer to data to be sent. + * @param size Size of the data in bytes. + * @param timeout Timeout. + * @return Number of bytes that have been sent on success, + * WaitResult::TIMEOUT on timeout and -errno on failure. + */ + virtual int Send(const int8_t* data, size_t size, int32_t timeout); + + /** + * Receive data from established connection. + * + * @param buffer Pointer to data buffer. + * @param size Size of the buffer in bytes. + * @param timeout Timeout. + * @return Number of bytes that have been received on success, + * WaitResult::TIMEOUT on timeout and -errno on failure. + */ + virtual int Receive(int8_t* buffer, size_t size, int32_t timeout); + + /** + * Check if the socket is blocking or not. + * @return @c true if the socket is blocking and false otherwise. + */ + virtual bool IsBlocking() const; + + /** + * Get socket error. + * @return Last socket error. + */ + static int GetLastSocketError(); + + /** + * Get socket error. + * @param handle Socket handle. + * @return Last socket error. + */ + static int GetLastSocketError(int handle); + + /** + * Check whether socket operation was interupted. + * @return @c true if the socket operation was interupted. + */ + static bool IsSocketOperationInterrupted(int errorCode); + private: + /** + * Close established connection. + */ + void InternalClose(); + + /** + * Tries set socket options. + */ + void TrySetOptions(); + + /** + * Wait on the socket for any event for specified time. + * This function uses poll to achive timeout functionality + * for every separate socket operation. + * + * @param timeout Timeout. + * @param rd Wait for read if @c true, or for write if @c false. + * @return -errno on error, WaitResult::TIMEOUT on timeout and + * WaitResult::SUCCESS on success. + */ + int WaitOnSocket(int32_t timeout, bool rd); + + /** Handle. */ + intptr_t socketHandle; + + /** Blocking flag. */ + bool blocking; + + IGNITE_NO_COPY_ASSIGNMENT(TcpSocketClient) + }; + } + } + } +} + +#endif //_IGNITE_IMPL_THIN_NET_TCP_SOCKET_CLIENT \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/ed658597/modules/platforms/cpp/thin-client/src/impl/protocol_version.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/thin-client/src/impl/protocol_version.cpp b/modules/platforms/cpp/thin-client/src/impl/protocol_version.cpp new file mode 100644 index 0000000..fbcf3dd --- /dev/null +++ b/modules/platforms/cpp/thin-client/src/impl/protocol_version.cpp @@ -0,0 +1,151 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <sstream> + +#include <ignite/ignite_error.h> + +#include "impl/protocol_version.h" + +namespace ignite +{ + namespace impl + { + namespace thin + { + ProtocolVersion::ProtocolVersion(int16_t vmajor, int16_t vminor, int16_t vmaintenance) : + vmajor(vmajor), + vminor(vminor), + vmaintenance(vmaintenance) + { + // No-op. + } + + ProtocolVersion::ProtocolVersion() : + vmajor(0), + vminor(0), + vmaintenance(0) + { + // No-op. + } + + void ThrowParseError() + { + throw IgniteError(IgniteError::IGNITE_ERR_GENERIC, + "Invalid version format. Valid format is X.Y.Z, where X, Y and Z are major, " + "minor and maintenance version parts of Ignite since which protocol is introduced."); + } + + ProtocolVersion ProtocolVersion::FromString(const std::string& version) + { + ProtocolVersion res; + + std::stringstream buf(version); + + buf >> res.vmajor; + + if (!buf.good()) + ThrowParseError(); + + if (buf.get() != '.' || !buf.good()) + ThrowParseError(); + + buf >> res.vminor; + + if (!buf.good()) + ThrowParseError(); + + if (buf.get() != '.' || !buf.good()) + ThrowParseError(); + + buf >> res.vmaintenance; + + if (buf.bad()) + ThrowParseError(); + + return res; + } + + std::string ProtocolVersion::ToString() const + { + std::stringstream buf; + buf << vmajor << '.' << vminor << '.' << vmaintenance; + + return buf.str(); + } + + int16_t ProtocolVersion::GetMajor() const + { + return vmajor; + } + + int16_t ProtocolVersion::GetMinor() const + { + return vminor; + } + + int16_t ProtocolVersion::GetMaintenance() const + { + return vmaintenance; + } + + int32_t ProtocolVersion::Compare(const ProtocolVersion& other) const + { + int32_t res = vmajor - other.vmajor; + + if (res == 0) + res = vminor - other.vminor; + + if (res == 0) + res = vmaintenance - other.vmaintenance; + + return res; + } + + bool operator==(const ProtocolVersion& val1, const ProtocolVersion& val2) + { + return val1.Compare(val2) == 0; + } + + bool operator!=(const ProtocolVersion& val1, const ProtocolVersion& val2) + { + return val1.Compare(val2) != 0; + } + + bool operator<(const ProtocolVersion& val1, const ProtocolVersion& val2) + { + return val1.Compare(val2) < 0; + } + + bool operator<=(const ProtocolVersion& val1, const ProtocolVersion& val2) + { + return val1.Compare(val2) <= 0; + } + + bool operator>(const ProtocolVersion& val1, const ProtocolVersion& val2) + { + return val1.Compare(val2) > 0; + } + + bool operator>=(const ProtocolVersion& val1, const ProtocolVersion& val2) + { + return val1.Compare(val2) >= 0; + } + } + } +} + http://git-wip-us.apache.org/repos/asf/ignite/blob/ed658597/modules/platforms/cpp/thin-client/src/impl/protocol_version.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/thin-client/src/impl/protocol_version.h b/modules/platforms/cpp/thin-client/src/impl/protocol_version.h new file mode 100644 index 0000000..870406d --- /dev/null +++ b/modules/platforms/cpp/thin-client/src/impl/protocol_version.h @@ -0,0 +1,163 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _IGNITE_IMPL_THIN_PROTOCOL_VERSION +#define _IGNITE_IMPL_THIN_PROTOCOL_VERSION + +#include <stdint.h> + +#include <string> +#include <set> + +namespace ignite +{ + namespace impl + { + namespace thin + { + /** Protocol version. */ + class ProtocolVersion + { + public: + /** + * Parse string and extract protocol version. + * + * @throw IgniteException if version can not be parsed. + * @param version Version string to parse. + * @return Protocol version. + */ + static ProtocolVersion FromString(const std::string& version); + + /** + * Convert to string value. + * + * @return Protocol version. + */ + std::string ToString() const; + + /** + * Default constructor. + */ + ProtocolVersion(); + + /** + * Constructor. + * + * @param vmajor Major version part. + * @param vminor Minor version part. + * @param vmaintenance Maintenance version part. + */ + ProtocolVersion(int16_t vmajor, int16_t vminor, int16_t vmaintenance); + + /** + * Get major part. + * + * @return Major part. + */ + int16_t GetMajor() const; + + /** + * Get minor part. + * + * @return Minor part. + */ + int16_t GetMinor() const; + + /** + * Get maintenance part. + * + * @return Maintenance part. + */ + int16_t GetMaintenance() const; + + /** + * Compare to another value. + * + * @param other Instance to compare to. + * @return Zero if equeals, negative number if less and positive if more. + */ + int32_t Compare(const ProtocolVersion& other) const; + + /** + * Comparison operator. + * + * @param val1 First value. + * @param val2 Second value. + * @return True if equal. + */ + friend bool operator==(const ProtocolVersion& val1, const ProtocolVersion& val2); + + /** + * Comparison operator. + * + * @param val1 First value. + * @param val2 Second value. + * @return True if not equal. + */ + friend bool operator!=(const ProtocolVersion& val1, const ProtocolVersion& val2); + + /** + * Comparison operator. + * + * @param val1 First value. + * @param val2 Second value. + * @return True if less. + */ + friend bool operator<(const ProtocolVersion& val1, const ProtocolVersion& val2); + + /** + * Comparison operator. + * + * @param val1 First value. + * @param val2 Second value. + * @return True if less or equal. + */ + friend bool operator<=(const ProtocolVersion& val1, const ProtocolVersion& val2); + + /** + * Comparison operator. + * + * @param val1 First value. + * @param val2 Second value. + * @return True if gretter. + */ + friend bool operator>(const ProtocolVersion& val1, const ProtocolVersion& val2); + + /** + * Comparison operator. + * + * @param val1 First value. + * @param val2 Second value. + * @return True if gretter or equal. + */ + friend bool operator>=(const ProtocolVersion& val1, const ProtocolVersion& val2); + + private: + /** Major part. */ + int16_t vmajor; + + /** Minor part. */ + int16_t vminor; + + /** Maintenance part. */ + int16_t vmaintenance; + }; + } + } +} + +#endif //_IGNITE_IMPL_THIN_PROTOCOL_VERSION \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/ed658597/modules/platforms/cpp/thin-client/src/impl/response_status.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/thin-client/src/impl/response_status.h b/modules/platforms/cpp/thin-client/src/impl/response_status.h new file mode 100644 index 0000000..ddc81d0 --- /dev/null +++ b/modules/platforms/cpp/thin-client/src/impl/response_status.h @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _IGNITE_IMPL_THIN_RESPONSE_STATUS +#define _IGNITE_IMPL_THIN_RESPONSE_STATUS + +namespace ignite +{ + namespace impl + { + namespace thin + { + struct ResponseStatus + { + enum Type + { + /** Operation completed successfully. */ + SUCCESS = 0, + + /** Command failed. */ + FAILED = 1, + + /** Invalid op code. */ + INVALID_OP_CODE = 2, + + /** Cache does not exist. */ + CACHE_DOES_NOT_EXIST = 1000, + + /** Cache already exists. */ + CACHE_EXISTS = 1001, + + /** Too many cursors. */ + TOO_MANY_CURSORS = 1010, + + /** Resource does not exist. */ + RESOURCE_DOES_NOT_EXIST = 1011, + + /** Authorization failure. */ + SECURITY_VIOLATION = 1012, + + /** Authentication failed. */ + AUTH_FAILED = 2000, + }; + }; + } + } +} + +#endif //_IGNITE_IMPL_THIN_RESPONSE_STATUS \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/ed658597/modules/platforms/cpp/thin-client/src/impl/socket_client.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/thin-client/src/impl/socket_client.h b/modules/platforms/cpp/thin-client/src/impl/socket_client.h new file mode 100644 index 0000000..c94146d --- /dev/null +++ b/modules/platforms/cpp/thin-client/src/impl/socket_client.h @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _IGNITE_IMPL_THIN_SOCKET_CLIENT +#define _IGNITE_IMPL_THIN_SOCKET_CLIENT + +#include <stdint.h> + +namespace ignite +{ + namespace impl + { + namespace thin + { + /** + * Socket client implementation. + */ + class SocketClient + { + public: + /** + * Non-negative timeout operation result. + */ + struct WaitResult + { + enum T + { + /** Timeout. */ + TIMEOUT = 0, + + /** Success. */ + SUCCESS = 1 + }; + }; + + /** + * Destructor. + */ + virtual ~SocketClient() + { + // No-op. + } + + /** + * Establish connection with remote service. + * + * @param hostname Remote host name. + * @param port Service port. + * @param timeout Timeout. + * @return True on success. + */ + virtual bool Connect(const char* hostname, uint16_t port, int32_t timeout) = 0; + + /** + * Close established connection. + */ + virtual void Close() = 0; + + /** + * Send data by established connection. + * + * @param data Pointer to data to be sent. + * @param size Size of the data in bytes. + * @param timeout Timeout. + * @return Number of bytes that have been sent on success, + * WaitResult::TIMEOUT on timeout and -errno on failure. + */ + virtual int Send(const int8_t* data, size_t size, int32_t timeout) = 0; + + /** + * Receive data from established connection. + * + * @param buffer Pointer to data buffer. + * @param size Size of the buffer in bytes. + * @param timeout Timeout. + * @return Number of bytes that have been received on success, + * WaitResult::TIMEOUT on timeout and -errno on failure. + */ + virtual int Receive(int8_t* buffer, size_t size, int32_t timeout) = 0; + + /** + * Check if the socket is blocking or not. + * @return @c true if the socket is blocking and false otherwise. + */ + virtual bool IsBlocking() const = 0; + }; + } + } +} + +#endif //_IGNITE_IMPL_THIN_SOCKET_CLIENT \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/ed658597/modules/platforms/cpp/thin-client/src/impl/ssl/secure_socket_client.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/thin-client/src/impl/ssl/secure_socket_client.cpp b/modules/platforms/cpp/thin-client/src/impl/ssl/secure_socket_client.cpp new file mode 100644 index 0000000..e7e60b6 --- /dev/null +++ b/modules/platforms/cpp/thin-client/src/impl/ssl/secure_socket_client.cpp @@ -0,0 +1,445 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <sstream> +#include <cassert> + +#include <ignite/common/utils.h> +#include <ignite/common/concurrent.h> +#include <ignite/ignite_error.h> + +#include "impl/net/tcp_socket_client.h" +#include "impl/ssl/secure_socket_client.h" +#include "impl/ssl/ssl_bindings.h" + +#ifndef SOCKET_ERROR +# define SOCKET_ERROR (-1) +#endif // SOCKET_ERROR + +namespace ignite +{ + namespace impl + { + namespace thin + { + namespace ssl + { + SecureSocketClient::SecureSocketClient(const std::string& certPath, const std::string& keyPath, + const std::string& caPath): + certPath(certPath), + keyPath(keyPath), + caPath(caPath), + context(0), + ssl(0), + blocking(true) + { + // No-op. + } + + SecureSocketClient::~SecureSocketClient() + { + CloseInteral(); + + if (context) + ssl::SSL_CTX_free(reinterpret_cast<SSL_CTX*>(context)); + } + + bool SecureSocketClient::Connect(const char* hostname, uint16_t port, int32_t timeout) + { + assert(SslGateway::GetInstance().Loaded()); + + if (!context) + { + context = MakeContext(certPath, keyPath, caPath); + + if (!context) + { + throw IgniteError(IgniteError::IGNITE_ERR_GENERIC, + "Can not create SSL context. Aborting connect."); + } + } + + SSL* ssl0 = reinterpret_cast<SSL*>(MakeSsl(context, hostname, port, blocking)); + if (!ssl0) + return false; + + int res = ssl::SSL_set_tlsext_host_name_(ssl0, hostname); + if (res != OPERATION_SUCCESS) + { + ssl::SSL_free_(ssl0); + + std::string err = "Can not set host name for secure connection: " + GetSslError(ssl0, res); + + throw IgniteError(IgniteError::IGNITE_ERR_GENERIC, err.c_str()); + } + + ssl::SSL_set_connect_state_(ssl0); + + bool connected = CompleteConnectInternal(ssl0, timeout); + + if (!connected) + { + ssl::SSL_free_(ssl0); + + return false; + } + + // Verify a server certificate was presented during the negotiation + X509* cert = ssl::SSL_get_peer_certificate(ssl0); + if (cert) + ssl::X509_free(cert); + else + { + ssl::SSL_free_(ssl0); + +// std::string err = "Remote host did not provide certificate: " + GetSslError(ssl0, res); + + return false; + } + + // Verify the result of chain verification + // Verification performed according to RFC 4158 + res = ssl::SSL_get_verify_result(ssl0); + if (X509_V_OK != res) + { + ssl::SSL_free_(ssl0); + +// std::string err = "Certificate chain verification failed: " + GetSslError(ssl0, res); + + return false; + } + + ssl = reinterpret_cast<void*>(ssl0); + + return true; + } + + void SecureSocketClient::Close() + { + CloseInteral(); + } + + int SecureSocketClient::Send(const int8_t* data, size_t size, int32_t timeout) + { + assert(SslGateway::GetInstance().Loaded()); + + if (!ssl) + { + throw IgniteError(IgniteError::IGNITE_ERR_GENERIC, + "Trying to send data using closed connection"); + } + + SSL* ssl0 = reinterpret_cast<SSL*>(ssl); + + int res = ssl::SSL_write_(ssl0, data, static_cast<int>(size)); + + return res; + } + + int SecureSocketClient::Receive(int8_t* buffer, size_t size, int32_t timeout) + { + assert(SslGateway::GetInstance().Loaded()); + + if (!ssl) + { + throw IgniteError(IgniteError::IGNITE_ERR_GENERIC, + "Trying to receive data using closed connection"); + } + + SSL* ssl0 = reinterpret_cast<SSL*>(ssl); + + int res = 0; + + if (!blocking && ssl::SSL_pending_(ssl0) == 0) + { + res = WaitOnSocket(ssl, timeout, true); + + if (res < 0 || res == WaitResult::TIMEOUT) + return res; + } + + res = ssl::SSL_read_(ssl0, buffer, static_cast<int>(size)); + + return res; + } + + bool SecureSocketClient::IsBlocking() const + { + return blocking; + } + + void* SecureSocketClient::MakeContext(const std::string& certPath, const std::string& keyPath, + const std::string& caPath) + { + assert(SslGateway::GetInstance().Loaded()); + + static bool sslLibInited = false; + static common::concurrent::CriticalSection sslCs; + + if (!sslLibInited) + { + common::concurrent::CsLockGuard lock(sslCs); + + if (!sslLibInited) + { + (void)SSL_library_init(); + + SSL_load_error_strings(); + + OPENSSL_config(0); + + sslLibInited = true; + } + } + + const SSL_METHOD* method = ssl::SSLv23_client_method_(); + if (!method) + throw IgniteError(IgniteError::IGNITE_ERR_GENERIC, "Can not get SSL method"); + + SSL_CTX* ctx = ssl::SSL_CTX_new(method); + if (!ctx) + throw IgniteError(IgniteError::IGNITE_ERR_GENERIC, "Can not create new SSL context"); + + ssl::SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, 0); + + ssl::SSL_CTX_set_verify_depth(ctx, 8); + + const long flags = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION; + ssl::SSL_CTX_ctrl(ctx, SSL_CTRL_OPTIONS, flags, NULL); + + const char* cCaPath = caPath.empty() ? 0 : caPath.c_str(); + + long res = ssl::SSL_CTX_load_verify_locations(ctx, cCaPath, 0); + if (res != OPERATION_SUCCESS) + { + ssl::SSL_CTX_free(ctx); + + throw IgniteError(IgniteError::IGNITE_ERR_GENERIC, + "Can not set Certificate Authority path for secure connection"); + } + + res = ssl::SSL_CTX_use_certificate_chain_file(ctx, certPath.c_str()); + if (res != OPERATION_SUCCESS) + { + ssl::SSL_CTX_free(ctx); + + throw IgniteError(IgniteError::IGNITE_ERR_GENERIC, + "Can not set client certificate file for secure connection"); + } + + res = ssl::SSL_CTX_use_RSAPrivateKey_file(ctx, keyPath.c_str(), SSL_FILETYPE_PEM); + if (res != OPERATION_SUCCESS) + { + ssl::SSL_CTX_free(ctx); + + throw IgniteError(IgniteError::IGNITE_ERR_GENERIC, + "Can not set private key file for secure connection"); + } + + const char* const PREFERRED_CIPHERS = "HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4"; + res = ssl::SSL_CTX_set_cipher_list(ctx, PREFERRED_CIPHERS); + if (res != OPERATION_SUCCESS) + { + ssl::SSL_CTX_free(ctx); + + throw IgniteError(IgniteError::IGNITE_ERR_GENERIC, + "Can not set ciphers list for secure connection"); + } + + return ctx; + } + + void* SecureSocketClient::MakeSsl(void* context, const char* hostname, uint16_t port, bool& blocking) + { + BIO* bio = ssl::BIO_new_ssl_connect(reinterpret_cast<SSL_CTX*>(context)); + if (!bio) + throw IgniteError(IgniteError::IGNITE_ERR_GENERIC, "Can not create SSL connection."); + + blocking = ssl::BIO_set_nbio_(bio, 1) != OPERATION_SUCCESS; + + std::stringstream stream; + stream << hostname << ":" << port; + + std::string address = stream.str(); + + long res = ssl::BIO_set_conn_hostname_(bio, address.c_str()); + if (res != OPERATION_SUCCESS) + { + ssl::BIO_free_all(bio); + + throw IgniteError(IgniteError::IGNITE_ERR_GENERIC, "Can not set SSL connection hostname."); + } + + SSL* ssl = 0; + ssl::BIO_get_ssl_(bio, &ssl); + if (!ssl) + { + ssl::BIO_free_all(bio); + + throw IgniteError(IgniteError::IGNITE_ERR_GENERIC, "Can not get SSL instance from BIO."); + } + + return ssl; + } + + bool SecureSocketClient::CompleteConnectInternal(void* ssl, int timeout) + { + SSL* ssl0 = reinterpret_cast<SSL*>(ssl); + + while (true) + { + int res = ssl::SSL_connect_(ssl0); + + if (res == OPERATION_SUCCESS) + return true; + + int sslError = ssl::SSL_get_error_(ssl0, res); + + if (IsActualError(sslError)) + return false; + + int want = ssl::SSL_want_(ssl0); + + res = WaitOnSocket(ssl, timeout, want == SSL_READING); + + if (res == WaitResult::TIMEOUT) + return false; + + if (res != WaitResult::SUCCESS) + return false; + } + } + + std::string SecureSocketClient::GetSslError(void* ssl, int ret) + { + SSL* ssl0 = reinterpret_cast<SSL*>(ssl); + + int sslError = ssl::SSL_get_error_(ssl0, ret); + + switch (sslError) + { + case SSL_ERROR_NONE: + break; + + case SSL_ERROR_WANT_WRITE: + return std::string("SSL_connect wants write"); + + case SSL_ERROR_WANT_READ: + return std::string("SSL_connect wants read"); + + default: + return std::string("SSL error: ") + common::LexicalCast<std::string>(sslError); + } + + long error = ssl::ERR_get_error_(); + + char errBuf[1024] = { 0 }; + + ssl::ERR_error_string_n_(error, errBuf, sizeof(errBuf)); + + return std::string(errBuf); + } + + bool SecureSocketClient::IsActualError(int err) + { + switch (err) + { + case SSL_ERROR_NONE: + case SSL_ERROR_WANT_WRITE: + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_CONNECT: + case SSL_ERROR_WANT_ACCEPT: + case SSL_ERROR_WANT_X509_LOOKUP: + return false; + + default: + return true; + } + } + + void SecureSocketClient::CloseInteral() + { + assert(SslGateway::GetInstance().Loaded()); + + if (ssl) + { + ssl::SSL_free_(reinterpret_cast<SSL*>(ssl)); + + ssl = 0; + } + } + + int SecureSocketClient::WaitOnSocket(void* ssl, int32_t timeout, bool rd) + { + int ready = 0; + int lastError = 0; + SSL* ssl0 = reinterpret_cast<SSL*>(ssl); + + fd_set fds; + + int fd = ssl::SSL_get_fd_(ssl0); + + if (fd < 0) + { + std::stringstream ss; + + ss << "Can not get file descriptor from the SSL socket: " << fd << ", " << GetSslError(ssl, fd); + + std::string err = ss.str(); + + throw IgniteError(IgniteError::IGNITE_ERR_GENERIC, err.c_str()); + } + + do { + struct timeval tv = { 0 }; + tv.tv_sec = timeout; + + FD_ZERO(&fds); + FD_SET(static_cast<long>(fd), &fds); + + fd_set* readFds = 0; + fd_set* writeFds = 0; + + if (rd) + readFds = &fds; + else + writeFds = &fds; + + ready = select(fd + 1, readFds, writeFds, NULL, (timeout == 0 ? NULL : &tv)); + + if (ready == SOCKET_ERROR) + lastError = net::TcpSocketClient::GetLastSocketError(); + + } while (ready == SOCKET_ERROR && net::TcpSocketClient::IsSocketOperationInterrupted(lastError)); + + if (ready == SOCKET_ERROR) + return -lastError; + + lastError = net::TcpSocketClient::GetLastSocketError(fd); + + if (lastError != 0) + return -lastError; + + if (ready == 0) + return WaitResult::TIMEOUT; + + return WaitResult::SUCCESS; + } + } + } + } +}