Files
tuliprox/docs/src/troubleshooting.md
T

81 lines
4.4 KiB
Markdown
Raw Normal View History

# 🛠️ Troubleshooting & Resilience
Running a reverse proxy for IPTV involves navigating the quirks of various video players and the strict limitations of upstream providers. This page
documents common "real-world" behaviors that can lead to stream interruptions or provider bans, and how to mitigate them using Tuliprox's resilience
features.
The solutions below will help you fine-tune your configuration for a seamless experience.
---
## 1. The VLC "Seek" Problem (Grace Periods)
**The Problem:** A user watches a VOD movie via reverse proxy. They press "Fast forward 10 seconds" in VLC. VLC calculates the new byte offset, kills
the TCP connection, and instantly fires a new HTTP GET request (with a `Range` header) to your Tuliprox server.
Tuliprox opens a new connection to the upstream provider. However, since the old connection takes milliseconds to officially close at the provider
side, the provider sees **two** active streams. If you only paid for 1 connection, the provider throws a 509 Bandwidth Exceeded error or bans your IP!
**The Solution in `config.yml`:**
```yaml
reverse_proxy:
stream:
grace_period_hold_stream: true
grace_period_millis: 2000
grace_period_timeout_secs: 5
```
**What happens now?**
Tuliprox detects the bottleneck and grants a temporary "grace" state:
* **Hold State:** Because `grace_period_hold_stream: true` is set, Tuliprox keeps the client connection "warm" but
waits before requesting new bytes from the provider.
* **The Handover:** It waits for `grace_period_millis` (2000ms) to give the provider's server time to register the old connection as closed.
* **Resolution:**
* **Success:** If the old "ghost" connection dies within the window ➔ The new stream flows instantly.
* **Timeout:** If the old connection persists beyond `grace_period_timeout_secs` (5s) ➔ Grace is revoked, and the client receives the
`user_connections_exhausted.ts` video.
---
## 2. Zombie Connections After a Client IP Change (Wi-Fi → Mobile Data)
**The Problem:** A user starts a stream on their mobile phone while connected to home Wi-Fi. They then walk outside, and the phone automatically
switches to 4G/5G. The phone's public IP address changes, and the old stream stalls.
A new connection attempt from the new IP address hits the `max_connections` limit and starts playing the `user_connections_exhausted.ts` video —
even though the user is the only viewer. The original stream slot appears "stuck" and is not released, even though no data is flowing to the client
anymore.
**Root Cause — Why the Slot Gets Stuck:**
When a phone switches networks without explicitly closing its TCP connection (no FIN/RST packet), the server has no way to know the client is gone.
The kernel keeps trying to deliver buffered stream data with exponential retransmission back-off.
TCP Keepalive probes — while configured in Tuliprox — only fire on **idle** connections (no data sent for a period of time). A live IPTV stream is
never idle from the server's perspective, so keepalive probes never trigger. The result is that the kernel can keep retransmitting for **2–15 minutes**
before it finally gives up and closes the connection.
**The Solution — `TCP_USER_TIMEOUT` (Linux only):**
Tuliprox automatically sets the `TCP_USER_TIMEOUT` socket option on every accepted connection on Linux. This option instructs the kernel to forcibly
close a connection once transmitted data has been unacknowledged for a defined period — regardless of whether the connection was idle or actively
sending.
With the default value of **30 seconds**, a dead streaming connection is detected and its slot is freed within 30 seconds of the client disappearing.
```code
t = 0 s Phone switches from Wi-Fi to 4G (old TCP connection dies silently)
t = 0 s Server continues sending stream data; kernel buffers it (no ACKs)
t ≤ 30 s TCP_USER_TIMEOUT exceeded → kernel forcibly closes the connection
t ≤ 30 s Tuliprox releases the user connection slot
t ≤ 30 s New connection from the 4G IP can now acquire the slot normally
```
> **Platform Note:** `TCP_USER_TIMEOUT` is a Linux-specific feature (available since kernel 2.6.37). On **Windows** and **macOS**, this option is not
> available. Those platforms handle dead connections through TCP Keepalive probes or platform-specific socket options, which are less effective for
> active streaming connections. In practice this is not an issue since Tuliprox is designed to run on Linux servers and Docker containers.
---