2 Copyright 2004-2005 Chris Tallon
4 This file is part of VOMP.
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.
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.
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
21 #include "mvpclient.h"
23 MVPClient::MVPClient(int tsocket)
28 recordingManager = NULL;
30 // Get IP address of client for config module
33 struct sockaddr_in peer;
34 socklen_t salen = sizeof(struct sockaddr);
35 if(getpeername(tsocket, (struct sockaddr*)&peer, &salen) == 0)
37 strcpy(ipa, inet_ntoa(peer.sin_addr));
42 printf("Cannot get peer name!\n");
45 const char* configDir = cPlugin::ConfigDirectory();
48 printf("No config dir!\n");
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);
56 printf("Config file name: %s\n", configFileName);
58 // processGetChannelSchedule(NULL, 0);
65 MVPClient::~MVPClient()
67 printf("MVP client destructor\n");
79 delete recordingManager;
81 recordingManager = NULL;
87 cChannel* MVPClient::channelFromNumber(unsigned long channelNumber)
89 cChannel* channel = NULL;
91 for (channel = Channels.First(); channel; channel = Channels.Next(channel))
93 if (!channel->GroupSep())
95 printf("Looking for channel %lu::: number: %i name: '%s'\n", channelNumber, channel->Number(), channel->Name());
97 if (channel->Number() == (int)channelNumber)
99 int vpid = channel->Vpid();
100 int apid1 = channel->Apid1();
102 printf("Found channel number %lu, vpid = %i, apid1 = %i\n", channelNumber, vpid, apid1);
110 printf("Channel not found\n");
117 void MVPClient::writeResumeData()
119 config.setValueLongLong("ResumeData", (char*)rp->getCurrentRecording()->FileName(), rp->getLastPosition());
122 void MVPClient::sendULONG(ULONG ul)
124 unsigned char sendBuffer[8];
125 *(unsigned long*)&sendBuffer[0] = htonl(4);
126 *(unsigned long*)&sendBuffer[4] = htonl(ul);
128 tcp.sendPacket(sendBuffer, 8);
129 printf("written ULONG %lu\n", ul);
132 void MVPClientStartThread(void* arg)
134 MVPClient* m = (MVPClient*)arg;
136 // Nothing external to this class has a reference to it
137 // This is the end of the thread.. so delete m
144 if (pthread_create(&runThread, NULL, (void*(*)(void*))MVPClientStartThread, (void *)this) == -1) return 0;
145 printf("MVPClient run success\n");
149 void MVPClient::run2()
154 pthread_sigmask(SIG_BLOCK, &sigset, NULL);
155 pthread_detach(runThread); // Detach
157 tcp.disableReadTimeout();
159 tcp.setSoKeepTime(3);
160 tcp.setNonBlocking();
162 unsigned char* buffer;
165 unsigned long opcode;
169 printf("starting wait\n");
170 buffer = (unsigned char*)tcp.receivePacket();
171 printf("back from wait\n");
174 printf("Detected connection closed\n");
178 packetLength = tcp.getDataLength() - 4;
179 opcode = ntohl(*(unsigned long*)buffer);
186 processLogin(data, packetLength);
189 processGetRecordingsList(data, packetLength);
192 processDeleteRecording(data, packetLength);
195 processGetSummary(data, packetLength);
198 processGetChannelsList(data, packetLength);
201 processStartStreamingChannel(data, packetLength);
204 processGetBlock(data, packetLength);
207 processStopStreaming(data, packetLength);
210 processStartStreamingRecording(data, packetLength);
213 processGetChannelSchedule(data, packetLength);
216 processConfigSave(data, packetLength);
219 processConfigLoad(data, packetLength);
227 void MVPClient::processLogin(unsigned char* buffer, int length)
229 time_t timeNow = time(NULL);
230 struct tm* timeStruct = localtime(&timeNow);
231 int timeOffset = timeStruct->tm_gmtoff;
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);
238 tcp.sendPacket(sendBuffer, 12);
239 printf("written login reply\n");
242 void MVPClient::processGetRecordingsList(unsigned char* data, int length)
244 unsigned char* sendBuffer = new unsigned char[50000]; // hope this is enough
245 int count = 4; // leave space for the packet length
250 int Percent = VideoDiskSpace(&FreeMB);
251 int Total = (FreeMB / (100 - Percent)) * 100;
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);
261 cRecordings Recordings;
264 for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording))
266 if (count > 49000) break; // just how big is that hard disk?!
267 *(unsigned long*)&sendBuffer[count] = htonl(recording->start);// + timeOffset);
270 point = (char*)recording->Name();
271 strcpy((char*)&sendBuffer[count], point);
272 count += strlen(point) + 1;
274 point = (char*)recording->FileName();
275 strcpy((char*)&sendBuffer[count], point);
276 count += strlen(point) + 1;
279 *(unsigned long*)&sendBuffer[0] = htonl(count - 4); // -4 : take off the size field
281 printf("recorded size as %u\n", ntohl(*(unsigned long*)&sendBuffer[0]));
283 tcp.sendPacket(sendBuffer, count);
285 printf("Written list\n");
288 void MVPClient::processDeleteRecording(unsigned char* data, int length)
290 // data is a pointer to the fileName string
292 cRecordings Recordings;
293 Recordings.Load(); // probably have to do this
295 cRecording* recording = Recordings.GetByName((char*)data);
297 printf("recording pointer %p\n", recording);
301 printf("deleting recording: %s\n", recording->Name());
311 void MVPClient::processGetSummary(unsigned char* data, int length)
313 // data is a pointer to the fileName string
315 cRecordings Recordings;
316 Recordings.Load(); // probably have to do this
318 cRecording* recording = Recordings.GetByName((char*)data);
320 printf("recording pointer %p\n", recording);
324 unsigned char* sendBuffer = new unsigned char[50000]; // hope this is enough
325 int count = 4; // leave space for the packet length
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
334 printf("recorded size as %u\n", ntohl(*(unsigned long*)&sendBuffer[0]));
336 tcp.sendPacket(sendBuffer, count);
338 printf("Written summary\n");
348 void MVPClient::processGetChannelsList(unsigned char* data, int length)
350 unsigned char* sendBuffer = new unsigned char[50000]; // FIXME hope this is enough
351 int count = 4; // leave space for the packet length
355 for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
357 if (!channel->GroupSep())
359 printf("name: '%s'\n", channel->Name());
361 if (count > 49000) break;
362 *(unsigned long*)&sendBuffer[count] = htonl(channel->Number());
365 if (channel->Vpid()) type = 1;
368 *(unsigned long*)&sendBuffer[count] = htonl(type);
371 point = (char*)channel->Name();
372 strcpy((char*)&sendBuffer[count], point);
373 count += strlen(point) + 1;
377 *(unsigned long*)&sendBuffer[0] = htonl(count - 4); // -4 : take off the size field
379 printf("recorded size as %u\n", ntohl(*(unsigned long*)&sendBuffer[0]));
381 tcp.sendPacket(sendBuffer, count);
383 printf("Written channels list\n");
386 void MVPClient::processStartStreamingChannel(unsigned char* data, int length)
388 printf("length = %i\n", length);
389 unsigned long channelNumber = ntohl(*(unsigned long*)data);
391 cChannel* channel = channelFromNumber(channelNumber);
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);
406 void MVPClient::processStopStreaming(unsigned char* data, int length)
408 printf("STOP STREAMING RECEIVED\n");
419 delete recordingManager;
421 recordingManager = NULL;
427 void MVPClient::processGetBlock(unsigned char* data, int length)
431 printf("Get block called when no streaming happening!\n");
435 ULLONG position = ntohll(*(ULLONG*)data);
436 printf("getblock called for position = %llu\n", position);
438 data += sizeof(ULLONG);
440 unsigned long amount = ntohl(*(unsigned long*)data);
441 printf("getblock called for length = %lu\n", amount);
443 unsigned char sendBuffer[amount + 4];
444 unsigned long amountReceived = 0; // compiler moan.
447 printf("getting from live\n");
448 amountReceived = cm->getBlock(&sendBuffer[4], amount);
452 printf("getting from recording\n");
453 amountReceived = rp->getBlock(&sendBuffer[4], position, amount);
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);
462 void MVPClient::processStartStreamingRecording(unsigned char* data, int length)
464 // data is a pointer to the fileName string
466 recordingManager = new cRecordings;
467 recordingManager->Load();
469 cRecording* recording = recordingManager->GetByName((char*)data);
471 printf("recording pointer %p\n", recording);
475 rp = new RecPlayer(recording);
477 unsigned char sendBuffer[12];
478 *(unsigned long*)&sendBuffer[0] = htonl(8);
479 *(ULLONG*)&sendBuffer[4] = htonll(rp->getTotalLength());
481 tcp.sendPacket(sendBuffer, 12);
482 printf("written totalLength\n");
486 delete recordingManager;
487 recordingManager = NULL;
491 void MVPClient::processGetChannelSchedule(unsigned char* data, int length)
493 ULONG channelNumber = ntohl(*(ULLONG*)data);
494 printf("get schedule called for channel %lu\n", channelNumber);
496 cChannel* channel = channelFromNumber(channelNumber);
499 unsigned char sendBuffer[4];
500 *(unsigned long*)&sendBuffer[0] = htonl(0);
501 tcp.sendPacket(sendBuffer, 4);
502 printf("written null\n");
506 cMutexLock MutexLock;
507 const cSchedules* Schedules = cSIProcessor::Schedules(MutexLock);
508 // const cSchedules* Schedules = cSchedules::Schedules(MutexLock);
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");
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");
528 void MVPClient::testChannelSchedule(unsigned char* data, int length)
530 FILE* f = fopen("/tmp/s.txt", "w");
532 cMutexLock MutexLock;
533 const cSchedules* Schedules = cSIProcessor::Schedules(MutexLock);
534 // const cSchedules* Schedules = cSchedules::Schedules(MutexLock);
537 fprintf(f, "Schedules = NULL\n");
542 fprintf(f, "Schedules dump:\n");
546 const cSchedule *Schedule;
547 int scheduleNumber = 0;
550 cChannel *thisChannel;
552 const cEventInfo* event;
555 // Schedule = Schedules->GetSchedule(channel->GetChannelID());
556 // Schedule = Schedules->GetSchedule();
557 Schedule = Schedules->First();
560 fprintf(f, "First Schedule = NULL\n");
567 fprintf(f, "Schedule #%i\n", scheduleNumber);
568 fprintf(f, "-------------\n\n");
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);
576 fprintf(f, "Channel Number: %p %i\n", thisChannel, thisChannel->Number());
580 fprintf(f, "thisChannel = NULL for tchid\n");
583 for (eventNumber = 0; eventNumber < Schedule->NumEvents(); eventNumber++)
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);
598 fprintf(f, "\nDump from object:\n");
600 fprintf(f, "\nEND\n");
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); }
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;
636 fprintf(f, "End of current Schedule\n\n\n");
638 Schedule = (const cSchedule *)Schedules->Next(Schedule);
645 void MVPClient::processConfigSave(unsigned char* buffer, int length)
647 char* section = (char*)buffer;
651 for (int k = 0; k < length; k++)
653 if (buffer[k] == '\0')
657 key = (char*)&buffer[k+1];
661 value = (char*)&buffer[k+1];
667 // if the last string (value) doesnt have null terminator, give up
668 if (buffer[length - 1] != '\0') return;
670 printf("Config save:\n%s\n%s\n%s\n", section, key, value);
671 if (config.setValueString(section, key, value))
681 void MVPClient::processConfigLoad(unsigned char* buffer, int length)
683 char* section = (char*)buffer;
686 for (int k = 0; k < length; k++)
688 if (buffer[k] == '\0')
690 key = (char*)&buffer[k+1];
695 char* value = config.getValueString(section, key);
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);
704 printf("Written config load packet\n");
709 unsigned char sendBuffer[8];
710 *(unsigned long*)&sendBuffer[0] = htonl(0);
711 *(unsigned long*)&sendBuffer[4] = htonl(0);
712 tcp.sendPacket(sendBuffer, 8);
714 printf("Written config load failed packet\n");
718 void MVPClient::cleanConfig()
720 printf("Clean config\n");
722 cRecordings Recordings;
727 char* resumes = config.getSectionKeyNames("ResumeData", numReturns, length);
728 char* position = resumes;
729 for(int k = 0; k < numReturns; k++)
731 printf("EXAMINING: %i %i %p %s\n", k, numReturns, position, position);
733 cRecording* recording = Recordings.GetByName(position);
736 // doesn't exist anymore
737 printf("Found a recording that doesn't exist anymore\n");
738 config.deleteValue("ResumeData", position);
742 printf("This recording still exists\n");
745 position += strlen(position) + 1;