]> git.vomp.tv Git - vompserver.git/blob - mvpclient.c
Fix for timezone on client #1233050
[vompserver.git] / mvpclient.c
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 #include "mvpclient.h"
22
23 MVPClient::MVPClient(int tsocket)
24  : tcp(tsocket)
25 {
26   cm = NULL;
27   rp = NULL;
28   recordingManager = NULL;
29
30   // Get IP address of client for config module
31
32   char ipa[20];
33   struct sockaddr_in peer;
34   socklen_t salen = sizeof(struct sockaddr);
35   if(getpeername(tsocket, (struct sockaddr*)&peer, &salen) == 0)
36   {
37     strcpy(ipa, inet_ntoa(peer.sin_addr));
38   }
39   else
40   {
41     ipa[0] = '\0';
42     printf("Cannot get peer name!\n");
43   }
44
45   const char* configDir = cPlugin::ConfigDirectory();
46   if (!configDir)
47   {
48     printf("No config dir!\n");
49     return;
50   }
51
52   char configFileName[PATH_MAX];
53   snprintf(configFileName, PATH_MAX - strlen(configDir) - strlen(ipa) - 20, "%s/vomp-%s.conf", configDir, ipa);
54   config.init(configFileName);
55
56   printf("Config file name: %s\n", configFileName);
57
58 //  processGetChannelSchedule(NULL, 0);
59
60 //  printf("here\n");
61 //test();
62
63 }
64
65 MVPClient::~MVPClient()
66 {
67   printf("MVP client destructor\n");
68   if (cm)
69   {
70     cm->Stop();
71     delete cm;
72     cm = NULL;
73   }
74   else if (rp)
75   {
76     writeResumeData();
77
78     delete rp;
79     delete recordingManager;
80     rp = NULL;
81     recordingManager = NULL;
82   }
83
84   cleanConfig();
85 }
86
87 cChannel* MVPClient::channelFromNumber(unsigned long channelNumber)
88 {
89   cChannel* channel = NULL;
90
91   for (channel = Channels.First(); channel; channel = Channels.Next(channel))
92   {
93     if (!channel->GroupSep())
94     {
95       printf("Looking for channel %lu::: number: %i name: '%s'\n", channelNumber, channel->Number(), channel->Name());
96
97       if (channel->Number() == (int)channelNumber)
98       {
99         int vpid = channel->Vpid();
100         int apid1 = channel->Apid1();
101
102         printf("Found channel number %lu, vpid = %i, apid1 = %i\n", channelNumber, vpid, apid1);
103         return channel;
104       }
105     }
106   }
107
108   if (!channel)
109   {
110     printf("Channel not found\n");
111   }
112
113   return channel;
114 }
115
116
117 void MVPClient::writeResumeData()
118 {
119   config.setValueLongLong("ResumeData", (char*)rp->getCurrentRecording()->FileName(), rp->getLastPosition());
120 }
121
122 void MVPClient::sendULONG(ULONG ul)
123 {
124   unsigned char sendBuffer[8];
125   *(unsigned long*)&sendBuffer[0] = htonl(4);
126   *(unsigned long*)&sendBuffer[4] = htonl(ul);
127
128   tcp.sendPacket(sendBuffer, 8);
129   printf("written ULONG %lu\n", ul);
130 }
131
132 void MVPClientStartThread(void* arg)
133 {
134   MVPClient* m = (MVPClient*)arg;
135   m->run2();
136   // Nothing external to this class has a reference to it
137   // This is the end of the thread.. so delete m
138   delete m;
139   pthread_exit(NULL);
140 }
141
142 int MVPClient::run()
143 {
144   if (pthread_create(&runThread, NULL, (void*(*)(void*))MVPClientStartThread, (void *)this) == -1) return 0;
145   printf("MVPClient run success\n");
146   return 1;
147 }
148
149 void MVPClient::run2()
150 {
151   // Thread stuff
152   sigset_t sigset;
153   sigfillset(&sigset);
154   pthread_sigmask(SIG_BLOCK, &sigset, NULL);
155   pthread_detach(runThread);  // Detach
156
157   tcp.disableReadTimeout();
158
159   tcp.setSoKeepTime(3);
160   tcp.setNonBlocking();
161
162   unsigned char* buffer;
163   unsigned char* data;
164   int packetLength;
165   unsigned long opcode;
166
167   while(1)
168   {
169     printf("starting wait\n");
170     buffer = (unsigned char*)tcp.receivePacket();
171     printf("back from wait\n");
172     if (buffer == NULL)
173     {
174       printf("Detected connection closed\n");
175       break;
176     }
177
178     packetLength = tcp.getDataLength() - 4;
179     opcode = ntohl(*(unsigned long*)buffer);
180     data = buffer + 4;
181
182
183     switch(opcode)
184     {
185       case 1:
186         processLogin(data, packetLength);
187         break;
188       case 2:
189         processGetRecordingsList(data, packetLength);
190         break;
191       case 3:
192         processDeleteRecording(data, packetLength);
193         break;
194       case 4:
195         processGetSummary(data, packetLength);
196         break;
197       case 5:
198         processGetChannelsList(data, packetLength);
199         break;
200       case 6:
201         processStartStreamingChannel(data, packetLength);
202         break;
203       case 7:
204         processGetBlock(data, packetLength);
205         break;
206       case 8:
207         processStopStreaming(data, packetLength);
208         break;
209       case 9:
210         processStartStreamingRecording(data, packetLength);
211         break;
212       case 10:
213         processGetChannelSchedule(data, packetLength);
214         break;
215       case 11:
216         processConfigSave(data, packetLength);
217         break;
218       case 12:
219         processConfigLoad(data, packetLength);
220         break;
221     }
222
223     free(buffer);
224   }
225 }
226
227 void MVPClient::processLogin(unsigned char* buffer, int length)
228 {
229   time_t timeNow = time(NULL);
230   struct tm* timeStruct = localtime(&timeNow);
231   int timeOffset = timeStruct->tm_gmtoff;
232
233   unsigned char sendBuffer[12];
234   *(unsigned long*)&sendBuffer[0] = htonl(8);
235   *(unsigned long*)&sendBuffer[4] = htonl(timeNow);
236   *(signed int*)&sendBuffer[8] = htonl(timeOffset);
237
238   tcp.sendPacket(sendBuffer, 12);
239   printf("written login reply\n");
240 }
241
242 void MVPClient::processGetRecordingsList(unsigned char* data, int length)
243 {
244   unsigned char* sendBuffer = new unsigned char[50000]; // hope this is enough
245   int count = 4; // leave space for the packet length
246   char* point;
247
248
249   int FreeMB;
250   int Percent = VideoDiskSpace(&FreeMB);
251   int Total = (FreeMB / (100 - Percent)) * 100;
252
253   *(unsigned long*)&sendBuffer[count] = htonl(Total);
254   count += sizeof(unsigned long);
255   *(unsigned long*)&sendBuffer[count] = htonl(FreeMB);
256   count += sizeof(unsigned long);
257   *(unsigned long*)&sendBuffer[count] = htonl(Percent);
258   count += sizeof(unsigned long);
259
260
261   cRecordings Recordings;
262   Recordings.Load();
263
264   for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording))
265   {
266     if (count > 49000) break; // just how big is that hard disk?!
267     *(unsigned long*)&sendBuffer[count] = htonl(recording->start);// + timeOffset);
268     count += 4;
269
270     point = (char*)recording->Name();
271     strcpy((char*)&sendBuffer[count], point);
272     count += strlen(point) + 1;
273
274     point = (char*)recording->FileName();
275     strcpy((char*)&sendBuffer[count], point);
276     count += strlen(point) + 1;
277   }
278
279   *(unsigned long*)&sendBuffer[0] = htonl(count - 4); // -4 :  take off the size field
280
281   printf("recorded size as %u\n", ntohl(*(unsigned long*)&sendBuffer[0]));
282
283   tcp.sendPacket(sendBuffer, count);
284   delete[] sendBuffer;
285   printf("Written list\n");
286 }
287
288 void MVPClient::processDeleteRecording(unsigned char* data, int length)
289 {
290   // data is a pointer to the fileName string
291
292   cRecordings Recordings;
293   Recordings.Load(); // probably have to do this
294
295   cRecording* recording = Recordings.GetByName((char*)data);
296
297   printf("recording pointer %p\n", recording);
298
299   if (recording)
300   {
301     printf("deleting recording: %s\n", recording->Name());
302     recording->Delete();
303     sendULONG(1);
304   }
305   else
306   {
307     sendULONG(0);
308   }
309 }
310
311 void MVPClient::processGetSummary(unsigned char* data, int length)
312 {
313   // data is a pointer to the fileName string
314
315   cRecordings Recordings;
316   Recordings.Load(); // probably have to do this
317
318   cRecording* recording = Recordings.GetByName((char*)data);
319
320   printf("recording pointer %p\n", recording);
321
322   if (recording)
323   {
324     unsigned char* sendBuffer = new unsigned char[50000]; // hope this is enough
325     int count = 4; // leave space for the packet length
326
327     char* point;
328
329     point = (char*)recording->Summary();
330     strcpy((char*)&sendBuffer[count], point);
331     count += strlen(point) + 1;
332     *(unsigned long*)&sendBuffer[0] = htonl(count - 4); // -4 :  take off the size field
333
334     printf("recorded size as %u\n", ntohl(*(unsigned long*)&sendBuffer[0]));
335
336     tcp.sendPacket(sendBuffer, count);
337     delete[] sendBuffer;
338     printf("Written summary\n");
339
340
341   }
342   else
343   {
344     sendULONG(0);
345   }
346 }
347
348 void MVPClient::processGetChannelsList(unsigned char* data, int length)
349 {
350   unsigned char* sendBuffer = new unsigned char[50000]; // FIXME hope this is enough
351   int count = 4; // leave space for the packet length
352   char* point;
353   unsigned long type;
354
355   for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
356   {
357     if (!channel->GroupSep())
358     {
359       printf("name: '%s'\n", channel->Name());
360
361       if (count > 49000) break;
362       *(unsigned long*)&sendBuffer[count] = htonl(channel->Number());
363       count += 4;
364
365       if (channel->Vpid()) type = 1;
366       else type = 2;
367
368       *(unsigned long*)&sendBuffer[count] = htonl(type);
369       count += 4;
370
371       point = (char*)channel->Name();
372       strcpy((char*)&sendBuffer[count], point);
373       count += strlen(point) + 1;
374     }
375   }
376
377   *(unsigned long*)&sendBuffer[0] = htonl(count - 4); // -4 :  take off the size field
378
379   printf("recorded size as %u\n", ntohl(*(unsigned long*)&sendBuffer[0]));
380
381   tcp.sendPacket(sendBuffer, count);
382   delete[] sendBuffer;
383   printf("Written channels list\n");
384 }
385
386 void MVPClient::processStartStreamingChannel(unsigned char* data, int length)
387 {
388   printf("length = %i\n", length);
389   unsigned long channelNumber = ntohl(*(unsigned long*)data);
390
391   cChannel* channel = channelFromNumber(channelNumber);
392   if (!channel)
393   {
394     sendULONG(0);
395     return;
396   }
397
398 //  MVPReceiver* m = new MVPReceiver(channel->Vpid(), channel->Apid1());
399   cm = new cMediamvpTransceiver(channel, 0, 0, cDevice::ActualDevice());
400   cDevice::ActualDevice()->AttachReceiver(cm);
401   //cDevice::ActualDevice()->SwitchChannel(channel, false);
402
403   sendULONG(1);
404 }
405
406 void MVPClient::processStopStreaming(unsigned char* data, int length)
407 {
408   printf("STOP STREAMING RECEIVED\n");
409   if (cm)
410   {
411     delete cm;
412     cm = NULL;
413   }
414   else if (rp)
415   {
416     writeResumeData();
417
418     delete rp;
419     delete recordingManager;
420     rp = NULL;
421     recordingManager = NULL;
422   }
423
424   sendULONG(1);
425 }
426
427 void MVPClient::processGetBlock(unsigned char* data, int length)
428 {
429   if (!cm && !rp)
430   {
431     printf("Get block called when no streaming happening!\n");
432     return;
433   }
434
435   ULLONG position = ntohll(*(ULLONG*)data);
436   printf("getblock called for position = %llu\n", position);
437
438   data += sizeof(ULLONG);
439
440   unsigned long amount = ntohl(*(unsigned long*)data);
441   printf("getblock called for length = %lu\n", amount);
442
443   unsigned char sendBuffer[amount + 4];
444   unsigned long amountReceived = 0; // compiler moan.
445   if (cm)
446   {
447     printf("getting from live\n");
448     amountReceived = cm->getBlock(&sendBuffer[4], amount);
449   }
450   else if (rp)
451   {
452     printf("getting from recording\n");
453     amountReceived = rp->getBlock(&sendBuffer[4], position, amount);
454   }
455
456   *(unsigned long*)&sendBuffer[0] = htonl(amountReceived);
457   printf("sendpacket go\n");
458   tcp.sendPacket(sendBuffer, amountReceived + 4);
459   printf("written ok %lu\n", amountReceived);
460 }
461
462 void MVPClient::processStartStreamingRecording(unsigned char* data, int length)
463 {
464   // data is a pointer to the fileName string
465
466   recordingManager = new cRecordings;
467   recordingManager->Load();
468
469   cRecording* recording = recordingManager->GetByName((char*)data);
470
471   printf("recording pointer %p\n", recording);
472
473   if (recording)
474   {
475     rp = new RecPlayer(recording);
476
477     unsigned char sendBuffer[12];
478     *(unsigned long*)&sendBuffer[0] = htonl(8);
479     *(ULLONG*)&sendBuffer[4] = htonll(rp->getTotalLength());
480
481     tcp.sendPacket(sendBuffer, 12);
482     printf("written totalLength\n");
483   }
484   else
485   {
486     delete recordingManager;
487     recordingManager = NULL;
488   }
489 }
490
491 void MVPClient::processGetChannelSchedule(unsigned char* data, int length)
492 {
493   ULONG channelNumber = ntohl(*(ULLONG*)data);
494   printf("get schedule called for channel %lu\n", channelNumber);
495
496   cChannel* channel = channelFromNumber(channelNumber);
497   if (!channel)
498   {
499     unsigned char sendBuffer[4];
500     *(unsigned long*)&sendBuffer[0] = htonl(0);
501     tcp.sendPacket(sendBuffer, 4);
502     printf("written null\n");
503     return;
504   }
505
506   cMutexLock MutexLock;
507   const cSchedules* Schedules = cSIProcessor::Schedules(MutexLock);
508 //  const cSchedules* Schedules = cSchedules::Schedules(MutexLock);
509   if (!Schedules)
510   {
511     unsigned char sendBuffer[8];
512     *(unsigned long*)&sendBuffer[0] = htonl(4);
513     *(unsigned long*)&sendBuffer[4] = htonl(0);
514     tcp.sendPacket(sendBuffer, 8);
515     printf("written 0\n");
516     return;
517   }
518
519   unsigned char sendBuffer[8];
520   *(unsigned long*)&sendBuffer[0] = htonl(4);
521   *(unsigned long*)&sendBuffer[4] = htonl(1);
522   tcp.sendPacket(sendBuffer, 8);
523   printf("written 1\n");
524
525
526 }
527
528 void MVPClient::testChannelSchedule(unsigned char* data, int length)
529 {
530   FILE* f = fopen("/tmp/s.txt", "w");
531
532   cMutexLock MutexLock;
533   const cSchedules* Schedules = cSIProcessor::Schedules(MutexLock);
534 //  const cSchedules* Schedules = cSchedules::Schedules(MutexLock);
535   if (!Schedules)
536   {
537     fprintf(f, "Schedules = NULL\n");
538     fclose(f);
539     return;
540   }
541
542   fprintf(f, "Schedules dump:\n");
543   Schedules->Dump(f);
544
545
546   const cSchedule *Schedule;
547   int scheduleNumber = 0;
548
549   tChannelID tchid;
550   cChannel *thisChannel;
551
552   const cEventInfo* event;
553   int eventNumber = 0;
554
555 //    Schedule = Schedules->GetSchedule(channel->GetChannelID());
556 //    Schedule = Schedules->GetSchedule();
557   Schedule = Schedules->First();
558   if (!Schedule)
559   {
560     fprintf(f, "First Schedule = NULL\n");
561     fclose(f);
562     return;
563   }
564
565   while (Schedule)
566   {
567     fprintf(f, "Schedule #%i\n", scheduleNumber);
568     fprintf(f, "-------------\n\n");
569
570     tchid = Schedule->GetChannelID();
571     fprintf(f, "ChannelID.ToString() = %s\n", tchid.ToString());
572     fprintf(f, "NumEvents() = %i\n", Schedule->NumEvents());
573     thisChannel = Channels.GetByChannelID(tchid, true);
574     if (thisChannel)
575     {
576       fprintf(f, "Channel Number: %p %i\n", thisChannel, thisChannel->Number());
577     }
578     else
579     {
580       fprintf(f, "thisChannel = NULL for tchid\n");
581     }
582
583     for (eventNumber = 0; eventNumber < Schedule->NumEvents(); eventNumber++)
584     {
585       event = Schedule->GetEventNumber(eventNumber);
586       fprintf(f, "Event %i tableid = %i timestring = %s endtimestring = %s\n", eventNumber, event->GetTableID(), event->GetTimeString(), event->GetEndTimeString());
587       fprintf(f, "Event %i date = %s isfollowing = %i ispresent = %i\n", eventNumber, event->GetDate(), event->IsFollowing(), event->IsPresent());
588       fprintf(f, "Event %i extendeddescription = %s\n", eventNumber, event->GetExtendedDescription());
589       fprintf(f, "Event %i subtitle = %s title = %s\n", eventNumber, event->GetSubtitle(), event->GetTitle());
590       fprintf(f, "Event %i eventid = %u duration = %li time = %lu channelnumber = %i\n", eventNumber, event->GetEventID(), event->GetDuration(), event->GetTime(), event->GetChannelNumber());
591       fprintf(f, "Event %u dump:\n", eventNumber);
592       event->Dump(f);
593       fprintf(f, "\n\n");
594     }
595
596
597
598     fprintf(f, "\nDump from object:\n");
599     Schedule->Dump(f);
600     fprintf(f, "\nEND\n");
601
602
603
604
605 /*
606   const cEventInfo *GetPresentEvent(void) const;
607   const cEventInfo *GetFollowingEvent(void) const;
608   const cEventInfo *GetEvent(unsigned short uEventID, time_t tTime = 0) const;
609   const cEventInfo *GetEventAround(time_t tTime) const;
610   const cEventInfo *GetEventNumber(int n) const { return Events.Get(n); }
611
612
613   const unsigned char GetTableID(void) const;
614   const char *GetTimeString(void) const;
615   const char *GetEndTimeString(void) const;
616   const char *GetDate(void) const;
617   bool IsFollowing(void) const;
618   bool IsPresent(void) const;
619   const char *GetExtendedDescription(void) const;
620   const char *GetSubtitle(void) const;
621   const char *GetTitle(void) const;
622   unsigned short GetEventID(void) const;
623   long GetDuration(void) const;
624   time_t GetTime(void) const;
625   tChannelID GetChannelID(void) const;
626   int GetChannelNumber(void) const { return nChannelNumber; }
627   void SetChannelNumber(int ChannelNumber) const { ((cEventInfo *)this)->nChannelNumber = ChannelNumber; } // doesn't modify the EIT data, so it's ok to make it 'const'
628   void Dump(FILE *f, const char *Prefix = "") const;
629
630 */
631
632
633
634
635
636     fprintf(f, "End of current Schedule\n\n\n");
637
638     Schedule = (const cSchedule *)Schedules->Next(Schedule);
639     scheduleNumber++;
640   }
641
642   fclose(f);
643 }
644
645 void MVPClient::processConfigSave(unsigned char* buffer, int length)
646 {
647   char* section = (char*)buffer;
648   char* key = NULL;
649   char* value = NULL;
650
651   for (int k = 0; k < length; k++)
652   {
653     if (buffer[k] == '\0')
654     {
655       if (!key)
656       {
657         key = (char*)&buffer[k+1];
658       }
659       else
660       {
661         value = (char*)&buffer[k+1];
662         break;
663       }
664     }
665   }
666
667   // if the last string (value) doesnt have null terminator, give up
668   if (buffer[length - 1] != '\0') return;
669
670   printf("Config save:\n%s\n%s\n%s\n", section, key, value);
671   if (config.setValueString(section, key, value))
672   {
673     sendULONG(1);
674   }
675   else
676   {
677     sendULONG(0);
678   }
679 }
680
681 void MVPClient::processConfigLoad(unsigned char* buffer, int length)
682 {
683   char* section = (char*)buffer;
684   char* key = NULL;
685
686   for (int k = 0; k < length; k++)
687   {
688     if (buffer[k] == '\0')
689     {
690       key = (char*)&buffer[k+1];
691       break;
692     }
693   }
694
695   char* value = config.getValueString(section, key);
696
697   if (value)
698   {
699     unsigned char sendBuffer[4 + strlen(value) + 1];
700     *(unsigned long*)&sendBuffer[0] = htonl(strlen(value) + 1);
701     strcpy((char*)&sendBuffer[4], value);
702     tcp.sendPacket(sendBuffer, 4 + strlen(value) + 1);
703
704     printf("Written config load packet\n");
705     delete[] value;
706   }
707   else
708   {
709     unsigned char sendBuffer[8];
710     *(unsigned long*)&sendBuffer[0] = htonl(0);
711     *(unsigned long*)&sendBuffer[4] = htonl(0);
712     tcp.sendPacket(sendBuffer, 8);
713
714     printf("Written config load failed packet\n");
715   }
716 }
717
718 void MVPClient::cleanConfig()
719 {
720   printf("Clean config\n");
721
722   cRecordings Recordings;
723   Recordings.Load();
724
725   int numReturns;
726   int length;
727   char* resumes = config.getSectionKeyNames("ResumeData", numReturns, length);
728   char* position = resumes;
729   for(int k = 0; k < numReturns; k++)
730   {
731     printf("EXAMINING: %i %i %p %s\n", k, numReturns, position, position);
732
733     cRecording* recording = Recordings.GetByName(position);
734     if (!recording)
735     {
736       // doesn't exist anymore
737       printf("Found a recording that doesn't exist anymore\n");
738       config.deleteValue("ResumeData", position);
739     }
740     else
741     {
742       printf("This recording still exists\n");
743     }
744
745     position += strlen(position) + 1;
746   }
747
748   delete[] resumes;
749 }
750
751