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-06-14 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
31
const BIO_METHOD NodeBIO::method = {
32
  BIO_TYPE_MEM,
33
  "node.js SSL buffer",
34
  NodeBIO::Write,
35
  NodeBIO::Read,
36
  NodeBIO::Puts,
37
  NodeBIO::Gets,
38
  NodeBIO::Ctrl,
39
  NodeBIO::New,
40
  NodeBIO::Free,
41
  nullptr
42
};
43
44
45
46003
BIO* NodeBIO::New() {
46
  // The const_cast doesn't violate const correctness.  OpenSSL's usage of
47
  // BIO_METHOD is effectively const but BIO_new() takes a non-const argument.
48
46003
  return BIO_new(const_cast<BIO_METHOD*>(&method));
49
}
50
51
52
24527
BIO* NodeBIO::NewFixed(const char* data, size_t len) {
53
24527
  BIO* bio = New();
54
55

49054
  if (bio == nullptr ||
56
24527
      len > INT_MAX ||
57

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

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


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



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

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

586622
  if (child == write_head_ || child == read_head_)
302
584528
    return;
303
2094
  Buffer* cur = child->next_;
304

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

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

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

45206
  if (w == nullptr ||
438
10890
      (w->write_pos_ == w->len_ &&
439
2269
       (w->next_ == r || w->next_->write_pos_ != 0))) {
440
    size_t len = w == nullptr ? initial_ :
441
26413
                             kThroughputBufferLength;
442
26413
    if (len < hint)
443
22124
      len = hint;
444
26413
    Buffer* next = new Buffer(env_, len);
445
446
26413
    if (w == nullptr) {
447
26054
      next->next_ = next;
448
26054
      write_head_ = next;
449
26054
      read_head_ = next;
450
    } else {
451
359
      next->next_ = w->next_;
452
359
      w->next_ = next;
453
    }
454
  }
455
35630
}
456
457
458
3
void NodeBIO::Reset() {
459
3
  if (read_head_ == nullptr)
460
3
    return;
461
462
9
  while (read_head_->read_pos_ != read_head_->write_pos_) {
463
3
    CHECK(read_head_->write_pos_ > read_head_->read_pos_);
464
465
3
    length_ -= read_head_->write_pos_ - read_head_->read_pos_;
466
3
    read_head_->write_pos_ = 0;
467
3
    read_head_->read_pos_ = 0;
468
469
3
    read_head_ = read_head_->next_;
470
  }
471
3
  write_head_ = read_head_;
472
3
  CHECK_EQ(length_, 0);
473
}
474
475
476
46662
NodeBIO::~NodeBIO() {
477
46662
  if (read_head_ == nullptr)
478
20638
    return;
479
480
26024
  Buffer* current = read_head_;
481
26058
  do {
482
26058
    Buffer* next = current->next_;
483
26058
    delete current;
484
26058
    current = next;
485
26058
  } while (current != read_head_);
486
487
26024
  read_head_ = nullptr;
488
26024
  write_head_ = nullptr;
489
46662
}
490
491
}  // namespace node