]> git.vomp.tv Git - vompserver.git/blob - mvpclient.c
Initial import
[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   timeOffset = timeStruct->tm_gmtoff;
232
233   // seems dhcp is sending timezone out to mvp
234   // so just supply utc timestamp
235   timeOffset = 0;
236
237   sendULONG(timeNow + timeOffset);
238   printf("written time\n");
239 }
240
241 void MVPClient::processGetRecordingsList(unsigned char* data, int length)
242 {
243   unsigned char* sendBuffer = new unsigned char[50000]; // hope this is enough
244   int count = 4; // leave space for the packet length
245   char* point;
246
247
248   int FreeMB;
249   int Percent = VideoDiskSpace(&FreeMB);
250   int Total = (FreeMB / (100 - Percent)) * 100;
251
252   *(unsigned long*)&sendBuffer[count] = htonl(Total);
253   count += sizeof(unsigned long);
254   *(unsigned long*)&sendBuffer[count] = htonl(FreeMB);
255   count += sizeof(unsigned long);
256   *(unsigned long*)&sendBuffer[count] = htonl(Percent);
257   count += sizeof(unsigned long);
258
259
260   cRecordings Recordings;
261   Recordings.Load();
262
263   for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording))
264   {
265     if (count > 49000) break; // just how big is that hard disk?!
266     *(unsigned long*)&sendBuffer[count] = htonl(recording->start + timeOffset);
267     count += 4;
268
269     point = (char*)recording->Name();
270     strcpy((char*)&sendBuffer[count], point);
271     count += strlen(point) + 1;
272
273     point = (char*)recording->FileName();
274     strcpy((char*)&sendBuffer[count], point);
275     count += strlen(point) + 1;
276   }
277
278   *(unsigned long*)&sendBuffer[0] = htonl(count - 4); // -4 :  take off the size field
279
280   printf("recorded size as %u\n", ntohl(*(unsigned long*)&sendBuffer[0]));
281
282   tcp.sendPacket(sendBuffer, count);
283   delete[] sendBuffer;
284   printf("Written list\n");
285 }
286
287 void MVPClient::processDeleteRecording(unsigned char* data, int length)
288 {
289   // data is a pointer to the fileName string
290
291   cRecordings Recordings;
292   Recordings.Load(); // probably have to do this
293
294   cRecording* recording = Recordings.GetByName((char*)data);
295
296   printf("recording pointer %p\n", recording);
297
298   if (recording)
299   {
300     printf("deleting recording: %s\n", recording->Name());
301     recording->Delete();
302     sendULONG(1);
303   }
304   else
305   {
306     sendULONG(0);
307   }
308 }
309
310 void MVPClient::processGetSummary(unsigned char* data, int length)
311 {
312   // data is a pointer to the fileName string
313
314   cRecordings Recordings;
315   Recordings.Load(); // probably have to do this
316
317   cRecording* recording = Recordings.GetByName((char*)data);
318
319   printf("recording pointer %p\n", recording);
320
321   if (recording)
322   {
323     unsigned char* sendBuffer = new unsigned char[50000]; // hope this is enough
324     int count = 4; // leave space for the packet length
325
326     char* point;
327
328     point = (char*)recording->Summary();
329     strcpy((char*)&sendBuffer[count], point);
330     count += strlen(point) + 1;
331     *(unsigned long*)&sendBuffer[0] = htonl(count - 4); // -4 :  take off the size field
332
333     printf("recorded size as %u\n", ntohl(*(unsigned long*)&sendBuffer[0]));
334
335     tcp.sendPacket(sendBuffer, count);
336     delete[] sendBuffer;
337     printf("Written summary\n");
338
339
340   }
341   else
342   {
343     sendULONG(0);
344   }
345 }
346
347 void MVPClient::processGetChannelsList(unsigned char* data, int length)
348 {
349   unsigned char* sendBuffer = new unsigned char[50000]; // FIXME hope this is enough
350   int count = 4; // leave space for the packet length
351   char* point;
352   unsigned long type;
353
354   for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
355   {
356     if (!channel->GroupSep())
357     {
358       printf("name: '%s'\n", channel->Name());
359
360       if (count > 49000) break;
361       *(unsigned long*)&sendBuffer[count] = htonl(channel->Number());
362       count += 4;
363
364       if (channel->Vpid()) type = 1;
365       else type = 2;
366
367       *(unsigned long*)&sendBuffer[count] = htonl(type);
368       count += 4;
369
370       point = (char*)channel->Name();
371       strcpy((char*)&sendBuffer[count], point);
372       count += strlen(point) + 1;
373     }
374   }
375
376   *(unsigned long*)&sendBuffer[0] = htonl(count - 4); // -4 :  take off the size field
377
378   printf("recorded size as %u\n", ntohl(*(unsigned long*)&sendBuffer[0]));
379
380   tcp.sendPacket(sendBuffer, count);
381   delete[] sendBuffer;
382   printf("Written channels list\n");
383 }
384
385 void MVPClient::processStartStreamingChannel(unsigned char* data, int length)
386 {
387   printf("length = %i\n", length);
388   unsigned long channelNumber = ntohl(*(unsigned long*)data);
389
390   cChannel* channel = channelFromNumber(channelNumber);
391   if (!channel)
392   {
393     sendULONG(0);
394     return;
395   }
396
397 //  MVPReceiver* m = new MVPReceiver(channel->Vpid(), channel->Apid1());
398   cm = new cMediamvpTransceiver(channel, 0, 0, cDevice::ActualDevice());
399   cDevice::ActualDevice()->AttachReceiver(cm);
400   //cDevice::ActualDevice()->SwitchChannel(channel, false);
401
402   sendULONG(1);
403 }
404
405 void MVPClient::processStopStreaming(unsigned char* data, int length)
406 {
407   printf("STOP STREAMING RECEIVED\n");
408   if (cm)
409   {
410     delete cm;
411     cm = NULL;
412   }
413   else if (rp)
414   {
415     writeResumeData();
416
417     delete rp;
418     delete recordingManager;
419     rp = NULL;
420     recordingManager = NULL;
421   }
422
423   sendULONG(1);
424 }
425
426 void MVPClient::processGetBlock(unsigned char* data, int length)
427 {
428   if (!cm && !rp)
429   {
430     printf("Get block called when no streaming happening!\n");
431     return;
432   }
433
434   ULLONG position = ntohll(*(ULLONG*)data);
435   printf("getblock called for position = %llu\n", position);
436
437   data += sizeof(ULLONG);
438
439   unsigned long amount = ntohl(*(unsigned long*)data);
440   printf("getblock called for length = %lu\n", amount);
441
442   unsigned char sendBuffer[amount + 4];
443   unsigned long amountReceived = 0; // compiler moan.
444   if (cm)
445   {
446     printf("getting from live\n");
447     amountReceived = cm->getBlock(&sendBuffer[4], amount);
448   }
449   else if (rp)
450   {
451     printf("getting from recording\n");
452     amountReceived = rp->getBlock(&sendBuffer[4], position, amount);
453   }
454
455   *(unsigned long*)&sendBuffer[0] = htonl(amountReceived);
456   printf("sendpacket go\n");
457   tcp.sendPacket(sendBuffer, amountReceived + 4);
458   printf("written ok %lu\n", amountReceived);
459 }
460
461 void MVPClient::processStartStreamingRecording(unsigned char* data, int length)
462 {
463   // data is a pointer to the fileName string
464
465   recordingManager = new cRecordings;
466   recordingManager->Load();
467
468   cRecording* recording = recordingManager->GetByName((char*)data);
469
470   printf("recording pointer %p\n", recording);
471
472   if (recording)
473   {
474     rp = new RecPlayer(recording);
475
476     unsigned char sendBuffer[12];
477     *(unsigned long*)&sendBuffer[0] = htonl(8);
478     *(ULLONG*)&sendBuffer[4] = htonll(rp->getTotalLength());
479
480     tcp.sendPacket(sendBuffer, 12);
481     printf("written totalLength\n");
482   }
483   else
484   {
485     delete recordingManager;
486     recordingManager = NULL;
487   }
488 }
489
490 void MVPClient::processGetChannelSchedule(unsigned char* data, int length)
491 {
492   ULONG channelNumber = ntohl(*(ULLONG*)data);
493   printf("get schedule called for channel %lu\n", channelNumber);
494
495   cChannel* channel = channelFromNumber(channelNumber);
496   if (!channel)
497   {
498     unsigned char sendBuffer[4];
499     *(unsigned long*)&sendBuffer[0] = htonl(0);
500     tcp.sendPacket(sendBuffer, 4);
501     printf("written null\n");
502     return;
503   }
504
505   cMutexLock MutexLock;
506   const cSchedules* Schedules = cSIProcessor::Schedules(MutexLock);
507 //  const cSchedules* Schedules = cSchedules::Schedules(MutexLock);
508   if (!Schedules)
509   {
510     unsigned char sendBuffer[8];
511     *(unsigned long*)&sendBuffer[0] = htonl(4);
512     *(unsigned long*)&sendBuffer[4] = htonl(0);
513     tcp.sendPacket(sendBuffer, 8);
514     printf("written 0\n");
515     return;
516   }
517
518   unsigned char sendBuffer[8];
519   *(unsigned long*)&sendBuffer[0] = htonl(4);
520   *(unsigned long*)&sendBuffer[4] = htonl(1);
521   tcp.sendPacket(sendBuffer, 8);
522   printf("written 1\n");
523
524
525 }
526
527 void MVPClient::testChannelSchedule(unsigned char* data, int length)
528 {
529   FILE* f = fopen("/tmp/s.txt", "w");
530
531   cMutexLock MutexLock;
532   const cSchedules* Schedules = cSIProcessor::Schedules(MutexLock);
533 //  const cSchedules* Schedules = cSchedules::Schedules(MutexLock);
534   if (!Schedules)
535   {
536     fprintf(f, "Schedules = NULL\n");
537     fclose(f);
538     return;
539   }
540
541   fprintf(f, "Schedules dump:\n");
542   Schedules->Dump(f);
543
544
545   const cSchedule *Schedule;
546   int scheduleNumber = 0;
547
548   tChannelID tchid;
549   cChannel *thisChannel;
550
551   const cEventInfo* event;
552   int eventNumber = 0;
553
554 //    Schedule = Schedules->GetSchedule(channel->GetChannelID());
555 //    Schedule = Schedules->GetSchedule();
556   Schedule = Schedules->First();
557   if (!Schedule)
558   {
559     fprintf(f, "First Schedule = NULL\n");
560     fclose(f);
561     return;
562   }
563
564   while (Schedule)
565   {
566     fprintf(f, "Schedule #%i\n", scheduleNumber);
567     fprintf(f, "-------------\n\n");
568
569     tchid = Schedule->GetChannelID();
570     fprintf(f, "ChannelID.ToString() = %s\n", tchid.ToString());
571     fprintf(f, "NumEvents() = %i\n", Schedule->NumEvents());
572     thisChannel = Channels.GetByChannelID(tchid, true);
573     if (thisChannel)
574     {
575       fprintf(f, "Channel Number: %p %i\n", thisChannel, thisChannel->Number());
576     }
577     else
578     {
579       fprintf(f, "thisChannel = NULL for tchid\n");
580     }
581
582     for (eventNumber = 0; eventNumber < Schedule->NumEvents(); eventNumber++)
583     {
584       event = Schedule->GetEventNumber(eventNumber);
585       fprintf(f, "Event %i tableid = %i timestring = %s endtimestring = %s\n", eventNumber, event->GetTableID(), event->GetTimeString(), event->GetEndTimeString());
586       fprintf(f, "Event %i date = %s isfollowing = %i ispresent = %i\n", eventNumber, event->GetDate(), event->IsFollowing(), event->IsPresent());
587       fprintf(f, "Event %i extendeddescription = %s\n", eventNumber, event->GetExtendedDescription());
588       fprintf(f, "Event %i subtitle = %s title = %s\n", eventNumber, event->GetSubtitle(), event->GetTitle());
589       fprintf(f, "Event %i eventid = %u duration = %li time = %lu channelnumber = %i\n", eventNumber, event->GetEventID(), event->GetDuration(), event->GetTime(), event->GetChannelNumber());
590       fprintf(f, "Event %u dump:\n", eventNumber);
591       event->Dump(f);
592       fprintf(f, "\n\n");
593     }
594
595
596
597     fprintf(f, "\nDump from object:\n");
598     Schedule->Dump(f);
599     fprintf(f, "\nEND\n");
600
601
602
603
604 /*
605   const cEventInfo *GetPresentEvent(void) const;
606   const cEventInfo *GetFollowingEvent(void) const;
607   const cEventInfo *GetEvent(unsigned short uEventID, time_t tTime = 0) const;
608   const cEventInfo *GetEventAround(time_t tTime) const;
609   const cEventInfo *GetEventNumber(int n) const { return Events.Get(n); }
610
611
612   const unsigned char GetTableID(void) const;
613   const char *GetTimeString(void) const;
614   const char *GetEndTimeString(void) const;
615   const char *GetDate(void) const;
616   bool IsFollowing(void) const;
617   bool IsPresent(void) const;
618   const char *GetExtendedDescription(void) const;
619   const char *GetSubtitle(void) const;
620   const char *GetTitle(void) const;
621   unsigned short GetEventID(void) const;
622   long GetDuration(void) const;
623   time_t GetTime(void) const;
624   tChannelID GetChannelID(void) const;
625   int GetChannelNumber(void) const { return nChannelNumber; }
626   void SetChannelNumber(int ChannelNumber) const { ((cEventInfo *)this)->nChannelNumber = ChannelNumber; } // doesn't modify the EIT data, so it's ok to make it 'const'
627   void Dump(FILE *f, const char *Prefix = "") const;
628
629 */
630
631
632
633
634
635     fprintf(f, "End of current Schedule\n\n\n");
636
637     Schedule = (const cSchedule *)Schedules->Next(Schedule);
638     scheduleNumber++;
639   }
640
641   fclose(f);
642 }
643
644 void MVPClient::processConfigSave(unsigned char* buffer, int length)
645 {
646   char* section = (char*)buffer;
647   char* key = NULL;
648   char* value = NULL;
649
650   for (int k = 0; k < length; k++)
651   {
652     if (buffer[k] == '\0')
653     {
654       if (!key)
655       {
656         key = (char*)&buffer[k+1];
657       }
658       else
659       {
660         value = (char*)&buffer[k+1];
661         break;
662       }
663     }
664   }
665
666   // if the last string (value) doesnt have null terminator, give up
667   if (buffer[length - 1] != '\0') return;
668
669   printf("Config save:\n%s\n%s\n%s\n", section, key, value);
670   if (config.setValueString(section, key, value))
671   {
672     sendULONG(1);
673   }
674   else
675   {
676     sendULONG(0);
677   }
678 }
679
680 void MVPClient::processConfigLoad(unsigned char* buffer, int length)
681 {
682   char* section = (char*)buffer;
683   char* key = NULL;
684
685   for (int k = 0; k < length; k++)
686   {
687     if (buffer[k] == '\0')
688     {
689       key = (char*)&buffer[k+1];
690       break;
691     }
692   }
693
694   char* value = config.getValueString(section, key);
695
696   if (value)
697   {
698     unsigned char sendBuffer[4 + strlen(value) + 1];
699     *(unsigned long*)&sendBuffer[0] = htonl(strlen(value) + 1);
700     strcpy((char*)&sendBuffer[4], value);
701     tcp.sendPacket(sendBuffer, 4 + strlen(value) + 1);
702
703     printf("Written config load packet\n");
704     delete[] value;
705   }
706   else
707   {
708     unsigned char sendBuffer[8];
709     *(unsigned long*)&sendBuffer[0] = htonl(0);
710     *(unsigned long*)&sendBuffer[4] = htonl(0);
711     tcp.sendPacket(sendBuffer, 8);
712
713     printf("Written config load failed packet\n");
714   }
715 }
716
717 void MVPClient::cleanConfig()
718 {
719   printf("Clean config\n");
720
721   cRecordings Recordings;
722   Recordings.Load();
723
724   int numReturns;
725   int length;
726   char* resumes = config.getSectionKeyNames("ResumeData", numReturns, length);
727   char* position = resumes;
728   for(int k = 0; k < numReturns; k++)
729   {
730     printf("EXAMINING: %i %i %p %s\n", k, numReturns, position, position);
731
732     cRecording* recording = Recordings.GetByName(position);
733     if (!recording)
734     {
735       // doesn't exist anymore
736       printf("Found a recording that doesn't exist anymore\n");
737       config.deleteValue("ResumeData", position);
738     }
739     else
740     {
741       printf("This recording still exists\n");
742     }
743
744     position += strlen(position) + 1;
745   }
746
747   delete[] resumes;
748 }
749
750