GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage/nodes/benchmark/out/../src/node_crypto_bio.cc Lines: 227 251 90.4 %
Date: 2017-10-21 Branches: 115 160 71.9 %

Line Branch Exec Source
1
// Copyright Joyent, Inc. and other Node contributors.
2
//
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:
10
//
11
// The above copyright notice and this permission notice shall be included
12
// in all copies or substantial portions of the Software.
13
//
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.
21
22
#include "node_crypto_bio.h"
23
#include "openssl/bio.h"
24
#include "util.h"
25
#include "util-inl.h"
26
#include <limits.h>
27
#include <string.h>
28
29
namespace node {
30
namespace crypto {
31
32
const BIO_METHOD NodeBIO::method = {
33
  BIO_TYPE_MEM,
34
  "node.js SSL buffer",
35
  NodeBIO::Write,
36
  NodeBIO::Read,
37
  NodeBIO::Puts,
38
  NodeBIO::Gets,
39
  NodeBIO::Ctrl,
40
  NodeBIO::New,
41
  NodeBIO::Free,
42
  nullptr
43
};
44
45
46
50183
BIO* NodeBIO::New() {
47
  // The const_cast doesn't violate const correctness.  OpenSSL's usage of
48
  // BIO_METHOD is effectively const but BIO_new() takes a non-const argument.
49
50183
  return BIO_new(const_cast<BIO_METHOD*>(&method));
50
}
51
52
53
28583
BIO* NodeBIO::NewFixed(const char* data, size_t len) {
54
28583
  BIO* bio = New();
55
56

57166
  if (bio == nullptr ||
57
28583
      len > INT_MAX ||
58

85749
      BIO_write(bio, data, len) != static_cast<int>(len) ||
59
28583
      BIO_set_mem_eof_return(bio, 0) != 1) {
60
    BIO_free(bio);
61
    return nullptr;
62
  }
63
64
28583
  return bio;
65
}
66
67
68
2352
void NodeBIO::AssignEnvironment(Environment* env) {
69
2352
  env_ = env;
70
2352
}
71
72
73
50183
int NodeBIO::New(BIO* bio) {
74
50183
  bio->ptr = new NodeBIO();
75
76
  // XXX Why am I doing it?!
77
50183
  bio->shutdown = 1;
78
50183
  bio->init = 1;
79
50183
  bio->num = -1;
80
81
50183
  return 1;
82
}
83
84
85
50127
int NodeBIO::Free(BIO* bio) {
86
50127
  if (bio == nullptr)
87
    return 0;
88
89
50127
  if (bio->shutdown) {
90

50127
    if (bio->init && bio->ptr != nullptr) {
91
50127
      delete FromBIO(bio);
92
50127
      bio->ptr = nullptr;
93
    }
94
  }
95
96
50127
  return 1;
97
}
98
99
100
16404
int NodeBIO::Read(BIO* bio, char* out, int len) {
101
  int bytes;
102
16404
  BIO_clear_retry_flags(bio);
103
104
16404
  bytes = FromBIO(bio)->Read(out, len);
105
106
16404
  if (bytes == 0) {
107
3885
    bytes = bio->num;
108
3885
    if (bytes != 0) {
109
3883
      BIO_set_retry_read(bio);
110
    }
111
  }
112
113
16404
  return bytes;
114
}
115
116
117
486
char* NodeBIO::Peek(size_t* size) {
118
486
  *size = read_head_->write_pos_ - read_head_->read_pos_;
119
486
  return read_head_->data_ + read_head_->read_pos_;
120
}
121
122
123
2575
size_t NodeBIO::PeekMultiple(char** out, size_t* size, size_t* count) {
124
2575
  Buffer* pos = read_head_;
125
2575
  size_t max = *count;
126
2575
  size_t total = 0;
127
128
  size_t i;
129
3164
  for (i = 0; i < max; i++) {
130
3122
    size[i] = pos->write_pos_ - pos->read_pos_;
131
3122
    total += size[i];
132
3122
    out[i] = pos->data_ + pos->read_pos_;
133
134
    /* Don't get past write head */
135
3122
    if (pos == write_head_)
136
2533
      break;
137
    else
138
589
      pos = pos->next_;
139
  }
140
141
2575
  if (i == max)
142
42
    *count = i;
143
  else
144
2533
    *count = i + 1;
145
146
2575
  return total;
147
}
148
149
150
34481
int NodeBIO::Write(BIO* bio, const char* data, int len) {
151
34481
  BIO_clear_retry_flags(bio);
152
153
34481
  FromBIO(bio)->Write(data, len);
154
155
34481
  return len;
156
}
157
158
159
int NodeBIO::Puts(BIO* bio, const char* str) {
160
  return Write(bio, str, strlen(str));
161
}
162
163
164
664299
int NodeBIO::Gets(BIO* bio, char* out, int size) {
165
664299
  NodeBIO* nbio =  FromBIO(bio);
166
167
664299
  if (nbio->Length() == 0)
168
478
    return 0;
169
170
663821
  int i = nbio->IndexOf('\n', size);
171
172
  // Include '\n', if it's there.  If not, don't read off the end.
173


663821
  if (i < size && i >= 0 && static_cast<size_t>(i) < nbio->Length())
174
663810
    i++;
175
176
  // Shift `i` a bit to nullptr-terminate string later
177
663821
  if (size == i)
178
    i--;
179
180
  // Flush read data
181
663821
  nbio->Read(out, i);
182
183
663821
  out[i] = 0;
184
185
663821
  return i;
186
}
187
188
189
41919
long NodeBIO::Ctrl(BIO* bio, int cmd, long num,  // NOLINT(runtime/int)
190
                   void* ptr) {
191
  NodeBIO* nbio;
192
  long ret;  // NOLINT(runtime/int)
193
194
41919
  nbio = FromBIO(bio);
195
41919
  ret = 1;
196
197



41919
  switch (cmd) {
198
    case BIO_CTRL_RESET:
199
      nbio->Reset();
200
      break;
201
    case BIO_CTRL_EOF:
202
      ret = nbio->Length() == 0;
203
      break;
204
    case BIO_C_SET_BUF_MEM_EOF_RETURN:
205
28583
      bio->num = num;
206
28583
      break;
207
    case BIO_CTRL_INFO:
208
      ret = nbio->Length();
209
      if (ptr != nullptr)
210
        *reinterpret_cast<void**>(ptr) = nullptr;
211
      break;
212
    case BIO_C_SET_BUF_MEM:
213
      CHECK(0 && "Can't use SET_BUF_MEM_PTR with NodeBIO");
214
      break;
215
    case BIO_C_GET_BUF_MEM_PTR:
216
      CHECK(0 && "Can't use GET_BUF_MEM_PTR with NodeBIO");
217
      ret = 0;
218
      break;
219
    case BIO_CTRL_GET_CLOSE:
220
      ret = bio->shutdown;
221
      break;
222
    case BIO_CTRL_SET_CLOSE:
223
      bio->shutdown = num;
224
      break;
225
    case BIO_CTRL_WPENDING:
226
      ret = 0;
227
      break;
228
    case BIO_CTRL_PENDING:
229
10746
      ret = nbio->Length();
230
10746
      break;
231
    case BIO_CTRL_DUP:
232
    case BIO_CTRL_FLUSH:
233
1095
      ret = 1;
234
1095
      break;
235
    case BIO_CTRL_PUSH:
236
    case BIO_CTRL_POP:
237
    default:
238
1495
      ret = 0;
239
1495
      break;
240
  }
241
41919
  return ret;
242
}
243
244
245
681005
void NodeBIO::TryMoveReadHead() {
246
  // `read_pos_` and `write_pos_` means the position of the reader and writer
247
  // inside the buffer, respectively. When they're equal - its safe to reset
248
  // them, because both reader and writer will continue doing their stuff
249
  // from new (zero) positions.
250

2076116
  while (read_head_->read_pos_ != 0 &&
251
679560
         read_head_->read_pos_ == read_head_->write_pos_) {
252
    // Reset positions
253
34546
    read_head_->read_pos_ = 0;
254
34546
    read_head_->write_pos_ = 0;
255
256
    // Move read_head_ forward, just in case if there're still some data to
257
    // read in the next buffer.
258
34546
    if (read_head_ != write_head_)
259
1439
      read_head_ = read_head_->next_;
260
  }
261
681005
}
262
263
264
682898
size_t NodeBIO::Read(char* out, size_t size) {
265
682898
  size_t bytes_read = 0;
266
682898
  size_t expected = Length() > size ? size : Length();
267
682898
  size_t offset = 0;
268
682898
  size_t left = size;
269
270
2045356
  while (bytes_read < expected) {
271
679560
    CHECK_LE(read_head_->read_pos_, read_head_->write_pos_);
272
679560
    size_t avail = read_head_->write_pos_ - read_head_->read_pos_;
273
679560
    if (avail > left)
274
645014
      avail = left;
275
276
    // Copy data
277
679560
    if (out != nullptr)
278
676340
      memcpy(out + offset, read_head_->data_ + read_head_->read_pos_, avail);
279
679560
    read_head_->read_pos_ += avail;
280
281
    // Move pointers
282
679560
    bytes_read += avail;
283
679560
    offset += avail;
284
679560
    left -= avail;
285
286
679560
    TryMoveReadHead();
287
  }
288
682898
  CHECK_EQ(expected, bytes_read);
289
682898
  length_ -= bytes_read;
290
291
  // Free all empty buffers, but write_head's child
292
682898
  FreeEmpty();
293
294
682898
  return bytes_read;
295
}
296
297
298
682898
void NodeBIO::FreeEmpty() {
299
682898
  if (write_head_ == nullptr)
300
628
    return;
301
682270
  Buffer* child = write_head_->next_;
302

682270
  if (child == write_head_ || child == read_head_)
303
679764
    return;
304
2506
  Buffer* cur = child->next_;
305

2506
  if (cur == write_head_ || cur == read_head_)
306
2456
    return;
307
308
50
  Buffer* prev = child;
309
544
  while (cur != read_head_) {
310
444
    CHECK_NE(cur, write_head_);
311
444
    CHECK_EQ(cur->write_pos_, cur->read_pos_);
312
313
444
    Buffer* next = cur->next_;
314
444
    delete cur;
315
444
    cur = next;
316
  }
317
50
  prev->next_ = cur;
318
}
319
320
321
663821
size_t NodeBIO::IndexOf(char delim, size_t limit) {
322
663821
  size_t bytes_read = 0;
323
663821
  size_t max = Length() > limit ? limit : Length();
324
663821
  size_t left = limit;
325
663821
  Buffer* current = read_head_;
326
327
1327653
  while (bytes_read < max) {
328
663821
    CHECK_LE(current->read_pos_, current->write_pos_);
329
663821
    size_t avail = current->write_pos_ - current->read_pos_;
330
663821
    if (avail > left)
331
547195
      avail = left;
332
333
    // Walk through data
334
663821
    char* tmp = current->data_ + current->read_pos_;
335
663821
    size_t off = 0;
336

45522833
    while (off < avail && *tmp != delim) {
337
44195191
      off++;
338
44195191
      tmp++;
339
    }
340
341
    // Move pointers
342
663821
    bytes_read += off;
343
663821
    left -= off;
344
345
    // Found `delim`
346
663821
    if (off != avail) {
347
663810
      return bytes_read;
348
    }
349
350
    // Move to next buffer
351
11
    if (current->read_pos_ + avail == current->len_) {
352
      current = current->next_;
353
    }
354
  }
355
11
  CHECK_EQ(max, bytes_read);
356
357
11
  return max;
358
}
359
360
361
34612
void NodeBIO::Write(const char* data, size_t size) {
362
34612
  size_t offset = 0;
363
34612
  size_t left = size;
364
365
  // Allocate initial buffer if the ring is empty
366
34612
  TryAllocateForWrite(left);
367
368
104425
  while (left > 0) {
369
35201
    size_t to_write = left;
370
35201
    CHECK_LE(write_head_->write_pos_, write_head_->len_);
371
35201
    size_t avail = write_head_->len_ - write_head_->write_pos_;
372
373
35201
    if (to_write > avail)
374
589
      to_write = avail;
375
376
    // Copy data
377
35201
    memcpy(write_head_->data_ + write_head_->write_pos_,
378
35201
           data + offset,
379
70402
           to_write);
380
381
    // Move pointers
382
35201
    left -= to_write;
383
35201
    offset += to_write;
384
35201
    length_ += to_write;
385
35201
    write_head_->write_pos_ += to_write;
386
35201
    CHECK_LE(write_head_->write_pos_, write_head_->len_);
387
388
    // Go to next buffer if there still are some bytes to write
389
35201
    if (left != 0) {
390
589
      CHECK_EQ(write_head_->write_pos_, write_head_->len_);
391
589
      TryAllocateForWrite(left);
392
589
      write_head_ = write_head_->next_;
393
394
      // Additionally, since we're moved to the next buffer, read head
395
      // may be moved as well.
396
589
      TryMoveReadHead();
397
    }
398
  }
399
34612
  CHECK_EQ(left, 0);
400
34612
}
401
402
403
3005
char* NodeBIO::PeekWritable(size_t* size) {
404
3005
  TryAllocateForWrite(*size);
405
406
3005
  size_t available = write_head_->len_ - write_head_->write_pos_;
407

3005
  if (*size != 0 && available > *size)
408
    available = *size;
409
  else
410
3005
    *size = available;
411
412
3005
  return write_head_->data_ + write_head_->write_pos_;
413
}
414
415
416
2758
void NodeBIO::Commit(size_t size) {
417
2758
  write_head_->write_pos_ += size;
418
2758
  length_ += size;
419
2758
  CHECK_LE(write_head_->write_pos_, write_head_->len_);
420
421
  // Allocate new buffer if write head is full,
422
  // and there're no other place to go
423
2758
  TryAllocateForWrite(0);
424
2758
  if (write_head_->write_pos_ == write_head_->len_) {
425
856
    write_head_ = write_head_->next_;
426
427
    // Additionally, since we're moved to the next buffer, read head
428
    // may be moved as well.
429
856
    TryMoveReadHead();
430
  }
431
2758
}
432
433
434
40964
void NodeBIO::TryAllocateForWrite(size_t hint) {
435
40964
  Buffer* w = write_head_;
436
40964
  Buffer* r = read_head_;
437
  // If write head is full, next buffer is either read head or not empty.
438

51697
  if (w == nullptr ||
439
12459
      (w->write_pos_ == w->len_ &&
440
2968
       (w->next_ == r || w->next_->write_pos_ != 0))) {
441
    size_t len = w == nullptr ? initial_ :
442
30715
                             kThroughputBufferLength;
443
30715
    if (len < hint)
444
25808
      len = hint;
445
30715
    Buffer* next = new Buffer(env_, len);
446
447
30715
    if (w == nullptr) {
448
30231
      next->next_ = next;
449
30231
      write_head_ = next;
450
30231
      read_head_ = next;
451
    } else {
452
484
      next->next_ = w->next_;
453
484
      w->next_ = next;
454
    }
455
  }
456
40964
}
457
458
459
5
void NodeBIO::Reset() {
460
5
  if (read_head_ == nullptr)
461
5
    return;
462
463
15
  while (read_head_->read_pos_ != read_head_->write_pos_) {
464
5
    CHECK(read_head_->write_pos_ > read_head_->read_pos_);
465
466
5
    length_ -= read_head_->write_pos_ - read_head_->read_pos_;
467
5
    read_head_->write_pos_ = 0;
468
5
    read_head_->read_pos_ = 0;
469
470
5
    read_head_ = read_head_->next_;
471
  }
472
5
  write_head_ = read_head_;
473
5
  CHECK_EQ(length_, 0);
474
}
475
476
477
50889
NodeBIO::~NodeBIO() {
478
50889
  if (read_head_ == nullptr)
479
20703
    return;
480
481
30186
  Buffer* current = read_head_;
482
30223
  do {
483
30223
    Buffer* next = current->next_;
484
30223
    delete current;
485
30223
    current = next;
486
30223
  } while (current != read_head_);
487
488
30186
  read_head_ = nullptr;
489
30186
  write_head_ = nullptr;
490
50889
}
491
492
}  // namespace crypto
493
}  // namespace node