]> git.vomp.tv Git - vompserver.git/blob - vompclient.c
Version number
[vompserver.git] / vompclient.c
1 /*
2     Copyright 2004-2008 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 "mediaplayer.h"
22 #include "media.h"
23 #include "servermediafile.h"
24 #include "vdrcommand.h"
25 #include "vompclient.h"
26
27 #include "responsepacket.h"
28
29 #ifndef VOMPSTANDALONE
30 #include <vdr/channels.h>
31 #include <vdr/recording.h>
32 #include "recplayer.h"
33 #include "mvpreceiver.h"
34 #endif
35
36
37
38 pthread_mutex_t threadClientMutex;
39 int VompClient::nr_clients = 0;
40
41
42 VompClient::VompClient(Config* cfgBase, char* tconfigDir, int tsocket)
43  : rrproc(*this), tcp(tsocket), i18n(tconfigDir)
44 {
45 #ifndef VOMPSTANDALONE
46   lp = NULL;
47   recplayer = NULL;
48   recordingManager = NULL;
49 #endif
50   log = Log::getInstance();
51   loggedIn = false;
52   configDir = tconfigDir;
53   log->log("Client", Log::DEBUG, "Config dir: %s", configDir);
54   baseConfig = cfgBase;
55   incClients();
56   media=new MediaPlayer();
57   mediaprovider=new ServerMediaFile(cfgBase,media);
58   
59   rrproc.init();
60 }
61
62 VompClient::~VompClient()
63 {
64   log->log("Client", Log::DEBUG, "Vomp client destructor");
65 #ifndef VOMPSTANDALONE  
66   if (lp)
67   {
68     delete lp;
69     lp = NULL;
70   }
71   else if (recplayer)
72   {
73     writeResumeData();
74
75     delete recplayer;
76     delete recordingManager;
77     recplayer = NULL;
78     recordingManager = NULL;
79   }
80 #endif
81   //if (loggedIn) cleanConfig();
82   decClients();
83   
84   delete media;
85   delete mediaprovider;
86 }
87
88 void VompClient::incClients()
89 {
90   pthread_mutex_lock(&threadClientMutex);
91   VompClient::nr_clients++;
92   pthread_mutex_unlock(&threadClientMutex);
93 }
94
95 void VompClient::decClients()
96 {
97   pthread_mutex_lock(&threadClientMutex);
98   VompClient::nr_clients--;
99   pthread_mutex_unlock(&threadClientMutex);
100 }
101
102 int VompClient::getNrClients()
103 {
104   int nrClients;
105   pthread_mutex_lock(&threadClientMutex);
106   nrClients = VompClient::nr_clients;
107   pthread_mutex_unlock(&threadClientMutex);
108   return nrClients;
109 }
110
111 /*
112 void VompClient::cleanConfig()
113 {
114   log->log("Client", Log::DEBUG, "Clean config");
115
116 #ifndef VOMPSTANDALONE
117
118   cRecordings Recordings;
119   Recordings.Load();
120
121   int numReturns;
122   int length;
123   char* resumes = config.getSectionKeyNames("ResumeData", numReturns, length);
124   char* position = resumes;
125   for(int k = 0; k < numReturns; k++)
126   {
127     log->log("Client", Log::DEBUG, "EXAMINING: %i %i %p %s", k, numReturns, position, position);
128
129     cRecording* recording = Recordings.GetByName(position);
130     if (!recording)
131     {
132       // doesn't exist anymore
133       log->log("Client", Log::DEBUG, "Found a recording that doesn't exist anymore");
134       config.deleteValue("ResumeData", position);
135     }
136     else
137     {
138       log->log("Client", Log::DEBUG, "This recording still exists");
139     }
140
141     position += strlen(position) + 1;
142   }
143
144   delete[] resumes;
145 #endif
146 } */
147
148 void VompClientStartThread(void* arg)
149 {
150   VompClient* m = (VompClient*)arg;
151   m->run2();
152   // Nothing external to this class has a reference to it
153   // This is the end of the thread.. so delete m
154   delete m;
155   pthread_exit(NULL);
156 }
157
158 int VompClient::run()
159 {
160   if (pthread_create(&runThread, NULL, (void*(*)(void*))VompClientStartThread, (void *)this) == -1) return 0;
161   log->log("Client", Log::DEBUG, "VompClient run success");
162   return 1;
163 }
164
165 void VompClient::run2()
166 {
167   // Thread stuff
168   sigset_t sigset;
169   sigfillset(&sigset);
170   pthread_sigmask(SIG_BLOCK, &sigset, NULL);
171   pthread_detach(runThread);  // Detach
172
173 //  tcp.disableReadTimeout();
174
175 //  tcp.setSoKeepTime(3);
176   tcp.setNonBlocking();
177
178   ULONG channelID;
179   ULONG requestID;
180   ULONG opcode;
181   ULONG extraDataLength;
182   UCHAR* data;
183   
184   ULONG kaTimeStamp;
185
186   while(1)
187   {
188     log->log("Client", Log::DEBUG, "Waiting");
189     
190     if (!tcp.readData((UCHAR*)&channelID, sizeof(ULONG)))
191     {
192       // If this read fails then the client just hasn't sent anything.
193       // If any of the lower reads fail, then break, the connection is probably dead
194
195       // check connection is ok
196 //      if (tcp.isConnected()) continue;
197       
198       log->log("Client", Log::DEBUG, "Disconnection detected");
199       break;
200     }     
201     
202     channelID = ntohl(channelID);
203     if (channelID == 1)
204     {
205       if (!tcp.readData((UCHAR*)&requestID, sizeof(ULONG))) break;
206       requestID = ntohl(requestID);
207
208       if (!tcp.readData((UCHAR*)&opcode, sizeof(ULONG))) break;
209       opcode = ntohl(opcode);
210
211       if (!tcp.readData((UCHAR*)&extraDataLength, sizeof(ULONG))) break;
212       extraDataLength = ntohl(extraDataLength);
213       if (extraDataLength > 200000) // a random sanity limit
214       {
215         log->log("Client", Log::ERR, "ExtraDataLength > 200000!");
216         break;
217       }
218
219       if (extraDataLength)
220       {
221         data = (UCHAR*)malloc(extraDataLength);
222         if (!data)
223         {
224           log->log("Client", Log::ERR, "Extra data buffer malloc error");
225           break;
226         }
227         
228         if (!tcp.readData(data, extraDataLength))
229         {
230           log->log("Client", Log::ERR, "Could not read extradata");
231           free(data);
232           break;
233         }      
234       }
235       else
236       {
237         data = NULL;
238       }
239
240       log->log("Client", Log::DEBUG, "Received chan=%lu, ser=%lu, op=%lu, edl=%lu", channelID, requestID, opcode, extraDataLength);
241
242       if (!loggedIn && (opcode != 1))
243       {
244         log->log("Client", Log::ERR, "Not logged in and opcode != 1");
245         if (data) free(data);
246         break;
247       }
248
249       RequestPacket* req = new RequestPacket(requestID, opcode, data, extraDataLength);
250       rrproc.recvRequest(req);
251     }
252     else if (channelID == 3)
253     {
254       if (!tcp.readData((UCHAR*)&kaTimeStamp, sizeof(ULONG))) break;
255       kaTimeStamp = ntohl(kaTimeStamp);
256
257       log->log("Client", Log::DEBUG, "Received chan=%lu kats=%lu", channelID, kaTimeStamp);    
258
259       UCHAR buffer[8];
260       *(ULONG*)&buffer[0] = htonl(3); // KA CHANNEL
261       *(ULONG*)&buffer[4] = htonl(kaTimeStamp);
262       if (!tcp.sendPacket(buffer, 8))
263       {
264         log->log("Client", Log::ERR, "Could not send back KA reply");
265         break;
266       }      
267     }
268     else
269     {
270       log->log("Client", Log::ERR, "Incoming channel number unknown");
271       break;
272     }
273   }
274 }
275
276 ULLONG VompClient::ntohll(ULLONG a)
277 {
278   return htonll(a);
279 }
280
281 ULLONG VompClient::htonll(ULLONG a)
282 {
283   #if BYTE_ORDER == BIG_ENDIAN
284     return a;
285   #else
286     ULLONG b = 0;
287
288     b = ((a << 56) & 0xFF00000000000000ULL)
289       | ((a << 40) & 0x00FF000000000000ULL)
290       | ((a << 24) & 0x0000FF0000000000ULL)
291       | ((a <<  8) & 0x000000FF00000000ULL)
292       | ((a >>  8) & 0x00000000FF000000ULL)
293       | ((a >> 24) & 0x0000000000FF0000ULL)
294       | ((a >> 40) & 0x000000000000FF00ULL)
295       | ((a >> 56) & 0x00000000000000FFULL) ;
296
297     return b;
298   #endif
299 }
300
301 #ifndef VOMPSTANDALONE
302
303 cChannel* VompClient::channelFromNumber(ULONG channelNumber)
304 {
305   cChannel* channel = NULL;
306
307   for (channel = Channels.First(); channel; channel = Channels.Next(channel))
308   {
309     if (!channel->GroupSep())
310     {
311       log->log("Client", Log::DEBUG, "Looking for channel %lu::: number: %i name: '%s'", channelNumber, channel->Number(), channel->Name());
312
313       if (channel->Number() == (int)channelNumber)
314       {
315         int vpid = channel->Vpid();
316 #if VDRVERSNUM < 10300
317         int apid1 = channel->Apid1();
318 #else
319         int apid1 = channel->Apid(0);
320 #endif
321         log->log("Client", Log::DEBUG, "Found channel number %lu, vpid = %i, apid1 = %i", channelNumber, vpid, apid1);
322         return channel;
323       }
324     }
325   }
326
327   if (!channel)
328   {
329     log->log("Client", Log::DEBUG, "Channel not found");
330   }
331
332   return channel;
333 }
334
335 void VompClient::writeResumeData()
336 {
337   /*config.setValueLong("ResumeData",
338                           (char*)recplayer->getCurrentRecording()->FileName(),
339                           recplayer->frameNumberFromPosition(recplayer->getLastPosition()) );*/
340
341   /* write to vdr resume file */
342   int resume = recplayer->frameNumberFromPosition(recplayer->getLastPosition());
343   char* ResumeIdC = config.getValueString("General", "ResumeId");
344   int ResumeId;
345   if (ResumeIdC)
346     ResumeId = atoi(ResumeIdC);
347   else
348     ResumeId = 0;
349
350   while (ResumeIDLock)
351           cCondWait::SleepMs(100);
352   ResumeIDLock = true;
353   int OldSetupResumeID = Setup.ResumeID;
354   Setup.ResumeID = ResumeId;                            //UGLY: quickly change resumeid
355 #if VDRVERSNUM < 10703
356   cResumeFile ResumeFile((char*)recplayer->getCurrentRecording()->FileName());  //get corresponding resume file
357 #else
358   cResumeFile ResumeFile((char*)recplayer->getCurrentRecording()->FileName(),(char*)recplayer->getCurrentRecording()->IsPesRecording());        //get corresponding resume file
359 #endif
360   Setup.ResumeID = OldSetupResumeID;                    //and restore it back
361   ResumeIDLock = false;
362   ResumeFile.Save(resume);
363   //isyslog("VOMPDEBUG: Saving resume = %i, ResumeId = %i",resume, ResumeId);
364 }
365
366 #endif
367