Skip to content

Commit a798cf3

Browse files
committed
[SoftCSA] Fix 100% CPU usage and missing CWs on softcam restart
CPU bug: When the softcam restarts, the old socket gets closed but read() returning 0 (EOF) was never handled in the CWHandler poll loop. Additionally, POLLHUP was gated behind !(revents & POLLIN) which fails when both flags are set on a closed socket. This caused an infinite busy-loop: poll() -> read() -> 0 -> ignored -> poll() -> ... Fix: Handle EOF (read==0) for both softcam_fd and proxy_fd paths, and remove the POLLIN gate from POLLHUP/POLLERR handling. CW bug: After softcam reconnect, the running channel never received new CW keys. On reconnect (m_protocol3_established), distributeCAPMT() was called before the Protocol-3 handshake, sending CAPMTs in legacy format. The softcam processed these and started descrambling. The subsequent Protocol-3 CAPMTs after SERVER_INFO were treated as duplicates - no CW keys were sent. Fix: On Protocol-3 reconnect, complete the handshake first before distributing CAPMTs. processServerInfoPacket() already calls distributeCAPMT() after the handshake completes.
1 parent 0208ba8 commit a798cf3

File tree

2 files changed

+52
-34
lines changed

2 files changed

+52
-34
lines changed

lib/dvb/cahandler.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -381,23 +381,24 @@ void eDVBCAHandler::newConnection(int socket)
381381
ePMTClient *client = new ePMTClient(this, client_fd);
382382
clients.push_back(client);
383383

384-
/* Always distribute current CAPMTs first (legacy format, works for all clients) */
385-
distributeCAPMT();
386-
387-
/* Send CLIENT_INFO only when appropriate:
388-
* - Protocol-3 already established (OSCam reconnect): always send
389-
* - First connection ever: send to probe for Protocol-3 support
390-
* - Legacy client detected (no SERVER_INFO after first attempt): skip
391-
* to avoid unnecessary errors in legacy softcam logs */
392384
if (m_protocol3_established)
393385
{
386+
/* Protocol-3 reconnect: complete handshake first, distributeCAPMT()
387+
* will be called from processServerInfoPacket() */
394388
client->sendClientInfo();
395389
}
396390
else if (!m_handshake_attempted)
397391
{
392+
/* First connection: send legacy CAPMTs, then probe for Protocol-3 */
393+
distributeCAPMT();
398394
client->sendClientInfo();
399395
m_handshake_attempted = true;
400396
}
397+
else
398+
{
399+
/* Legacy softcam - send CAPMTs immediately */
400+
distributeCAPMT();
401+
}
401402
}
402403

403404
void eDVBCAHandler::connectionLost(ePMTClient *client)

lib/dvb/cwhandler.cpp

Lines changed: 43 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ void eDVBCWHandler::threadLoop()
257257
const Connection& conn = conns_snapshot[i];
258258

259259
// Softcam → proxy_fd (and intercept CWs)
260+
bool softcam_disconnected = false;
260261
if (pfds[softcam_idx].revents & POLLIN)
261262
{
262263
ssize_t n = ::read(conn.softcam_fd, buf, sizeof(buf));
@@ -283,31 +284,40 @@ void eDVBCWHandler::threadLoop()
283284
written += w;
284285
}
285286
}
287+
else if (n == 0)
288+
{
289+
// EOF - softcam closed the connection
290+
eDebug("[eDVBCWHandler] Softcam EOF on fd %d", conn.softcam_fd);
291+
softcam_disconnected = true;
292+
}
293+
else if (errno != EINTR && errno != EAGAIN)
294+
{
295+
eDebug("[eDVBCWHandler] Softcam read error on fd %d: %m", conn.softcam_fd);
296+
softcam_disconnected = true;
297+
}
286298
}
287299

288300
// Handle softcam disconnect
289-
if (pfds[softcam_idx].revents & (POLLHUP | POLLERR))
301+
if (softcam_disconnected || (pfds[softcam_idx].revents & (POLLHUP | POLLERR)))
290302
{
291-
if (!(pfds[softcam_idx].revents & POLLIN)) // Only if no data pending
303+
eDebug("[eDVBCWHandler] Softcam disconnected on fd %d", conn.softcam_fd);
304+
// Close proxy_fd so ePMTClient gets connectionLost
305+
std::lock_guard<std::mutex> lock(m_connections_mutex);
306+
for (auto it = m_connections.begin(); it != m_connections.end(); ++it)
292307
{
293-
eDebug("[eDVBCWHandler] Softcam disconnected on fd %d", conn.softcam_fd);
294-
// Close proxy_fd so ePMTClient gets connectionLost
295-
std::lock_guard<std::mutex> lock(m_connections_mutex);
296-
for (auto it = m_connections.begin(); it != m_connections.end(); ++it)
308+
if (it->softcam_fd == conn.softcam_fd)
297309
{
298-
if (it->softcam_fd == conn.softcam_fd)
299-
{
300-
::close(it->softcam_fd);
301-
::close(it->proxy_fd);
302-
m_connections.erase(it);
303-
break;
304-
}
310+
::close(it->softcam_fd);
311+
::close(it->proxy_fd);
312+
m_connections.erase(it);
313+
break;
305314
}
306-
continue;
307315
}
316+
continue;
308317
}
309318

310319
// proxy_fd → softcam (CAPMT writes from ePMTClient)
320+
bool proxy_disconnected = false;
311321
if (pfds[proxy_idx].revents & POLLIN)
312322
{
313323
ssize_t n = ::read(conn.proxy_fd, buf, sizeof(buf));
@@ -330,24 +340,31 @@ void eDVBCWHandler::threadLoop()
330340
written += w;
331341
}
332342
}
343+
else if (n == 0)
344+
{
345+
eDebug("[eDVBCWHandler] ePMTClient EOF on proxy_fd %d", conn.proxy_fd);
346+
proxy_disconnected = true;
347+
}
348+
else if (errno != EINTR && errno != EAGAIN)
349+
{
350+
eDebug("[eDVBCWHandler] ePMTClient read error on proxy_fd %d: %m", conn.proxy_fd);
351+
proxy_disconnected = true;
352+
}
333353
}
334354

335355
// Handle ePMTClient disconnect
336-
if (pfds[proxy_idx].revents & (POLLHUP | POLLERR))
356+
if (proxy_disconnected || (pfds[proxy_idx].revents & (POLLHUP | POLLERR)))
337357
{
338-
if (!(pfds[proxy_idx].revents & POLLIN))
358+
eDebug("[eDVBCWHandler] ePMTClient disconnected on proxy_fd %d", conn.proxy_fd);
359+
std::lock_guard<std::mutex> lock(m_connections_mutex);
360+
for (auto it = m_connections.begin(); it != m_connections.end(); ++it)
339361
{
340-
eDebug("[eDVBCWHandler] ePMTClient disconnected on proxy_fd %d", conn.proxy_fd);
341-
std::lock_guard<std::mutex> lock(m_connections_mutex);
342-
for (auto it = m_connections.begin(); it != m_connections.end(); ++it)
362+
if (it->proxy_fd == conn.proxy_fd)
343363
{
344-
if (it->proxy_fd == conn.proxy_fd)
345-
{
346-
::close(it->softcam_fd);
347-
::close(it->proxy_fd);
348-
m_connections.erase(it);
349-
break;
350-
}
364+
::close(it->softcam_fd);
365+
::close(it->proxy_fd);
366+
m_connections.erase(it);
367+
break;
351368
}
352369
}
353370
}

0 commit comments

Comments
 (0)