Skip to content

Commit ee15142

Browse files
puzpuzpuztargos
authored andcommitted
tls: allow reading data into a static buffer
Refs: #25436 PR-URL: #35753 Refs: #25436 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Minwoo Jung <nodecorelab@gmail.com>
1 parent 4e76a3c commit ee15142

6 files changed

Lines changed: 362 additions & 44 deletions

File tree

‎benchmark/tls/throughput-s2c.js‎

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
'use strict';
2+
constcommon=require('../common.js');
3+
constbench=common.createBenchmark(main,{
4+
dur: [5],
5+
type: ['buf','asc','utf'],
6+
sendchunklen: [256,32*1024,128*1024,16*1024*1024],
7+
recvbuflen: [0,64*1024,1024*1024],
8+
recvbufgenfn: ['true','false']
9+
});
10+
11+
constfixtures=require('../../test/common/fixtures');
12+
letoptions;
13+
letrecvbuf;
14+
letreceived=0;
15+
consttls=require('tls');
16+
17+
functionmain({ dur, type, sendchunklen, recvbuflen, recvbufgenfn }){
18+
if(isFinite(recvbuflen)&&recvbuflen>0)
19+
recvbuf=Buffer.alloc(recvbuflen);
20+
21+
letencoding;
22+
letchunk;
23+
switch(type){
24+
case'buf':
25+
chunk=Buffer.alloc(sendchunklen,'b');
26+
break;
27+
case'asc':
28+
chunk='a'.repeat(sendchunklen);
29+
encoding='ascii';
30+
break;
31+
case'utf':
32+
chunk='ü'.repeat(sendchunklen/2);
33+
encoding='utf8';
34+
break;
35+
default:
36+
thrownewError('invalid type');
37+
}
38+
39+
options={
40+
key: fixtures.readKey('rsa_private.pem'),
41+
cert: fixtures.readKey('rsa_cert.crt'),
42+
ca: fixtures.readKey('rsa_ca.crt'),
43+
ciphers: 'AES256-GCM-SHA384'
44+
};
45+
46+
letsocketOpts;
47+
if(recvbuf===undefined){
48+
socketOpts={port: common.PORT,rejectUnauthorized: false};
49+
}else{
50+
letbuffer=recvbuf;
51+
if(recvbufgenfn==='true'){
52+
letbufidx=-1;
53+
constbufpool=[
54+
recvbuf,
55+
Buffer.from(recvbuf),
56+
Buffer.from(recvbuf),
57+
];
58+
buffer=()=>{
59+
bufidx=(bufidx+1)%bufpool.length;
60+
returnbufpool[bufidx];
61+
};
62+
}
63+
socketOpts={
64+
port: common.PORT,
65+
rejectUnauthorized: false,
66+
onread: {
67+
buffer,
68+
callback: function(nread,buf){
69+
received+=nread;
70+
}
71+
}
72+
};
73+
}
74+
75+
constserver=tls.createServer(options,(socket)=>{
76+
socket.on('data',(buf)=>{
77+
socket.on('drain',write);
78+
write();
79+
});
80+
81+
functionwrite(){
82+
while(false!==socket.write(chunk,encoding));
83+
}
84+
});
85+
86+
letconn;
87+
server.listen(common.PORT,()=>{
88+
conn=tls.connect(socketOpts,()=>{
89+
setTimeout(done,dur*1000);
90+
bench.start();
91+
conn.write('hello');
92+
});
93+
94+
conn.on('data',(chunk)=>{
95+
received+=chunk.length;
96+
});
97+
});
98+
99+
functiondone(){
100+
constmbits=(received*8)/(1024*1024);
101+
bench.end(mbits);
102+
process.exit(0);
103+
}
104+
}

‎doc/api/tls.md‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1343,6 +1343,9 @@ being issued by trusted CA (`options.ca`).
13431343
<!-- YAML
13441344
added: v0.11.3
13451345
changes:
1346+
- version: REPLACEME
1347+
pr-url: https://github.com/nodejs/node/pull/35753
1348+
description: Added `onread` option.
13461349
- version:
13471350
- v14.1.0
13481351
- v13.14.0
@@ -1456,6 +1459,10 @@ changes:
14561459
[`tls.createSecureContext()`][]. If a `secureContext` is _not_ provided, one
14571460
will be created by passing the entire `options` object to
14581461
`tls.createSecureContext()`.
1462+
*`onread` {Object} If the `socket` option is missing, incoming data is
1463+
stored in a single `buffer` and passed to the supplied `callback` when
1464+
data arrives on the socket, otherwise the option is ignored. See the
1465+
`onread` option of [`net.Socket`][] for details.
14591466
* ...: [`tls.createSecureContext()`][] options that are used if the
14601467
`secureContext` option is missing, otherwise they are ignored.
14611468
* ...: Any [`socket.connect()`][] option not already listed.

‎lib/_tls_wrap.js‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,7 @@ function TLSSocket(socket, opts) {
502502
pauseOnCreate: tlsOptions.pauseOnConnect,
503503
manualStart: true,
504504
highWaterMark: tlsOptions.highWaterMark,
505+
onread: !socket ? tlsOptions.onread : null,
505506
});
506507

507508
// Proxy for API compatibility
@@ -1592,6 +1593,7 @@ exports.connect = function connect(...args) {
15921593
enableTrace: options.enableTrace,
15931594
pskCallback: options.pskCallback,
15941595
highWaterMark: options.highWaterMark,
1596+
onread: options.onread,
15951597
});
15961598

15971599
tlssock[kConnectOptions]=options;

‎lib/net.js‎

Lines changed: 43 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -304,55 +304,54 @@ function Socket(options) {
304304
if(options.handle){
305305
this._handle=options.handle;// private
306306
this[async_id_symbol]=getNewAsyncId(this._handle);
307-
}else{
308-
constonread=options.onread;
309-
if(onread!==null&&typeofonread==='object'&&
310-
(isUint8Array(onread.buffer)||typeofonread.buffer==='function')&&
311-
typeofonread.callback==='function'){
312-
if(typeofonread.buffer==='function'){
313-
this[kBuffer]=true;
314-
this[kBufferGen]=onread.buffer;
315-
}else{
316-
this[kBuffer]=onread.buffer;
317-
}
318-
this[kBufferCb]=onread.callback;
319-
}
320-
if(options.fd!==undefined){
321-
const{ fd }=options;
322-
leterr;
307+
}elseif(options.fd!==undefined){
308+
const{ fd }=options;
309+
leterr;
323310

324-
// createHandle will throw ERR_INVALID_FD_TYPE if `fd` is not
325-
// a valid `PIPE` or `TCP` descriptor
326-
this._handle=createHandle(fd,false);
311+
// createHandle will throw ERR_INVALID_FD_TYPE if `fd` is not
312+
// a valid `PIPE` or `TCP` descriptor
313+
this._handle=createHandle(fd,false);
314+
315+
err=this._handle.open(fd);
316+
317+
// While difficult to fabricate, in some architectures
318+
// `open` may return an error code for valid file descriptors
319+
// which cannot be opened. This is difficult to test as most
320+
// un-openable fds will throw on `createHandle`
321+
if(err)
322+
throwerrnoException(err,'open');
327323

328-
err=this._handle.open(fd);
324+
this[async_id_symbol]=this._handle.getAsyncId();
329325

330-
// While difficult to fabricate, in some architectures
331-
// `open` may return an error code for valid file descriptors
332-
// which cannot be opened. This is difficult to test as most
333-
// un-openable fds will throw on `createHandle`
326+
if((fd===1||fd===2)&&
327+
(this._handleinstanceofPipe)&&isWindows){
328+
// Make stdout and stderr blocking on Windows
329+
err=this._handle.setBlocking(true);
334330
if(err)
335-
throwerrnoException(err,'open');
336-
337-
this[async_id_symbol]=this._handle.getAsyncId();
338-
339-
if((fd===1||fd===2)&&
340-
(this._handleinstanceofPipe)&&isWindows){
341-
// Make stdout and stderr blocking on Windows
342-
err=this._handle.setBlocking(true);
343-
if(err)
344-
throwerrnoException(err,'setBlocking');
345-
346-
this._writev=null;
347-
this._write=makeSyncWrite(fd);
348-
// makeSyncWrite adjusts this value like the original handle would, so
349-
// we need to let it do that by turning it into a writable, own
350-
// property.
351-
ObjectDefineProperty(this._handle,'bytesWritten',{
352-
value: 0,writable: true
353-
});
354-
}
331+
throwerrnoException(err,'setBlocking');
332+
333+
this._writev=null;
334+
this._write=makeSyncWrite(fd);
335+
// makeSyncWrite adjusts this value like the original handle would, so
336+
// we need to let it do that by turning it into a writable, own
337+
// property.
338+
ObjectDefineProperty(this._handle,'bytesWritten',{
339+
value: 0,writable: true
340+
});
341+
}
342+
}
343+
344+
constonread=options.onread;
345+
if(onread!==null&&typeofonread==='object'&&
346+
(isUint8Array(onread.buffer)||typeofonread.buffer==='function')&&
347+
typeofonread.callback==='function'){
348+
if(typeofonread.buffer==='function'){
349+
this[kBuffer]=true;
350+
this[kBufferGen]=onread.buffer;
351+
}else{
352+
this[kBuffer]=onread.buffer;
355353
}
354+
this[kBufferCb]=onread.callback;
356355
}
357356

358357
// Shut down the socket when we're finished with it.

0 commit comments

Comments
 (0)