GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/node_crypto_bio.cc Lines: 230 262 87.8 %
Date: 2019-05-05 22:32:45 Branches: 125 176 71.0 %

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 "base_object-inl.h"
23
#include "node_crypto_bio.h"
24
#include "openssl/bio.h"
25
#include "util-inl.h"
26
#include <climits>
27
#include <cstring>
28
29
namespace node {
30
namespace crypto {
31
32
#if OPENSSL_VERSION_NUMBER < 0x10100000L
33
#define BIO_set_data(bio, data) bio->ptr = data
34
#define BIO_get_data(bio) bio->ptr
35
#define BIO_set_shutdown(bio, shutdown_) bio->shutdown = shutdown_
36
#define BIO_get_shutdown(bio) bio->shutdown
37
#define BIO_set_init(bio, init_) bio->init = init_
38
#define BIO_get_init(bio) bio->init
39
#endif
40
41
42
59664
BIOPointer NodeBIO::New(Environment* env) {
43
59664
  BIOPointer bio(BIO_new(GetMethod()));
44

59664
  if (bio && env != nullptr)
45
24434
    NodeBIO::FromBIO(bio.get())->env_ = env;
46
59664
  return bio;
47
}
48
49
50
35230
BIOPointer NodeBIO::NewFixed(const char* data, size_t len, Environment* env) {
51
35230
  BIOPointer bio = New(env);
52
53

105690
  if (!bio ||
54
35230
      len > INT_MAX ||
55

105690
      BIO_write(bio.get(), data, len) != static_cast<int>(len) ||
56
35230
      BIO_set_mem_eof_return(bio.get(), 0) != 1) {
57
    return BIOPointer();
58
  }
59
60
35230
  return bio;
61
}
62
63
64
59664
int NodeBIO::New(BIO* bio) {
65
59664
  BIO_set_data(bio, new NodeBIO());
66
59664
  BIO_set_init(bio, 1);
67
68
59664
  return 1;
69
}
70
71
72
59628
int NodeBIO::Free(BIO* bio) {
73
59628
  if (bio == nullptr)
74
    return 0;
75
76
59628
  if (BIO_get_shutdown(bio)) {
77

59628
    if (BIO_get_init(bio) && BIO_get_data(bio) != nullptr) {
78
59628
      delete FromBIO(bio);
79
59628
      BIO_set_data(bio, nullptr);
80
    }
81
  }
82
83
59628
  return 1;
84
}
85
86
87
81784
int NodeBIO::Read(BIO* bio, char* out, int len) {
88
81784
  BIO_clear_retry_flags(bio);
89
90
81784
  NodeBIO* nbio = FromBIO(bio);
91
81784
  int bytes = nbio->Read(out, len);
92
93
81784
  if (bytes == 0) {
94
9677
    bytes = nbio->eof_return();
95
9677
    if (bytes != 0) {
96
9675
      BIO_set_retry_read(bio);
97
    }
98
  }
99
100
81784
  return bytes;
101
}
102
103
104
20
char* NodeBIO::Peek(size_t* size) {
105
20
  *size = read_head_->write_pos_ - read_head_->read_pos_;
106
20
  return read_head_->data_ + read_head_->read_pos_;
107
}
108
109
110
6321
size_t NodeBIO::PeekMultiple(char** out, size_t* size, size_t* count) {
111
6321
  Buffer* pos = read_head_;
112
6321
  size_t max = *count;
113
6321
  size_t total = 0;
114
115
  size_t i;
116
13294
  for (i = 0; i < max; i++) {
117
12663
    size[i] = pos->write_pos_ - pos->read_pos_;
118
12663
    total += size[i];
119
12663
    out[i] = pos->data_ + pos->read_pos_;
120
121
    /* Don't get past write head */
122
12663
    if (pos == write_head_)
123
5690
      break;
124
    else
125
6973
      pos = pos->next_;
126
  }
127
128
6321
  if (i == max)
129
631
    *count = i;
130
  else
131
5690
    *count = i + 1;
132
133
6321
  return total;
134
}
135
136
137
68507
int NodeBIO::Write(BIO* bio, const char* data, int len) {
138
68507
  BIO_clear_retry_flags(bio);
139
140
68507
  FromBIO(bio)->Write(data, len);
141
142
68507
  return len;
143
}
144
145
146
int NodeBIO::Puts(BIO* bio, const char* str) {
147
  return Write(bio, str, strlen(str));
148
}
149
150
151
807098
int NodeBIO::Gets(BIO* bio, char* out, int size) {
152
807098
  NodeBIO* nbio = FromBIO(bio);
153
154
807098
  if (nbio->Length() == 0)
155
1361
    return 0;
156
157
805737
  int i = nbio->IndexOf('\n', size);
158
159
  // Include '\n', if it's there.  If not, don't read off the end.
160


805737
  if (i < size && i >= 0 && static_cast<size_t>(i) < nbio->Length())
161
805732
    i++;
162
163
  // Shift `i` a bit to nullptr-terminate string later
164
805737
  if (size == i)
165
    i--;
166
167
  // Flush read data
168
805737
  nbio->Read(out, i);
169
170
805737
  out[i] = 0;
171
172
805737
  return i;
173
}
174
175
176
62560
long NodeBIO::Ctrl(BIO* bio, int cmd, long num,  // NOLINT(runtime/int)
177
                   void* ptr) {
178
  NodeBIO* nbio;
179
  long ret;  // NOLINT(runtime/int)
180
181
62560
  nbio = FromBIO(bio);
182
62560
  ret = 1;
183
184



62560
  switch (cmd) {
185
    case BIO_CTRL_RESET:
186
      nbio->Reset();
187
      break;
188
    case BIO_CTRL_EOF:
189
      ret = nbio->Length() == 0;
190
      break;
191
    case BIO_C_SET_BUF_MEM_EOF_RETURN:
192
35230
      nbio->set_eof_return(num);
193
35230
      break;
194
    case BIO_CTRL_INFO:
195
      ret = nbio->Length();
196
      if (ptr != nullptr)
197
        *reinterpret_cast<void**>(ptr) = nullptr;
198
      break;
199
    case BIO_C_SET_BUF_MEM:
200
      CHECK(0 && "Can't use SET_BUF_MEM_PTR with NodeBIO");
201
      break;
202
    case BIO_C_GET_BUF_MEM_PTR:
203
      CHECK(0 && "Can't use GET_BUF_MEM_PTR with NodeBIO");
204
      ret = 0;
205
      break;
206
    case BIO_CTRL_GET_CLOSE:
207
      ret = BIO_get_shutdown(bio);
208
      break;
209
    case BIO_CTRL_SET_CLOSE:
210
      BIO_set_shutdown(bio, num);
211
      break;
212
    case BIO_CTRL_WPENDING:
213
      ret = 0;
214
      break;
215
    case BIO_CTRL_PENDING:
216
16438
      ret = nbio->Length();
217
16438
      break;
218
    case BIO_CTRL_DUP:
219
    case BIO_CTRL_FLUSH:
220
5180
      ret = 1;
221
5180
      break;
222
    case BIO_CTRL_PUSH:
223
    case BIO_CTRL_POP:
224
    default:
225
5712
      ret = 0;
226
5712
      break;
227
  }
228
62560
  return ret;
229
}
230
231
232
60254
const BIO_METHOD* NodeBIO::GetMethod() {
233
#if OPENSSL_VERSION_NUMBER < 0x10100000L
234
  static const BIO_METHOD method = {
235
    BIO_TYPE_MEM,
236
    "node.js SSL buffer",
237
    Write,
238
    Read,
239
    Puts,
240
    Gets,
241
    Ctrl,
242
    New,
243
    Free,
244
    nullptr
245
  };
246
247
  return &method;
248
#else
249
  // This is called from InitCryptoOnce() to avoid race conditions during
250
  // initialization.
251
  static BIO_METHOD* method = nullptr;
252
253
60254
  if (method == nullptr) {
254
591
    method = BIO_meth_new(BIO_TYPE_MEM, "node.js SSL buffer");
255
591
    BIO_meth_set_write(method, Write);
256
591
    BIO_meth_set_read(method, Read);
257
591
    BIO_meth_set_puts(method, Puts);
258
591
    BIO_meth_set_gets(method, Gets);
259
591
    BIO_meth_set_ctrl(method, Ctrl);
260
591
    BIO_meth_set_create(method, New);
261
591
    BIO_meth_set_destroy(method, Free);
262
  }
263
264
60254
  return method;
265
#endif
266
}
267
268
269
903017
void NodeBIO::TryMoveReadHead() {
270
  // `read_pos_` and `write_pos_` means the position of the reader and writer
271
  // inside the buffer, respectively. When they're equal - its safe to reset
272
  // them, because both reader and writer will continue doing their stuff
273
  // from new (zero) positions.
274

2751357
  while (read_head_->read_pos_ != 0 &&
275
890371
         read_head_->read_pos_ == read_head_->write_pos_) {
276
    // Reset positions
277
54952
    read_head_->read_pos_ = 0;
278
54952
    read_head_->write_pos_ = 0;
279
280
    // Move read_head_ forward, just in case if there're still some data to
281
    // read in the next buffer.
282
54952
    if (read_head_ != write_head_)
283
9368
      read_head_ = read_head_->next_;
284
  }
285
903017
}
286
287
288
893737
size_t NodeBIO::Read(char* out, size_t size) {
289
893737
  size_t bytes_read = 0;
290
893737
  size_t expected = Length() > size ? size : Length();
291
893737
  size_t offset = 0;
292
893737
  size_t left = size;
293
294
2677845
  while (bytes_read < expected) {
295
890371
    CHECK_LE(read_head_->read_pos_, read_head_->write_pos_);
296
890371
    size_t avail = read_head_->write_pos_ - read_head_->read_pos_;
297
890371
    if (avail > left)
298
835419
      avail = left;
299
300
    // Copy data
301
890371
    if (out != nullptr)
302
877844
      memcpy(out + offset, read_head_->data_ + read_head_->read_pos_, avail);
303
890371
    read_head_->read_pos_ += avail;
304
305
    // Move pointers
306
890371
    bytes_read += avail;
307
890371
    offset += avail;
308
890371
    left -= avail;
309
310
890371
    TryMoveReadHead();
311
  }
312
893737
  CHECK_EQ(expected, bytes_read);
313
893737
  length_ -= bytes_read;
314
315
  // Free all empty buffers, but write_head's child
316
893737
  FreeEmpty();
317
318
893737
  return bytes_read;
319
}
320
321
322
893737
void NodeBIO::FreeEmpty() {
323
893737
  if (write_head_ == nullptr)
324
894672
    return;
325
892070
  Buffer* child = write_head_->next_;
326

892070
  if (child == write_head_ || child == read_head_)
327
880929
    return;
328
11141
  Buffer* cur = child->next_;
329

11141
  if (cur == write_head_ || cur == read_head_)
330
10409
    return;
331
332
732
  Buffer* prev = child;
333
7916
  while (cur != read_head_) {
334
6452
    CHECK_NE(cur, write_head_);
335
6452
    CHECK_EQ(cur->write_pos_, cur->read_pos_);
336
337
6452
    Buffer* next = cur->next_;
338
6452
    delete cur;
339
6452
    cur = next;
340
  }
341
732
  prev->next_ = cur;
342
}
343
344
345
805737
size_t NodeBIO::IndexOf(char delim, size_t limit) {
346
805737
  size_t bytes_read = 0;
347
805737
  size_t max = Length() > limit ? limit : Length();
348
805737
  size_t left = limit;
349
805737
  Buffer* current = read_head_;
350
351
1611479
  while (bytes_read < max) {
352
805737
    CHECK_LE(current->read_pos_, current->write_pos_);
353
805737
    size_t avail = current->write_pos_ - current->read_pos_;
354
805737
    if (avail > left)
355
660769
      avail = left;
356
357
    // Walk through data
358
805737
    char* tmp = current->data_ + current->read_pos_;
359
805737
    size_t off = 0;
360

54842551
    while (off < avail && *tmp != delim) {
361
53231077
      off++;
362
53231077
      tmp++;
363
    }
364
365
    // Move pointers
366
805737
    bytes_read += off;
367
805737
    left -= off;
368
369
    // Found `delim`
370
805737
    if (off != avail) {
371
805732
      return bytes_read;
372
    }
373
374
    // Move to next buffer
375
5
    if (current->read_pos_ + avail == current->len_) {
376
2
      current = current->next_;
377
    }
378
  }
379
5
  CHECK_EQ(max, bytes_read);
380
381
5
  return max;
382
}
383
384
385
68507
void NodeBIO::Write(const char* data, size_t size) {
386
68507
  size_t offset = 0;
387
68507
  size_t left = size;
388
389
  // Allocate initial buffer if the ring is empty
390
68507
  TryAllocateForWrite(left);
391
392
215226
  while (left > 0) {
393
78212
    size_t to_write = left;
394
78212
    CHECK_LE(write_head_->write_pos_, write_head_->len_);
395
78212
    size_t avail = write_head_->len_ - write_head_->write_pos_;
396
397
78212
    if (to_write > avail)
398
9705
      to_write = avail;
399
400
    // Copy data
401
78212
    memcpy(write_head_->data_ + write_head_->write_pos_,
402
78212
           data + offset,
403
156424
           to_write);
404
405
    // Move pointers
406
78212
    left -= to_write;
407
78212
    offset += to_write;
408
78212
    length_ += to_write;
409
78212
    write_head_->write_pos_ += to_write;
410
78212
    CHECK_LE(write_head_->write_pos_, write_head_->len_);
411
412
    // Go to next buffer if there still are some bytes to write
413
78212
    if (left != 0) {
414
9705
      CHECK_EQ(write_head_->write_pos_, write_head_->len_);
415
9705
      TryAllocateForWrite(left);
416
9705
      write_head_ = write_head_->next_;
417
418
      // Additionally, since we're moved to the next buffer, read head
419
      // may be moved as well.
420
9705
      TryMoveReadHead();
421
    }
422
  }
423
68507
  CHECK_EQ(left, 0);
424
68507
}
425
426
427
8445
char* NodeBIO::PeekWritable(size_t* size) {
428
8445
  TryAllocateForWrite(*size);
429
430
8445
  size_t available = write_head_->len_ - write_head_->write_pos_;
431

8445
  if (*size == 0 || available <= *size)
432
8397
    *size = available;
433
434
8445
  return write_head_->data_ + write_head_->write_pos_;
435
}
436
437
438
7877
void NodeBIO::Commit(size_t size) {
439
7877
  write_head_->write_pos_ += size;
440
7877
  length_ += size;
441
7877
  CHECK_LE(write_head_->write_pos_, write_head_->len_);
442
443
  // Allocate new buffer if write head is full,
444
  // and there're no other place to go
445
7877
  TryAllocateForWrite(0);
446
7877
  if (write_head_->write_pos_ == write_head_->len_) {
447
2941
    write_head_ = write_head_->next_;
448
449
    // Additionally, since we're moved to the next buffer, read head
450
    // may be moved as well.
451
2941
    TryMoveReadHead();
452
  }
453
7877
}
454
455
456
94534
void NodeBIO::TryAllocateForWrite(size_t hint) {
457
94534
  Buffer* w = write_head_;
458
94534
  Buffer* r = read_head_;
459
  // If write head is full, next buffer is either read head or not empty.
460

149477
  if (w == nullptr ||
461
73221
      (w->write_pos_ == w->len_ &&
462
26717
       (w->next_ == r || w->next_->write_pos_ != 0))) {
463
    size_t len = w == nullptr ? initial_ :
464
49430
                             kThroughputBufferLength;
465
49430
    if (len < hint)
466
38065
      len = hint;
467
49430
    Buffer* next = new Buffer(env_, len);
468
469
49430
    if (w == nullptr) {
470
39591
      next->next_ = next;
471
39591
      write_head_ = next;
472
39591
      read_head_ = next;
473
    } else {
474
9839
      next->next_ = w->next_;
475
9839
      w->next_ = next;
476
    }
477
  }
478
94534
}
479
480
481
void NodeBIO::Reset() {
482
  if (read_head_ == nullptr)
483
    return;
484
485
  while (read_head_->read_pos_ != read_head_->write_pos_) {
486
    CHECK(read_head_->write_pos_ > read_head_->read_pos_);
487
488
    length_ -= read_head_->write_pos_ - read_head_->read_pos_;
489
    read_head_->write_pos_ = 0;
490
    read_head_->read_pos_ = 0;
491
492
    read_head_ = read_head_->next_;
493
  }
494
  write_head_ = read_head_;
495
  CHECK_EQ(length_, 0);
496
}
497
498
499
178884
NodeBIO::~NodeBIO() {
500
59628
  if (read_head_ == nullptr)
501
20071
    return;
502
503
39557
  Buffer* current = read_head_;
504
40235
  do {
505
40235
    Buffer* next = current->next_;
506
40235
    delete current;
507
40235
    current = next;
508
40235
  } while (current != read_head_);
509
510
39557
  read_head_ = nullptr;
511
39557
  write_head_ = nullptr;
512
99185
}
513
514
515
1144253
NodeBIO* NodeBIO::FromBIO(BIO* bio) {
516
1144253
  CHECK_NOT_NULL(BIO_get_data(bio));
517
1144253
  return static_cast<NodeBIO*>(BIO_get_data(bio));
518
}
519
520
521
}  // namespace crypto
522
}  // namespace node