uNetworking / uWebSockets.js

μWebSockets for Node.js back-ends :metal:
Apache License 2.0
8.09k stars 577 forks source link

Video streaming example segfaults #736

Closed o5k closed 2 years ago

o5k commented 2 years ago

While going off of the VideoStreamer example to implement reading from a read stream, I'm hitting into a segfault. The example code alone is enough to cause this, so you should be able to repro on that alone. I've noticed that adding console.logs in a bunch of places (to try and figure out which call to any uWS function causes it, no luck) made the issue less common. Some kind of race condition perhaps...?

Is the VideoStreamer example still correct, or should reading from a large stream be implemented differently?

Exception thrown at 0x00000001402068F2 in node.exe: 0xC0000005: Access violation reading location 0x0000005F656C6309.

2022-04-26_20-45-43

I'm running Node v16.14.2 on Windows, and uWS.js 20.8.0.

ghost commented 2 years ago

Interesting. What are you doing to reproduce it?

o5k commented 2 years ago

Managed to reproduce on clean Win7 and Kubuntu 22.04 VMs too.

I simply install uWS 20.8.0 through npm, grab the example code, supply it my own video file for testing, and open it in browser. It doesn't always break, sometimes it needs a little work. Firefox makes it a bit easier, holding F5 there will cause it to happen soon enough...

Got a slightly better stack trace on the Kubuntu VM:

PID 10375 received SIGSEGV for address: 0x0
/home/kubuntu/test/node_modules/segfault-handler/build/Release/segfault-handler.node(+0x370d)[0x7fb0c17cc70d]
/lib/x86_64-linux-gnu/libc.so.6(+0x42520)[0x7fb0c12a3520]
node(_ZN2v88internal6Object12BooleanValueEPNS0_7IsolateE+0x4e)[0x10c324e]
node(_ZNK2v85Value12BooleanValueEPNS_7IsolateE+0x18)[0xd000f8]
/home/kubuntu/test/node_modules/uWebSockets.js/uws_linux_x64_93.node(_ZN5ofats10any_detail14handler_traitsIbJmEE13large_handlerIZN19HttpResponseWrapper14res_onWritableILb0EEEvRKN2v820FunctionCallbackInfoINS6_5ValueEEEEUlmE_E4callERNS0_7storageEm+0xa9)[0x7fb0b251df29]
/home/kubuntu/test/node_modules/uWebSockets.js/uws_linux_x64_93.node(_ZZN3uWS11HttpContextILb0EE4initEvENUlP11us_socket_tE_8__invokeES3_+0x28)[0x7fb0b2512088]
/home/kubuntu/test/node_modules/uWebSockets.js/uws_linux_x64_93.node(us_internal_dispatch_ready_poll+0xca)[0x7fb0b2520d0a]
node[0x1575af4]
node(uv_run+0x138)[0x1563d18]
node(_ZN4node13SpinEventLoopEPNS_11EnvironmentE+0x135)[0xa43dd5]
node(_ZN4node16NodeMainInstance3RunEPKNS_16EnvSerializeInfoE+0x196)[0xb4bab6]
node(_ZN4node5StartEiPPc+0x222)[0xacd3f2]
/lib/x86_64-linux-gnu/libc.so.6(+0x29d90)[0x7fb0c128ad90]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0x80)[0x7fb0c128ae40]
node[0xa4076c]
o5k commented 2 years ago

Also happens on node v18.0.0

o5k commented 2 years ago

Screen recording:

https://user-images.githubusercontent.com/52112045/165393607-a71263f1-951b-4e05-bbdc-7cab63cb4881.mp4

(I was holding F5 in Firefox to make it trigger as fast as possible; sometimes it can take a bit, other times it happens first try)

ghost commented 2 years ago

Very good report, will look at this

zdm commented 2 years ago

I have random segfaults for uws v20.8.0 node v18.0.0 under linux. Happens, when trying to use tryEnd with onWritable. Hard to say more about conditions when this is happens.

zdm commented 2 years ago

For me under windows no segfaults, only under linux.

o5k commented 2 years ago

~~Can't seem to reproduce it on a fresh Win8.1 (build 9600) install either, may be a Win7-only thing on the Windows side of things...? Strange that this issue is shared between Win7 and Linux, though~~

o5k commented 2 years ago

Can't seem to reproduce it on a fresh Win8.1 (build 9600) install either, may be a Win7-only thing on the Windows side of things...? Strange that this issue is shared between Win7 and Linux, though

Scratch that, can also reproduce on 8.1. Took a bit more work though, had to open multiple tabs and reload them all, but it'd still trip within at least 5000 reloads...? I'm not sure why it's harder to trigger it here, perhaps it's because of 8.1 being slower due to compositing, if still going off of the race condition hypothesis. Not sure. Same location in code:

2022-04-28_15-16-24 2022-04-28_15-25-37

Edit: Slightly easier repro is opening a bunch of tabs of the streaming video, selecting them all, then hitting F5 and letting the video play for about a second or so (so it loads some data), then refreshing all tabs, doing this a few times triggers relatively consistently on Win8.1 for me, while holding F5 can take a while (even though it works fine for other OSes...?)

ghost commented 2 years ago

I failed to reproduce on macos / chrome

zdm commented 2 years ago

For me it crashes on each ~10-th request using code from example. Pls, try to reproduce under linux and node 18.

On 28.04.2022 17:12, Alex Hultman wrote:

I failed to reproduce on macos / chrome

— Reply to this email directly, view it on GitHub https://github.com/uNetworking/uWebSockets.js/issues/736#issuecomment-1112257297, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAH2MSCKLK6HVOJ3WB5QHHLVHKMENANCNFSM5UMZQ32Q. You are receiving this because you commented.Message ID: @.***>

ghost commented 2 years ago

I'm running wrk with 40 connections downloading the video while I hit refresh in Chrome a billion times, no reproduce. Tested on macos and linux.

ghost commented 2 years ago

valgrind ./node-v18.0.0-linux-x64/bin/node examples/VideoStreamer.js ==8444== Memcheck, a memory error detector ==8444== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==8444== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info ==8444== Command: ./node-v18.0.0-linux-x64/bin/node examples/VideoStreamer.js ==8444== Video size is: 1172428172 bytes Listening to port 9001 Stream was opened, openStreams: 1 Stream was opened, openStreams: 2 Stream was opened, openStreams: 3 Stream was opened, openStreams: 4 Stream was opened, openStreams: 5 Stream was opened, openStreams: 6 Stream was opened, openStreams: 7 Stream was opened, openStreams: 8 Stream was opened, openStreams: 9 Stream was opened, openStreams: 10 Stream was opened, openStreams: 11 Stream was opened, openStreams: 12 Stream was opened, openStreams: 13 Stream was opened, openStreams: 14 Stream was opened, openStreams: 15 Stream was opened, openStreams: 16 Stream was opened, openStreams: 17 Stream was opened, openStreams: 18 Stream was opened, openStreams: 19 Stream was opened, openStreams: 20 Stream was opened, openStreams: 21 Stream was opened, openStreams: 22 Stream was opened, openStreams: 23 Stream was opened, openStreams: 24 Stream was opened, openStreams: 25 Stream was opened, openStreams: 26 Stream was opened, openStreams: 27 Stream was opened, openStreams: 28 Stream was opened, openStreams: 29 Stream was opened, openStreams: 30 Stream was opened, openStreams: 31 Stream was opened, openStreams: 32 Stream was opened, openStreams: 33 Stream was opened, openStreams: 34 Stream was opened, openStreams: 35 Stream was opened, openStreams: 36 Stream was opened, openStreams: 37 Stream was opened, openStreams: 38 Stream was opened, openStreams: 39 Stream was opened, openStreams: 40 Stream was opened, openStreams: 41 Stream was opened, openStreams: 42 Stream was closed, openStreams: 41 1: 33.086s Stream was closed, openStreams: 40 42: 231.474ms Stream was opened, openStreams: 41 Stream was opened, openStreams: 42 Stream was closed, openStreams: 41 43: 1.113s Stream was closed, openStreams: 40 44: 230.733ms Stream was opened, openStreams: 41 Stream was opened, openStreams: 42 Stream was closed, openStreams: 41 45: 193.252ms Stream was closed, openStreams: 40 46: 46.12ms Stream was opened, openStreams: 41 Stream was opened, openStreams: 42 Stream was closed, openStreams: 41 47: 536.224ms Stream was closed, openStreams: 40 48: 209.492ms Stream was opened, openStreams: 41 Stream was opened, openStreams: 42 Stream was closed, openStreams: 41 49: 413.561ms Stream was closed, openStreams: 40 50: 245.328ms Stream was opened, openStreams: 41 Stream was opened, openStreams: 42 Stream was closed, openStreams: 41 51: 419.589ms Stream was closed, openStreams: 40 52: 240.264ms Stream was opened, openStreams: 41 Stream was opened, openStreams: 42 Stream was closed, openStreams: 41 53: 364.119ms Stream was closed, openStreams: 40 54: 193.263ms Stream was opened, openStreams: 41 Stream was opened, openStreams: 42 Stream was closed, openStreams: 41 55: 488.034ms Stream was closed, openStreams: 40 56: 199.907ms Stream was opened, openStreams: 41 Stream was opened, openStreams: 42 Stream was closed, openStreams: 41 57: 317.499ms Stream was closed, openStreams: 40 58: 196.367ms Stream was opened, openStreams: 41 Stream was opened, openStreams: 42 Stream was closed, openStreams: 41 59: 354.499ms Stream was closed, openStreams: 40 60: 190.986ms Stream was opened, openStreams: 41 Stream was opened, openStreams: 42 Stream was closed, openStreams: 41 61: 355.409ms Stream was closed, openStreams: 40 62: 194.677ms Stream was opened, openStreams: 41 Stream was opened, openStreams: 42 Stream was closed, openStreams: 41 63: 362.016ms Stream was closed, openStreams: 40 64: 188.017ms Stream was opened, openStreams: 41 Stream was opened, openStreams: 42 Stream was closed, openStreams: 41 66: 181.963ms Stream was opened, openStreams: 42 Stream was opened, openStreams: 43 Stream was opened, openStreams: 44 Stream was closed, openStreams: 43 68: 202.428ms Stream was closed, openStreams: 42 69: 202.448ms Stream was opened, openStreams: 43 Stream was closed, openStreams: 42 41: 1:39.778 (m:ss.mmm) Stream was closed, openStreams: 41 39: 1:39.803 (m:ss.mmm) Stream was closed, openStreams: 40 37: 1:39.815 (m:ss.mmm) Stream was closed, openStreams: 39 36: 1:39.821 (m:ss.mmm) Stream was closed, openStreams: 38 32: 1:39.851 (m:ss.mmm) Stream was closed, openStreams: 37 28: 1:39.882 (m:ss.mmm) Stream was closed, openStreams: 36 27: 1:39.896 (m:ss.mmm) Stream was closed, openStreams: 35 24: 1:39.933 (m:ss.mmm) Stream was closed, openStreams: 34 23: 1:39.939 (m:ss.mmm) Stream was closed, openStreams: 33 19: 1:39.956 (m:ss.mmm) Stream was closed, openStreams: 32 15: 1:39.985 (m:ss.mmm) Stream was closed, openStreams: 31 14: 1:39.999 (m:ss.mmm) Stream was closed, openStreams: 30 13: 1:40.028 (m:ss.mmm) Stream was closed, openStreams: 29 11: 1:40.070 (m:ss.mmm) Stream was closed, openStreams: 28 10: 1:40.098 (m:ss.mmm) Stream was closed, openStreams: 27 9: 1:40.128 (m:ss.mmm) Stream was closed, openStreams: 26 3: 1:40.183 (m:ss.mmm) Stream was closed, openStreams: 25 2: 1:40.270 (m:ss.mmm) Stream was closed, openStreams: 24 25: 1:40.001 (m:ss.mmm) Stream was closed, openStreams: 23 5: 1:40.216 (m:ss.mmm) Stream was closed, openStreams: 22 4: 1:40.228 (m:ss.mmm) Stream was closed, openStreams: 21 34: 1:39.938 (m:ss.mmm) Stream was closed, openStreams: 20 6: 1:40.220 (m:ss.mmm) Stream was closed, openStreams: 19 31: 1:39.966 (m:ss.mmm) Stream was closed, openStreams: 18 40: 1:39.929 (m:ss.mmm) Stream was closed, openStreams: 17 26: 1:40.008 (m:ss.mmm) Stream was closed, openStreams: 16 35: 1:39.952 (m:ss.mmm) Stream was closed, openStreams: 15 7: 1:40.215 (m:ss.mmm) Stream was closed, openStreams: 14 30: 1:39.986 (m:ss.mmm) Stream was closed, openStreams: 13 17: 1:40.077 (m:ss.mmm) Stream was closed, openStreams: 12 20: 1:40.059 (m:ss.mmm) Stream was closed, openStreams: 11 12: 1:40.150 (m:ss.mmm) Stream was closed, openStreams: 10 22: 1:40.059 (m:ss.mmm) Stream was closed, openStreams: 9 18: 1:40.082 (m:ss.mmm) Stream was closed, openStreams: 8 16: 1:40.099 (m:ss.mmm) Stream was closed, openStreams: 7 8: 1:40.240 (m:ss.mmm) Stream was closed, openStreams: 6 33: 1:39.994 (m:ss.mmm) Stream was closed, openStreams: 5 29: 1:40.022 (m:ss.mmm) Stream was closed, openStreams: 4 21: 1:40.084 (m:ss.mmm) Stream was closed, openStreams: 3 38: 1:39.990 (m:ss.mmm) Stream was closed, openStreams: 2 70: 3.308s Stream was opened, openStreams: 3 Stream was opened, openStreams: 4 Stream was opened, openStreams: 5 Stream was closed, openStreams: 4 65: 1:53.549 (m:ss.mmm) Stream was closed, openStreams: 3 73: 71.372ms Stream was opened, openStreams: 4 Stream was opened, openStreams: 5 Stream was closed, openStreams: 4 67: 1:28.967 (m:ss.mmm) Stream was closed, openStreams: 3 75: 55.498ms Stream was opened, openStreams: 4 Stream was opened, openStreams: 5 Stream was closed, openStreams: 4 72: 14.581s Stream was closed, openStreams: 3 77: 43.338ms Stream was opened, openStreams: 4 Stream was opened, openStreams: 5 Stream was closed, openStreams: 4 71: 51.349s Stream was closed, openStreams: 3 79: 44.682ms Stream was opened, openStreams: 4

Wyzix33 commented 2 years ago

i was able to reproduce it using window 10 FF and the server was on codesandbox https://codesandbox.io/s/cool-star-f89q0r?file=/src/index.js here is a recording, sorry for the sound forgot to turn it down .. I was pressing F5 every second or so, not holding it

https://user-images.githubusercontent.com/13553412/165785667-8d965cfa-5668-4062-a269-79206d3c521e.mp4

Thanks

ghost commented 2 years ago

I cannot reproduce anything

ghost commented 2 years ago

I cannot even get Firefox to show the video. Only chrome works and I've refreshed two gazillion times. How far back, uWS version, can you trigger this?

Wyzix33 commented 2 years ago

I've tried with node 16.13.2 and uws 19.5.0, it crashes without any message on second refresh 4 windows opened, I think I can see the video on FF because of VLC

C:\github>node -v
v16.13.2

C:\github>yarn add uWebSockets.js@uNetworking/uWebSockets.js#v19.5.0
yarn add v1.22.18
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...

success Saved 0 new dependencies.
Done in 1.09s.

C:\github>node app.js
Video size is: 7292510 bytes
Listening to port 443
Stream was opened, openStreams: 1
Stream was opened, openStreams: 2
Stream was opened, openStreams: 3
Stream was opened, openStreams: 4
Stream was closed, openStreams: 3
2: 384.986ms
Stream was closed, openStreams: 2
4: 504.726ms
Stream was closed, openStreams: 1
1: 1.935s
Stream was closed, openStreams: 0
3: 1.939s
Stream was opened, openStreams: 1
Stream was opened, openStreams: 2
Stream was opened, openStreams: 3
Stream was opened, openStreams: 4
Stream was closed, openStreams: 3
5: 228.084ms

C:\github>

https://user-images.githubusercontent.com/13553412/165807424-e7af9222-9fa3-4df5-98ef-0a3709309f35.mp4

Wyzix33 commented 2 years ago

Unable to reproduce with uWebSockets.js@18.0.0 and node 14.19.1 Do you want me to test all versions from 18 to 20 to see the first that introduced this bug?

Wyzix33 commented 2 years ago

Seems that the first version that introduced this bug was v19.0.0, i tested with node v14.19.1 and was unable to reproduce it with older versions than 19... Hope it helps

C:\github>node -v
v14.19.1

C:\github>yarn add uWebSockets.js@uNetworking/uWebSockets.js#v19.0.0
yarn add v1.22.18
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved 0 new dependencies.
Done in 1.43s.

C:\github>node -v
v14.19.1

C:\github>node app.js
Video size is: 7292510 bytes
Listening to port 443
Stream was opened, openStreams: 1
Stream was opened, openStreams: 2
Stream was opened, openStreams: 3
Stream was opened, openStreams: 4
Stream was opened, openStreams: 5
Stream was opened, openStreams: 6
Stream was closed, openStreams: 5
2: 560.909ms
Stream was closed, openStreams: 4
5: 607.139ms
Stream was closed, openStreams: 3
6: 695.844ms
Stream was opened, openStreams: 4
Stream was closed, openStreams: 3
1: 1.022s
Stream was closed, openStreams: 2
7: 147.871ms
Stream was closed, openStreams: 1
3: 1.123s
Stream was opened, openStreams: 2
Stream was closed, openStreams: 1
4: 1.207s
Stream was closed, openStreams: 0
8: 129.966ms
Stream was opened, openStreams: 1
Stream was closed, openStreams: 0
9: 117.088ms
Stream was opened, openStreams: 1
Stream was closed, openStreams: 0
10: 170.197ms
Stream was opened, openStreams: 1
Stream was opened, openStreams: 2
Stream was opened, openStreams: 3
Stream was opened, openStreams: 4
Stream was opened, openStreams: 5
Stream was opened, openStreams: 6
Stream was closed, openStreams: 5
14: 626.023ms
Stream was closed, openStreams: 4
12: 871.169ms
Stream was closed, openStreams: 3
15: 883.192ms
Stream was closed, openStreams: 2
13: 974.058ms
Stream was closed, openStreams: 1
11: 1.036s
Stream was opened, openStreams: 2
Stream was closed, openStreams: 1
16: 1.324s
Stream was closed, openStreams: 0
17: 183.731ms
Stream was opened, openStreams: 1
Stream was closed, openStreams: 0
18: 182.47ms

C:\github>
ghost commented 2 years ago

Are you all using SSL?

ghost commented 2 years ago

What about v18.14.0

Wyzix33 commented 2 years ago

Unable to reproduce it on 18.14.0, I'm trying with SSL because that's how I use uws... but on codesandbox it was without SSL

o5k commented 2 years ago

I'm not using SSL. With some testing, can't seem to reproduce it on Kubuntu 20.04, while 22.04 shows it. Not sure

zdm commented 2 years ago

Code to reproduce, you need linux and node 18

#!/usr/bin/env node

import http from "http";
import uws from "uWebSockets.js";
import fs from "fs";

const app = uws.App().get( "/*", ( res, req ) => {
    const stream = fs.createReadStream( process.argv[0] );

    res.onAborted( () => stream.destroy() );

    stream.once( "end", () => res.end() );

    stream.on( "data", buffer => {
        const chunk = buffer.buffer.slice( buffer.byteOffset, buffer.byteOffset + buffer.byteLength );

        const ok = res.write( chunk );

        if ( !ok ) {
            stream.pause();

            res.onWritable( offset => {
                stream.resume();

                return true;
            } );
        }
    } );
} );

await new Promise( resolve => app.listen( 80, resolve ) );

var n = 0;

while ( ++n ) {
    console.log( n );

    await new Promise( resolve => {
        http.request( "http://127.0.0.1/", {}, res => {
            res.resume();
            res.once( "end", resolve );
        } ).end();
    } );
}

package.json

{
    "type": "module",
    "dependencies": {
        "uWebSockets.js": "github:uNetworking/uWebSockets.js#semver:>=20.8.0"
    }
}
zdm commented 2 years ago
image
ghost commented 2 years ago
Screenshot 2022-04-29 at 01 48 52
Wyzix33 commented 2 years ago

I was unable to reproduce it with this code on windows 10 and Ubuntu 20.04 but once i change the code a bit:

40
41
42
43
44
node:events:505
      throw er; // Unhandled 'error' event
      ^

Error: read ECONNRESET
    at TCP.onStreamRead (node:internal/stream_base_commons:217:20)
Emitted 'error' event on ClientRequest instance at:
    at Socket.socketErrorListener (node:_http_client:454:9)
    at Socket.emit (node:events:527:28)
    at emitErrorNT (node:internal/streams/destroy:151:8)
    at emitErrorCloseNT (node:internal/streams/destroy:116:3)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
  errno: -104,
  code: 'ECONNRESET',
  syscall: 'read'
}

Node.js v18.0.0

here are the changes i made,

#!/usr/bin/env node

import http from 'http';
import uws from 'uWebSockets.js';
import fs from 'fs';

const app = uws.App().get('/*', (res, req) => {
 const stream = fs.createReadStream('1.mp4');
 res.onAborted(() => stream.destroy());

 stream.once('end', () => res.end());

 stream.on('data', (buffer) => {
  const chunk = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);

  const ok = res.write(chunk);

  if (!ok) {
   stream.pause();

   res.onWritable((offset) => {
    stream.resume();

    return true;
   });
  }
 });
});

await new Promise((resolve) => app.listen(80, resolve));

var n = 0;

while (++n) {
 console.log(n);

 await new Promise((resolve) => {
  http
   .request('http://analitic.go.ro/', {}, (res) => {
    res.resume();
    res.once('end', resolve);
   })
   .end();
 });
}

basically

i changed that process.argv[0] because in my environment array was [ 'C:\\Program Files\\nodejs\\node.exe', 'C:\\github\\ws.js', '1.mp4' ] so it wasn't reading the right file and i changed the request ip from 127.0.0.1 to my dynamic DNS address, this made the counting go slower and the server has just stopped on windows at 668 and throw that error on Ubuntu...

Hope it helps.

zdm commented 2 years ago

process.argv[0] is correct, because we just need any file with the meangfull size. process.argv[0] is the path to the nodejs interpreter, that has several megabytes, that is enough for our test.

Wyzix33 commented 2 years ago

You are right :) so the only thing that helps me reproduce this bug is the dynamic DNS i have from my provider, using localhost/127.0.0.1 i'm unable to reproduce on Ubuntu (WSL 2) or Windows, both on the same laptop

zdm commented 2 years ago

Crashes are random, sometimes it does not crashes, but usually for me it crashes between 200 and 400 requests. This is unpredictable.

zdm commented 2 years ago

And for me it doesn't crashes under windows 11 at all, only under linux. My linux is ubuntu 22.04, but i don;t this that this is important.

Wyzix33 commented 2 years ago

@zdm can you try reproduce it using v18.14.0 using node 14?

o5k commented 2 years ago

https://user-images.githubusercontent.com/52112045/165934601-6c242632-9dc5-41ae-be26-609253cde98f.mp4

Here's a step-by-step guide to reproduce on a fresh Kubuntu 22.04 live session It still seems to be rather platform/OS-dependant though, make sure to try this specific setup to debug.. I can't test macOS

ghost commented 2 years ago

I'm going to port VideoStreamer to C++ and then you can test if it reproduces there. If not, then this is isolated to Node.js addon.

ghost commented 2 years ago

Does this reproduce it? You need to replace fileName.

const uWS = require('uWebSockets.js');
const fs = require('fs');

const port = 9001;
const fileName = '/Users/alexhultman/Downloads/sintel(1).mkv';
const videoFile = toArrayBuffer(fs.readFileSync(fileName));
const totalSize = videoFile.byteLength;

console.log('Video size is: ' + totalSize + ' bytes');

/* Helper function converting Node.js buffer to ArrayBuffer */
function toArrayBuffer(buffer) {
  return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset +
buffer.byteLength);
}

/* Yes, you can easily swap to SSL streaming by uncommenting here */
const app = uWS.App({
  key_file_name: 'misc/key.pem',
  cert_file_name: 'misc/cert.pem',
  passphrase: '1234'
}).get('/sintel.mkv', (res, req) => {
  console.log('Streaming video...');
  let [ok, done] = res.tryEnd(videoFile);
  if (!ok) {
    res.onWritable((offset) => {
      let [ok, done] = res.tryEnd(videoFile.slice(offset));

      return ok;
    });
    res.onAborted(() => {});
  }
}).get('/*', (res, req) => {
  /* Make sure to always handle every route */
  res.end('Nothing to see here!');
}).listen(port, (token) => {
  if (token) {
    console.log('Listening to port ' + port);
  } else {
    console.log('Failed to listen to port ' + port);
  }
});
Wyzix33 commented 2 years ago

getting

Listening to port 443
Streaming video...
Error: Returning from a request handler without responding or attaching an abort handler is forbidden!
PS C:\github> 

i've modified the script like this:

const uWS = require('uWebSockets.js');
const fs = require('fs');
const https = require('https');
const port = 443;
const fileName = '1.mp4';
const videoFile = toArrayBuffer(fs.readFileSync(fileName));
const totalSize = videoFile.byteLength;

console.log('Video size is: ' + totalSize + ' bytes');

/* Helper function converting Node.js buffer to ArrayBuffer */
function toArrayBuffer(buffer) {
 return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
}
let i = 0;
/* Yes, you can easily swap to SSL streaming by uncommenting here */
const app = uWS
 .SSLApp({
  key_file_name: 'privkey.pem',
  cert_file_name: 'fullchain.pem',
 })
 .get('/1.mp4', (res, req) => {
  res.onAborted(() => {
   res.aborted = true;
  });
  console.log('Streaming video...', i++);
  let [ok, done] = res.tryEnd(videoFile);
  if (!ok) {
   res.onWritable((offset) => {
    //if (res.aborted) return;
    let [ok, done] = res.tryEnd(videoFile.slice(offset));

    return ok;
   });
  }
 })
 .get('/*', (res, req) => {
  /* Make sure to always handle every route */
  res.end('Nothing to see here!');
 })
 .listen(port, (token) => {
  if (token) {
   console.log('Listening to port ' + port);
  } else {
   console.log('Failed to listen to port ' + port);
  }
 });
let completed_requests = 0;
let x = 0;
while (x < 1000) {
 x++;
 https.get('https://analitic.go.ro/1.mp4', function (res) {
  completed_requests++;
  if (completed_requests == 999) {
   // All download done, process responses array
   console.log({ completed_requests });
  }
 });
}

i got

Streaming video... 591
Streaming video... 592
Streaming video... 593
Streaming video... 594
Streaming video... 595
node:events:505
      throw er; // Unhandled 'error' event
      ^

Error: read ECONNRESET
    at TLSWrap.onStreamRead (node:internal/stream_base_commons:217:20)
Emitted 'error' event on ClientRequest instance at:
    at TLSSocket.socketErrorListener (node:_http_client:454:9)
    at TLSSocket.emit (node:events:527:28)
    at emitErrorNT (node:internal/streams/destroy:151:8)
    at emitErrorCloseNT (node:internal/streams/destroy:116:3)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
  errno: -4077,
  code: 'ECONNRESET',
  syscall: 'read'
}

Node.js v18.0.0
PS C:\github> 

tested on windows 10

ghost commented 2 years ago

See my edited code. Try and reproduce with it.

Wyzix33 commented 2 years ago

Sadly .. yes


const uWS = require('uWebSockets.js');
const fs = require('fs');
const http = require('http');

const port = 80;
const fileName = '1.mp4';
const videoFile = toArrayBuffer(fs.readFileSync(fileName));
const totalSize = videoFile.byteLength;

console.log('Video size is: ' + totalSize + ' bytes');

/* Helper function converting Node.js buffer to ArrayBuffer */
function toArrayBuffer(buffer) {
 return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
}
let i = 0;
/* Yes, you can easily swap to SSL streaming by uncommenting here */
const app = uWS
 .App({
  // key_file_name: 'misc/key.pem',
  // cert_file_name: 'misc/cert.pem',
  // passphrase: '1234',
 })
 .get('/1.mp4', (res, req) => {
  console.log('Streaming video...',i++);
  let [ok, done] = res.tryEnd(videoFile);
  if (!ok) {
   res.onWritable((offset) => {
    let [ok, done] = res.tryEnd(videoFile.slice(offset));

    return ok;
   });
   res.onAborted(() => {});
  }
 })
 .get('/*', (res, req) => {
  /* Make sure to always handle every route */
  res.end('Nothing to see here!');
 })
 .listen(port, (token) => {
  if (token) {
   console.log('Listening to port ' + port);
  } else {
   console.log('Failed to listen to port ' + port);
  }
 });

let completed_requests = 0;
let x = 0;
while (x < 10000) {
 x++;
 http.get('http://analitic.go.ro/1.mp4', function (res) {
  completed_requests++;
  if (completed_requests == 9999) {
   // All download done, process responses array
   console.log({ completed_requests });
  }
 });
}

dies after about 1500 streaming videos

Streaming video... 1348
Streaming video... 1349
node:events:505
      throw er; // Unhandled 'error' event
      ^

Error: connect ENOBUFS 188.27.251.150:80 - Local (undefined:undefined)
    at internalConnect (node:net:959:16)
    at defaultTriggerAsyncIdScope (node:internal/async_hooks:463:18)
    at GetAddrInfoReqWrap.emitLookup [as callback] (node:net:1105:9)
    at GetAddrInfoReqWrap.onlookup [as oncomplete] (node:dns:85:8)
Emitted 'error' event on ClientRequest instance at:
    at Socket.socketErrorListener (node:_http_client:454:9)
    at Socket.emit (node:events:527:28)
    at emitErrorNT (node:internal/streams/destroy:151:8)
    at emitErrorCloseNT (node:internal/streams/destroy:116:3)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
  errno: -4060,
  code: 'ENOBUFS',
  syscall: 'connect',
  address: '188.27.251.150',
  port: 80
}

Node.js v18.0.0

c:\github>

will try ssl too

ghost commented 2 years ago

None of those are reproduces, we want a segfault not nodejs error

zdm commented 2 years ago

did you tried under linux?

On 29.04.2022 23:36, Alex Hultman wrote:

None of those are reproduces, we want a segfault not nodejs error

— Reply to this email directly, view it on GitHub https://github.com/uNetworking/uWebSockets.js/issues/736#issuecomment-1113707102, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAH2MSGYW5VTGCRDXQARLC3VHRB6PANCNFSM5UMZQ32Q. You are receiving this because you were mentioned.Message ID: @.***>

Wyzix33 commented 2 years ago

i'm getting the same thing in linux too...

Streaming video... 2244
Streaming video... 2245
node:events:505
      throw er; // Unhandled 'error' event
      ^

Error: read ECONNRESET
    at TCP.onStreamRead (node:internal/stream_base_commons:217:20)
Emitted 'error' event on ClientRequest instance at:
    at Socket.socketErrorListener (node:_http_client:454:9)
    at Socket.emit (node:events:527:28)
    at emitErrorNT (node:internal/streams/destroy:151:8)
    at emitErrorCloseNT (node:internal/streams/destroy:116:3)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
  errno: -104,
  code: 'ECONNRESET',
  syscall: 'read'
}

Node.js v18.0.0
root@MSI:/mnt/c/github#

do i need to enable something to see segfaults?

zdm commented 2 years ago

By the way, it doesnt crashes when tryEnd + onWritable used, only when write + onWritable. Maybe this can help.

On 29.04.2022 23:51, Fabriel wrote:

i'm getting the same thing in linux too...

|Streaming video... 2244 Streaming video... 2245 node:events:505 throw er; // Unhandled 'error' event ^ Error: read ECONNRESET at TCP.onStreamRead (node:internal/stream_base_commons:217:20) Emitted 'error' event on ClientRequest instance at: at Socket.socketErrorListener (node:_http_client:454:9) at Socket.emit (node:events:527:28) at emitErrorNT (node:internal/streams/destroy:151:8) at emitErrorCloseNT (node:internal/streams/destroy:116:3) at process.processTicksAndRejections (node:internal/process/task_queues:82:21) { errno: -104, code: 'ECONNRESET', syscall: 'read' } Node.js v18.0.0 @.***:/mnt/c/github# |

do i need to enable something to see segfaults?

— Reply to this email directly, view it on GitHub https://github.com/uNetworking/uWebSockets.js/issues/736#issuecomment-1113716323, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAH2MSAQEQJEIJQHINLGWOTVHRDV3ANCNFSM5UMZQ32Q. You are receiving this because you were mentioned.Message ID: @.***>

ghost commented 2 years ago

Does this reproduce it? You need to replace fileName.

const uWS = require('uWebSockets.js');
const fs = require('fs');

const port = 9001;
const fileName = '/Users/alexhultman/Downloads/sintel(1).mkv';
const videoFile = toArrayBuffer(fs.readFileSync(fileName));
const totalSize = videoFile.byteLength;

console.log('Video size is: ' + totalSize + ' bytes');

/* Helper function converting Node.js buffer to ArrayBuffer */
function toArrayBuffer(buffer) {
  return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset +
buffer.byteLength);
}

/* Yes, you can easily swap to SSL streaming by uncommenting here */
const app = uWS.App({
  key_file_name: 'misc/key.pem',
  cert_file_name: 'misc/cert.pem',
  passphrase: '1234'
}).get('/sintel.mkv', (res, req) => {
  console.log('Streaming video...');
  let [ok, done] = res.tryEnd(videoFile);
  if (!ok) {
    res.onWritable((offset) => {
      let [ok, done] = res.tryEnd(videoFile.slice(offset));

      return ok;
    });
    res.onAborted(() => {});
  }
}).get('/*', (res, req) => {
  /* Make sure to always handle every route */
  res.end('Nothing to see here!');
}).listen(port, (token) => {
  if (token) {
    console.log('Listening to port ' + port);
  } else {
    console.log('Failed to listen to port ' + port);
  }
});

I need a segfault from this code, or small variation of it. I haven't reproduced anything so far, and I have made a fuzzing C++ case that runs without any issues, so unless something like this snippet can reproduce it without anything involving Node.js 'fs' module, I cannot continue with this as an issue.

o5k commented 2 years ago

Does this reproduce it? You need to replace fileName.

That doesn't reproduce for me as far as I can tell, not on Win7 and not on Kubuntu 22.04 either. Similar code has been working flawlessly in testing for me in my implementation for sending smaller responses. I'd presume it has something to do with sending the data received from a read stream...

Wyzix33 commented 2 years ago

Tried on ubuntu 20.04 and the last version doesn't crash, but had to use node 16, will update my server to 22.04 and will try again

zdm commented 2 years ago

I don't know how to make it reproduceable for everybody. For me it crashes constantly and this is real problem.

ghost commented 2 years ago

I don't know how to make it reproduceable for everybody. For me it crashes constantly and this is real problem.

You can reproduce using the snippet I posted in this thread?

zdm commented 2 years ago

With your code - it works. I wrote, that it crashes only when write + onWritable used. With tryEnd + onWritable - it works fine.

o5k commented 2 years ago

With tryEnd + onWritable - it works fine.

Does the original issue (node readstream + tryEnd + onWritable) not segfault for you, then? You said at the start of this issue it was tryEnd + onWritable that has issues for you...? I'm a bit confused now...

ghost commented 2 years ago

I don't care about nodejs file streams - I cannot reproduce anything here whatsoever.

If I'm going to look at this, people need to give mea small sample that uses nothing other than uWS - give me one such snippet that triggers it and I can look at it.

For all I know as of now - VideoStreamer example is buggy and incorrect in some way