// Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to permit // persons to whom the Software is furnished to do so, subject to the // following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. #ifndef SRC_NODE_CRYPTO_BIO_H_ #define SRC_NODE_CRYPTO_BIO_H_ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS #include "node_crypto.h" #include "openssl/bio.h" #include "env-inl.h" #include "util-inl.h" #include "v8.h" namespace node { namespace crypto { // This class represents buffers for OpenSSL I/O, implemented as a singly-linked // list of chunks. It can be used either for writing data from Node to OpenSSL, // or for reading data back, but not both. // The structure is only accessed, and owned by, the OpenSSL BIOPointer // (a.k.a. std::unique_ptr). class NodeBIO : public MemoryRetainer { public: ~NodeBIO(); static BIOPointer New(Environment* env = nullptr); // NewFixed takes a copy of `len` bytes from `data` and returns a BIO that, // when read from, returns those bytes followed by EOF. static BIOPointer NewFixed(const char* data, size_t len, Environment* env = nullptr); // Move read head to next buffer if needed void TryMoveReadHead(); // Allocate new buffer for write if needed void TryAllocateForWrite(size_t hint); // Read `len` bytes maximum into `out`, return actual number of read bytes size_t Read(char* out, size_t size); // Memory optimization: // Deallocate children of write head's child if they're empty void FreeEmpty(); // Return pointer to internal data and amount of // contiguous data available to read char* Peek(size_t* size); // Return pointers and sizes of multiple internal data chunks available for // reading size_t PeekMultiple(char** out, size_t* size, size_t* count); // Find first appearance of `delim` in buffer or `limit` if `delim` // wasn't found. size_t IndexOf(char delim, size_t limit); // Discard all available data void Reset(); // Put `len` bytes from `data` into buffer void Write(const char* data, size_t size); // Return pointer to contiguous block of reserved data and the size available // for future writes. Call Commit() once the write is complete. char* PeekWritable(size_t* size); // Specify how much data was written into the block returned by // PeekWritable(). void Commit(size_t size); // Return size of buffer in bytes inline size_t Length() const { return length_; } inline void set_eof_return(int num) { eof_return_ = num; } inline int eof_return() { return eof_return_; } inline void set_initial(size_t initial) { initial_ = initial; } static NodeBIO* FromBIO(BIO* bio); void MemoryInfo(MemoryTracker* tracker) const override { tracker->TrackFieldWithSize("buffer", length_, "NodeBIO::Buffer"); } SET_MEMORY_INFO_NAME(NodeBIO) SET_SELF_SIZE(NodeBIO) private: static int New(BIO* bio); static int Free(BIO* bio); static int Read(BIO* bio, char* out, int len); static int Write(BIO* bio, const char* data, int len); static int Puts(BIO* bio, const char* str); static int Gets(BIO* bio, char* out, int size); static long Ctrl(BIO* bio, int cmd, long num, // NOLINT(runtime/int) void* ptr); static const BIO_METHOD* GetMethod(); // Enough to handle the most of the client hellos static const size_t kInitialBufferLength = 1024; static const size_t kThroughputBufferLength = 16384; class Buffer { public: Buffer(Environment* env, size_t len) : env_(env), read_pos_(0), write_pos_(0), len_(len), next_(nullptr) { data_ = new char[len]; if (env_ != nullptr) env_->isolate()->AdjustAmountOfExternalAllocatedMemory(len); } ~Buffer() { delete[] data_; if (env_ != nullptr) { const int64_t len = static_cast(len_); env_->isolate()->AdjustAmountOfExternalAllocatedMemory(-len); } } Environment* env_; size_t read_pos_; size_t write_pos_; size_t len_; Buffer* next_; char* data_; }; Environment* env_ = nullptr; size_t initial_ = kInitialBufferLength; size_t length_ = 0; int eof_return_ = -1; Buffer* read_head_ = nullptr; Buffer* write_head_ = nullptr; friend void node::crypto::InitCryptoOnce(); }; } // namespace crypto } // namespace node #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS #endif // SRC_NODE_CRYPTO_BIO_H_