savonet / liquidsoap

Liquidsoap is a statically typed scripting general-purpose language with dedicated operators and backend for all thing media, streaming, file generation, automation, HTTP backend and more.
http://liquidsoap.info
GNU General Public License v2.0
1.36k stars 121 forks source link

`output.file` causes shutdown on fail #2437

Open vitoyucepi opened 2 years ago

vitoyucepi commented 2 years ago

Describe the bug Using output.file to dump the source, causes shutdown if system error happened. If this happened, then there's no way you can intercept the error.

liquidsoap_1  | 2022/06/06 20:50:14 [input.harbor_0:3] Decoding...
liquidsoap_1  | [opus @ 0x7fe078042800] Could not update timestamps for skipped samples.
liquidsoap_1  | 2022/06/06 20:50:17 [clock.main:2] Source /restricted/path/test.ogg failed while streaming: Lang.Runtime_error { kind: "system", msg: Some "/restricted/path/test.ogg: Permission denied", pos: [] }!
liquidsoap_1  | 2022/06/06 20:50:17 [main:3] Shutdown started!
liquidsoap_1  | 2022/06/06 20:50:17 [main:3] Waiting for main threads to terminate...
liquidsoap_1  | 2022/06/06 20:50:17 [harbor:3] Removing mountpoint '/radio' on port 8000
liquidsoap_1  | 2022/06/06 20:50:17 [harbor:3] Nothing more on port 8000: closing sockets.
liquidsoap_1  | 2022/06/06 20:50:17 [clock.main:3] Streaming loop stopped.
liquidsoap_1  | 2022/06/06 20:50:18 [input.harbor_0:2] Error while reading from client: Bad file descriptor in read()
liquidsoap_1  | 2022/06/06 20:50:18 [input.harbor_0:2] Feeding stopped: Ffmpeg_decoder.End_of_file.
liquidsoap_1  | 2022/06/06 20:50:18 [main:3] Main threads terminated.
liquidsoap_1  | 2022/06/06 20:50:18 [threads:3] Shutting down scheduler...
liquidsoap_1  | 2022/06/06 20:50:18 [threads:3] Scheduler shut down.
liquidsoap_1  | 2022/06/06 20:50:18 [main:3] Cleaning downloaded files...
liquidsoap_1  | 2022/06/06 20:50:18 [main:3] Freeing memory...

To Reproduce The script to test, ensure /restricted/path/test.ogg will not accessible by liquidsoap.

default_harbor = input.harbor(
  port = 8000,
  user = "source",
  password = "hackme",
  buffer = 1.0,
  "radio"
)

output.file(%vorbis, "/restricted/path/test.ogg", default_harbor, fallible = true)

Expected behavior I think it's better to throw an exception instead of shutting down the server.

Version details

Install method Deb package from liquidsoap ci artifacts at github

Common issues N/A

toots commented 2 years ago

Thanks for this report. I am not sure yet how to deal with it. Streaming errors are major errors. How do you suggest one should catch and recover from it?

vitoyucepi commented 2 years ago

I use output.file to create archive of live streams. For me this means that the main consumer of the source is icecast.

I would rather ignore the error here than get a full stop. Also I think that the same will happen if the storage device will be full.

Nevertheless I could terminate server in error handler by myself.

toots commented 2 years ago

Thanks. That makes sense. I'll see what I can do.

vitoyucepi commented 2 months ago

Still there

1a262d49bd2cfb8457439e986c748a1a0317f8d4 ``` [clock:2] Source output_file failed while streaming: Lang.Runtime_error { kind: "system", msg: "Sys_error(\"/restricted/path/test.ogg: Permission denied\")", pos: [at stdlib.ml, line 331, char 26-26, at src/core/outputs/pipe_output.ml, line 530, char 31-31, at src/core/outputs/pipe_output.ml, line 480, char 36-36] }! [clock:2] Raised by primitive operation at Stdlib.open_out_gen in file "stdlib.ml", line 331, characters 29-55 [clock:2] Called from Pipe_output.file_output_using_encoder#open_out_gen in file "src/core/outputs/pipe_output.ml", line 530, characters 15-46 [clock:2] Called from Pipe_output.file_output_base#open_chan in file "src/core/outputs/pipe_output.ml", line 480, characters 8-44 [clock:2] Re-raised at Liquidsoap_lang__Lang_core.raise_as_runtime in file "src/lang/lang_core.ml", line 424, characters 8-146 [clock:2] Called from Pipe_output.chan_output#open_pipe in file "src/core/outputs/pipe_output.ml", line 415, characters 36-50 [clock:2] Called from Pipe_output.piped_output#prepare_pipe in file "src/core/outputs/pipe_output.ml", line 339, characters 6-20 [clock:2] Called from Start_stop.base#transition_to in file "src/core/tools/start_stop.ml", line 52, characters 12-22 [clock:2] Called from Output.output#output in file "src/core/outputs/output.ml", line 162, characters 8-41 [clock:2] Called from Pipe_output.piped_output#output in file "src/core/outputs/pipe_output.ml", line 370, characters 10-21 [clock:2] Re-raised at Pipe_output.piped_output#reopen_on_error in file "src/core/outputs/pipe_output.ml", line 362, characters 12-48 [clock:2] Called from Clock._tick.(fun) in file "src/core/clock.ml", line 404, characters 41-49 [clock:2] ```
c15ac2ea08f36e49014d8e06e583387d5e11aff5 ``` [clock.main:2] Source output_file failed while streaming: Lang.Runtime_error { kind: "system", msg: "Sys_error(\"/restricted/path/test.ogg: Permission denied\")", pos: [at stdlib.ml, line 331, char 26-26, at src/core/outputs/pipe_output.ml, line 524, char 31-31, at src/core/outputs/pipe_output.ml, line 475, char 36-36] }! [clock.main:2] Raised by primitive operation at Stdlib.open_out_gen in file "stdlib.ml", line 331, characters 29-55 [clock.main:2] Called from Pipe_output.file_output_using_encoder#open_out_gen in file "src/core/outputs/pipe_output.ml", line 524, characters 15-46 [clock.main:2] Called from Pipe_output.file_output_base#open_chan in file "src/core/outputs/pipe_output.ml", line 475, characters 8-44 [clock.main:2] Re-raised at Liquidsoap_lang__Lang_core.raise_as_runtime in file "src/lang/lang_core.ml", line 416, characters 8-146 [clock.main:2] Called from Pipe_output.chan_output#open_pipe in file "src/core/outputs/pipe_output.ml", line 412, characters 36-50 [clock.main:2] Called from Pipe_output.piped_output#prepare_pipe in file "src/core/outputs/pipe_output.ml", line 336, characters 6-20 [clock.main:2] Called from Start_stop.base#transition_to in file "src/core/tools/start_stop.ml", line 53, characters 12-22 [clock.main:2] Called from Output.output#output in file "src/core/outputs/output.ml", line 175, characters 8-41 [clock.main:2] Called from Pipe_output.piped_output#output in file "src/core/outputs/pipe_output.ml", line 367, characters 10-21 [clock.main:2] Re-raised at Pipe_output.piped_output#reopen_on_error in file "src/core/outputs/pipe_output.ml", line 359, characters 12-48 [clock.main:2] Called from Clock.MkClock.clock#end_tick.(fun) in file "src/core/clock.ml", line 318, characters 16-24 [clock.main:2] ```
toots commented 2 months ago

I think I could implement a generic error catching code in 2.3.x now that we have switched to OCaml 5 with effect handlers. I'll see if I can come up with something soon.