]> git.vomp.tv Git - vompclient.git/blob - vdr.cc
Client side timeouts
[vompclient.git] / vdr.cc
1 /*
2     Copyright 2004-2005 Chris Tallon
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 */
20
21 #include "vdr.h"
22
23 #include "recman.h"
24 #include "tcp.h"
25 #include "log.h"
26 #include "recinfo.h"
27 #include "dsock.h"
28 #include "channel.h"
29 #include "event.h"
30 #include "wol.h"
31 #include "vdrrequestpacket.h"
32 #include "vdrresponsepacket.h"
33 #include "command.h"
34
35 VDR* VDR::instance = NULL;
36
37 VDR::VDR()
38 {
39   if (instance) return;
40   instance = this;
41   initted = 0;
42   findingServer = 0;
43   tcp = NULL;
44   connected = false;
45   maxChannelNumber = 0;
46   channelNumberWidth = 1;
47   TEMP_SINGLE_VDR_PR = NULL;
48 }
49
50 VDR::~VDR()
51 {
52   instance = NULL;
53   if (initted) shutdown();
54 }
55
56 VDR* VDR::getInstance()
57 {
58   return instance;
59 }
60
61 int VDR::init(int tport)
62 {
63   if (initted) return 0;
64   initted = 1;
65   port = tport;
66   logger = Log::getInstance();
67   return 1;
68 }
69
70 int VDR::shutdown()
71 {
72   if (!initted) return 0;
73   initted = 0;
74   disconnect();
75   return 1;
76 }
77
78 void VDR::findServers(vector<VDRServer>& servers)
79 {
80   Wol* wol = Wol::getInstance();
81   findingServer = 1;
82   char* message = "VOMP";
83
84   DatagramSocket ds(port);
85   int haveAtLeastOne = 0;
86   int retval;
87   int waitType = 1;
88   bool firstloop = true;
89   while(findingServer)
90   {
91     if (waitType == 1)
92     {
93       ds.shutdown();
94       ds.init();
95       logger->log("VDR", Log::NOTICE, "Broadcasting for server");
96       ds.send("255.255.255.255", 3024, message, strlen(message));
97       if(!firstloop) wol->doWakeUp();
98     }
99     retval = ds.waitforMessage(waitType);
100
101     if (retval == 2) // we got a reply
102     {
103       if (!strcmp(ds.getData(), "VOMP")) // echo.....
104       {
105         waitType = 2;
106       }
107       else
108       {
109         VDRServer newServer;
110         newServer.ip = new char[16];
111         strcpy(newServer.ip, ds.getFromIPA());
112
113         if (ds.getDataLength() == 0)
114         {
115           newServer.name = new char[1];
116           newServer.name[0] = '\0';
117         }
118         else
119         {
120           newServer.name = new char[strlen(ds.getData())+1];
121           strcpy(newServer.name, ds.getData());
122         }
123
124         servers.push_back(newServer);
125         waitType = 2;
126         haveAtLeastOne = 1;
127       }
128     }
129     else
130     {
131       if (haveAtLeastOne) break;
132       waitType = 1;
133       firstloop = false;
134     }
135   }
136   sort(servers.begin(), servers.end(), ServerSorter());
137 }
138
139 void VDR::cancelFindingServer()
140 {
141   findingServer = 0;
142 }
143
144 void VDR::setServerIP(char* newIP)
145 {
146   strcpy(serverIP, newIP);
147 }
148
149 int VDR::connect()
150 {
151   maxChannelNumber = 0;
152   channelNumberWidth = 1;
153
154   if (tcp) delete tcp;
155   tcp = new TCP();
156   if (tcp->connectTo(serverIP, 3024))
157   {
158     connected = true;
159     threadStart();
160     return 1;
161   }
162   else
163   {
164     return 0;
165   }
166 }
167
168 void VDR::disconnect()
169 {
170   threadCancel();
171   if (tcp) delete tcp;
172   tcp = NULL;
173   connected = false;
174   logger->log("VDR", Log::DEBUG, "Disconnect");
175 }
176
177 void VDR::setReceiveWindow(size_t size)
178 {
179   if (connected) tcp->setReceiveWindow(size);
180 }
181
182 ///////////////////////////////////////////////////////
183
184 void VDR::threadMethod()
185 {
186   logger->log("VDR", Log::DEBUG, "VDR RUN");  
187
188   threadSetKillable(); // FIXME - change this to deal with the EDRs
189   
190   ULONG channelID;
191   
192   ULONG requestID;
193   ULONG userDataLength;
194   UCHAR* userData;
195
196   ULONG streamID;
197   ULONG flag;
198
199   VDR_ResponsePacket* vresp;
200   
201   int timeoutCount = 0;
202   ULONG lastKAsent = 0;
203   ULONG timeNow = 0;
204   
205   while(1) 
206   {  
207     if (!tcp->readData((UCHAR*)&channelID, sizeof(ULONG)))  // 2s timeout atm
208     {
209       ++timeoutCount;
210     
211       // Error or timeout.
212
213       /* This is the simple version of timeout system until I work out how to make it better
214          e.g. different timeout lengths for different requests, a decent keepalive system
215          running in parallel etc etc.
216         
217          Ignore the stream channel
218          Start with lastPacketReceived = 0
219          When a packet comes in, set lastPacketReceived = time(NULL)
220          loop
221          {
222            if last packet is over 20s ago
223            {
224              if lastKAsent is less than 20s ago, continue
225              
226              if lastKAsent = 0, send a KA, continue
227              
228              if lastKAsent is over 20s ago, connection is dead, kill it
229            }
230          }         
231       */
232
233       logger->log("VDR", Log::DEBUG, "Net read timeout %i", timeoutCount);
234
235       if (!tcp->isConnected()) { connectionDied(); return; } // return to stop this thread
236       
237       timeoutCount = 0; // disable it for now
238       
239       if (timeoutCount >= 3) // x2 for seconds
240       {
241         timeNow = (ULONG)time(NULL);
242       
243         if (lastKAsent > (timeNow - 6)) continue;
244         
245         if (lastKAsent == 0)
246         {
247           logger->log("VDR", Log::DEBUG, "(Not actually) Sending KA packet");
248 //          if (!sendKA(timeNow))
249 //          {
250 //            logger->log("VDR", Log::DEBUG, "Could not send KA, calling connectionDied");
251 //            connectionDied();
252 //            return;
253 //          }
254           lastKAsent = timeNow;
255           continue;
256         }
257         
258         if (lastKAsent <= (timeNow - 6))
259         {
260           logger->log("VDR", Log::DEBUG, "lastKA over 20s ago, calling connectionDied");
261           connectionDied();
262           return;
263         }
264       }
265      
266       continue;      
267     }
268     
269     // Data was read
270             
271     timeoutCount = 0;
272     
273     channelID = ntohl(channelID);
274    
275     if (channelID == CHANNEL_REQUEST_RESPONSE)
276     {
277       if (!tcp->readData((UCHAR*)&requestID, sizeof(ULONG))) break;
278       requestID = ntohl(requestID);
279       if (!tcp->readData((UCHAR*)&userDataLength, sizeof(ULONG))) break;
280       userDataLength = ntohl(userDataLength);
281       if (userDataLength > 5000000) break; // how big can these packets get?
282       userData = NULL;
283       if (userDataLength > 0)
284       {
285         userData = (UCHAR*)malloc(userDataLength);
286         if (!userData) break;
287         if (!tcp->readData(userData, userDataLength)) break;
288       }
289
290       vresp = new VDR_ResponsePacket();  
291       vresp->setResponse(requestID, userData, userDataLength);
292       logger->log("VDR", Log::DEBUG, "Rxd a response packet, requestID=%lu, len=%lu", requestID, userDataLength);
293
294       if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )
295       {
296         // If edFindAndCall returns true, edr was called and vresp was handed off.
297         // else, delete vresp here.
298         delete vresp;
299       }
300     }
301     else if (channelID == CHANNEL_STREAM)
302     {
303       if (!tcp->readData((UCHAR*)&streamID, sizeof(ULONG))) break;
304       streamID = ntohl(streamID);
305
306       if (!tcp->readData((UCHAR*)&flag, sizeof(ULONG))) break;
307       flag = ntohl(flag);
308
309       if (!tcp->readData((UCHAR*)&userDataLength, sizeof(ULONG))) break; 
310       userDataLength = ntohl(userDataLength);
311       userData = NULL;
312       if (userDataLength > 0)
313       {
314         userData = (UCHAR*)malloc(userDataLength);
315         if (!userData) break;
316         if (!tcp->readData(userData, userDataLength)) break;
317       }
318
319       vresp = new VDR_ResponsePacket();    
320       vresp->setStream(streamID, flag, userData, userDataLength);
321 //      logger->log("VDR", Log::DEBUG, "Rxd a stream packet, streamID=%lu, flag=%lu, len=%lu", streamID, flag, userDataLength);
322
323       if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )
324       {
325         // If edFindAndCall returns true, edr was called and vresp was handed off.
326         // else, delete vresp here.
327         delete vresp;
328       }
329     }
330     else if (channelID == CHANNEL_KEEPALIVE)
331     {
332       ULONG KAreply = 0;
333       if (!tcp->readData((UCHAR*)&KAreply, sizeof(ULONG))) break;
334       KAreply = (ULONG)ntohl(KAreply);
335       if (KAreply == lastKAsent) // successful KA response
336       {
337         lastKAsent = 0;
338         timeoutCount = 0;
339         logger->log("VDR", Log::ERR, "Rxd correct KA reply");
340       }
341     }
342     else
343     {
344       logger->log("VDR", Log::ERR, "Rxd a response packet on channel %lu !!", channelID);
345       break;
346     }
347
348     // Who deletes vresp?
349     // If RR, the individual protocol functions must delete vresp.
350     // If stream, the data and length is taken out in ed_cb_call and vresp is deleted there.
351   }
352  
353   connectionDied();
354 }
355
356 void VDR::connectionDied()
357 {
358   // Called from within threadMethod to do cleanup if it decides the connection has died
359
360   connected = false; // though actually it could still be connected until someone calls vdr->disconnect
361
362   // Need to wake up any waiting channel 1 request-response threads
363   // Normally this is done by a packet coming in with channelid and requestid      
364   // Instead, go through the list and for each channel 1 edr, make an empty vresp
365   // An empty vresp will have userData == NULL, which means vresp->noResponse() == true
366
367   // If it's a stream receiver, generate a stream packet with flag == connection_lost
368
369   edLock();
370   VDR_PacketReceiver* vdrpr;
371   VDR_ResponsePacket* vresp;
372   while(receivers.size())
373   {
374     vdrpr = (VDR_PacketReceiver*) *(receivers.begin());
375     if (vdrpr->receiverChannel == CHANNEL_REQUEST_RESPONSE)
376     {
377       vresp = new VDR_ResponsePacket();
378       vresp->setResponse(vdrpr->requestSerialNumber, NULL, 0);
379       logger->log("VDR", Log::DEBUG, "Timeouts: created blank response packet for request serial %lu", vdrpr->requestSerialNumber);
380       edUnlock();
381       if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )
382       {
383         // If edFindAndCall returns true, edr was called and vresp was handed off.
384         // else, delete vresp here.
385         logger->log("VDR", Log::ERR, "Timeouts: no waiting thread found for request serial %lu !!!", vdrpr->requestSerialNumber);
386         delete vresp;
387       }
388       edLock();
389     }
390     else if (vdrpr->receiverChannel == CHANNEL_STREAM)
391     {
392       vresp = new VDR_ResponsePacket();
393       vresp->setStream(vdrpr->streamID, 2 /* connection-lost flag */ , NULL, 0);
394       logger->log("VDR", Log::DEBUG, "Timeouts: created blank response packet for streamid %lu", vdrpr->streamID);
395       edUnlock();
396       if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )
397       {
398         // If edFindAndCall returns true, edr was called and vresp was handed off.
399         // else, delete vresp here.
400         logger->log("VDR", Log::ERR, "Timeouts: no waiting stream receiver found for streamid %lu !!!", vdrpr->streamID);
401         delete vresp;
402       }
403       edLock();
404       
405       for(EDRL::iterator i = receivers.begin(); i != receivers.end(); i++)
406         if ((VDR_PacketReceiver*)*i == vdrpr) { receivers.erase(i); break; }
407     }
408   }
409   edUnlock();
410   // Ok, all event receviers should be dealt with. just in case there weren't any, inform command
411   logger->log("VDR", Log::DEBUG, "edUnlock at end of connectionDied");
412
413   Command::getInstance()->connectionLost();
414 }
415
416 bool VDR::ed_cb_find(EDReceiver* edr, void* userTag)
417 {
418   // edr is a VDR_PacketReceiver object made in VDR::RequestResponse
419   // userTag is a VDR_ResponsePacket made in threadMethod
420
421   VDR_PacketReceiver* vdrpr = (VDR_PacketReceiver*)edr;
422   VDR_ResponsePacket* vresp = (VDR_ResponsePacket*)userTag;
423   
424   // Is vresp for vdrpr ?
425   
426   ULONG packetChannel = vresp->getChannelID();
427   if (vdrpr->receiverChannel != packetChannel) return false;
428
429   if (packetChannel == CHANNEL_REQUEST_RESPONSE)
430   {
431     if (vdrpr->requestSerialNumber == vresp->getRequestID()) return true;
432   }
433   else if (packetChannel == CHANNEL_STREAM)
434   {
435     if (vdrpr->streamID == vresp->getStreamID()) return true;
436   }
437  
438   return false;
439 }
440
441 VDR_ResponsePacket* VDR::RequestResponse(VDR_RequestPacket* vrp)
442 {
443   logger->log("VDR", Log::DEBUG, "RR %lu", vrp->getOpcode());
444
445   if (!connected)
446   {
447     logger->log("VDR", Log::DEBUG, "RR when !connected");
448     VDR_ResponsePacket* vresp = new VDR_ResponsePacket();
449     return vresp; // "no-response" return
450   }
451
452   // ED make new VDR and register
453   // make a VDR_PacketReceiver
454   // - init with serial number of request packet
455
456   VDR_PacketReceiver vdrpr;
457 //  vdrpr.requestTime = time(NULL);
458   vdrpr.receiverChannel = VDR::CHANNEL_REQUEST_RESPONSE;
459   vdrpr.requestSerialNumber = vrp->getSerial();
460
461   edRegister(&vdrpr);
462    
463   edLock();  
464
465   if ((ULONG)tcp->sendData(vrp->getPtr(), vrp->getLen()) != vrp->getLen())
466   {
467     edUnlock();
468     edUnregister(&vdrpr);
469     VDR_ResponsePacket* vresp = new VDR_ResponsePacket();
470     return vresp; // "no-response" return
471   }
472
473   // Sleep and block this thread. The sleep unlocks the mutex
474   logger->log("VDR", Log::DEBUG, "RR sleep");
475   edSleepThisReceiver(&vdrpr);
476   logger->log("VDR", Log::DEBUG, "RR unsleep");
477     
478   // Woken because a response packet has arrived, mutex will be locked
479   
480   edUnlock();
481   return vdrpr.save_vresp;
482 }
483
484 bool VDR::sendKA(ULONG timeStamp)
485 {
486   char buffer[8];
487   *(ULONG*)&buffer[0] = htonl(CHANNEL_KEEPALIVE);
488   *(ULONG*)&buffer[4] = htonl(timeStamp);
489   if ((ULONG)tcp->sendData(buffer, 8) != 8) return false;
490   return true;
491 }
492
493 /////////////////////////////////////////////////////////////////////////////
494
495 // Here VDR takes a break for the VDR_PacketReceiver helper class
496
497 bool VDR_PacketReceiver::call(void* userTag)
498 {
499   if (receiverChannel == VDR::CHANNEL_REQUEST_RESPONSE)
500   {
501     // It's a RR. Save vresp and, signal the waiting thread and return.
502     // VDR::RequestResponse will be blocking waiting for this to happen.
503     // That function has a pointer to this object and can read save_vresp.
504     save_vresp = (VDR_ResponsePacket*)userTag;
505     return true; // Signals ED to remove edr from receivers and wake up edr thread
506   }
507   
508   if (receiverChannel == VDR::CHANNEL_STREAM)
509   {
510     // It's a stream packet.
511     VDR_ResponsePacket* vresp = (VDR_ResponsePacket*)userTag;
512     streamReceiver->streamReceive(vresp->getFlag(), vresp->getUserData(), vresp->getUserDataLength());
513     delete vresp;
514     return false;
515   }
516
517   abort(); // unknown receiverChannel, should not happen
518 }
519
520 /////////////////////////////////////////////////////////////////////////////
521
522 int VDR::doLogin()
523 {
524   VDR_RequestPacket vrp;
525   if (!vrp.init(VDR_LOGIN, true, 6)) return 0;
526
527   char* mactemp[6];
528   tcp->getMAC((char*)mactemp);
529   if (!vrp.copyin((UCHAR*)mactemp, 6)) return 0;
530
531   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
532   if (vresp->noResponse()) { delete vresp; return 0; }
533
534   ULONG vdrTime = vresp->extractULONG();
535   logger->log("VDR", Log::DEBUG, "vdrtime = %lu", vdrTime);
536   long vdrTimeOffset = vresp->extractLONG();
537   logger->log("VDR", Log::DEBUG, "offset = %i", vdrTimeOffset);
538
539   delete vresp;
540
541   // Set the time and zone on the MVP
542
543 #ifndef WIN32
544   struct timespec currentTime;
545   currentTime.tv_sec = vdrTime;
546   currentTime.tv_nsec = 0;
547   int b = clock_settime(CLOCK_REALTIME, &currentTime);
548
549   logger->log("VDR", Log::DEBUG, "set clock = %u", b);
550
551   // now make a TZ variable and set it
552   char sign;
553   int hours;
554   int minutes;
555   if (vdrTimeOffset > 0) sign = '-';
556   else sign = '+';
557
558   vdrTimeOffset = abs(vdrTimeOffset);
559
560   hours = (int)vdrTimeOffset / 3600;
561   minutes = vdrTimeOffset % 3600;
562
563   logger->log("VDR", Log::DEBUG, "%c %i %i", sign, hours, minutes);
564
565   minutes = (int)minutes / 60;
566
567   logger->log("VDR", Log::DEBUG, "%c %i %i", sign, hours, minutes);
568
569   char newTZ[30];
570   sprintf(newTZ, "MVP%c%i:%i", sign, hours, minutes);
571   setenv("TZ", newTZ, 1);
572
573   logger->log("VDR", Log::DEBUG, "Timezone data: %s", newTZ);
574 #endif
575
576   return 1;
577 }
578
579 bool VDR::getRecordingsList(RecMan* recman)
580 {
581   VDR_RequestPacket vrp;
582   if (!vrp.init(VDR_GETRECORDINGLIST, true, 0)) return false;
583
584   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
585   if (vresp->noResponse()) { delete vresp; return false; }
586   
587   ULONG totalSpace = vresp->extractULONG();
588   ULONG freeSpace = vresp->extractULONG();
589   ULONG percent = vresp->extractULONG();
590   recman->setStats(totalSpace, freeSpace, percent);
591
592   ULONG start;
593   char* name;
594   char* fileName;
595
596   while (!vresp->end())
597   {
598     start = vresp->extractULONG();
599     name = vresp->extractString();
600     fileName = vresp->extractString();
601
602     recman->addEntry(start, name, fileName);
603
604     delete[] name;
605     delete[] fileName;
606   }
607
608   delete vresp;
609
610   return true;
611 }
612
613 int VDR::deleteRecording(char* fileName)
614 {
615   VDR_RequestPacket vrp;
616   if (!vrp.init(VDR_DELETERECORDING, true, strlen(fileName) + 1)) return 0;
617   if (!vrp.addString(fileName)) return 0;
618   
619   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
620   if (vresp->noResponse()) { delete vresp; return 0; }
621   
622   int toReturn = (int)vresp->extractULONG();
623   delete vresp;
624
625   return toReturn;
626 }
627
628 char* VDR::moveRecording(char* fileName, char* newPath)
629 {
630   VDR_RequestPacket vrp;
631   if (!vrp.init(VDR_MOVERECORDING, true, strlen(fileName) + 1 + strlen(newPath) + 1)) return NULL;
632   if (!vrp.addString(fileName)) return NULL;
633   if (!vrp.addString(newPath)) return NULL;
634   
635   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
636   if (vresp->noResponse()) { delete vresp; return NULL; }
637   
638   char* toReturn = NULL;
639   int success = (int)vresp->extractULONG();
640   if (success == 1)
641   {
642     toReturn = vresp->extractString();
643   }
644
645   delete vresp;
646
647   return toReturn;
648 }
649
650 ChannelList* VDR::getChannelsList(ULONG type)
651 {
652   VDR_RequestPacket vrp;
653   if (!vrp.init(VDR_GETCHANNELLIST, true, 0)) return NULL;
654
655   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
656   if (vresp->noResponse()) { delete vresp; return NULL; }
657   
658   ChannelList* chanList = new ChannelList();
659
660   while (!vresp->end())
661   {
662     Channel* chan = new Channel();
663     chan->number = vresp->extractULONG();
664     chan->type = vresp->extractULONG();
665     chan->name = vresp->extractString();
666
667     if (chan->type == type)
668     {
669       chanList->push_back(chan);
670       logger->log("VDR", Log::DEBUG, "Have added a channel to list. %lu %lu %s", chan->number, chan->type, chan->name);
671       if (chan->number > maxChannelNumber) maxChannelNumber = chan->number;
672     }
673     else
674     {
675       delete chan;
676     }
677   }
678
679   delete vresp;
680
681   if (maxChannelNumber > 99999)
682     channelNumberWidth = 6;
683   else if (maxChannelNumber > 9999)
684     channelNumberWidth = 5;
685   else if (maxChannelNumber > 999)
686     channelNumberWidth = 4;
687   else if (maxChannelNumber > 99)
688     channelNumberWidth = 3;
689   else if (maxChannelNumber > 9)
690     channelNumberWidth = 2;
691   else
692     channelNumberWidth = 1;
693
694   return chanList;
695 }
696
697
698 int VDR::streamChannel(ULONG number)
699 {
700   // FIXME radio
701   return 0;
702 }
703
704 int VDR::streamChannel(ULONG number, StreamReceiver* tstreamReceiver)
705 {
706   VDR_RequestPacket vrp;
707   if (!vrp.init(VDR_STREAMCHANNEL, true, sizeof(ULONG))) return 0;
708   if (!vrp.addULONG(number)) return 0;
709   
710   
711   VDR_PacketReceiver* vdrpr = new VDR_PacketReceiver();
712   vdrpr->receiverChannel = VDR::CHANNEL_STREAM;
713   vdrpr->streamID = vrp.getSerial();
714   vdrpr->streamReceiver = tstreamReceiver;
715   edRegister(vdrpr);
716   TEMP_SINGLE_VDR_PR = vdrpr;
717   
718   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
719   if (vresp->noResponse())
720   {
721     delete vresp;
722     edUnregister(vdrpr);
723     delete vdrpr;
724     return 0;
725   }
726   
727   int toReturn = (int)vresp->extractULONG();
728   logger->log("VDR", Log::DEBUG, "VDR said %lu to start streaming request", toReturn);
729   delete vresp;
730
731   return toReturn;
732 }
733
734 int VDR::stopStreaming()
735 {
736   VDR_RequestPacket vrp;
737   if (!vrp.init(VDR_STOPSTREAMING, true, 0)) return 0;
738
739   if (TEMP_SINGLE_VDR_PR) // this block only needs to be done if it was a live stream
740                           // TEMP_SINGLE_VDR_PR will not be set unless we are streaming a channel
741   {
742     edUnregister(TEMP_SINGLE_VDR_PR);
743     delete TEMP_SINGLE_VDR_PR;
744     TEMP_SINGLE_VDR_PR = NULL;
745   }
746
747   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
748   if (vresp->noResponse()) { delete vresp; return 0; }
749   
750   int toReturn = (int)vresp->extractULONG();
751   delete vresp;
752
753   return toReturn;
754 }
755
756 UCHAR* VDR::getImageBlock(ULONG position, UINT maxAmount, UINT* amountReceived)
757 {
758   return getBlock(position, maxAmount, amountReceived, VDR_GETIMAGEBLOCK);
759 }
760
761 UCHAR* VDR::getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived)
762 {
763   return getBlock(position, maxAmount, amountReceived, VDR_GETBLOCK);
764 }
765
766 UCHAR* VDR::getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived, ULONG cmd)
767 {
768   VDR_RequestPacket vrp;
769   if (!vrp.init(cmd, true, sizeof(ULLONG) + sizeof(ULONG))) return NULL;
770   if (!vrp.addULLONG(position)) return NULL;
771   if (!vrp.addULONG(maxAmount)) return NULL;
772
773   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
774   if (vresp->noResponse()) { delete vresp; return NULL; }
775
776   if (vresp->serverError())
777   {
778     logger->log("VDR", Log::DEBUG, "Detected getblock 0");
779     delete vresp;
780     return NULL;
781   }
782
783   // Special handling for getblock
784   UCHAR* toReturn = vresp->getUserData();
785   *amountReceived = vresp->getUserDataLength();
786   
787   delete vresp;
788   
789   return toReturn;
790 }
791
792 ULLONG VDR::streamRecording(char* fileName, ULONG* totalFrames)
793 {
794   VDR_RequestPacket vrp;
795   if (!vrp.init(VDR_STREAMRECORDING, true, strlen(fileName) + 1)) return 0;
796   if (!vrp.addString(fileName)) return 0;
797
798   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
799   if (vresp->noResponse()) { delete vresp; return 0; }
800   
801   ULLONG lengthBytes = vresp->extractULLONG();
802   ULONG lengthFrames = vresp->extractULONG();
803   delete vresp;
804
805   logger->log("VDR", Log::DEBUG, "VDR said length is: %llu %lu", lengthBytes, lengthFrames);
806
807   *totalFrames = lengthFrames;
808   return lengthBytes;
809 }
810
811 ULLONG VDR::positionFromFrameNumber(ULONG frameNumber)
812 {
813   VDR_RequestPacket vrp;
814   if (!vrp.init(VDR_POSFROMFRAME, true, sizeof(ULONG))) return 0;
815   if (!vrp.addULONG(frameNumber)) return 0;
816
817   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
818   if (vresp->noResponse()) { delete vresp; return 0; }
819   
820   ULLONG position = vresp->extractULLONG();
821   delete vresp;
822   
823   logger->log("VDR", Log::DEBUG, "VDR said new position is: %llu", position);
824
825   return position;
826 }
827
828 ULONG VDR::frameNumberFromPosition(ULLONG position)
829 {
830   VDR_RequestPacket vrp;
831   if (!vrp.init(VDR_FRAMEFROMPOS, true, sizeof(ULLONG))) return 0;
832   if (!vrp.addULLONG(position)) return 0;
833
834   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
835   if (vresp->noResponse()) { delete vresp; return 0; }
836   
837   ULONG framenumber = vresp->extractULONG();
838   delete vresp;
839   
840   logger->log("VDR", Log::DEBUG, "VDR said new framenumber is: %u", framenumber);
841
842   return framenumber;
843 }
844
845 bool VDR::getNextIFrame(ULONG frameNumber, ULONG direction, ULLONG* rfilePosition, ULONG* rframeNumber, ULONG* rframeLength)
846 {
847   VDR_RequestPacket vrp;
848   if (!vrp.init(VDR_GETNEXTIFRAME, true, sizeof(ULONG)*2)) return false;
849   if (!vrp.addULONG(frameNumber)) return false;
850   if (!vrp.addULONG(direction)) return false;
851
852   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
853   if (vresp->noResponse()) { delete vresp; return false; }
854   
855   if (vresp->serverError())
856   {
857     logger->log("VDR", Log::DEBUG, "Detected getNextIFrame error");
858     delete vresp;
859     return false;
860   }
861
862   *rfilePosition = vresp->extractULLONG();
863   *rframeNumber = vresp->extractULONG();
864   *rframeLength = vresp->extractULONG();
865
866   delete vresp;
867
868 //  logger->log("VDR", Log::DEBUG, "VDR GNIF said %llu %lu %lu", *rfilePosition, *rframeNumber, *rframeLength);
869
870   return true;
871 }
872
873 EventList* VDR::getChannelSchedule(ULONG number)
874 {
875   time_t now;
876   time(&now);
877   return getChannelSchedule(number, now, 24 * 60 * 60);
878 }
879
880 EventList* VDR::getChannelSchedule(ULONG number, time_t start, ULONG duration)
881 {
882 // retrieve event list (vector of events) from vdr within filter window. duration is in seconds
883
884   VDR_RequestPacket vrp;
885   if (!vrp.init(VDR_GETCHANNELSCHEDULE, true, sizeof(ULONG)*3)) return NULL;
886   if (!vrp.addULONG(number)) return NULL;
887   if (!vrp.addULONG(start)) return NULL;
888   if (!vrp.addULONG(duration)) return NULL;
889
890   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
891   if (vresp->noResponse()) { delete vresp; return NULL; }
892   
893   // received a ulong(0) - schedules error in the plugin
894   if (vresp->serverError())
895   {
896     delete vresp;
897     return NULL;
898   }
899
900   EventList* eventList = new EventList();
901
902   while (!vresp->end())
903   {
904     Event* event = new Event();
905     event->id = vresp->extractULONG();
906     event->time = vresp->extractULONG();
907     event->duration = vresp->extractULONG();
908     event->title = vresp->extractString();
909     event->subtitle = vresp->extractString();
910     event->description = vresp->extractString();
911     eventList->push_back(event);
912   }
913
914   delete vresp;
915
916   logger->log("VDR", Log::DEBUG, "Success got to end of getChannelSchedule");
917   return eventList;
918 }
919
920 int VDR::configSave(const char* section, const char* key, const char* value)
921 {
922   VDR_RequestPacket vrp;
923   if (!vrp.init(VDR_CONFIGSAVE, false, 0)) return 0;
924   if (!vrp.addString(section)) return 0;
925   if (!vrp.addString(key)) return 0;
926   if (!vrp.addString(value)) return 0;
927
928   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
929   if (vresp->noResponse()) { delete vresp; return 0; }
930   
931   int toReturn = (int)vresp->extractULONG();
932   delete vresp;
933
934   return toReturn;
935 }
936
937 char* VDR::configLoad(const char* section, const char* key)
938 {
939   VDR_RequestPacket vrp;
940   if (!vrp.init(VDR_CONFIGLOAD, false, 0)) return NULL;
941   if (!vrp.addString(section)) return NULL;
942   if (!vrp.addString(key)) return NULL;
943
944   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
945   if (vresp->noResponse()) { delete vresp; return NULL; }
946   
947   char* toReturn = vresp->extractString();
948   delete vresp;
949
950   return toReturn;
951 }
952
953 RecTimerList* VDR::getRecTimersList()
954 {
955   VDR_RequestPacket vrp;
956   if (!vrp.init(VDR_GETTIMERS, true, 0)) return NULL;
957
958   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
959   if (vresp->noResponse()) { delete vresp; return NULL; }
960
961   RecTimerList* recTimerList = new RecTimerList();
962
963   ULONG numTimers = vresp->extractULONG();
964   if (numTimers > 0)
965   {
966     RecTimer* newRecTimer;
967     char* tempString;
968
969     while (!vresp->end())
970     {
971       newRecTimer = new RecTimer();
972       newRecTimer->active = vresp->extractULONG();
973       newRecTimer->recording = vresp->extractULONG();
974       newRecTimer->pending = vresp->extractULONG();
975       newRecTimer->priority = vresp->extractULONG();
976       newRecTimer->lifeTime = vresp->extractULONG();
977       newRecTimer->channelNumber = vresp->extractULONG();
978       newRecTimer->startTime = vresp->extractULONG();
979       newRecTimer->stopTime = vresp->extractULONG();
980       newRecTimer->day = vresp->extractULONG();
981       newRecTimer->weekDays = vresp->extractULONG();
982
983       tempString = vresp->extractString();
984       newRecTimer->setFile(tempString);
985       delete[] tempString;
986
987       recTimerList->push_back(newRecTimer);
988       logger->log("VDR", Log::DEBUG, "TL: %lu %lu %lu %lu %lu %lu %lu %lu %s",
989         newRecTimer->active, newRecTimer->recording, newRecTimer->pending, newRecTimer->priority, newRecTimer->lifeTime,
990         newRecTimer->channelNumber, newRecTimer->startTime, newRecTimer->stopTime, newRecTimer->getFile());
991     }
992   }
993
994   delete vresp;
995
996   sort(recTimerList->begin(), recTimerList->end(), RecTimerSorter());
997
998   return recTimerList;
999 }
1000
1001 ULONG VDR::setEventTimer(char* timerString)
1002 {
1003   VDR_RequestPacket vrp;
1004   if (!vrp.init(VDR_SETTIMER, true, strlen(timerString) + 1)) return 0;
1005   if (!vrp.addString(timerString)) return 0;
1006
1007   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1008   if (vresp->noResponse()) { delete vresp; return 0; }
1009   
1010   ULONG toReturn = vresp->extractULONG();
1011   delete vresp;
1012
1013   return toReturn;
1014 }
1015
1016 RecInfo* VDR::getRecInfo(char* fileName)
1017 {
1018   VDR_RequestPacket vrp;
1019   if (!vrp.init(VDR_GETRECINFO, true, strlen(fileName) + 1)) return NULL;
1020   if (!vrp.addString(fileName)) return NULL;
1021   
1022   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1023   if (vresp->noResponse()) { delete vresp; return NULL; }
1024   
1025   if (vresp->serverError())
1026   {
1027     logger->log("VDR", Log::DEBUG, "Could not get rec info");
1028     delete vresp;
1029     return NULL;
1030   }
1031
1032   RecInfo* recInfo = new RecInfo();
1033
1034   recInfo->timerStart = vresp->extractULONG();
1035   recInfo->timerEnd = vresp->extractULONG();
1036   recInfo->resumePoint = vresp->extractULONG();
1037   recInfo->summary = vresp->extractString();
1038
1039   ULONG numComponents = vresp->extractULONG();
1040   if (numComponents)
1041   {
1042     recInfo->setNumComponents(numComponents);
1043     for (ULONG i = 0; i < numComponents; i++)
1044     {
1045       recInfo->streams[i] = vresp->extractUCHAR();
1046       recInfo->types[i] = vresp->extractUCHAR();
1047       recInfo->languages[i] = vresp->extractString();
1048       recInfo->descriptions[i] = vresp->extractString();
1049     }
1050   }
1051
1052   recInfo->print();
1053
1054   delete vresp;
1055   return recInfo;
1056 }
1057
1058 // FIXME obselete
1059 ULLONG VDR::rescanRecording(ULONG* totalFrames)
1060 {
1061   VDR_RequestPacket vrp;
1062   if (!vrp.init(VDR_RESCANRECORDING, true, 0)) return 0;
1063
1064   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1065   if (vresp->noResponse()) { delete vresp; return 0; }
1066   
1067   ULLONG lengthBytes = vresp->extractULLONG();
1068   ULONG lengthFrames = vresp->extractULONG();
1069   delete vresp;
1070   
1071   logger->log("VDR", Log::DEBUG, "VDR said length is: %llu %lu", lengthBytes, lengthFrames);
1072
1073   *totalFrames = lengthFrames;
1074   return lengthBytes;
1075 }
1076
1077 MarkList* VDR::getMarks(char* fileName)
1078 {
1079   VDR_RequestPacket vrp;
1080   if (!vrp.init(VDR_GETMARKS, true, strlen(fileName) + 1)) return NULL;
1081   if (!vrp.addString(fileName)) return NULL;
1082
1083   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1084   if (vresp->noResponse()) { delete vresp; return NULL; }
1085   
1086   if (vresp->serverError())
1087   {
1088     delete vresp;
1089     return NULL;
1090   }
1091
1092   MarkList* markList = new MarkList();
1093
1094   while (!vresp->end())
1095   {
1096     Mark* mark = new Mark();
1097     mark->pos = vresp->extractULONG();
1098
1099     markList->push_back(mark);
1100     logger->log("VDR", Log::DEBUG, "Have added a mark to list. %lu", mark->pos);
1101   }
1102
1103   delete vresp;
1104   
1105   return markList;
1106 }
1107
1108 void VDR::getChannelPids(Channel* channel)
1109 {
1110   VDR_RequestPacket vrp;
1111   if (!vrp.init(VDR_GETCHANNELPIDS, true, sizeof(ULONG))) return ;
1112   if (!vrp.addULONG(channel->number)) return ;
1113
1114   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1115   if (vresp->noResponse()) { delete vresp; return ; }
1116   
1117   // Format of response
1118   // vpid
1119   // number of apids
1120   // {
1121   //    apid
1122   //    lang string
1123   // }
1124
1125   channel->vpid = vresp->extractULONG();
1126   channel->numAPids = vresp->extractULONG();
1127
1128   for (ULONG i = 0; i < channel->numAPids; i++)
1129   {
1130     apid newapid;
1131     newapid.pid = vresp->extractULONG();
1132     newapid.name = vresp->extractString();
1133     channel->apids.push_back(newapid);
1134   }
1135
1136   channel->numDPids = vresp->extractULONG();
1137
1138   for (ULONG i = 0; i < channel->numDPids; i++)
1139   {
1140     apid newdpid;
1141     newdpid.pid = vresp->extractULONG();
1142     newdpid.name = vresp->extractString();
1143     channel->dpids.push_back(newdpid);
1144   }
1145
1146   channel->numSPids = vresp->extractULONG();
1147
1148   for (ULONG i = 0; i < channel->numSPids; i++)
1149   {
1150     apid newspid;
1151     newspid.pid = vresp->extractULONG();
1152     newspid.name = vresp->extractString();
1153     channel->spids.push_back(newspid);
1154   }
1155   channel->tpid = vresp->extractULONG();
1156
1157   delete vresp;
1158   
1159   return ;
1160 }
1161
1162 /**
1163   * media List Request:
1164   * 4 flags (currently unused)
1165   * n dirname
1166   * n+1 0
1167   * Media List response:
1168   * 4 length
1169   * 4 VDR_
1170   * 4 numentries
1171   * per entry:
1172   * 4 media type
1173   * 4 time stamp
1174   * 4 flags
1175   * 4 strlen (incl. 0 Byte)
1176   * string
1177   * 0
1178 */
1179 MediaList* VDR::getMediaList(const char* parent,int mediaType)
1180 {
1181   logger->log("VDR", Log::DEBUG, "getMediaList %s,type=%d", (parent?parent:"NULL"), mediaType);
1182
1183   VDR_RequestPacket vrp;
1184   if (!vrp.init(VDR_GETMEDIALIST, false, 0)) return NULL;
1185   if (!vrp.addULONG(0)) return NULL; // unused flags
1186
1187   //name
1188   if (parent) {
1189     if (!vrp.addString(parent)) return NULL;
1190   }
1191     
1192   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1193   if (vresp->noResponse()) { delete vresp; return NULL; }
1194   
1195   if (vresp->serverError())
1196   {
1197     delete vresp;
1198     return NULL;
1199   }
1200   
1201   if (vresp->getUserDataLength() < 12)
1202   {
1203     logger->log("VDR", Log::ERR, "receiveMediaList packet too short, expected 12, got %d", vresp->getUserDataLength());
1204     delete vresp;
1205     return NULL;
1206   }
1207
1208   MediaList* mediaList = new MediaList();
1209   ULONG code=0;
1210   code = vresp->extractULONG();
1211   ULONG numEntries = vresp->extractULONG();
1212   Log::getInstance()->log("VDR", Log::DEBUG, "receiveMediaList with %d entries",numEntries);
1213   while (!vresp->end() && numEntries >0)
1214   {
1215     Media* m = new Media();
1216     ULONG mtype = vresp->extractULONG();
1217     ULONG mtime=vresp->extractULONG();
1218     ULONG flags=0;
1219     flags=vresp->extractULONG();
1220     ULONG stsize=vresp->extractULONG();
1221     char * name=vresp->extractString();
1222     if (! name || stsize != (strlen(name)+1)) {
1223       Log::getInstance()->log("VDR", Log::ERR, "receiveMediaList invalid packet entry, read size %d, strlen %d", stsize, strlen(name)+1);
1224       delete m;
1225       delete mediaList;
1226       delete vresp;
1227       return NULL;
1228       }
1229     //ignore . and .. entries
1230     if (strcmp(name,".") == 0 || strcmp(name,"..")==0) {
1231   delete m;
1232   continue;
1233     }
1234     m->setFileName(name);
1235     m->setTime(mtime);
1236     m->setMediaType(mtype);
1237     mediaList->push_back(m);
1238     Log::getInstance()->log("VDR", Log::DEBUG, "Have added a media to list. %s, type=%d, time=%d", name,mtype,mtime);
1239     numEntries--;
1240   }
1241
1242   delete vresp;
1243   return mediaList;
1244 }
1245
1246 /**
1247   * get image Request:
1248   * 4 flags (currently unused)
1249   * 4 x size
1250   * 4 y size
1251   * n filename
1252   * n+1 0
1253   * get image response:
1254   * 4 length
1255   * 4 VDR_GETIMAGE
1256   * 4 len of image
1257 */
1258 ULONG VDR::loadImage(const char* fileName, ULONG x, ULONG y)
1259 {
1260   VDR_RequestPacket vrp;
1261   if (!vrp.init(VDR_GETIMAGE, false, 0)) return 0;
1262   if (!vrp.addULONG(0)) return 0; // unused flags
1263   if (!vrp.addULONG(x)) return 0;
1264   if (!vrp.addULONG(y)) return 0;
1265   if (!vrp.addString(fileName)) return 0;
1266
1267   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1268   if (vresp->noResponse()) { delete vresp; return 0; }
1269
1270   ULONG cmd = vresp->extractULONG();
1271   ULONG lengthBytes = vresp->extractULONG();
1272   delete vresp;
1273
1274   Log::getInstance()->log("VDR", Log::DEBUG, "getImage %s: cmd=%lu len=%lu", fileName, cmd, lengthBytes);
1275   return lengthBytes;
1276 }
1277
1278 int VDR::deleteTimer(RecTimer* delTimer)
1279 {
1280   Log::getInstance()->log("VDR", Log::DEBUG, "Delete timer called");
1281   
1282   VDR_RequestPacket vrp;
1283   if (!vrp.init(VDR_DELETETIMER, false, 0)) return 0;
1284   if (!vrp.addULONG(delTimer->channelNumber)) return 0;
1285   if (!vrp.addULONG(delTimer->weekDays)) return 0;    
1286   if (!vrp.addULONG(delTimer->day)) return 0;
1287   if (!vrp.addULONG(delTimer->startTime)) return 0;  
1288   if (!vrp.addULONG(delTimer->stopTime)) return 0; 
1289    
1290   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1291   if (vresp->noResponse()) { delete vresp; return 0; }
1292   
1293   int toReturn = (int)vresp->extractULONG();
1294   delete vresp;
1295
1296   return toReturn;
1297 }
1298
1299 I18n::lang_code_list VDR::getLanguageList()
1300 {
1301   I18n::lang_code_list CodeList;
1302   CodeList["en"] = "English"; // Default entry
1303   VDR_RequestPacket vrp;
1304   if (!vrp.init(VDR_GETLANGUAGELIST, false, 0)) return CodeList;
1305   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1306   if (vresp->noResponse() || vresp->end())
1307   {
1308     delete vresp;
1309     return CodeList;
1310   }
1311   CodeList.clear();
1312   while (!vresp->end())
1313   {
1314     char* c_code = vresp->extractString();
1315     char* c_name = vresp->extractString();
1316     string code = c_code;
1317     string name = c_name;
1318     CodeList[code] = name;
1319     delete[] c_code;
1320     delete[] c_name;
1321   }
1322   delete vresp;
1323   return CodeList;
1324 }
1325
1326 int VDR::getLanguageContent(const std::string code, I18n::trans_table& texts)
1327 {
1328   VDR_RequestPacket vrp;
1329   if (!vrp.init(VDR_GETLANGUAGECONTENT, false, 0)) return 0;
1330   if (!vrp.addString(code.c_str())) return 0;
1331   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1332   if (vresp->noResponse()) { delete vresp; return 0; }
1333   texts.clear();
1334   while (!vresp->end())
1335   {
1336     char* c_key = vresp->extractString();
1337     char* c_text = vresp->extractString();
1338     string key = c_key;
1339     string text = c_text;
1340     texts[key] = text;
1341     delete[] c_key;
1342     delete[] c_text;
1343   }
1344   delete vresp;
1345   return 1;
1346 }