diff --git a/CMakeLists.txt b/CMakeLists.txt
index b03bbd6..61f6d5e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -58,7 +58,8 @@ target_link_libraries( uxplay
install( TARGETS uxplay RUNTIME DESTINATION bin )
install( FILES uxplay.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 )
install( FILES README.md README.txt README.html LICENSE DESTINATION ${CMAKE_INSTALL_DOCDIR} )
-install( FILES lib/llhttp/LICENSE-MIT DESTINATION ${CMAKE_INSTALL_DOCDIR}/llhttp )
+install( FILES lib/llhttp/LICENSE-MIT DESTINATION ${CMAKE_INSTALL_DOCDIR}/llhttp )
+install( FILES uxplay.service DESTINATION ${CMAKE_INSTALL_DOCDIR}/systemd )
# uninstall target
if(NOT TARGET uninstall)
diff --git a/README.html b/README.html
index a441989..d647f50 100644
--- a/README.html
+++ b/README.html
@@ -1,19 +1,46 @@
Since UxPlay-1.64, UxPlay can be started with options read from a
@@ -494,8 +560,12 @@ option: see “-pin” and “-reg” in Usage for details, if you wish to use it. Some
clients with MDM (Mobile Device Management, often present on
employer-owned devices) are required to use pin-authentication: UxPlay
-will provide this even when running without the pin
-option.
+will provide this even when running without the pin option.
+Password authentication (-pw By default, GStreamer uses an algorithm to search for the best
“videosink” (GStreamer’s term for a graphics driver to display images)
@@ -679,10 +751,9 @@ framebuffer video, use <videosink> =
Sound and video will play on the remote host; “nohup” will keep
uxplay running if the ssh session is closed. Terminal output is saved to
FILE (which can be /dev/null to discard it)
@@ -690,10 +761,10 @@ FILE (which can be /dev/null to discard it)
id="building-uxplay-on-macos-intel-x86_64-and-apple-silicon-m1m2-macs">Building
UxPlay on macOS: These instructions for macOS assume that the Xcode command-line
developer tools are installed (if Xcode is installed, open the Terminal,
type “sudo xcode-select –install” and accept the conditions).
@@ -753,23 +824,16 @@ not supply a complete GStreamer, but seems to have everything needed for
UxPlay). After installing GStreamer, build and install uxplay: open a terminal
and change into the UxPlay source directory (“UxPlay-master” for zipfile
downloads, “UxPlay” for “git clone” downloads) and build/install with
@@ -780,27 +844,22 @@ with “export GST_DEBUG=2” before runnng UxPlay) reveals that with the
default (since UxPlay 1.64) use of timestamps for video synchonization,
many video frames are being dropped (only on macOS), perhaps due to
another error (about videometa) that shows up in the GStreamer warnings.
-Recommendation: use the new UxPlay “no timestamp” option
+Recommendation: use the UxPlay “no timestamp” option
“-vsync no” (you can add a line “vsync no” in the
uxplayrc configuration file).
We will simply build UxPlay from the command line in the MSYS2
+environment (using “ninja” in place of “make”
+for the build system).
- libav
- plugins-good
@@ -886,9 +965,9 @@ Settings->Update and Security->Windows Security->Firewall &
network protection -> allow an app through firewall. If your
virus protection flags uxplay.exe as “suspicious” (but without a true
malware signature) you may need to give it an exception.
-Now test by running “uxplay” (in a MSYS2 terminal
-window). If you need to specify the audiosink, there are two main
-choices on Windows: the older DirectSound plugin
+
Now test by running “uxplay” (in a MSYS2 UCRT64 terminal
+window. If you need to specify the audiosink, there are two main choices
+on Windows: the older DirectSound plugin
“-as directsoundsink”, and the more modern Windows Audio
Session API (wasapi) plugin “-as wasapisink”, which
supports device” is not specified, the default audio device is
used.
If you wish to specify the videosink using the
-vs <videosink> option, some choices for
-<videosink> are d3d11videosink,
-d3dvideosink, glimagesink,
-gtksink.
+<videosink> are d3d12videosink,
+d3d11videosink, d3dvideosink,
+glimagesink, gtksink,
+autovideosink. If you do not specify the videosink, the
+d3d11videosink will be used (users have reported segfaults of the newer
+d3d12 videodecoder on certain older Nvidia cards when the image
+resolution changes: d3d11 will used by default until this is fixed).
-- With Direct3D 11.0 or greater, you can either always be in
-fullscreen mode using option
-
-vs "d3d11videosink fullscreen-toggle-mode=property fullscreen=true",
-or get the ability to toggle into and out of fullscreen mode using the
-Alt-Enter key combination with option
--vs "d3d11videosink fullscreen-toggle-mode=alt-enter". For
-convenience, these options will be added if just
--vs d3d11videosink with or without the fullscreen option
-“-fs” is used. (Windows users may wish to add
-“vs d3d11videosink” (no initial “-”) to the
-UxPlay startup options file; see “man uxplay” or “uxplay -h”.)
+- With Direct3D 11.0 or greater, various options can be set using
+e.g.
-vs "d3d11videosink <options>" (see the
+gstreamer videosink documentation for these videosinks). For
+convenience, if no <options> are set, the option to
+toggle in and out of fullscreen mode with the Alt-Enter key combination
+is added.
The executable uxplay.exe can also be run without the MSYS2
environment, in the Windows Terminal, with
-C:\msys64\mingw64\bin\uxplay.
+C:\msys64\ucrt64\bin\uxplay.
Usage
Options:
@@ -933,6 +1011,9 @@ or ~/.config/uxplayrc); lines begining with
“#” are treated as comments, and ignored. Command line
options supersede options in the startup file.
+-rc file can also be used to specify the
+startup file location: this overrides $UXPLAYRC,
+~/.uxplayrc, etc.
-n server_name (Default: UxPlay);
server_name@_hostname_ will be the name that appears offering AirPlay
services to your iPad, iPhone etc, where hostname is the name
@@ -953,10 +1034,14 @@ and some iPhones) can send h265 video if a resolution “-s wxh” with h
> 1080 is requested. The “-h265” option changes the default
resolution (“-s” option) from 1920x1080 to 3840x2160, and leaves default
maximum framerate (“-fps” option) at 30fps.
--hls Activate HTTP Live Streaming support. With this
-option YouTube videos can be streamed directly from YouTube servers to
-UxPlay (without passing through the client) by clicking on the AirPlay
-icon in the YouTube app.
+-hls [v] Activate HTTP Live Streaming support. With
+this option YouTube videos can be streamed directly from YouTube servers
+to UxPlay (without passing through the client) by clicking on the
+AirPlay icon in the YouTube app. Optional [v] (allowed values 2 or 3,
+default: 3) allows selection of the version of GStreamer’s "playbin"
+video player to use for playing HLS video. (Playbin v3 is the
+recommended player, but if some videos fail to play, you can try with
+version 2.)
-pin [nnnn]: (since v1.67) use Apple-style
(one-time) “pin” authentication when a new client connects for the first
time: a four-digit pin code is displayed on the terminal, and the client
@@ -983,6 +1068,17 @@ key (base-64 format), Device ID, and Device name; commenting out (with
options -restrict, -block, -allow for more ways to control client
access). (Add a line “reg” in the startup file if you wish to use
this feature.)
+-pw [pwd]. (since 1.72). As an alternative
+to -pin, client access can be controlled with a password set when uxplay
+starts (set it in the .uxplay startup file, where it is stored as
+cleartext.) All users must then know this password. This uses HTTP md5
+Digest authentication, which is now regarded as providing weak security,
+but it is only used to validate the uxplay password, and no user
+credentials are exposed. If pwd is not
+specified, a random 4-digit pin code is displayed, and must be entered
+on the client at each new connection. Note: -pin
+and -pw are alternatives: if both are specified at startup, the earlier
+of these two options is discarded.
-vsync [x] (In Mirror mode:) this option
(now the default) uses timestamps to synchronize audio
with video on the server, with an optional audio delay in (decimal)
@@ -1030,6 +1126,9 @@ each time the length of the volume slider (or the number of steps above
mute, where 16 steps = full volume) is reduced by 50%, the perceived
volume is halved (a 10dB attenuation). (This is modified at low volumes,
to use the “untapered” volume if it is louder.)
+-vol v Sets initial audio-streaming volume
+(on client): range is [0:1], with 0.0 = mute, 1.0 = full volume
+(v is a decimal number).
-s wxh e.g. -s 1920x1080 (= “1080p”), the default
width and height resolutions in pixels for h264 video. (The default
becomes 3840x2160 (= “4K”) when the -h265 option is used.) This is just
@@ -1049,8 +1148,8 @@ an empty boundary frame of unused pixels (which would be lost in a
full-screen display that overscans, and is not displayed by gstreamer).
Recommendation: don’t use this option unless there is
some special reason to use it.
--fs uses fullscreen mode, but only works with X11,
-Wayland, VAAPI, and D3D11 (Windows).
+-fs uses fullscreen mode, but currently only works
+with X11, Wayland, VAAPI, kms and D3D11 (Windows).
-p allows you to select the network ports used by
UxPlay (these need to be opened if the server is behind a firewall). By
itself, -p sets “legacy” ports TCP 7100, 7000, 7001, UDP 6000, 6001,
@@ -1144,6 +1243,9 @@ client. Values in the range [0.0, 10.0] seconds are allowed, and will be
converted to a whole number of microseconds. Default is 0.25 sec (250000
usec). (However, the client appears to ignore this reported latency,
so this option seems non-functional.)
+-ca (without specifying a filename) now displays
+“cover art” that accompanies Apple Music when played in “Audio-only”
+(ALAC) mode.
-ca filename provides a file (where
filename can include a full path) used for output of “cover
art” (from Apple Music, etc.,) in audio-only ALAC mode. This
@@ -1158,17 +1260,22 @@ then run the the image viewer in the foreground. Example, using
in which uxplay was put into the background). To quit, use
ctrl-C fg ctrl-C to terminate the image viewer, bring
uxplay into the foreground, and terminate it too.
+-md filename Like the -ca option, but
+exports audio metadata text (Artist, Title, Genre, etc.) to file for
+possible display by a process that watches the file for changes.
+Previous text is overwritten as new metadata is received, and the file
+is deleted when uxplay terminates.
-reset n sets a limit of n consecutive
-timeout failures of the client to respond to ntp requests from the
-server (these are sent every 3 seconds to check if the client is still
-present, and synchronize with it). After n failures, the client
-will be presumed to be offline, and the connection will be reset to
-allow a new connection. The default value of n is 5; the value
-n = 0 means “no limit” on timeouts.
+failures of the client to send feedback requests (these “heartbeat
+signals” are sent by the client once per second to ask for a response
+showing that the server is still online). After n missing
+signals, the client will be presumed to be offline, and the connection
+will be reset to allow a new connection. The default value of n
+is 15 seconds; the value n = 0 means “no limit”.
-nofreeze closes the video window after a reset due
-to ntp timeout (default is to leave window open to allow a smoother
-reconection to the same client). This option may be useful in fullscreen
-mode.
+to client going offline (default is to leave window open to allow a
+smoother reconection to the same client). This option may be useful in
+fullscreen mode.
-nc maintains previous UxPlay < 1.45 behavior
that does not close the video window when the the
client sends the “Stop Mirroring” signal. This option is currently
@@ -1267,9 +1374,10 @@ to a file to n or less. To change the name audiodump,
use -admp [n] filename. Note that (unlike dumped video) the
dumped audio is currently only useful for debugging, as it is not
containerized to make it playable with standard audio players.
--d Enable debug output. Note: this does not show
-GStreamer error or debug messages. To see GStreamer error and warning
-messages, set the environment variable GST_DEBUG with “export
+
-d [n] Enable debug output; optional argument n=1
+suppresses audio/video packet data in debug output. Note: this does not
+show GStreamer error or debug messages. To see GStreamer error and
+warning messages, set the environment variable GST_DEBUG with “export
GST_DEBUG=2” before running uxplay. To see GStreamer information
messages, set GST_DEBUG=4; for DEBUG messages, GST_DEBUG=5; increase
this to see even more of the GStreamer inner workings.
@@ -1602,6 +1710,22 @@ an AppleTV6,2 with sourceVersion 380.20.1 (an AppleTV 4K 1st gen,
introduced 2017, running tvOS 12.2.1), so it does not seem to matter
what version UxPlay claims to be.
Changelog
+xxxx 2025-07-07 Render Audio cover-art inside UxPlay with -ca option
+(no file specified).
+1.72.2 2025-07-07 Fix bug (typo) in DNS_SD advertisement introduced
+with -pw option. Update llhttp to v 9.3.0
+1.72.1 2025-06-06 minor update: fix regression in -reg option; add
+option -rc to specify initialization file; add “-nc no” to
+unset “-nc” option (for macOS users, where -nc is default); add
+user-installable systemd script for running UxPlay as an
+always-available “rootless daemon”
+1.72 2025-05-07. Improved HLS Live Streaming (YouTube) support,
+including “scrub”. Add requested options -md <filename> to output
+audio metadata text to a file for possible display (complements -ca
+option), and -vol option to set initial audio-streaming volume. Add
+support password user access control with HTTP digest Authentication
+(-pw [pwd]). If no pwd is set, a random pin is displayed for entry at
+each new connection.
1.71 2024-12-13 Add support for HTTP Live Streaming (HLS), initially
only for YouTube movies. Fix issue with NTP timeout on Windows.
1.70 2024-10-04 Add support for 4K (h265) video (resolution 3840 x
diff --git a/README.md b/README.md
index ab3f872..2821164 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,35 @@
-# UxPlay 1.71: AirPlay-Mirror and AirPlay-Audio server for Linux, macOS, and Unix (now also runs on Windows).
+# UxPlay 1.72: AirPlay-Mirror and AirPlay-Audio server for Linux, macOS, and Unix (also runs on Windows).
### **Now developed at the GitHub site (where ALL user issues should be posted, and latest versions can be found).**
-- ***NEW in v1.71**: Support for (YouTube) HLS (HTTP Live Streaming)
- video with the new "-hls" option.* Click on the airplay icon in the
- YouTube app to stream video. (You may need to wait until
- advertisements have finished or been skipped before clicking the
- YouTube airplay icon.) **Please report any issues with this new
- feature of UxPlay**.
+- **NEW on github**: option -ca (with no filename given) will now render
+ Apple Music cover art (in audio-only mode) inside
+ UxPlay. (-ca `` will continue to export cover art for
+ display by an external viewer).
+- **NEW in v1.72**: Improved Support for (YouTube) HLS (HTTP Live Streaming)
+ video with the new "-hls" option (introduced in 1.71).* **Only streaming from the YouTube iOS app
+ (in \"m3u8\" protocol) is currently supported**: (streaming using the AirPlay icon in a browser window
+ is **not** yet supported).Click on the airplay icon in the
+ YouTube app to stream video.
+ **Please report any issues with this new feature of UxPlay**.
+
+ _The default video player for HLS is
+ GStreamer playbin v3: use "-hls 2" to revert to playbin v2 if
+ some videos fail to play_.
+
+ * user-requested features: added support for setting a password (as an alternative to on-screen
+ pin codes) to control client access (-pw option, see "man pw" or this README for details); added support for
+ setting initial client audio-streaming volume (-vol option), and output of audio-mode
+ metadata to file (for display by some external process, -md option).
+
+ **ISSUES** ***(Please help to solve if you have expertise)***
+
+ * in HLS video streaming from the YouTube app (-hls option), rendered using GStreamer's media player "playbin3" (or playbin2, with option -hls 2),
+ we don't understand how to correctly deal with "interstitials" (= 15 sec commercials) when "skip" is pressed on the client.
+ (HLS is handled by handlers in lib/http_handlers.h). (Should response to HTTP requests POST /action (playlistRemove) and POST
+ /Stop be modified? _Wireshark data from HLS on an AppleTV model 3 with UN-upgraded original OS (unencrypted communications) could be useful!_
+
## Highlights:
- GPLv3, open source.
@@ -44,7 +65,8 @@ status](https://repology.org/badge/vertical-allrepos/uxplay.svg)](https://repolo
- Install uxplay on Debian-based Linux systems with
"`sudo apt install uxplay`"; on FreeBSD with
- "`sudo pkg install uxplay`". Also available on Arch-based systems
+ "`sudo pkg install uxplay`"; on OpenBSD with
+ "`doas pkg_add uxplay`". Also available on Arch-based systems
through AUR. Since v. 1.66, uxplay is now also packaged in RPM
format by Fedora 38 ("`sudo dnf install uxplay`").
@@ -55,7 +77,12 @@ status](https://repology.org/badge/vertical-allrepos/uxplay.svg)](https://repolo
See the section on using this specfile for [building an installable
RPM package](#building-an-installable-rpm-package).
-After installation:
+- If your distribution does not supply UxPlay, or you want the latest version,
+ it is very easy to build it yourself: see the very
+ [detailed instructions for building UxPlay from source](#building-uxplay-from-source).
+ later in this document.
+
+## After installation:
- (On Linux and \*BSD): if a firewall is active on the server hosting
UxPlay, make sure the default network port (UDP 5353) for
@@ -71,16 +98,40 @@ After installation:
- For Audio-only mode (Apple Music, etc.) best quality is obtained
with the option "uxplay -async", but there is then a 2 second
- latency imposed by iOS.
+ latency imposed by iOS. Use option "uxplay -ca" to display any "Cover Art" that
+ accompanies the audio.
+
+- If you are using UxPlay just to mirror the client's screen (without
+ showing videos that need audio synchronized with video), it is best to
+ use the option "uxplay -vsync no".
- Add any UxPlay options you want to use as defaults to a startup file
`~/.uxplayrc` (see "`man uxplay`" or "`uxplay -h`" for format and
- other possible locations). In particular, if your system uses
+ other possible locations; the location can also be set with "uxplay -rc _location_").
+ In particular, if your system uses
PipeWire audio or Wayland video systems, you may wish to add "as
pipewiresink" or "vs waylandsink" as defaults to the file. *(Output
from terminal commands "ps waux \| grep pulse" or "pactl info" will
contain "pipewire" if your Linux/BSD system uses it).*
+- For Linux systems using systemd, there is a **systemd** service file **uxplay.service**
+ found in the UxPlay top directory of the distribution, and also installed
+ in `/uxplay/systemd/` (where DOCDIR is usually ``/usr/local/share/doc``), that allows users to start
+ their own instance of UxPlay as a rootless daemon: it should either be added to the
+ directory /etc/systemd/user, or the user can just create their own
+ systemd directory `~/.config/systemd/user/` and then copy uxplay.service into it. To save
+ uxplay terminal output to a file ~/uxplay.log, uncomment the StandardOutput entry in
+ uxplay.service. Then
+
+ `systemctl --user [start/stop/enable/disable/status] uxplay`
+
+ can be used to control the daemon. If it is enabled, the daemon will start
+ at the user's first login and stop when they no longer have any open sessions. See
+ https://www.baeldung.com/linux/systemd-create-user-services for more about
+ systemd user services. If more than one user might simultaneously run uxplay this way, they should
+ specify distinct -p and -m options (ports and deviceID) in their startup files.
+ **Note: it is NOT recommended to run UxPlay as a root service.**
+
- On Raspberry Pi: models using hardware h264 video decoding by the
Broadcom GPU (models 4B and earlier) may require the uxplay option -bt709.
If you use Ubuntu 22.10 or earlier, GStreamer must
@@ -91,9 +142,10 @@ After installation:
decoding is used seems to have reappeared
starting with GStreamer-1.22.
-To (easily) compile the latest UxPlay from source, see the section
-[Getting UxPlay](#getting-uxplay).
-
+- If UxPlay is used in a public space, there are security options for requiring an AppleTV-style
+ one-time pin (displayed on the terminal) to be entered, or a password, and for barring/permitting
+ client access by their device ID. See options -pin, -reg, -pw, -restrict, -allow, -block.
+
# Detailed description of UxPlay
This project is a GPLv3 open source unix AirPlay2 Mirror server for
@@ -235,7 +287,7 @@ clause incompatible with the GPL unless OpenSSL can be regarded as a
OpenSSL as a "System Library", but some (e.g. Debian) do not: in this
case, the issue is solved by linking with OpenSSL-3.0.0 or later.
-# Getting UxPlay
+# Building UxPlay from source
Either download and unzip
[UxPlay-master.zip](https://github.com/FDH2/UxPlay/archive/refs/heads/master.zip),
@@ -369,6 +421,11 @@ package](#building-an-installable-rpm-package).
avahi-libdns or mDNSResponder must also be installed to provide the
dns_sd library. OpenSSL is already installed as a System Library.
+- **OpenBSD:** (doas pkg_add) libplist gstreamer1-plugins-base.
+ avahi-libs must also be installed to provide the dns_sd library;
+ (avahi-main must also be installed).
+ OpenSSL is already installed as a System Library.
+
#### Building an installable RPM package
First-time RPM builders should first install the rpm-build and
@@ -450,6 +507,9 @@ repositories for those distributions.
gstreamer1-plugins-\* (\* = core, good, bad, x, gtk, gl, vulkan,
pulse, v4l2, ...), (+ gstreamer1-vaapi for Intel/AMD graphics).
+- **OpenBSD:** Install gstreamer1-libav, gstreamer-plugins-\*
+ (\* = core, bad, base, good).
+
### Starting and running UxPlay
Since UxPlay-1.64, UxPlay can be started with options read from a
@@ -486,7 +546,11 @@ below for help with this or other problems.
[Usage](#usage) for details, if you wish to use it. *Some clients
with MDM (Mobile Device Management, often present on employer-owned
devices) are required to use pin-authentication: UxPlay will provide
- this even when running without the pin option.*
+ this even when running without the pin option.* Password authentication
+ (-pw _pwd_) is also offered as an alternative solution to pin codes:
+ users need to know the password _pwd_ and enter it on their iOS/macOS device
+ to access UxPlay, when prompted (if _pwd_ is not set, a displayed random
+ pin code must be entered at **each** new connection.)
- By default, UxPlay is locked to its current client until that client
drops the connection; since UxPlay-1.58, the option `-nohold`
@@ -548,12 +612,14 @@ value advances it.)
-FPSdata.) When using this, you should use the default
timestamp-based synchronization option `-vsync`.
-- Since UxPlay-1.54, you can display the accompanying "Cover Art" from
- sources like Apple Music in Audio-Only (ALAC) mode: run
+- You can now display (inside UxPlay) the accompanying "Cover Art" from
+ sources like Apple Music in Audio-Only (ALAC) mode with the option
+ `uxplay -ca`. _The older method of exporting cover art to an external
+ viewer remains available: run
"`uxplay -ca &`" in the background, then run a image viewer
with an autoreload feature: an example is "feh": run
"`feh -R 1 `" in the foreground; terminate feh and then Uxplay
- with "`ctrl-C fg ctrl-C`".
+ with "`ctrl-C fg ctrl-C`"_.
By default, GStreamer uses an algorithm to search for the best
"videosink" (GStreamer's term for a graphics driver to display images)
@@ -672,15 +738,14 @@ choice `` = `glimagesink` is sometimes useful. With the
Wayland video compositor, use `` = `waylandsink`. With
framebuffer video, use `` = `kmssink`.
-- Tip: to start UxPlay on a remote host (such as a Raspberry Pi) using
+* Tip: to start UxPlay on a remote host (such as a Raspberry Pi) using
ssh:
-```{=html}
-
```
- ssh user@remote_host
+ssh user@remote_host
export DISPLAY=:0
nohup uxplay [options] > FILE &
+```
Sound and video will play on the remote host; "nohup" will keep uxplay
running if the ssh session is closed. Terminal output is saved to FILE
@@ -688,9 +753,10 @@ running if the ssh session is closed. Terminal output is saved to FILE
## Building UxPlay on macOS: **(Intel X86_64 and "Apple Silicon" M1/M2 Macs)**
-*Note: A native AirPlay Server feature is included in macOS 12 Monterey,
-but is restricted to recent hardware. UxPlay can run on older macOS
-systems that will not be able to run Monterey, or can run Monterey but
+*Note: A native AirPlay Server feature is included in macOS since macOS 12 Monterey,
+but is restricted to recent hardware. As well as running on latest macOS,
+UxPlay can run on older macOS
+systems that will cannot run Monterey, or can run Monterey but
not AirPlay.*
These instructions for macOS assume that the Xcode command-line
@@ -752,19 +818,12 @@ complete GStreamer, but seems to have everything needed for UxPlay).
installations in non-standard locations indicated by the environment
variable `$HOMEBREW_PREFIX`.**
-**Using GStreamer installed from MacPorts**: this is **not**
-recommended, as currently the MacPorts GStreamer is old (v1.16.2),
-unmaintained, and built to use X11:
-
-- Instead [build gstreamer
- yourself](https://github.com/FDH2/UxPlay/wiki/Building-GStreamer-from-Source-on-macOS-with-MacPorts)
- if you use MacPorts and do not want to use the "Official" Gstreamer
- binaries.
-
-*(If you really wish to use the MacPorts GStreamer-1.16.2, install
-pkgconf ("sudo port install pkgconf"), then "sudo port install
+**Using GStreamer installed from MacPorts**: MacPorts is now providing
+recent GStreamer releases: install
+pkgconf ("sudo port install pkgconf"), then "sudo port install gstreamer1
gstreamer1-gst-plugins-base gstreamer1-gst-plugins-good
-gstreamer1-gst-plugins-bad gstreamer1-gst-libav". For X11 support on
+gstreamer1-gst-plugins-bad gstreamer1-gst-libav".
+(The following may no longer be relevant: *For X11 support on
macOS, compile UxPlay using a special cmake option `-DUSE_X11=ON`, and
run it from an XQuartz terminal with -vs ximagesink; older non-retina
macs require a lower resolution when using X11: `uxplay -s 800x600`.)*
@@ -779,30 +838,26 @@ downloads, "UxPlay" for "git clone" downloads) and build/install with
default (since UxPlay 1.64) use of timestamps for video
synchonization, many video frames are being dropped (only on macOS),
perhaps due to another error (about videometa) that shows up in the
- GStreamer warnings. **Recommendation: use the new UxPlay "no
+ GStreamer warnings. **Recommendation: use the UxPlay "no
timestamp" option "`-vsync no`"** (you can add a line "vsync no" in
the uxplayrc configuration file).
- On macOS with this installation of GStreamer, the only videosinks
- available seem to be glimagesink (default choice made by
- autovideosink) and osxvideosink. The window title does not show the
- Airplay server name, but the window is visible to screen-sharing
- apps (e.g., Zoom). The only available audiosink seems to be
+ available are glimagesink (default choice made by
+ autovideosink) and osxvideosink.
+ The window title does not show the
+ Airplay server name, but the window can be shared on Zoom.
+ Because of issues with glimagesink, you may find
+ osxvideosink works better. The only available audiosink is
osxaudiosink.
-- The option -nc is always used, whether or not it is selected. This
- is a workaround for a problem with GStreamer videosinks on macOS: if
- the GStreamer pipeline is destroyed while the mirror window is still
- open, a segfault occurs.
+- The option -nc is currently used by default on macOS, This
+ is a workaround for window-closing problems with GStreamer videosinks on macOS.
+ This option can be canceled with "-nc no", if not needed.
-- In the case of glimagesink, the resolution settings "-s wxh" do not
+- In the case of glimagesink, the resolution settings "-s wxh" may not
affect the (small) initial OpenGL mirror window size, but the window
- can be expanded using the mouse or trackpad. In contrast, a window
- created with "-vs osxvideosink" is initially big, but has the wrong
- aspect ratio (stretched image); in this case the aspect ratio
- changes when the window width is changed by dragging its side; the
- option `-vs "osxvideosink force-aspect-ratio=true"` can be used to
- make the window have the correct aspect ratio when it first opens.
+ can be expanded using the mouse or trackpad.
## Building UxPlay on Microsoft Windows, using MSYS2 with the MinGW-64 compiler.
@@ -825,16 +880,25 @@ downloads, "UxPlay" for "git clone" downloads) and build/install with
3. [MSYS2 packages](https://packages.msys2.org/package/) are installed
with a variant of the "pacman" package manager used by Arch Linux.
- Open a "MSYS2 MINGW64" terminal from the MSYS2 tab in the Windows
+ Open a "MSYS2" terminal from the MSYS2 tab in the Windows
Start menu, and update the new MSYS2 installation with "pacman
- -Syu". Then install the **MinGW-64** compiler and **cmake**
+ -Syu".
- pacman -S mingw-w64-x86_64-cmake mingw-w64-x86_64-gcc
+ * _NEW: MSYS2 now recommends using the newer UCRT64 terminal environment (which uses the newer Microsoft
+ UCRT "Universal C RunTime Library", included as part of the Windows OS since Windows 10)
+ rather than the MINGW64 terminal environment
+ (which uses the older Microsoft MSVCRT C library, which has "legacy" status, but is available on all Windows systems).
+ If you wish to use the legacy MSVCRT library, to support older Windows versions, modify the instructions below as follows:
+ (1) change the MSYS2 terminal type from UCRT64 to MINGW64; (2) modify mingw-w64-ucrt-x86_64-* package names to mingw-w64-x86_64-*, (just omit "-ucrt");
+ (3) replace `ucrt64` by ``mingw64`` in directory names._
- The compiler with all required dependencies will be installed in the
- msys64 directory, with default path `C:/msys64/mingw64`. Here we
- will simply build UxPlay from the command line in the MSYS2
- environment (this uses "`ninja`" in place of "`make`" for the build
+
+ Open a new MSYS2 UCRT64 terminal, and install the gcc compiler and cmake:
+
+ `pacman -S mingw-w64-ucrt-x86_64-cmake mingw-w64-ucrt-x86_64-gcc`
+
+ We will simply build UxPlay from the command line in the MSYS2
+ environment (using "`ninja`" in place of "`make`" for the build
system).
4. Download the latest UxPlay from github **(to use `git`, install it
@@ -842,7 +906,7 @@ downloads, "UxPlay" for "git clone" downloads) and build/install with
"`git clone https://github.com/FDH2/UxPlay`")**, then install UxPlay
dependencies (openssl is already installed with MSYS2):
- `pacman -S mingw-w64-x86_64-libplist mingw-w64-x86_64-gstreamer mingw-w64-x86_64-gst-plugins-base`
+ `pacman -S mingw-w64-ucrt-x86_64-libplist mingw-w64-ucrt-x86_64-gstreamer mingw-w64-ucrt-x86_64-gst-plugins-base`
If you are trying a different Windows build system, MSVC versions of
GStreamer for Windows are available from the [official GStreamer
@@ -862,18 +926,23 @@ downloads, "UxPlay" for "git clone" downloads) and build/install with
6. Assuming no error in either of these, you will have built the uxplay
executable **uxplay.exe** in the current ("build") directory. The
"sudo make install" and "sudo make uninstall" features offered in
- the other builds are not available on Windows; instead, the MSYS2
- environment has `/mingw64/...` available, and you can install the
- uxplay.exe executable in `C:/msys64/mingw64/bin` (plus manpage and
- documentation in `C:/msys64/mingw64/share/...`) with
+ the other builds are not available on Windows; instead, you can install the
+ uxplay.exe executable in `C:/msys64/ucrt64/bin` (plus manpage and
+ documentation in `C:/msys64/ucrt64/share/...`) with
- `cmake --install . --prefix /mingw64`
+ `cmake --install . --prefix $HOME/../../ucrt64`
+
+ You can later uninstall uxplay by returning to the build directory and running
+
+ `ninja uninstall`
+
+ (This assumes that certain files in the build directory were not deleted since building UxPlay).
To be able to view the manpage, you need to install the manpage
viewer with "`pacman -S man`".
To run **uxplay.exe** you need to install some gstreamer plugin packages
-with `pacman -S mingw-w64-x86_64-gst-`, where the required ones
+with `pacman -S mingw-w64-ucrt-x86_64-gst-`, where the required ones
have `` given by
1. **libav**
@@ -892,7 +961,7 @@ app through firewall**. If your virus protection flags uxplay.exe as
"suspicious" (but without a true malware signature) you may need to give
it an exception.
-Now test by running "`uxplay`" (in a MSYS2 terminal window). If you need
+Now test by running "`uxplay`" (in a MSYS2 UCRT64 terminal window. If you need
to specify the audiosink, there are two main choices on Windows: the
older DirectSound plugin "`-as directsoundsink`", and the more modern
Windows Audio Session API (wasapi) plugin "`-as wasapisink`", which
@@ -908,23 +977,20 @@ like `\{0.0.0.00000000\}.\{98e35b2b-8eba-412e-b840-fd2c2492cf44\}`. If
"`device`" is not specified, the default audio device is used.
If you wish to specify the videosink using the `-vs ` option,
-some choices for `` are `d3d11videosink`, `d3dvideosink`,
-`glimagesink`, `gtksink`.
+some choices for `` are `d3d12videosink`, ``d3d11videosink``, ```d3dvideosink```,
+`glimagesink`, ``gtksink``, ```autovideosink```. If you do not specify the videosink,
+the d3d11videosink will be used (users have reported segfaults of the newer d3d12 videodecoder
+on certain older Nvidia cards when the image resolution changes:
+d3d11 will used by default until this is fixed).
-- With Direct3D 11.0 or greater, you can either always be in
- fullscreen mode using option
- `-vs "d3d11videosink fullscreen-toggle-mode=property fullscreen=true"`,
- or get the ability to toggle into and out of fullscreen mode using
- the Alt-Enter key combination with option
- `-vs "d3d11videosink fullscreen-toggle-mode=alt-enter"`. For
- convenience, these options will be added if just
- `-vs d3d11videosink` with or without the fullscreen option "-fs" is
- used. *(Windows users may wish to add "`vs d3d11videosink`" (no
- initial "`-`") to the UxPlay startup options file; see "man uxplay"
- or "uxplay -h".)*
+- With Direct3D 11.0 or greater, various options can be set
+ using e.g. `-vs "d3d11videosink "` (see the gstreamer videosink
+ documentation for these videosinks).
+ For convenience, if no `` are set, the option to
+ toggle in and out of fullscreen mode with the Alt-Enter key combination is added.
The executable uxplay.exe can also be run without the MSYS2 environment,
-in the Windows Terminal, with `C:\msys64\mingw64\bin\uxplay`.
+in the Windows Terminal, with `C:\msys64\ucrt64\bin\uxplay`.
# Usage
@@ -937,6 +1003,9 @@ Options:
comments, and ignored. Command line options supersede options in the
startup file.
+**-rc _file_** can also be used to specify the startup file location: this
+overrides `$UXPLAYRC`, ``~/.uxplayrc``, etc.
+
**-n server_name** (Default: UxPlay); server_name@\_hostname\_ will be
the name that appears offering AirPlay services to your iPad, iPhone
etc, where *hostname* is the name of the server running uxplay. This
@@ -958,10 +1027,14 @@ The "-h265" option changes the default resolution ("-s" option) from
1920x1080 to 3840x2160, and leaves default maximum framerate ("-fps"
option) at 30fps.
-**-hls** Activate HTTP Live Streaming support. With this option YouTube
+**-hls \[v\]** Activate HTTP Live Streaming support. With this option YouTube
videos can be streamed directly from YouTube servers to UxPlay (without
passing through the client) by clicking on the AirPlay icon in the
-YouTube app.
+YouTube app. Optional \[v\] (allowed values 2 or 3, default: 3)
+allows selection of the version of GStreamer's
+\"playbin\" video player to use for playing HLS video. _(Playbin v3
+is the recommended player, but if some videos fail to play, you can try
+with version 2.)_
**-pin \[nnnn\]**: (since v1.67) use Apple-style (one-time) "pin"
authentication when a new client connects for the first time: a
@@ -990,6 +1063,17 @@ deregisters the corresponding client (see options -restrict, -block,
-allow for more ways to control client access). *(Add a line "reg" in
the startup file if you wish to use this feature.)*
+**-pw** [*pwd*]. (since 1.72). As an alternative to -pin, client access
+can be controlled with a password set when uxplay starts (set it in
+the .uxplay startup file, where it is stored as cleartext.) All users must
+then know this password. This uses HTTP md5 Digest authentication,
+which is now regarded as providing weak security, but it is only used to
+validate the uxplay password, and no user credentials are exposed.
+If *pwd* is **not** specified, a random 4-digit pin code is displayed, and must
+be entered on the client at **each** new connection.
+_Note: -pin and -pw are alternatives: if both are specified at startup, the
+earlier of these two options is discarded._
+
**-vsync \[x\]** (In Mirror mode:) this option (**now the default**)
uses timestamps to synchronize audio with video on the server, with an
optional audio delay in (decimal) milliseconds (*x* = "20.5" means
@@ -1038,6 +1122,9 @@ where 16 steps = full volume) is reduced by 50%, the perceived volume is
halved (a 10dB attenuation). (This is modified at low volumes, to use
the "untapered" volume if it is louder.)
+**-vol *v*** Sets initial audio-streaming volume (on client): range is [0:1],
+with 0.0 = mute, 1.0 = full volume (*v* is a decimal number).
+
**-s wxh** e.g. -s 1920x1080 (= "1080p"), the default width and height
resolutions in pixels for h264 video. (The default becomes 3840x2160 (=
"4K") when the -h265 option is used.) This is just a request made to the
@@ -1060,8 +1147,8 @@ display that overscans, and is not displayed by gstreamer).
Recommendation: **don't use this option** unless there is some special
reason to use it.
-**-fs** uses fullscreen mode, but only works with X11, Wayland, VAAPI,
-and D3D11 (Windows).
+**-fs** uses fullscreen mode, but currently only works with X11, Wayland, VAAPI,
+kms and D3D11 (Windows).
**-p** allows you to select the network ports used by UxPlay (these need
to be opened if the server is behind a firewall). By itself, -p sets
@@ -1166,6 +1253,9 @@ number of microseconds. Default is 0.25 sec (250000 usec). *(However,
the client appears to ignore this reported latency, so this option seems
non-functional.)*
+**-ca** (without specifying a filename) now displays "cover art"
+ that accompanies Apple Music when played in "Audio-only" (ALAC) mode.
+
**-ca *filename*** provides a file (where *filename* can include a full
path) used for output of "cover art" (from Apple Music, *etc.*,) in
audio-only ALAC mode. This file is overwritten with the latest cover art
@@ -1179,14 +1269,19 @@ uxplay was put into the background). To quit, use `ctrl-C fg ctrl-C` to
terminate the image viewer, bring `uxplay` into the foreground, and
terminate it too.
-**-reset n** sets a limit of *n* consecutive timeout failures of the
-client to respond to ntp requests from the server (these are sent every
-3 seconds to check if the client is still present, and synchronize with
-it). After *n* failures, the client will be presumed to be offline, and
-the connection will be reset to allow a new connection. The default
-value of *n* is 5; the value *n* = 0 means "no limit" on timeouts.
+**-md *filename*** Like the -ca option, but exports audio metadata text
+(Artist, Title, Genre, etc.) to file for possible display by a process that watches
+the file for changes. Previous text is overwritten as new metadata is received,
+and the file is deleted when uxplay terminates.
-**-nofreeze** closes the video window after a reset due to ntp timeout
+**-reset n** sets a limit of *n* consecutive failures of the
+client to send feedback requests (these "heartbeat signals" are sent by the client
+once per second to ask for a response showing that the server is still online).
+After *n* missing signals, the client will be presumed to be offline, and
+the connection will be reset to allow a new connection. The default
+value of *n* is 15 seconds; the value *n* = 0 means "no limit".
+
+**-nofreeze** closes the video window after a reset due to client going offline
(default is to leave window open to allow a smoother reconection to the
same client). This option may be useful in fullscreen mode.
@@ -1297,7 +1392,9 @@ that (unlike dumped video) the dumped audio is currently only useful for
debugging, as it is not containerized to make it playable with standard
audio players.*
-**-d** Enable debug output. Note: this does not show GStreamer error or
+**-d \[n\]** Enable debug output; optional argument n=1 suppresses audio/video
+packet data in debug output.
+Note: this does not show GStreamer error or
debug messages. To see GStreamer error and warning messages, set the
environment variable GST_DEBUG with "export GST_DEBUG=2" before running
uxplay. To see GStreamer information messages, set GST_DEBUG=4; for
@@ -1645,6 +1742,24 @@ introduced 2017, running tvOS 12.2.1), so it does not seem to matter
what version UxPlay claims to be.
# Changelog
+xxxx 2025-07-07 Render Audio cover-art inside UxPlay with -ca option (no file
+specified).
+
+1.72.2 2025-07-07 Fix bug (typo) in DNS_SD advertisement introduced with -pw
+option. Update llhttp to v 9.3.0
+
+1.72.1 2025-06-06 minor update: fix regression in -reg option; add option
+-rc to specify initialization file; add "-nc no" to unset "-nc"
+option (for macOS users, where -nc is default); add user-installable
+systemd script for running UxPlay as an always-available "rootless daemon"
+
+1.72 2025-05-07. Improved HLS Live Streaming (YouTube) support, including
+"scrub".
+Add requested options -md \ to output audio
+metadata text to a file for possible display (complements -ca option),
+and -vol option to set initial audio-streaming volume. Add support
+password user access control with HTTP digest Authentication (-pw [pwd]).
+If no pwd is set, a random pin is displayed for entry at each new connection.
1.71 2024-12-13 Add support for HTTP Live Streaming (HLS), initially
only for YouTube movies. Fix issue with NTP timeout on Windows.
diff --git a/README.txt b/README.txt
index 01ed687..c2283ef 100644
--- a/README.txt
+++ b/README.txt
@@ -1,13 +1,41 @@
-# UxPlay 1.71: AirPlay-Mirror and AirPlay-Audio server for Linux, macOS, and Unix (now also runs on Windows).
+# UxPlay 1.72: AirPlay-Mirror and AirPlay-Audio server for Linux, macOS, and Unix (also runs on Windows).
### **Now developed at the GitHub site (where ALL user issues should be posted, and latest versions can be found).**
-- ***NEW in v1.71**: Support for (YouTube) HLS (HTTP Live Streaming)
- video with the new "-hls" option.* Click on the airplay icon in the
- YouTube app to stream video. (You may need to wait until
- advertisements have finished or been skipped before clicking the
- YouTube airplay icon.) **Please report any issues with this new
- feature of UxPlay**.
+- **NEW on github**: option -ca (with no filename given) will now
+ render Apple Music cover art (in audio-only mode) inside UxPlay.
+ (-ca `` will continue to export cover art for display by
+ an external viewer).
+
+- **NEW in v1.72**: Improved Support for (YouTube) HLS (HTTP Live
+ Streaming) video with the new "-hls" option (introduced in 1.71).\*
+ **Only streaming from the YouTube iOS app (in \"m3u8\" protocol) is
+ currently supported**: (streaming using the AirPlay icon in a
+ browser window is **not** yet supported).Click on the airplay icon
+ in the YouTube app to stream video. **Please report any issues with
+ this new feature of UxPlay**.
+
+ *The default video player for HLS is GStreamer playbin v3: use "-hls
+ 2" to revert to playbin v2 if some videos fail to play*.
+
+ - user-requested features: added support for setting a password
+ (as an alternative to on-screen pin codes) to control client
+ access (-pw option, see "man pw" or this README for details);
+ added support for setting initial client audio-streaming volume
+ (-vol option), and output of audio-mode metadata to file (for
+ display by some external process, -md option).
+
+ **ISSUES** ***(Please help to solve if you have expertise)***
+
+ - in HLS video streaming from the YouTube app (-hls option),
+ rendered using GStreamer's media player "playbin3" (or playbin2,
+ with option -hls 2), we don't understand how to correctly deal
+ with "interstitials" (= 15 sec commercials) when "skip" is
+ pressed on the client. (HLS is handled by handlers in
+ lib/http_handlers.h). (Should response to HTTP requests POST
+ /action (playlistRemove) and POST /Stop be modified? *Wireshark
+ data from HLS on an AppleTV model 3 with UN-upgraded original OS
+ (unencrypted communications) could be useful!*
## Highlights:
@@ -44,7 +72,8 @@ status](https://repology.org/badge/vertical-allrepos/uxplay.svg)](https://repolo
- Install uxplay on Debian-based Linux systems with
"`sudo apt install uxplay`"; on FreeBSD with
- "`sudo pkg install uxplay`". Also available on Arch-based systems
+ "`sudo pkg install uxplay`"; on OpenBSD with
+ "`doas pkg_add uxplay`". Also available on Arch-based systems
through AUR. Since v. 1.66, uxplay is now also packaged in RPM
format by Fedora 38 ("`sudo dnf install uxplay`").
@@ -55,7 +84,12 @@ status](https://repology.org/badge/vertical-allrepos/uxplay.svg)](https://repolo
See the section on using this specfile for [building an installable
RPM package](#building-an-installable-rpm-package).
-After installation:
+- If your distribution does not supply UxPlay, or you want the latest
+ version, it is very easy to build it yourself: see the very
+ [detailed instructions for building UxPlay from
+ source](#building-uxplay-from-source). later in this document.
+
+## After installation:
- (On Linux and \*BSD): if a firewall is active on the server hosting
UxPlay, make sure the default network port (UDP 5353) for
@@ -71,15 +105,43 @@ After installation:
- For Audio-only mode (Apple Music, etc.) best quality is obtained
with the option "uxplay -async", but there is then a 2 second
- latency imposed by iOS.
+ latency imposed by iOS. Use option "uxplay -ca" to display any
+ "Cover Art" that accompanies the audio.
+
+- If you are using UxPlay just to mirror the client's screen (without
+ showing videos that need audio synchronized with video), it is best
+ to use the option "uxplay -vsync no".
- Add any UxPlay options you want to use as defaults to a startup file
`~/.uxplayrc` (see "`man uxplay`" or "`uxplay -h`" for format and
- other possible locations). In particular, if your system uses
- PipeWire audio or Wayland video systems, you may wish to add "as
- pipewiresink" or "vs waylandsink" as defaults to the file. *(Output
- from terminal commands "ps waux \| grep pulse" or "pactl info" will
- contain "pipewire" if your Linux/BSD system uses it).*
+ other possible locations; the location can also be set with "uxplay
+ -rc *location*"). In particular, if your system uses PipeWire audio
+ or Wayland video systems, you may wish to add "as pipewiresink" or
+ "vs waylandsink" as defaults to the file. *(Output from terminal
+ commands "ps waux \| grep pulse" or "pactl info" will contain
+ "pipewire" if your Linux/BSD system uses it).*
+
+- For Linux systems using systemd, there is a **systemd** service file
+ **uxplay.service** found in the UxPlay top directory of the
+ distribution, and also installed in `/uxplay/systemd/`
+ (where DOCDIR is usually `/usr/local/share/doc`), that allows users
+ to start their own instance of UxPlay as a rootless daemon: it
+ should either be added to the directory /etc/systemd/user, or the
+ user can just create their own systemd directory
+ `~/.config/systemd/user/` and then copy uxplay.service into it. To
+ save uxplay terminal output to a file \~/uxplay.log, uncomment the
+ StandardOutput entry in uxplay.service. Then
+
+ `systemctl --user [start/stop/enable/disable/status] uxplay`
+
+ can be used to control the daemon. If it is enabled, the daemon will
+ start at the user's first login and stop when they no longer have
+ any open sessions. See
+ https://www.baeldung.com/linux/systemd-create-user-services for more
+ about systemd user services. If more than one user might
+ simultaneously run uxplay this way, they should specify distinct -p
+ and -m options (ports and deviceID) in their startup files. **Note:
+ it is NOT recommended to run UxPlay as a root service.**
- On Raspberry Pi: models using hardware h264 video decoding by the
Broadcom GPU (models 4B and earlier) may require the uxplay option
@@ -91,8 +153,11 @@ After installation:
video decoding is used seems to have reappeared starting with
GStreamer-1.22.
-To (easily) compile the latest UxPlay from source, see the section
-[Getting UxPlay](#getting-uxplay).
+- If UxPlay is used in a public space, there are security options for
+ requiring an AppleTV-style one-time pin (displayed on the terminal)
+ to be entered, or a password, and for barring/permitting client
+ access by their device ID. See options -pin, -reg, -pw, -restrict,
+ -allow, -block.
# Detailed description of UxPlay
@@ -235,7 +300,7 @@ clause incompatible with the GPL unless OpenSSL can be regarded as a
OpenSSL as a "System Library", but some (e.g. Debian) do not: in this
case, the issue is solved by linking with OpenSSL-3.0.0 or later.
-# Getting UxPlay
+# Building UxPlay from source
Either download and unzip
[UxPlay-master.zip](https://github.com/FDH2/UxPlay/archive/refs/heads/master.zip),
@@ -369,6 +434,11 @@ package](#building-an-installable-rpm-package).
avahi-libdns or mDNSResponder must also be installed to provide the
dns_sd library. OpenSSL is already installed as a System Library.
+- **OpenBSD:** (doas pkg_add) libplist gstreamer1-plugins-base.
+ avahi-libs must also be installed to provide the dns_sd library;
+ (avahi-main must also be installed). OpenSSL is already installed as
+ a System Library.
+
#### Building an installable RPM package
First-time RPM builders should first install the rpm-build and
@@ -450,6 +520,9 @@ repositories for those distributions.
gstreamer1-plugins-\* (\* = core, good, bad, x, gtk, gl, vulkan,
pulse, v4l2, ...), (+ gstreamer1-vaapi for Intel/AMD graphics).
+- **OpenBSD:** Install gstreamer1-libav, gstreamer-plugins-\* (\* =
+ core, bad, base, good).
+
### Starting and running UxPlay
Since UxPlay-1.64, UxPlay can be started with options read from a
@@ -486,7 +559,12 @@ below for help with this or other problems.
[Usage](#usage) for details, if you wish to use it. *Some clients
with MDM (Mobile Device Management, often present on employer-owned
devices) are required to use pin-authentication: UxPlay will provide
- this even when running without the pin option.*
+ this even when running without the pin option.* Password
+ authentication (-pw *pwd*) is also offered as an alternative
+ solution to pin codes: users need to know the password *pwd* and
+ enter it on their iOS/macOS device to access UxPlay, when prompted
+ (if *pwd* is not set, a displayed random pin code must be entered at
+ **each** new connection.)
- By default, UxPlay is locked to its current client until that client
drops the connection; since UxPlay-1.58, the option `-nohold`
@@ -548,12 +626,13 @@ value advances it.)
-FPSdata.) When using this, you should use the default
timestamp-based synchronization option `-vsync`.
-- Since UxPlay-1.54, you can display the accompanying "Cover Art" from
- sources like Apple Music in Audio-Only (ALAC) mode: run
- "`uxplay -ca &`" in the background, then run a image viewer
- with an autoreload feature: an example is "feh": run
- "`feh -R 1 `" in the foreground; terminate feh and then Uxplay
- with "`ctrl-C fg ctrl-C`".
+- You can now display (inside UxPlay) the accompanying "Cover Art"
+ from sources like Apple Music in Audio-Only (ALAC) mode with the
+ option `uxplay -ca`. *The older method of exporting cover art to an
+ external viewer remains available: run "`uxplay -ca &`" in
+ the background, then run a image viewer with an autoreload feature:
+ an example is "feh": run "`feh -R 1 `" in the foreground;
+ terminate feh and then Uxplay with "`ctrl-C fg ctrl-C`"*.
By default, GStreamer uses an algorithm to search for the best
"videosink" (GStreamer's term for a graphics driver to display images)
@@ -679,9 +758,9 @@ framebuffer video, use `` = `kmssink`.
```{=html}
```
- ssh user@remote_host
- export DISPLAY=:0
- nohup uxplay [options] > FILE &
+ ssh user@remote_host
+ export DISPLAY=:0
+ nohup uxplay [options] > FILE &
Sound and video will play on the remote host; "nohup" will keep uxplay
running if the ssh session is closed. Terminal output is saved to FILE
@@ -689,10 +768,10 @@ running if the ssh session is closed. Terminal output is saved to FILE
## Building UxPlay on macOS: **(Intel X86_64 and "Apple Silicon" M1/M2 Macs)**
-*Note: A native AirPlay Server feature is included in macOS 12 Monterey,
-but is restricted to recent hardware. UxPlay can run on older macOS
-systems that will not be able to run Monterey, or can run Monterey but
-not AirPlay.*
+*Note: A native AirPlay Server feature is included in macOS since macOS
+12 Monterey, but is restricted to recent hardware. As well as running on
+latest macOS, UxPlay can run on older macOS systems that will cannot run
+Monterey, or can run Monterey but not AirPlay.*
These instructions for macOS assume that the Xcode command-line
developer tools are installed (if Xcode is installed, open the Terminal,
@@ -753,22 +832,15 @@ complete GStreamer, but seems to have everything needed for UxPlay).
installations in non-standard locations indicated by the environment
variable `$HOMEBREW_PREFIX`.**
-**Using GStreamer installed from MacPorts**: this is **not**
-recommended, as currently the MacPorts GStreamer is old (v1.16.2),
-unmaintained, and built to use X11:
-
-- Instead [build gstreamer
- yourself](https://github.com/FDH2/UxPlay/wiki/Building-GStreamer-from-Source-on-macOS-with-MacPorts)
- if you use MacPorts and do not want to use the "Official" Gstreamer
- binaries.
-
-*(If you really wish to use the MacPorts GStreamer-1.16.2, install
-pkgconf ("sudo port install pkgconf"), then "sudo port install
+**Using GStreamer installed from MacPorts**: MacPorts is now providing
+recent GStreamer releases: install pkgconf ("sudo port install
+pkgconf"), then "sudo port install gstreamer1
gstreamer1-gst-plugins-base gstreamer1-gst-plugins-good
-gstreamer1-gst-plugins-bad gstreamer1-gst-libav". For X11 support on
-macOS, compile UxPlay using a special cmake option `-DUSE_X11=ON`, and
-run it from an XQuartz terminal with -vs ximagesink; older non-retina
-macs require a lower resolution when using X11: `uxplay -s 800x600`.)*
+gstreamer1-gst-plugins-bad gstreamer1-gst-libav". (The following may no
+longer be relevant: *For X11 support on macOS, compile UxPlay using a
+special cmake option `-DUSE_X11=ON`, and run it from an XQuartz terminal
+with -vs ximagesink; older non-retina macs require a lower resolution
+when using X11: `uxplay -s 800x600`.)*
After installing GStreamer, build and install uxplay: open a terminal
and change into the UxPlay source directory ("UxPlay-master" for zipfile
@@ -780,30 +852,24 @@ downloads, "UxPlay" for "git clone" downloads) and build/install with
default (since UxPlay 1.64) use of timestamps for video
synchonization, many video frames are being dropped (only on macOS),
perhaps due to another error (about videometa) that shows up in the
- GStreamer warnings. **Recommendation: use the new UxPlay "no
- timestamp" option "`-vsync no`"** (you can add a line "vsync no" in
- the uxplayrc configuration file).
+ GStreamer warnings. **Recommendation: use the UxPlay "no timestamp"
+ option "`-vsync no`"** (you can add a line "vsync no" in the
+ uxplayrc configuration file).
- On macOS with this installation of GStreamer, the only videosinks
- available seem to be glimagesink (default choice made by
- autovideosink) and osxvideosink. The window title does not show the
- Airplay server name, but the window is visible to screen-sharing
- apps (e.g., Zoom). The only available audiosink seems to be
- osxaudiosink.
+ available are glimagesink (default choice made by autovideosink) and
+ osxvideosink. The window title does not show the Airplay server
+ name, but the window can be shared on Zoom. Because of issues with
+ glimagesink, you may find osxvideosink works better. The only
+ available audiosink is osxaudiosink.
-- The option -nc is always used, whether or not it is selected. This
- is a workaround for a problem with GStreamer videosinks on macOS: if
- the GStreamer pipeline is destroyed while the mirror window is still
- open, a segfault occurs.
+- The option -nc is currently used by default on macOS, This is a
+ workaround for window-closing problems with GStreamer videosinks on
+ macOS. This option can be canceled with "-nc no", if not needed.
-- In the case of glimagesink, the resolution settings "-s wxh" do not
+- In the case of glimagesink, the resolution settings "-s wxh" may not
affect the (small) initial OpenGL mirror window size, but the window
- can be expanded using the mouse or trackpad. In contrast, a window
- created with "-vs osxvideosink" is initially big, but has the wrong
- aspect ratio (stretched image); in this case the aspect ratio
- changes when the window width is changed by dragging its side; the
- option `-vs "osxvideosink force-aspect-ratio=true"` can be used to
- make the window have the correct aspect ratio when it first opens.
+ can be expanded using the mouse or trackpad.
## Building UxPlay on Microsoft Windows, using MSYS2 with the MinGW-64 compiler.
@@ -826,16 +892,30 @@ downloads, "UxPlay" for "git clone" downloads) and build/install with
3. [MSYS2 packages](https://packages.msys2.org/package/) are installed
with a variant of the "pacman" package manager used by Arch Linux.
- Open a "MSYS2 MINGW64" terminal from the MSYS2 tab in the Windows
- Start menu, and update the new MSYS2 installation with "pacman
- -Syu". Then install the **MinGW-64** compiler and **cmake**
+ Open a "MSYS2" terminal from the MSYS2 tab in the Windows Start
+ menu, and update the new MSYS2 installation with "pacman -Syu".
- pacman -S mingw-w64-x86_64-cmake mingw-w64-x86_64-gcc
+ - \_NEW: MSYS2 now recommends using the newer UCRT64 terminal
+ environment (which uses the newer Microsoft UCRT "Universal C
+ RunTime Library", included as part of the Windows OS since
+ Windows 10) rather than the MINGW64 terminal environment (which
+ uses the older Microsoft MSVCRT C library, which has "legacy"
+ status, but is available on all Windows systems). If you wish to
+ use the legacy MSVCRT library, to support older Windows
+ versions, modify the instructions below as follows:
- The compiler with all required dependencies will be installed in the
- msys64 directory, with default path `C:/msys64/mingw64`. Here we
- will simply build UxPlay from the command line in the MSYS2
- environment (this uses "`ninja`" in place of "`make`" for the build
+ (1) change the MSYS2 terminal type from UCRT64 to MINGW64; (2)
+ modify mingw-w64-ucrt-x86_64-\* package names to
+ mingw-w64-x86_64-\*, (just omit "-ucrt");
+ (2) replace `ucrt64` by `mingw64` in directory names.\_
+
+ Open a new MSYS2 UCRT64 terminal, and install the gcc compiler and
+ cmake:
+
+ `pacman -S mingw-w64-ucrt-x86_64-cmake mingw-w64-ucrt-x86_64-gcc`
+
+ We will simply build UxPlay from the command line in the MSYS2
+ environment (using "`ninja`" in place of "`make`" for the build
system).
4. Download the latest UxPlay from github **(to use `git`, install it
@@ -843,7 +923,7 @@ downloads, "UxPlay" for "git clone" downloads) and build/install with
"`git clone https://github.com/FDH2/UxPlay`")**, then install UxPlay
dependencies (openssl is already installed with MSYS2):
- `pacman -S mingw-w64-x86_64-libplist mingw-w64-x86_64-gstreamer mingw-w64-x86_64-gst-plugins-base`
+ `pacman -S mingw-w64-ucrt-x86_64-libplist mingw-w64-ucrt-x86_64-gstreamer mingw-w64-ucrt-x86_64-gst-plugins-base`
If you are trying a different Windows build system, MSVC versions of
GStreamer for Windows are available from the [official GStreamer
@@ -863,19 +943,26 @@ downloads, "UxPlay" for "git clone" downloads) and build/install with
6. Assuming no error in either of these, you will have built the uxplay
executable **uxplay.exe** in the current ("build") directory. The
"sudo make install" and "sudo make uninstall" features offered in
- the other builds are not available on Windows; instead, the MSYS2
- environment has `/mingw64/...` available, and you can install the
- uxplay.exe executable in `C:/msys64/mingw64/bin` (plus manpage and
- documentation in `C:/msys64/mingw64/share/...`) with
+ the other builds are not available on Windows; instead, you can
+ install the uxplay.exe executable in `C:/msys64/ucrt64/bin` (plus
+ manpage and documentation in `C:/msys64/ucrt64/share/...`) with
- `cmake --install . --prefix /mingw64`
+ `cmake --install . --prefix $HOME/../../ucrt64`
+
+ You can later uninstall uxplay by returning to the build directory
+ and running
+
+ `ninja uninstall`
+
+ (This assumes that certain files in the build directory were not
+ deleted since building UxPlay).
To be able to view the manpage, you need to install the manpage
viewer with "`pacman -S man`".
To run **uxplay.exe** you need to install some gstreamer plugin packages
-with `pacman -S mingw-w64-x86_64-gst-`, where the required ones
-have `` given by
+with `pacman -S mingw-w64-ucrt-x86_64-gst-`, where the required
+ones have `` given by
1. **libav**
2. **plugins-good**
@@ -893,11 +980,11 @@ app through firewall**. If your virus protection flags uxplay.exe as
"suspicious" (but without a true malware signature) you may need to give
it an exception.
-Now test by running "`uxplay`" (in a MSYS2 terminal window). If you need
-to specify the audiosink, there are two main choices on Windows: the
-older DirectSound plugin "`-as directsoundsink`", and the more modern
-Windows Audio Session API (wasapi) plugin "`-as wasapisink`", which
-supports [additional
+Now test by running "`uxplay`" (in a MSYS2 UCRT64 terminal window. If
+you need to specify the audiosink, there are two main choices on
+Windows: the older DirectSound plugin "`-as directsoundsink`", and the
+more modern Windows Audio Session API (wasapi) plugin
+"`-as wasapisink`", which supports [additional
options](https://gstreamer.freedesktop.org/documentation/wasapi/wasapisink.html)
such as
@@ -909,23 +996,21 @@ like `\{0.0.0.00000000\}.\{98e35b2b-8eba-412e-b840-fd2c2492cf44\}`. If
"`device`" is not specified, the default audio device is used.
If you wish to specify the videosink using the `-vs ` option,
-some choices for `` are `d3d11videosink`, `d3dvideosink`,
-`glimagesink`, `gtksink`.
+some choices for `` are `d3d12videosink`, `d3d11videosink`,
+`d3dvideosink`, `glimagesink`, `gtksink`, `autovideosink`. If you do not
+specify the videosink, the d3d11videosink will be used (users have
+reported segfaults of the newer d3d12 videodecoder on certain older
+Nvidia cards when the image resolution changes: d3d11 will used by
+default until this is fixed).
-- With Direct3D 11.0 or greater, you can either always be in
- fullscreen mode using option
- `-vs "d3d11videosink fullscreen-toggle-mode=property fullscreen=true"`,
- or get the ability to toggle into and out of fullscreen mode using
- the Alt-Enter key combination with option
- `-vs "d3d11videosink fullscreen-toggle-mode=alt-enter"`. For
- convenience, these options will be added if just
- `-vs d3d11videosink` with or without the fullscreen option "-fs" is
- used. *(Windows users may wish to add "`vs d3d11videosink`" (no
- initial "`-`") to the UxPlay startup options file; see "man uxplay"
- or "uxplay -h".)*
+- With Direct3D 11.0 or greater, various options can be set using
+ e.g. `-vs "d3d11videosink "` (see the gstreamer videosink
+ documentation for these videosinks). For convenience, if no
+ `` are set, the option to toggle in and out of fullscreen
+ mode with the Alt-Enter key combination is added.
The executable uxplay.exe can also be run without the MSYS2 environment,
-in the Windows Terminal, with `C:\msys64\mingw64\bin\uxplay`.
+in the Windows Terminal, with `C:\msys64\ucrt64\bin\uxplay`.
# Usage
@@ -938,6 +1023,9 @@ Options:
comments, and ignored. Command line options supersede options in the
startup file.
+**-rc *file*** can also be used to specify the startup file location:
+this overrides `$UXPLAYRC`, `~/.uxplayrc`, etc.
+
**-n server_name** (Default: UxPlay); server_name@\_hostname\_ will be
the name that appears offering AirPlay services to your iPad, iPhone
etc, where *hostname* is the name of the server running uxplay. This
@@ -959,10 +1047,13 @@ The "-h265" option changes the default resolution ("-s" option) from
1920x1080 to 3840x2160, and leaves default maximum framerate ("-fps"
option) at 30fps.
-**-hls** Activate HTTP Live Streaming support. With this option YouTube
-videos can be streamed directly from YouTube servers to UxPlay (without
-passing through the client) by clicking on the AirPlay icon in the
-YouTube app.
+**-hls \[v\]** Activate HTTP Live Streaming support. With this option
+YouTube videos can be streamed directly from YouTube servers to UxPlay
+(without passing through the client) by clicking on the AirPlay icon in
+the YouTube app. Optional \[v\] (allowed values 2 or 3, default: 3)
+allows selection of the version of GStreamer's \"playbin\" video player
+to use for playing HLS video. *(Playbin v3 is the recommended player,
+but if some videos fail to play, you can try with version 2.)*
**-pin \[nnnn\]**: (since v1.67) use Apple-style (one-time) "pin"
authentication when a new client connects for the first time: a
@@ -991,6 +1082,17 @@ deregisters the corresponding client (see options -restrict, -block,
-allow for more ways to control client access). *(Add a line "reg" in
the startup file if you wish to use this feature.)*
+**-pw** \[*pwd*\]. (since 1.72). As an alternative to -pin, client
+access can be controlled with a password set when uxplay starts (set it
+in the .uxplay startup file, where it is stored as cleartext.) All users
+must then know this password. This uses HTTP md5 Digest authentication,
+which is now regarded as providing weak security, but it is only used to
+validate the uxplay password, and no user credentials are exposed. If
+*pwd* is **not** specified, a random 4-digit pin code is displayed, and
+must be entered on the client at **each** new connection. *Note: -pin
+and -pw are alternatives: if both are specified at startup, the earlier
+of these two options is discarded.*
+
**-vsync \[x\]** (In Mirror mode:) this option (**now the default**)
uses timestamps to synchronize audio with video on the server, with an
optional audio delay in (decimal) milliseconds (*x* = "20.5" means
@@ -1039,6 +1141,9 @@ where 16 steps = full volume) is reduced by 50%, the perceived volume is
halved (a 10dB attenuation). (This is modified at low volumes, to use
the "untapered" volume if it is louder.)
+**-vol *v*** Sets initial audio-streaming volume (on client): range is
+\[0:1\], with 0.0 = mute, 1.0 = full volume (*v* is a decimal number).
+
**-s wxh** e.g. -s 1920x1080 (= "1080p"), the default width and height
resolutions in pixels for h264 video. (The default becomes 3840x2160 (=
"4K") when the -h265 option is used.) This is just a request made to the
@@ -1061,8 +1166,8 @@ display that overscans, and is not displayed by gstreamer).
Recommendation: **don't use this option** unless there is some special
reason to use it.
-**-fs** uses fullscreen mode, but only works with X11, Wayland, VAAPI,
-and D3D11 (Windows).
+**-fs** uses fullscreen mode, but currently only works with X11,
+Wayland, VAAPI, kms and D3D11 (Windows).
**-p** allows you to select the network ports used by UxPlay (these need
to be opened if the server is behind a firewall). By itself, -p sets
@@ -1167,6 +1272,9 @@ number of microseconds. Default is 0.25 sec (250000 usec). *(However,
the client appears to ignore this reported latency, so this option seems
non-functional.)*
+**-ca** (without specifying a filename) now displays "cover art" that
+accompanies Apple Music when played in "Audio-only" (ALAC) mode.
+
**-ca *filename*** provides a file (where *filename* can include a full
path) used for output of "cover art" (from Apple Music, *etc.*,) in
audio-only ALAC mode. This file is overwritten with the latest cover art
@@ -1180,16 +1288,21 @@ uxplay was put into the background). To quit, use `ctrl-C fg ctrl-C` to
terminate the image viewer, bring `uxplay` into the foreground, and
terminate it too.
-**-reset n** sets a limit of *n* consecutive timeout failures of the
-client to respond to ntp requests from the server (these are sent every
-3 seconds to check if the client is still present, and synchronize with
-it). After *n* failures, the client will be presumed to be offline, and
-the connection will be reset to allow a new connection. The default
-value of *n* is 5; the value *n* = 0 means "no limit" on timeouts.
+**-md *filename*** Like the -ca option, but exports audio metadata text
+(Artist, Title, Genre, etc.) to file for possible display by a process
+that watches the file for changes. Previous text is overwritten as new
+metadata is received, and the file is deleted when uxplay terminates.
-**-nofreeze** closes the video window after a reset due to ntp timeout
-(default is to leave window open to allow a smoother reconection to the
-same client). This option may be useful in fullscreen mode.
+**-reset n** sets a limit of *n* consecutive failures of the client to
+send feedback requests (these "heartbeat signals" are sent by the client
+once per second to ask for a response showing that the server is still
+online). After *n* missing signals, the client will be presumed to be
+offline, and the connection will be reset to allow a new connection. The
+default value of *n* is 15 seconds; the value *n* = 0 means "no limit".
+
+**-nofreeze** closes the video window after a reset due to client going
+offline (default is to leave window open to allow a smoother reconection
+to the same client). This option may be useful in fullscreen mode.
**-nc** maintains previous UxPlay \< 1.45 behavior that does **not
close** the video window when the the client sends the "Stop Mirroring"
@@ -1298,12 +1411,13 @@ that (unlike dumped video) the dumped audio is currently only useful for
debugging, as it is not containerized to make it playable with standard
audio players.*
-**-d** Enable debug output. Note: this does not show GStreamer error or
-debug messages. To see GStreamer error and warning messages, set the
-environment variable GST_DEBUG with "export GST_DEBUG=2" before running
-uxplay. To see GStreamer information messages, set GST_DEBUG=4; for
-DEBUG messages, GST_DEBUG=5; increase this to see even more of the
-GStreamer inner workings.
+**-d \[n\]** Enable debug output; optional argument n=1 suppresses
+audio/video packet data in debug output. Note: this does not show
+GStreamer error or debug messages. To see GStreamer error and warning
+messages, set the environment variable GST_DEBUG with "export
+GST_DEBUG=2" before running uxplay. To see GStreamer information
+messages, set GST_DEBUG=4; for DEBUG messages, GST_DEBUG=5; increase
+this to see even more of the GStreamer inner workings.
# Troubleshooting
@@ -1647,6 +1761,26 @@ what version UxPlay claims to be.
# Changelog
+xxxx 2025-07-07 Render Audio cover-art inside UxPlay with -ca option (no
+file specified).
+
+1.72.2 2025-07-07 Fix bug (typo) in DNS_SD advertisement introduced with
+-pw option. Update llhttp to v 9.3.0
+
+1.72.1 2025-06-06 minor update: fix regression in -reg option; add
+option -rc ``{=html} to specify initialization file; add "-nc
+no" to unset "-nc" option (for macOS users, where -nc is default); add
+user-installable systemd script for running UxPlay as an
+always-available "rootless daemon"
+
+1.72 2025-05-07. Improved HLS Live Streaming (YouTube) support,
+including "scrub". Add requested options -md \ to output
+audio metadata text to a file for possible display (complements -ca
+option), and -vol ``{=html} option to set initial audio-streaming
+volume. Add support password user access control with HTTP digest
+Authentication (-pw \[pwd\]). If no pwd is set, a random pin is
+displayed for entry at each new connection.
+
1.71 2024-12-13 Add support for HTTP Live Streaming (HLS), initially
only for YouTube movies. Fix issue with NTP timeout on Windows.
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 520c5bb..4f5545b 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -1,4 +1,3 @@
-cmake_minimum_required(VERSION 3.5)
include_directories( playfair llhttp )
message( STATUS "*** CFLAGS \"" ${CMAKE_C_FLAGS} "\" from build environment will be postpended to CMAKE_CFLAGS" )
@@ -102,7 +101,11 @@ else ()
target_link_libraries ( airplay PUBLIC ${LIBPLIST} )
endif()
if ( PLIST_FOUND )
- message( STATUS "found libplist-${PLIST_VERSION}" )
+ message( STATUS "found libplist-${PLIST_VERSION}")
+ pkg_check_modules ( PLIST_23 libplist-2.0>=2.3.0 )
+ if ( PLIST_23_FOUND )
+ add_definitions( -DPLIST_230 )
+ endif()
endif()
target_include_directories( airplay PRIVATE ${PLIST_INCLUDE_DIRS} )
diff --git a/lib/airplay_video.c b/lib/airplay_video.c
index 5749057..9b0ccd2 100644
--- a/lib/airplay_video.c
+++ b/lib/airplay_video.c
@@ -29,7 +29,7 @@
struct media_item_s {
char *uri;
char *playlist;
- int access;
+ int num;
};
struct airplay_video_s {
@@ -61,6 +61,8 @@ int airplay_video_service_init(raop_t *raop, unsigned short http_port,
airplay_video_service_destroy(airplay_video);
}
+ /* calloc guarantees that the 36-character strings apple_session_id and
+ playback_uuid are null-terminated */
airplay_video = (airplay_video_t *) calloc(1, sizeof(airplay_video_t));
if (!airplay_video) {
return -1;
@@ -82,16 +84,12 @@ int airplay_video_service_init(raop_t *raop, unsigned short http_port,
//printf(" %p %p\n", airplay_video, get_airplay_video(raop));
airplay_video->raop = raop;
-
-
airplay_video->FCUP_RequestID = 0;
-
size_t len = strlen(session_id);
assert(len == 36);
strncpy(airplay_video->apple_session_id, session_id, len);
- (airplay_video->apple_session_id)[len] = '\0';
-
+
airplay_video->start_position_seconds = 0.0f;
airplay_video->master_uri = NULL;
@@ -143,6 +141,10 @@ void set_playback_uuid(airplay_video_t *airplay_video, const char *playback_uuid
(airplay_video->playback_uuid)[len] = '\0';
}
+const char *get_playback_uuid(airplay_video_t *airplay_video) {
+ return (const char *) airplay_video->playback_uuid;
+}
+
void set_uri_prefix(airplay_video_t *airplay_video, char *uri_prefix, int uri_prefix_len) {
if (airplay_video->uri_prefix) {
free (airplay_video->uri_prefix);
@@ -159,12 +161,10 @@ char *get_uri_local_prefix(airplay_video_t *airplay_video) {
return airplay_video->local_uri_prefix;
}
-
char *get_master_uri(airplay_video_t *airplay_video) {
return airplay_video->master_uri;
}
-
int get_next_FCUP_RequestID(airplay_video_t *airplay_video) {
return ++(airplay_video->FCUP_RequestID);
}
@@ -177,9 +177,6 @@ int get_next_media_uri_id(airplay_video_t *airplay_video) {
return airplay_video->next_uri;
}
-
-/* master playlist */
-
void store_master_playlist(airplay_video_t *airplay_video, char *master_playlist) {
if (airplay_video->master_playlist) {
free (airplay_video->master_playlist);
@@ -219,90 +216,50 @@ void create_media_data_store(airplay_video_t * airplay_video, char ** uri_list,
for (int i = 0; i < num_uri; i++) {
media_data_store[i].uri = uri_list[i];
media_data_store[i].playlist = NULL;
- media_data_store[i].access = 0;
+ media_data_store[i].num = i;
}
airplay_video->media_data_store = media_data_store;
airplay_video->num_uri = num_uri;
}
-int store_media_data_playlist_by_num(airplay_video_t *airplay_video, char * media_playlist, int num) {
+int store_media_playlist(airplay_video_t *airplay_video, char * media_playlist, int num) {
media_item_t *media_data_store = airplay_video->media_data_store;
if ( num < 0 || num >= airplay_video->num_uri) {
- return -1;
+ return -1;
} else if (media_data_store[num].playlist) {
- return -2;
+ return -2;
+ }
+ for (int i = 0; i < num ; i++) {
+ if (strcmp(media_data_store[i].uri, media_data_store[num].uri) == 0) {
+ assert(strcmp(media_data_store[i].playlist, media_playlist) == 0);
+ media_data_store[num].num = i;
+ free (media_playlist);
+ return 1;
+ }
}
media_data_store[num].playlist = media_playlist;
return 0;
}
-char * get_media_playlist_by_num(airplay_video_t *airplay_video, int num) {
+char * get_media_playlist(airplay_video_t *airplay_video, const char *uri) {
media_item_t *media_data_store = airplay_video->media_data_store;
if (media_data_store == NULL) {
return NULL;
}
- if (num >= 0 && num num_uri) {
- return media_data_store[num].playlist;
- }
- return NULL;
-}
-
-int get_media_playlist_by_uri(airplay_video_t *airplay_video, const char *uri) {
- /* Problem: there can be more than one StreamInf playlist with the same uri:
- * they differ by choice of partner Media (audio, subtitles) playlists
- * If the same uri is requested again, one of the other ones will be returned
- * (the least-previously-requested one will be served up)
- */
- // modified to return the position of the media playlist in the master playlist
- media_item_t *media_data_store = airplay_video->media_data_store;
- if (media_data_store == NULL) {
- return -2;
- }
- int found = 0;;
- int num = -1;
- int access = -1;
for (int i = 0; i < airplay_video->num_uri; i++) {
if (strstr(media_data_store[i].uri, uri)) {
- if (!found) {
- found = 1;
- num = i;
- access = media_data_store[i].access;
- } else {
- /* change > below to >= to reverse the order of choice */
- if (access > media_data_store[i].access) {
- access = media_data_store[i].access;
- num = i;
- }
- }
+ return media_data_store[media_data_store[i].num].playlist;
}
}
- if (found) {
- //printf("found %s\n", media_data_store[num].uri);
- ++media_data_store[num].access;
- return num;
- }
- return -1;
+ return NULL;
}
char * get_media_uri_by_num(airplay_video_t *airplay_video, int num) {
media_item_t * media_data_store = airplay_video->media_data_store;
- if (media_data_store == NULL) {
- return NULL;
- }
if (num >= 0 && num < airplay_video->num_uri) {
return media_data_store[num].uri;
- }
- return NULL;
-}
-
-int get_media_uri_num(airplay_video_t *airplay_video, char * uri) {
- media_item_t *media_data_store = airplay_video->media_data_store;
- for (int i = 0; i < airplay_video->num_uri ; i++) {
- if (strstr(media_data_store[i].uri, uri)) {
- return i;
- }
}
- return -1;
+ return NULL;
}
int analyze_media_playlist(char *playlist, float *duration) {
@@ -320,3 +277,258 @@ int analyze_media_playlist(char *playlist, float *duration) {
}
return count;
}
+
+/* parse Master Playlist, make table of Media Playlist uri's that it lists */
+int create_media_uri_table(const char *url_prefix, const char *master_playlist_data,
+ int datalen, char ***media_uri_table, int *num_uri) {
+ char *ptr = strstr(master_playlist_data, url_prefix);
+ char ** table = NULL;
+ if (ptr == NULL) {
+ return -1;
+ }
+ int count = 0;
+ while (ptr != NULL) {
+ char *end = strstr(ptr, "m3u8");
+ if (end == NULL) {
+ return 1;
+ }
+ end += sizeof("m3u8");
+ count++;
+ ptr = strstr(end, url_prefix);
+ }
+ table = (char **) calloc(count, sizeof(char *));
+ if (!table) {
+ return -1;
+ }
+ for (int i = 0; i < count; i++) {
+ table[i] = NULL;
+ }
+ ptr = strstr(master_playlist_data, url_prefix);
+ count = 0;
+ while (ptr != NULL) {
+ char *end = strstr(ptr, "m3u8");
+ char *uri;
+ if (end == NULL) {
+ return 0;
+ }
+ end += sizeof("m3u8");
+ size_t len = end - ptr - 1;
+ uri = (char *) calloc(len + 1, sizeof(char));
+ memcpy(uri , ptr, len);
+ table[count] = uri;
+ uri = NULL;
+ count ++;
+ ptr = strstr(end, url_prefix);
+ }
+ *num_uri = count;
+
+ *media_uri_table = table;
+ return 0;
+}
+
+/* Adjust uri prefixes in the Master Playlist, for sending to the Media Player */
+char *adjust_master_playlist (char *fcup_response_data, int fcup_response_datalen,
+ char *uri_prefix, char *uri_local_prefix) {
+ size_t uri_prefix_len = strlen(uri_prefix);
+ size_t uri_local_prefix_len = strlen(uri_local_prefix);
+ int counter = 0;
+ char *ptr = strstr(fcup_response_data, uri_prefix);
+ while (ptr != NULL) {
+ counter++;
+ ptr++;
+ ptr = strstr(ptr, uri_prefix);
+ }
+
+ size_t len = uri_local_prefix_len - uri_prefix_len;
+ len *= counter;
+ len += fcup_response_datalen;
+ char *new_master = (char *) malloc(len + 1);
+ *(new_master + len) = '\0';
+ char *first = fcup_response_data;
+ char *new = new_master;
+ char *last = strstr(first, uri_prefix);
+ counter = 0;
+ while (last != NULL) {
+ counter++;
+ len = last - first;
+ memcpy(new, first, len);
+ first = last + uri_prefix_len;
+ new += len;
+ memcpy(new, uri_local_prefix, uri_local_prefix_len);
+ new += uri_local_prefix_len;
+ last = strstr(last + uri_prefix_len, uri_prefix);
+ if (last == NULL) {
+ len = fcup_response_data + fcup_response_datalen - first;
+ memcpy(new, first, len);
+ break;
+ }
+ }
+ return new_master;
+}
+
+char *adjust_yt_condensed_playlist(const char *media_playlist) {
+/* this copies a Media Playlist into a null-terminated string.
+ If it has the "#YT-EXT-CONDENSED-URI" header, it is also expanded into
+ the full Media Playlist format.
+ It returns a pointer to the expanded playlist, WHICH MUST BE FREED AFTER USE */
+
+ const char *base_uri_begin;
+ const char *params_begin;
+ const char *prefix_begin;
+ size_t base_uri_len;
+ size_t params_len;
+ size_t prefix_len;
+ const char* ptr = strstr(media_playlist, "#EXTM3U\n");
+
+ ptr += strlen("#EXTM3U\n");
+ assert(ptr);
+ if (strncmp(ptr, "#YT-EXT-CONDENSED-URL", strlen("#YT-EXT-CONDENSED-URL"))) {
+ size_t len = strlen(media_playlist);
+ char * playlist_copy = (char *) malloc(len + 1);
+ memcpy(playlist_copy, media_playlist, len);
+ playlist_copy[len] = '\0';
+ return playlist_copy;
+ }
+ ptr = strstr(ptr, "BASE-URI=");
+ base_uri_begin = strchr(ptr, '"');
+ base_uri_begin++;
+ ptr = strchr(base_uri_begin, '"');
+ base_uri_len = ptr - base_uri_begin;
+ char *base_uri = (char *) calloc(base_uri_len + 1, sizeof(char));
+ assert(base_uri);
+ memcpy(base_uri, base_uri_begin, base_uri_len); //must free
+
+ ptr = strstr(ptr, "PARAMS=");
+ params_begin = strchr(ptr, '"');
+ params_begin++;
+ ptr = strchr(params_begin,'"');
+ params_len = ptr - params_begin;
+ char *params = (char *) calloc(params_len + 1, sizeof(char));
+ assert(params);
+ memcpy(params, params_begin, params_len); //must free
+
+ ptr = strstr(ptr, "PREFIX=");
+ prefix_begin = strchr(ptr, '"');
+ prefix_begin++;
+ ptr = strchr(prefix_begin,'"');
+ prefix_len = ptr - prefix_begin;
+ char *prefix = (char *) calloc(prefix_len + 1, sizeof(char));
+ assert(prefix);
+ memcpy(prefix, prefix_begin, prefix_len); //must free
+
+ /* expand params */
+ int nparams = 0;
+ int *params_size = NULL;
+ const char **params_start = NULL;
+ if (strlen(params)) {
+ nparams = 1;
+ char * comma = strchr(params, ',');
+ while (comma) {
+ nparams++;
+ comma++;
+ comma = strchr(comma, ',');
+ }
+ params_start = (const char **) calloc(nparams, sizeof(char *)); //must free
+ params_size = (int *) calloc(nparams, sizeof(int)); //must free
+ ptr = params;
+ for (int i = 0; i < nparams; i++) {
+ comma = strchr(ptr, ',');
+ params_start[i] = ptr;
+ if (comma) {
+ params_size[i] = (int) (comma - ptr);
+ ptr = comma;
+ ptr++;
+ } else {
+ params_size[i] = (int) (params + params_len - ptr);
+ break;
+ }
+ }
+ }
+
+ int count = 0;
+ ptr = strstr(media_playlist, "#EXTINF");
+ while (ptr) {
+ count++;
+ ptr = strstr(++ptr, "#EXTINF");
+ }
+
+ size_t old_size = strlen(media_playlist);
+ size_t new_size = old_size;
+ new_size += count * (base_uri_len + params_len);
+
+ char * new_playlist = (char *) calloc( new_size + 100, sizeof(char));
+ const char *old_pos = media_playlist;
+ char *new_pos = new_playlist;
+ ptr = old_pos;
+ ptr = strstr(old_pos, "#EXTINF:");
+ size_t len = ptr - old_pos;
+ /* copy header section before chunks */
+ memcpy(new_pos, old_pos, len);
+ old_pos += len;
+ new_pos += len;
+ while (ptr) {
+ /* for each chunk */
+ const char *end = NULL;
+ char *start = strstr(ptr, prefix);
+ len = start - ptr;
+ /* copy first line of chunk entry */
+ memcpy(new_pos, old_pos, len);
+ old_pos += len;
+ new_pos += len;
+
+ /* copy base uri to replace prefix*/
+ memcpy(new_pos, base_uri, base_uri_len);
+ new_pos += base_uri_len;
+ old_pos += prefix_len;
+ ptr = strstr(old_pos, "#EXTINF:");
+
+ /* insert the PARAMS separators on the slices line */
+ end = old_pos;
+ int last = nparams - 1;
+ for (int i = 0; i < nparams; i++) {
+ if (i != last) {
+ end = strchr(end, '/');
+ } else {
+ /* the next line starts with either #EXTINF (usually)
+ or #EXT-X-ENDLIST (at last chunk)*/
+ end = strstr(end, "#EXT");
+ }
+ *new_pos = '/';
+ new_pos++;
+ memcpy(new_pos, params_start[i], params_size[i]);
+ new_pos += params_size[i];
+ *new_pos = '/';
+ new_pos++;
+
+ len = end - old_pos;
+ end++;
+
+ memcpy (new_pos, old_pos, len);
+ new_pos += len;
+ old_pos += len;
+ if (i != last) {
+ old_pos++; /* last entry is not followed by "/" separator */
+ }
+ }
+ }
+ /* copy tail */
+
+ len = media_playlist + strlen(media_playlist) - old_pos;
+ memcpy(new_pos, old_pos, len);
+ new_pos += len;
+ old_pos += len;
+
+ new_playlist[new_size] = '\0';
+
+ free (prefix);
+ free (base_uri);
+ free (params);
+ if (params_size) {
+ free (params_size);
+ }
+ if (params_start) {
+ free (params_start);
+ }
+
+ return new_playlist;
+}
diff --git a/lib/airplay_video.h b/lib/airplay_video.h
index 81fb589..12db0f9 100644
--- a/lib/airplay_video.h
+++ b/lib/airplay_video.h
@@ -30,23 +30,27 @@ const char *get_apple_session_id(airplay_video_t *airplay_video);
void set_start_position_seconds(airplay_video_t *airplay_video, float start_position_seconds);
float get_start_position_seconds(airplay_video_t *airplay_video);
void set_playback_uuid(airplay_video_t *airplay_video, const char *playback_uuid);
+const char *get_playback_uuid(airplay_video_t *airplay_video);
void set_uri_prefix(airplay_video_t *airplay_video, char *uri_prefix, int uri_prefix_len);
char *get_uri_prefix(airplay_video_t *airplay_video);
char *get_uri_local_prefix(airplay_video_t *airplay_video);
+
int get_next_FCUP_RequestID(airplay_video_t *airplay_video);
void set_next_media_uri_id(airplay_video_t *airplay_video, int id);
int get_next_media_uri_id(airplay_video_t *airplay_video);
-int get_media_playlist_by_uri(airplay_video_t *airplay_video, const char *uri);
-void store_master_playlist(airplay_video_t *airplay_video, char *master_playlist);
-char *get_master_playlist(airplay_video_t *airplay_video);
int get_num_media_uri(airplay_video_t *airplay_video);
+char *get_media_uri_by_num(airplay_video_t *airplay_video, int num);
+
+int analyze_media_playlist(char *playlist, float *duration);
+int create_media_uri_table(const char *url_prefix, const char *master_playlist_data,
+ int datalen, char ***media_uri_table, int *num_uri);
+void store_master_playlist(airplay_video_t *airplay_video, char *master_playlist);
+int store_media_playlist(airplay_video_t *airplay_video, char *media_playlist, int num);
+char *get_master_playlist(airplay_video_t *airplay_video);
+char *get_media_playlist(airplay_video_t *airplay_video, const char *uri);
+
void destroy_media_data_store(airplay_video_t *airplay_video);
void create_media_data_store(airplay_video_t * airplay_video, char ** media_data_store, int num_uri);
-int store_media_data_playlist_by_num(airplay_video_t *airplay_video, char * media_playlist, int num);
-char *get_media_playlist_by_num(airplay_video_t *airplay_video, int num);
-char *get_media_uri_by_num(airplay_video_t *airplay_video, int num);
-int get_media_uri_num(airplay_video_t *airplay_video, char * uri);
-int analyze_media_playlist(char *playlist, float *duration);
void airplay_video_service_destroy(airplay_video_t *airplay_video);
@@ -59,6 +63,9 @@ void media_data_store_destroy(void *media_data_store);
// called by the POST /action handler:
char *process_media_data(void *media_data_store, const char *url, const char *data, int datalen);
+char *adjust_master_playlist (char *fcup_response_data, int fcup_response_datalen,
+ char *uri_prefix, char *uri_local_prefix);
+char *adjust_yt_condensed_playlist(const char *media_playlist);
//called by the POST /play handler
bool request_media_data(void *media_data_store, const char *primary_url, const char * session_id);
@@ -70,5 +77,5 @@ char *query_media_data(void *media_data_store, const char *url, int *len);
void media_data_store_reset(void *media_data_store);
const char *adjust_primary_uri(void *media_data_store, const char *url);
-
+
#endif //AIRPLAY_VIDEO_H
diff --git a/lib/byteutils.c b/lib/byteutils.c
index 1687fb5..0950208 100644
--- a/lib/byteutils.c
+++ b/lib/byteutils.c
@@ -31,6 +31,9 @@
# ifndef ntonll
# define ntohll(x) ((1==ntohl(1)) ? (x) : (((uint64_t)ntohl((x) & 0xFFFFFFFFUL)) << 32) | ntohl((uint32_t)((x) >> 32)))
# endif
+#ifndef htonll
+# define htonll(x) ((1==htonl(1)) ? (x) : (((uint64_t)htonl((x) & 0xFFFFFFFFUL)) << 32) | htonl((uint32_t)((x) >> 32)))
+#endif
#else
# ifndef htonll
# ifdef SYS_ENDIAN_H
@@ -86,6 +89,12 @@ uint32_t byteutils_get_int_be(unsigned char* b, int offset) {
uint64_t byteutils_get_long_be(unsigned char* b, int offset) {
return ntohll(byteutils_get_long(b, offset));
}
+/**
+ * Writes a big endian unsigned 64 bit integer to the buffer at position offset
+ */
+void byteutils_put_long_be(unsigned char* b, int offset, uint64_t value) {
+ *((uint64_t*)(b + offset)) = htonll(value);
+}
/**
* Reads a float from the buffer at position offset
diff --git a/lib/byteutils.h b/lib/byteutils.h
index 9f8a4c5..ebdac21 100644
--- a/lib/byteutils.h
+++ b/lib/byteutils.h
@@ -28,5 +28,6 @@ float byteutils_get_float(unsigned char* b, int offset);
uint64_t byteutils_get_ntp_timestamp(unsigned char *b, int offset);
void byteutils_put_ntp_timestamp(unsigned char *b, int offset, uint64_t us_since_1970);
+void byteutils_put_long_be(unsigned char* b, int offset, uint64_t value);
#endif //AIRPLAYSERVER_BYTEUTILS_H
diff --git a/lib/crypto.c b/lib/crypto.c
index d530d97..9056e49 100644
--- a/lib/crypto.c
+++ b/lib/crypto.c
@@ -507,6 +507,8 @@ void ed25519_key_destroy(ed25519_key_t *key) {
}
}
+
+
// SHA 512
struct sha_ctx_s {
@@ -540,7 +542,6 @@ void sha_final(sha_ctx_t *ctx, uint8_t *out, unsigned int *len) {
void sha_reset(sha_ctx_t *ctx) {
if (!EVP_MD_CTX_reset(ctx->digest_ctx) ||
!EVP_DigestInit_ex(ctx->digest_ctx, EVP_sha512(), NULL)) {
-
handle_error(__func__);
}
}
@@ -552,6 +553,63 @@ void sha_destroy(sha_ctx_t *ctx) {
}
}
+//MD5
+struct md5_ctx_s {
+ EVP_MD_CTX *digest_ctx;
+};
+
+md5_ctx_t *md5_init() {
+ md5_ctx_t *ctx = malloc(sizeof(md5_ctx_t));
+ assert(ctx != NULL);
+ ctx->digest_ctx = EVP_MD_CTX_new();
+ assert(ctx->digest_ctx != NULL);
+
+ if (!EVP_DigestInit_ex(ctx->digest_ctx, EVP_md5(), NULL)) {
+ handle_error(__func__);
+ }
+ return ctx;
+}
+
+void md5_update(md5_ctx_t *ctx, const uint8_t *in, int len) {
+ if (!EVP_DigestUpdate(ctx->digest_ctx, in, len)) {
+ handle_error(__func__);
+ }
+}
+
+void md5_final(md5_ctx_t *ctx, uint8_t *out, unsigned int *len) {
+ if (!EVP_DigestFinal_ex(ctx->digest_ctx, out, len)) {
+ handle_error(__func__);
+ }
+}
+
+void md5_reset(md5_ctx_t *ctx) {
+ if (!EVP_MD_CTX_reset(ctx->digest_ctx) ||
+ !EVP_DigestInit_ex(ctx->digest_ctx, EVP_md5(), NULL)) {
+
+ handle_error(__func__);
+ }
+}
+
+void md5_destroy(md5_ctx_t *ctx) {
+ if (ctx) {
+ EVP_MD_CTX_free(ctx->digest_ctx);
+ free(ctx);
+ }
+}
+
+#define MD5_DIGEST_LENGTH 16
+char *get_md5(char *string) {
+ unsigned char hash[MD5_DIGEST_LENGTH];
+ md5_ctx_t *ctx = NULL;
+ ctx = md5_init();
+ md5_update(ctx, (const unsigned char *) string, strlen(string));
+ md5_final(ctx, hash, NULL);
+ md5_destroy(ctx);
+ ctx = NULL;
+ char *result_str = utils_hex_to_string(hash, MD5_DIGEST_LENGTH);
+ return result_str; //must free result_str after use
+}
+
int get_random_bytes(unsigned char *buf, int num) {
return RAND_bytes(buf, num);
}
diff --git a/lib/crypto.h b/lib/crypto.h
index 7bd2d5e..b999c92 100644
--- a/lib/crypto.h
+++ b/lib/crypto.h
@@ -109,6 +109,15 @@ void sha_final(sha_ctx_t *ctx, uint8_t *out, unsigned int *len);
void sha_reset(sha_ctx_t *ctx);
void sha_destroy(sha_ctx_t *ctx);
+//MD5
+typedef struct md5_ctx_s md5_ctx_t;
+md5_ctx_t *md5_init();
+void md5_update(md5_ctx_t *ctx, const uint8_t *in, int len);
+void md5_final(md5_ctx_t *ctx, uint8_t *out, unsigned int *len);
+void md5_reset(md5_ctx_t *ctx);
+void md5_destroy(md5_ctx_t *ctx);
+char *get_md5(char *string);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/dnssd.c b/lib/dnssd.c
index 0725937..b66563c 100644
--- a/lib/dnssd.c
+++ b/lib/dnssd.c
@@ -151,17 +151,21 @@ struct dnssd_s {
uint32_t features1;
uint32_t features2;
- unsigned char require_pw;
+ unsigned char pin_pw;
};
dnssd_t *
-dnssd_init(const char* name, int name_len, const char* hw_addr, int hw_addr_len, int *error, int require_pw)
+dnssd_init(const char* name, int name_len, const char* hw_addr, int hw_addr_len, int *error, unsigned char pin_pw)
{
dnssd_t *dnssd;
char *end;
unsigned long features;
+ /* pin_pw = 0: no pin or password
+ 1: use onscreen pin for client access control
+ 2 or 3: require password for client access control
+ */
if (error) *error = DNSSD_ERROR_NOERROR;
@@ -171,7 +175,7 @@ dnssd_init(const char* name, int name_len, const char* hw_addr, int hw_addr_len,
return NULL;
}
- dnssd->require_pw = (unsigned char) require_pw;
+ dnssd->pin_pw = pin_pw;
features = strtoul(FEATURES_1, &end, 16);
if (!end || (features & 0xFFFFFFFF) != features) {
@@ -302,10 +306,20 @@ dnssd_register_raop(dnssd_t *dnssd, unsigned short port)
dnssd->TXTRecordSetValue(&dnssd->raop_record, "am", strlen(GLOBAL_MODEL), GLOBAL_MODEL);
dnssd->TXTRecordSetValue(&dnssd->raop_record, "md", strlen(RAOP_MD), RAOP_MD);
dnssd->TXTRecordSetValue(&dnssd->raop_record, "rhd", strlen(RAOP_RHD), RAOP_RHD);
- if (dnssd->require_pw) {
+ switch (dnssd->pin_pw) {
+ case 2:
+ case 3:
dnssd->TXTRecordSetValue(&dnssd->raop_record, "pw", strlen("true"), "true");
- } else {
+ dnssd->TXTRecordSetValue(&dnssd->raop_record, "sf", 4, "0x84");
+ break;
+ case 1:
+ dnssd->TXTRecordSetValue(&dnssd->raop_record, "pw", strlen("true"), "true");
+ dnssd->TXTRecordSetValue(&dnssd->raop_record, "sf", 3, "0x8c");
+ break;
+ default:
dnssd->TXTRecordSetValue(&dnssd->raop_record, "pw", strlen("false"), "false");
+ dnssd->TXTRecordSetValue(&dnssd->raop_record, "sf", strlen(RAOP_SF), RAOP_SF);
+ break;
}
dnssd->TXTRecordSetValue(&dnssd->raop_record, "sr", strlen(RAOP_SR), RAOP_SR);
dnssd->TXTRecordSetValue(&dnssd->raop_record, "ss", strlen(RAOP_SS), RAOP_SS);
@@ -361,18 +375,27 @@ dnssd_register_airplay(dnssd_t *dnssd, unsigned short port)
return -1;
}
-
+ // flags is a string representing a 20-bit flag (up to 3 hex digits)
dnssd->TXTRecordCreate(&dnssd->airplay_record, 0, NULL);
dnssd->TXTRecordSetValue(&dnssd->airplay_record, "deviceid", strlen(device_id), device_id);
dnssd->TXTRecordSetValue(&dnssd->airplay_record, "features", strlen(features), features);
- dnssd->TXTRecordSetValue(&dnssd->airplay_record, "flags", strlen(AIRPLAY_FLAGS), AIRPLAY_FLAGS);
+ switch (dnssd->pin_pw) {
+ case 1: // display onscreen pin
+ dnssd->TXTRecordSetValue(&dnssd->airplay_record, "pw", strlen("true"), "true");
+ dnssd->TXTRecordSetValue(&dnssd->airplay_record, "flags", 3, "0x4");
+ break;
+ case 2: // require password
+ case 3:
+ dnssd->TXTRecordSetValue(&dnssd->airplay_record, "pw", strlen("true"), "true");
+ dnssd->TXTRecordSetValue(&dnssd->airplay_record, "flags", 3, "0x4");
+ break;
+ default:
+ dnssd->TXTRecordSetValue(&dnssd->airplay_record, "pw", strlen("false"), "false");
+ dnssd->TXTRecordSetValue(&dnssd->airplay_record, "flags", 3, "0x4");
+ break;
+ }
dnssd->TXTRecordSetValue(&dnssd->airplay_record, "model", strlen(GLOBAL_MODEL), GLOBAL_MODEL);
dnssd->TXTRecordSetValue(&dnssd->airplay_record, "pk", strlen(dnssd->pk), dnssd->pk);
- if (dnssd->require_pw) {
- dnssd->TXTRecordSetValue(&dnssd->airplay_record, "pw", strlen("true"), "true");
- } else {
- dnssd->TXTRecordSetValue(&dnssd->airplay_record, "pw", strlen("false"), "false");
- }
dnssd->TXTRecordSetValue(&dnssd->airplay_record, "pi", strlen(AIRPLAY_PI), AIRPLAY_PI);
dnssd->TXTRecordSetValue(&dnssd->airplay_record, "srcvers", strlen(AIRPLAY_SRCVERS), AIRPLAY_SRCVERS);
dnssd->TXTRecordSetValue(&dnssd->airplay_record, "vv", strlen(AIRPLAY_VV), AIRPLAY_VV);
diff --git a/lib/dnssd.h b/lib/dnssd.h
index 1f83210..968d523 100644
--- a/lib/dnssd.h
+++ b/lib/dnssd.h
@@ -35,7 +35,7 @@ extern "C" {
typedef struct dnssd_s dnssd_t;
- DNSSD_API dnssd_t *dnssd_init(const char *name, int name_len, const char *hw_addr, int hw_addr_len, int *error, int require_pw);
+DNSSD_API dnssd_t *dnssd_init(const char *name, int name_len, const char *hw_addr, int hw_addr_len, int *error, unsigned char pin_pw);
DNSSD_API int dnssd_register_raop(dnssd_t *dnssd, unsigned short port);
DNSSD_API int dnssd_register_airplay(dnssd_t *dnssd, unsigned short port);
diff --git a/lib/dnssdint.h b/lib/dnssdint.h
index 6a457d0..b1478ea 100644
--- a/lib/dnssdint.h
+++ b/lib/dnssdint.h
@@ -44,7 +44,7 @@
#define RAOP_VN "65537"
#define AIRPLAY_SRCVERS GLOBAL_VERSION /*defined in global.h */
-#define AIRPLAY_FLAGS "0x4"
+#define AIRPLAY_FLAGS "0x84"
#define AIRPLAY_VV "2"
#define AIRPLAY_PI "2e388006-13ba-4041-9a67-25dd4a43d536"
diff --git a/lib/fcup_request.h b/lib/fcup_request.h
index 166ffa9..8bd42a2 100644
--- a/lib/fcup_request.h
+++ b/lib/fcup_request.h
@@ -94,7 +94,7 @@ int fcup_request(void *conn_opaque, const char *media_url, const char *client_se
if (send_len < 0) {
int sock_err = SOCKET_GET_ERROR();
logger_log(conn->raop->logger, LOGGER_ERR, "fcup_request: send error %d:%s\n",
- sock_err, strerror(sock_err));
+ sock_err, SOCKET_ERROR_STRING(sock_err));
http_response_destroy(request);
/* shut down connection? */
return -1;
diff --git a/lib/http_handlers.h b/lib/http_handlers.h
index 3db7fdc..25c83d9 100644
--- a/lib/http_handlers.h
+++ b/lib/http_handlers.h
@@ -279,10 +279,10 @@ http_handler_playback_info(raop_conn_t *conn, http_request_t *request, http_resp
playback_info_t playback_info;
playback_info.stallcount = 0;
- playback_info.ready_to_play = true; // ???;
- playback_info.playback_buffer_empty = false; // maybe need to get this from playbin
- playback_info.playback_buffer_full = true;
- playback_info.playback_likely_to_keep_up = true;
+ //playback_info.playback_buffer_empty = false; // maybe need to get this from playbin
+ //playback_info.playback_buffer_full = true;
+ //ayback_info.ready_to_play = true; // ???;
+ //ayback_info.playback_likely_to_keep_up = true;
conn->raop->callbacks.on_video_acquire_playback_info(conn->raop->callbacks.cls, &playback_info);
if (playback_info.duration == -1.0) {
@@ -353,262 +353,6 @@ http_handler_reverse(raop_conn_t *conn, http_request_t *request, http_response_t
}
}
-/* this copies a Media Playlist into a null-terminated string. If it has the "#YT-EXT-CONDENSED-URI"
- header, it is also expanded into the full Media Playlist format */
-
-char *adjust_yt_condensed_playlist(const char *media_playlist) {
- /* expands a YT-EXT_CONDENSED-URL media playlist into a full media playlist
- * returns a pointer to the expanded playlist, WHICH MUST BE FREED AFTER USE */
-
- const char *base_uri_begin;
- const char *params_begin;
- const char *prefix_begin;
- size_t base_uri_len;
- size_t params_len;
- size_t prefix_len;
- const char* ptr = strstr(media_playlist, "#EXTM3U\n");
-
- ptr += strlen("#EXTM3U\n");
- assert(ptr);
- if (strncmp(ptr, "#YT-EXT-CONDENSED-URL", strlen("#YT-EXT-CONDENSED-URL"))) {
- size_t len = strlen(media_playlist);
- char * playlist_copy = (char *) malloc(len + 1);
- memcpy(playlist_copy, media_playlist, len);
- playlist_copy[len] = '\0';
- return playlist_copy;
- }
- ptr = strstr(ptr, "BASE-URI=");
- base_uri_begin = strchr(ptr, '"');
- base_uri_begin++;
- ptr = strchr(base_uri_begin, '"');
- base_uri_len = ptr - base_uri_begin;
- char *base_uri = (char *) calloc(base_uri_len + 1, sizeof(char));
- assert(base_uri);
- memcpy(base_uri, base_uri_begin, base_uri_len); //must free
-
- ptr = strstr(ptr, "PARAMS=");
- params_begin = strchr(ptr, '"');
- params_begin++;
- ptr = strchr(params_begin,'"');
- params_len = ptr - params_begin;
- char *params = (char *) calloc(params_len + 1, sizeof(char));
- assert(params);
- memcpy(params, params_begin, params_len); //must free
-
- ptr = strstr(ptr, "PREFIX=");
- prefix_begin = strchr(ptr, '"');
- prefix_begin++;
- ptr = strchr(prefix_begin,'"');
- prefix_len = ptr - prefix_begin;
- char *prefix = (char *) calloc(prefix_len + 1, sizeof(char));
- assert(prefix);
- memcpy(prefix, prefix_begin, prefix_len); //must free
-
- /* expand params */
- int nparams = 0;
- int *params_size = NULL;
- const char **params_start = NULL;
- if (strlen(params)) {
- nparams = 1;
- char * comma = strchr(params, ',');
- while (comma) {
- nparams++;
- comma++;
- comma = strchr(comma, ',');
- }
- params_start = (const char **) calloc(nparams, sizeof(char *)); //must free
- params_size = (int *) calloc(nparams, sizeof(int)); //must free
- ptr = params;
- for (int i = 0; i < nparams; i++) {
- comma = strchr(ptr, ',');
- params_start[i] = ptr;
- if (comma) {
- params_size[i] = (int) (comma - ptr);
- ptr = comma;
- ptr++;
- } else {
- params_size[i] = (int) (params + params_len - ptr);
- break;
- }
- }
- }
-
- int count = 0;
- ptr = strstr(media_playlist, "#EXTINF");
- while (ptr) {
- count++;
- ptr = strstr(++ptr, "#EXTINF");
- }
-
- size_t old_size = strlen(media_playlist);
- size_t new_size = old_size;
- new_size += count * (base_uri_len + params_len);
-
- char * new_playlist = (char *) calloc( new_size + 100, sizeof(char));
- const char *old_pos = media_playlist;
- char *new_pos = new_playlist;
- ptr = old_pos;
- ptr = strstr(old_pos, "#EXTINF:");
- size_t len = ptr - old_pos;
- /* copy header section before chunks */
- memcpy(new_pos, old_pos, len);
- old_pos += len;
- new_pos += len;
- while (ptr) {
- /* for each chunk */
- const char *end = NULL;
- char *start = strstr(ptr, prefix);
- len = start - ptr;
- /* copy first line of chunk entry */
- memcpy(new_pos, old_pos, len);
- old_pos += len;
- new_pos += len;
-
- /* copy base uri to replace prefix*/
- memcpy(new_pos, base_uri, base_uri_len);
- new_pos += base_uri_len;
- old_pos += prefix_len;
- ptr = strstr(old_pos, "#EXTINF:");
-
- /* insert the PARAMS separators on the slices line */
- end = old_pos;
- int last = nparams - 1;
- for (int i = 0; i < nparams; i++) {
- if (i != last) {
- end = strchr(end, '/');
- } else {
- end = strstr(end, "#EXT"); /* the next line starts with either #EXTINF (usually) or #EXT-X-ENDLIST (at last chunk)*/
- }
- *new_pos = '/';
- new_pos++;
- memcpy(new_pos, params_start[i], params_size[i]);
- new_pos += params_size[i];
- *new_pos = '/';
- new_pos++;
-
- len = end - old_pos;
- end++;
-
- memcpy (new_pos, old_pos, len);
- new_pos += len;
- old_pos += len;
- if (i != last) {
- old_pos++; /* last entry is not followed by "/" separator */
- }
- }
- }
- /* copy tail */
-
- len = media_playlist + strlen(media_playlist) - old_pos;
- memcpy(new_pos, old_pos, len);
- new_pos += len;
- old_pos += len;
-
- new_playlist[new_size] = '\0';
-
- free (prefix);
- free (base_uri);
- free (params);
- if (params_size) {
- free (params_size);
- }
- if (params_start) {
- free (params_start);
- }
-
- return new_playlist;
-}
-
-/* this adjusts the uri prefixes in the Master Playlist, for sending to the Media Player running on the Server Host */
-
-char *adjust_master_playlist (char *fcup_response_data, int fcup_response_datalen, char *uri_prefix, char *uri_local_prefix) {
-
- size_t uri_prefix_len = strlen(uri_prefix);
- size_t uri_local_prefix_len = strlen(uri_local_prefix);
- int counter = 0;
- char *ptr = strstr(fcup_response_data, uri_prefix);
- while (ptr != NULL) {
- counter++;
- ptr++;
- ptr = strstr(ptr, uri_prefix);
- }
-
- size_t len = uri_local_prefix_len - uri_prefix_len;
- len *= counter;
- len += fcup_response_datalen;
- char *new_master = (char *) malloc(len + 1);
- *(new_master + len) = '\0';
- char *first = fcup_response_data;
- char *new = new_master;
- char *last = strstr(first, uri_prefix);
- counter = 0;
- while (last != NULL) {
- counter++;
- len = last - first;
- memcpy(new, first, len);
- first = last + uri_prefix_len;
- new += len;
- memcpy(new, uri_local_prefix, uri_local_prefix_len);
- new += uri_local_prefix_len;
- last = strstr(last + uri_prefix_len, uri_prefix);
- if (last == NULL) {
- len = fcup_response_data + fcup_response_datalen - first;
- memcpy(new, first, len);
- break;
- }
- }
- return new_master;
-}
-
-/* this parses the Master Playlist to make a table of the Media Playlist uri's that it lists */
-
-int create_media_uri_table(const char *url_prefix, const char *master_playlist_data, int datalen,
- char ***media_uri_table, int *num_uri) {
- char *ptr = strstr(master_playlist_data, url_prefix);
- char ** table = NULL;
- if (ptr == NULL) {
- return -1;
- }
- int count = 0;
- while (ptr != NULL) {
- char *end = strstr(ptr, "m3u8");
- if (end == NULL) {
- return 1;
- }
- end += sizeof("m3u8");
- count++;
- ptr = strstr(end, url_prefix);
- }
- table = (char **) calloc(count, sizeof(char *));
- if (!table) {
- return -1;
- }
- for (int i = 0; i < count; i++) {
- table[i] = NULL;
- }
- ptr = strstr(master_playlist_data, url_prefix);
- count = 0;
- while (ptr != NULL) {
- char *end = strstr(ptr, "m3u8");
- char *uri;
- if (end == NULL) {
- return 0;
- }
- end += sizeof("m3u8");
- size_t len = end - ptr - 1;
- uri = (char *) calloc(len + 1, sizeof(char));
- memcpy(uri , ptr, len);
- table[count] = uri;
- uri = NULL;
- count ++;
- ptr = strstr(end, url_prefix);
- }
- *num_uri = count;
-
- *media_uri_table = table;
- return 0;
-}
-
/* the POST /action request from Client to Server on the AirPlay http channel follows a POST /event "FCUP Request"
from Server to Client on the reverse http channel, for a HLS playlist (first the Master Playlist, then the Media Playlists
listed in the Master Playlist. The POST /action request contains the playlist requested by the Server in
@@ -664,31 +408,65 @@ http_handler_action(raop_conn_t *conn, http_request_t *request, http_response_t
goto post_action_error;
}
+ plist_t req_params_node = NULL;
+
/* three possible types are known */
char *type = NULL;
- int action_type = 0;
plist_get_string_val(req_type_node, &type);
logger_log(conn->raop->logger, LOGGER_DEBUG, "action type is %s", type);
if (strstr(type, "unhandledURLResponse")) {
- action_type = 1;
- } else if (strstr(type, "playlistInsert")) {
- action_type = 2;
+ goto unhandledURLResponse;
} else if (strstr(type, "playlistRemove")) {
- action_type = 3;
- }
- free (type);
-
- plist_t req_params_node = NULL;
- switch (action_type) {
- case 1:
- goto unhandledURLResponse;
- case 2:
- logger_log(conn->raop->logger, LOGGER_INFO, "unhandled action type playlistInsert (add new playback)");
- goto finish;
- case 3:
logger_log(conn->raop->logger, LOGGER_INFO, "unhandled action type playlistRemove (stop playback)");
+ req_params_node = plist_dict_get_item(req_root_node, "params");
+ if (!req_params_node || !PLIST_IS_DICT (req_params_node)) {
+ goto post_action_error;
+ }
+ plist_t req_params_item_node = plist_dict_get_item(req_params_node, "item");
+ if (!req_params_item_node) {
+ goto post_action_error;
+ } else {
+ if (!PLIST_IS_DICT (req_params_item_node)) {
+ goto post_action_error;
+ }
+ plist_t req_params_item_uuid_node = plist_dict_get_item(req_params_item_node, "uuid");
+ char* remove_uuid = NULL;
+ plist_get_string_val(req_params_item_uuid_node, &remove_uuid);
+ const char *playback_uuid = get_playback_uuid(conn->raop->airplay_video);
+ if (strcmp(remove_uuid, playback_uuid)) {
+ logger_log(conn->raop->logger, LOGGER_ERR, "uuid of playlist removal action request did not match current playlist:\n"
+ " current: %s\n remove: %s", playback_uuid, remove_uuid);
+ } else {
+ logger_log(conn->raop->logger, LOGGER_DEBUG, "removal_uuid matches playback_uuid\n");
+ }
+ free (remove_uuid);
+ }
+ logger_log(conn->raop->logger, LOGGER_ERR, "FIXME: playlist removal not yet implemented");
goto finish;
- default:
+ } else if (strstr(type, "playlistInsert")) {
+ logger_log(conn->raop->logger, LOGGER_INFO, "unhandled action type playlistInsert (add new playback)");
+ printf("\n***************FIXME************************\nPlaylist insertion needs more information for it to be implemented:\n"
+ "please report following output as an \"Issue\" at http://github.com/FDH2/UxPlay:\n");
+ char *header_str = NULL;
+ http_request_get_header_string(request, &header_str);
+ printf("\n\n%s\n", header_str);
+ bool is_plist = (bool) strstr(header_str,"apple-binary-plist");
+ free(header_str);
+ if (is_plist) {
+ int request_datalen;
+ const char *request_data = http_request_get_data(request, &request_datalen);
+ plist_t req_root_node = NULL;
+ plist_from_bin(request_data, request_datalen, &req_root_node);
+ char * plist_xml;
+ uint32_t plist_len;
+ plist_to_xml(req_root_node, &plist_xml, &plist_len);
+ plist_xml = utils_strip_data_from_plist_xml(plist_xml);
+ printf("%s", plist_xml);
+ free(plist_xml);
+ plist_free(req_root_node);
+ }
+ assert(0);
+ } else {
logger_log(conn->raop->logger, LOGGER_INFO, "unknown action type (unhandled)");
goto finish;
}
@@ -705,45 +483,45 @@ http_handler_action(raop_conn_t *conn, http_request_t *request, http_response_t
int fcup_response_datalen = 0;
if (logger_debug) {
- plist_t plist_fcup_response_statuscode_node = plist_dict_get_item(req_params_node,
+ plist_t req_params_fcup_response_statuscode_node = plist_dict_get_item(req_params_node,
"FCUP_Response_StatusCode");
- if (plist_fcup_response_statuscode_node) {
- plist_get_uint_val(plist_fcup_response_statuscode_node, &uint_val);
+ if (req_params_fcup_response_statuscode_node) {
+ plist_get_uint_val(req_params_fcup_response_statuscode_node, &uint_val);
fcup_response_statuscode = (int) uint_val;
uint_val = 0;
logger_log(conn->raop->logger, LOGGER_DEBUG, "FCUP_Response_StatusCode = %d",
fcup_response_statuscode);
}
- plist_t plist_fcup_response_requestid_node = plist_dict_get_item(req_params_node,
+ plist_t req_params_fcup_response_requestid_node = plist_dict_get_item(req_params_node,
"FCUP_Response_RequestID");
- if (plist_fcup_response_requestid_node) {
- plist_get_uint_val(plist_fcup_response_requestid_node, &uint_val);
+ if (req_params_fcup_response_requestid_node) {
+ plist_get_uint_val(req_params_fcup_response_requestid_node, &uint_val);
request_id = (int) uint_val;
uint_val = 0;
logger_log(conn->raop->logger, LOGGER_DEBUG, "FCUP_Response_RequestID = %d", request_id);
}
}
- plist_t plist_fcup_response_url_node = plist_dict_get_item(req_params_node, "FCUP_Response_URL");
- if (!PLIST_IS_STRING(plist_fcup_response_url_node)) {
+ plist_t req_params_fcup_response_url_node = plist_dict_get_item(req_params_node, "FCUP_Response_URL");
+ if (!PLIST_IS_STRING(req_params_fcup_response_url_node)) {
goto post_action_error;
}
char *fcup_response_url = NULL;
- plist_get_string_val(plist_fcup_response_url_node, &fcup_response_url);
+ plist_get_string_val(req_params_fcup_response_url_node, &fcup_response_url);
if (!fcup_response_url) {
goto post_action_error;
}
logger_log(conn->raop->logger, LOGGER_DEBUG, "FCUP_Response_URL = %s", fcup_response_url);
- plist_t plist_fcup_response_data_node = plist_dict_get_item(req_params_node, "FCUP_Response_Data");
- if (!PLIST_IS_DATA(plist_fcup_response_data_node)){
+ plist_t req_params_fcup_response_data_node = plist_dict_get_item(req_params_node, "FCUP_Response_Data");
+ if (!PLIST_IS_DATA(req_params_fcup_response_data_node)){
goto post_action_error;
}
uint_val = 0;
char *fcup_response_data = NULL;
- plist_get_data_val(plist_fcup_response_data_node, &fcup_response_data, &uint_val);
+ plist_get_data_val(req_params_fcup_response_data_node, &fcup_response_data, &uint_val);
fcup_response_datalen = (int) uint_val;
if (!fcup_response_data) {
@@ -782,7 +560,7 @@ http_handler_action(raop_conn_t *conn, http_request_t *request, http_response_t
memcpy(playlist, fcup_response_data, fcup_response_datalen);
int uri_num = get_next_media_uri_id(conn->raop->airplay_video);
--uri_num; // (next num is current num + 1)
- store_media_data_playlist_by_num(conn->raop->airplay_video, playlist, uri_num);
+ store_media_playlist(conn->raop->airplay_video, playlist, uri_num);
float duration = 0.0f;
int count = analyze_media_playlist(playlist, &duration);
if (count) {
@@ -836,12 +614,14 @@ http_handler_play(raop_conn_t *conn, http_request_t *request, http_response_t *r
char **response_data, int *response_datalen) {
char* playback_location = NULL;
+ char* client_proc_name = NULL;
plist_t req_root_node = NULL;
float start_position_seconds = 0.0f;
bool data_is_binary_plist = false;
bool data_is_text = false;
bool data_is_octet = false;
-
+ char supported_hls_proc_names[] = "YouTube;";
+
logger_log(conn->raop->logger, LOGGER_DEBUG, "http_handler_play");
const char* session_id = http_request_get_header(request, "X-Apple-Session-ID");
@@ -902,6 +682,17 @@ http_handler_play(raop_conn_t *conn, http_request_t *request, http_response_t *r
plist_get_string_val(req_content_location_node, &playback_location);
}
+ plist_t req_client_proc_name_node = plist_dict_get_item(req_root_node, "clientProcName");
+ if (!req_client_proc_name_node) {
+ goto play_error;
+ } else {
+ plist_get_string_val(req_client_proc_name_node, &client_proc_name);
+ if (!strstr(supported_hls_proc_names, client_proc_name)){
+ logger_log(conn->raop->logger, LOGGER_WARNING, "Unsupported HLS streaming format: clientProcName %s not found in supported list: %s",
+ client_proc_name, supported_hls_proc_names);
+ }
+ }
+
plist_t req_start_position_seconds_node = plist_dict_get_item(req_root_node, "Start-Position-Seconds");
if (!req_start_position_seconds_node) {
logger_log(conn->raop->logger, LOGGER_INFO, "No Start-Position-Seconds in Play request");
@@ -914,6 +705,10 @@ http_handler_play(raop_conn_t *conn, http_request_t *request, http_response_t *r
}
char *ptr = strstr(playback_location, "/master.m3u8");
+ if (!ptr) {
+ logger_log(conn->raop->logger, LOGGER_ERR, "Content-Location has unsupported form:\n%s\n", playback_location);
+ goto play_error;
+ }
int prefix_len = (int) (ptr - playback_location);
set_uri_prefix(conn->raop->airplay_video, playback_location, prefix_len);
set_next_media_uri_id(conn->raop->airplay_video, 0);
@@ -932,8 +727,10 @@ http_handler_play(raop_conn_t *conn, http_request_t *request, http_response_t *r
if (req_root_node) {
plist_free(req_root_node);
}
- logger_log(conn->raop->logger, LOGGER_ERR, "Could not find valid Plist Data for /play, Unhandled");
+ logger_log(conn->raop->logger, LOGGER_ERR, "Could not find valid Plist Data for POST/play request, Unhandled");
http_response_init(response, "HTTP/1.1", 400, "Bad Request");
+ http_response_set_disconnect(response, 1);
+ conn->raop->callbacks.conn_reset(conn->raop->callbacks.cls, 2);
}
/* the HLS handler handles http requests GET /[uri] on the HLS channel from the media player to the Server, asking for
@@ -952,26 +749,32 @@ http_handler_hls(raop_conn_t *conn, http_request_t *request, http_response_t *r
const char *url = http_request_get_url(request);
const char* upgrade = http_request_get_header(request, "Upgrade");
if (upgrade) {
- //don't accept Upgrade: h2c request ?
- return;
+ //don't accept Upgrade: h2c request ?
+ char *header_str = NULL;
+ http_request_get_header_string(request, &header_str);
+ logger_log(conn->raop->logger, LOGGER_INFO,
+ "%s\nhls upgrade request declined", header_str);
+ free (header_str);
+ return;
}
if (!strcmp(url, "/master.m3u8")){
char * master_playlist = get_master_playlist(conn->raop->airplay_video);
- size_t len = strlen(master_playlist);
- char * data = (char *) malloc(len + 1);
- memcpy(data, master_playlist, len);
- data[len] = '\0';
- *response_data = data;
- *response_datalen = (int ) len;
+ if (master_playlist) {
+ size_t len = strlen(master_playlist);
+ char * data = (char *) malloc(len + 1);
+ memcpy(data, master_playlist, len);
+ data[len] = '\0';
+ *response_data = data;
+ *response_datalen = (int ) len;
+ } else {
+ logger_log(conn->raop->logger, LOGGER_ERR,"requested master playlist %s not found", url);
+ *response_datalen = 0;
+ }
+
} else {
- int num = get_media_playlist_by_uri(conn->raop->airplay_video, url);
- if (num < 0) {
- logger_log(conn->raop->logger, LOGGER_ERR,"Requested playlist %s not found", url);
- assert(0);
- } else {
- char *media_playlist = get_media_playlist_by_num(conn->raop->airplay_video, num);
- assert(media_playlist);
+ char *media_playlist = get_media_playlist(conn->raop->airplay_video, url);
+ if (media_playlist) {
char *data = adjust_yt_condensed_playlist(media_playlist);
*response_data = data;
*response_datalen = strlen(data);
@@ -979,8 +782,11 @@ http_handler_hls(raop_conn_t *conn, http_request_t *request, http_response_t *r
int chunks = analyze_media_playlist(data, &duration);
logger_log(conn->raop->logger, LOGGER_INFO,
"Requested media_playlist %s has %5d chunks, total duration %9.3f secs", url, chunks, duration);
+ } else {
+ logger_log(conn->raop->logger, LOGGER_ERR,"requested media playlist %s not found", url);
+ *response_datalen = 0;
}
- }
+ }
http_response_add_header(response, "Access-Control-Allow-Headers", "Content-type");
http_response_add_header(response, "Access-Control-Allow-Origin", "*");
diff --git a/lib/httpd.c b/lib/httpd.c
index 28f3d3c..9a4b990 100644
--- a/lib/httpd.c
+++ b/lib/httpd.c
@@ -205,13 +205,25 @@ httpd_remove_connection(httpd_t *httpd, http_connection_t *connection)
http_request_destroy(connection->request);
connection->request = NULL;
}
- httpd->callbacks.conn_destroy(connection->user_data);
- shutdown(connection->socket_fd, SHUT_WR);
- closesocket(connection->socket_fd);
- connection->connected = 0;
- connection->user_data = NULL;
+ logger_log(httpd->logger, LOGGER_DEBUG, "removing connection type %s socket %d conn %p", typename[connection->type],
+ connection->socket_fd, connection->user_data);
+ if (connection->user_data) {
+ httpd->callbacks.conn_destroy(connection->user_data);
+ connection->user_data = NULL;
+ }
+ if (connection->socket_fd) {
+ shutdown(connection->socket_fd, SHUT_WR);
+ int ret = closesocket(connection->socket_fd);
+ if (ret == -1) {
+ logger_log(httpd->logger, LOGGER_ERR, "httpd error in closesocket (close): %d %s", errno, strerror(errno));
+ }
+ connection->socket_fd = 0;
+ }
+ if (connection->connected) {
+ connection->connected = 0;
+ httpd->open_connections--;
+ }
connection->type = CONNECTION_TYPE_UNKNOWN;
- httpd->open_connections--;
}
static int
@@ -303,6 +315,17 @@ httpd_remove_known_connections(httpd_t *httpd) {
}
}
+void
+httpd_remove_connections_by_type(httpd_t *httpd, connection_type_t type) {
+ for (int i = 0; i < httpd->max_connections; i++) {
+ http_connection_t *connection = &httpd->connections[i];
+ if (!connection->connected || connection->type != type) {
+ continue;
+ }
+ httpd_remove_connection(httpd, connection);
+ }
+}
+
static THREAD_RETVAL
httpd_thread(void *arg)
{
@@ -450,7 +473,7 @@ httpd_thread(void *arg)
} else {
int sock_err = SOCKET_GET_ERROR();
logger_log(httpd->logger, LOGGER_ERR, "httpd: recv socket error %d:%s",
- sock_err, strerror(sock_err));
+ sock_err, SOCKET_ERROR_STRING(sock_err));
break;
}
} else {
@@ -571,7 +594,7 @@ httpd_thread(void *arg)
httpd->running = 0;
MUTEX_UNLOCK(httpd->run_mutex);
- logger_log(httpd->logger, LOGGER_DEBUG, "Exiting HTTP thread");
+ logger_log(httpd->logger, LOGGER_DEBUG, "Exiting httpd thread");
return 0;
}
diff --git a/lib/httpd.h b/lib/httpd.h
index 1df0e6b..72cc137 100644
--- a/lib/httpd.h
+++ b/lib/httpd.h
@@ -39,6 +39,7 @@ struct httpd_callbacks_s {
typedef struct httpd_callbacks_s httpd_callbacks_t;
bool httpd_nohold(httpd_t *httpd);
void httpd_remove_known_connections(httpd_t *httpd);
+void httpd_remove_connections_by_type(httpd_t *httpd, connection_type_t type);
int httpd_set_connection_type (httpd_t *http, void *user_data, connection_type_t type);
int httpd_count_connection_type (httpd_t *http, connection_type_t type);
diff --git a/lib/llhttp/CMakeLists.txt b/lib/llhttp/CMakeLists.txt
index 3895909..cebc2a7 100644
--- a/lib/llhttp/CMakeLists.txt
+++ b/lib/llhttp/CMakeLists.txt
@@ -1,4 +1,3 @@
-cmake_minimum_required(VERSION 3.5)
aux_source_directory(. llhttp_src)
set(DIR_SRCS ${llhttp_src})
include_directories(.)
diff --git a/lib/llhttp/api.c b/lib/llhttp/api.c
index 8c2ce3d..0245254 100644
--- a/lib/llhttp/api.c
+++ b/lib/llhttp/api.c
@@ -57,29 +57,14 @@ static int wasm_on_headers_complete_wrap(llhttp_t* p) {
}
const llhttp_settings_t wasm_settings = {
- wasm_on_message_begin,
- wasm_on_url,
- wasm_on_status,
- NULL,
- NULL,
- wasm_on_header_field,
- wasm_on_header_value,
- NULL,
- NULL,
- wasm_on_headers_complete_wrap,
- wasm_on_body,
- wasm_on_message_complete,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
+ .on_message_begin = wasm_on_message_begin,
+ .on_url = wasm_on_url,
+ .on_status = wasm_on_status,
+ .on_header_field = wasm_on_header_field,
+ .on_header_value = wasm_on_header_value,
+ .on_headers_complete = wasm_on_headers_complete_wrap,
+ .on_body = wasm_on_body,
+ .on_message_complete = wasm_on_message_complete,
};
@@ -341,6 +326,20 @@ int llhttp__on_message_begin(llhttp_t* s, const char* p, const char* endp) {
}
+int llhttp__on_protocol(llhttp_t* s, const char* p, const char* endp) {
+ int err;
+ SPAN_CALLBACK_MAYBE(s, on_protocol, p, endp - p);
+ return err;
+}
+
+
+int llhttp__on_protocol_complete(llhttp_t* s, const char* p, const char* endp) {
+ int err;
+ CALLBACK_MAYBE(s, on_protocol_complete);
+ return err;
+}
+
+
int llhttp__on_url(llhttp_t* s, const char* p, const char* endp) {
int err;
SPAN_CALLBACK_MAYBE(s, on_url, p, endp - p);
diff --git a/lib/llhttp/llhttp.c b/lib/llhttp/llhttp.c
index 3ef3b81..aa4c468 100644
--- a/lib/llhttp/llhttp.c
+++ b/lib/llhttp/llhttp.c
@@ -10,10 +10,20 @@
#endif /* _MSC_VER */
#endif /* __SSE4_2__ */
+#ifdef __ARM_NEON__
+ #include
+#endif /* __ARM_NEON__ */
+
+#ifdef __wasm__
+ #include
+#endif /* __wasm__ */
+
#ifdef _MSC_VER
#define ALIGN(n) _declspec(align(n))
+ #define UNREACHABLE __assume(0)
#else /* !_MSC_VER */
#define ALIGN(n) __attribute__((aligned(n)))
+ #define UNREACHABLE __builtin_unreachable()
#endif /* _MSC_VER */
#include "llhttp.h"
@@ -72,16 +82,16 @@ static const unsigned char llparse_blob12[] = {
'p', 'g', 'r', 'a', 'd', 'e'
};
static const unsigned char llparse_blob13[] = {
- 'T', 'T', 'P', '/'
+ 'T', 'T', 'P'
};
static const unsigned char llparse_blob14[] = {
0xd, 0xa, 0xd, 0xa, 'S', 'M', 0xd, 0xa, 0xd, 0xa
};
static const unsigned char llparse_blob15[] = {
- 'C', 'E', '/'
+ 'C', 'E'
};
static const unsigned char llparse_blob16[] = {
- 'T', 'S', 'P', '/'
+ 'T', 'S', 'P'
};
static const unsigned char llparse_blob17[] = {
'N', 'O', 'U', 'N', 'C', 'E'
@@ -207,12 +217,18 @@ static const unsigned char llparse_blob57[] = {
'U', 'B', 'S', 'C', 'R', 'I', 'B', 'E'
};
static const unsigned char llparse_blob58[] = {
- 'H', 'T', 'T', 'P', '/'
+ 'T', 'T', 'P'
};
static const unsigned char llparse_blob59[] = {
- 'A', 'D'
+ 'C', 'E'
};
static const unsigned char llparse_blob60[] = {
+ 'T', 'S', 'P'
+};
+static const unsigned char llparse_blob61[] = {
+ 'A', 'D'
+};
+static const unsigned char llparse_blob62[] = {
'T', 'P', '/'
};
@@ -425,17 +441,27 @@ enum llparse_state_e {
s_n_llhttp__internal__n_req_http_complete,
s_n_llhttp__internal__n_invoke_load_method_1,
s_n_llhttp__internal__n_invoke_llhttp__on_version_complete,
- s_n_llhttp__internal__n_error_66,
- s_n_llhttp__internal__n_error_73,
- s_n_llhttp__internal__n_req_http_minor,
+ s_n_llhttp__internal__n_error_67,
s_n_llhttp__internal__n_error_74,
- s_n_llhttp__internal__n_req_http_dot,
+ s_n_llhttp__internal__n_req_http_minor,
s_n_llhttp__internal__n_error_75,
+ s_n_llhttp__internal__n_req_http_dot,
+ s_n_llhttp__internal__n_error_76,
s_n_llhttp__internal__n_req_http_major,
s_n_llhttp__internal__n_span_start_llhttp__on_version,
- s_n_llhttp__internal__n_req_http_start_1,
- s_n_llhttp__internal__n_req_http_start_2,
- s_n_llhttp__internal__n_req_http_start_3,
+ s_n_llhttp__internal__n_req_after_protocol,
+ s_n_llhttp__internal__n_invoke_load_method,
+ s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete,
+ s_n_llhttp__internal__n_error_82,
+ s_n_llhttp__internal__n_req_after_http_start_1,
+ s_n_llhttp__internal__n_invoke_load_method_2,
+ s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete_1,
+ s_n_llhttp__internal__n_req_after_http_start_2,
+ s_n_llhttp__internal__n_invoke_load_method_3,
+ s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete_2,
+ s_n_llhttp__internal__n_req_after_http_start_3,
+ s_n_llhttp__internal__n_req_after_http_start,
+ s_n_llhttp__internal__n_span_start_llhttp__on_protocol,
s_n_llhttp__internal__n_req_http_start,
s_n_llhttp__internal__n_url_to_http,
s_n_llhttp__internal__n_url_skip_to_http,
@@ -543,15 +569,22 @@ enum llparse_state_e {
s_n_llhttp__internal__n_res_status_code_digit_1,
s_n_llhttp__internal__n_res_after_version,
s_n_llhttp__internal__n_invoke_llhttp__on_version_complete_1,
- s_n_llhttp__internal__n_error_89,
- s_n_llhttp__internal__n_error_103,
+ s_n_llhttp__internal__n_error_93,
+ s_n_llhttp__internal__n_error_107,
s_n_llhttp__internal__n_res_http_minor,
- s_n_llhttp__internal__n_error_104,
+ s_n_llhttp__internal__n_error_108,
s_n_llhttp__internal__n_res_http_dot,
- s_n_llhttp__internal__n_error_105,
+ s_n_llhttp__internal__n_error_109,
s_n_llhttp__internal__n_res_http_major,
s_n_llhttp__internal__n_span_start_llhttp__on_version_1,
- s_n_llhttp__internal__n_start_res,
+ s_n_llhttp__internal__n_res_after_protocol,
+ s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete_3,
+ s_n_llhttp__internal__n_error_115,
+ s_n_llhttp__internal__n_res_after_start_1,
+ s_n_llhttp__internal__n_res_after_start_2,
+ s_n_llhttp__internal__n_res_after_start_3,
+ s_n_llhttp__internal__n_res_after_start,
+ s_n_llhttp__internal__n_span_start_llhttp__on_protocol_1,
s_n_llhttp__internal__n_invoke_llhttp__on_method_complete,
s_n_llhttp__internal__n_req_or_res_method_2,
s_n_llhttp__internal__n_invoke_update_type_1,
@@ -574,6 +607,10 @@ int llhttp__on_url(
llhttp__internal_t* s, const unsigned char* p,
const unsigned char* endp);
+int llhttp__on_protocol(
+ llhttp__internal_t* s, const unsigned char* p,
+ const unsigned char* endp);
+
int llhttp__on_version(
llhttp__internal_t* s, const unsigned char* p,
const unsigned char* endp);
@@ -1057,6 +1094,10 @@ int llhttp__internal__c_or_flags_20(
return 0;
}
+int llhttp__on_protocol_complete(
+ llhttp__internal_t* s, const unsigned char* p,
+ const unsigned char* endp);
+
int llhttp__internal__c_load_method(
llhttp__internal_t* state,
const unsigned char* p,
@@ -1192,8 +1233,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_invoke_test_lenient_flags_3;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_invoke_llhttp__after_message_complete:
s_n_llhttp__internal__n_invoke_llhttp__after_message_complete: {
@@ -1203,8 +1243,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_invoke_update_finish_1;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_pause_1:
s_n_llhttp__internal__n_pause_1: {
@@ -1213,8 +1252,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__after_message_complete;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_invoke_is_equal_upgrade:
s_n_llhttp__internal__n_invoke_is_equal_upgrade: {
@@ -1224,8 +1262,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_pause_1;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2:
s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2: {
@@ -1237,8 +1274,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_error_38;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_chunk_data_almost_done_1:
s_n_llhttp__internal__n_chunk_data_almost_done_1: {
@@ -1254,8 +1290,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_invoke_test_lenient_flags_7;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_chunk_data_almost_done:
s_n_llhttp__internal__n_chunk_data_almost_done: {
@@ -1275,8 +1310,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_invoke_test_lenient_flags_7;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_consume_content_length:
s_n_llhttp__internal__n_consume_content_length: {
@@ -1293,8 +1327,7 @@ static llparse_state_t llhttp__internal__run(
state->content_length -= avail;
return s_n_llhttp__internal__n_consume_content_length;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_span_start_llhttp__on_body:
s_n_llhttp__internal__n_span_start_llhttp__on_body: {
@@ -1304,8 +1337,7 @@ static llparse_state_t llhttp__internal__run(
state->_span_pos0 = (void*) p;
state->_span_cb0 = llhttp__on_body;
goto s_n_llhttp__internal__n_consume_content_length;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_invoke_is_equal_content_length:
s_n_llhttp__internal__n_invoke_is_equal_content_length: {
@@ -1315,8 +1347,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_invoke_or_flags;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_chunk_size_almost_done:
s_n_llhttp__internal__n_chunk_size_almost_done: {
@@ -1332,8 +1363,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_invoke_test_lenient_flags_8;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_invoke_test_lenient_flags_9:
s_n_llhttp__internal__n_invoke_test_lenient_flags_9: {
@@ -1343,8 +1373,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_error_20;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete:
s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete: {
@@ -1356,8 +1385,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_error_19;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_1:
s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_1: {
@@ -1369,8 +1397,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_error_21;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_2:
s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_2: {
@@ -1382,8 +1409,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_error_22;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_invoke_test_lenient_flags_10:
s_n_llhttp__internal__n_invoke_test_lenient_flags_10: {
@@ -1393,8 +1419,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_error_25;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete:
s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete: {
@@ -1406,8 +1431,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_error_24;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_1:
s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_1: {
@@ -1419,8 +1443,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_error_26;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_chunk_extension_quoted_value_done:
s_n_llhttp__internal__n_chunk_extension_quoted_value_done: {
@@ -1443,8 +1466,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_error_29;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_2:
s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_2: {
@@ -1456,8 +1478,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_error_27;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_error_30:
s_n_llhttp__internal__n_error_30: {
@@ -1466,8 +1487,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_chunk_extension_quoted_value_quoted_pair:
s_n_llhttp__internal__n_chunk_extension_quoted_value_quoted_pair: {
@@ -1501,8 +1521,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_3;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_error_31:
s_n_llhttp__internal__n_error_31: {
@@ -1511,8 +1530,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_chunk_extension_quoted_value:
s_n_llhttp__internal__n_chunk_extension_quoted_value: {
@@ -1554,8 +1572,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_4;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_3:
s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_3: {
@@ -1567,8 +1584,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_error_32;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_error_33:
s_n_llhttp__internal__n_error_33: {
@@ -1577,8 +1593,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_chunk_extension_value:
s_n_llhttp__internal__n_chunk_extension_value: {
@@ -1625,8 +1640,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_6;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_value:
s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_value: {
@@ -1636,8 +1650,7 @@ static llparse_state_t llhttp__internal__run(
state->_span_pos0 = (void*) p;
state->_span_cb0 = llhttp__on_chunk_extension_value;
goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_3;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_error_34:
s_n_llhttp__internal__n_error_34: {
@@ -1646,8 +1659,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_chunk_extension_name:
s_n_llhttp__internal__n_chunk_extension_name: {
@@ -1693,8 +1705,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name_4;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_name:
s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_name: {
@@ -1704,8 +1715,7 @@ static llparse_state_t llhttp__internal__run(
state->_span_pos0 = (void*) p;
state->_span_cb0 = llhttp__on_chunk_extension_name;
goto s_n_llhttp__internal__n_chunk_extension_name;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_chunk_extensions:
s_n_llhttp__internal__n_chunk_extensions: {
@@ -1725,8 +1735,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_name;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_chunk_size_otherwise:
s_n_llhttp__internal__n_chunk_size_otherwise: {
@@ -1758,8 +1767,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_error_35;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_chunk_size:
s_n_llhttp__internal__n_chunk_size: {
@@ -1881,8 +1889,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_chunk_size_otherwise;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_chunk_size_digit:
s_n_llhttp__internal__n_chunk_size_digit: {
@@ -2004,8 +2011,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_error_37;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_invoke_update_content_length_1:
s_n_llhttp__internal__n_invoke_update_content_length_1: {
@@ -2013,8 +2019,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_chunk_size_digit;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_consume_content_length_1:
s_n_llhttp__internal__n_consume_content_length_1: {
@@ -2031,8 +2036,7 @@ static llparse_state_t llhttp__internal__run(
state->content_length -= avail;
return s_n_llhttp__internal__n_consume_content_length_1;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_span_start_llhttp__on_body_1:
s_n_llhttp__internal__n_span_start_llhttp__on_body_1: {
@@ -2042,8 +2046,7 @@ static llparse_state_t llhttp__internal__run(
state->_span_pos0 = (void*) p;
state->_span_cb0 = llhttp__on_body;
goto s_n_llhttp__internal__n_consume_content_length_1;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_eof:
s_n_llhttp__internal__n_eof: {
@@ -2052,8 +2055,7 @@ static llparse_state_t llhttp__internal__run(
}
p++;
goto s_n_llhttp__internal__n_eof;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_span_start_llhttp__on_body_2:
s_n_llhttp__internal__n_span_start_llhttp__on_body_2: {
@@ -2063,8 +2065,7 @@ static llparse_state_t llhttp__internal__run(
state->_span_pos0 = (void*) p;
state->_span_cb0 = llhttp__on_body;
goto s_n_llhttp__internal__n_eof;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete:
s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete: {
@@ -2082,8 +2083,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_error_5:
s_n_llhttp__internal__n_error_5: {
@@ -2092,8 +2092,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_headers_almost_done:
s_n_llhttp__internal__n_headers_almost_done: {
@@ -2109,8 +2108,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_invoke_test_lenient_flags_12;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_header_field_colon_discard_ws:
s_n_llhttp__internal__n_header_field_colon_discard_ws: {
@@ -2126,8 +2124,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_header_field_colon;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete:
s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete: {
@@ -2139,8 +2136,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_error_48;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_span_start_llhttp__on_header_value:
s_n_llhttp__internal__n_span_start_llhttp__on_header_value: {
@@ -2150,8 +2146,7 @@ static llparse_state_t llhttp__internal__run(
state->_span_pos0 = (void*) p;
state->_span_cb0 = llhttp__on_header_value;
goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_header_value_discard_lws:
s_n_llhttp__internal__n_header_value_discard_lws: {
@@ -2171,8 +2166,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_invoke_load_header_state_1;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_header_value_discard_ws_almost_done:
s_n_llhttp__internal__n_header_value_discard_ws_almost_done: {
@@ -2188,8 +2182,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_invoke_test_lenient_flags_16;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_header_value_lws:
s_n_llhttp__internal__n_header_value_lws: {
@@ -2207,8 +2200,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_invoke_load_header_state_5;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_header_value_almost_done:
s_n_llhttp__internal__n_header_value_almost_done: {
@@ -2224,8 +2216,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_error_53;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_invoke_test_lenient_flags_17:
s_n_llhttp__internal__n_invoke_test_lenient_flags_17: {
@@ -2235,8 +2226,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_error_51;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_header_value_lenient:
s_n_llhttp__internal__n_header_value_lenient: {
@@ -2255,8 +2245,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_header_value_lenient;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_error_54:
s_n_llhttp__internal__n_error_54: {
@@ -2265,8 +2254,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_header_value_otherwise:
s_n_llhttp__internal__n_header_value_otherwise: {
@@ -2284,8 +2272,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_invoke_test_lenient_flags_19;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_header_value_connection_token:
s_n_llhttp__internal__n_header_value_connection_token: {
@@ -2323,8 +2310,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_header_value_otherwise;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_header_value_connection_ws:
s_n_llhttp__internal__n_header_value_connection_ws: {
@@ -2350,8 +2336,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_invoke_update_header_state_5;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_header_value_connection_1:
s_n_llhttp__internal__n_header_value_connection_1: {
@@ -2374,8 +2359,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_header_value_connection_token;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_header_value_connection_2:
s_n_llhttp__internal__n_header_value_connection_2: {
@@ -2398,8 +2382,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_header_value_connection_token;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_header_value_connection_3:
s_n_llhttp__internal__n_header_value_connection_3: {
@@ -2422,8 +2405,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_header_value_connection_token;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_header_value_connection:
s_n_llhttp__internal__n_header_value_connection: {
@@ -2455,8 +2437,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_header_value_connection_token;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_error_56:
s_n_llhttp__internal__n_error_56: {
@@ -2465,8 +2446,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_error_57:
s_n_llhttp__internal__n_error_57: {
@@ -2475,8 +2455,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_header_value_content_length_ws:
s_n_llhttp__internal__n_header_value_content_length_ws: {
@@ -2498,8 +2477,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_7;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_header_value_content_length:
s_n_llhttp__internal__n_header_value_content_length: {
@@ -2561,8 +2539,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_header_value_content_length_ws;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_error_59:
s_n_llhttp__internal__n_error_59: {
@@ -2571,8 +2548,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_error_58:
s_n_llhttp__internal__n_error_58: {
@@ -2581,8 +2557,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_header_value_te_token_ows:
s_n_llhttp__internal__n_header_value_te_token_ows: {
@@ -2602,8 +2577,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_header_value_te_chunked;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_header_value:
s_n_llhttp__internal__n_header_value: {
@@ -2632,7 +2606,6 @@ static llparse_state_t llhttp__internal__run(
if (endp - p >= 16) {
__m128i ranges;
__m128i input;
- int avail;
int match_len;
/* Load input */
@@ -2652,6 +2625,78 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_header_value_otherwise;
}
#endif /* __SSE4_2__ */
+ #ifdef __ARM_NEON__
+ while (endp - p >= 16) {
+ uint8x16_t input;
+ uint8x16_t single;
+ uint8x16_t mask;
+ uint8x8_t narrow;
+ uint64_t match_mask;
+ int match_len;
+
+ /* Load input */
+ input = vld1q_u8(p);
+ /* Find first character that does not match `ranges` */
+ single = vceqq_u8(input, vdupq_n_u8(0x9));
+ mask = single;
+ single = vandq_u16(
+ vcgeq_u8(input, vdupq_n_u8(' ')),
+ vcleq_u8(input, vdupq_n_u8('~'))
+ );
+ mask = vorrq_u16(mask, single);
+ single = vandq_u16(
+ vcgeq_u8(input, vdupq_n_u8(0x80)),
+ vcleq_u8(input, vdupq_n_u8(0xff))
+ );
+ mask = vorrq_u16(mask, single);
+ narrow = vshrn_n_u16(mask, 4);
+ match_mask = ~vget_lane_u64(vreinterpret_u64_u8(narrow), 0);
+ match_len = __builtin_ctzll(match_mask) >> 2;
+ if (match_len != 16) {
+ p += match_len;
+ goto s_n_llhttp__internal__n_header_value_otherwise;
+ }
+ p += 16;
+ }
+ if (p == endp) {
+ return s_n_llhttp__internal__n_header_value;
+ }
+ #endif /* __ARM_NEON__ */
+ #ifdef __wasm_simd128__
+ while (endp - p >= 16) {
+ v128_t input;
+ v128_t mask;
+ v128_t single;
+ int match_len;
+
+ /* Load input */
+ input = wasm_v128_load(p);
+ /* Find first character that does not match `ranges` */
+ single = wasm_i8x16_eq(input, wasm_u8x16_const_splat(0x9));
+ mask = single;
+ single = wasm_v128_and(
+ wasm_i8x16_ge(input, wasm_u8x16_const_splat(' ')),
+ wasm_i8x16_le(input, wasm_u8x16_const_splat('~'))
+ );
+ mask = wasm_v128_or(mask, single);
+ single = wasm_v128_and(
+ wasm_i8x16_ge(input, wasm_u8x16_const_splat(0x80)),
+ wasm_i8x16_le(input, wasm_u8x16_const_splat(0xff))
+ );
+ mask = wasm_v128_or(mask, single);
+ match_len = __builtin_ctz(
+ ~wasm_i8x16_bitmask(mask)
+ );
+ if (match_len != 16) {
+ p += match_len;
+ goto s_n_llhttp__internal__n_header_value_otherwise;
+ }
+ p += 16;
+ }
+ if (p == endp) {
+ return s_n_llhttp__internal__n_header_value;
+ }
+ #endif /* __wasm_simd128__ */
switch (lookup_table[(uint8_t) *p]) {
case 1: {
p++;
@@ -2661,8 +2706,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_header_value_otherwise;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_header_value_te_token:
s_n_llhttp__internal__n_header_value_te_token: {
@@ -2700,8 +2744,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_invoke_update_header_state_9;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_header_value_te_chunked_last:
s_n_llhttp__internal__n_header_value_te_chunked_last: {
@@ -2726,8 +2769,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_header_value_te_token;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_header_value_te_chunked:
s_n_llhttp__internal__n_header_value_te_chunked: {
@@ -2750,8 +2792,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_header_value_te_token;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1:
s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1: {
@@ -2761,8 +2802,7 @@ static llparse_state_t llhttp__internal__run(
state->_span_pos0 = (void*) p;
state->_span_cb0 = llhttp__on_header_value;
goto s_n_llhttp__internal__n_invoke_load_header_state_3;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_header_value_discard_ws:
s_n_llhttp__internal__n_header_value_discard_ws: {
@@ -2790,8 +2830,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_invoke_load_header_state:
s_n_llhttp__internal__n_invoke_load_header_state: {
@@ -2803,8 +2842,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_header_value_discard_ws;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete:
s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete: {
@@ -2816,8 +2854,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_error_45;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_header_field_general_otherwise:
s_n_llhttp__internal__n_header_field_general_otherwise: {
@@ -2832,8 +2869,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_error_62;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_header_field_general:
s_n_llhttp__internal__n_header_field_general: {
@@ -2862,7 +2898,6 @@ static llparse_state_t llhttp__internal__run(
if (endp - p >= 16) {
__m128i ranges;
__m128i input;
- int avail;
int match_len;
/* Load input */
@@ -2903,8 +2938,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_header_field_general_otherwise;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_header_field_colon:
s_n_llhttp__internal__n_header_field_colon: {
@@ -2922,8 +2956,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_invoke_update_header_state_10;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_header_field_3:
s_n_llhttp__internal__n_header_field_3: {
@@ -2947,8 +2980,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_invoke_update_header_state_11;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_header_field_4:
s_n_llhttp__internal__n_header_field_4: {
@@ -2972,8 +3004,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_invoke_update_header_state_11;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_header_field_2:
s_n_llhttp__internal__n_header_field_2: {
@@ -2993,8 +3024,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_invoke_update_header_state_11;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_header_field_1:
s_n_llhttp__internal__n_header_field_1: {
@@ -3017,8 +3047,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_invoke_update_header_state_11;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_header_field_5:
s_n_llhttp__internal__n_header_field_5: {
@@ -3042,8 +3071,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_invoke_update_header_state_11;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_header_field_6:
s_n_llhttp__internal__n_header_field_6: {
@@ -3067,8 +3095,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_invoke_update_header_state_11;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_header_field_7:
s_n_llhttp__internal__n_header_field_7: {
@@ -3092,8 +3119,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_invoke_update_header_state_11;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_header_field:
s_n_llhttp__internal__n_header_field: {
@@ -3121,8 +3147,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_invoke_update_header_state_11;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_span_start_llhttp__on_header_field:
s_n_llhttp__internal__n_span_start_llhttp__on_header_field: {
@@ -3132,8 +3157,7 @@ static llparse_state_t llhttp__internal__run(
state->_span_pos0 = (void*) p;
state->_span_cb0 = llhttp__on_header_field;
goto s_n_llhttp__internal__n_header_field;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_header_field_start:
s_n_llhttp__internal__n_header_field_start: {
@@ -3156,8 +3180,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_span_start_llhttp__on_header_field;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_headers_start:
s_n_llhttp__internal__n_headers_start: {
@@ -3173,8 +3196,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_header_field_start;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_url_to_http_09:
s_n_llhttp__internal__n_url_to_http_09: {
@@ -3194,8 +3216,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_invoke_update_http_major;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_url_skip_to_http09:
s_n_llhttp__internal__n_url_skip_to_http09: {
@@ -3216,8 +3237,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_url_to_http_09;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_url_skip_lf_to_http09_1:
s_n_llhttp__internal__n_url_skip_lf_to_http09_1: {
@@ -3233,8 +3253,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_error_63;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_url_skip_lf_to_http09:
s_n_llhttp__internal__n_url_skip_lf_to_http09: {
@@ -3258,8 +3277,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_error_63;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_req_pri_upgrade:
s_n_llhttp__internal__n_req_pri_upgrade: {
@@ -3273,17 +3291,16 @@ static llparse_state_t llhttp__internal__run(
switch (match_seq.status) {
case kMatchComplete: {
p++;
- goto s_n_llhttp__internal__n_error_71;
+ goto s_n_llhttp__internal__n_error_72;
}
case kMatchPause: {
return s_n_llhttp__internal__n_req_pri_upgrade;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_72;
+ goto s_n_llhttp__internal__n_error_73;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_req_http_complete_crlf:
s_n_llhttp__internal__n_req_http_complete_crlf: {
@@ -3299,8 +3316,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_invoke_test_lenient_flags_26;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_req_http_complete:
s_n_llhttp__internal__n_req_http_complete: {
@@ -3317,11 +3333,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_req_http_complete_crlf;
}
default: {
- goto s_n_llhttp__internal__n_error_70;
+ goto s_n_llhttp__internal__n_error_71;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_invoke_load_method_1:
s_n_llhttp__internal__n_invoke_load_method_1: {
@@ -3331,8 +3346,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_req_http_complete;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_invoke_llhttp__on_version_complete:
s_n_llhttp__internal__n_invoke_llhttp__on_version_complete: {
@@ -3342,30 +3356,27 @@ static llparse_state_t llhttp__internal__run(
case 21:
goto s_n_llhttp__internal__n_pause_21;
default:
- goto s_n_llhttp__internal__n_error_67;
+ goto s_n_llhttp__internal__n_error_68;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- case s_n_llhttp__internal__n_error_66:
- s_n_llhttp__internal__n_error_66: {
+ case s_n_llhttp__internal__n_error_67:
+ s_n_llhttp__internal__n_error_67: {
state->error = 0x9;
state->reason = "Invalid HTTP version";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- case s_n_llhttp__internal__n_error_73:
- s_n_llhttp__internal__n_error_73: {
+ case s_n_llhttp__internal__n_error_74:
+ s_n_llhttp__internal__n_error_74: {
state->error = 0x9;
state->reason = "Invalid minor version";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_req_http_minor:
s_n_llhttp__internal__n_req_http_minor: {
@@ -3427,18 +3438,16 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_span_end_llhttp__on_version_2;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- case s_n_llhttp__internal__n_error_74:
- s_n_llhttp__internal__n_error_74: {
+ case s_n_llhttp__internal__n_error_75:
+ s_n_llhttp__internal__n_error_75: {
state->error = 0x9;
state->reason = "Expected dot";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_req_http_dot:
s_n_llhttp__internal__n_req_http_dot: {
@@ -3454,18 +3463,16 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_span_end_llhttp__on_version_3;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- case s_n_llhttp__internal__n_error_75:
- s_n_llhttp__internal__n_error_75: {
+ case s_n_llhttp__internal__n_error_76:
+ s_n_llhttp__internal__n_error_76: {
state->error = 0x9;
state->reason = "Invalid major version";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_req_http_major:
s_n_llhttp__internal__n_req_http_major: {
@@ -3527,8 +3534,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_span_end_llhttp__on_version_4;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_span_start_llhttp__on_version:
s_n_llhttp__internal__n_span_start_llhttp__on_version: {
@@ -3538,80 +3544,297 @@ static llparse_state_t llhttp__internal__run(
state->_span_pos0 = (void*) p;
state->_span_cb0 = llhttp__on_version;
goto s_n_llhttp__internal__n_req_http_major;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- case s_n_llhttp__internal__n_req_http_start_1:
- s_n_llhttp__internal__n_req_http_start_1: {
- llparse_match_t match_seq;
-
+ case s_n_llhttp__internal__n_req_after_protocol:
+ s_n_llhttp__internal__n_req_after_protocol: {
if (p == endp) {
- return s_n_llhttp__internal__n_req_http_start_1;
+ return s_n_llhttp__internal__n_req_after_protocol;
}
- match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob13, 4);
- p = match_seq.current;
- switch (match_seq.status) {
- case kMatchComplete: {
+ switch (*p) {
+ case '/': {
p++;
+ goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
+ }
+ default: {
+ goto s_n_llhttp__internal__n_error_77;
+ }
+ }
+ UNREACHABLE;
+ }
+ case s_n_llhttp__internal__n_invoke_load_method:
+ s_n_llhttp__internal__n_invoke_load_method: {
+ switch (llhttp__internal__c_load_method(state, p, endp)) {
+ case 0:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 1:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 2:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 3:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 4:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 5:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 6:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 7:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 8:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 9:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 10:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 11:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 12:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 13:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 14:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 15:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 16:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 17:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 18:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 19:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 20:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 21:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 22:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 23:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 24:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 25:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 26:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 27:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 28:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 29:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 30:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 31:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 32:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 33:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 34:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 46:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ default:
+ goto s_n_llhttp__internal__n_error_66;
+ }
+ UNREACHABLE;
+ }
+ case s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete:
+ s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete: {
+ switch (llhttp__on_protocol_complete(state, p, endp)) {
+ case 0:
goto s_n_llhttp__internal__n_invoke_load_method;
- }
- case kMatchPause: {
- return s_n_llhttp__internal__n_req_http_start_1;
- }
- case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_78;
- }
+ case 21:
+ goto s_n_llhttp__internal__n_pause_22;
+ default:
+ goto s_n_llhttp__internal__n_error_65;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- case s_n_llhttp__internal__n_req_http_start_2:
- s_n_llhttp__internal__n_req_http_start_2: {
+ case s_n_llhttp__internal__n_error_82:
+ s_n_llhttp__internal__n_error_82: {
+ state->error = 0x8;
+ state->reason = "Expected HTTP/, RTSP/ or ICE/";
+ state->error_pos = (const char*) p;
+ state->_current = (void*) (intptr_t) s_error;
+ return s_error;
+ UNREACHABLE;
+ }
+ case s_n_llhttp__internal__n_req_after_http_start_1:
+ s_n_llhttp__internal__n_req_after_http_start_1: {
llparse_match_t match_seq;
if (p == endp) {
- return s_n_llhttp__internal__n_req_http_start_2;
+ return s_n_llhttp__internal__n_req_after_http_start_1;
}
- match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob15, 3);
+ match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob13, 3);
p = match_seq.current;
switch (match_seq.status) {
case kMatchComplete: {
p++;
+ goto s_n_llhttp__internal__n_span_end_llhttp__on_protocol;
+ }
+ case kMatchPause: {
+ return s_n_llhttp__internal__n_req_after_http_start_1;
+ }
+ case kMatchMismatch: {
+ goto s_n_llhttp__internal__n_span_end_llhttp__on_protocol_3;
+ }
+ }
+ UNREACHABLE;
+ }
+ case s_n_llhttp__internal__n_invoke_load_method_2:
+ s_n_llhttp__internal__n_invoke_load_method_2: {
+ switch (llhttp__internal__c_load_method(state, p, endp)) {
+ case 33:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ default:
+ goto s_n_llhttp__internal__n_error_79;
+ }
+ UNREACHABLE;
+ }
+ case s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete_1:
+ s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete_1: {
+ switch (llhttp__on_protocol_complete(state, p, endp)) {
+ case 0:
goto s_n_llhttp__internal__n_invoke_load_method_2;
- }
- case kMatchPause: {
- return s_n_llhttp__internal__n_req_http_start_2;
- }
- case kMatchMismatch: {
+ case 21:
+ goto s_n_llhttp__internal__n_pause_23;
+ default:
goto s_n_llhttp__internal__n_error_78;
- }
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- case s_n_llhttp__internal__n_req_http_start_3:
- s_n_llhttp__internal__n_req_http_start_3: {
+ case s_n_llhttp__internal__n_req_after_http_start_2:
+ s_n_llhttp__internal__n_req_after_http_start_2: {
llparse_match_t match_seq;
if (p == endp) {
- return s_n_llhttp__internal__n_req_http_start_3;
+ return s_n_llhttp__internal__n_req_after_http_start_2;
}
- match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob16, 4);
+ match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob15, 2);
p = match_seq.current;
switch (match_seq.status) {
case kMatchComplete: {
p++;
- goto s_n_llhttp__internal__n_invoke_load_method_3;
+ goto s_n_llhttp__internal__n_span_end_llhttp__on_protocol_1;
}
case kMatchPause: {
- return s_n_llhttp__internal__n_req_http_start_3;
+ return s_n_llhttp__internal__n_req_after_http_start_2;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_78;
+ goto s_n_llhttp__internal__n_span_end_llhttp__on_protocol_3;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
+ }
+ case s_n_llhttp__internal__n_invoke_load_method_3:
+ s_n_llhttp__internal__n_invoke_load_method_3: {
+ switch (llhttp__internal__c_load_method(state, p, endp)) {
+ case 1:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 3:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 6:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 35:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 36:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 37:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 38:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 39:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 40:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 41:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 42:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 43:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 44:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ case 45:
+ goto s_n_llhttp__internal__n_req_after_protocol;
+ default:
+ goto s_n_llhttp__internal__n_error_81;
+ }
+ UNREACHABLE;
+ }
+ case s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete_2:
+ s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete_2: {
+ switch (llhttp__on_protocol_complete(state, p, endp)) {
+ case 0:
+ goto s_n_llhttp__internal__n_invoke_load_method_3;
+ case 21:
+ goto s_n_llhttp__internal__n_pause_24;
+ default:
+ goto s_n_llhttp__internal__n_error_80;
+ }
+ UNREACHABLE;
+ }
+ case s_n_llhttp__internal__n_req_after_http_start_3:
+ s_n_llhttp__internal__n_req_after_http_start_3: {
+ llparse_match_t match_seq;
+
+ if (p == endp) {
+ return s_n_llhttp__internal__n_req_after_http_start_3;
+ }
+ match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob16, 3);
+ p = match_seq.current;
+ switch (match_seq.status) {
+ case kMatchComplete: {
+ p++;
+ goto s_n_llhttp__internal__n_span_end_llhttp__on_protocol_2;
+ }
+ case kMatchPause: {
+ return s_n_llhttp__internal__n_req_after_http_start_3;
+ }
+ case kMatchMismatch: {
+ goto s_n_llhttp__internal__n_span_end_llhttp__on_protocol_3;
+ }
+ }
+ UNREACHABLE;
+ }
+ case s_n_llhttp__internal__n_req_after_http_start:
+ s_n_llhttp__internal__n_req_after_http_start: {
+ if (p == endp) {
+ return s_n_llhttp__internal__n_req_after_http_start;
+ }
+ switch (*p) {
+ case 'H': {
+ p++;
+ goto s_n_llhttp__internal__n_req_after_http_start_1;
+ }
+ case 'I': {
+ p++;
+ goto s_n_llhttp__internal__n_req_after_http_start_2;
+ }
+ case 'R': {
+ p++;
+ goto s_n_llhttp__internal__n_req_after_http_start_3;
+ }
+ default: {
+ goto s_n_llhttp__internal__n_span_end_llhttp__on_protocol_3;
+ }
+ }
+ UNREACHABLE;
+ }
+ case s_n_llhttp__internal__n_span_start_llhttp__on_protocol:
+ s_n_llhttp__internal__n_span_start_llhttp__on_protocol: {
+ if (p == endp) {
+ return s_n_llhttp__internal__n_span_start_llhttp__on_protocol;
+ }
+ state->_span_pos0 = (void*) p;
+ state->_span_cb0 = llhttp__on_protocol;
+ goto s_n_llhttp__internal__n_req_after_http_start;
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_req_http_start:
s_n_llhttp__internal__n_req_http_start: {
@@ -3623,24 +3846,11 @@ static llparse_state_t llhttp__internal__run(
p++;
goto s_n_llhttp__internal__n_req_http_start;
}
- case 'H': {
- p++;
- goto s_n_llhttp__internal__n_req_http_start_1;
- }
- case 'I': {
- p++;
- goto s_n_llhttp__internal__n_req_http_start_2;
- }
- case 'R': {
- p++;
- goto s_n_llhttp__internal__n_req_http_start_3;
- }
default: {
- goto s_n_llhttp__internal__n_error_78;
+ goto s_n_llhttp__internal__n_span_start_llhttp__on_protocol;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_url_to_http:
s_n_llhttp__internal__n_url_to_http: {
@@ -3660,8 +3870,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_invoke_llhttp__on_url_complete_1;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_url_skip_to_http:
s_n_llhttp__internal__n_url_skip_to_http: {
@@ -3682,8 +3891,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_url_to_http;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_url_fragment:
s_n_llhttp__internal__n_url_fragment: {
@@ -3727,11 +3935,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_url_fragment;
}
default: {
- goto s_n_llhttp__internal__n_error_79;
+ goto s_n_llhttp__internal__n_error_83;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_span_end_stub_query_3:
s_n_llhttp__internal__n_span_end_stub_query_3: {
@@ -3740,8 +3947,7 @@ static llparse_state_t llhttp__internal__run(
}
p++;
goto s_n_llhttp__internal__n_url_fragment;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_url_query:
s_n_llhttp__internal__n_url_query: {
@@ -3788,11 +3994,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_span_end_stub_query_3;
}
default: {
- goto s_n_llhttp__internal__n_error_80;
+ goto s_n_llhttp__internal__n_error_84;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_url_query_or_fragment:
s_n_llhttp__internal__n_url_query_or_fragment: {
@@ -3826,11 +4031,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_url_query;
}
default: {
- goto s_n_llhttp__internal__n_error_81;
+ goto s_n_llhttp__internal__n_error_85;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_url_path:
s_n_llhttp__internal__n_url_path: {
@@ -3868,8 +4072,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_url_query_or_fragment;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_span_start_stub_path_2:
s_n_llhttp__internal__n_span_start_stub_path_2: {
@@ -3878,8 +4081,7 @@ static llparse_state_t llhttp__internal__run(
}
p++;
goto s_n_llhttp__internal__n_url_path;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_span_start_stub_path:
s_n_llhttp__internal__n_span_start_stub_path: {
@@ -3888,8 +4090,7 @@ static llparse_state_t llhttp__internal__run(
}
p++;
goto s_n_llhttp__internal__n_url_path;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_span_start_stub_path_1:
s_n_llhttp__internal__n_span_start_stub_path_1: {
@@ -3898,8 +4099,7 @@ static llparse_state_t llhttp__internal__run(
}
p++;
goto s_n_llhttp__internal__n_url_path;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_url_server_with_at:
s_n_llhttp__internal__n_url_server_with_at: {
@@ -3951,14 +4151,13 @@ static llparse_state_t llhttp__internal__run(
}
case 8: {
p++;
- goto s_n_llhttp__internal__n_error_82;
+ goto s_n_llhttp__internal__n_error_86;
}
default: {
- goto s_n_llhttp__internal__n_error_83;
+ goto s_n_llhttp__internal__n_error_87;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_url_server:
s_n_llhttp__internal__n_url_server: {
@@ -4013,11 +4212,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_url_server_with_at;
}
default: {
- goto s_n_llhttp__internal__n_error_84;
+ goto s_n_llhttp__internal__n_error_88;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_url_schema_delim_1:
s_n_llhttp__internal__n_url_schema_delim_1: {
@@ -4030,11 +4228,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_url_server;
}
default: {
- goto s_n_llhttp__internal__n_error_85;
+ goto s_n_llhttp__internal__n_error_89;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_url_schema_delim:
s_n_llhttp__internal__n_url_schema_delim: {
@@ -4067,11 +4264,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_url_schema_delim_1;
}
default: {
- goto s_n_llhttp__internal__n_error_85;
+ goto s_n_llhttp__internal__n_error_89;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_span_end_stub_schema:
s_n_llhttp__internal__n_span_end_stub_schema: {
@@ -4080,8 +4276,7 @@ static llparse_state_t llhttp__internal__run(
}
p++;
goto s_n_llhttp__internal__n_url_schema_delim;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_url_schema:
s_n_llhttp__internal__n_url_schema: {
@@ -4119,11 +4314,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_url_schema;
}
default: {
- goto s_n_llhttp__internal__n_error_86;
+ goto s_n_llhttp__internal__n_error_90;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_url_start:
s_n_llhttp__internal__n_url_start: {
@@ -4160,11 +4354,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_url_schema;
}
default: {
- goto s_n_llhttp__internal__n_error_87;
+ goto s_n_llhttp__internal__n_error_91;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_span_start_llhttp__on_url_1:
s_n_llhttp__internal__n_span_start_llhttp__on_url_1: {
@@ -4174,8 +4367,7 @@ static llparse_state_t llhttp__internal__run(
state->_span_pos0 = (void*) p;
state->_span_cb0 = llhttp__on_url;
goto s_n_llhttp__internal__n_url_start;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_url_entry_normal:
s_n_llhttp__internal__n_url_entry_normal: {
@@ -4195,8 +4387,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_span_start_llhttp__on_url_1;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_span_start_llhttp__on_url:
s_n_llhttp__internal__n_span_start_llhttp__on_url: {
@@ -4206,8 +4397,7 @@ static llparse_state_t llhttp__internal__run(
state->_span_pos0 = (void*) p;
state->_span_cb0 = llhttp__on_url;
goto s_n_llhttp__internal__n_url_server;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_url_entry_connect:
s_n_llhttp__internal__n_url_entry_connect: {
@@ -4227,8 +4417,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_span_start_llhttp__on_url;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_req_spaces_before_url:
s_n_llhttp__internal__n_req_spaces_before_url: {
@@ -4244,8 +4433,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_invoke_is_equal_method;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_req_first_space_before_url:
s_n_llhttp__internal__n_req_first_space_before_url: {
@@ -4258,11 +4446,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_req_spaces_before_url;
}
default: {
- goto s_n_llhttp__internal__n_error_88;
+ goto s_n_llhttp__internal__n_error_92;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_invoke_llhttp__on_method_complete_1:
s_n_llhttp__internal__n_invoke_llhttp__on_method_complete_1: {
@@ -4270,12 +4457,11 @@ static llparse_state_t llhttp__internal__run(
case 0:
goto s_n_llhttp__internal__n_req_first_space_before_url;
case 21:
- goto s_n_llhttp__internal__n_pause_26;
+ goto s_n_llhttp__internal__n_pause_29;
default:
- goto s_n_llhttp__internal__n_error_107;
+ goto s_n_llhttp__internal__n_error_111;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_2:
s_n_llhttp__internal__n_after_start_req_2: {
@@ -4289,11 +4475,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_invoke_store_method_1;
}
default: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_3:
s_n_llhttp__internal__n_after_start_req_3: {
@@ -4314,11 +4499,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_3;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_1:
s_n_llhttp__internal__n_after_start_req_1: {
@@ -4335,11 +4519,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_after_start_req_3;
}
default: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_4:
s_n_llhttp__internal__n_after_start_req_4: {
@@ -4360,11 +4543,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_4;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_6:
s_n_llhttp__internal__n_after_start_req_6: {
@@ -4385,11 +4567,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_6;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_8:
s_n_llhttp__internal__n_after_start_req_8: {
@@ -4410,11 +4591,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_8;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_9:
s_n_llhttp__internal__n_after_start_req_9: {
@@ -4428,11 +4608,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_invoke_store_method_1;
}
default: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_7:
s_n_llhttp__internal__n_after_start_req_7: {
@@ -4449,11 +4628,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_after_start_req_9;
}
default: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_5:
s_n_llhttp__internal__n_after_start_req_5: {
@@ -4470,11 +4648,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_after_start_req_7;
}
default: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_12:
s_n_llhttp__internal__n_after_start_req_12: {
@@ -4495,11 +4672,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_12;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_13:
s_n_llhttp__internal__n_after_start_req_13: {
@@ -4520,11 +4696,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_13;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_11:
s_n_llhttp__internal__n_after_start_req_11: {
@@ -4541,11 +4716,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_after_start_req_13;
}
default: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_10:
s_n_llhttp__internal__n_after_start_req_10: {
@@ -4558,11 +4732,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_after_start_req_11;
}
default: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_14:
s_n_llhttp__internal__n_after_start_req_14: {
@@ -4583,11 +4756,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_14;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_17:
s_n_llhttp__internal__n_after_start_req_17: {
@@ -4608,11 +4780,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_17;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_16:
s_n_llhttp__internal__n_after_start_req_16: {
@@ -4629,8 +4800,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_invoke_store_method_1;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_15:
s_n_llhttp__internal__n_after_start_req_15: {
@@ -4650,11 +4820,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_15;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_18:
s_n_llhttp__internal__n_after_start_req_18: {
@@ -4675,11 +4844,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_18;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_20:
s_n_llhttp__internal__n_after_start_req_20: {
@@ -4700,11 +4868,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_20;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_21:
s_n_llhttp__internal__n_after_start_req_21: {
@@ -4725,11 +4892,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_21;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_19:
s_n_llhttp__internal__n_after_start_req_19: {
@@ -4746,11 +4912,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_after_start_req_21;
}
default: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_23:
s_n_llhttp__internal__n_after_start_req_23: {
@@ -4771,11 +4936,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_23;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_24:
s_n_llhttp__internal__n_after_start_req_24: {
@@ -4796,11 +4960,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_24;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_26:
s_n_llhttp__internal__n_after_start_req_26: {
@@ -4821,11 +4984,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_26;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_28:
s_n_llhttp__internal__n_after_start_req_28: {
@@ -4846,11 +5008,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_28;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_29:
s_n_llhttp__internal__n_after_start_req_29: {
@@ -4864,11 +5025,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_invoke_store_method_1;
}
default: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_27:
s_n_llhttp__internal__n_after_start_req_27: {
@@ -4885,11 +5045,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_after_start_req_29;
}
default: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_25:
s_n_llhttp__internal__n_after_start_req_25: {
@@ -4906,11 +5065,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_after_start_req_27;
}
default: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_30:
s_n_llhttp__internal__n_after_start_req_30: {
@@ -4931,11 +5089,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_30;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_22:
s_n_llhttp__internal__n_after_start_req_22: {
@@ -4960,11 +5117,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_after_start_req_30;
}
default: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_31:
s_n_llhttp__internal__n_after_start_req_31: {
@@ -4985,11 +5141,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_31;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_32:
s_n_llhttp__internal__n_after_start_req_32: {
@@ -5010,11 +5165,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_32;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_35:
s_n_llhttp__internal__n_after_start_req_35: {
@@ -5035,11 +5189,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_35;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_36:
s_n_llhttp__internal__n_after_start_req_36: {
@@ -5060,11 +5213,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_36;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_34:
s_n_llhttp__internal__n_after_start_req_34: {
@@ -5081,11 +5233,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_after_start_req_36;
}
default: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_37:
s_n_llhttp__internal__n_after_start_req_37: {
@@ -5106,11 +5257,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_37;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_38:
s_n_llhttp__internal__n_after_start_req_38: {
@@ -5131,11 +5281,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_38;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_42:
s_n_llhttp__internal__n_after_start_req_42: {
@@ -5156,11 +5305,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_42;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_43:
s_n_llhttp__internal__n_after_start_req_43: {
@@ -5181,11 +5329,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_43;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_41:
s_n_llhttp__internal__n_after_start_req_41: {
@@ -5202,11 +5349,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_after_start_req_43;
}
default: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_40:
s_n_llhttp__internal__n_after_start_req_40: {
@@ -5219,11 +5365,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_after_start_req_41;
}
default: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_39:
s_n_llhttp__internal__n_after_start_req_39: {
@@ -5241,11 +5386,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_after_start_req_40;
}
default: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_45:
s_n_llhttp__internal__n_after_start_req_45: {
@@ -5266,11 +5410,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_45;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_44:
s_n_llhttp__internal__n_after_start_req_44: {
@@ -5288,11 +5431,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_invoke_store_method_1;
}
default: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_33:
s_n_llhttp__internal__n_after_start_req_33: {
@@ -5321,11 +5463,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_after_start_req_44;
}
default: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_46:
s_n_llhttp__internal__n_after_start_req_46: {
@@ -5346,11 +5487,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_46;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_49:
s_n_llhttp__internal__n_after_start_req_49: {
@@ -5371,11 +5511,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_49;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_50:
s_n_llhttp__internal__n_after_start_req_50: {
@@ -5396,11 +5535,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_50;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_51:
s_n_llhttp__internal__n_after_start_req_51: {
@@ -5421,11 +5559,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_51;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_52:
s_n_llhttp__internal__n_after_start_req_52: {
@@ -5446,11 +5583,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_52;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_48:
s_n_llhttp__internal__n_after_start_req_48: {
@@ -5475,11 +5611,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_after_start_req_52;
}
default: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_47:
s_n_llhttp__internal__n_after_start_req_47: {
@@ -5492,11 +5627,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_after_start_req_48;
}
default: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_55:
s_n_llhttp__internal__n_after_start_req_55: {
@@ -5517,11 +5651,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_55;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_57:
s_n_llhttp__internal__n_after_start_req_57: {
@@ -5535,11 +5668,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_invoke_store_method_1;
}
default: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_58:
s_n_llhttp__internal__n_after_start_req_58: {
@@ -5560,11 +5692,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_58;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_56:
s_n_llhttp__internal__n_after_start_req_56: {
@@ -5581,11 +5712,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_after_start_req_58;
}
default: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_54:
s_n_llhttp__internal__n_after_start_req_54: {
@@ -5602,11 +5732,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_after_start_req_56;
}
default: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_59:
s_n_llhttp__internal__n_after_start_req_59: {
@@ -5627,11 +5756,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_59;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_60:
s_n_llhttp__internal__n_after_start_req_60: {
@@ -5652,11 +5780,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_60;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_53:
s_n_llhttp__internal__n_after_start_req_53: {
@@ -5677,11 +5804,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_after_start_req_60;
}
default: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_62:
s_n_llhttp__internal__n_after_start_req_62: {
@@ -5702,11 +5828,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_62;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_63:
s_n_llhttp__internal__n_after_start_req_63: {
@@ -5727,11 +5852,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_63;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_61:
s_n_llhttp__internal__n_after_start_req_61: {
@@ -5748,11 +5872,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_after_start_req_63;
}
default: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_66:
s_n_llhttp__internal__n_after_start_req_66: {
@@ -5773,11 +5896,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_66;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_68:
s_n_llhttp__internal__n_after_start_req_68: {
@@ -5798,11 +5920,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_68;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_69:
s_n_llhttp__internal__n_after_start_req_69: {
@@ -5823,11 +5944,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_69;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_67:
s_n_llhttp__internal__n_after_start_req_67: {
@@ -5844,11 +5964,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_after_start_req_69;
}
default: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_70:
s_n_llhttp__internal__n_after_start_req_70: {
@@ -5869,11 +5988,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_after_start_req_70;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_65:
s_n_llhttp__internal__n_after_start_req_65: {
@@ -5894,11 +6012,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_after_start_req_70;
}
default: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req_64:
s_n_llhttp__internal__n_after_start_req_64: {
@@ -5911,11 +6028,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_after_start_req_65;
}
default: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_after_start_req:
s_n_llhttp__internal__n_after_start_req: {
@@ -5992,11 +6108,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_after_start_req_64;
}
default: {
- goto s_n_llhttp__internal__n_error_108;
+ goto s_n_llhttp__internal__n_error_112;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_span_start_llhttp__on_method_1:
s_n_llhttp__internal__n_span_start_llhttp__on_method_1: {
@@ -6006,8 +6121,7 @@ static llparse_state_t llhttp__internal__run(
state->_span_pos0 = (void*) p;
state->_span_cb0 = llhttp__on_method;
goto s_n_llhttp__internal__n_after_start_req;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_res_line_almost_done:
s_n_llhttp__internal__n_res_line_almost_done: {
@@ -6027,8 +6141,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_invoke_test_lenient_flags_29;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_invoke_test_lenient_flags_30:
s_n_llhttp__internal__n_invoke_test_lenient_flags_30: {
@@ -6036,10 +6149,9 @@ static llparse_state_t llhttp__internal__run(
case 1:
goto s_n_llhttp__internal__n_invoke_llhttp__on_status_complete;
default:
- goto s_n_llhttp__internal__n_error_94;
+ goto s_n_llhttp__internal__n_error_98;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_res_status:
s_n_llhttp__internal__n_res_status: {
@@ -6058,8 +6170,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_res_status;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_span_start_llhttp__on_status:
s_n_llhttp__internal__n_span_start_llhttp__on_status: {
@@ -6069,8 +6180,7 @@ static llparse_state_t llhttp__internal__run(
state->_span_pos0 = (void*) p;
state->_span_cb0 = llhttp__on_status;
goto s_n_llhttp__internal__n_res_status;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_res_status_code_otherwise:
s_n_llhttp__internal__n_res_status_code_otherwise: {
@@ -6091,11 +6201,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_span_start_llhttp__on_status;
}
default: {
- goto s_n_llhttp__internal__n_error_95;
+ goto s_n_llhttp__internal__n_error_99;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_res_status_code_digit_3:
s_n_llhttp__internal__n_res_status_code_digit_3: {
@@ -6154,11 +6263,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_invoke_mul_add_status_code_2;
}
default: {
- goto s_n_llhttp__internal__n_error_97;
+ goto s_n_llhttp__internal__n_error_101;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_res_status_code_digit_2:
s_n_llhttp__internal__n_res_status_code_digit_2: {
@@ -6217,11 +6325,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_invoke_mul_add_status_code_1;
}
default: {
- goto s_n_llhttp__internal__n_error_99;
+ goto s_n_llhttp__internal__n_error_103;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_res_status_code_digit_1:
s_n_llhttp__internal__n_res_status_code_digit_1: {
@@ -6280,11 +6387,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_invoke_mul_add_status_code;
}
default: {
- goto s_n_llhttp__internal__n_error_101;
+ goto s_n_llhttp__internal__n_error_105;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_res_after_version:
s_n_llhttp__internal__n_res_after_version: {
@@ -6297,11 +6403,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_invoke_update_status_code;
}
default: {
- goto s_n_llhttp__internal__n_error_102;
+ goto s_n_llhttp__internal__n_error_106;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_invoke_llhttp__on_version_complete_1:
s_n_llhttp__internal__n_invoke_llhttp__on_version_complete_1: {
@@ -6309,32 +6414,29 @@ static llparse_state_t llhttp__internal__run(
case 0:
goto s_n_llhttp__internal__n_res_after_version;
case 21:
- goto s_n_llhttp__internal__n_pause_25;
+ goto s_n_llhttp__internal__n_pause_28;
default:
- goto s_n_llhttp__internal__n_error_90;
+ goto s_n_llhttp__internal__n_error_94;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- case s_n_llhttp__internal__n_error_89:
- s_n_llhttp__internal__n_error_89: {
+ case s_n_llhttp__internal__n_error_93:
+ s_n_llhttp__internal__n_error_93: {
state->error = 0x9;
state->reason = "Invalid HTTP version";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- case s_n_llhttp__internal__n_error_103:
- s_n_llhttp__internal__n_error_103: {
+ case s_n_llhttp__internal__n_error_107:
+ s_n_llhttp__internal__n_error_107: {
state->error = 0x9;
state->reason = "Invalid minor version";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_res_http_minor:
s_n_llhttp__internal__n_res_http_minor: {
@@ -6396,18 +6498,16 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_span_end_llhttp__on_version_7;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- case s_n_llhttp__internal__n_error_104:
- s_n_llhttp__internal__n_error_104: {
+ case s_n_llhttp__internal__n_error_108:
+ s_n_llhttp__internal__n_error_108: {
state->error = 0x9;
state->reason = "Expected dot";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_res_http_dot:
s_n_llhttp__internal__n_res_http_dot: {
@@ -6423,18 +6523,16 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_span_end_llhttp__on_version_8;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- case s_n_llhttp__internal__n_error_105:
- s_n_llhttp__internal__n_error_105: {
+ case s_n_llhttp__internal__n_error_109:
+ s_n_llhttp__internal__n_error_109: {
state->error = 0x9;
state->reason = "Invalid major version";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_res_http_major:
s_n_llhttp__internal__n_res_http_major: {
@@ -6496,8 +6594,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_span_end_llhttp__on_version_9;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_span_start_llhttp__on_version_1:
s_n_llhttp__internal__n_span_start_llhttp__on_version_1: {
@@ -6507,32 +6604,147 @@ static llparse_state_t llhttp__internal__run(
state->_span_pos0 = (void*) p;
state->_span_cb0 = llhttp__on_version;
goto s_n_llhttp__internal__n_res_http_major;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- case s_n_llhttp__internal__n_start_res:
- s_n_llhttp__internal__n_start_res: {
+ case s_n_llhttp__internal__n_res_after_protocol:
+ s_n_llhttp__internal__n_res_after_protocol: {
+ if (p == endp) {
+ return s_n_llhttp__internal__n_res_after_protocol;
+ }
+ switch (*p) {
+ case '/': {
+ p++;
+ goto s_n_llhttp__internal__n_span_start_llhttp__on_version_1;
+ }
+ default: {
+ goto s_n_llhttp__internal__n_error_114;
+ }
+ }
+ UNREACHABLE;
+ }
+ case s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete_3:
+ s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete_3: {
+ switch (llhttp__on_protocol_complete(state, p, endp)) {
+ case 0:
+ goto s_n_llhttp__internal__n_res_after_protocol;
+ case 21:
+ goto s_n_llhttp__internal__n_pause_30;
+ default:
+ goto s_n_llhttp__internal__n_error_113;
+ }
+ UNREACHABLE;
+ }
+ case s_n_llhttp__internal__n_error_115:
+ s_n_llhttp__internal__n_error_115: {
+ state->error = 0x8;
+ state->reason = "Expected HTTP/, RTSP/ or ICE/";
+ state->error_pos = (const char*) p;
+ state->_current = (void*) (intptr_t) s_error;
+ return s_error;
+ UNREACHABLE;
+ }
+ case s_n_llhttp__internal__n_res_after_start_1:
+ s_n_llhttp__internal__n_res_after_start_1: {
llparse_match_t match_seq;
if (p == endp) {
- return s_n_llhttp__internal__n_start_res;
+ return s_n_llhttp__internal__n_res_after_start_1;
}
- match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob58, 5);
+ match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob58, 3);
p = match_seq.current;
switch (match_seq.status) {
case kMatchComplete: {
p++;
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version_1;
+ goto s_n_llhttp__internal__n_span_end_llhttp__on_protocol_4;
}
case kMatchPause: {
- return s_n_llhttp__internal__n_start_res;
+ return s_n_llhttp__internal__n_res_after_start_1;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_109;
+ goto s_n_llhttp__internal__n_span_end_llhttp__on_protocol_5;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
+ }
+ case s_n_llhttp__internal__n_res_after_start_2:
+ s_n_llhttp__internal__n_res_after_start_2: {
+ llparse_match_t match_seq;
+
+ if (p == endp) {
+ return s_n_llhttp__internal__n_res_after_start_2;
+ }
+ match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob59, 2);
+ p = match_seq.current;
+ switch (match_seq.status) {
+ case kMatchComplete: {
+ p++;
+ goto s_n_llhttp__internal__n_span_end_llhttp__on_protocol_4;
+ }
+ case kMatchPause: {
+ return s_n_llhttp__internal__n_res_after_start_2;
+ }
+ case kMatchMismatch: {
+ goto s_n_llhttp__internal__n_span_end_llhttp__on_protocol_5;
+ }
+ }
+ UNREACHABLE;
+ }
+ case s_n_llhttp__internal__n_res_after_start_3:
+ s_n_llhttp__internal__n_res_after_start_3: {
+ llparse_match_t match_seq;
+
+ if (p == endp) {
+ return s_n_llhttp__internal__n_res_after_start_3;
+ }
+ match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob60, 3);
+ p = match_seq.current;
+ switch (match_seq.status) {
+ case kMatchComplete: {
+ p++;
+ goto s_n_llhttp__internal__n_span_end_llhttp__on_protocol_4;
+ }
+ case kMatchPause: {
+ return s_n_llhttp__internal__n_res_after_start_3;
+ }
+ case kMatchMismatch: {
+ goto s_n_llhttp__internal__n_span_end_llhttp__on_protocol_5;
+ }
+ }
+ UNREACHABLE;
+ }
+ case s_n_llhttp__internal__n_res_after_start:
+ s_n_llhttp__internal__n_res_after_start: {
+ if (p == endp) {
+ return s_n_llhttp__internal__n_res_after_start;
+ }
+ switch (*p) {
+ case 'H': {
+ p++;
+ goto s_n_llhttp__internal__n_res_after_start_1;
+ }
+ case 'I': {
+ p++;
+ goto s_n_llhttp__internal__n_res_after_start_2;
+ }
+ case 'R': {
+ p++;
+ goto s_n_llhttp__internal__n_res_after_start_3;
+ }
+ default: {
+ goto s_n_llhttp__internal__n_span_end_llhttp__on_protocol_5;
+ }
+ }
+ UNREACHABLE;
+ }
+ case s_n_llhttp__internal__n_span_start_llhttp__on_protocol_1:
+ s_n_llhttp__internal__n_span_start_llhttp__on_protocol_1: {
+ if (p == endp) {
+ return s_n_llhttp__internal__n_span_start_llhttp__on_protocol_1;
+ }
+ state->_span_pos0 = (void*) p;
+ state->_span_cb0 = llhttp__on_protocol;
+ goto s_n_llhttp__internal__n_res_after_start;
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_invoke_llhttp__on_method_complete:
s_n_llhttp__internal__n_invoke_llhttp__on_method_complete: {
@@ -6540,12 +6752,11 @@ static llparse_state_t llhttp__internal__run(
case 0:
goto s_n_llhttp__internal__n_req_first_space_before_url;
case 21:
- goto s_n_llhttp__internal__n_pause_23;
+ goto s_n_llhttp__internal__n_pause_26;
default:
goto s_n_llhttp__internal__n_error_1;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_req_or_res_method_2:
s_n_llhttp__internal__n_req_or_res_method_2: {
@@ -6554,7 +6765,7 @@ static llparse_state_t llhttp__internal__run(
if (p == endp) {
return s_n_llhttp__internal__n_req_or_res_method_2;
}
- match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob59, 2);
+ match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob61, 2);
p = match_seq.current;
switch (match_seq.status) {
case kMatchComplete: {
@@ -6566,11 +6777,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_req_or_res_method_2;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_106;
+ goto s_n_llhttp__internal__n_error_110;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_invoke_update_type_1:
s_n_llhttp__internal__n_invoke_update_type_1: {
@@ -6578,8 +6788,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_span_start_llhttp__on_version_1;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_req_or_res_method_3:
s_n_llhttp__internal__n_req_or_res_method_3: {
@@ -6588,7 +6797,7 @@ static llparse_state_t llhttp__internal__run(
if (p == endp) {
return s_n_llhttp__internal__n_req_or_res_method_3;
}
- match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob60, 3);
+ match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob62, 3);
p = match_seq.current;
switch (match_seq.status) {
case kMatchComplete: {
@@ -6599,11 +6808,10 @@ static llparse_state_t llhttp__internal__run(
return s_n_llhttp__internal__n_req_or_res_method_3;
}
case kMatchMismatch: {
- goto s_n_llhttp__internal__n_error_106;
+ goto s_n_llhttp__internal__n_error_110;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_req_or_res_method_1:
s_n_llhttp__internal__n_req_or_res_method_1: {
@@ -6620,11 +6828,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_req_or_res_method_3;
}
default: {
- goto s_n_llhttp__internal__n_error_106;
+ goto s_n_llhttp__internal__n_error_110;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_req_or_res_method:
s_n_llhttp__internal__n_req_or_res_method: {
@@ -6637,11 +6844,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_req_or_res_method_1;
}
default: {
- goto s_n_llhttp__internal__n_error_106;
+ goto s_n_llhttp__internal__n_error_110;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_span_start_llhttp__on_method:
s_n_llhttp__internal__n_span_start_llhttp__on_method: {
@@ -6651,8 +6857,7 @@ static llparse_state_t llhttp__internal__run(
state->_span_pos0 = (void*) p;
state->_span_cb0 = llhttp__on_method;
goto s_n_llhttp__internal__n_req_or_res_method;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_start_req_or_res:
s_n_llhttp__internal__n_start_req_or_res: {
@@ -6667,8 +6872,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_invoke_update_type_2;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_invoke_load_type:
s_n_llhttp__internal__n_invoke_load_type: {
@@ -6676,12 +6880,11 @@ static llparse_state_t llhttp__internal__run(
case 1:
goto s_n_llhttp__internal__n_span_start_llhttp__on_method_1;
case 2:
- goto s_n_llhttp__internal__n_start_res;
+ goto s_n_llhttp__internal__n_span_start_llhttp__on_protocol_1;
default:
goto s_n_llhttp__internal__n_start_req_or_res;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_invoke_update_finish:
s_n_llhttp__internal__n_invoke_update_finish: {
@@ -6689,8 +6892,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_invoke_llhttp__on_message_begin;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
case s_n_llhttp__internal__n_start:
s_n_llhttp__internal__n_start: {
@@ -6710,12 +6912,10 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_invoke_load_initial_message_completed;
}
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
default:
- /* UNREACHABLE */
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_2: {
state->error = 0x7;
@@ -6723,32 +6923,28 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_update_finish_2: {
switch (llhttp__internal__c_update_finish_1(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_start;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_update_initial_message_completed: {
switch (llhttp__internal__c_update_initial_message_completed(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_invoke_update_finish_2;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_update_content_length: {
switch (llhttp__internal__c_update_content_length(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_invoke_update_initial_message_completed;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_8: {
state->error = 0x5;
@@ -6756,8 +6952,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_test_lenient_flags_3: {
switch (llhttp__internal__c_test_lenient_flags_3(state, p, endp)) {
@@ -6766,8 +6961,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_error_8;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_test_lenient_flags_2: {
switch (llhttp__internal__c_test_lenient_flags_2(state, p, endp)) {
@@ -6776,16 +6970,14 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_closed;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_update_finish_1: {
switch (llhttp__internal__c_update_finish_1(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_invoke_test_lenient_flags_2;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_pause_13: {
state->error = 0x15;
@@ -6793,8 +6985,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_is_equal_upgrade;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_38: {
state->error = 0x12;
@@ -6802,8 +6993,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_pause_15: {
state->error = 0x15;
@@ -6811,8 +7001,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_40: {
state->error = 0x14;
@@ -6820,8 +7009,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete_1: {
switch (llhttp__on_chunk_complete(state, p, endp)) {
@@ -6832,8 +7020,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_error_40;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_pause_2: {
state->error = 0x15;
@@ -6841,8 +7028,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_pause_1;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_9: {
state->error = 0x12;
@@ -6850,8 +7036,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_1: {
switch (llhttp__on_message_complete(state, p, endp)) {
@@ -6862,8 +7047,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_error_9;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_36: {
state->error = 0xc;
@@ -6871,8 +7055,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_10: {
state->error = 0xc;
@@ -6880,8 +7063,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_test_lenient_flags_4: {
switch (llhttp__internal__c_test_lenient_flags_4(state, p, endp)) {
@@ -6890,8 +7072,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_error_10;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_pause_3: {
state->error = 0x15;
@@ -6899,8 +7080,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_update_content_length_1;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_14: {
state->error = 0x14;
@@ -6908,8 +7088,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete: {
switch (llhttp__on_chunk_complete(state, p, endp)) {
@@ -6920,8 +7099,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_error_14;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_13: {
state->error = 0x19;
@@ -6929,8 +7107,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_test_lenient_flags_6: {
switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) {
@@ -6939,8 +7116,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_error_13;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_15: {
state->error = 0x2;
@@ -6948,8 +7124,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_test_lenient_flags_7: {
switch (llhttp__internal__c_test_lenient_flags_7(state, p, endp)) {
@@ -6958,8 +7133,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_error_15;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_body: {
const unsigned char* start;
@@ -6975,16 +7149,14 @@ static llparse_state_t llhttp__internal__run(
return s_error;
}
goto s_n_llhttp__internal__n_chunk_data_almost_done;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_or_flags: {
switch (llhttp__internal__c_or_flags(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_header_field_start;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_pause_4: {
state->error = 0x15;
@@ -6992,8 +7164,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_is_equal_content_length;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_12: {
state->error = 0x13;
@@ -7001,8 +7172,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_llhttp__on_chunk_header: {
switch (llhttp__on_chunk_header(state, p, endp)) {
@@ -7013,8 +7183,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_error_12;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_16: {
state->error = 0x2;
@@ -7022,8 +7191,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_test_lenient_flags_8: {
switch (llhttp__internal__c_test_lenient_flags_8(state, p, endp)) {
@@ -7032,8 +7200,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_error_16;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_11: {
state->error = 0x19;
@@ -7041,8 +7208,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_test_lenient_flags_5: {
switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) {
@@ -7051,8 +7217,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_error_11;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_17: {
state->error = 0x2;
@@ -7060,8 +7225,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_18: {
state->error = 0x2;
@@ -7069,8 +7233,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_20: {
state->error = 0x19;
@@ -7078,8 +7241,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_pause_5: {
state->error = 0x15;
@@ -7087,8 +7249,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_test_lenient_flags_9;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_19: {
state->error = 0x22;
@@ -7096,8 +7257,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name: {
const unsigned char* start;
@@ -7113,8 +7273,7 @@ static llparse_state_t llhttp__internal__run(
return s_error;
}
goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_pause_6: {
state->error = 0x15;
@@ -7122,8 +7281,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_size_almost_done;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_21: {
state->error = 0x22;
@@ -7131,8 +7289,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name_1: {
const unsigned char* start;
@@ -7149,8 +7306,7 @@ static llparse_state_t llhttp__internal__run(
}
p++;
goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_1;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_pause_7: {
state->error = 0x15;
@@ -7158,8 +7314,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_extensions;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_22: {
state->error = 0x22;
@@ -7167,8 +7322,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name_2: {
const unsigned char* start;
@@ -7185,8 +7339,7 @@ static llparse_state_t llhttp__internal__run(
}
p++;
goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_2;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_25: {
state->error = 0x19;
@@ -7194,8 +7347,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_pause_8: {
state->error = 0x15;
@@ -7203,8 +7355,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_test_lenient_flags_10;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_24: {
state->error = 0x23;
@@ -7212,8 +7363,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value: {
const unsigned char* start;
@@ -7229,8 +7379,7 @@ static llparse_state_t llhttp__internal__run(
return s_error;
}
goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_pause_9: {
state->error = 0x15;
@@ -7238,8 +7387,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_size_almost_done;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_26: {
state->error = 0x23;
@@ -7247,8 +7395,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_1: {
const unsigned char* start;
@@ -7265,8 +7412,7 @@ static llparse_state_t llhttp__internal__run(
}
p++;
goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_1;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_28: {
state->error = 0x19;
@@ -7274,8 +7420,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_test_lenient_flags_11: {
switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) {
@@ -7284,8 +7429,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_error_28;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_29: {
state->error = 0x2;
@@ -7293,8 +7437,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_pause_10: {
state->error = 0x15;
@@ -7302,8 +7445,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_extension_quoted_value_done;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_27: {
state->error = 0x23;
@@ -7311,8 +7453,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_2: {
const unsigned char* start;
@@ -7328,8 +7469,7 @@ static llparse_state_t llhttp__internal__run(
return s_error;
}
goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_2;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_3: {
const unsigned char* start;
@@ -7346,8 +7486,7 @@ static llparse_state_t llhttp__internal__run(
}
p++;
goto s_n_llhttp__internal__n_error_30;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_4: {
const unsigned char* start;
@@ -7364,8 +7503,7 @@ static llparse_state_t llhttp__internal__run(
}
p++;
goto s_n_llhttp__internal__n_error_31;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_pause_11: {
state->error = 0x15;
@@ -7373,8 +7511,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_extensions;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_32: {
state->error = 0x23;
@@ -7382,8 +7519,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_5: {
const unsigned char* start;
@@ -7400,8 +7536,7 @@ static llparse_state_t llhttp__internal__run(
}
p++;
goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_3;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_6: {
const unsigned char* start;
@@ -7418,8 +7553,7 @@ static llparse_state_t llhttp__internal__run(
}
p++;
goto s_n_llhttp__internal__n_error_33;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_pause_12: {
state->error = 0x15;
@@ -7427,8 +7561,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_extension_value;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_23: {
state->error = 0x22;
@@ -7436,8 +7569,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_3: {
switch (llhttp__on_chunk_extension_name_complete(state, p, endp)) {
@@ -7448,8 +7580,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_error_23;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name_3: {
const unsigned char* start;
@@ -7466,8 +7597,7 @@ static llparse_state_t llhttp__internal__run(
}
p++;
goto s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_value;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name_4: {
const unsigned char* start;
@@ -7484,8 +7614,7 @@ static llparse_state_t llhttp__internal__run(
}
p++;
goto s_n_llhttp__internal__n_error_34;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_35: {
state->error = 0xc;
@@ -7493,8 +7622,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_mul_add_content_length: {
switch (llhttp__internal__c_mul_add_content_length(state, p, endp, match)) {
@@ -7503,8 +7631,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_chunk_size;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_37: {
state->error = 0xc;
@@ -7512,8 +7639,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_body_1: {
const unsigned char* start;
@@ -7529,16 +7655,14 @@ static llparse_state_t llhttp__internal__run(
return s_error;
}
goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_update_finish_3: {
switch (llhttp__internal__c_update_finish_3(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_span_start_llhttp__on_body_2;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_39: {
state->error = 0xf;
@@ -7546,8 +7670,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_pause: {
state->error = 0x15;
@@ -7555,8 +7678,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__after_message_complete;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_7: {
state->error = 0x12;
@@ -7564,8 +7686,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_llhttp__on_message_complete: {
switch (llhttp__on_message_complete(state, p, endp)) {
@@ -7576,32 +7697,28 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_error_7;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_or_flags_1: {
switch (llhttp__internal__c_or_flags_1(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_or_flags_2: {
switch (llhttp__internal__c_or_flags_1(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_update_upgrade: {
switch (llhttp__internal__c_update_upgrade(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_invoke_or_flags_2;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_pause_14: {
state->error = 0x15;
@@ -7609,8 +7726,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_6: {
state->error = 0x11;
@@ -7618,8 +7734,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_llhttp__on_headers_complete: {
switch (llhttp__on_headers_complete(state, p, endp)) {
@@ -7634,16 +7749,14 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_error_6;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_llhttp__before_headers_complete: {
switch (llhttp__before_headers_complete(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_invoke_llhttp__on_headers_complete;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_test_flags: {
switch (llhttp__internal__c_test_flags(state, p, endp)) {
@@ -7652,8 +7765,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_invoke_llhttp__before_headers_complete;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_test_lenient_flags_1: {
switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) {
@@ -7662,8 +7774,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_error_5;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_pause_17: {
state->error = 0x15;
@@ -7671,8 +7782,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_42: {
state->error = 0x14;
@@ -7680,8 +7790,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete_2: {
switch (llhttp__on_chunk_complete(state, p, endp)) {
@@ -7692,32 +7801,28 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_error_42;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_or_flags_3: {
switch (llhttp__internal__c_or_flags_1(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_or_flags_4: {
switch (llhttp__internal__c_or_flags_1(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_update_upgrade_1: {
switch (llhttp__internal__c_update_upgrade(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_invoke_or_flags_4;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_pause_16: {
state->error = 0x15;
@@ -7725,8 +7830,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_41: {
state->error = 0x11;
@@ -7734,8 +7838,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_llhttp__on_headers_complete_1: {
switch (llhttp__on_headers_complete(state, p, endp)) {
@@ -7750,16 +7853,14 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_error_41;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_llhttp__before_headers_complete_1: {
switch (llhttp__before_headers_complete(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_invoke_llhttp__on_headers_complete_1;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_test_flags_1: {
switch (llhttp__internal__c_test_flags(state, p, endp)) {
@@ -7768,8 +7869,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_invoke_llhttp__before_headers_complete_1;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_43: {
state->error = 0x2;
@@ -7777,8 +7877,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_test_lenient_flags_12: {
switch (llhttp__internal__c_test_lenient_flags_8(state, p, endp)) {
@@ -7787,8 +7886,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_error_43;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_44: {
state->error = 0xa;
@@ -7796,8 +7894,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_header_field: {
const unsigned char* start;
@@ -7814,8 +7911,7 @@ static llparse_state_t llhttp__internal__run(
}
p++;
goto s_n_llhttp__internal__n_error_5;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_test_lenient_flags_13: {
switch (llhttp__internal__c_test_lenient_flags(state, p, endp)) {
@@ -7824,8 +7920,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_span_end_llhttp__on_header_field;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_60: {
state->error = 0xb;
@@ -7833,8 +7928,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_47: {
state->error = 0xa;
@@ -7842,8 +7936,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_test_lenient_flags_15: {
switch (llhttp__internal__c_test_lenient_flags(state, p, endp)) {
@@ -7852,8 +7945,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_error_47;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_49: {
state->error = 0xb;
@@ -7861,8 +7953,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_pause_18: {
state->error = 0x15;
@@ -7870,8 +7961,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_field_start;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_48: {
state->error = 0x1d;
@@ -7879,8 +7969,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_header_value: {
const unsigned char* start;
@@ -7896,48 +7985,42 @@ static llparse_state_t llhttp__internal__run(
return s_error;
}
goto s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_update_header_state: {
switch (llhttp__internal__c_update_header_state(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_or_flags_5: {
switch (llhttp__internal__c_or_flags_5(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_invoke_update_header_state;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_or_flags_6: {
switch (llhttp__internal__c_or_flags_6(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_invoke_update_header_state;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_or_flags_7: {
switch (llhttp__internal__c_or_flags_7(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_invoke_update_header_state;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_or_flags_8: {
switch (llhttp__internal__c_or_flags_8(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_load_header_state_2: {
switch (llhttp__internal__c_load_header_state(state, p, endp)) {
@@ -7952,8 +8035,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_load_header_state_1: {
switch (llhttp__internal__c_load_header_state(state, p, endp)) {
@@ -7962,8 +8044,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_invoke_load_header_state_2;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_46: {
state->error = 0xa;
@@ -7971,8 +8052,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_test_lenient_flags_14: {
switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) {
@@ -7981,8 +8061,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_error_46;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_50: {
state->error = 0x2;
@@ -7990,8 +8069,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_test_lenient_flags_16: {
switch (llhttp__internal__c_test_lenient_flags(state, p, endp)) {
@@ -8000,16 +8078,14 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_error_50;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_update_header_state_1: {
switch (llhttp__internal__c_update_header_state_1(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_load_header_state_4: {
switch (llhttp__internal__c_load_header_state(state, p, endp)) {
@@ -8018,8 +8094,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_52: {
state->error = 0xa;
@@ -8027,8 +8102,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_test_lenient_flags_18: {
switch (llhttp__internal__c_test_lenient_flags(state, p, endp)) {
@@ -8037,48 +8111,42 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_error_52;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_update_header_state_2: {
switch (llhttp__internal__c_update_header_state(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_or_flags_9: {
switch (llhttp__internal__c_or_flags_5(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_invoke_update_header_state_2;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_or_flags_10: {
switch (llhttp__internal__c_or_flags_6(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_invoke_update_header_state_2;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_or_flags_11: {
switch (llhttp__internal__c_or_flags_7(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_invoke_update_header_state_2;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_or_flags_12: {
switch (llhttp__internal__c_or_flags_8(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_load_header_state_5: {
switch (llhttp__internal__c_load_header_state(state, p, endp)) {
@@ -8093,8 +8161,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_53: {
state->error = 0x3;
@@ -8102,8 +8169,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_51: {
state->error = 0x19;
@@ -8111,8 +8177,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_header_value_1: {
const unsigned char* start;
@@ -8128,8 +8193,7 @@ static llparse_state_t llhttp__internal__run(
return s_error;
}
goto s_n_llhttp__internal__n_invoke_test_lenient_flags_17;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_header_value_2: {
const unsigned char* start;
@@ -8146,8 +8210,7 @@ static llparse_state_t llhttp__internal__run(
}
p++;
goto s_n_llhttp__internal__n_header_value_almost_done;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_header_value_4: {
const unsigned char* start;
@@ -8163,8 +8226,7 @@ static llparse_state_t llhttp__internal__run(
return s_error;
}
goto s_n_llhttp__internal__n_header_value_almost_done;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_header_value_5: {
const unsigned char* start;
@@ -8181,8 +8243,7 @@ static llparse_state_t llhttp__internal__run(
}
p++;
goto s_n_llhttp__internal__n_header_value_almost_done;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_header_value_3: {
const unsigned char* start;
@@ -8198,8 +8259,7 @@ static llparse_state_t llhttp__internal__run(
return s_error;
}
goto s_n_llhttp__internal__n_error_54;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_test_lenient_flags_19: {
switch (llhttp__internal__c_test_lenient_flags(state, p, endp)) {
@@ -8208,48 +8268,42 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_3;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_update_header_state_4: {
switch (llhttp__internal__c_update_header_state(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_header_value_connection;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_or_flags_13: {
switch (llhttp__internal__c_or_flags_5(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_invoke_update_header_state_4;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_or_flags_14: {
switch (llhttp__internal__c_or_flags_6(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_invoke_update_header_state_4;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_or_flags_15: {
switch (llhttp__internal__c_or_flags_7(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_invoke_update_header_state_4;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_or_flags_16: {
switch (llhttp__internal__c_or_flags_8(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_header_value_connection;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_load_header_state_6: {
switch (llhttp__internal__c_load_header_state(state, p, endp)) {
@@ -8264,40 +8318,35 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_header_value_connection;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_update_header_state_5: {
switch (llhttp__internal__c_update_header_state_1(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_header_value_connection_token;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_update_header_state_3: {
switch (llhttp__internal__c_update_header_state_3(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_header_value_connection_ws;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_update_header_state_6: {
switch (llhttp__internal__c_update_header_state_6(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_header_value_connection_ws;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_update_header_state_7: {
switch (llhttp__internal__c_update_header_state_7(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_header_value_connection_ws;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_header_value_6: {
const unsigned char* start;
@@ -8313,8 +8362,7 @@ static llparse_state_t llhttp__internal__run(
return s_error;
}
goto s_n_llhttp__internal__n_error_56;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_mul_add_content_length_1: {
switch (llhttp__internal__c_mul_add_content_length_1(state, p, endp, match)) {
@@ -8323,16 +8371,14 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_header_value_content_length;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_or_flags_17: {
switch (llhttp__internal__c_or_flags_17(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_header_value_otherwise;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_header_value_7: {
const unsigned char* start;
@@ -8348,8 +8394,7 @@ static llparse_state_t llhttp__internal__run(
return s_error;
}
goto s_n_llhttp__internal__n_error_57;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_55: {
state->error = 0x4;
@@ -8357,8 +8402,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_test_flags_2: {
switch (llhttp__internal__c_test_flags_2(state, p, endp)) {
@@ -8367,8 +8411,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_error_55;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_header_value_9: {
const unsigned char* start;
@@ -8385,16 +8428,14 @@ static llparse_state_t llhttp__internal__run(
}
p++;
goto s_n_llhttp__internal__n_error_59;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_update_header_state_8: {
switch (llhttp__internal__c_update_header_state_8(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_header_value_otherwise;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_header_value_8: {
const unsigned char* start;
@@ -8411,8 +8452,7 @@ static llparse_state_t llhttp__internal__run(
}
p++;
goto s_n_llhttp__internal__n_error_58;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_test_lenient_flags_20: {
switch (llhttp__internal__c_test_lenient_flags_20(state, p, endp)) {
@@ -8421,8 +8461,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_header_value_te_chunked;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_load_type_1: {
switch (llhttp__internal__c_load_type(state, p, endp)) {
@@ -8431,32 +8470,28 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_header_value_te_chunked;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_update_header_state_9: {
switch (llhttp__internal__c_update_header_state_1(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_header_value;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_and_flags: {
switch (llhttp__internal__c_and_flags(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_header_value_te_chunked;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_or_flags_19: {
switch (llhttp__internal__c_or_flags_18(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_invoke_and_flags;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_test_lenient_flags_21: {
switch (llhttp__internal__c_test_lenient_flags_20(state, p, endp)) {
@@ -8465,8 +8500,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_invoke_or_flags_19;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_load_type_2: {
switch (llhttp__internal__c_load_type(state, p, endp)) {
@@ -8475,16 +8509,14 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_invoke_or_flags_19;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_or_flags_18: {
switch (llhttp__internal__c_or_flags_18(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_invoke_and_flags;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_test_flags_3: {
switch (llhttp__internal__c_test_flags_3(state, p, endp)) {
@@ -8493,16 +8525,14 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_invoke_or_flags_18;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_or_flags_20: {
switch (llhttp__internal__c_or_flags_20(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_invoke_update_header_state_9;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_load_header_state_3: {
switch (llhttp__internal__c_load_header_state(state, p, endp)) {
@@ -8517,8 +8547,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_header_value;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_test_lenient_flags_22: {
switch (llhttp__internal__c_test_lenient_flags_22(state, p, endp)) {
@@ -8527,8 +8556,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_header_value_discard_ws;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_test_flags_4: {
switch (llhttp__internal__c_test_flags_4(state, p, endp)) {
@@ -8537,8 +8565,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_header_value_discard_ws;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_61: {
state->error = 0xf;
@@ -8546,8 +8573,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_test_lenient_flags_23: {
switch (llhttp__internal__c_test_lenient_flags_22(state, p, endp)) {
@@ -8556,8 +8582,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_header_value_discard_ws;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_test_flags_5: {
switch (llhttp__internal__c_test_flags_2(state, p, endp)) {
@@ -8566,8 +8591,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_header_value_discard_ws;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_pause_19: {
state->error = 0x15;
@@ -8575,8 +8599,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_load_header_state;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_45: {
state->error = 0x1c;
@@ -8584,8 +8607,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_header_field_1: {
const unsigned char* start;
@@ -8602,8 +8624,7 @@ static llparse_state_t llhttp__internal__run(
}
p++;
goto s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_header_field_2: {
const unsigned char* start;
@@ -8620,8 +8641,7 @@ static llparse_state_t llhttp__internal__run(
}
p++;
goto s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_62: {
state->error = 0xa;
@@ -8629,32 +8649,28 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_update_header_state_10: {
switch (llhttp__internal__c_update_header_state_1(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_header_field_general;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_store_header_state: {
switch (llhttp__internal__c_store_header_state(state, p, endp, match)) {
default:
goto s_n_llhttp__internal__n_header_field_colon;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_update_header_state_11: {
switch (llhttp__internal__c_update_header_state_1(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_header_field_general;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_4: {
state->error = 0x1e;
@@ -8662,8 +8678,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_test_lenient_flags: {
switch (llhttp__internal__c_test_lenient_flags(state, p, endp)) {
@@ -8672,8 +8687,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_error_4;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_pause_20: {
state->error = 0x15;
@@ -8681,8 +8695,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_headers_start;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_3: {
state->error = 0x1a;
@@ -8690,8 +8703,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_llhttp__on_url_complete: {
switch (llhttp__on_url_complete(state, p, endp)) {
@@ -8702,24 +8714,21 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_error_3;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_update_http_minor: {
switch (llhttp__internal__c_update_http_minor(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_invoke_llhttp__on_url_complete;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_update_http_major: {
switch (llhttp__internal__c_update_http_major(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_invoke_update_http_minor;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_url_3: {
const unsigned char* start;
@@ -8735,8 +8744,7 @@ static llparse_state_t llhttp__internal__run(
return s_error;
}
goto s_n_llhttp__internal__n_url_skip_to_http09;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_63: {
state->error = 0x7;
@@ -8744,8 +8752,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_url_4: {
const unsigned char* start;
@@ -8761,73 +8768,65 @@ static llparse_state_t llhttp__internal__run(
return s_error;
}
goto s_n_llhttp__internal__n_url_skip_lf_to_http09;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- s_n_llhttp__internal__n_error_71: {
+ s_n_llhttp__internal__n_error_72: {
state->error = 0x17;
state->reason = "Pause on PRI/Upgrade";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- s_n_llhttp__internal__n_error_72: {
+ s_n_llhttp__internal__n_error_73: {
state->error = 0x9;
state->reason = "Expected HTTP/2 Connection Preface";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- s_n_llhttp__internal__n_error_69: {
+ s_n_llhttp__internal__n_error_70: {
state->error = 0x2;
state->reason = "Expected CRLF after version";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_test_lenient_flags_26: {
switch (llhttp__internal__c_test_lenient_flags_8(state, p, endp)) {
case 1:
goto s_n_llhttp__internal__n_headers_start;
default:
- goto s_n_llhttp__internal__n_error_69;
+ goto s_n_llhttp__internal__n_error_70;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- s_n_llhttp__internal__n_error_68: {
+ s_n_llhttp__internal__n_error_69: {
state->error = 0x9;
state->reason = "Expected CRLF after version";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_test_lenient_flags_25: {
switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) {
case 1:
goto s_n_llhttp__internal__n_req_http_complete_crlf;
default:
- goto s_n_llhttp__internal__n_error_68;
+ goto s_n_llhttp__internal__n_error_69;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- s_n_llhttp__internal__n_error_70: {
+ s_n_llhttp__internal__n_error_71: {
state->error = 0x9;
state->reason = "Expected CRLF after version";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_pause_21: {
state->error = 0x15;
@@ -8835,17 +8834,15 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_load_method_1;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- s_n_llhttp__internal__n_error_67: {
+ s_n_llhttp__internal__n_error_68: {
state->error = 0x21;
state->reason = "`on_version_complete` callback error";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_version_1: {
const unsigned char* start;
@@ -8861,8 +8858,7 @@ static llparse_state_t llhttp__internal__run(
return s_error;
}
goto s_n_llhttp__internal__n_invoke_llhttp__on_version_complete;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_version: {
const unsigned char* start;
@@ -8874,12 +8870,11 @@ static llparse_state_t llhttp__internal__run(
if (err != 0) {
state->error = err;
state->error_pos = (const char*) p;
- state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_66;
+ state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_67;
return s_error;
}
- goto s_n_llhttp__internal__n_error_66;
- /* UNREACHABLE */;
- abort();
+ goto s_n_llhttp__internal__n_error_67;
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_load_http_minor: {
switch (llhttp__internal__c_load_http_minor(state, p, endp)) {
@@ -8888,8 +8883,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_span_end_llhttp__on_version;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_load_http_minor_1: {
switch (llhttp__internal__c_load_http_minor(state, p, endp)) {
@@ -8900,8 +8894,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_span_end_llhttp__on_version;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_load_http_minor_2: {
switch (llhttp__internal__c_load_http_minor(state, p, endp)) {
@@ -8910,8 +8903,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_span_end_llhttp__on_version;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_load_http_major: {
switch (llhttp__internal__c_load_http_major(state, p, endp)) {
@@ -8924,8 +8916,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_span_end_llhttp__on_version;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_test_lenient_flags_24: {
switch (llhttp__internal__c_test_lenient_flags_24(state, p, endp)) {
@@ -8934,38 +8925,19 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_invoke_load_http_major;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_store_http_minor: {
switch (llhttp__internal__c_store_http_minor(state, p, endp, match)) {
default:
goto s_n_llhttp__internal__n_invoke_test_lenient_flags_24;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_version_2: {
const unsigned char* start;
int err;
- start = state->_span_pos0;
- state->_span_pos0 = NULL;
- err = llhttp__on_version(state, start, p);
- if (err != 0) {
- state->error = err;
- state->error_pos = (const char*) p;
- state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_73;
- return s_error;
- }
- goto s_n_llhttp__internal__n_error_73;
- /* UNREACHABLE */;
- abort();
- }
- s_n_llhttp__internal__n_span_end_llhttp__on_version_3: {
- const unsigned char* start;
- int err;
-
start = state->_span_pos0;
state->_span_pos0 = NULL;
err = llhttp__on_version(state, start, p);
@@ -8976,18 +8948,9 @@ static llparse_state_t llhttp__internal__run(
return s_error;
}
goto s_n_llhttp__internal__n_error_74;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- s_n_llhttp__internal__n_invoke_store_http_major: {
- switch (llhttp__internal__c_store_http_major(state, p, endp, match)) {
- default:
- goto s_n_llhttp__internal__n_req_http_dot;
- }
- /* UNREACHABLE */;
- abort();
- }
- s_n_llhttp__internal__n_span_end_llhttp__on_version_4: {
+ s_n_llhttp__internal__n_span_end_llhttp__on_version_3: {
const unsigned char* start;
int err;
@@ -9001,179 +8964,182 @@ static llparse_state_t llhttp__internal__run(
return s_error;
}
goto s_n_llhttp__internal__n_error_75;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- s_n_llhttp__internal__n_error_65: {
+ s_n_llhttp__internal__n_invoke_store_http_major: {
+ switch (llhttp__internal__c_store_http_major(state, p, endp, match)) {
+ default:
+ goto s_n_llhttp__internal__n_req_http_dot;
+ }
+ UNREACHABLE;
+ }
+ s_n_llhttp__internal__n_span_end_llhttp__on_version_4: {
+ const unsigned char* start;
+ int err;
+
+ start = state->_span_pos0;
+ state->_span_pos0 = NULL;
+ err = llhttp__on_version(state, start, p);
+ if (err != 0) {
+ state->error = err;
+ state->error_pos = (const char*) p;
+ state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_76;
+ return s_error;
+ }
+ goto s_n_llhttp__internal__n_error_76;
+ UNREACHABLE;
+ }
+ s_n_llhttp__internal__n_error_77: {
+ state->error = 0x8;
+ state->reason = "Expected HTTP/, RTSP/ or ICE/";
+ state->error_pos = (const char*) p;
+ state->_current = (void*) (intptr_t) s_error;
+ return s_error;
+ UNREACHABLE;
+ }
+ s_n_llhttp__internal__n_error_66: {
state->error = 0x8;
state->reason = "Invalid method for HTTP/x.x request";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- s_n_llhttp__internal__n_invoke_load_method: {
- switch (llhttp__internal__c_load_method(state, p, endp)) {
- case 0:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 1:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 2:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 3:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 4:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 5:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 6:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 7:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 8:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 9:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 10:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 11:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 12:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 13:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 14:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 15:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 16:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 17:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 18:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 19:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 20:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 21:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 22:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 23:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 24:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 25:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 26:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 27:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 28:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 29:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 30:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 31:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 32:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 33:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 34:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 46:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- default:
- goto s_n_llhttp__internal__n_error_65;
- }
- /* UNREACHABLE */;
- abort();
+ s_n_llhttp__internal__n_pause_22: {
+ state->error = 0x15;
+ state->reason = "on_protocol_complete pause";
+ state->error_pos = (const char*) p;
+ state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_load_method;
+ return s_error;
+ UNREACHABLE;
}
- s_n_llhttp__internal__n_error_78: {
- state->error = 0x8;
- state->reason = "Expected HTTP/";
+ s_n_llhttp__internal__n_error_65: {
+ state->error = 0x26;
+ state->reason = "`on_protocol_complete` callback error";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- s_n_llhttp__internal__n_error_76: {
+ s_n_llhttp__internal__n_span_end_llhttp__on_protocol: {
+ const unsigned char* start;
+ int err;
+
+ start = state->_span_pos0;
+ state->_span_pos0 = NULL;
+ err = llhttp__on_protocol(state, start, p);
+ if (err != 0) {
+ state->error = err;
+ state->error_pos = (const char*) p;
+ state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete;
+ return s_error;
+ }
+ goto s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete;
+ UNREACHABLE;
+ }
+ s_n_llhttp__internal__n_span_end_llhttp__on_protocol_3: {
+ const unsigned char* start;
+ int err;
+
+ start = state->_span_pos0;
+ state->_span_pos0 = NULL;
+ err = llhttp__on_protocol(state, start, p);
+ if (err != 0) {
+ state->error = err;
+ state->error_pos = (const char*) p;
+ state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_82;
+ return s_error;
+ }
+ goto s_n_llhttp__internal__n_error_82;
+ UNREACHABLE;
+ }
+ s_n_llhttp__internal__n_error_79: {
state->error = 0x8;
state->reason = "Expected SOURCE method for ICE/x.x request";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- s_n_llhttp__internal__n_invoke_load_method_2: {
- switch (llhttp__internal__c_load_method(state, p, endp)) {
- case 33:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- default:
- goto s_n_llhttp__internal__n_error_76;
+ s_n_llhttp__internal__n_pause_23: {
+ state->error = 0x15;
+ state->reason = "on_protocol_complete pause";
+ state->error_pos = (const char*) p;
+ state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_load_method_2;
+ return s_error;
+ UNREACHABLE;
+ }
+ s_n_llhttp__internal__n_error_78: {
+ state->error = 0x26;
+ state->reason = "`on_protocol_complete` callback error";
+ state->error_pos = (const char*) p;
+ state->_current = (void*) (intptr_t) s_error;
+ return s_error;
+ UNREACHABLE;
+ }
+ s_n_llhttp__internal__n_span_end_llhttp__on_protocol_1: {
+ const unsigned char* start;
+ int err;
+
+ start = state->_span_pos0;
+ state->_span_pos0 = NULL;
+ err = llhttp__on_protocol(state, start, p);
+ if (err != 0) {
+ state->error = err;
+ state->error_pos = (const char*) p;
+ state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete_1;
+ return s_error;
}
- /* UNREACHABLE */;
- abort();
+ goto s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete_1;
+ UNREACHABLE;
}
- s_n_llhttp__internal__n_error_77: {
+ s_n_llhttp__internal__n_error_81: {
state->error = 0x8;
state->reason = "Invalid method for RTSP/x.x request";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- s_n_llhttp__internal__n_invoke_load_method_3: {
- switch (llhttp__internal__c_load_method(state, p, endp)) {
- case 1:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 3:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 6:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 35:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 36:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 37:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 38:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 39:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 40:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 41:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 42:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 43:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 44:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- case 45:
- goto s_n_llhttp__internal__n_span_start_llhttp__on_version;
- default:
- goto s_n_llhttp__internal__n_error_77;
+ s_n_llhttp__internal__n_pause_24: {
+ state->error = 0x15;
+ state->reason = "on_protocol_complete pause";
+ state->error_pos = (const char*) p;
+ state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_load_method_3;
+ return s_error;
+ UNREACHABLE;
+ }
+ s_n_llhttp__internal__n_error_80: {
+ state->error = 0x26;
+ state->reason = "`on_protocol_complete` callback error";
+ state->error_pos = (const char*) p;
+ state->_current = (void*) (intptr_t) s_error;
+ return s_error;
+ UNREACHABLE;
+ }
+ s_n_llhttp__internal__n_span_end_llhttp__on_protocol_2: {
+ const unsigned char* start;
+ int err;
+
+ start = state->_span_pos0;
+ state->_span_pos0 = NULL;
+ err = llhttp__on_protocol(state, start, p);
+ if (err != 0) {
+ state->error = err;
+ state->error_pos = (const char*) p;
+ state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete_2;
+ return s_error;
}
- /* UNREACHABLE */;
- abort();
+ goto s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete_2;
+ UNREACHABLE;
}
- s_n_llhttp__internal__n_pause_22: {
+ s_n_llhttp__internal__n_pause_25: {
state->error = 0x15;
state->reason = "on_url_complete pause";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_req_http_start;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_64: {
state->error = 0x1a;
@@ -9181,20 +9147,18 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_llhttp__on_url_complete_1: {
switch (llhttp__on_url_complete(state, p, endp)) {
case 0:
goto s_n_llhttp__internal__n_req_http_start;
case 21:
- goto s_n_llhttp__internal__n_pause_22;
+ goto s_n_llhttp__internal__n_pause_25;
default:
goto s_n_llhttp__internal__n_error_64;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_url_5: {
const unsigned char* start;
@@ -9210,8 +9174,7 @@ static llparse_state_t llhttp__internal__run(
return s_error;
}
goto s_n_llhttp__internal__n_url_skip_to_http;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_url_6: {
const unsigned char* start;
@@ -9227,8 +9190,7 @@ static llparse_state_t llhttp__internal__run(
return s_error;
}
goto s_n_llhttp__internal__n_url_skip_to_http09;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_url_7: {
const unsigned char* start;
@@ -9244,8 +9206,7 @@ static llparse_state_t llhttp__internal__run(
return s_error;
}
goto s_n_llhttp__internal__n_url_skip_lf_to_http09;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_url_8: {
const unsigned char* start;
@@ -9261,17 +9222,15 @@ static llparse_state_t llhttp__internal__run(
return s_error;
}
goto s_n_llhttp__internal__n_url_skip_to_http;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- s_n_llhttp__internal__n_error_79: {
+ s_n_llhttp__internal__n_error_83: {
state->error = 0x7;
state->reason = "Invalid char in url fragment start";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_url_9: {
const unsigned char* start;
@@ -9287,8 +9246,7 @@ static llparse_state_t llhttp__internal__run(
return s_error;
}
goto s_n_llhttp__internal__n_url_skip_to_http09;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_url_10: {
const unsigned char* start;
@@ -9304,8 +9262,7 @@ static llparse_state_t llhttp__internal__run(
return s_error;
}
goto s_n_llhttp__internal__n_url_skip_lf_to_http09;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_url_11: {
const unsigned char* start;
@@ -9321,26 +9278,23 @@ static llparse_state_t llhttp__internal__run(
return s_error;
}
goto s_n_llhttp__internal__n_url_skip_to_http;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- s_n_llhttp__internal__n_error_80: {
+ s_n_llhttp__internal__n_error_84: {
state->error = 0x7;
state->reason = "Invalid char in url query";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- s_n_llhttp__internal__n_error_81: {
+ s_n_llhttp__internal__n_error_85: {
state->error = 0x7;
state->reason = "Invalid char in url path";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_url: {
const unsigned char* start;
@@ -9356,8 +9310,7 @@ static llparse_state_t llhttp__internal__run(
return s_error;
}
goto s_n_llhttp__internal__n_url_skip_to_http09;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_url_1: {
const unsigned char* start;
@@ -9373,8 +9326,7 @@ static llparse_state_t llhttp__internal__run(
return s_error;
}
goto s_n_llhttp__internal__n_url_skip_lf_to_http09;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_url_2: {
const unsigned char* start;
@@ -9390,8 +9342,7 @@ static llparse_state_t llhttp__internal__run(
return s_error;
}
goto s_n_llhttp__internal__n_url_skip_to_http;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_url_12: {
const unsigned char* start;
@@ -9407,8 +9358,7 @@ static llparse_state_t llhttp__internal__run(
return s_error;
}
goto s_n_llhttp__internal__n_url_skip_to_http09;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_url_13: {
const unsigned char* start;
@@ -9424,8 +9374,7 @@ static llparse_state_t llhttp__internal__run(
return s_error;
}
goto s_n_llhttp__internal__n_url_skip_lf_to_http09;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_url_14: {
const unsigned char* start;
@@ -9441,62 +9390,55 @@ static llparse_state_t llhttp__internal__run(
return s_error;
}
goto s_n_llhttp__internal__n_url_skip_to_http;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- s_n_llhttp__internal__n_error_82: {
+ s_n_llhttp__internal__n_error_86: {
state->error = 0x7;
state->reason = "Double @ in url";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
- }
- s_n_llhttp__internal__n_error_83: {
- state->error = 0x7;
- state->reason = "Unexpected char in url server";
- state->error_pos = (const char*) p;
- state->_current = (void*) (intptr_t) s_error;
- return s_error;
- /* UNREACHABLE */;
- abort();
- }
- s_n_llhttp__internal__n_error_84: {
- state->error = 0x7;
- state->reason = "Unexpected char in url server";
- state->error_pos = (const char*) p;
- state->_current = (void*) (intptr_t) s_error;
- return s_error;
- /* UNREACHABLE */;
- abort();
- }
- s_n_llhttp__internal__n_error_85: {
- state->error = 0x7;
- state->reason = "Unexpected char in url schema";
- state->error_pos = (const char*) p;
- state->_current = (void*) (intptr_t) s_error;
- return s_error;
- /* UNREACHABLE */;
- abort();
- }
- s_n_llhttp__internal__n_error_86: {
- state->error = 0x7;
- state->reason = "Unexpected char in url schema";
- state->error_pos = (const char*) p;
- state->_current = (void*) (intptr_t) s_error;
- return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_87: {
+ state->error = 0x7;
+ state->reason = "Unexpected char in url server";
+ state->error_pos = (const char*) p;
+ state->_current = (void*) (intptr_t) s_error;
+ return s_error;
+ UNREACHABLE;
+ }
+ s_n_llhttp__internal__n_error_88: {
+ state->error = 0x7;
+ state->reason = "Unexpected char in url server";
+ state->error_pos = (const char*) p;
+ state->_current = (void*) (intptr_t) s_error;
+ return s_error;
+ UNREACHABLE;
+ }
+ s_n_llhttp__internal__n_error_89: {
+ state->error = 0x7;
+ state->reason = "Unexpected char in url schema";
+ state->error_pos = (const char*) p;
+ state->_current = (void*) (intptr_t) s_error;
+ return s_error;
+ UNREACHABLE;
+ }
+ s_n_llhttp__internal__n_error_90: {
+ state->error = 0x7;
+ state->reason = "Unexpected char in url schema";
+ state->error_pos = (const char*) p;
+ state->_current = (void*) (intptr_t) s_error;
+ return s_error;
+ UNREACHABLE;
+ }
+ s_n_llhttp__internal__n_error_91: {
state->error = 0x7;
state->reason = "Unexpected start char in url";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_is_equal_method: {
switch (llhttp__internal__c_is_equal_method(state, p, endp)) {
@@ -9505,35 +9447,31 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_url_entry_connect;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- s_n_llhttp__internal__n_error_88: {
+ s_n_llhttp__internal__n_error_92: {
state->error = 0x6;
state->reason = "Expected space after method";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- s_n_llhttp__internal__n_pause_26: {
+ s_n_llhttp__internal__n_pause_29: {
state->error = 0x15;
state->reason = "on_method_complete pause";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_req_first_space_before_url;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- s_n_llhttp__internal__n_error_107: {
+ s_n_llhttp__internal__n_error_111: {
state->error = 0x20;
state->reason = "`on_method_complete` callback error";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_method_2: {
const unsigned char* start;
@@ -9549,25 +9487,38 @@ static llparse_state_t llhttp__internal__run(
return s_error;
}
goto s_n_llhttp__internal__n_invoke_llhttp__on_method_complete_1;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_store_method_1: {
switch (llhttp__internal__c_store_method(state, p, endp, match)) {
default:
goto s_n_llhttp__internal__n_span_end_llhttp__on_method_2;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- s_n_llhttp__internal__n_error_108: {
+ s_n_llhttp__internal__n_error_112: {
state->error = 0x6;
state->reason = "Invalid method encountered";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
+ }
+ s_n_llhttp__internal__n_error_104: {
+ state->error = 0xd;
+ state->reason = "Invalid status code";
+ state->error_pos = (const char*) p;
+ state->_current = (void*) (intptr_t) s_error;
+ return s_error;
+ UNREACHABLE;
+ }
+ s_n_llhttp__internal__n_error_102: {
+ state->error = 0xd;
+ state->reason = "Invalid status code";
+ state->error_pos = (const char*) p;
+ state->_current = (void*) (intptr_t) s_error;
+ return s_error;
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_100: {
state->error = 0xd;
@@ -9575,103 +9526,76 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- s_n_llhttp__internal__n_error_98: {
- state->error = 0xd;
- state->reason = "Invalid status code";
- state->error_pos = (const char*) p;
- state->_current = (void*) (intptr_t) s_error;
- return s_error;
- /* UNREACHABLE */;
- abort();
- }
- s_n_llhttp__internal__n_error_96: {
- state->error = 0xd;
- state->reason = "Invalid status code";
- state->error_pos = (const char*) p;
- state->_current = (void*) (intptr_t) s_error;
- return s_error;
- /* UNREACHABLE */;
- abort();
- }
- s_n_llhttp__internal__n_pause_24: {
+ s_n_llhttp__internal__n_pause_27: {
state->error = 0x15;
state->reason = "on_status_complete pause";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_headers_start;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- s_n_llhttp__internal__n_error_92: {
+ s_n_llhttp__internal__n_error_96: {
state->error = 0x1b;
state->reason = "`on_status_complete` callback error";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_llhttp__on_status_complete: {
switch (llhttp__on_status_complete(state, p, endp)) {
case 0:
goto s_n_llhttp__internal__n_headers_start;
case 21:
- goto s_n_llhttp__internal__n_pause_24;
+ goto s_n_llhttp__internal__n_pause_27;
default:
- goto s_n_llhttp__internal__n_error_92;
+ goto s_n_llhttp__internal__n_error_96;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- s_n_llhttp__internal__n_error_91: {
+ s_n_llhttp__internal__n_error_95: {
state->error = 0xd;
state->reason = "Invalid response status";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_test_lenient_flags_28: {
switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) {
case 1:
goto s_n_llhttp__internal__n_invoke_llhttp__on_status_complete;
default:
- goto s_n_llhttp__internal__n_error_91;
+ goto s_n_llhttp__internal__n_error_95;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- s_n_llhttp__internal__n_error_93: {
+ s_n_llhttp__internal__n_error_97: {
state->error = 0x2;
state->reason = "Expected LF after CR";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_test_lenient_flags_29: {
switch (llhttp__internal__c_test_lenient_flags_8(state, p, endp)) {
case 1:
goto s_n_llhttp__internal__n_invoke_llhttp__on_status_complete;
default:
- goto s_n_llhttp__internal__n_error_93;
+ goto s_n_llhttp__internal__n_error_97;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- s_n_llhttp__internal__n_error_94: {
+ s_n_llhttp__internal__n_error_98: {
state->error = 0x19;
state->reason = "Missing expected CR after response line";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_status: {
const unsigned char* start;
@@ -9688,8 +9612,7 @@ static llparse_state_t llhttp__internal__run(
}
p++;
goto s_n_llhttp__internal__n_invoke_test_lenient_flags_30;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_status_1: {
const unsigned char* start;
@@ -9706,65 +9629,24 @@ static llparse_state_t llhttp__internal__run(
}
p++;
goto s_n_llhttp__internal__n_res_line_almost_done;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- s_n_llhttp__internal__n_error_95: {
+ s_n_llhttp__internal__n_error_99: {
state->error = 0xd;
state->reason = "Invalid response status";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_mul_add_status_code_2: {
switch (llhttp__internal__c_mul_add_status_code(state, p, endp, match)) {
case 1:
- goto s_n_llhttp__internal__n_error_96;
+ goto s_n_llhttp__internal__n_error_100;
default:
goto s_n_llhttp__internal__n_res_status_code_otherwise;
}
- /* UNREACHABLE */;
- abort();
- }
- s_n_llhttp__internal__n_error_97: {
- state->error = 0xd;
- state->reason = "Invalid status code";
- state->error_pos = (const char*) p;
- state->_current = (void*) (intptr_t) s_error;
- return s_error;
- /* UNREACHABLE */;
- abort();
- }
- s_n_llhttp__internal__n_invoke_mul_add_status_code_1: {
- switch (llhttp__internal__c_mul_add_status_code(state, p, endp, match)) {
- case 1:
- goto s_n_llhttp__internal__n_error_98;
- default:
- goto s_n_llhttp__internal__n_res_status_code_digit_3;
- }
- /* UNREACHABLE */;
- abort();
- }
- s_n_llhttp__internal__n_error_99: {
- state->error = 0xd;
- state->reason = "Invalid status code";
- state->error_pos = (const char*) p;
- state->_current = (void*) (intptr_t) s_error;
- return s_error;
- /* UNREACHABLE */;
- abort();
- }
- s_n_llhttp__internal__n_invoke_mul_add_status_code: {
- switch (llhttp__internal__c_mul_add_status_code(state, p, endp, match)) {
- case 1:
- goto s_n_llhttp__internal__n_error_100;
- default:
- goto s_n_llhttp__internal__n_res_status_code_digit_2;
- }
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_101: {
state->error = 0xd;
@@ -9772,43 +9654,72 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
+ }
+ s_n_llhttp__internal__n_invoke_mul_add_status_code_1: {
+ switch (llhttp__internal__c_mul_add_status_code(state, p, endp, match)) {
+ case 1:
+ goto s_n_llhttp__internal__n_error_102;
+ default:
+ goto s_n_llhttp__internal__n_res_status_code_digit_3;
+ }
+ UNREACHABLE;
+ }
+ s_n_llhttp__internal__n_error_103: {
+ state->error = 0xd;
+ state->reason = "Invalid status code";
+ state->error_pos = (const char*) p;
+ state->_current = (void*) (intptr_t) s_error;
+ return s_error;
+ UNREACHABLE;
+ }
+ s_n_llhttp__internal__n_invoke_mul_add_status_code: {
+ switch (llhttp__internal__c_mul_add_status_code(state, p, endp, match)) {
+ case 1:
+ goto s_n_llhttp__internal__n_error_104;
+ default:
+ goto s_n_llhttp__internal__n_res_status_code_digit_2;
+ }
+ UNREACHABLE;
+ }
+ s_n_llhttp__internal__n_error_105: {
+ state->error = 0xd;
+ state->reason = "Invalid status code";
+ state->error_pos = (const char*) p;
+ state->_current = (void*) (intptr_t) s_error;
+ return s_error;
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_update_status_code: {
switch (llhttp__internal__c_update_status_code(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_res_status_code_digit_1;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- s_n_llhttp__internal__n_error_102: {
+ s_n_llhttp__internal__n_error_106: {
state->error = 0x9;
state->reason = "Expected space after version";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- s_n_llhttp__internal__n_pause_25: {
+ s_n_llhttp__internal__n_pause_28: {
state->error = 0x15;
state->reason = "on_version_complete pause";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_res_after_version;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- s_n_llhttp__internal__n_error_90: {
+ s_n_llhttp__internal__n_error_94: {
state->error = 0x21;
state->reason = "`on_version_complete` callback error";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_version_6: {
const unsigned char* start;
@@ -9824,8 +9735,7 @@ static llparse_state_t llhttp__internal__run(
return s_error;
}
goto s_n_llhttp__internal__n_invoke_llhttp__on_version_complete_1;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_version_5: {
const unsigned char* start;
@@ -9837,12 +9747,11 @@ static llparse_state_t llhttp__internal__run(
if (err != 0) {
state->error = err;
state->error_pos = (const char*) p;
- state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_89;
+ state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_93;
return s_error;
}
- goto s_n_llhttp__internal__n_error_89;
- /* UNREACHABLE */;
- abort();
+ goto s_n_llhttp__internal__n_error_93;
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_load_http_minor_3: {
switch (llhttp__internal__c_load_http_minor(state, p, endp)) {
@@ -9851,8 +9760,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_span_end_llhttp__on_version_5;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_load_http_minor_4: {
switch (llhttp__internal__c_load_http_minor(state, p, endp)) {
@@ -9863,8 +9771,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_span_end_llhttp__on_version_5;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_load_http_minor_5: {
switch (llhttp__internal__c_load_http_minor(state, p, endp)) {
@@ -9873,8 +9780,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_span_end_llhttp__on_version_5;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_load_http_major_1: {
switch (llhttp__internal__c_load_http_major(state, p, endp)) {
@@ -9887,8 +9793,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_span_end_llhttp__on_version_5;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_test_lenient_flags_27: {
switch (llhttp__internal__c_test_lenient_flags_24(state, p, endp)) {
@@ -9897,16 +9802,14 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_invoke_load_http_major_1;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_store_http_minor_1: {
switch (llhttp__internal__c_store_http_minor(state, p, endp, match)) {
default:
goto s_n_llhttp__internal__n_invoke_test_lenient_flags_27;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_version_7: {
const unsigned char* start;
@@ -9918,12 +9821,11 @@ static llparse_state_t llhttp__internal__run(
if (err != 0) {
state->error = err;
state->error_pos = (const char*) p;
- state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_103;
+ state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_107;
return s_error;
}
- goto s_n_llhttp__internal__n_error_103;
- /* UNREACHABLE */;
- abort();
+ goto s_n_llhttp__internal__n_error_107;
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_version_8: {
const unsigned char* start;
@@ -9935,20 +9837,18 @@ static llparse_state_t llhttp__internal__run(
if (err != 0) {
state->error = err;
state->error_pos = (const char*) p;
- state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_104;
+ state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_108;
return s_error;
}
- goto s_n_llhttp__internal__n_error_104;
- /* UNREACHABLE */;
- abort();
+ goto s_n_llhttp__internal__n_error_108;
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_store_http_major_1: {
switch (llhttp__internal__c_store_http_major(state, p, endp, match)) {
default:
goto s_n_llhttp__internal__n_res_http_dot;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_version_9: {
const unsigned char* start;
@@ -9960,30 +9860,75 @@ static llparse_state_t llhttp__internal__run(
if (err != 0) {
state->error = err;
state->error_pos = (const char*) p;
- state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_105;
+ state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_109;
return s_error;
}
- goto s_n_llhttp__internal__n_error_105;
- /* UNREACHABLE */;
- abort();
+ goto s_n_llhttp__internal__n_error_109;
+ UNREACHABLE;
}
- s_n_llhttp__internal__n_error_109: {
+ s_n_llhttp__internal__n_error_114: {
state->error = 0x8;
- state->reason = "Expected HTTP/";
+ state->reason = "Expected HTTP/, RTSP/ or ICE/";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- s_n_llhttp__internal__n_pause_23: {
+ s_n_llhttp__internal__n_pause_30: {
+ state->error = 0x15;
+ state->reason = "on_protocol_complete pause";
+ state->error_pos = (const char*) p;
+ state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_res_after_protocol;
+ return s_error;
+ UNREACHABLE;
+ }
+ s_n_llhttp__internal__n_error_113: {
+ state->error = 0x26;
+ state->reason = "`on_protocol_complete` callback error";
+ state->error_pos = (const char*) p;
+ state->_current = (void*) (intptr_t) s_error;
+ return s_error;
+ UNREACHABLE;
+ }
+ s_n_llhttp__internal__n_span_end_llhttp__on_protocol_4: {
+ const unsigned char* start;
+ int err;
+
+ start = state->_span_pos0;
+ state->_span_pos0 = NULL;
+ err = llhttp__on_protocol(state, start, p);
+ if (err != 0) {
+ state->error = err;
+ state->error_pos = (const char*) p;
+ state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete_3;
+ return s_error;
+ }
+ goto s_n_llhttp__internal__n_invoke_llhttp__on_protocol_complete_3;
+ UNREACHABLE;
+ }
+ s_n_llhttp__internal__n_span_end_llhttp__on_protocol_5: {
+ const unsigned char* start;
+ int err;
+
+ start = state->_span_pos0;
+ state->_span_pos0 = NULL;
+ err = llhttp__on_protocol(state, start, p);
+ if (err != 0) {
+ state->error = err;
+ state->error_pos = (const char*) p;
+ state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_115;
+ return s_error;
+ }
+ goto s_n_llhttp__internal__n_error_115;
+ UNREACHABLE;
+ }
+ s_n_llhttp__internal__n_pause_26: {
state->error = 0x15;
state->reason = "on_method_complete pause";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_req_first_space_before_url;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error_1: {
state->error = 0x20;
@@ -9991,8 +9936,7 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_method: {
const unsigned char* start;
@@ -10008,33 +9952,29 @@ static llparse_state_t llhttp__internal__run(
return s_error;
}
goto s_n_llhttp__internal__n_invoke_llhttp__on_method_complete;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_update_type: {
switch (llhttp__internal__c_update_type(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_span_end_llhttp__on_method;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_store_method: {
switch (llhttp__internal__c_store_method(state, p, endp, match)) {
default:
goto s_n_llhttp__internal__n_invoke_update_type;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- s_n_llhttp__internal__n_error_106: {
+ s_n_llhttp__internal__n_error_110: {
state->error = 0x8;
state->reason = "Invalid word encountered";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_span_end_llhttp__on_method_1: {
const unsigned char* start;
@@ -10050,25 +9990,22 @@ static llparse_state_t llhttp__internal__run(
return s_error;
}
goto s_n_llhttp__internal__n_invoke_update_type_1;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_update_type_2: {
switch (llhttp__internal__c_update_type(state, p, endp)) {
default:
goto s_n_llhttp__internal__n_span_start_llhttp__on_method_1;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- s_n_llhttp__internal__n_pause_27: {
+ s_n_llhttp__internal__n_pause_31: {
state->error = 0x15;
state->reason = "on_message_begin pause";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_load_type;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_error: {
state->error = 0x10;
@@ -10076,50 +10013,45 @@ static llparse_state_t llhttp__internal__run(
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_llhttp__on_message_begin: {
switch (llhttp__on_message_begin(state, p, endp)) {
case 0:
goto s_n_llhttp__internal__n_invoke_load_type;
case 21:
- goto s_n_llhttp__internal__n_pause_27;
+ goto s_n_llhttp__internal__n_pause_31;
default:
goto s_n_llhttp__internal__n_error;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- s_n_llhttp__internal__n_pause_28: {
+ s_n_llhttp__internal__n_pause_32: {
state->error = 0x15;
state->reason = "on_reset pause";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_update_finish;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
- s_n_llhttp__internal__n_error_110: {
+ s_n_llhttp__internal__n_error_116: {
state->error = 0x1f;
state->reason = "`on_reset` callback error";
state->error_pos = (const char*) p;
state->_current = (void*) (intptr_t) s_error;
return s_error;
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_llhttp__on_reset: {
switch (llhttp__on_reset(state, p, endp)) {
case 0:
goto s_n_llhttp__internal__n_invoke_update_finish;
case 21:
- goto s_n_llhttp__internal__n_pause_28;
+ goto s_n_llhttp__internal__n_pause_32;
default:
- goto s_n_llhttp__internal__n_error_110;
+ goto s_n_llhttp__internal__n_error_116;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
s_n_llhttp__internal__n_invoke_load_initial_message_completed: {
switch (llhttp__internal__c_load_initial_message_completed(state, p, endp)) {
@@ -10128,8 +10060,7 @@ static llparse_state_t llhttp__internal__run(
default:
goto s_n_llhttp__internal__n_invoke_update_finish;
}
- /* UNREACHABLE */;
- abort();
+ UNREACHABLE;
}
}
diff --git a/lib/llhttp/llhttp.h b/lib/llhttp/llhttp.h
index 37b7934..6054459 100644
--- a/lib/llhttp/llhttp.h
+++ b/lib/llhttp/llhttp.h
@@ -3,8 +3,8 @@
#define INCLUDE_LLHTTP_H_
#define LLHTTP_VERSION_MAJOR 9
-#define LLHTTP_VERSION_MINOR 2
-#define LLHTTP_VERSION_PATCH 1
+#define LLHTTP_VERSION_MINOR 3
+#define LLHTTP_VERSION_PATCH 0
#ifndef INCLUDE_LLHTTP_ITSELF_H_
#define INCLUDE_LLHTTP_ITSELF_H_
@@ -90,7 +90,8 @@ enum llhttp_errno {
HPE_CB_HEADER_VALUE_COMPLETE = 29,
HPE_CB_CHUNK_EXTENSION_NAME_COMPLETE = 34,
HPE_CB_CHUNK_EXTENSION_VALUE_COMPLETE = 35,
- HPE_CB_RESET = 31
+ HPE_CB_RESET = 31,
+ HPE_CB_PROTOCOL_COMPLETE = 38
};
typedef enum llhttp_errno llhttp_errno_t;
@@ -326,6 +327,7 @@ typedef enum llhttp_status llhttp_status_t;
XX(34, CB_CHUNK_EXTENSION_NAME_COMPLETE, CB_CHUNK_EXTENSION_NAME_COMPLETE) \
XX(35, CB_CHUNK_EXTENSION_VALUE_COMPLETE, CB_CHUNK_EXTENSION_VALUE_COMPLETE) \
XX(31, CB_RESET, CB_RESET) \
+ XX(38, CB_PROTOCOL_COMPLETE, CB_PROTOCOL_COMPLETE) \
#define HTTP_METHOD_MAP(XX) \
@@ -567,6 +569,7 @@ struct llhttp_settings_s {
llhttp_cb on_message_begin;
/* Possible return values 0, -1, HPE_USER */
+ llhttp_data_cb on_protocol;
llhttp_data_cb on_url;
llhttp_data_cb on_status;
llhttp_data_cb on_method;
@@ -592,6 +595,7 @@ struct llhttp_settings_s {
/* Possible return values 0, -1, `HPE_PAUSED` */
llhttp_cb on_message_complete;
+ llhttp_cb on_protocol_complete;
llhttp_cb on_url_complete;
llhttp_cb on_status_complete;
llhttp_cb on_method_complete;
diff --git a/lib/logger.h b/lib/logger.h
index 970344f..bf2653f 100644
--- a/lib/logger.h
+++ b/lib/logger.h
@@ -31,6 +31,7 @@ extern "C" {
#define LOGGER_NOTICE 5 /* normal but significant condition */
#define LOGGER_INFO 6 /* informational */
#define LOGGER_DEBUG 7 /* debug-level messages */
+#define LOGGER_DEBUG_DATA 8 /* debug-level messages including audio/video packet data */
typedef void (*logger_callback_t)(void *cls, int level, const char *msg);
diff --git a/lib/pairing.c b/lib/pairing.c
index e60273c..3660e6e 100644
--- a/lib/pairing.c
+++ b/lib/pairing.c
@@ -16,6 +16,7 @@
*/
#include
+#include
#include
#include
#include
@@ -195,6 +196,184 @@ pairing_session_get_public_key(pairing_session_t *session, unsigned char ecdh_ke
return 0;
}
+
+
+int
+pairing_session_make_nonce(pairing_session_t *session, uint64_t *local_time, const char *client_data, unsigned char *nonce, int len) {
+ unsigned char hash[SHA512_DIGEST_LENGTH];
+ if (len > sizeof(hash)) {
+ return -1;
+ }
+ if (!client_data || !local_time || !session || !nonce || len <= 0) {
+ return -2;
+ }
+ sha_ctx_t *ctx = sha_init();
+ sha_update(ctx, (const unsigned char *) local_time, sizeof(uint64_t));
+ sha_update(ctx, (const unsigned char *) client_data, strlen(client_data));
+ sha_update(ctx, (const unsigned char *) session->ed_ours, ED25519_KEY_SIZE);
+ sha_final(ctx, hash, NULL);
+ sha_destroy(ctx);
+ memcpy(nonce, hash, len);
+ return 0;
+}
+
+static
+char *get_token(char **cursor, char *token_name, char start_char, char end_char) {
+ char *ptr = *cursor;
+
+ ptr = strstr(ptr, token_name);
+ if (!ptr) {
+ return NULL;
+ }
+ ptr += strlen(token_name);
+ ptr = strchr(ptr, start_char);
+ if (!ptr) {
+ return NULL;
+ }
+
+ char *token = ++ptr;
+ ptr = strchr(ptr, end_char);
+ if (!ptr) {
+ return NULL;
+ }
+
+ *(ptr++) = '\0';
+ *cursor = ptr;
+ return token;
+}
+
+//#define test_digest
+bool
+pairing_digest_verify(const char *method, const char * authorization, const char *password) {
+ /* RFC 2617 HTTP md5 Digest password authentication */
+ size_t authlen = strlen(authorization);
+ char *sentence = (char *) malloc(authlen + 1);
+ memcpy(sentence, authorization, authlen);
+ *(sentence + authlen) = '\0';
+ char *username = NULL;
+ char *realm = NULL;
+ char *nonce = NULL;
+ char *uri = NULL;
+ char *qop = NULL;
+ char *nc = NULL;
+ char *cnonce = NULL;
+ char *response = NULL;
+
+ char *cursor = sentence;
+ const char *pwd = password;
+ const char *mthd = method;
+ char *raw;
+ int len;
+ bool authenticated;
+
+#ifdef test_digest
+ char testauth[] = "Digest username=\"Mufasa\","
+ "realm=\"testrealm@host.com\","
+ "nonce=\"dcd98b7102dd2f0e8b11d0f600bfb0c093\","
+ "uri=\"/dir/index.html\","
+ "qop=auth,"
+ "nc=00000001,"
+ "cnonce=\"0a4f113b\","
+ "response=\"6629fae49393a05397450978507c4ef1\","
+ "opaque=\"5ccc069c403ebaf9f0171e9517f40e41\""
+ ;
+ pwd = "Circle Of Life";
+ mthd = "GET";
+ cursor = testauth;
+
+ char HA1[] = "939e7578ed9e3c518a452acee763bce9";
+ char HA2[] = "39aff3a2bab6126f332b942af96d3366";
+#endif
+ username = get_token(&cursor, "username", '\"', '\"');
+ realm = get_token(&cursor, "realm", '\"', '\"');
+ nonce = get_token(&cursor,"nonce", '\"', '\"');
+ uri = get_token(&cursor,"uri", '\"', '\"');
+ qop = get_token(&cursor, "qop", '=', ',');
+ if (qop) {
+ nc = get_token(&cursor, "nc", '=', ',');
+ cnonce = get_token(&cursor, "cnonce", '\"', '\"');
+ }
+ response = get_token(&cursor, "response", '\"', '\"');
+
+#ifdef test_digest
+ printf("username: [%s] realm: [%s]\n", username, realm);
+ printf("nonce: [%s]\n", nonce);
+ printf("method: [%s]\n", mthd);
+ printf("uri: [%s]\n", uri);
+ if (qop) {
+ printf("qop: [%s], nc=[%s], cnonce: [%s]\n", qop, nc, cnonce);
+ }
+ printf("response: [%s]\n", response);
+
+#endif
+
+ /* H1 = H(username : realm : password ) */
+ len = strlen(username) + strlen(realm) + strlen(pwd) + 3;
+ raw = (char *) calloc(len, sizeof(char));
+ strncat(raw, username, len - strlen(raw) - 1);
+ strncat(raw, ":", len - strlen(raw) - 1);
+ strncat(raw, realm, len - strlen(raw) - 1);
+ strncat(raw, ":", len - strlen(raw) - 1);
+ strncat(raw, pwd, len - strlen(raw) - 1);
+ char *hash1 = get_md5(raw);
+ free (raw);
+
+#ifdef test_digest
+ printf("hash1: should be %s, was: %s\n", HA1, hash1);
+#endif
+
+ /* H2 = H(method : uri) */
+ len = strlen(mthd) + strlen(uri) + 2;
+ raw = (char *) calloc(len, sizeof(char));
+ strncat(raw, mthd, len - strlen(raw) - 1);
+ strncat(raw, ":", len - strlen(raw) - 1);
+ strncat(raw, uri, len - strlen(raw) - 1);
+ char *hash2 = get_md5(raw);
+ free (raw);
+
+#ifdef test_digest
+ printf("hash2: should be %s, was: %s\n", HA2, hash2);
+#endif
+
+ /* result = H(H1 : nonce (or nonce:nc:cnonce:qop) : H2) */
+ len = strlen(hash1) + strlen(nonce) + strlen(hash2) + 3;
+ if (qop) {
+ len += strlen(nc) + strlen(cnonce) + strlen(qop) + 3;
+ }
+ raw = (char *) calloc(len, sizeof(char));
+ strncat(raw, hash1, len - strlen(raw) - 1);
+ strncat(raw, ":", len - strlen(raw) - 1);
+ strncat(raw, nonce, len - strlen(raw) - 1);
+ strncat(raw, ":", len - strlen(raw) - 1);
+ if (qop) {
+ strncat(raw, nc, len - strlen(raw) - 1);
+ strncat(raw, ":", len - strlen(raw) - 1);
+ strncat(raw, cnonce, len - strlen(raw) - 1);
+ strncat(raw, ":", len - strlen(raw) - 1);
+ strncat(raw, qop, len - strlen(raw) - 1);
+ strncat(raw, ":", len - strlen(raw) - 1);
+ }
+ strncat(raw, hash2, len - strlen(raw) - 1);
+ free (hash1);
+ free (hash2);
+ char *result = get_md5(raw);
+ free (raw);
+ authenticated = (strcmp(result,response) ? false : true);
+
+#ifdef test_digest
+ printf("result: should be %s, was: %s, authenticated is %s\n", response, result, (authenticated ? "true" : "false"));
+#endif
+
+ free (result);
+ free(sentence);
+
+#ifdef test_digest
+ exit(0);
+#endif
+
+ return authenticated;
+}
+
int
pairing_session_get_signature(pairing_session_t *session, unsigned char signature[PAIRING_SIG_SIZE])
{
@@ -447,11 +626,10 @@ srp_confirm_pair_setup(pairing_session_t *session, pairing_t *pairing,
return epk_len;
}
-void access_client_session_data(pairing_session_t *session, char **username, char **client_pk64, bool *setup) {
+void get_pairing_session_client_data(pairing_session_t *session, char **username, char **client_pk64) {
int len64 = 4 * (1 + (ED25519_KEY_SIZE / 3)) + 1;
- setup = &(session->pair_setup);
*username = session->username;
- if (setup) {
+ if (session->pair_setup) {
*client_pk64 = (char *) malloc(len64);
pk_to_base64(session->client_pk, ED25519_KEY_SIZE, *client_pk64, len64);
} else {
diff --git a/lib/pairing.h b/lib/pairing.h
index 54db62b..cdb1374 100644
--- a/lib/pairing.h
+++ b/lib/pairing.h
@@ -60,6 +60,9 @@ int srp_validate_proof(pairing_session_t *session, pairing_t *pairing, const uns
int len_A, unsigned char *proof, int client_proof_len, int proof_len);
int srp_confirm_pair_setup(pairing_session_t *session, pairing_t *pairing, unsigned char *epk,
unsigned char *auth_tag);
-void access_client_session_data(pairing_session_t *session, char **username, char **client_pk, bool *setup);
+void get_pairing_session_client_data(pairing_session_t *session, char **username, char **client_pk);
void ed25519_pk_to_base64(const unsigned char *pk, char **pk64);
+int pairing_session_make_nonce(pairing_session_t *session, uint64_t *local_time, const char *client_data, unsigned char *nonce, int len);
+bool pairing_digest_verify(const char *method, const char * authorization, const char *password);
+
#endif
diff --git a/lib/playfair/CMakeLists.txt b/lib/playfair/CMakeLists.txt
index 163f9aa..548d3ae 100644
--- a/lib/playfair/CMakeLists.txt
+++ b/lib/playfair/CMakeLists.txt
@@ -1,4 +1,3 @@
-cmake_minimum_required(VERSION 3.5)
aux_source_directory(. playfair_src)
set(DIR_SRCS ${playfair_src})
include_directories(.)
diff --git a/lib/raop.c b/lib/raop.c
index c275dc1..d9939ba 100644
--- a/lib/raop.c
+++ b/lib/raop.c
@@ -64,20 +64,24 @@ struct raop_s {
uint8_t clientFPSdata;
int audio_delay_micros;
- int max_ntp_timeouts;
/* for temporary storage of pin during pair-pin start */
- unsigned short pin;
- bool use_pin;
+ unsigned short pin;
+ bool use_pin;
/* public key as string */
- char pk_str[2*ED25519_KEY_SIZE + 1];
+ char pk_str[2*ED25519_KEY_SIZE + 1];
/* place to store media_data_store */
- airplay_video_t *airplay_video;
+ airplay_video_t *airplay_video;
/* activate support for HLS live streaming */
- bool hls_support;
+ bool hls_support;
+
+ /* used in digest authentication */
+ char *nonce;
+ char *random_pw;
+ unsigned char auth_fail_count;
};
struct raop_conn_s {
@@ -100,7 +104,7 @@ struct raop_conn_s {
connection_type_t connection_type;
char *client_session_id;
-
+ bool authenticated;
bool have_active_remote;
};
typedef struct raop_conn_s raop_conn_t;
@@ -160,6 +164,7 @@ conn_init(void *opaque, unsigned char *local, int locallen, unsigned char *remot
conn->client_session_id = NULL;
conn->airplay_video = NULL;
+ conn->authenticated = false;
conn->have_active_remote = false;
@@ -193,8 +198,9 @@ conn_request(void *ptr, http_request_t *request, http_response_t **response) {
*/
const char *method = http_request_get_method(request);
+ const char *url = http_request_get_url(request);
- if (!method) {
+ if (!method || !url) {
return;
}
@@ -206,7 +212,6 @@ conn_request(void *ptr, http_request_t *request, http_response_t **response) {
return;
}
- const char *url = http_request_get_url(request);
const char *client_session_id = http_request_get_header(request, "X-Apple-Session-ID");
const char *host = http_request_get_header(request, "Host");
hls_request = (host && !cseq && !client_session_id);
@@ -308,11 +313,22 @@ conn_request(void *ptr, http_request_t *request, http_response_t **response) {
if (data_is_plist) {
plist_t req_root_node = NULL;
plist_from_bin(request_data, request_datalen, &req_root_node);
- char * plist_xml;
+ char * plist_xml = NULL;
+ char * stripped_xml = NULL;
uint32_t plist_len;
plist_to_xml(req_root_node, &plist_xml, &plist_len);
- logger_log(conn->raop->logger, LOGGER_DEBUG, "%s", plist_xml);
- free(plist_xml);
+ stripped_xml = utils_strip_data_from_plist_xml(plist_xml);
+ logger_log(conn->raop->logger, LOGGER_DEBUG, "%s", (stripped_xml ? stripped_xml : plist_xml));
+ if (stripped_xml) {
+ free(stripped_xml);
+ }
+ if (plist_xml) {
+#ifdef PLIST_230
+ plist_mem_free(plist_xml);
+#else
+ plist_to_xml_free(plist_xml);
+#endif
+ }
plist_free(req_root_node);
} else if (data_is_text) {
char *data_str = utils_data_to_text((char *) request_data, request_datalen);
@@ -370,7 +386,9 @@ conn_request(void *ptr, http_request_t *request, http_response_t **response) {
handler = &raop_handler_flush;
} else if (!strcmp(method, "TEARDOWN")) {
handler = &raop_handler_teardown;
- }
+ } else {
+ http_response_init(*response, protocol, 501, "Not Implemented");
+ }
} else if (!hls_request && !strcmp(protocol, "HTTP/1.1")) {
if (!strcmp(method, "POST")) {
if (!strcmp(url, "/reverse")) {
@@ -399,7 +417,6 @@ conn_request(void *ptr, http_request_t *request, http_response_t **response) {
} else if (!strcmp(method, "PUT")) {
if (!strncmp (url, "/setProperty?", strlen("/setProperty?"))) {
handler = &http_handler_set_property;
- } else {
}
}
} else if (hls_request) {
@@ -442,12 +459,23 @@ conn_request(void *ptr, http_request_t *request, http_response_t **response) {
if (data_is_plist) {
plist_t res_root_node = NULL;
plist_from_bin(response_data, response_datalen, &res_root_node);
- char * plist_xml;
+ char * plist_xml = NULL;
+ char * stripped_xml = NULL;
uint32_t plist_len;
plist_to_xml(res_root_node, &plist_xml, &plist_len);
+ stripped_xml = utils_strip_data_from_plist_xml(plist_xml);
+ logger_log(conn->raop->logger, LOGGER_DEBUG, "%s", (stripped_xml ? stripped_xml : plist_xml));
+ if (stripped_xml) {
+ free(stripped_xml);
+ }
+ if (plist_xml) {
+#ifdef PLIST_230
+ plist_mem_free(plist_xml);
+#else
+ plist_to_xml_free(plist_xml);
+#endif
+ }
plist_free(res_root_node);
- logger_log(conn->raop->logger, LOGGER_DEBUG, "%s", plist_xml);
- free(plist_xml);
} else if (data_is_text) {
char *data_str = utils_data_to_text((char*) response_data, response_datalen);
logger_log(conn->raop->logger, LOGGER_DEBUG, "%s", data_str);
@@ -554,11 +582,11 @@ raop_init(raop_callbacks_t *callbacks) {
/* initialize switch for display of client's streaming data records */
raop->clientFPSdata = 0;
- raop->max_ntp_timeouts = 0;
raop->audio_delay_micros = 250000;
raop->hls_support = false;
+ raop->nonce = NULL;
return raop;
}
@@ -582,7 +610,7 @@ raop_init2(raop_t *raop, int nohold, const char *device_id, const char *keyfile)
#else
unsigned char public_key[ED25519_KEY_SIZE];
pairing_get_public_key(pairing, public_key);
- char *pk_str = utils_pk_to_string(public_key, ED25519_KEY_SIZE);
+ char *pk_str = utils_hex_to_string(public_key, ED25519_KEY_SIZE);
strncpy(raop->pk_str, (const char *) pk_str, 2*ED25519_KEY_SIZE);
free(pk_str);
#endif
@@ -614,10 +642,17 @@ void
raop_destroy(raop_t *raop) {
if (raop) {
raop_destroy_airplay_video(raop);
- raop_stop(raop);
+ raop_stop_httpd(raop);
pairing_destroy(raop->pairing);
httpd_destroy(raop->httpd);
logger_destroy(raop->logger);
+ if (raop->nonce) {
+ free(raop->nonce);
+ }
+ if (raop->random_pw) {
+ free(raop->random_pw);
+ }
+
free(raop);
/* Cleanup the network */
@@ -662,9 +697,6 @@ int raop_set_plist(raop_t *raop, const char *plist_item, const int value) {
} else if (strcmp(plist_item, "clientFPSdata") == 0) {
raop->clientFPSdata = (value ? 1 : 0);
if ((int) raop->clientFPSdata != value) retval = 1;
- } else if (strcmp(plist_item, "max_ntp_timeouts") == 0) {
- raop->max_ntp_timeouts = (value > 0 ? value : 0);
- if (raop->max_ntp_timeouts != value) retval = 1;
} else if (strcmp(plist_item, "audio_delay_micros") == 0) {
if (value >= 0 && value <= 10 * SECOND_IN_USECS) {
raop->audio_delay_micros = value;
@@ -730,14 +762,14 @@ raop_set_dnssd(raop_t *raop, dnssd_t *dnssd) {
int
-raop_start(raop_t *raop, unsigned short *port) {
+raop_start_httpd(raop_t *raop, unsigned short *port) {
assert(raop);
assert(port);
return httpd_start(raop->httpd, port);
}
void
-raop_stop(raop_t *raop) {
+raop_stop_httpd(raop_t *raop) {
assert(raop);
httpd_stop(raop->httpd);
}
@@ -770,3 +802,7 @@ void raop_destroy_airplay_video(raop_t *raop) {
raop->airplay_video = NULL;
}
}
+
+uint64_t get_local_time() {
+ return raop_ntp_get_local_time();
+}
diff --git a/lib/raop.h b/lib/raop.h
index e0a2062..6cbe3d6 100644
--- a/lib/raop.h
+++ b/lib/raop.h
@@ -67,17 +67,22 @@ struct raop_callbacks_s {
void (*video_process)(void *cls, raop_ntp_t *ntp, video_decode_struct *data);
void (*video_pause)(void *cls);
void (*video_resume)(void *cls);
-
- /* Optional but recommended callback functions */
+ void (*conn_feedback) (void *cls);
+ void (*conn_reset) (void *cls, int reason);
+ void (*video_reset) (void *cls);
+
+
+ /* Optional but recommended callback functions (probably not optional, check this)*/
void (*conn_init)(void *cls);
void (*conn_destroy)(void *cls);
- void (*conn_reset) (void *cls, int timeouts, bool reset_video);
void (*conn_teardown)(void *cls, bool *teardown_96, bool *teardown_110 );
void (*audio_flush)(void *cls);
void (*video_flush)(void *cls);
+ double (*audio_set_client_volume)(void *cls);
void (*audio_set_volume)(void *cls, float volume);
void (*audio_set_metadata)(void *cls, const void *buffer, int buflen);
void (*audio_set_coverart)(void *cls, const void *buffer, int buflen);
+ void (*audio_stop_coverart_rendering) (void* cls);
void (*audio_remote_control_id)(void *cls, const char *dacp_id, const char *active_remote_header);
void (*audio_set_progress)(void *cls, unsigned int start, unsigned int curr, unsigned int end);
void (*audio_get_format)(void *cls, unsigned char *ct, unsigned short *spf, bool *usingScreen, bool *isMedia, uint64_t *audioFormat);
@@ -86,17 +91,17 @@ struct raop_callbacks_s {
void (*display_pin) (void *cls, char * pin);
void (*register_client) (void *cls, const char *device_id, const char *pk_str, const char *name);
bool (*check_register) (void *cls, const char *pk_str);
+ const char* (*passwd) (void *cls, int *len);
void (*export_dacp) (void *cls, const char *active_remote, const char *dacp_id);
- void (*video_reset) (void *cls);
- void (*video_set_codec)(void *cls, video_codec_t codec);
+ int (*video_set_codec)(void *cls, video_codec_t codec);
/* for HLS video player controls */
void (*on_video_play) (void *cls, const char *location, const float start_position);
void (*on_video_scrub) (void *cls, const float position);
void (*on_video_rate) (void *cls, const float rate);
void (*on_video_stop) (void *cls);
void (*on_video_acquire_playback_info) (void *cls, playback_info_t *playback_video);
-
};
+
typedef struct raop_callbacks_s raop_callbacks_t;
raop_ntp_t *raop_ntp_init(logger_t *logger, raop_callbacks_t *callbacks, const char *remote,
int remote_addr_len, unsigned short timing_rport,
@@ -107,7 +112,8 @@ int airplay_video_service_init(raop_t *raop, unsigned short port, const char *se
bool register_airplay_video(raop_t *raop, airplay_video_t *airplay_video);
airplay_video_t *get_airplay_video(raop_t *raop);
airplay_video_t *deregister_airplay_video(raop_t *raop);
-
+uint64_t get_local_time();
+
RAOP_API raop_t *raop_init(raop_callbacks_t *callbacks);
RAOP_API int raop_init2(raop_t *raop, int nohold, const char *device_id, const char *keyfile);
RAOP_API void raop_set_log_level(raop_t *raop, int level);
@@ -118,9 +124,9 @@ RAOP_API void raop_set_udp_ports(raop_t *raop, unsigned short port[3]);
RAOP_API void raop_set_tcp_ports(raop_t *raop, unsigned short port[2]);
RAOP_API unsigned short raop_get_port(raop_t *raop);
RAOP_API void *raop_get_callback_cls(raop_t *raop);
-RAOP_API int raop_start(raop_t *raop, unsigned short *port);
+RAOP_API int raop_start_httpd(raop_t *raop, unsigned short *port);
RAOP_API int raop_is_running(raop_t *raop);
-RAOP_API void raop_stop(raop_t *raop);
+RAOP_API void raop_stop_httpd(raop_t *raop);
RAOP_API void raop_set_dnssd(raop_t *raop, dnssd_t *dnssd);
RAOP_API void raop_destroy(raop_t *raop);
RAOP_API void raop_remove_known_connections(raop_t * raop);
diff --git a/lib/raop_buffer.c b/lib/raop_buffer.c
index 4fc8d76..99cd961 100644
--- a/lib/raop_buffer.c
+++ b/lib/raop_buffer.c
@@ -39,10 +39,11 @@ typedef struct {
/* Data available */
int filled;
+ uint64_t packet_arrival_time;
+
/* RTP header */
unsigned short seqnum;
- uint64_t rtp_timestamp;
- uint64_t ntp_timestamp;
+ uint32_t rtp_timestamp;
/* Payload data */
unsigned int payload_size;
@@ -165,7 +166,7 @@ raop_buffer_decrypt(raop_buffer_t *raop_buffer, unsigned char *data, unsigned ch
}
int
-raop_buffer_enqueue(raop_buffer_t *raop_buffer, unsigned char *data, unsigned short datalen, uint64_t *ntp_timestamp, uint64_t *rtp_timestamp, int use_seqnum) {
+raop_buffer_enqueue(raop_buffer_t *raop_buffer, unsigned char *data, unsigned short datalen, int use_seqnum) {
unsigned char empty_packet_marker[] = { 0x00, 0x68, 0x34, 0x00 };
assert(raop_buffer);
@@ -206,8 +207,7 @@ raop_buffer_enqueue(raop_buffer_t *raop_buffer, unsigned char *data, unsigned sh
/* Update the raop_buffer entry header */
entry->seqnum = seqnum;
- entry->rtp_timestamp = *rtp_timestamp;
- entry->ntp_timestamp = *ntp_timestamp;
+ entry->rtp_timestamp = byteutils_get_int_be(data, 4);
entry->filled = 1;
entry->payload_data = malloc(payload_size);
@@ -228,7 +228,7 @@ raop_buffer_enqueue(raop_buffer_t *raop_buffer, unsigned char *data, unsigned sh
}
void *
-raop_buffer_dequeue(raop_buffer_t *raop_buffer, unsigned int *length, uint64_t *ntp_timestamp, uint64_t *rtp_timestamp, unsigned short *seqnum, int no_resend) {
+raop_buffer_dequeue(raop_buffer_t *raop_buffer, unsigned int *length, uint32_t *rtp_timestamp, unsigned short *seqnum, int no_resend) {
assert(raop_buffer);
/* Calculate number of entries in the current buffer */
@@ -261,7 +261,6 @@ raop_buffer_dequeue(raop_buffer_t *raop_buffer, unsigned int *length, uint64_t *
/* Return entry payload buffer */
*rtp_timestamp = entry->rtp_timestamp;
- *ntp_timestamp = entry->ntp_timestamp;
*seqnum = entry->seqnum;
*length = entry->payload_size;
entry->payload_size = 0;
diff --git a/lib/raop_buffer.h b/lib/raop_buffer.h
index 1093188..a3322da 100644
--- a/lib/raop_buffer.h
+++ b/lib/raop_buffer.h
@@ -28,8 +28,8 @@ typedef int (*raop_resend_cb_t)(void *opaque, unsigned short seqno, unsigned sho
raop_buffer_t *raop_buffer_init(logger_t *logger,
const unsigned char *aeskey,
const unsigned char *aesiv);
-int raop_buffer_enqueue(raop_buffer_t *raop_buffer, unsigned char *data, unsigned short datalen, uint64_t *ntp_timestamp, uint64_t *rtp_timestamp, int use_seqnum);
-void *raop_buffer_dequeue(raop_buffer_t *raop_buffer, unsigned int *length, uint64_t *ntp_timestamp, uint64_t *rtp_timestamp, unsigned short *seqnum, int no_resend);
+int raop_buffer_enqueue(raop_buffer_t *raop_buffer, unsigned char *data, unsigned short datalen, int use_seqnum);
+void *raop_buffer_dequeue(raop_buffer_t *raop_buffer, unsigned int *length, uint32_t *rtp_timestamp, unsigned short *seqnum, int no_resend);
void raop_buffer_handle_resends(raop_buffer_t *raop_buffer, raop_resend_cb_t resend_cb, void *opaque);
void raop_buffer_flush(raop_buffer_t *raop_buffer, int next_seq);
diff --git a/lib/raop_handlers.h b/lib/raop_handlers.h
index 3b2c838..4dcfbab 100644
--- a/lib/raop_handlers.h
+++ b/lib/raop_handlers.h
@@ -25,6 +25,8 @@
#include
#define AUDIO_SAMPLE_RATE 44100 /* all supported AirPlay audio format use this sample rate */
#define SECOND_IN_USECS 1000000
+#define SECOND_IN_NSECS 1000000000
+#define MAX_PW_ATTEMPTS 5
typedef void (*raop_handler_t)(raop_conn_t *, http_request_t *,
http_response_t *, char **, int *);
@@ -36,6 +38,33 @@ raop_handler_info(raop_conn_t *conn,
{
assert(conn->raop->dnssd);
+#if 0
+ /* initial GET/info request sends plist with string "txtAirPlay" */
+ bool txtAirPlay = false;
+ const char* content_type = NULL;
+ content_type = http_request_get_header(request, "Content-Type");
+ if (content_type && strstr(content_type, "application/x-apple-binary-plist")) {
+ char *qualifier_string = NULL;
+ const char *data = NULL;
+ int data_len = 0;
+ data = http_request_get_data(request, &data_len);
+ //parsing bplist
+ plist_t req_root_node = NULL;
+ plist_from_bin(data, data_len, &req_root_node);
+ plist_t req_qualifier_node = plist_dict_get_item(req_root_node, "qualifier");
+ if (PLIST_IS_ARRAY(req_qualifier_node)) {
+ plist_t req_string_node = plist_array_get_item(req_qualifier_node, 0);
+ plist_get_string_val(req_string_node, &qualifier_string);
+ }
+ if (qualifier_string && !strcmp(qualifier_string, "txtAirPlay")) {
+ printf("qualifier: %s\n", qualifier_string);
+ txtAirPlay = true;
+ }
+ if (qualifier_string) {
+ free(qualifier_string);
+ }
+ }
+#endif
plist_t res_node = plist_new_dict();
/* deviceID is the physical hardware address, and will not change */
@@ -509,7 +538,7 @@ raop_handler_options(raop_conn_t *conn,
http_request_t *request, http_response_t *response,
char **response_data, int *response_datalen)
{
- http_response_add_header(response, "Public", "SETUP, RECORD, PAUSE, FLUSH, TEARDOWN, OPTIONS, GET_PARAMETER, SET_PARAMETER");
+ http_response_add_header(response, "Public", "SETUP, RECORD, FLUSH, TEARDOWN, OPTIONS, GET_PARAMETER, SET_PARAMETER");
}
static void
@@ -517,12 +546,12 @@ raop_handler_setup(raop_conn_t *conn,
http_request_t *request, http_response_t *response,
char **response_data, int *response_datalen)
{
- const char *dacp_id;
- const char *active_remote_header;
+ const char *dacp_id = NULL;
+ const char *active_remote_header = NULL;
bool logger_debug = (logger_get_level(conn->raop->logger) >= LOGGER_DEBUG);
- const char *data;
- int data_len;
+ const char *data = NULL;
+ int data_len = 0;
data = http_request_get_data(request, &data_len);
dacp_id = http_request_get_header(request, "DACP-ID");
@@ -548,22 +577,117 @@ raop_handler_setup(raop_conn_t *conn,
if (PLIST_IS_DATA(req_eiv_node) && PLIST_IS_DATA(req_ekey_node)) {
// The first SETUP call that initializes keys and timing
- unsigned char aesiv[16];
- unsigned char aeskey[16];
- unsigned char eaeskey[72];
+ unsigned char aesiv[16] = { 0 };
+ unsigned char aeskey[16] = { 0 };
+ unsigned char eaeskey[72] = { 0 };
logger_log(conn->raop->logger, LOGGER_DEBUG, "SETUP 1");
// First setup
- char* eiv = NULL;
- uint64_t eiv_len = 0;
char *deviceID = NULL;
- char *model = NULL;
- char *name = NULL;
- bool admit_client = true;
plist_t req_deviceid_node = plist_dict_get_item(req_root_node, "deviceID");
plist_get_string_val(req_deviceid_node, &deviceID);
+
+
+ /* RFC2617 Digest authentication (md5 hash) of uxplay client-access password, if set */
+ if (!conn->authenticated && conn->raop->callbacks.passwd) {
+ size_t pin_len = 4;
+ if (conn->raop->random_pw && strncmp(conn->raop->random_pw + pin_len + 1, deviceID, 17)) {
+ conn->raop->auth_fail_count = MAX_PW_ATTEMPTS;
+ }
+ int len;
+ const char *password = conn->raop->callbacks.passwd(conn->raop->callbacks.cls, &len);
+ // len = -1 means use a random password for this connection; len = 0 means no password
+ if (len == -1 && conn->raop->random_pw && conn->raop->auth_fail_count >= MAX_PW_ATTEMPTS) {
+ // change random_pw after MAX_PW_ATTEMPTS failed authentication attempts
+ logger_log(conn->raop->logger, LOGGER_INFO, "Too many authentication failures or new client: generate new random password");
+ free(conn->raop->random_pw);
+ conn->raop->random_pw = NULL;
+ }
+ if (len == -1 && !conn->raop->random_pw) {
+ // get and store 4 random digits
+ int pin_4 = random_pin();
+ if (pin_4 < 0) {
+ logger_log(conn->raop->logger, LOGGER_ERR, "Failed to generate random pin");
+ pin_4 = 1234;
+ }
+ conn->raop->random_pw = (char *) malloc(pin_len + 1 + 18);
+ char *pin = conn->raop->random_pw;
+ snprintf(pin, pin_len + 1, "%04u", pin_4 % 10000);
+ pin[pin_len] = '\0';
+ snprintf(pin + pin_len + 1, 18, "%s", deviceID);
+ conn->raop->auth_fail_count = 0;
+ if (conn->raop->callbacks.display_pin) {
+ conn->raop->callbacks.display_pin(conn->raop->callbacks.cls, pin);
+ }
+ logger_log(conn->raop->logger, LOGGER_INFO, "*** CLIENT MUST NOW ENTER PIN = \"%s\" AS AIRPLAY PASSWORD", pin);
+ }
+ if (len && !conn->authenticated) {
+ if (len == -1) {
+ password = (const char *) conn->raop->random_pw;
+ }
+ char nonce_string[33] = { '\0' };
+ //bool stale = false; //not implemented
+ const char *authorization = NULL;
+ authorization = http_request_get_header(request, "Authorization");
+ if (authorization) {
+ char *ptr = strstr(authorization, "nonce=\"") + strlen("nonce=\"");
+ strncpy(nonce_string, ptr, 32);
+ const char *method = http_request_get_method(request);
+ conn->authenticated = pairing_digest_verify(method, authorization, password);
+ if (!conn->authenticated) {
+ conn->raop->auth_fail_count++;
+ logger_log(conn->raop->logger, LOGGER_INFO, "*** authentication failure: count = %u", conn->raop->auth_fail_count);
+ if (conn->raop->callbacks.display_pin && conn->raop->auth_fail_count > 1) {
+ conn->raop->callbacks.display_pin(conn->raop->callbacks.cls, conn->raop->random_pw);
+ }
+ logger_log(conn->raop->logger, LOGGER_INFO, "*** CLIENT MUST NOW ENTER PIN = \"%s\" AS AIRPLAY PASSWORD", conn->raop->random_pw);
+ }
+ if (conn->authenticated) {
+ //printf("initial authenticatication OK\n");
+ conn->authenticated = conn->authenticated && !strcmp(nonce_string, conn->raop->nonce);
+ if (!conn->authenticated) {
+ logger_log(conn->raop->logger, LOGGER_INFO, "authentication rejected (nonce mismatch) %s %s",
+ nonce_string, conn->raop->nonce);
+ }
+ }
+ if (conn->authenticated && conn->raop->random_pw) {
+ free (conn->raop->random_pw);
+ conn->raop->random_pw = NULL;
+ }
+ if (conn->raop->nonce) {
+ free(conn->raop->nonce);
+ conn->raop->nonce = NULL;
+ }
+ logger_log(conn->raop->logger, LOGGER_INFO, "Client authentication %s", (conn->authenticated ? "success" : "failure"));
+ }
+ if (!conn->authenticated) {
+ /* create a nonce */
+ const char *url = http_request_get_url(request);
+ unsigned char nonce[16] = { '\0' };
+ int len = 16;
+ uint64_t now = raop_ntp_get_local_time();
+ assert (!pairing_session_make_nonce(conn->session, &now, url, nonce, len));
+ if (conn->raop->nonce) {
+ free(conn->raop->nonce);
+ }
+ conn->raop->nonce = utils_hex_to_string(nonce, len);
+ char response_text[80] = "Digest realm=\"raop\", nonce=\"";
+ strncat(response_text, conn->raop->nonce, 80 - strlen(response_text) - 1);
+ strncat(response_text, "\"", 80 - strlen(response_text) - 1);
+ http_response_init(response, "RTSP/1.0", 401, "Unauthorized");
+ http_response_add_header(response, "WWW-Authenticate", response_text);
+ return;
+ }
+ }
+ }
+
+ char* eiv = NULL;
+ uint64_t eiv_len = 0;
+ char *model = NULL;
+ char *name = NULL;
+ bool admit_client = true;
plist_t req_model_node = plist_dict_get_item(req_root_node, "model");
plist_get_string_val(req_model_node, &model);
plist_t req_name_node = plist_dict_get_item(req_root_node, "name");
@@ -572,16 +696,11 @@ raop_handler_setup(raop_conn_t *conn,
conn->raop->callbacks.report_client_request(conn->raop->callbacks.cls, deviceID, model, name, &admit_client);
}
if (admit_client && deviceID && name && conn->raop->callbacks.register_client) {
- bool pending_registration;
- char *client_device_id;
- char *client_pk; /* encoded as null-terminated base64 string*/
- access_client_session_data(conn->session, &client_device_id, &client_pk, &pending_registration);
- if (pending_registration) {
- if (client_pk && !strcmp(deviceID, client_device_id)) {
- conn->raop->callbacks.register_client(conn->raop->callbacks.cls, client_device_id, client_pk, name);
- }
- }
- if (client_pk) {
+ char *client_device_id = NULL;
+ char *client_pk = NULL; /* encoded as null-terminated base64 string, must be freed*/
+ get_pairing_session_client_data(conn->session, &client_device_id, &client_pk);
+ if (client_pk && !strcmp(deviceID, client_device_id)) {
+ conn->raop->callbacks.register_client(conn->raop->callbacks.cls, client_device_id, client_pk, name);
free (client_pk);
}
}
@@ -691,7 +810,7 @@ raop_handler_setup(raop_conn_t *conn,
}
}
char *timing_protocol = NULL;
- timing_protocol_t time_protocol;
+ timing_protocol_t time_protocol = TP_NONE;
plist_t req_timing_protocol_node = plist_dict_get_item(req_root_node, "timingProtocol");
plist_get_string_val(req_timing_protocol_node, &timing_protocol);
if (timing_protocol) {
@@ -730,7 +849,7 @@ raop_handler_setup(raop_conn_t *conn,
conn->raop_ntp = NULL;
conn->raop_rtp = NULL;
conn->raop_rtp_mirror = NULL;
- char remote[40];
+ char remote[40] = { 0 };
int len = utils_ipaddress_to_string(conn->remotelen, conn->remote, conn->zone_id, remote, (int) sizeof(remote));
if (!len || len > sizeof(remote)) {
char *str = utils_data_to_string(conn->remote, conn->remotelen, 16);
@@ -742,7 +861,7 @@ raop_handler_setup(raop_conn_t *conn,
}
conn->raop_ntp = raop_ntp_init(conn->raop->logger, &conn->raop->callbacks, remote,
conn->remotelen, (unsigned short) timing_rport, &time_protocol);
- raop_ntp_start(conn->raop_ntp, &timing_lport, conn->raop->max_ntp_timeouts);
+ raop_ntp_start(conn->raop_ntp, &timing_lport);
conn->raop_rtp = raop_rtp_init(conn->raop->logger, &conn->raop->callbacks, conn->raop_ntp,
remote, conn->remotelen, aeskey, aesiv);
conn->raop_rtp_mirror = raop_rtp_mirror_init(conn->raop->logger, &conn->raop->callbacks,
@@ -776,7 +895,7 @@ raop_handler_setup(raop_conn_t *conn,
// Mirroring
unsigned short dport = conn->raop->mirror_data_lport;
plist_t stream_id_node = plist_dict_get_item(req_stream_node, "streamConnectionID");
- uint64_t stream_connection_id;
+ uint64_t stream_connection_id = 0;
plist_get_uint_val(stream_id_node, &stream_connection_id);
logger_log(conn->raop->logger, LOGGER_DEBUG, "streamConnectionID (needed for AES-CTR video decryption"
" key and iv): %llu", stream_connection_id);
@@ -802,7 +921,7 @@ raop_handler_setup(raop_conn_t *conn,
// Audio
unsigned short cport = conn->raop->control_lport, dport = conn->raop->data_lport;
unsigned short remote_cport = 0;
- unsigned char ct;
+ unsigned char ct = 0;
unsigned int sr = AUDIO_SAMPLE_RATE; /* all AirPlay audio formats supported so far have sample rate 44.1kHz */
uint64_t uint_val = 0;
@@ -816,10 +935,10 @@ raop_handler_setup(raop_conn_t *conn,
if (conn->raop->callbacks.audio_get_format) {
/* get additional audio format parameters */
- uint64_t audioFormat;
- unsigned short spf;
- bool isMedia;
- bool usingScreen;
+ uint64_t audioFormat = 0;
+ unsigned short spf = 0;
+ bool isMedia = false;
+ bool usingScreen = false;
uint8_t bool_val = 0;
plist_t req_stream_spf_node = plist_dict_get_item(req_stream_node, "spf");
@@ -894,6 +1013,11 @@ raop_handler_get_parameter(raop_conn_t *conn,
int datalen;
content_type = http_request_get_header(request, "Content-Type");
+ if (!content_type) {
+ http_response_init(response, "RTSP/1.0", 451, "Parameter not understood");
+ return;
+ }
+
data = http_request_get_data(request, &datalen);
if (!strcmp(content_type, "text/parameters")) {
const char *current = data;
@@ -903,8 +1027,10 @@ raop_handler_get_parameter(raop_conn_t *conn,
/* This is a bit ugly, but seems to be how airport works too */
if ((datalen - (current - data) >= 8) && !strncmp(current, "volume\r\n", 8)) {
- const char volume[] = "volume: 0.0\r\n";
-
+ char volume[25] = "volume: 0.0\r\n";
+ if (conn->raop->callbacks.audio_set_client_volume) {
+ snprintf(volume, 25, "volume: %9.6f\r\n", conn->raop->callbacks.audio_set_client_volume(conn->raop->callbacks.cls));
+ }
http_response_add_header(response, "Content-Type", "text/parameters");
*response_data = strdup(volume);
if (*response_data) {
@@ -940,6 +1066,10 @@ raop_handler_set_parameter(raop_conn_t *conn,
int datalen;
content_type = http_request_get_header(request, "Content-Type");
+ if (!content_type) {
+ http_response_init(response, "RTSP/1.0", 451, "Parameter not understood");
+ return;
+ }
data = http_request_get_data(request, &datalen);
if (!strcmp(content_type, "text/parameters")) {
char *datastr;
@@ -983,6 +1113,8 @@ raop_handler_feedback(raop_conn_t *conn,
char **response_data, int *response_datalen)
{
logger_log(conn->raop->logger, LOGGER_DEBUG, "raop_handler_feedback");
+ /* register receipt of client's "heartbeat" signal */
+ conn->raop->callbacks.conn_feedback(conn->raop->callbacks.cls);
}
static void
@@ -1043,7 +1175,7 @@ raop_handler_teardown(raop_conn_t *conn,
uint64_t val;
int count = plist_array_get_size(req_streams_node);
for (int i = 0; i < count; i++) {
- plist_t req_stream_node = plist_array_get_item(req_streams_node,0);
+ plist_t req_stream_node = plist_array_get_item(req_streams_node,i);
plist_t req_stream_type_node = plist_dict_get_item(req_stream_node, "type");
plist_get_uint_val(req_stream_type_node, &val);
if (val == 96) {
@@ -1065,8 +1197,13 @@ raop_handler_teardown(raop_conn_t *conn,
if (conn->raop_rtp) {
/* Stop our audio RTP session */
raop_rtp_stop(conn->raop_rtp);
+ /* stop any coverart rendering */
+ if (conn->raop->callbacks.audio_stop_coverart_rendering) {
+ conn->raop->callbacks.audio_stop_coverart_rendering(conn->raop->callbacks.cls);
+ }
}
} else if (teardown_110) {
+ conn->raop->callbacks.video_reset(conn->raop->callbacks.cls);
if (conn->raop_rtp_mirror) {
/* Stop our video RTP session */
raop_rtp_mirror_stop(conn->raop_rtp_mirror);
@@ -1081,5 +1218,7 @@ raop_handler_teardown(raop_conn_t *conn,
raop_rtp_mirror_destroy(conn->raop_rtp_mirror);
conn->raop_rtp_mirror = NULL;
}
+ /* shut down any HLS connections */
+ httpd_remove_connections_by_type(conn->raop->httpd, CONNECTION_TYPE_HLS);
}
}
diff --git a/lib/raop_ntp.c b/lib/raop_ntp.c
index 1a932e4..2264883 100644
--- a/lib/raop_ntp.c
+++ b/lib/raop_ntp.c
@@ -58,8 +58,6 @@ struct raop_ntp_s {
logger_t *logger;
raop_callbacks_t callbacks;
- int max_ntp_timeouts;
-
thread_handle_t thread;
mutex_handle_t run_mutex;
@@ -94,8 +92,19 @@ struct raop_ntp_s {
int tsock;
timing_protocol_t time_protocol;
+ bool client_time_received;
+
+ uint64_t video_arrival_offset;
};
+/* for use in syncing audio before a first rtp_sync */
+void raop_ntp_set_video_arrival_offset(raop_ntp_t* raop_ntp, const uint64_t *offset) {
+ raop_ntp->video_arrival_offset = *offset;
+}
+
+uint64_t raop_ntp_get_video_arrival_offset(raop_ntp_t* raop_ntp) {
+ return raop_ntp->video_arrival_offset;
+}
/*
* Used for sorting the data array by delay
@@ -153,6 +162,9 @@ raop_ntp_t *raop_ntp_init(logger_t *logger, raop_callbacks_t *callbacks, const c
raop_ntp->logger = logger;
memcpy(&raop_ntp->callbacks, callbacks, sizeof(raop_callbacks_t));
raop_ntp->timing_rport = timing_rport;
+ raop_ntp->client_time_received = false;
+
+ raop_ntp->video_arrival_offset = 0;
if (raop_ntp_parse_remote(raop_ntp, remote, remote_addr_len) < 0) {
free(raop_ntp);
@@ -165,7 +177,7 @@ raop_ntp_t *raop_ntp_init(logger_t *logger, raop_callbacks_t *callbacks, const c
raop_ntp->running = 0;
raop_ntp->joined = 1;
- uint64_t time = raop_ntp_get_local_time(raop_ntp);
+ uint64_t time = raop_ntp_get_local_time();
for (int i = 0; i < RAOP_NTP_DATA_COUNT; ++i) {
raop_ntp->data[i].offset = 0ll;
@@ -274,10 +286,9 @@ raop_ntp_thread(void *arg)
};
raop_ntp_data_t data_sorted[RAOP_NTP_DATA_COUNT];
const unsigned two_pow_n[RAOP_NTP_DATA_COUNT] = {2, 4, 8, 16, 32, 64, 128, 256};
- int timeout_counter = 0;
- bool conn_reset = false;
bool logger_debug = (logger_get_level(raop_ntp->logger) >= LOGGER_DEBUG);
-
+ uint64_t recv_time = 0, client_ref_time = 0;
+
while (1) {
MUTEX_LOCK(raop_ntp->run_mutex);
if (!raop_ntp->running) {
@@ -290,8 +301,12 @@ raop_ntp_thread(void *arg)
raop_ntp_flush_socket(raop_ntp->tsock);
// Send request
- uint64_t send_time = raop_ntp_get_local_time(raop_ntp);
+ uint64_t send_time = raop_ntp_get_local_time();
byteutils_put_ntp_timestamp(request, 24, send_time);
+ if (recv_time) {
+ byteutils_put_long_be(request, 8, client_ref_time);
+ byteutils_put_ntp_timestamp(request, 16, recv_time);
+ }
int send_len = sendto(raop_ntp->tsock, (char *)request, sizeof(request), 0,
(struct sockaddr *) &raop_ntp->remote_saddr, raop_ntp->remote_saddr_len);
if (logger_debug) {
@@ -308,20 +323,17 @@ raop_ntp_thread(void *arg)
// Read response
response_len = recvfrom(raop_ntp->tsock, (char *)response, sizeof(response), 0, NULL, NULL);
if (response_len < 0) {
- timeout_counter++;
char time[30];
- int level = (timeout_counter == 1 ? LOGGER_DEBUG : LOGGER_ERR);
ntp_timestamp_to_time(send_time, time, sizeof(time));
- logger_log(raop_ntp->logger, level, "raop_ntp receive timeout %d (limit %d) (request sent %s)",
- timeout_counter, raop_ntp->max_ntp_timeouts, time);
- if (timeout_counter == raop_ntp->max_ntp_timeouts) {
- conn_reset = true; /* client is no longer responding */
- break;
- }
+ logger_log(raop_ntp->logger, LOGGER_DEBUG , "raop_ntp receive timeout (request sent %s)", time);
} else {
+ recv_time = raop_ntp_get_local_time();
+ client_ref_time = byteutils_get_long_be(response, 24);
+ if (!raop_ntp->client_time_received) {
+ raop_ntp->client_time_received = true;
+ }
//local time of the server when the NTP response packet returns
- int64_t t3 = (int64_t) raop_ntp_get_local_time(raop_ntp);
- timeout_counter = 0;
+ int64_t t3 = (int64_t) recv_time;
// Local time of the server when the NTP request packet leaves the server
int64_t t0 = (int64_t) byteutils_get_ntp_timestamp(response, 8);
@@ -391,15 +403,11 @@ raop_ntp_thread(void *arg)
MUTEX_UNLOCK(raop_ntp->run_mutex);
logger_log(raop_ntp->logger, LOGGER_DEBUG, "raop_ntp exiting thread");
- if (conn_reset && raop_ntp->callbacks.conn_reset) {
- const bool video_reset = false; /* leave "frozen video" in place */
- raop_ntp->callbacks.conn_reset(raop_ntp->callbacks.cls, timeout_counter, video_reset);
- }
return 0;
}
void
-raop_ntp_start(raop_ntp_t *raop_ntp, unsigned short *timing_lport, int max_ntp_timeouts)
+raop_ntp_start(raop_ntp_t *raop_ntp, unsigned short *timing_lport)
{
logger_log(raop_ntp->logger, LOGGER_DEBUG, "raop_ntp starting time");
int use_ipv6 = 0;
@@ -407,7 +415,6 @@ raop_ntp_start(raop_ntp_t *raop_ntp, unsigned short *timing_lport, int max_ntp_t
assert(raop_ntp);
assert(timing_lport);
- raop_ntp->max_ntp_timeouts = max_ntp_timeouts;
raop_ntp->timing_lport = *timing_lport;
MUTEX_LOCK(raop_ntp->run_mutex);
@@ -457,13 +464,13 @@ raop_ntp_stop(raop_ntp_t *raop_ntp)
COND_SIGNAL(raop_ntp->wait_cond);
MUTEX_UNLOCK(raop_ntp->wait_mutex);
+ THREAD_JOIN(raop_ntp->thread);
+
if (raop_ntp->tsock != -1) {
closesocket(raop_ntp->tsock);
raop_ntp->tsock = -1;
}
- THREAD_JOIN(raop_ntp->thread);
-
logger_log(raop_ntp->logger, LOGGER_DEBUG, "raop_ntp stopped time thread");
/* Mark thread as joined */
@@ -495,7 +502,7 @@ uint64_t raop_remote_timestamp_to_nano_seconds(raop_ntp_t *raop_ntp, uint64_t ti
* Returns the current time in nano seconds according to the local wall clock.
* The system Unix time is used as the local wall clock.
*/
-uint64_t raop_ntp_get_local_time(raop_ntp_t *raop_ntp) {
+uint64_t raop_ntp_get_local_time() {
struct timespec time;
clock_gettime(CLOCK_REALTIME, &time);
return ((uint64_t) time.tv_nsec) + (uint64_t) time.tv_sec * SECOND_IN_NSECS;
@@ -505,16 +512,22 @@ uint64_t raop_ntp_get_local_time(raop_ntp_t *raop_ntp) {
* Returns the current time in nano seconds according to the remote wall clock.
*/
uint64_t raop_ntp_get_remote_time(raop_ntp_t *raop_ntp) {
+ if (!raop_ntp->client_time_received) {
+ return 0;
+ }
MUTEX_LOCK(raop_ntp->sync_params_mutex);
int64_t offset = raop_ntp->sync_offset;
MUTEX_UNLOCK(raop_ntp->sync_params_mutex);
- return (uint64_t) ((int64_t) raop_ntp_get_local_time(raop_ntp) + offset);
+ return (uint64_t) ((int64_t) raop_ntp_get_local_time() + offset);
}
/**
* Returns the local wall clock time in nano seconds for the given point in remote clock time
*/
uint64_t raop_ntp_convert_remote_time(raop_ntp_t *raop_ntp, uint64_t remote_time) {
+ if (!raop_ntp->client_time_received) {
+ return 0;
+ }
MUTEX_LOCK(raop_ntp->sync_params_mutex);
int64_t offset = raop_ntp->sync_offset;
MUTEX_UNLOCK(raop_ntp->sync_params_mutex);
@@ -525,6 +538,9 @@ uint64_t raop_ntp_convert_remote_time(raop_ntp_t *raop_ntp, uint64_t remote_time
* Returns the remote wall clock time in nano seconds for the given point in local clock time
*/
uint64_t raop_ntp_convert_local_time(raop_ntp_t *raop_ntp, uint64_t local_time) {
+ if (!raop_ntp->client_time_received) {
+ return 0;
+ }
MUTEX_LOCK(raop_ntp->sync_params_mutex);
int64_t offset = raop_ntp->sync_offset;
MUTEX_UNLOCK(raop_ntp->sync_params_mutex);
diff --git a/lib/raop_ntp.h b/lib/raop_ntp.h
index bf2f5bb..ad7a1ad 100644
--- a/lib/raop_ntp.h
+++ b/lib/raop_ntp.h
@@ -27,7 +27,7 @@ typedef struct raop_ntp_s raop_ntp_t;
typedef enum timing_protocol_e { NTP, TP_NONE, TP_OTHER, TP_UNSPECIFIED } timing_protocol_t;
-void raop_ntp_start(raop_ntp_t *raop_ntp, unsigned short *timing_lport, int max_ntp_timeouts);
+void raop_ntp_start(raop_ntp_t *raop_ntp, unsigned short *timing_lport);
void raop_ntp_stop(raop_ntp_t *raop_ntp);
@@ -38,9 +38,12 @@ void raop_ntp_destroy(raop_ntp_t *raop_rtp);
uint64_t raop_ntp_timestamp_to_nano_seconds(uint64_t ntp_timestamp, bool account_for_epoch_diff);
uint64_t raop_remote_timestamp_to_nano_seconds(raop_ntp_t *raop_ntp, uint64_t timestamp);
-uint64_t raop_ntp_get_local_time(raop_ntp_t *raop_ntp);
+uint64_t raop_ntp_get_local_time();
uint64_t raop_ntp_get_remote_time(raop_ntp_t *raop_ntp);
uint64_t raop_ntp_convert_remote_time(raop_ntp_t *raop_ntp, uint64_t remote_time);
uint64_t raop_ntp_convert_local_time(raop_ntp_t *raop_ntp, uint64_t local_time);
+void raop_ntp_set_video_arrival_offset(raop_ntp_t* raop_ntp, const uint64_t *offset);
+uint64_t raop_ntp_get_video_arrival_offset(raop_ntp_t* raop_ntp);
+
#endif //RAOP_NTP_H
diff --git a/lib/raop_rtp.c b/lib/raop_rtp.c
index 62543f7..f51eeab 100644
--- a/lib/raop_rtp.c
+++ b/lib/raop_rtp.c
@@ -36,10 +36,9 @@
#define NO_FLUSH (-42)
#define SECOND_IN_NSECS 1000000000
-#define RAOP_RTP_SYNC_DATA_COUNT 8
#define SEC SECOND_IN_NSECS
-#define DELAY_AAC 0.275 //empirical, matches audio latency of about -0.25 sec after first clock sync event
+#define DELAY_AAC 0.20 //empirical, matches audio latency of about -0.25 sec after first clock sync event
/* note: it is unclear what will happen in the unlikely event that this code is running at the time of the unix-time
* epoch event on 2038-01-19 at 3:14:08 UTC ! (but Apple will surely have removed AirPlay "legacy pairing" by then!) */
@@ -56,14 +55,16 @@ struct raop_rtp_s {
// Time and sync
raop_ntp_t *ntp;
double rtp_clock_rate;
- int64_t rtp_sync_offset;
- raop_rtp_sync_data_t sync_data[RAOP_RTP_SYNC_DATA_COUNT];
- int sync_data_index;
+
uint64_t ntp_start_time;
uint64_t rtp_start_time;
uint64_t rtp_time;
bool rtp_clock_started;
+ uint32_t rtp_sync;
+ uint64_t client_ntp_sync;
+ bool initial_sync;
+
// Transmission Stats, could be used if a playout buffer is needed
// float interarrival_jitter; // As defined by RTP RFC 3550, Section 6.4.1
// unsigned int last_packet_transit_time;
@@ -161,12 +162,10 @@ raop_rtp_init(logger_t *logger, raop_callbacks_t *callbacks, raop_ntp_t *ntp, co
raop_rtp->logger = logger;
raop_rtp->ntp = ntp;
- raop_rtp->rtp_sync_offset = 0;
- raop_rtp->sync_data_index = 0;
- for (int i = 0; i < RAOP_RTP_SYNC_DATA_COUNT; ++i) {
- raop_rtp->sync_data[i].ntp_time = 0;
- raop_rtp->sync_data[i].rtp_time = 0;
- }
+ raop_rtp->rtp_sync = 0;
+ raop_rtp->client_ntp_sync = 0;
+ raop_rtp->initial_sync = false;
+
raop_rtp->ntp_start_time = 0;
raop_rtp->rtp_start_time = 0;
raop_rtp->rtp_clock_started = false;
@@ -386,59 +385,24 @@ raop_rtp_process_events(raop_rtp_t *raop_rtp, void *cb_data)
return 0;
}
-void raop_rtp_sync_clock(raop_rtp_t *raop_rtp, uint64_t *ntp_time, uint64_t *rtp_time) {
- /* ntp_time = (uint64_t)(((int64_t)(raop_rtp->rtp_clock_rate * rtp_time)) + raop_rtp->rtp_sync_offset) */
- int latest, valid_data_count = 0;
- uint64_t ntp_sum = 0, rtp_sum = 0;
- double offset = ((double) *ntp_time) - raop_rtp->rtp_clock_rate * *rtp_time;
- int64_t correction = 0;
-
- raop_rtp->sync_data_index = (raop_rtp->sync_data_index + 1) % RAOP_RTP_SYNC_DATA_COUNT;
- latest = raop_rtp->sync_data_index;
- raop_rtp->sync_data[latest].rtp_time = *rtp_time;
- raop_rtp->sync_data[latest].ntp_time = *ntp_time;
-
- for (int i = 0; i < RAOP_RTP_SYNC_DATA_COUNT; i++) {
- if (raop_rtp->sync_data[i].ntp_time == 0) continue;
- valid_data_count++;
- if (i == latest) continue;
- ntp_sum += *ntp_time - raop_rtp->sync_data[i].ntp_time;
- rtp_sum += *rtp_time - raop_rtp->sync_data[i].rtp_time;
+static uint64_t rtp_time_to_client_ntp(raop_rtp_t *raop_rtp, uint32_t rtp32) {
+ if (!raop_rtp->initial_sync) {
+ return 0;
}
-
- if (valid_data_count > 1) {
- correction -= raop_rtp->rtp_sync_offset;
- offset += (((double) ntp_sum) - raop_rtp->rtp_clock_rate * rtp_sum) / valid_data_count;
- }
- raop_rtp->rtp_sync_offset = (int64_t) offset;
- correction += raop_rtp->rtp_sync_offset;
-
- logger_log(raop_rtp->logger, LOGGER_DEBUG, "dataset %d raop_rtp sync correction=%lld, rtp_sync_offset = %lld ",
- valid_data_count, correction, raop_rtp->rtp_sync_offset);
-}
-
-uint64_t rtp64_time (raop_rtp_t *raop_rtp, const uint32_t *rtp32) {
- /* convert from 32-bit to 64-bit rtp time:
- * the rtp_time 32-bit epoch at 44.1kHz has length of about 27 hours
- * using 64-bit rtp time avoids any epoch issues.
- * initial call sets epoch to 1; subsequent calls maintain consistent epoch.
- * (assumes successive calls are close in time) */
-
- if (raop_rtp->rtp_clock_started) {
- uint32_t diff1 = *rtp32 - ((uint32_t) raop_rtp->rtp_time);
- uint32_t diff2 = ((uint32_t) raop_rtp->rtp_time) - *rtp32;
- if (diff1 <= diff2) {
- raop_rtp->rtp_time += (uint64_t) diff1;
- } else {
- raop_rtp->rtp_time -= (uint64_t) diff2;
- }
+ int32_t rtp_change;
+ rtp32 -= raop_rtp->rtp_sync;
+ if (rtp32 <= INT32_MAX) {
+ rtp_change = (int32_t) rtp32;
} else {
- raop_rtp->rtp_time = (0x01ULL << 32 ) + (uint64_t) *rtp32;
- raop_rtp->rtp_start_time = raop_rtp->rtp_time;
- raop_rtp->rtp_clock_started = true;
+ rtp_change = -(int32_t) (-rtp32);
+ }
+ double incr = raop_rtp->rtp_clock_rate * (double) rtp_change;
+ incr += (double) raop_rtp->client_ntp_sync;
+ if (incr < 0.0) {
+ return 0;
+ } else {
+ return (uint64_t) incr;
}
- //assert(*rtp32 == (uint32_t) raop_rtp->rtp_time);
- return raop_rtp->rtp_time;
}
static THREAD_RETVAL
@@ -450,22 +414,16 @@ raop_rtp_thread_udp(void *arg)
struct sockaddr_storage saddr;
socklen_t saddrlen;
bool got_remote_control_saddr = false;
+ uint64_t video_arrival_offset = 0;
- /* for initial rtp to ntp conversions */
- bool have_synced = false;
- bool no_data_yet = true;
+ /* initial audio stream has no data */
unsigned char no_data_marker[] = {0x00, 0x68, 0x34, 0x00 };
- int rtp_count = 0;
- double sync_adjustment = 0;
- unsigned short seqnum1 = 0, seqnum2 = 0;
assert(raop_rtp);
bool logger_debug = (logger_get_level(raop_rtp->logger) >= LOGGER_DEBUG);
- raop_rtp->ntp_start_time = raop_ntp_get_local_time(raop_rtp->ntp);
+ bool logger_debug_data = (logger_get_level(raop_rtp->logger) >= LOGGER_DEBUG_DATA);
+ raop_rtp->ntp_start_time = raop_ntp_get_local_time();
raop_rtp->rtp_clock_started = false;
- for (int i = 0; i < RAOP_RTP_SYNC_DATA_COUNT; i++) {
- raop_rtp->sync_data[i].ntp_time = 0;
- }
int no_resend = (raop_rtp->control_rport == 0); /* true when control_rport is not set */
@@ -500,7 +458,9 @@ raop_rtp_thread_udp(void *arg)
/* Timeout happened */
continue;
} else if (ret == -1) {
- logger_log(raop_rtp->logger, LOGGER_ERR, "raop_rtp error in select");
+ int sock_err = SOCKET_GET_ERROR();
+ logger_log(raop_rtp->logger, LOGGER_ERR,
+ "raop_rtp error in select %d %s", sock_err, SOCKET_ERROR_STRING(sock_err));
break;
}
@@ -526,14 +486,8 @@ raop_rtp_thread_udp(void *arg)
unsigned int resent_packetlen = packetlen - 4;
unsigned short seqnum = byteutils_get_short_be(resent_packet, 2);
if (resent_packetlen >= 12) {
- uint32_t timestamp = byteutils_get_int_be(resent_packet, 4);
- uint64_t rtp_time = rtp64_time(raop_rtp, ×tamp);
- uint64_t ntp_time = 0;
- if (have_synced) {
- ntp_time = (uint64_t) (raop_rtp->rtp_sync_offset + (int64_t) (raop_rtp->rtp_clock_rate * rtp_time));
- }
logger_log(raop_rtp->logger, LOGGER_DEBUG, "raop_rtp resent audio packet: seqnum=%u", seqnum);
- int result = raop_buffer_enqueue(raop_rtp->buffer, resent_packet, resent_packetlen, &ntp_time, &rtp_time, 1);
+ int result = raop_buffer_enqueue(raop_rtp->buffer, resent_packet, resent_packetlen, 1);
assert(result >= 0);
} else if (logger_debug) {
/* type_c = 0x56 packets with length 8 have been reported */
@@ -553,24 +507,30 @@ raop_rtp_thread_udp(void *arg)
* next_rtp = sync_rtp + 77175 = 441 * 175 (1.75 sec) for ALAC */
// The unit for the rtp clock is 1 / sample rate = 1 / 44100
- uint32_t sync_rtp = byteutils_get_int_be(packet, 4);
- uint64_t sync_rtp64 = rtp64_time(raop_rtp, &sync_rtp);
- if (have_synced == false) {
+ uint64_t client_ntp_sync_prev = 0;
+ uint64_t rtp_sync_prev = 0;
+ if (!raop_rtp->initial_sync) {
logger_log(raop_rtp->logger, LOGGER_DEBUG, "first audio rtp sync");
- have_synced = true;
- }
+ raop_rtp->initial_sync = true;
+ } else {
+ client_ntp_sync_prev = raop_rtp->client_ntp_sync;
+ rtp_sync_prev = raop_rtp->rtp_sync;
+ }
+ raop_rtp->rtp_sync = byteutils_get_int_be(packet, 4);
uint64_t sync_ntp_raw = byteutils_get_long_be(packet, 8);
- uint64_t sync_ntp_remote = raop_remote_timestamp_to_nano_seconds(raop_rtp->ntp, sync_ntp_raw);
+ raop_rtp->client_ntp_sync = raop_remote_timestamp_to_nano_seconds(raop_rtp->ntp, sync_ntp_raw);
+
if (logger_debug) {
- uint64_t sync_ntp_local = raop_ntp_convert_remote_time(raop_rtp->ntp, sync_ntp_remote);
+ double offset_change = ((double) raop_rtp->client_ntp_sync) - raop_rtp->rtp_clock_rate * raop_rtp->rtp_sync;
+ offset_change -= ((double) client_ntp_sync_prev) - raop_rtp->rtp_clock_rate * rtp_sync_prev;
+ uint64_t sync_ntp_local = raop_ntp_convert_remote_time(raop_rtp->ntp, raop_rtp->rtp_sync);
char *str = utils_data_to_string(packet, packetlen, 20);
logger_log(raop_rtp->logger, LOGGER_DEBUG,
- "raop_rtp sync: client ntp=%8.6f, ntp = %8.6f, ntp_start_time %8.6f\nts_client = %8.6f sync_rtp=%u\n%s",
- (double) sync_ntp_remote / SEC, (double) sync_ntp_local / SEC,
- (double) raop_rtp->ntp_start_time / SEC, (double) sync_ntp_remote / SEC, sync_rtp, str);
+ "raop_rtp sync: ntp = %8.6f, ntp_start_time %8.6f\nts_client = %8.6f sync_rtp=%u offset change = %8.6f\n%s",
+ (double) sync_ntp_local / SEC, (double) raop_rtp->ntp_start_time / SEC,
+ (double) raop_rtp->client_ntp_sync / SEC, raop_rtp->rtp_sync, offset_change / SEC, str);
free(str);
}
- raop_rtp_sync_clock(raop_rtp, &sync_ntp_remote, &sync_rtp64);
} else if (logger_debug) {
char *str = utils_data_to_string(packet, packetlen, 16);
logger_log(raop_rtp->logger, LOGGER_DEBUG, "raop_rtp unknown udp control packet\n%s", str);
@@ -615,6 +575,9 @@ raop_rtp_thread_udp(void *arg)
if (FD_ISSET(raop_rtp->dsock, &rfds)) {
+ if (!raop_rtp->initial_sync && !video_arrival_offset) {
+ video_arrival_offset = raop_ntp_get_video_arrival_offset(raop_rtp->ntp);
+ }
//logger_log(raop_rtp->logger, LOGGER_INFO, "Would have data packet in queue");
// Receiving audio data here
saddrlen = sizeof(saddr);
@@ -633,83 +596,58 @@ raop_rtp_thread_udp(void *arg)
continue;
}
- uint32_t rtp_timestamp = byteutils_get_int_be(packet, 4);
- uint64_t rtp_time = rtp64_time(raop_rtp, &rtp_timestamp);
- uint64_t ntp_time = 0;
+ if (!raop_rtp->initial_sync && raop_rtp->ct == 8 && video_arrival_offset) {
+ /* estimate a fake initial remote timestamp for video synchronization with AAC audio before the first rtp sync */
+ uint64_t ts = raop_ntp_get_local_time() - video_arrival_offset;
+ double delay = DELAY_AAC;
+ ts += (uint64_t) (delay * SEC);
+ raop_rtp->client_ntp_sync = ts;
+ raop_rtp->rtp_sync = byteutils_get_int_be(packet, 4);
+ raop_rtp->initial_sync = true;
+ }
+ if (packetlen == 16 && memcmp(packet + 12, no_data_marker, 4) == 0) {
+ /* this is a "no data" packet */
+ /* the first such packet could be used to provide the initial rtptime and seqnum formerly given in the RECORD request */
+ continue;
+ }
+
if (raop_rtp->ct == 2 && packetlen == 44) continue; /* ignore the ALAC packets with format information only. */
- if (have_synced) {
- ntp_time = (uint64_t) (raop_rtp->rtp_sync_offset + (int64_t) (raop_rtp->rtp_clock_rate * rtp_time));
- } else if (packetlen == 16 && memcmp(packet + 12, no_data_marker, 4) == 0) {
- /* use the special "no_data" packet to help determine an initial offset before the first rtp sync.
- * until the first rtp sync occurs, we don't know the exact client ntp timestamp that matches the client rtp timestamp */
- if (no_data_yet) {
- int64_t sync_ntp = ((int64_t) raop_ntp_get_local_time(raop_rtp->ntp)) - ((int64_t) raop_rtp->ntp_start_time) ;
- int64_t sync_rtp = ((int64_t) rtp_time) - ((int64_t) raop_rtp->rtp_start_time);
- unsigned short seqnum = byteutils_get_short_be(packet, 2);
- if (rtp_count == 0) {
- sync_adjustment = ((double) sync_ntp);
- rtp_count = 1;
- seqnum1 = seqnum;
- seqnum2 = seqnum;
- }
- if (seqnum2 != seqnum) { /* for AAC-ELD only use copy 1 of the 3 copies of each frame */
- rtp_count++;
- sync_adjustment += (((double) sync_ntp) - raop_rtp->rtp_clock_rate * sync_rtp - sync_adjustment) / rtp_count;
- }
- seqnum2 = seqnum1;
- seqnum1 = seqnum;
- }
- continue;
- } else {
- no_data_yet = false;
- }
- int result = raop_buffer_enqueue(raop_rtp->buffer, packet, packetlen, &ntp_time, &rtp_time, 1);
+ int result = raop_buffer_enqueue(raop_rtp->buffer, packet, packetlen, 1);
assert(result >= 0);
- if (raop_rtp->ct == 2 && !have_synced) {
- /* in ALAC Audio-only mode wait until the first sync before dequeing */
+ if (!raop_rtp->initial_sync) {
+ /* wait until the first sync before dequeing ALAC */
continue;
} else {
// Render continuous buffer entries
void *payload = NULL;
unsigned int payload_size;
unsigned short seqnum;
- uint64_t rtp64_timestamp;
- uint64_t ntp_timestamp;
+ uint32_t rtp_timestamp;
- while ((payload = raop_buffer_dequeue(raop_rtp->buffer, &payload_size, &ntp_timestamp, &rtp64_timestamp, &seqnum, no_resend))) {
+ while ((payload = raop_buffer_dequeue(raop_rtp->buffer, &payload_size, &rtp_timestamp, &seqnum, no_resend))) {
audio_decode_struct audio_data;
- audio_data.rtp_time = rtp64_timestamp;
+ audio_data.rtp_time = rtp_timestamp;
audio_data.seqnum = seqnum;
audio_data.data_len = payload_size;
audio_data.data = payload;
audio_data.ct = raop_rtp->ct;
- if (have_synced) {
- if (ntp_timestamp == 0) {
- ntp_timestamp = (uint64_t) (raop_rtp->rtp_sync_offset + (int64_t) (raop_rtp->rtp_clock_rate * rtp64_timestamp));
- }
- audio_data.ntp_time_remote = ntp_timestamp;
- audio_data.ntp_time_local = raop_ntp_convert_remote_time(raop_rtp->ntp, audio_data.ntp_time_remote);
- audio_data.sync_status = 1;
- } else {
- double elapsed_time = raop_rtp->rtp_clock_rate * (rtp64_timestamp - raop_rtp->rtp_start_time) + sync_adjustment
- + DELAY_AAC * SECOND_IN_NSECS;
- audio_data.ntp_time_local = raop_rtp->ntp_start_time + (uint64_t) elapsed_time;
- audio_data.ntp_time_remote = raop_ntp_convert_local_time(raop_rtp->ntp, audio_data.ntp_time_local);
- audio_data.sync_status = 0;
+ audio_data.ntp_time_remote = rtp_time_to_client_ntp(raop_rtp, rtp_timestamp);
+ audio_data.ntp_time_local = raop_ntp_convert_remote_time(raop_rtp->ntp, audio_data.ntp_time_remote);
+
+ if (logger_debug_data) {
+ uint64_t ntp_now = raop_ntp_get_local_time();
+ int64_t latency = (audio_data.ntp_time_local ? ((int64_t) ntp_now) - ((int64_t) audio_data.ntp_time_local) : 0);
+ logger_log(raop_rtp->logger, LOGGER_DEBUG,
+ "raop_rtp audio: now = %8.6f, ntp = %8.6f, latency = %9.6f, ts = %8.6f, rtp_time=%u seqnum = %u",
+ (double) ntp_now / SEC, (double) audio_data.ntp_time_local / SEC, (double) latency / SEC,
+ (double) audio_data.ntp_time_remote /SEC, rtp_timestamp, seqnum);
}
+
raop_rtp->callbacks.audio_process(raop_rtp->callbacks.cls, raop_rtp->ntp, &audio_data);
free(payload);
- if (logger_debug) {
- uint64_t ntp_now = raop_ntp_get_local_time(raop_rtp->ntp);
- int64_t latency = ((int64_t) ntp_now) - ((int64_t) audio_data.ntp_time_local);
- logger_log(raop_rtp->logger, LOGGER_DEBUG,
- "raop_rtp audio: now = %8.6f, ntp = %8.6f, latency = %8.6f, rtp_time=%u seqnum = %u",
- (double) ntp_now / SEC, (double) audio_data.ntp_time_local / SEC, (double) latency / SEC,
- (uint32_t) rtp64_timestamp, seqnum);
- }
}
/* Handle possible resend requests */
@@ -897,8 +835,14 @@ raop_rtp_stop(raop_rtp_t *raop_rtp)
/* Join the thread */
THREAD_JOIN(raop_rtp->thread);
- if (raop_rtp->csock != -1) closesocket(raop_rtp->csock);
- if (raop_rtp->dsock != -1) closesocket(raop_rtp->dsock);
+ if (raop_rtp->csock != -1) {
+ closesocket(raop_rtp->csock);
+ raop_rtp->csock = -1;
+ }
+ if (raop_rtp->dsock != -1) {
+ closesocket(raop_rtp->dsock);
+ raop_rtp->dsock = -1;
+ }
/* Flush buffer into initial state */
raop_buffer_flush(raop_rtp->buffer, -1);
diff --git a/lib/raop_rtp_mirror.c b/lib/raop_rtp_mirror.c
index bc88472..82c55df 100644
--- a/lib/raop_rtp_mirror.c
+++ b/lib/raop_rtp_mirror.c
@@ -62,6 +62,11 @@
#define TCP_KEEPIDLE TCP_KEEPALIVE
#endif
+/* for OpenBSD, where TCP_KEEPIDLE and TCP_KEEPALIVE are not defined */
+#if !defined(TCP_KEEPIDLE) && !defined(TCP_KEEPALIVE)
+#define TCP_KEEPIDLE SO_KEEPALIVE
+#endif
+
//struct h264codec_s {
// unsigned char compatibility;
// short pps_size;
@@ -195,12 +200,14 @@ raop_rtp_mirror_thread(void *arg)
uint64_t ntp_timestamp_local = 0;
unsigned char nal_start_code[4] = { 0x00, 0x00, 0x00, 0x01 };
bool logger_debug = (logger_get_level(raop_rtp_mirror->logger) >= LOGGER_DEBUG);
+ bool logger_debug_data = (logger_get_level(raop_rtp_mirror->logger) >= LOGGER_DEBUG_DATA);
bool h265_video = false;
- video_codec_t codec;
+ video_codec_t codec = VIDEO_CODEC_UNKNOWN;
const char h264[] = "h264";
const char h265[] = "h265";
bool unsupported_codec = false;
bool video_stream_suspended = false;
+ bool first_packet = true;
while (1) {
fd_set rfds;
@@ -232,7 +239,9 @@ raop_rtp_mirror_thread(void *arg)
/* Timeout happened */
continue;
} else if (ret == -1) {
- logger_log(raop_rtp_mirror->logger, LOGGER_ERR, "raop_rtp_mirror error in select");
+ int sock_err = SOCKET_GET_ERROR();
+ logger_log(raop_rtp_mirror->logger, LOGGER_ERR,
+ "raop_rtp_mirror error in select %d %s", sock_err, SOCKET_ERROR_STRING(sock_err));
break;
}
@@ -275,6 +284,8 @@ raop_rtp_mirror_thread(void *arg)
logger_log(raop_rtp_mirror->logger, LOGGER_WARNING,
"raop_rtp_mirror could not set stream socket keepalive time %d %s", sock_err, SOCKET_ERROR_STRING(sock_err));
}
+/* OpenBSD does not have these options. */
+#ifndef __OpenBSD__
option = 10;
if (setsockopt(stream_fd, SOL_TCP, TCP_KEEPINTVL, CAST &option, sizeof(option)) < 0) {
int sock_err = SOCKET_GET_ERROR();
@@ -287,6 +298,7 @@ raop_rtp_mirror_thread(void *arg)
logger_log(raop_rtp_mirror->logger, LOGGER_WARNING,
"raop_rtp_mirror could not set stream socket keepalive probes %d %s", sock_err, SOCKET_ERROR_STRING(sock_err));
}
+#endif /* !__OpenBSD__ */
readstart = 0;
}
@@ -327,6 +339,11 @@ raop_rtp_mirror_thread(void *arg)
}
ntp_timestamp_raw = byteutils_get_long(packet, 8);
ntp_timestamp_remote = raop_ntp_timestamp_to_nano_seconds(ntp_timestamp_raw, false);
+ if (first_packet) {
+ uint64_t offset = raop_ntp_get_local_time() - ntp_timestamp_remote;
+ raop_ntp_set_video_arrival_offset(raop_rtp_mirror->ntp, &offset);
+ first_packet = false;
+ }
/* packet[4] + packet[5] identify the payload type: values seen are: *
* 0x00 0x00: encrypted packet containing a non-IDR type 1 VCL NAL unit *
@@ -388,11 +405,11 @@ raop_rtp_mirror_thread(void *arg)
// counting nano seconds since last boot.
ntp_timestamp_local = raop_ntp_convert_remote_time(raop_rtp_mirror->ntp, ntp_timestamp_remote);
- if (logger_debug) {
- uint64_t ntp_now = raop_ntp_get_local_time(raop_rtp_mirror->ntp);
- int64_t latency = ((int64_t) ntp_now) - ((int64_t) ntp_timestamp_local);
+ if (logger_debug_data) {
+ uint64_t ntp_now = raop_ntp_get_local_time();
+ int64_t latency = (ntp_timestamp_local ? ((int64_t) ntp_now) - ((int64_t) ntp_timestamp_local) : 0);
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG,
- "raop_rtp video: now = %8.6f, ntp = %8.6f, latency = %8.6f, ts = %8.6f, %s %s",
+ "raop_rtp video: now = %8.6f, ntp = %8.6f, latency = %9.6f, ts = %8.6f, %s %s",
(double) ntp_now / SEC, (double) ntp_timestamp_local / SEC, (double) latency / SEC,
(double) ntp_timestamp_remote / SEC, packet_description, h265_video ? h265 : h264);
}
@@ -562,6 +579,9 @@ raop_rtp_mirror_thread(void *arg)
" payload_size %d header %s ts_client = %8.6f",
payload_size, packet_description, (double) ntp_timestamp_remote / SEC);
+ if (packet[6] == 0x56 || packet[6] == 0x5e) {
+ logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "This packet indicates video stream is stopping");
+ }
if (!video_stream_suspended && (packet[6] == 0x56 || packet[6] == 0x5e)) {
video_stream_suspended = true;
raop_rtp_mirror->callbacks.video_pause(raop_rtp_mirror->callbacks.cls);
@@ -570,7 +590,6 @@ raop_rtp_mirror_thread(void *arg)
video_stream_suspended = false;
}
- codec = VIDEO_CODEC_UNKNOWN;
assert (raop_rtp_mirror->callbacks.video_set_codec);
ntp_timestamp_nal = ntp_timestamp_raw;
@@ -611,9 +630,21 @@ raop_rtp_mirror_thread(void *arg)
if (!memcmp(payload + 4, hvc1, 4)) {
/* hvc1 HECV detected */
- codec = VIDEO_CODEC_H265;
- h265_video = true;
- raop_rtp_mirror->callbacks.video_set_codec(raop_rtp_mirror->callbacks.cls, codec);
+ if (codec == VIDEO_CODEC_UNKNOWN) {
+ codec = VIDEO_CODEC_H265;
+ h265_video = true;
+ if (raop_rtp_mirror->callbacks.video_set_codec(raop_rtp_mirror->callbacks.cls, codec) < 0) {
+ logger_log(raop_rtp_mirror->logger, LOGGER_ERR, "failed to set video codec as H265 ");
+ /* drop connection */
+ conn_reset = true;
+ break;
+ }
+ } else if (codec != VIDEO_CODEC_H265) {
+ logger_log(raop_rtp_mirror->logger, LOGGER_ERR, "invalid video codec change to H265: codec was set previously");
+ /* drop connection */
+ conn_reset = true;
+ break;
+ }
unsigned char vps_start_code[] = { 0xa0, 0x00, 0x01, 0x00 };
unsigned char sps_start_code[] = { 0xa1, 0x00, 0x01, 0x00 };
unsigned char pps_start_code[] = { 0xa2, 0x00, 0x01, 0x00 };
@@ -636,7 +667,7 @@ raop_rtp_mirror_thread(void *arg)
vps = ptr;
if (logger_debug) {
char *str = utils_data_to_string(vps, vps_size, 16);
- logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "h265 vps size %d\n%s",vps_size, str);
+ logger_log(raop_rtp_mirror->logger, LOGGER_INFO, "h265 vps size %d\n%s",vps_size, str);
free(str);
}
ptr += vps_size;
@@ -650,7 +681,7 @@ raop_rtp_mirror_thread(void *arg)
sps = ptr;
if (logger_debug) {
char *str = utils_data_to_string(sps, sps_size, 16);
- logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "h265 sps size %d\n%s",vps_size, str);
+ logger_log(raop_rtp_mirror->logger, LOGGER_INFO, "h265 sps size %d\n%s",vps_size, str);
free(str);
}
ptr += sps_size;
@@ -664,7 +695,7 @@ raop_rtp_mirror_thread(void *arg)
pps = ptr;
if (logger_debug) {
char *str = utils_data_to_string(pps, pps_size, 16);
- logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "h265 pps size %d\n%s",pps_size, str);
+ logger_log(raop_rtp_mirror->logger, LOGGER_INFO, "h265 pps size %d\n%s",pps_size, str);
free(str);
}
@@ -684,9 +715,21 @@ raop_rtp_mirror_thread(void *arg)
ptr += 4;
memcpy(ptr, pps, pps_size);
} else {
- codec = VIDEO_CODEC_H264;
- h265_video = false;
- raop_rtp_mirror->callbacks.video_set_codec(raop_rtp_mirror->callbacks.cls, codec);
+ if (codec == VIDEO_CODEC_UNKNOWN) {
+ codec = VIDEO_CODEC_H264;
+ h265_video = false;
+ if (raop_rtp_mirror->callbacks.video_set_codec(raop_rtp_mirror->callbacks.cls, codec) < 0) {
+ logger_log(raop_rtp_mirror->logger, LOGGER_ERR, "failed to set video codec as H264 ");
+ /* drop connection */
+ conn_reset = true;
+ break;
+ }
+ } else if (codec != VIDEO_CODEC_H264) {
+ logger_log(raop_rtp_mirror->logger, LOGGER_ERR, "invalid codec change to H264: codec was set previously");
+ /* drop connection */
+ conn_reset = true;
+ break;
+ }
short sps_size = byteutils_get_short_be(payload,6);
unsigned char *sequence_parameter_set = payload + 8;
short pps_size = byteutils_get_short_be(payload, sps_size + 9);
@@ -694,23 +737,23 @@ raop_rtp_mirror_thread(void *arg)
int data_size = 6;
if (logger_debug) {
char *str = utils_data_to_string(payload, data_size, 16);
- logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror: SPS+PPS header size = %d", data_size);
- logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror h264 SPS+PPS header:\n%s", str);
+ logger_log(raop_rtp_mirror->logger, LOGGER_INFO, "raop_rtp_mirror: SPS+PPS header size = %d", data_size);
+ logger_log(raop_rtp_mirror->logger, LOGGER_INFO, "raop_rtp_mirror h264 SPS+PPS header:\n%s", str);
free(str);
str = utils_data_to_string(sequence_parameter_set, sps_size,16);
- logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror SPS NAL size = %d", sps_size);
- logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror h264 Sequence Parameter Set:\n%s", str);
+ logger_log(raop_rtp_mirror->logger, LOGGER_INFO, "raop_rtp_mirror SPS NAL size = %d", sps_size);
+ logger_log(raop_rtp_mirror->logger, LOGGER_INFO, "raop_rtp_mirror h264 Sequence Parameter Set:\n%s", str);
free(str);
str = utils_data_to_string(picture_parameter_set, pps_size, 16);
- logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror PPS NAL size = %d", pps_size);
- logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror h264 Picture Parameter Set:\n%s", str);
+ logger_log(raop_rtp_mirror->logger, LOGGER_INFO, "raop_rtp_mirror PPS NAL size = %d", pps_size);
+ logger_log(raop_rtp_mirror->logger, LOGGER_INFO, "raop_rtp_mirror h264 Picture Parameter Set:\n%s", str);
free(str);
}
data_size = payload_size - sps_size - pps_size - 11;
if (data_size > 0 && logger_debug) {
char *str = utils_data_to_string (picture_parameter_set + pps_size, data_size, 16);
- logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "remainder size = %d", data_size);
- logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "remainder of SPS+PPS packet:\n%s", str);
+ logger_log(raop_rtp_mirror->logger, LOGGER_INFO, "remainder size = %d", data_size);
+ logger_log(raop_rtp_mirror->logger, LOGGER_INFO, "remainder of SPS+PPS packet:\n%s", str);
free(str);
} else if (data_size < 0) {
logger_log(raop_rtp_mirror->logger, LOGGER_ERR, " pps_sps error: packet remainder size = %d < 0", data_size);
@@ -804,9 +847,8 @@ raop_rtp_mirror_thread(void *arg)
MUTEX_UNLOCK(raop_rtp_mirror->run_mutex);
logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror exiting TCP thread");
- if (conn_reset && raop_rtp_mirror->callbacks.conn_reset) {
- const bool video_reset = false; /* leave "frozen video" showing */
- raop_rtp_mirror->callbacks.conn_reset(raop_rtp_mirror->callbacks.cls, 0, video_reset);
+ if (conn_reset&& raop_rtp_mirror->callbacks.conn_reset) {
+ raop_rtp_mirror->callbacks.conn_reset(raop_rtp_mirror->callbacks.cls, 1);
}
if (unsupported_codec) {
@@ -899,14 +941,14 @@ void raop_rtp_mirror_stop(raop_rtp_mirror_t *raop_rtp_mirror) {
raop_rtp_mirror->running = 0;
MUTEX_UNLOCK(raop_rtp_mirror->run_mutex);
+ /* Join the thread */
+ THREAD_JOIN(raop_rtp_mirror->thread_mirror);
+
if (raop_rtp_mirror->mirror_data_sock != -1) {
closesocket(raop_rtp_mirror->mirror_data_sock);
raop_rtp_mirror->mirror_data_sock = -1;
}
- /* Join the thread */
- THREAD_JOIN(raop_rtp_mirror->thread_mirror);
-
/* Mark thread as joined */
MUTEX_LOCK(raop_rtp_mirror->run_mutex);
raop_rtp_mirror->joined = 1;
diff --git a/lib/utils.c b/lib/utils.c
index 8f82186..ce2623e 100644
--- a/lib/utils.c
+++ b/lib/utils.c
@@ -186,14 +186,14 @@ char *utils_parse_hex(const char *str, int str_len, int *data_len) {
return data;
}
-char *utils_pk_to_string(const unsigned char *pk, int pk_len) {
- char *pk_str = (char *) malloc(2*pk_len + 1);
- char* pos = pk_str;
- for (int i = 0; i < pk_len; i++) {
- snprintf(pos, 3, "%2.2x", *(pk + i));
+char *utils_hex_to_string(const unsigned char *hex, int hex_len) {
+ char *hex_str = (char *) malloc(2*hex_len + 1);
+ char* pos = hex_str;
+ for (int i = 0; i < hex_len; i++) {
+ snprintf(pos, 3, "%2.2x", *(hex + i));
pos +=2;
}
- return pk_str;
+ return hex_str;
}
char *utils_data_to_string(const unsigned char *data, int datalen, int chars_per_line) {
@@ -283,6 +283,67 @@ int utils_ipaddress_to_string(int addresslen, const unsigned char *address, unsi
return ret;
}
+char *utils_strip_data_from_plist_xml(char *plist_xml) {
+ /* returns NULL if no data needs to be stripped out.
+ * returns pointer to newly-allocated stripped text char *xml
+ * WHICH (like plist_xml) MUST BE FREED AFTER USE*/
+ assert(plist_xml);
+ int len = (int) strlen(plist_xml);
+ char *last = plist_xml + len * sizeof(char); // position of null termination of plist_xml
+
+ char *eol;
+ char *eol_data;
+ char *xml = NULL;
+ int nchars;
+ char line[81];
+ int count;
+ char *begin = strstr(plist_xml, "");
+ char *end;
+ if (!begin) {
+ /* there are no data lines, nothing to do */
+ return NULL;
+ } else {
+ xml = (char *) calloc((len + 1), sizeof(char));
+ }
+ char *ptr1 = plist_xml;
+ char *ptr2 = xml;
+ do {
+ eol = strchr(begin,'\n');
+ nchars = eol + 1 - ptr1;
+ memcpy(ptr2, ptr1, nchars);
+ ptr2 += nchars;
+ ptr1 += nchars;
+ end = strstr(ptr1, "");
+ assert(end);
+ count = 0;
+ do {
+ eol_data = eol;
+ eol = strchr(eol + 1, '\n');
+ count++;
+ } while (eol < end);
+ count--; // last '\n' counted ends the first non-data line (contains "")
+ if (count > 1) {
+ snprintf(line, sizeof(line), " (%d lines data omitted, 64 chars/line)\n", count);
+ nchars = strlen(line);
+ memcpy(ptr2, line, nchars);
+ ptr2 += nchars;
+ ptr1 = eol_data + 1;
+ } else {
+ nchars = eol_data + 1 - ptr1;
+ memcpy(ptr2, ptr1, nchars);
+ ptr2 += nchars;
+ ptr1 += nchars;
+ }
+ begin = strstr(ptr1, "");
+ if (begin == NULL) {
+ nchars = (int) (last + 1 - ptr1);
+ memcpy(ptr2, ptr1, nchars); //includes the null terminator
+ break;
+ }
+ } while (ptr1 <= last);
+ return xml;
+}
+
const char *gmt_time_string() {
static char date_buf[64];
memset(date_buf, 0, 64);
diff --git a/lib/utils.h b/lib/utils.h
index 82df1f5..c55bb0e 100644
--- a/lib/utils.h
+++ b/lib/utils.h
@@ -25,7 +25,7 @@ int utils_read_file(char **dst, const char *pemstr);
int utils_hwaddr_raop(char *str, int strlen, const char *hwaddr, int hwaddrlen);
int utils_hwaddr_airplay(char *str, int strlen, const char *hwaddr, int hwaddrlen);
char *utils_parse_hex(const char *str, int str_len, int *data_len);
-char *utils_pk_to_string(const unsigned char *pk, int pk_len);
+char *utils_hex_to_string(const unsigned char *hex, int hex_len);
char *utils_data_to_string(const unsigned char *data, int datalen, int chars_per_line);
char *utils_data_to_text(const char *data, int datalen);
void ntp_timestamp_to_time(uint64_t ntp_timestamp, char *timestamp, size_t maxsize);
@@ -33,4 +33,5 @@ void ntp_timestamp_to_seconds(uint64_t ntp_timestamp, char *timestamp, size_t ma
const char *gmt_time_string();
int utils_ipaddress_to_string(int addresslen, const unsigned char *address,
unsigned int zone_id, char *string, int len);
+char *utils_strip_data_from_plist_xml(char * plist_xml);
#endif
diff --git a/renderers/CMakeLists.txt b/renderers/CMakeLists.txt
index 9c49df1..abf4bb3 100644
--- a/renderers/CMakeLists.txt
+++ b/renderers/CMakeLists.txt
@@ -1,4 +1,3 @@
-cmake_minimum_required(VERSION 3.5)
if (APPLE )
set( ENV{PKG_CONFIG_PATH} "/Library/FrameWorks/GStreamer.framework/Libraries/pkgconfig" ) # GStreamer.framework, preferred
diff --git a/renderers/video_renderer.c b/renderers/video_renderer.c
index bd7895c..c701c88 100644
--- a/renderers/video_renderer.c
+++ b/renderers/video_renderer.c
@@ -25,6 +25,7 @@
#include "video_renderer.h"
#define SECOND_IN_NSECS 1000000000UL
+#define SECOND_IN_MICROSECS 1000000
#ifdef X_DISPLAY_FIX
#include
#include "x_display_fix.h"
@@ -45,14 +46,39 @@ static bool use_x11 = false;
#endif
static bool logger_debug = false;
static bool video_terminate = false;
+static gint64 hls_requested_start_position = 0;
+static gint64 hls_seek_start = 0;
+static gint64 hls_seek_end = 0;
+static gint64 hls_duration;
+static gboolean hls_seek_enabled;
+static gboolean hls_playing;
+static gboolean hls_buffer_empty;
+static gboolean hls_buffer_full;
-#define NCODECS 2 /* renderers for h264 and h265 */
+
+typedef enum {
+ //GST_PLAY_FLAG_VIDEO = (1 << 0),
+ //GST_PLAY_FLAG_AUDIO = (1 << 1),
+ //GST_PLAY_FLAG_TEXT = (1 << 2),
+ //GST_PLAY_FLAG_VIS = (1 << 3),
+ //GST_PLAY_FLAG_SOFT_VOLUME = (1 << 4),
+ //GST_PLAY_FLAG_NATIVE_AUDIO = (1 << 5),
+ //GST_PLAY_FLAG_NATIVE_VIDEO = (1 << 6),
+ GST_PLAY_FLAG_DOWNLOAD = (1 << 7),
+ GST_PLAY_FLAG_BUFFERING = (1 << 8),
+ //GST_PLAY_FLAG_DEINTERLACE = (1 << 9),
+ //GST_PLAY_FLAG_SOFT_COLORBALANCE = (1 << 10),
+ //GST_PLAY_FLAG_FORCE_FILTERS = (1 << 11),
+ //GST_PLAY_FLAG_FORCE_SW_DECODERS = (1 << 12),
+} GstPlayFlags;
+
+#define NCODECS 3 /* renderers for h264,h265, and jpeg images */
struct video_renderer_s {
GstElement *appsrc, *pipeline;
GstBus *bus;
const char *codec;
- bool autovideo, state_pending;
+ bool autovideo;
int id;
gboolean terminate;
gint64 duration;
@@ -69,7 +95,8 @@ static video_renderer_t *renderer_type[NCODECS] = {0};
static int n_renderers = NCODECS;
static char h264[] = "h264";
static char h265[] = "h265";
-static char hls[] = "hls";
+static char hls[] = "hls";
+static char jpeg[] = "jpeg";
static void append_videoflip (GString *launch, const videoflip_t *flip, const videoflip_t *rot) {
/* videoflip image transform */
@@ -138,6 +165,7 @@ static void append_videoflip (GString *launch, const videoflip_t *flip, const vi
* closest used by GStreamer < 1.20.4 is BT709, 2:3:5:1 with * // now use sRGB = 1:1:7:1
* range = 2 -> GST_VIDEO_COLOR_RANGE_16_235 ("limited RGB") */
+static const char jpeg_caps[]="image/jpeg";
static const char h264_caps[]="video/x-h264,stream-format=(string)byte-stream,alignment=(string)au";
static const char h265_caps[]="video/x-h265,stream-format=(string)byte-stream,alignment=(string)au";
@@ -156,7 +184,7 @@ GstElement *make_video_sink(const char *videosink, const char *videosink_options
return NULL;
}
- /* process the video_sink_optons */
+ /* process the video_sink_options */
size_t len = strlen(videosink_options);
if (!len) {
return video_sink;
@@ -193,7 +221,7 @@ GstElement *make_video_sink(const char *videosink, const char *videosink_options
void video_renderer_init(logger_t *render_logger, const char *server_name, videoflip_t videoflip[2], const char *parser,
const char *decoder, const char *converter, const char *videosink, const char *videosink_options,
- bool initial_fullscreen, bool video_sync, bool h265_support, const char *uri) {
+ bool initial_fullscreen, bool video_sync, bool h265_support, guint playbin_version, const char *uri) {
GError *error = NULL;
GstCaps *caps = NULL;
hls_video = (uri != NULL);
@@ -203,6 +231,14 @@ void video_renderer_init(logger_t *render_logger, const char *server_name, vide
logger = render_logger;
logger_debug = (logger_get_level(logger) >= LOGGER_DEBUG);
video_terminate = false;
+ hls_seek_enabled = FALSE;
+ hls_playing = FALSE;
+ hls_seek_start = -1;
+ hls_seek_end = -1;
+ hls_duration = -1;
+ hls_buffer_empty = TRUE;
+ hls_buffer_empty = FALSE;
+
/* this call to g_set_application_name makes server_name appear in the X11 display window title bar, */
/* (instead of the program name uxplay taken from (argv[0]). It is only set one time. */
@@ -212,33 +248,45 @@ void video_renderer_init(logger_t *render_logger, const char *server_name, vide
appname = NULL;
/* the renderer for hls video will only be built if a HLS uri is provided in
- * the call to video_renderer_init, in which case the h264 and 265 mirror-mode
- * renderers will not be built. This is because it appears that we cannot
+ * the call to video_renderer_init, in which case the h264/h265 mirror-mode and jpeg
+ * audio-mode renderers will not be built. This is because it appears that we cannot
* put playbin into GST_STATE_READY before knowing the uri (?), so cannot use a
- * unified renderer structure with h264, h265 and hls */
+ * unified renderer structure with h264, h265, jpeg and hls */
if (hls_video) {
n_renderers = 1;
+ /* renderer[0]: playbin (hls) */
} else {
- n_renderers = h265_support ? 2 : 1;
+ n_renderers = h265_support ? 3 : 2;
+ /* renderer[0]: jpeg; [1]: h264; [2]: h265 */
}
g_assert (n_renderers <= NCODECS);
for (int i = 0; i < n_renderers; i++) {
- g_assert (i < 2);
+ g_assert (i < 3);
renderer_type[i] = (video_renderer_t *) calloc(1, sizeof(video_renderer_t));
g_assert(renderer_type[i]);
renderer_type[i]->autovideo = auto_videosink;
- renderer_type[i]->id = i;
- renderer_type[i]->bus = NULL;
+ renderer_type[i]->id = i;
+ renderer_type[i]->bus = NULL;
if (hls_video) {
- /* use playbin3 to play HLS video: replace "playbin3" by "playbin" to use playbin2 */
- renderer_type[i]->pipeline = gst_element_factory_make("playbin3", "hls-playbin3");
+ /* use playbin3 to play HLS video: replace "playbin3" by "playbin" to use playbin2 */
+ switch (playbin_version) {
+ case 2:
+ renderer_type[i]->pipeline = gst_element_factory_make("playbin", "hls-playbin2");
+ break;
+ case 3:
+ renderer_type[i]->pipeline = gst_element_factory_make("playbin3", "hls-playbin3");
+ break;
+ default:
+ logger_log(logger, LOGGER_ERR, "video_renderer_init: invalid playbin version %u", playbin_version);
+ g_assert(0);
+ }
+ logger_log(logger, LOGGER_INFO, "Will use GStreamer playbin version %u to play HLS streamed video", playbin_version);
g_assert(renderer_type[i]->pipeline);
renderer_type[i]->appsrc = NULL;
renderer_type[i]->codec = hls;
- /* if we are not using autovideosink, build a videossink based on the stricng "videosink" */
- if(strcmp(videosink, "autovideosink")) {
- GstElement *playbin_videosink = make_video_sink(videosink, videosink_options);
-
+ /* if we are not using an autovideosink, build a videosink based on the string "videosink" */
+ if (!auto_videosink) {
+ GstElement *playbin_videosink = make_video_sink(videosink, videosink_options);
if (!playbin_videosink) {
logger_log(logger, LOGGER_ERR, "video_renderer_init: failed to create playbin_videosink");
} else {
@@ -246,15 +294,25 @@ void video_renderer_init(logger_t *render_logger, const char *server_name, vide
g_object_set(G_OBJECT (renderer_type[i]->pipeline), "video-sink", playbin_videosink, NULL);
}
}
-
- g_object_set (G_OBJECT (renderer_type[i]->pipeline), "uri", uri, NULL);
+ gint flags;
+ g_object_get(renderer_type[i]->pipeline, "flags", &flags, NULL);
+ flags |= GST_PLAY_FLAG_DOWNLOAD;
+ flags |= GST_PLAY_FLAG_BUFFERING; // set by default in playbin3, but not in playbin2; is it needed?
+ g_object_set(renderer_type[i]->pipeline, "flags", flags, NULL);
+ g_object_set (G_OBJECT (renderer_type[i]->pipeline), "uri", uri, NULL);
} else {
+ bool jpeg_pipeline = false;
switch (i) {
case 0:
+ jpeg_pipeline = true;
+ renderer_type[i]->codec = jpeg;
+ caps = gst_caps_from_string(jpeg_caps);
+ break;
+ case 1:
renderer_type[i]->codec = h264;
caps = gst_caps_from_string(h264_caps);
break;
- case 1:
+ case 2:
renderer_type[i]->codec = h265;
caps = gst_caps_from_string(h265_caps);
break;
@@ -262,22 +320,29 @@ void video_renderer_init(logger_t *render_logger, const char *server_name, vide
g_assert(0);
}
GString *launch = g_string_new("appsrc name=video_source ! ");
- g_string_append(launch, "queue ! ");
- g_string_append(launch, parser);
- g_string_append(launch, " ! ");
- g_string_append(launch, decoder);
+ if (jpeg_pipeline) {
+ g_string_append(launch, "jpegdec ");
+ } else {
+ g_string_append(launch, "queue ! ");
+ g_string_append(launch, parser);
+ g_string_append(launch, " ! ");
+ g_string_append(launch, decoder);
+ }
g_string_append(launch, " ! ");
append_videoflip(launch, &videoflip[0], &videoflip[1]);
g_string_append(launch, converter);
g_string_append(launch, " ! ");
g_string_append(launch, "videoscale ! ");
+ if (jpeg_pipeline) {
+ g_string_append(launch, " imagefreeze allow-replace=TRUE ! ");
+ }
g_string_append(launch, videosink);
g_string_append(launch, " name=");
g_string_append(launch, videosink);
g_string_append(launch, "_");
g_string_append(launch, renderer_type[i]->codec);
g_string_append(launch, videosink_options);
- if (video_sync) {
+ if (video_sync && !jpeg_pipeline) {
g_string_append(launch, " sync=true");
sync = true;
} else {
@@ -302,7 +367,13 @@ void video_renderer_init(logger_t *render_logger, const char *server_name, vide
logger_log(logger, LOGGER_DEBUG, "GStreamer video pipeline %d:\n\"%s\"", i + 1, launch->str);
renderer_type[i]->pipeline = gst_parse_launch(launch->str, &error);
if (error) {
- g_error ("get_parse_launch error (video) :\n %s\n",error->message);
+ logger_log(logger, LOGGER_ERR, "GStreamer gst_parse_launch failed to create video pipeline %d\n"
+ "*** error message from gst_parse_launch was:\n%s\n"
+ "launch string parsed was \n[%s]", i + 1, error->message, launch->str);
+ if (strstr(error->message, "no element")) {
+ logger_log(logger, LOGGER_ERR, "This error usually means that a uxplay option was mistyped\n"
+ " or some requested part of GStreamer is not installed\n");
+ }
g_clear_error (&error);
}
g_assert (renderer_type[i]->pipeline);
@@ -312,7 +383,6 @@ void video_renderer_init(logger_t *render_logger, const char *server_name, vide
gst_pipeline_use_clock(GST_PIPELINE_CAST(renderer_type[i]->pipeline), clock);
renderer_type[i]->appsrc = gst_bin_get_by_name (GST_BIN (renderer_type[i]->pipeline), "video_source");
g_assert(renderer_type[i]->appsrc);
-
g_object_set(renderer_type[i]->appsrc, "caps", caps, "stream-type", 0, "is-live", TRUE, "format", GST_FORMAT_TIME, NULL);
g_string_free(launch, TRUE);
gst_caps_unref(caps);
@@ -325,13 +395,16 @@ void video_renderer_init(logger_t *render_logger, const char *server_name, vide
renderer_type[i]->gst_window = NULL;
renderer_type[i]->use_x11 = false;
X11_search_attempts = 0;
+ /* setting char *x11_display_name to NULL means the value is taken from $DISPLAY in the environment
+ * (a uxplay option to specify a different value is possible) */
+ char *x11_display_name = NULL;
if (use_x11) {
if (i == 0) {
renderer_type[0]->gst_window = (X11_Window_t *) calloc(1, sizeof(X11_Window_t));
g_assert(renderer_type[0]->gst_window);
- get_X11_Display(renderer_type[0]->gst_window);
+ get_X11_Display(renderer_type[0]->gst_window, x11_display_name);
if (renderer_type[0]->gst_window->display) {
- renderer_type[i]->use_x11 = true;
+ renderer_type[0]->use_x11 = true;
} else {
free(renderer_type[0]->gst_window);
renderer_type[0]->gst_window = NULL;
@@ -385,18 +458,23 @@ void video_renderer_resume() {
}
void video_renderer_start() {
+ GstState state;
+ const gchar *state_name;
if (hls_video) {
renderer->bus = gst_element_get_bus(renderer->pipeline);
- gst_element_set_state (renderer->pipeline, GST_STATE_PLAYING);
+ gst_element_set_state (renderer->pipeline, GST_STATE_PAUSED);
+ gst_element_get_state(renderer->pipeline, &state, NULL, 1000 * GST_MSECOND);
+ state_name= gst_element_state_get_name(state);
+ logger_log(logger, LOGGER_DEBUG, "video renderer_start: state %s", state_name);
return;
}
/* when not hls, start both h264 and h265 pipelines; will shut down the "wrong" one when we know the codec */
for (int i = 0; i < n_renderers; i++) {
- gst_element_set_state (renderer_type[i]->pipeline, GST_STATE_PLAYING);
- if (renderer_type[i]->appsrc) {
- gst_video_pipeline_base_time = gst_element_get_base_time(renderer_type[i]->appsrc);
- }
renderer_type[i]->bus = gst_element_get_bus(renderer_type[i]->pipeline);
+ gst_element_set_state (renderer_type[i]->pipeline, GST_STATE_PAUSED);
+ gst_element_get_state(renderer_type[i]->pipeline, &state, NULL, 1000 * GST_MSECOND);
+ state_name= gst_element_state_get_name(state);
+ logger_log(logger, LOGGER_DEBUG, "video renderer_start: renderer %d state %s", i, state_name);
}
renderer = NULL;
first_packet = true;
@@ -418,11 +496,24 @@ bool waiting_for_x11_window() {
return true; /* window still not found */
}
}
+ if (fullscreen) {
+ set_fullscreen(renderer->gst_window, &fullscreen);
+ }
#endif
return false;
}
-void video_renderer_render_buffer(unsigned char* data, int *data_len, int *nal_count, uint64_t *ntp_time) {
+void video_renderer_display_jpeg(const void *data, int *data_len) {
+ GstBuffer *buffer;
+ if (renderer && !strcmp(renderer->codec, jpeg)) {
+ buffer = gst_buffer_new_allocate(NULL, *data_len, NULL);
+ g_assert(buffer != NULL);
+ gst_buffer_fill(buffer, 0, data, *data_len);
+ gst_app_src_push_buffer (GST_APP_SRC(renderer->appsrc), buffer);
+ }
+}
+
+uint64_t video_renderer_render_buffer(unsigned char* data, int *data_len, int *nal_count, uint64_t *ntp_time) {
GstBuffer *buffer;
GstClockTime pts = (GstClockTime) *ntp_time; /*now in nsecs */
//GstClockTimeDiff latency = GST_CLOCK_DIFF(gst_element_get_current_clock_time (renderer->appsrc), pts);
@@ -430,9 +521,10 @@ void video_renderer_render_buffer(unsigned char* data, int *data_len, int *nal_c
if (pts >= gst_video_pipeline_base_time) {
pts -= gst_video_pipeline_base_time;
} else {
- logger_log(logger, LOGGER_ERR, "*** invalid ntp_time < gst_video_pipeline_base_time\n%8.6f ntp_time\n%8.6f base_time",
+ // adjust timestamps to be >= gst_video_pipeline_base time
+ logger_log(logger, LOGGER_DEBUG, "*** invalid ntp_time < gst_video_pipeline_base_time\n%8.6f ntp_time\n%8.6f base_time",
((double) *ntp_time) / SECOND_IN_NSECS, ((double) gst_video_pipeline_base_time) / SECOND_IN_NSECS);
- return;
+ return (uint64_t) gst_video_pipeline_base_time - pts;
}
}
g_assert(data_len != 0);
@@ -469,6 +561,7 @@ void video_renderer_render_buffer(unsigned char* data, int *data_len, int *nal_c
}
#endif
}
+ return 0;
}
void video_renderer_flush() {
@@ -476,6 +569,7 @@ void video_renderer_flush() {
void video_renderer_stop() {
if (renderer) {
+ logger_log(logger, LOGGER_DEBUG,"video_renderer_stop");
if (renderer->appsrc) {
gst_app_src_end_of_stream (GST_APP_SRC(renderer->appsrc));
}
@@ -484,15 +578,21 @@ void video_renderer_stop() {
}
}
-static void video_renderer_destroy_h26x(video_renderer_t *renderer) {
+static void video_renderer_destroy_instance(video_renderer_t *renderer) {
if (renderer) {
+ logger_log(logger, LOGGER_DEBUG,"destroying renderer instance %p", renderer);
GstState state;
+ GstStateChangeReturn ret;
gst_element_get_state(renderer->pipeline, &state, NULL, 100 * GST_MSECOND);
+ logger_log(logger, LOGGER_DEBUG,"pipeline state is %s", gst_element_state_get_name(state));
if (state != GST_STATE_NULL) {
if (!hls_video) {
gst_app_src_end_of_stream (GST_APP_SRC(renderer->appsrc));
}
- gst_element_set_state (renderer->pipeline, GST_STATE_NULL);
+ ret = gst_element_set_state (renderer->pipeline, GST_STATE_NULL);
+ logger_log(logger, LOGGER_DEBUG,"pipeline_state_change_return: %s",
+ gst_element_state_change_return_get_name(ret));
+ gst_element_get_state(renderer->pipeline, NULL, NULL, 1000 * GST_MSECOND);
}
gst_object_unref(renderer->bus);
if (renderer->appsrc) {
@@ -513,53 +613,139 @@ static void video_renderer_destroy_h26x(video_renderer_t *renderer) {
void video_renderer_destroy() {
for (int i = 0; i < n_renderers; i++) {
if (renderer_type[i]) {
- video_renderer_destroy_h26x(renderer_type[i]);
+ video_renderer_destroy_instance(renderer_type[i]);
}
- }
+ }
}
+static void get_stream_status_name(GstStreamStatusType type, char *name, size_t len) {
+ switch (type) {
+ case GST_STREAM_STATUS_TYPE_CREATE:
+ strncpy(name, "CREATE", len);
+ return;
+ case GST_STREAM_STATUS_TYPE_ENTER:
+ strncpy(name, "ENTER", len);
+ return;
+ case GST_STREAM_STATUS_TYPE_LEAVE:
+ strncpy(name, "LEAVE", len);
+ return;
+ case GST_STREAM_STATUS_TYPE_DESTROY:
+ strncpy(name, "DESTROY", len);
+ return;
+ case GST_STREAM_STATUS_TYPE_START:
+ strncpy(name, "START", len);
+ return;
+ case GST_STREAM_STATUS_TYPE_PAUSE:
+ strncpy(name, "PAUSE", len);
+ return;
+ case GST_STREAM_STATUS_TYPE_STOP:
+ strncpy(name, "STOP", len);
+ return;
+ default:
+ strncpy(name, "", len);
+ return;
+ }
+}
+
gboolean gstreamer_pipeline_bus_callback(GstBus *bus, GstMessage *message, void *loop) {
+ GstState old_state, new_state;
+ const gchar no_state[] = "";
+ const gchar *old_state_name = no_state, *new_state_name = no_state;
+ if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_STATE_CHANGED) {
+ GstState old_state, new_state;
+ gst_message_parse_state_changed (message, &old_state, &new_state, NULL);
+ old_state_name = gst_element_state_get_name (old_state);
+ new_state_name = gst_element_state_get_name (new_state);
+ }
- /* identify which pipeline sent the message */
+ /* identify which pipeline sent the message */
int type = -1;
for (int i = 0 ; i < n_renderers ; i ++ ) {
- if (renderer_type[i]->bus == bus) {
+ if (renderer_type[i] && renderer_type[i]->bus == bus) {
type = i;
break;
}
}
- g_assert(type != -1);
- if (logger_debug) {
- g_print("GStreamer %s bus message: %s %s\n", renderer_type[type]->codec, GST_MESSAGE_SRC_NAME(message), GST_MESSAGE_TYPE_NAME(message));
+ /* if the bus sending the message is not found, the renderer may already have been destroyed */
+ if (type == -1) {
+ if (logger_debug) {
+ g_print("GStreamer(UNKNOWN, now destroyed?) bus message: %s %s %s %s\n",
+ GST_MESSAGE_SRC_NAME(message), GST_MESSAGE_TYPE_NAME(message), old_state_name, new_state_name);
+ }
+ return TRUE;
}
- if (logger_debug && hls_video) {
- gint64 pos;
- gst_element_query_position (renderer_type[type]->pipeline, GST_FORMAT_TIME, &pos);
+ if (logger_debug) {
+ gchar *name = NULL;
+ GstElement *element = NULL;
+ gchar type_name[8] = { 0 };
+ if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_STREAM_STATUS) {
+ GstStreamStatusType type;
+ gst_message_parse_stream_status(message, &type, &element);
+ name = gst_element_get_name(element);
+ get_stream_status_name(type, type_name, 8);
+ old_state_name = name;
+ new_state_name = type_name;
+ }
+ gint64 pos = -1;
+ if (hls_video) {
+ gst_element_query_position (renderer_type[type]->pipeline, GST_FORMAT_TIME, &pos);
+ }
if (GST_CLOCK_TIME_IS_VALID(pos)) {
- g_print("GStreamer bus message %s %s; position: %" GST_TIME_FORMAT "\n", GST_MESSAGE_SRC_NAME(message),
- GST_MESSAGE_TYPE_NAME(message), GST_TIME_ARGS(pos));
+ g_print("GStreamer %s bus message %s %s %s %s; position: %" GST_TIME_FORMAT "\n" ,renderer_type[type]->codec,
+ GST_MESSAGE_SRC_NAME(message), GST_MESSAGE_TYPE_NAME(message), old_state_name, new_state_name, GST_TIME_ARGS(pos));
} else {
- g_print("GStreamer bus message %s %s; position: none\n", GST_MESSAGE_SRC_NAME(message),
- GST_MESSAGE_TYPE_NAME(message));
+ g_print("GStreamer %s bus message %s %s %s %s\n", renderer_type[type]->codec,
+ GST_MESSAGE_SRC_NAME(message), GST_MESSAGE_TYPE_NAME(message), old_state_name, new_state_name);
+ }
+ if (name) {
+ g_free(name);
+ }
+ }
+
+ /* monitor hls video position until seek to hls_start_position is achieved */
+ if (hls_video && hls_requested_start_position) {
+ if (strstr(GST_MESSAGE_SRC_NAME(message), "sink")) {
+ gint64 pos;
+ if (!GST_CLOCK_TIME_IS_VALID(hls_duration)) {
+ gst_element_query_duration (renderer->pipeline, GST_FORMAT_TIME, &hls_duration);
+ }
+ gst_element_query_position (renderer_type[type]->pipeline, GST_FORMAT_TIME, &pos);
+ //g_print("HLS position %" GST_TIME_FORMAT " requested_start_position %" GST_TIME_FORMAT " duration %" GST_TIME_FORMAT " %s\n",
+ // GST_TIME_ARGS(pos), GST_TIME_ARGS(hls_requested_start_position), GST_TIME_ARGS(hls_duration),
+ // (hls_seek_enabled ? "seek enabled" : "seek not enabled"));
+ if (pos > hls_requested_start_position) {
+ hls_requested_start_position = 0;
+ }
+ if ( hls_requested_start_position && pos < hls_requested_start_position && hls_seek_enabled) {
+ g_print("***************** seek to hls_requested_start_position %" GST_TIME_FORMAT "\n", GST_TIME_ARGS(hls_requested_start_position));
+ if (gst_element_seek_simple (renderer_type[type]->pipeline, GST_FORMAT_TIME,
+ GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT, hls_requested_start_position)) {
+ hls_requested_start_position = 0;
+ }
+ }
}
}
switch (GST_MESSAGE_TYPE (message)) {
case GST_MESSAGE_DURATION:
- renderer_type[type]->duration = GST_CLOCK_TIME_NONE;
+ hls_duration = GST_CLOCK_TIME_NONE;
break;
case GST_MESSAGE_BUFFERING:
if (hls_video) {
gint percent = -1;
gst_message_parse_buffering(message, &percent);
- if (percent >= 0) {
+ hls_buffer_empty = TRUE;
+ hls_buffer_full = FALSE;
+ if (percent > 0) {
+ hls_buffer_empty = FALSE;
renderer_type[type]->buffering_level = percent;
- logger_log(logger, LOGGER_DEBUG, "Buffering :%u percent done", percent);
+ logger_log(logger, LOGGER_DEBUG, "Buffering :%d percent done", percent);
if (percent < 100) {
gst_element_set_state (renderer_type[type]->pipeline, GST_STATE_PAUSED);
} else {
+ hls_buffer_full = TRUE;
gst_element_set_state (renderer_type[type]->pipeline, GST_STATE_PLAYING);
}
}
@@ -603,14 +789,31 @@ gboolean gstreamer_pipeline_bus_callback(GstBus *bus, GstMessage *message, void
}
break;
case GST_MESSAGE_STATE_CHANGED:
- if (renderer_type[type]->state_pending && strstr(GST_MESSAGE_SRC_NAME(message), "pipeline")) {
- GstState state;
- gst_element_get_state(renderer_type[type]->pipeline, &state, NULL, 100 * GST_MSECOND);
- if (state == GST_STATE_NULL) {
- gst_element_set_state(renderer_type[type]->pipeline, GST_STATE_PLAYING);
- } else if (state == GST_STATE_PLAYING) {
- renderer_type[type]->state_pending = false;
+ if (hls_video && logger_debug && strstr(GST_MESSAGE_SRC_NAME(message), "hls-playbin")) {
+ GstState old_state, new_state;
+ gst_message_parse_state_changed (message, &old_state, &new_state, NULL);
+ g_print ("****** hls_playbin: Element %s changed state from %s to %s.\n", GST_OBJECT_NAME (message->src),
+ gst_element_state_get_name (old_state),
+ gst_element_state_get_name (new_state));
+ if (new_state != GST_STATE_PLAYING) {
+ break;
+ hls_playing = FALSE;
}
+ hls_playing = TRUE;
+ GstQuery *query;
+ query = gst_query_new_seeking(GST_FORMAT_TIME);
+ if (gst_element_query(renderer->pipeline, query)) {
+ gst_query_parse_seeking (query, NULL, &hls_seek_enabled, &hls_seek_start, &hls_seek_end);
+ if (hls_seek_enabled) {
+ g_print ("Seeking is ENABLED from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT "\n",
+ GST_TIME_ARGS (hls_seek_start), GST_TIME_ARGS (hls_seek_end));
+ } else {
+ g_print ("Seeking is DISABLED for this stream.\n");
+ }
+ } else {
+ g_printerr ("Seeking query failed.");
+ }
+ gst_query_unref (query);
}
if (renderer_type[type]->autovideo) {
char *sink = strstr(GST_MESSAGE_SRC_NAME(message), "-actual-sink-");
@@ -672,27 +875,52 @@ gboolean gstreamer_pipeline_bus_callback(GstBus *bus, GstMessage *message, void
return TRUE;
}
-void video_renderer_choose_codec (bool video_is_h265) {
+int video_renderer_choose_codec (bool video_is_jpeg, bool video_is_h265) {
+ video_renderer_t *renderer_used = NULL;
g_assert(!hls_video);
- /* set renderer to h264 or h265, depending on pps/sps received by raop_rtp_mirror */
- video_renderer_t *renderer_new = video_is_h265 ? renderer_type[1] : renderer_type[0];
- if (renderer == renderer_new) {
- return;
+ if (video_is_jpeg) {
+ renderer_used = renderer_type[0];
+ } else if (n_renderers == 2) {
+ if (video_is_h265) {
+ logger_log(logger, LOGGER_ERR, "video is h265 but the -h265 option was not used");
+ return -1;
+ }
+ renderer_used = renderer_type[1];
+ } else {
+ renderer_used = video_is_h265 ? renderer_type[2] : renderer_type[1];
}
- video_renderer_t *renderer_prev = renderer;
- renderer = renderer_new;
+ if (renderer_used == NULL) {
+ return -1;
+ } else if (renderer_used == renderer) {
+ return 0;
+ } else if (renderer) {
+ return -1;
+ }
+ renderer = renderer_used;
+ gst_element_set_state (renderer->pipeline, GST_STATE_PLAYING);
+ GstState old_state, new_state;
+ if (gst_element_get_state(renderer->pipeline, &old_state, &new_state, 100 * GST_MSECOND) == GST_STATE_CHANGE_FAILURE) {
+ g_error("video pipeline failed to go into playing state");
+ return -1;
+ }
+ logger_log(logger, LOGGER_DEBUG, "video_pipeline state change from %s to %s\n",
+ gst_element_state_get_name (old_state),gst_element_state_get_name (new_state));
gst_video_pipeline_base_time = gst_element_get_base_time(renderer->appsrc);
- /* it seems unlikely that the codec will change between h264 and h265 during a connection,
- * but in case it does, we set the previous renderer to GST_STATE_NULL, detect
- * when this is finished by listening for the bus message, and then reset it to
- * GST_STATE_READY, so it can be reused if the codec changes again. */
- if (renderer_prev) {
- gst_app_src_end_of_stream (GST_APP_SRC(renderer_prev->appsrc));
- gst_bus_set_flushing(renderer_prev->bus, TRUE);
- /* set state of previous renderer to GST_STATE_NULL to (hopefully?) close its video window */
- gst_element_set_state (renderer_prev->pipeline, GST_STATE_NULL);
- renderer_prev->state_pending = true; // will set state to PLAYING once state is NULL
+ if (n_renderers > 2 && renderer == renderer_type[2]) {
+ logger_log(logger, LOGGER_INFO, "*** video format is h265 high definition (HD/4K) video %dx%d", width, height);
}
+ /* destroy unused renderers */
+ for (int i = 1; i < n_renderers; i++) {
+ if (renderer_type[i] == renderer) {
+ continue;
+ }
+ if (renderer_type[i]) {
+ video_renderer_t *renderer_unused = renderer_type[i];
+ renderer_type[i] = NULL;
+ video_renderer_destroy_instance(renderer_unused);
+ }
+ }
+ return 0;
}
unsigned int video_reset_callback(void * loop) {
@@ -709,16 +937,18 @@ unsigned int video_reset_callback(void * loop) {
return (unsigned int) TRUE;
}
-bool video_get_playback_info(double *duration, double *position, float *rate) {
+bool video_get_playback_info(double *duration, double *position, float *rate, bool *buffer_empty, bool *buffer_full) {
gint64 pos = 0;
GstState state;
*duration = 0.0;
*position = -1.0;
*rate = 0.0f;
if (!renderer) {
-
return true;
}
+
+ *buffer_empty = (bool) hls_buffer_empty;
+ *buffer_full = (bool) hls_buffer_full;
gst_element_get_state(renderer->pipeline, &state, NULL, 0);
*rate = 0.0f;
switch (state) {
@@ -728,12 +958,12 @@ bool video_get_playback_info(double *duration, double *position, float *rate) {
break;
}
- if (!GST_CLOCK_TIME_IS_VALID(renderer->duration)) {
- if (!gst_element_query_duration (renderer->pipeline, GST_FORMAT_TIME, &renderer->duration)) {
+ if (!GST_CLOCK_TIME_IS_VALID(hls_duration)) {
+ if (!gst_element_query_duration (renderer->pipeline, GST_FORMAT_TIME, &hls_duration)) {
return true;
}
}
- *duration = ((double) renderer->duration) / GST_SECOND;
+ *duration = ((double) hls_duration) / GST_SECOND;
if (*duration) {
if (gst_element_query_position (renderer->pipeline, GST_FORMAT_TIME, &pos) &&
GST_CLOCK_TIME_IS_VALID(pos)) {
@@ -742,19 +972,27 @@ bool video_get_playback_info(double *duration, double *position, float *rate) {
}
logger_log(logger, LOGGER_DEBUG, "********* video_get_playback_info: position %" GST_TIME_FORMAT " duration %" GST_TIME_FORMAT " %s *********",
- GST_TIME_ARGS (pos), GST_TIME_ARGS (renderer->duration), gst_element_state_get_name(state));
+ GST_TIME_ARGS (pos), GST_TIME_ARGS (hls_duration), gst_element_state_get_name(state));
return true;
}
+void video_renderer_set_start(float position) {
+ int pos_in_micros = (int) (position * SECOND_IN_MICROSECS);
+ hls_requested_start_position = (gint64) (pos_in_micros * GST_USECOND);
+ logger_log(logger, LOGGER_DEBUG, "register HLS video start position %f %lld", position,
+ hls_requested_start_position);
+}
+
void video_renderer_seek(float position) {
- double pos = (double) position;
- pos *= GST_SECOND;
- gint64 seek_position = (gint64) pos;
+ int pos_in_micros = (int) (position * SECOND_IN_MICROSECS);
+ gint64 seek_position = (gint64) (pos_in_micros * GST_USECOND);
+ /* don't seek to within 1 microsecond of beginning or end of video */
+ if (hls_duration < 2000) return;
seek_position = seek_position < 1000 ? 1000 : seek_position;
- seek_position = seek_position > renderer->duration - 1000 ? renderer->duration - 1000: seek_position;
+ seek_position = seek_position > hls_duration - 1000 ? hls_duration - 1000 : seek_position;
g_print("SCRUB: seek to %f secs = %" GST_TIME_FORMAT ", duration = %" GST_TIME_FORMAT "\n", position,
- GST_TIME_ARGS(seek_position), GST_TIME_ARGS(renderer->duration));
+ GST_TIME_ARGS(seek_position), GST_TIME_ARGS(hls_duration));
gboolean result = gst_element_seek_simple(renderer->pipeline, GST_FORMAT_TIME,
(GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
seek_position);
diff --git a/renderers/video_renderer.h b/renderers/video_renderer.h
index 4db432a..9c307e8 100644
--- a/renderers/video_renderer.h
+++ b/renderers/video_renderer.h
@@ -49,21 +49,23 @@ typedef struct video_renderer_s video_renderer_t;
void video_renderer_init (logger_t *logger, const char *server_name, videoflip_t videoflip[2], const char *parser,
const char *decoder, const char *converter, const char *videosink, const char *videosink_options,
- bool initial_fullscreen, bool video_sync, bool h265_support, const char *uri);
+ bool initial_fullscreen, bool video_sync, bool h265_support, guint playbin_version, const char *uri);
void video_renderer_start ();
void video_renderer_stop ();
void video_renderer_pause ();
void video_renderer_seek(float position);
+void video_renderer_set_start(float position);
void video_renderer_resume ();
bool video_renderer_is_paused();
-void video_renderer_render_buffer (unsigned char* data, int *data_len, int *nal_count, uint64_t *ntp_time);
+uint64_t video_renderer_render_buffer (unsigned char* data, int *data_len, int *nal_count, uint64_t *ntp_time);
+void video_renderer_display_jpeg(const void *data, int *data_len);
void video_renderer_flush ();
unsigned int video_renderer_listen(void *loop, int id);
void video_renderer_destroy ();
void video_renderer_size(float *width_source, float *height_source, float *width, float *height);
bool waiting_for_x11_window();
-bool video_get_playback_info(double *duration, double *position, float *rate);
-void video_renderer_choose_codec(bool is_h265);
+bool video_get_playback_info(double *duration, double *position, float *rate, bool *buffer_empty, bool *buffer_full);
+int video_renderer_choose_codec (bool video_is_jpeg, bool video_is_h265);
unsigned int video_renderer_listen(void *loop, int id);
unsigned int video_reset_callback(void *loop);
#ifdef __cplusplus
diff --git a/renderers/x_display_fix.h b/renderers/x_display_fix.h
index 90d5180..ef7d0e1 100644
--- a/renderers/x_display_fix.h
+++ b/renderers/x_display_fix.h
@@ -43,8 +43,8 @@ struct X11_Window_s {
Window window;
} typedef X11_Window_t;
-static void get_X11_Display(X11_Window_t * X11) {
- X11->display = XOpenDisplay(NULL);
+static void get_X11_Display(X11_Window_t * X11, char *display_name) {
+ X11->display = XOpenDisplay(display_name);
X11->window = (Window) NULL;
}
diff --git a/uxplay.1 b/uxplay.1
index ee8d3f6..3cda48d 100644
--- a/uxplay.1
+++ b/uxplay.1
@@ -1,11 +1,11 @@
-.TH UXPLAY "1" "December 2024" "1.71" "User Commands"
+.TH UXPLAY "1" "May 2025" "1.72" "User Commands"
.SH NAME
uxplay \- start AirPlay server
.SH SYNOPSIS
.B uxplay
[\fI\,-n name\/\fR] [\fI\,-s wxh\/\fR] [\fI\,-p \/\fR[\fI\,n\/\fR]] [more \fI OPTIONS \/\fR ...]
.SH DESCRIPTION
-UxPlay 1.71: An open\-source AirPlay mirroring (+ audio streaming) server:
+UxPlay 1.72: An open\-source AirPlay mirroring (+ audio streaming) server:
.SH OPTIONS
.TP
.B
@@ -16,6 +16,8 @@ UxPlay 1.71: An open\-source AirPlay mirroring (+ audio streaming) server:
\fB\-h265\fR Support h265 (4K) video (with h265 versions of h264 plugins)
.TP
\fB\-hls\fR Support HTTP Live Streaming (currently YouTube video only)
+.IP
+ v = 2 or 3 (default 3) optionally selects video player version
.TP
\fB\-pin\fI[xxxx]\fRUse a 4-digit pin code to control client access (default: no)
.IP
@@ -25,6 +27,13 @@ UxPlay 1.71: An open\-source AirPlay mirroring (+ audio streaming) server:
.IP
client pin-registration; (option: use file "fn" for this)
.TP
+\fB\-pw\fI [pwd]\fR Require use of password "pwd" to control client access.
+.IP
+ (with no \fIpwd\fR, pin entry is required at \fIeach\fR connection.)
+
+.IP
+ (option "-pw" after "-pin" overrides it, and vice versa.)
+.TP
\fB\-vsync\fI[x]\fR Mirror mode: sync audio to video using timestamps (default)
.IP
\fIx\fR is optional audio delay: millisecs, decimal, can be neg.
@@ -42,6 +51,8 @@ UxPlay 1.71: An open\-source AirPlay mirroring (+ audio streaming) server:
.TP
\fB\-taper\fR Use a "tapered" AirPlay volume-control profile.
.TP
+\fB\-vol\fI v \fR Set initial audio-streaming volume: range [mute=0.0:1.0=full].
+.TP
\fB\-s\fR wxh[@r]Request to client for video display resolution [refresh_rate]
.IP
default 1920x1080[@60] (or 3840x2160[@60] with -h265 option).
@@ -49,7 +60,7 @@ UxPlay 1.71: An open\-source AirPlay mirroring (+ audio streaming) server:
.TP
\fB\-o\fR Set display "overscanned" mode on (not usually needed)
.TP
-\fB-fs\fR Full-screen (only works with X11, Wayland, VAAPI, D3D11)
+\fB-fs\fR Full-screen (only with X11, Wayland, VAAPI, D3D11, kms)
.TP
\fB\-p\fR Use legacy ports UDP 6000:6001:7011 TCP 7000:7001:7100
.TP
@@ -104,13 +115,19 @@ UxPlay 1.71: An open\-source AirPlay mirroring (+ audio streaming) server:
.TP
\fB\-al\fR x Audio latency in seconds (default 0.25) reported to client.
.TP
+\fB\-ca\fR Display cover-art in AirPlay Audio (ALAC) mode.
+.TP
\fB\-ca\fI fn \fR In Airplay Audio (ALAC) mode, write cover-art to file fn.
.TP
-\fB\-reset\fR n Reset after 3n seconds client silence (default 5, 0=never).
+\fB\-md\fI fn \fR In Airplay Audio (ALAC) mode, write metadata text to file fn.
+.TP
+\fB\-reset\fR n Reset after n seconds client silence (default n=15, 0=never).
.TP
\fB\-nofreeze\fR Do NOT leave frozen screen in place after reset.
.TP
-\fB\-nc\fR Do NOT close video window when client stops mirroring
+\fB\-nc\fR Do NOT close video window when client stops mirroring.
+.TP
+\fB\-nc\fR no Cancel the -nc option (DO close video window).
.TP
\fB\-nohold\fR Drop current connection when new client connects.
.TP
@@ -163,11 +180,13 @@ UxPlay 1.71: An open\-source AirPlay mirroring (+ audio streaming) server:
audio packets are dumped. "aud"= unknown format.
.PP
.TP
-\fB\-d\fR Enable debug logging
+\fB\-d [n]\fR Enable debug logging; optional: n=1 to skip normal packet data.
.TP
\fB\-v\fR Displays version information
.TP
\fB\-h\fR Displays help information
+.TP
+\fB\-rc\fI fn\fR Read startup options from file "fn" instead of ~/.uxplayrc, etc
.SH
FILES
Options in one of $UXPLAYRC, or ~/.uxplayrc, or ~/.config/uxplayrc
diff --git a/uxplay.cpp b/uxplay.cpp
index b96053d..48f3a3b 100644
--- a/uxplay.cpp
+++ b/uxplay.cpp
@@ -52,6 +52,9 @@
# include
# else
# include
+# ifdef __OpenBSD__
+# include
+# endif
# endif
#endif
@@ -62,7 +65,7 @@
#include "renderers/video_renderer.h"
#include "renderers/audio_renderer.h"
-#define VERSION "1.71"
+#define VERSION "1.72"
#define SECOND_IN_USECS 1000000
#define SECOND_IN_NSECS 1000000000UL
@@ -70,7 +73,9 @@
#define DEFAULT_DEBUG_LOG false
#define LOWEST_ALLOWED_PORT 1024
#define HIGHEST_PORT 65535
-#define NTP_TIMEOUT_LIMIT 5
+#define MISSED_FEEDBACK_LIMIT 15
+#define MIN_PASSWORD_LENGTH 4
+#define DEFAULT_PLAYBIN_VERSION 3
#define BT709_FIX "capssetter caps=\"video/x-h264, colorimetry=bt709\""
#define SRGB_FIX " ! video/x-raw,colorimetry=sRGB,format=RGB ! "
#ifdef FULL_RANGE_RGB_FIX
@@ -98,13 +103,16 @@ static unsigned char compression_type = 0;
static std::string audiosink = "autoaudiosink";
static int audiodelay = -1;
static bool use_audio = true;
+#if __APPLE__
+static bool new_window_closing_behavior = false;
+#else
static bool new_window_closing_behavior = true;
+#endif
static bool close_window;
static std::string video_parser = "h264parse";
static std::string video_decoder = "decodebin";
static std::string video_converter = "videoconvert";
static bool show_client_FPS_data = false;
-static unsigned int max_ntp_timeouts = NTP_TIMEOUT_LIMIT;
static FILE *video_dumpfile = NULL;
static std::string video_dumpfile_name = "videodump";
static int video_dump_limit = 0;
@@ -121,11 +129,14 @@ static bool dump_audio = false;
static unsigned char audio_type = 0x00;
static unsigned char previous_audio_type = 0x00;
static bool fullscreen = false;
+static bool render_coverart = false;
static std::string coverart_filename = "";
+static std::string metadata_filename = "";
static bool do_append_hostname = true;
static bool use_random_hw_addr = false;
static unsigned short display[5] = {0}, tcp[3] = {0}, udp[3] = {0};
static bool debug_log = DEFAULT_DEBUG_LOG;
+static bool suppress_packet_debug_data = false;
static int log_level = LOGGER_INFO;
static bool bt709_fix = false;
static bool srgb_fix = DEFAULT_SRGB_FIX;
@@ -138,7 +149,9 @@ static std::vector allowed_clients;
static std::vector blocked_clients;
static bool restrict_clients;
static bool setup_legacy_pairing = false;
-static bool require_password = false;
+static unsigned char pin_pw = 0; /* 0: no client access control; 1: onscreen pin ; 2: require password (same password for all clients) 3: random pw*/
+static std::string password = "";
+static guint min_password_length = MIN_PASSWORD_LENGTH;
static unsigned short pin = 0;
static std::string keyfile = "";
static std::string mac_address = "";
@@ -149,6 +162,7 @@ static std::vector registered_keys;
static double db_low = -30.0;
static double db_high = 0.0;
static bool taper_volume = false;
+static double initial_volume = 0.0;
static bool h265_support = false;
static int n_renderers = 0;
static bool hls_support = false;
@@ -156,7 +170,10 @@ static std::string url = "";
static guint gst_x11_window_id = 0;
static guint gst_hls_position_id = 0;
static bool preserve_connections = false;
-
+static guint missed_feedback_limit = MISSED_FEEDBACK_LIMIT;
+static guint missed_feedback = 0;
+static guint playbin_version = DEFAULT_PLAYBIN_VERSION;
+static bool reset_httpd = false;
/* logging */
static void log(int level, const char* format, ...) {
@@ -225,6 +242,13 @@ static size_t write_coverart(const char *filename, const void *image, size_t len
return count;
}
+static size_t write_metadata(const char *filename, const char *text) {
+ FILE *fp = fopen(filename, "wb");
+ size_t count = fwrite(text, sizeof(char), strlen(text) + 1, fp);
+ fclose(fp);
+ return count;
+}
+
static char *create_pin_display(char *pin_str, int margin, int gap) {
char *ptr;
char num[2] = { 0 };
@@ -365,6 +389,30 @@ static void dump_video_to_file(unsigned char *data, int datalen) {
}
}
+static gboolean feedback_callback(gpointer loop) {
+ if (open_connections) {
+ if (missed_feedback_limit && missed_feedback > missed_feedback_limit) {
+ LOGI("***ERROR lost connection with client (network problem?)");
+ LOGI("%u missed client feedback signals exceeds limit of %u", missed_feedback, missed_feedback_limit);
+ LOGI(" Sometimes the network connection may recover after a longer delay:\n"
+ " the default limit n = %d seconds, can be changed with the \"-reset n\" option", MISSED_FEEDBACK_LIMIT);
+ if (!nofreeze) {
+ close_window = false; /* leave "frozen" window open if reset_video is false */
+ }
+ reset_httpd = true;
+ relaunch_video = true;
+ g_main_loop_quit((GMainLoop *) loop);
+ return TRUE;
+ } else if (missed_feedback > 2) {
+ LOGE("%u missed client feedback signals (expected once per second); client may be offline", missed_feedback);
+ }
+ missed_feedback++;
+ } else {
+ missed_feedback = 0;
+ }
+ return TRUE;
+}
+
static gboolean reset_callback(gpointer loop) {
if (reset_loop) {
g_main_loop_quit((GMainLoop *) loop);
@@ -420,6 +468,9 @@ static void main_loop() {
g_assert(n_renderers <= 2);
GMainLoop *loop = g_main_loop_new(NULL,FALSE);
relaunch_video = false;
+ reset_loop = false;
+ reset_httpd = false;
+ preserve_connections = false;
if (use_video) {
relaunch_video = true;
if (url.empty()) {
@@ -435,6 +486,8 @@ static void main_loop() {
gst_bus_watch_id[i] = (guint) video_renderer_listen((void *)loop, i);
}
}
+ missed_feedback = 0;
+ guint feedback_watch_id = g_timeout_add_seconds(1, (GSourceFunc) feedback_callback, (gpointer) loop);
guint reset_watch_id = g_timeout_add(100, (GSourceFunc) reset_callback, (gpointer) loop);
guint video_reset_watch_id = g_timeout_add(100, (GSourceFunc) video_reset_callback, (gpointer) loop);
guint sigterm_watch_id = g_unix_signal_add(SIGTERM, (GSourceFunc) sigterm_callback, (gpointer) loop);
@@ -449,6 +502,7 @@ static void main_loop() {
if (sigterm_watch_id > 0) g_source_remove(sigterm_watch_id);
if (reset_watch_id > 0) g_source_remove(reset_watch_id);
if (video_reset_watch_id > 0) g_source_remove(video_reset_watch_id);
+ if (feedback_watch_id > 0) g_source_remove(feedback_watch_id);
g_main_loop_unref(loop);
}
@@ -613,11 +667,15 @@ static void print_info (char *name) {
printf("-n name Specify the network name of the AirPlay server\n");
printf("-nh Do not add \"@hostname\" at the end of AirPlay server name\n");
printf("-h265 Support h265 (4K) video (with h265 versions of h264 plugins)\n");
- printf("-hls Support HTTP Live Streaming (currently Youtube video only) \n");
+ printf("-hls [v] Support HTTP Live Streaming (currently Youtube video only) \n");
+ printf(" v = 2 or 3 (default 3) optionally selects video player version\n");
printf("-pin[xxxx]Use a 4-digit pin code to control client access (default: no)\n");
printf(" default pin is random: optionally use fixed pin xxxx\n");
printf("-reg [fn] Keep a register in $HOME/.uxplay.register to verify returning\n");
printf(" client pin-registration; (option: use file \"fn\" for this)\n");
+ printf("-pw [pwd] Require use of password to control client access;\n");
+ printf(" (with no pwd, pin entry is required at *each* connection.)\n");
+ printf(" (option \"-pw\" after \"-pin\" overrides it, and vice versa)\n");
printf("-vsync [x]Mirror mode: sync audio to video using timestamps (default)\n");
printf(" x is optional audio delay: millisecs, decimal, can be neg.\n");
printf("-vsync no Switch off audio/(server)video timestamp synchronization \n");
@@ -626,10 +684,11 @@ static void print_info (char *name) {
printf("-db l[:h] Set minimum volume attenuation to l dB (decibels, negative);\n");
printf(" optional: set maximum to h dB (+ or -) default: -30.0:0.0 dB\n");
printf("-taper Use a \"tapered\" AirPlay volume-control profile\n");
+ printf("-vol Set initial audio-streaming volume: range [mute=0.0:1.0=full]\n");
printf("-s wxh[@r]Request to client for video display resolution [refresh_rate]\n");
printf(" default 1920x1080[@60] (or 3840x2160[@60] with -h265 option)\n");
printf("-o Set display \"overscanned\" mode on (not usually needed)\n");
- printf("-fs Full-screen (only works with X11, Wayland, VAAPI, D3D11)\n");
+ printf("-fs Full-screen (only with X11, Wayland, VAAPI, D3D11, kms)\n");
printf("-p Use legacy ports UDP 6000:6001:7011 TCP 7000:7001:7100\n");
printf("-p n Use TCP and UDP ports n,n+1,n+2. range %d-%d\n", LOWEST_ALLOWED_PORT, HIGHEST_PORT);
printf(" use \"-p n1,n2,n3\" to set each port, \"n1,n2\" for n3 = n2+1\n");
@@ -656,10 +715,12 @@ static void print_info (char *name) {
printf(" osssink,oss4sink,osxaudiosink,wasapisink,directsoundsink.\n");
printf("-as 0 (or -a) Turn audio off, streamed video only\n");
printf("-al x Audio latency in seconds (default 0.25) reported to client.\n");
- printf("-ca In Airplay Audio (ALAC) mode, write cover-art to file \n");
- printf("-reset n Reset after 3n seconds client silence (default %d, 0=never)\n", NTP_TIMEOUT_LIMIT);
+ printf("-ca []In Audio (ALAC) mode, render cover-art [or write to file ]\n");
+ printf("-md In Airplay Audio (ALAC) mode, write metadata text to file \n");
+ printf("-reset n Reset after n seconds of client silence (default n=%d, 0=never)\n", MISSED_FEEDBACK_LIMIT);
printf("-nofreeze Do NOT leave frozen screen in place after reset\n");
- printf("-nc Do NOT Close video window when client stops mirroring\n");
+ printf("-nc Do NOT Close video window when client stops mirroring\n");
+ printf("-nc no Cancel the -nc option (DO close video window) \n");
printf("-nohold Drop current connection when new client connects.\n");
printf("-restrict Restrict clients to those specified by \"-allow \"\n");
printf(" UxPlay displays deviceID when a client attempts to connect\n");
@@ -683,9 +744,10 @@ static void print_info (char *name) {
printf(" =1,2,..; fn=\"audiodump\"; change with \"-admp [n] filename\".\n");
printf(" x increases when audio format changes. If n is given, <= n\n");
printf(" audio packets are dumped. \"aud\"= unknown format.\n");
- printf("-d Enable debug logging\n");
+ printf("-d [n] Enable debug logging; optional: n=1 to skip normal packet data\n");
printf("-v Displays version information\n");
printf("-h Displays this help\n");
+ printf("-rc fn Read startup options from file \"fn\" instead of ~/.uxplayrc, etc\n");
printf("Startup options in $UXPLAYRC, ~/.uxplayrc, or ~/.config/uxplayrc are\n");
printf("applied first (command-line options may modify them): format is one \n");
printf("option per line, no initial \"-\"; lines starting with \"#\" are ignored.\n");
@@ -739,7 +801,7 @@ static bool get_value (const char *str, unsigned int *n) {
static bool get_ports (int nports, std::string option, const char * value, unsigned short * const port) {
/*valid entries are comma-separated values port_1,port_2,...,port_r, 0 < r <= nports */
/*where ports are distinct, and are in the allowed range. */
- /*missing values are consecutive to last given value (at least one value needed). */
+ /*missed values are consecutive to last given value (at least one value needed). */
char *end;
unsigned long l;
std::size_t pos;
@@ -827,7 +889,9 @@ static void parse_arguments (int argc, char *argv[]) {
// Parse arguments
for (int i = 1; i < argc; i++) {
std::string arg(argv[i]);
- if (arg == "-allow") {
+ if (arg == "-rc") {
+ i++; //specifies startup file: has already been processed
+ } else if (arg == "-allow") {
if (!option_has_value(i, argc, arg, argv[i+1])) exit(1);
i++;
allowed_clients.push_back(argv[i]);
@@ -934,7 +998,7 @@ static void parse_arguments (int argc, char *argv[]) {
if(!get_ports(3, arg, argv[++i], udp)) exit(1);
} else {
if(!get_ports(3, arg, argv[i], tcp)) exit(1);
- for (int j = 1; j < 3; j++) {
+ for (int j = 0; j < 3; j++) {
udp[j] = tcp[j];
}
}
@@ -955,7 +1019,18 @@ static void parse_arguments (int argc, char *argv[]) {
} else if (arg == "-a") {
use_audio = false;
} else if (arg == "-d") {
- debug_log = !debug_log;
+ if (i < argc - 1 && *argv[i+1] != '-') {
+ unsigned int n = 1;
+ if (!get_value(argv[++i], &n)) {
+ fprintf(stderr, "invalid \"-d %s\"; -d n : max n=1 (suppress packet data in debug output)\n", argv[i]);
+ exit(1);
+ }
+ debug_log = true;
+ suppress_packet_debug_data = true;
+ } else {
+ debug_log = !debug_log;
+ suppress_packet_debug_data = false;
+ }
} else if (arg == "-h" || arg == "--help" || arg == "-?" || arg == "-help") {
print_info(argv[0]);
exit(0);
@@ -994,6 +1069,13 @@ static void parse_arguments (int argc, char *argv[]) {
exit(1);
} else if (arg == "-nc") {
new_window_closing_behavior = false;
+ if (i < argc - 1) {
+ if (strlen(argv[i+1]) == 2 && strncmp(argv[i+1], "no", 2) == 0) {
+ new_window_closing_behavior = true;
+ i++;
+ continue;
+ }
+ }
} else if (arg == "-avdec") {
video_parser.erase();
video_parser = "h264parse";
@@ -1020,9 +1102,11 @@ static void parse_arguments (int argc, char *argv[]) {
} else if (arg == "-FPSdata") {
show_client_FPS_data = true;
} else if (arg == "-reset") {
- max_ntp_timeouts = 0;
- if (!get_value(argv[++i], &max_ntp_timeouts)) {
- fprintf(stderr, "invalid \"-reset %s\"; -reset n must have n >= 0, default n = %d\n", argv[i], NTP_TIMEOUT_LIMIT);
+ /* now using feedback (every 1 sec ) instead of ntp timeouts (every 3 secs) to detect offline client and reset connections */
+ fprintf(stderr,"*** NOTE CHANGE: -reset n now means reset n seconds (not 3n seconds) after client goes offline\n");
+ missed_feedback_limit = 0;
+ if (!get_value(argv[++i], &missed_feedback_limit)) {
+ fprintf(stderr, "invalid \"-reset %s\"; -reset n must have n >= 0, default n = %d seconds\n", argv[i], MISSED_FEEDBACK_LIMIT);
exit(1);
}
} else if (arg == "-vdmp") {
@@ -1071,19 +1155,32 @@ static void parse_arguments (int argc, char *argv[]) {
if (!file_has_write_access(fn)) {
fprintf(stderr, "%s cannot be written to:\noption \"-admp \" must be to a file with write access\n", fn);
exit(1);
- }
+ }
}
} else if (arg == "-ca" ) {
- if (option_has_value(i, argc, arg, argv[i+1])) {
+ if (i < argc - 1 && *argv[i+1] != '-') {
coverart_filename.erase();
coverart_filename.append(argv[++i]);
const char *fn = coverart_filename.c_str();
+ render_coverart = false;
if (!file_has_write_access(fn)) {
fprintf(stderr, "%s cannot be written to:\noption \"-ca \" must be to a file with write access\n", fn);
exit(1);
}
} else {
- fprintf(stderr,"option -ca must be followed by a filename for cover-art output\n");
+ render_coverart = true;
+ }
+ } else if (arg == "-md" ) {
+ if (option_has_value(i, argc, arg, argv[i+1])) {
+ metadata_filename.erase();
+ metadata_filename.append(argv[++i]);
+ const char *fn = metadata_filename.c_str();
+ if (!file_has_write_access(fn)) {
+ fprintf(stderr, "%s cannot be written to:\noption \"-md \" must be to a file with write access\n", fn);
+ exit(1);
+ }
+ } else {
+ fprintf(stderr,"option -md must be followed by a filename for metadata text output\n");
exit(1);
}
} else if (arg == "-bt709") {
@@ -1114,7 +1211,7 @@ static void parse_arguments (int argc, char *argv[]) {
exit(1);
} else if (arg == "-pin") {
setup_legacy_pairing = true;
- require_password = true;
+ pin_pw = 1;
if (i < argc - 1 && *argv[i+1] != '-') {
unsigned int n = 9999;
if (!get_value(argv[++i], &n)) {
@@ -1130,7 +1227,7 @@ static void parse_arguments (int argc, char *argv[]) {
pairing_register.append(argv[++i]);
const char * fn = pairing_register.c_str();
if (!file_has_write_access(fn)) {
- fprintf(stderr, "%s cannot be written to:\noption \"-key \" must be to a file with write access\n", fn);
+ fprintf(stderr, "%s cannot be written to:\noption \"-reg \" must be to a file with write access\n", fn);
exit(1);
}
}
@@ -1149,7 +1246,20 @@ static void parse_arguments (int argc, char *argv[]) {
keyfile.erase();
keyfile.append("0");
}
- } else if (arg == "-dacp") {
+ } else if (arg == "-pw") {
+ setup_legacy_pairing = false;
+ if (i < argc - 1 && *argv[i+1] != '-') {
+ password.erase();
+ password.append(argv[++i]);
+ pin_pw = 2;
+ if (password.size() < min_password_length) {
+ fprintf(stderr, "invalid client-access password \"%s\": length must be at least %u characters\n", password.c_str(), min_password_length);
+ exit(1);
+ }
+ } else {
+ pin_pw = 3; //a random password (pin) will be displayed at each connection
+ }
+ } else if (arg == "-dacp") {
dacpfile.erase();
if (i < argc - 1 && *argv[i+1] != '-') {
dacpfile.append(argv[++i]);
@@ -1167,31 +1277,63 @@ static void parse_arguments (int argc, char *argv[]) {
} else if (arg == "-db") {
bool db_bad = true;
double db1, db2;
- char *start = NULL;
if ( i < argc -1) {
char *end1, *end2;
- start = argv[i+1];
- db1 = strtod(start, &end1);
- if (end1 > start && *end1 == ':') {
+ db1 = strtod(argv[i+1], &end1);
+ if (*end1 == ':') {
db2 = strtod(++end1, &end2);
if ( *end2 == '\0' && end2 > end1 && db1 < 0 && db1 < db2) {
db_bad = false;
}
- } else if (*end1 =='\0' && end1 > start && db1 < 0 ) {
+ } else if (*end1 =='\0' && db1 < 0 ) {
db_bad = false;
db2 = 0.0;
}
}
if (db_bad) {
- fprintf(stderr, "invalid %s %s: db value must be \"low\" or \"low:high\", low < 0 and high > low are decibel gains\n", argv[i], start);
+ fprintf(stderr, "invalid \"-db %s\": db value must be \"low\" or \"low:high\", low < 0 and high > low are decibel gains\n", argv[i+1]);
exit(1);
}
i++;
db_low = db1;
db_high = db2;
- printf("db range %f:%f\n", db_low, db_high);
+ printf("db range %f:%f\n", db_low, db_high);
+ } else if (arg == "-vol") {
+ bool vol_bad = true;
+ if (i < argc - 1) {
+ char *end;
+ double frac = strtod(argv[i+1], &end);
+ if (*end == '\0' && frac >= 0.0 && frac <= 1.0) {
+ if (frac == 0.0) {
+ initial_volume = -144.0;
+ } else if (frac == 1.0) {
+ initial_volume = 0.0;
+ } else {
+ double db_flat = -30.0 + 30.0*frac;
+ //double db = 10.0 * (log10(frac) / log10(2.0)); //tapered
+ //printf("db %f db_flat %f \n", db, db_flat);
+ //db = (db > db_flat) ? db : db_flat;
+ initial_volume = db_flat;
+ }
+ }
+ printf("initial_volume attenuation %f db\n", initial_volume);
+ vol_bad = false;
+ }
+ if (vol_bad) {
+ fprintf(stderr, "invalid \"-vol %s\", value must be between 0.0 (mute) and 1.0 (full volume)\n", argv[i+1]);
+ exit(1);
+ }
+ i++;
} else if (arg == "-hls") {
hls_support = true;
+ if (i < argc - 1 && *argv[i+1] != '-') {
+ unsigned int n = 3;
+ if (!get_value(argv[++i], &n) || playbin_version < 2) {
+ fprintf(stderr, "invalid \"-hls %s\"; -hls n only allows \"playbin\" video player versions 2 or 3\n", argv[i]);
+ exit(1);
+ }
+ playbin_version = (guint) n;
+ }
} else if (arg == "-h265") {
h265_support = true;
} else if (arg == "-nofreeze") {
@@ -1203,7 +1345,7 @@ static void parse_arguments (int argc, char *argv[]) {
}
}
-static void process_metadata(int count, const char *dmap_tag, const unsigned char* metadata, int datalen) {
+static void process_metadata(int count, const char *dmap_tag, const unsigned char* metadata, int datalen, std::string *metadata_text) {
int dmap_type = 0;
/* DMAP metadata items can be strings (dmap_type = 9); other types are byte, short, int, long, date, and list. *
* The DMAP item begins with a 4-character (4-letter) "dmap_tag" string that identifies the type. */
@@ -1225,13 +1367,13 @@ static void process_metadata(int count, const char *dmap_tag, const unsigned cha
case 'a':
switch (dmap_tag[3]) {
case 'a':
- printf("Album artist: "); /*asaa*/
+ metadata_text->append("Album artist: "); /*asaa*/
break;
case 'l':
- printf("Album: "); /*asal*/
+ metadata_text->append("Album: "); /*asal*/
break;
case 'r':
- printf("Artist: "); /*asar*/
+ metadata_text->append("Artist: "); /*asar*/
break;
default:
dmap_type = 0;
@@ -1241,16 +1383,16 @@ static void process_metadata(int count, const char *dmap_tag, const unsigned cha
case 'c':
switch (dmap_tag[3]) {
case 'm':
- printf("Comment: "); /*ascm*/
+ metadata_text->append("Comment: "); /*ascm*/
break;
case 'n':
- printf("Content description: "); /*ascn*/
+ metadata_text->append("Content description: "); /*ascn*/
break;
case 'p':
- printf("Composer: "); /*ascp*/
+ metadata_text->append("Composer: "); /*ascp*/
break;
case 't':
- printf("Category: "); /*asct*/
+ metadata_text->append("Category: "); /*asct*/
break;
default:
dmap_type = 0;
@@ -1260,22 +1402,22 @@ static void process_metadata(int count, const char *dmap_tag, const unsigned cha
case 's':
switch (dmap_tag[3]) {
case 'a':
- printf("Sort Artist: "); /*assa*/
+ metadata_text->append("Sort Artist: "); /*assa*/
break;
case 'c':
- printf("Sort Composer: "); /*assc*/
+ metadata_text->append("Sort Composer: "); /*assc*/
break;
case 'l':
- printf("Sort Album artist: "); /*assl*/
+ metadata_text->append("Sort Album artist: "); /*assl*/
break;
case 'n':
- printf("Sort Name: "); /*assn*/
+ metadata_text->append("Sort Name: "); /*assn*/
break;
case 's':
- printf("Sort Series: "); /*asss*/
+ metadata_text->append("Sort Series: "); /*asss*/
break;
case 'u':
- printf("Sort Album: "); /*assu*/
+ metadata_text->append("Sort Album: "); /*assu*/
break;
default:
dmap_type = 0;
@@ -1284,15 +1426,15 @@ static void process_metadata(int count, const char *dmap_tag, const unsigned cha
break;
default:
if (strcmp(dmap_tag, "asdt") == 0) {
- printf("Description: ");
+ metadata_text->append("Description: ");
} else if (strcmp (dmap_tag, "asfm") == 0) {
- printf("Format: ");
+ metadata_text->append("Format: ");
} else if (strcmp (dmap_tag, "asgn") == 0) {
- printf("Genre: ");
+ metadata_text->append("Genre: ");
} else if (strcmp (dmap_tag, "asky") == 0) {
- printf("Keywords: ");
+ metadata_text->append("Keywords: ");
} else if (strcmp (dmap_tag, "aslc") == 0) {
- printf("Long Content Description: ");
+ metadata_text->append("Long Content Description: ");
} else {
dmap_type = 0;
}
@@ -1300,21 +1442,27 @@ static void process_metadata(int count, const char *dmap_tag, const unsigned cha
}
} else if (strcmp (dmap_tag, "minm") == 0) {
dmap_type = 9;
- printf("Title: ");
+ metadata_text->append("Title: ");
}
if (dmap_type == 9) {
- char *str = (char *) calloc(1, datalen + 1);
+ char *str = (char *) calloc(datalen + 1, sizeof(char));
memcpy(str, metadata, datalen);
- printf("%s", str);
+ metadata_text->append(str);
+ metadata_text->append("\n");
free(str);
} else if (debug_log) {
+ std::string md = "";
+ char hex[4];
for (int i = 0; i < datalen; i++) {
- if (i > 0 && i % 16 == 0) printf("\n");
- printf("%2.2x ", (int) metadata[i]);
+ if (i > 0 && i % 16 == 0) {
+ md.append("\n");
+ }
+ snprintf(hex, 4, "%2.2x ", (int) metadata[i]);
+ md.append(hex);
}
+ LOGI("%s", md.c_str());
}
- printf("\n");
}
static int parse_dmap_header(const unsigned char *metadata, char *tag, int *len) {
@@ -1391,12 +1539,17 @@ static void stop_dnssd() {
static int start_dnssd(std::vector hw_addr, std::string name) {
int dnssd_error;
- int require_pw = (require_password ? 1 : 0);
if (dnssd) {
LOGE("start_dnssd error: dnssd != NULL");
return 2;
}
- dnssd = dnssd_init(name.c_str(), strlen(name.c_str()), hw_addr.data(), hw_addr.size(), &dnssd_error, require_pw);
+ /* pin_pw controls client access
+ pin_pw = 1: client must enter pin displayed onscreen (first access only)
+ = 2: client must enter password (same password for all clients)
+ = 3: client must enter randoe 4-digit password displayed like an onscreen pin (every access)
+ = 0: no access control
+ */
+ dnssd = dnssd_init(name.c_str(), strlen(name.c_str()), hw_addr.data(), hw_addr.size(), &dnssd_error, pin_pw);
if (dnssd_error) {
LOGE("Could not initialize dnssd library!: error %d", dnssd_error);
return 1;
@@ -1529,17 +1682,16 @@ static bool check_blocked_client(char *deviceid) {
extern "C" void video_reset(void *cls) {
LOGD("video_reset");
+ video_renderer_stop();
url.erase();
- reset_loop = true;
remote_clock_offset = 0;
relaunch_video = true;
+ reset_loop = true;
}
-extern "C" void video_set_codec(void *cls, video_codec_t codec) {
- if (use_video) {
- bool video_is_h265 = (codec == VIDEO_CODEC_H265);
- video_renderer_choose_codec(video_is_h265);
- }
+extern "C" int video_set_codec(void *cls, video_codec_t codec) {
+ bool video_is_h265 = (codec == VIDEO_CODEC_H265);
+ return video_renderer_choose_codec(false, video_is_h265);
}
extern "C" void display_pin(void *cls, char *pin) {
@@ -1554,6 +1706,18 @@ extern "C" void display_pin(void *cls, char *pin) {
}
}
+extern "C" const char *passwd(void *cls, int *len){
+ if (pin_pw == 2) {
+ *len = password.size();
+ return password.c_str();
+ } else if (pin_pw == 3) {
+ *len = -1;
+ } else {
+ *len = 0; /* no password used */
+ }
+ return NULL;
+}
+
extern "C" void export_dacp(void *cls, const char *active_remote, const char *dacp_id) {
if (dacpfile.length()) {
FILE *fp = fopen(dacpfile.c_str(), "w");
@@ -1587,22 +1751,34 @@ extern "C" void conn_destroy (void *cls) {
}
}
-extern "C" void conn_reset (void *cls, int timeouts, bool reset_video) {
- LOGI("***ERROR lost connection with client (network problem?)");
- if (timeouts) {
- LOGI(" Client no-response limit of %d timeouts (%d seconds) reached:", timeouts, 3*timeouts);
- LOGI(" Sometimes the network connection may recover after a longer delay:\n"
- " the default timeout limit n = %d can be changed with the \"-reset n\" option", NTP_TIMEOUT_LIMIT);
+extern "C" void conn_feedback (void *cls) {
+ /* received client heartbeat signal: connection still exists */
+ missed_feedback = 0;
+}
+
+extern "C" void conn_reset (void *cls, int reason) {
+ switch (reason) {
+ case 1:
+ LOGI("*** ERROR lost connection with client (network problem?)");
+ break;
+ case 2:
+ LOGI("*** ERROR Unsupported HLS streaming source: (exit attempt to stream)");
+ break;
+ default:
+ break;
}
+
if (!nofreeze) {
- close_window = reset_video; /* leave "frozen" window open if reset_video is false */
+ close_window = false; /* leave "frozen" window open */
}
- raop_stop(raop);
+ reset_httpd = true;
+ relaunch_video = true;
reset_loop = true;
}
extern "C" void conn_teardown(void *cls, bool *teardown_96, bool *teardown_110) {
if (*teardown_110 && close_window) {
+ relaunch_video = true;
reset_loop = true;
}
}
@@ -1630,7 +1806,8 @@ extern "C" void audio_process (void *cls, raop_ntp_t *ntp, audio_decode_struct *
}
if (use_audio) {
if (!remote_clock_offset) {
- remote_clock_offset = data->ntp_time_local - data->ntp_time_remote;
+ uint64_t local_time = (data->ntp_time_local ? data->ntp_time_local : get_local_time());
+ remote_clock_offset = local_time - data->ntp_time_remote;
}
data->ntp_time_remote = data->ntp_time_remote + remote_clock_offset;
switch (data->ct) {
@@ -1658,10 +1835,20 @@ extern "C" void video_process (void *cls, raop_ntp_t *ntp, video_decode_struct *
}
if (use_video) {
if (!remote_clock_offset) {
- remote_clock_offset = data->ntp_time_local - data->ntp_time_remote;
+ uint64_t local_time = (data->ntp_time_local ? data->ntp_time_local : get_local_time());
+ remote_clock_offset = local_time - data->ntp_time_remote;
}
- data->ntp_time_remote = data->ntp_time_remote + remote_clock_offset;
- video_renderer_render_buffer(data->data, &(data->data_len), &(data->nal_count), &(data->ntp_time_remote));
+ int count = 0;
+ uint64_t pts_mismatch = 0;
+ do {
+ data->ntp_time_remote = data->ntp_time_remote + remote_clock_offset;
+ pts_mismatch = video_renderer_render_buffer(data->data, &(data->data_len), &(data->nal_count), &(data->ntp_time_remote));
+ if (pts_mismatch) {
+ LOGI("adjust timestamps by %8.6f secs", (double) pts_mismatch / SECOND_IN_NSECS);
+ remote_clock_offset += pts_mismatch;
+ }
+ count++;
+ } while (pts_mismatch && count < 10);
}
}
@@ -1690,6 +1877,10 @@ extern "C" void video_flush (void *cls) {
}
}
+extern "C" double audio_set_client_volume(void *cls) {
+ return initial_volume;
+}
+
extern "C" void audio_set_volume (void *cls, float volume) {
double db, db_flat, frac, gst_volume;
if (!use_audio) {
@@ -1762,6 +1953,9 @@ extern "C" void audio_get_format (void *cls, unsigned char *ct, unsigned short *
if (coverart_filename.length()) {
write_coverart(coverart_filename.c_str(), (const void *) empty_image, sizeof(empty_image));
}
+ if (metadata_filename.length()) {
+ write_metadata(metadata_filename.c_str(), "no data\n");
+ }
}
extern "C" void video_report_size(void *cls, float *width_source, float *height_source, float *width, float *height) {
@@ -1774,6 +1968,15 @@ extern "C" void audio_set_coverart(void *cls, const void *buffer, int buflen) {
if (buffer && coverart_filename.length()) {
write_coverart(coverart_filename.c_str(), buffer, buflen);
LOGI("coverart size %d written to %s", buflen, coverart_filename.c_str());
+ } else if (buffer && render_coverart) {
+ video_renderer_choose_codec(true, false); /* video_is_jpeg = true */
+ video_renderer_display_jpeg(buffer, &buflen);
+ }
+}
+
+extern "C" void audio_stop_coverart_rendering(void *cls) {
+ if (render_coverart) {
+ video_reset(cls);
}
}
@@ -1808,6 +2011,7 @@ extern "C" void audio_set_metadata(void *cls, const void *buffer, int buflen) {
dmap_tag, datalen, buflen);
return;
}
+ std::string metadata_text = "";
while (buflen >= 8) {
count++;
if (parse_dmap_header(metadata, dmap_tag, &datalen)) {
@@ -1816,12 +2020,16 @@ extern "C" void audio_set_metadata(void *cls, const void *buffer, int buflen) {
}
metadata += 8;
buflen -= 8;
- process_metadata(count, (const char *) dmap_tag, metadata, datalen);
+ process_metadata(count, (const char *) dmap_tag, metadata, datalen, &metadata_text);
metadata += datalen;
buflen -= datalen;
}
+ LOGI("%s", metadata_text.c_str());
+ if (metadata_filename.length()) {
+ write_metadata(metadata_filename.c_str(), metadata_text.c_str());
+ }
if (buflen != 0) {
- LOGE("%d bytes of metadata were not processed", buflen);
+ LOGE("%d bytes of metadata were not processed", buflen);
}
}
@@ -1860,12 +2068,13 @@ extern "C" bool check_register(void *cls, const char *client_pk) {
extern "C" void on_video_play(void *cls, const char* location, const float start_position) {
/* start_position needs to be implemented */
+ video_renderer_set_start(start_position);
url.erase();
url.append(location);
- reset_loop = true;
relaunch_video = true;
preserve_connections = true;
LOGD("********************on_video_play: location = %s***********************", url.c_str());
+ reset_loop = true;
}
extern "C" void on_video_scrub(void *cls, const float position) {
@@ -1892,7 +2101,12 @@ extern "C" void on_video_acquire_playback_info (void *cls, playback_info_t *play
int buffering_level;
LOGD("on_video_acquire_playback info\n");
bool still_playing = video_get_playback_info(&playback_info->duration, &playback_info->position,
- &playback_info->rate);
+ &playback_info->rate,
+ &playback_info->playback_buffer_empty,
+ &playback_info->playback_buffer_full);
+ playback_info->ready_to_play = true; //?
+ playback_info->playback_likely_to_keep_up = true; //?
+
LOGD("on_video_acquire_playback info done\n");
if (!still_playing) {
LOGI(" video has finished, %f", playback_info->position);
@@ -1931,6 +2145,7 @@ static int start_raop_server (unsigned short display[5], unsigned short tcp[3],
raop_cbs.conn_init = conn_init;
raop_cbs.conn_destroy = conn_destroy;
raop_cbs.conn_reset = conn_reset;
+ raop_cbs.conn_feedback = conn_feedback;
raop_cbs.conn_teardown = conn_teardown;
raop_cbs.audio_process = audio_process;
raop_cbs.video_process = video_process;
@@ -1938,16 +2153,19 @@ static int start_raop_server (unsigned short display[5], unsigned short tcp[3],
raop_cbs.video_flush = video_flush;
raop_cbs.video_pause = video_pause;
raop_cbs.video_resume = video_resume;
+ raop_cbs.audio_set_client_volume = audio_set_client_volume;
raop_cbs.audio_set_volume = audio_set_volume;
raop_cbs.audio_get_format = audio_get_format;
raop_cbs.video_report_size = video_report_size;
raop_cbs.audio_set_metadata = audio_set_metadata;
raop_cbs.audio_set_coverart = audio_set_coverart;
+ raop_cbs.audio_stop_coverart_rendering = audio_stop_coverart_rendering;
raop_cbs.audio_set_progress = audio_set_progress;
raop_cbs.report_client_request = report_client_request;
raop_cbs.display_pin = display_pin;
raop_cbs.register_client = register_client;
raop_cbs.check_register = check_register;
+ raop_cbs.passwd = passwd;
raop_cbs.export_dacp = export_dacp;
raop_cbs.video_reset = video_reset;
raop_cbs.video_set_codec = video_set_codec;
@@ -1981,9 +2199,8 @@ static int start_raop_server (unsigned short display[5], unsigned short tcp[3],
if (display[4]) raop_set_plist(raop, "overscanned", (int) display[4]);
if (show_client_FPS_data) raop_set_plist(raop, "clientFPSdata", 1);
- raop_set_plist(raop, "max_ntp_timeouts", max_ntp_timeouts);
if (audiodelay >= 0) raop_set_plist(raop, "audio_delay_micros", audiodelay);
- if (require_password) raop_set_plist(raop, "pin", (int) pin);
+ if (pin_pw == 1) raop_set_plist(raop, "pin", (int) pin);
if (hls_support) raop_set_plist(raop, "hls", 1);
/* network port selection (ports listed as "0" will be dynamically assigned) */
@@ -1991,7 +2208,7 @@ static int start_raop_server (unsigned short display[5], unsigned short tcp[3],
raop_set_udp_ports(raop, udp);
raop_port = raop_get_port(raop);
- raop_start(raop, &raop_port);
+ raop_start_httpd(raop, &raop_port);
raop_set_port(raop, raop_port);
/* use raop_port for airplay_port (instead of tcp[2]) */
@@ -2110,6 +2327,12 @@ int main (int argc, char *argv[]) {
std::vector server_hw_addr;
std::string config_file = "";
+#ifdef __OpenBSD__
+ if (unveil("/", "rwc") == -1 || unveil(NULL, NULL) == -1) {
+ err(1, "unveil");
+ }
+#endif
+
#ifdef SUPPRESS_AVAHI_COMPAT_WARNING
// suppress avahi_compat nag message. avahi emits a "nag" warning (once)
// if getenv("AVAHI_COMPAT_NOWARN") returns null.
@@ -2117,13 +2340,39 @@ int main (int argc, char *argv[]) {
if (!getenv("AVAHI_COMPAT_NOWARN")) putenv(avahi_compat_nowarn);
#endif
- config_file = find_uxplay_config_file();
+ char *rcfile = NULL;
+ /* see if option -rc was given */
+ for (int i = 1; i < argc ; i++) {
+ std::string arg(argv[i]);
+ if (arg == "-rc") {
+ struct stat sb;
+ if (i+1 == argc) {
+ LOGE ("option -rc requires a filename (-rc )");
+ exit(1);
+ }
+ rcfile = argv[i+1];
+ if (stat(rcfile, &sb) == -1) {
+ LOGE("startup file %s specified by option -rc was not found", rcfile);
+ exit(0);
+ }
+ break;
+ }
+ }
+ if (rcfile) {
+ config_file = rcfile;
+ } else {
+ config_file = find_uxplay_config_file();
+ }
if (config_file.length()) {
read_config_file(config_file.c_str(), argv[0]);
}
parse_arguments (argc, argv);
- log_level = (debug_log ? LOGGER_DEBUG : LOGGER_INFO);
+ log_level = (debug_log ? LOGGER_DEBUG_DATA : LOGGER_INFO);
+ if (debug_log && suppress_packet_debug_data) {
+ log_level = LOGGER_DEBUG;
+ }
+
#ifdef _WIN32 /* use utf-8 terminal output; don't buffer stdout in WIN32 when debug_log = false */
SetConsoleOutputCP(CP_UTF8);
@@ -2154,9 +2403,24 @@ int main (int argc, char *argv[]) {
}
#if __APPLE__
- /* force use of -nc option on macOS */
- LOGI("macOS detected: using -nc option as workaround for GStreamer problem");
- new_window_closing_behavior = false;
+ /* warn about default use of -nc option on macOS */
+ if (!new_window_closing_behavior) {
+ LOGI("UxPlay on macOS is using -nc option as workaround for GStreamer problem: use \"-nc no\" to omit workaround");
+ }
+#endif
+
+#ifdef _WIN32
+ /* because of issues in videosink dvd312videosink (segfault when resolution changes
+ with certain Nvdia graphics cards) make the default videosink d3d11videosink, and
+ use its decoder */
+ if (videosink == "autovideosink") {
+ videosink.erase();
+ videosink.append("d3d11videosink");
+ }
+ if (videosink == "d3d11videosink") {
+ video_decoder.erase();
+ video_decoder.append("d3d11h264dec");
+ }
#endif
if (videosink == "0") {
@@ -2171,19 +2435,29 @@ int main (int argc, char *argv[]) {
if (fullscreen && use_video) {
if (videosink == "waylandsink" || videosink == "vaapisink") {
videosink_options.append(" fullscreen=true");
+ } else if (videosink == "kmssink") {
+ videosink_options.append(" force_modesetting=true");
}
}
- if (videosink == "d3d11videosink" && videosink_options.empty() && use_video) {
+ if (videosink == "d3d11videosink" && videosink_options.empty() && use_video) {
if (fullscreen) {
- videosink_options.append(" fullscreen-toggle-mode=GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_PROPERTY fullscreen=true ");
+ videosink_options.append(" fullscreen-toggle-mode=GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_PROPERTY fullscreen=TRUE");
} else {
videosink_options.append(" fullscreen-toggle-mode=GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_ALT_ENTER ");
+ LOGI("Use Alt-Enter key combination to toggle into/out of full-screen mode");
}
- LOGI("d3d11videosink is being used with option fullscreen-toggle-mode=alt-enter\n"
- "Use Alt-Enter key combination to toggle into/out of full-screen mode");
}
+ if (videosink == "d3d12videosink" && videosink_options.empty() && use_video) {
+ if (fullscreen) {
+ videosink_options.append("fullscreen=TRUE");
+ } else {
+ videosink_options.append(" fullscreen-on-alt-enter=TRUE ");
+ LOGI("Use Alt-Enter key combination to toggle into/out of full-screen mode");
+ }
+ }
+
if (bt709_fix && use_video) {
video_parser.append(" ! ");
video_parser.append(BT709_FIX);
@@ -2195,7 +2469,7 @@ int main (int argc, char *argv[]) {
video_converter.append(option);
}
- if (require_password && registration_list) {
+ if (pin_pw == 1 && registration_list) {
if (pairing_register == "") {
const char * homedir = get_homedir();
if (homedir) {
@@ -2206,7 +2480,7 @@ int main (int argc, char *argv[]) {
}
/* read in public keys that were previously registered with pair-setup-pin */
- if (require_password && registration_list && strlen(pairing_register.c_str())) {
+ if (pin_pw == 1 && registration_list && strlen(pairing_register.c_str())) {
size_t len = 0;
std::string key;
int clients = 0;
@@ -2227,7 +2501,7 @@ int main (int argc, char *argv[]) {
}
}
- if (require_password && keyfile == "0") {
+ if (pin_pw == 1 && keyfile == "0") {
const char * homedir = get_homedir();
if (homedir) {
keyfile.erase();
@@ -2263,8 +2537,14 @@ int main (int argc, char *argv[]) {
if (use_video) {
video_renderer_init(render_logger, server_name.c_str(), videoflip, video_parser.c_str(),
video_decoder.c_str(), video_converter.c_str(), videosink.c_str(),
- videosink_options.c_str(), fullscreen, video_sync, h265_support, NULL);
+ videosink_options.c_str(), fullscreen, video_sync, h265_support, playbin_version, NULL);
video_renderer_start();
+#ifdef __OpenBSD__
+ } else {
+ if (pledge("stdio rpath wpath cpath inet unix prot_exec", NULL) == -1) {
+ err(1, "pledge");
+ }
+#endif
}
if (udp[0]) {
@@ -2291,6 +2571,11 @@ int main (int argc, char *argv[]) {
write_coverart(coverart_filename.c_str(), (const void *) empty_image, sizeof(empty_image));
}
+ if (metadata_filename.length()) {
+ LOGI("any AirPlay audio metadata text will be written to file %s",metadata_filename.c_str());
+ write_metadata(metadata_filename.c_str(), "no data\n");
+ }
+
/* set default resolutions for h264 or h265*/
if (!display[0] && !display[1]) {
if (h265_support) {
@@ -2302,7 +2587,6 @@ int main (int argc, char *argv[]) {
}
}
- restart:
if (start_dnssd(server_hw_addr, server_name)) {
goto cleanup;
}
@@ -2320,13 +2604,13 @@ int main (int argc, char *argv[]) {
close_window = new_window_closing_behavior;
main_loop();
- if (relaunch_video || reset_loop) {
- if(reset_loop) {
- reset_loop = false;
- } else {
- raop_stop(raop);
+ if (relaunch_video) {
+ if (reset_httpd) {
+ raop_stop_httpd(raop);
+ }
+ if (use_audio) {
+ audio_renderer_stop();
}
- if (use_audio) audio_renderer_stop();
if (use_video && (close_window || preserve_connections)) {
video_renderer_destroy();
if (!preserve_connections) {
@@ -2334,26 +2618,20 @@ int main (int argc, char *argv[]) {
url.erase();
raop_remove_known_connections(raop);
}
- preserve_connections = false;
const char *uri = (url.empty() ? NULL : url.c_str());
video_renderer_init(render_logger, server_name.c_str(), videoflip, video_parser.c_str(),
video_decoder.c_str(), video_converter.c_str(), videosink.c_str(),
- videosink_options.c_str(), fullscreen, video_sync, h265_support, uri);
+ videosink_options.c_str(), fullscreen, video_sync, h265_support, playbin_version, uri);
video_renderer_start();
}
- if (relaunch_video) {
+ if (reset_httpd) {
unsigned short port = raop_get_port(raop);
- raop_start(raop, &port);
+ raop_start_httpd(raop, &port);
raop_set_port(raop, port);
- goto reconnect;
- } else {
- LOGI("Re-launching RAOP server...");
- stop_raop_server();
- stop_dnssd();
- goto restart;
}
+ goto reconnect;
} else {
- LOGI("Stopping...");
+ LOGI("Stopping RAOP Server...");
stop_raop_server();
stop_dnssd();
}
@@ -2376,4 +2654,7 @@ int main (int argc, char *argv[]) {
if (coverart_filename.length()) {
remove (coverart_filename.c_str());
}
+ if (metadata_filename.length()) {
+ remove (metadata_filename.c_str());
+ }
}
diff --git a/uxplay.service b/uxplay.service
new file mode 100644
index 0000000..50f0c27
--- /dev/null
+++ b/uxplay.service
@@ -0,0 +1,13 @@
+[Unit]
+Description=AirPlay Unix mirroring server
+Requires=avahi-daemon
+After=avahi-daemon
+
+[Service]
+Type=simple
+ExecStart=uxplay
+Restart=on-failure
+#StandardOutput=file:%h/uxplay.log
+
+[Install]
+WantedBy=default.target
diff --git a/uxplay.spec b/uxplay.spec
index 9dd17df..e302bb4 100644
--- a/uxplay.spec
+++ b/uxplay.spec
@@ -1,5 +1,5 @@
Name: uxplay
-Version: 1.71.1
+Version: 1.72.2
Release: 1%{?dist}
%global gittag v%{version}
@@ -135,6 +135,8 @@ cd build
%{_docdir}/%{name}/llhttp/LICENSE-MIT
%changelog
+* Mon Jul 7 2025 UxPlay maintainer
+ Update for 1.72.2 release
* Fri Nov 15 2024 UxPlay maintainer
Initial uxplay.spec: tested on Fedora 38, Rocky Linux 9.2, OpenSUSE
Leap 15.5, Mageia 9, OpenMandriva ROME, PCLinuxOS