From 5413b485c681912443b76707941b9665d713fec3 Mon Sep 17 00:00:00 2001
From: Chris Tallon <chris@vomp.tv>
Date: Sun, 11 May 2008 16:53:16 +0000
Subject: [PATCH] Started work on the client side timeouts

---
 command.cc         |  2 +-
 playerliveradio.cc |  1 +
 playerlivetv.cc    |  1 +
 vdr.cc             | 86 ++++++++++++++++++++++++++++++++++++++++------
 4 files changed, 79 insertions(+), 11 deletions(-)

diff --git a/command.cc b/command.cc
index 16fa00a..a2b1968 100644
--- a/command.cc
+++ b/command.cc
@@ -569,7 +569,7 @@ void Command::connectionLost()
   Message* m = new Message(); // break into master mutex
   m->message = Message::CONNECTION_LOST;
   m->to = this;
-  postMessageNoLock(m);
+  postMessageFromOuterSpace(m);
 }
 
 void Command::buildCrashedBox()
diff --git a/playerliveradio.cc b/playerliveradio.cc
index 5e798ae..e4a5f38 100644
--- a/playerliveradio.cc
+++ b/playerliveradio.cc
@@ -153,6 +153,7 @@ void PlayerLiveRadio::streamReceive(ULONG flag, void* data, ULONG len)
   // Flag:
   // 0 = normal stream packet
   // 1 = stream end
+  // 2 = connection lost
 
   if (flag == 1)
   {
diff --git a/playerlivetv.cc b/playerlivetv.cc
index d0591ea..6295ee9 100644
--- a/playerlivetv.cc
+++ b/playerlivetv.cc
@@ -215,6 +215,7 @@ void PlayerLiveTV::streamReceive(ULONG flag, void* data, ULONG len)
   // Flag:
   // 0 = normal stream packet
   // 1 = stream end
+  // 2 = connection lost
 
 //  logger->log("PlayerLiveTV", Log::DEBUG, "Received a streamchunk from VDR, flag = %lu", flag);
 
diff --git a/vdr.cc b/vdr.cc
index cbab39b..c228fd8 100644
--- a/vdr.cc
+++ b/vdr.cc
@@ -30,6 +30,7 @@
 #include "wol.h"
 #include "vdrrequestpacket.h"
 #include "vdrresponsepacket.h"
+#include "command.h"
 
 VDR* VDR::instance = NULL;
 
@@ -182,7 +183,7 @@ void VDR::setReceiveWindow(size_t size)
 
 void VDR::threadMethod()
 {
-  threadSetKillable();
+  threadSetKillable(); // FIXME - change this to deal with the EDRs
   
   ULONG channelID;
   
@@ -195,21 +196,86 @@ void VDR::threadMethod()
 
   VDR_ResponsePacket* vresp;
   
+  int timeoutCount = 0;
+  
   while(1) 
   {  
-    if (!tcp->readData((UCHAR*)&channelID, sizeof(ULONG)))
+    if (!tcp->readData((UCHAR*)&channelID, sizeof(ULONG))) // 2s timeout atm
     {
+      ++timeoutCount;
+    
       // Error or timeout.
-      logger->log("VDR", Log::DEBUG, "Net read timeout");
-      
-      // Do timeouts
-      //edLock();
-      //for(EDRL::iterator i = receivers.begin(); i != receivers.end(); i++)
-      //{
-      
-      
+
+      // Thsi is the simple version of timeout system until I work out how to make it better
+      // e.g. different timeout lengths for different requests, a decent keepalive system
+      // running in parallel etc etc.
+
+      logger->log("VDR", Log::DEBUG, "Net read timeout %i", timeoutCount);
+
+      if (!tcp->isConnected())// FIXME disabled for now until it works ... !! || (timeoutCount > 10)) // 20s
+      {
+        // timeout, kill it
+
+        connected = false; // though actually it could still be connected until someone calls vdr->disconnect
+
+        // Need to wake up any waiting channel 1 request-response threads
+        // Normally this is done by a packet coming in with channelid and requestid      
+        // Instead, go through the list and for each channel 1 edr, make an empty vresp
+        // An empty vresp will have userData == NULL, which means vresp->noResponse() == true
+
+        // If it's a stream receiver, generate a stream packet with flag == connection_lost
+
+        edLock();
+        VDR_PacketReceiver* vdrpr;
+        while(receivers.size())
+        {
+          vdrpr = (VDR_PacketReceiver*) *(receivers.begin());
+          if (vdrpr->receiverChannel == CHANNEL_REQUEST_RESPONSE)
+          {
+            vresp = new VDR_ResponsePacket();
+            vresp->setResponse(vdrpr->requestSerialNumber, NULL, 0);
+            logger->log("VDR", Log::DEBUG, "Timeouts: created blank response packet for request serial %lu", vdrpr->requestSerialNumber);
+            edUnlock();
+            if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )
+            {
+              // If edFindAndCall returns true, edr was called and vresp was handed off.
+              // else, delete vresp here.
+              logger->log("VDR", Log::ERR, "Timeouts: no waiting thread found for request serial %lu !!!", vdrpr->requestSerialNumber);
+              delete vresp;
+            }
+            edLock();
+          }
+          else if (vdrpr->receiverChannel == CHANNEL_STREAM)
+          {
+            vresp->setStream(vdrpr->streamID, 2 /* connection-lost flag */ , NULL, 0);
+            logger->log("VDR", Log::DEBUG, "Timeouts: created blank response packet for streamid %lu", vdrpr->streamID);
+            edUnlock();
+            if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )
+            {
+              // If edFindAndCall returns true, edr was called and vresp was handed off.
+              // else, delete vresp here.
+              logger->log("VDR", Log::ERR, "Timeouts: no waiting stream receiver found for streamid %lu !!!", vdrpr->streamID);
+              delete vresp;
+            }
+            edLock();  
+          }
+        }
+        edUnlock();
+        // Ok, all event receviers should be dealt with. just in case there weren't any, inform command
+        
+        Command::getInstance()->connectionLost();
+        
+        // return and stop this thread
+        return;
+      }
+     
       continue;      
     }
+    
+    // Data was read
+    
+    timeoutCount = 0;
+    
     channelID = ntohl(channelID);
 
     vresp = new VDR_ResponsePacket();  
-- 
2.39.5