1 // Copyright Joyent, Inc. and other Node contributors.
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to permit
8 // persons to whom the Software is furnished to do so, subject to the
9 // following conditions:
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17 // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 // USE OR OTHER DEALINGS IN THE SOFTWARE.
22 #include "node_crypto_bio.h"
23 #include "openssl/bio.h"
28 const BIO_METHOD NodeBIO::method = {
43 // The const_cast doesn't violate const correctness. OpenSSL's usage of
44 // BIO_METHOD is effectively const but BIO_new() takes a non-const argument.
45 return BIO_new(const_cast<BIO_METHOD*>(&method));
49 int NodeBIO::New(BIO* bio) {
50 bio->ptr = new NodeBIO();
52 // XXX Why am I doing it?!
61 int NodeBIO::Free(BIO* bio) {
66 if (bio->init && bio->ptr != NULL) {
76 int NodeBIO::Read(BIO* bio, char* out, int len) {
78 BIO_clear_retry_flags(bio);
80 bytes = FromBIO(bio)->Read(out, len);
85 BIO_set_retry_read(bio);
93 char* NodeBIO::Peek(size_t* size) {
94 *size = read_head_->write_pos_ - read_head_->read_pos_;
95 return read_head_->data_ + read_head_->read_pos_;
99 size_t NodeBIO::PeekMultiple(char** out, size_t* size, size_t* count) {
100 Buffer* pos = read_head_;
105 for (i = 0; i < max; i++) {
106 size[i] = pos->write_pos_ - pos->read_pos_;
108 out[i] = pos->data_ + pos->read_pos_;
110 /* Don't get past write head */
111 if (pos == write_head_)
126 int NodeBIO::Write(BIO* bio, const char* data, int len) {
127 BIO_clear_retry_flags(bio);
129 FromBIO(bio)->Write(data, len);
135 int NodeBIO::Puts(BIO* bio, const char* str) {
136 return Write(bio, str, strlen(str));
140 int NodeBIO::Gets(BIO* bio, char* out, int size) {
141 NodeBIO* nbio = FromBIO(bio);
143 if (nbio->Length() == 0)
146 int i = nbio->IndexOf('\n', size);
152 // Shift `i` a bit to NULL-terminate string later
165 long NodeBIO::Ctrl(BIO* bio, int cmd, long num, void* ptr) {
177 ret = nbio->Length() == 0;
179 case BIO_C_SET_BUF_MEM_EOF_RETURN:
183 ret = nbio->Length();
185 *reinterpret_cast<void**>(ptr) = NULL;
187 case BIO_C_SET_BUF_MEM:
188 assert(0 && "Can't use SET_BUF_MEM_PTR with NodeBIO");
191 case BIO_C_GET_BUF_MEM_PTR:
192 assert(0 && "Can't use GET_BUF_MEM_PTR with NodeBIO");
195 case BIO_CTRL_GET_CLOSE:
198 case BIO_CTRL_SET_CLOSE:
201 case BIO_CTRL_WPENDING:
204 case BIO_CTRL_PENDING:
205 ret = nbio->Length();
221 void NodeBIO::TryMoveReadHead() {
222 // `read_pos_` and `write_pos_` means the position of the reader and writer
223 // inside the buffer, respectively. When they're equal - its safe to reset
224 // them, because both reader and writer will continue doing their stuff
225 // from new (zero) positions.
226 if (read_head_->read_pos_ != read_head_->write_pos_)
230 read_head_->read_pos_ = 0;
231 read_head_->write_pos_ = 0;
233 // Move read_head_ forward, just in case if there're still some data to
234 // read in the next buffer.
235 if (read_head_ != write_head_)
236 read_head_ = read_head_->next_;
240 size_t NodeBIO::Read(char* out, size_t size) {
241 size_t bytes_read = 0;
242 size_t expected = Length() > size ? size : Length();
246 while (bytes_read < expected) {
247 assert(read_head_->read_pos_ <= read_head_->write_pos_);
248 size_t avail = read_head_->write_pos_ - read_head_->read_pos_;
254 memcpy(out + offset, read_head_->data_ + read_head_->read_pos_, avail);
255 read_head_->read_pos_ += avail;
264 assert(expected == bytes_read);
265 length_ -= bytes_read;
267 // Free all empty buffers, but write_head's child
274 void NodeBIO::FreeEmpty() {
275 Buffer* child = write_head_->next_;
276 if (child == write_head_ || child == read_head_)
278 Buffer* cur = child->next_;
279 if (cur == write_head_ || cur == read_head_)
282 Buffer* prev = child;
283 while (cur != read_head_) {
284 // Skip embedded buffer, and continue deallocating again starting from it
291 assert(cur != write_head_);
292 assert(cur->write_pos_ == cur->read_pos_);
294 Buffer* next = cur->next_;
298 assert(prev == child || prev == &head_);
303 size_t NodeBIO::IndexOf(char delim, size_t limit) {
304 size_t bytes_read = 0;
305 size_t max = Length() > limit ? limit : Length();
307 Buffer* current = read_head_;
309 while (bytes_read < max) {
310 assert(current->read_pos_ <= current->write_pos_);
311 size_t avail = current->write_pos_ - current->read_pos_;
316 char* tmp = current->data_ + current->read_pos_;
318 while (off < avail && *tmp != delim) {
332 // Move to next buffer
333 if (current->read_pos_ + avail == kBufferLength) {
334 current = current->next_;
337 assert(max == bytes_read);
343 void NodeBIO::Write(const char* data, size_t size) {
347 size_t to_write = left;
348 assert(write_head_->write_pos_ <= kBufferLength);
349 size_t avail = kBufferLength - write_head_->write_pos_;
351 if (to_write > avail)
355 memcpy(write_head_->data_ + write_head_->write_pos_,
363 write_head_->write_pos_ += to_write;
364 assert(write_head_->write_pos_ <= kBufferLength);
366 // Go to next buffer if there still are some bytes to write
368 assert(write_head_->write_pos_ == kBufferLength);
369 TryAllocateForWrite();
370 write_head_ = write_head_->next_;
372 // Additionally, since we're moved to the next buffer, read head
373 // may be moved as well.
381 char* NodeBIO::PeekWritable(size_t* size) {
382 size_t available = kBufferLength - write_head_->write_pos_;
383 if (*size != 0 && available > *size)
388 return write_head_->data_ + write_head_->write_pos_;
392 void NodeBIO::Commit(size_t size) {
393 write_head_->write_pos_ += size;
395 assert(write_head_->write_pos_ <= kBufferLength);
397 // Allocate new buffer if write head is full,
398 // and there're no other place to go
399 TryAllocateForWrite();
400 if (write_head_->write_pos_ == kBufferLength)
401 write_head_ = write_head_->next_;
405 void NodeBIO::TryAllocateForWrite() {
406 // If write head is full, next buffer is either read head or not empty.
407 if (write_head_->write_pos_ == kBufferLength &&
408 (write_head_->next_ == read_head_ ||
409 write_head_->next_->write_pos_ != 0)) {
410 Buffer* next = new Buffer();
411 next->next_ = write_head_->next_;
412 write_head_->next_ = next;
417 void NodeBIO::Reset() {
418 while (read_head_->read_pos_ != read_head_->write_pos_) {
419 assert(read_head_->write_pos_ > read_head_->read_pos_);
421 length_ -= read_head_->write_pos_ - read_head_->read_pos_;
422 read_head_->write_pos_ = 0;
423 read_head_->read_pos_ = 0;
425 read_head_ = read_head_->next_;
427 write_head_ = read_head_;
428 assert(length_ == 0);
432 NodeBIO::~NodeBIO() {
433 Buffer* current = head_.next_;
434 while (current != &head_) {
435 Buffer* next = current->next_;