2 Copyright 2004-2008 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include "vompclient.h"
23 #include "responsepacket.h"
25 #ifndef VOMPSTANDALONE
26 #include <vdr/channels.h>
27 #include <vdr/recording.h>
28 #include "recplayer.h"
29 #include "mvpreceiver.h"
34 pthread_mutex_t threadClientMutex;
35 int VompClient::nr_clients = 0;
38 VompClient::VompClient(Config* cfgBase, char* tconfigDir, int tsocket)
39 : rrproc(*this), tcp(tsocket), i18n(tconfigDir)
41 #ifndef VOMPSTANDALONE
44 recordingManager = NULL;
47 log = Log::getInstance();
49 configDir = tconfigDir;
50 log->log("Client", Log::DEBUG, "Config dir: %s", configDir);
57 VompClient::~VompClient()
59 log->log("Client", Log::DEBUG, "Vomp client destructor");
60 #ifndef VOMPSTANDALONE
71 delete recordingManager;
73 recordingManager = NULL;
76 if (loggedIn) cleanConfig();
80 void VompClient::incClients()
82 pthread_mutex_lock(&threadClientMutex);
83 VompClient::nr_clients++;
84 pthread_mutex_unlock(&threadClientMutex);
87 void VompClient::decClients()
89 pthread_mutex_lock(&threadClientMutex);
90 VompClient::nr_clients--;
91 pthread_mutex_unlock(&threadClientMutex);
94 int VompClient::getNrClients()
97 pthread_mutex_lock(&threadClientMutex);
98 nrClients = VompClient::nr_clients;
99 pthread_mutex_unlock(&threadClientMutex);
104 void VompClient::cleanConfig()
106 log->log("Client", Log::DEBUG, "Clean config");
108 #ifndef VOMPSTANDALONE
110 cRecordings Recordings;
115 char* resumes = config.getSectionKeyNames("ResumeData", numReturns, length);
116 char* position = resumes;
117 for(int k = 0; k < numReturns; k++)
119 log->log("Client", Log::DEBUG, "EXAMINING: %i %i %p %s", k, numReturns, position, position);
121 cRecording* recording = Recordings.GetByName(position);
124 // doesn't exist anymore
125 log->log("Client", Log::DEBUG, "Found a recording that doesn't exist anymore");
126 config.deleteValue("ResumeData", position);
130 log->log("Client", Log::DEBUG, "This recording still exists");
133 position += strlen(position) + 1;
140 void VompClientStartThread(void* arg)
142 VompClient* m = (VompClient*)arg;
144 // Nothing external to this class has a reference to it
145 // This is the end of the thread.. so delete m
150 int VompClient::run()
152 if (pthread_create(&runThread, NULL, (void*(*)(void*))VompClientStartThread, (void *)this) == -1) return 0;
153 log->log("Client", Log::DEBUG, "VompClient run success");
157 void VompClient::run2()
162 pthread_sigmask(SIG_BLOCK, &sigset, NULL);
163 pthread_detach(runThread); // Detach
165 // tcp.disableReadTimeout();
167 // tcp.setSoKeepTime(3);
168 tcp.setNonBlocking();
173 ULONG extraDataLength;
180 log->log("Client", Log::DEBUG, "Waiting");
182 if (!tcp.readData((UCHAR*)&channelID, sizeof(ULONG)))
184 // If this read fails then the client just hasn't sent anything.
185 // If any of the lower reads fail, then break, the connection is probably dead
187 // check connection is ok
188 // if (tcp.isConnected()) continue;
190 log->log("Client", Log::DEBUG, "Disconnection detected");
194 channelID = ntohl(channelID);
197 if (!tcp.readData((UCHAR*)&requestID, sizeof(ULONG))) break;
198 requestID = ntohl(requestID);
200 if (!tcp.readData((UCHAR*)&opcode, sizeof(ULONG))) break;
201 opcode = ntohl(opcode);
203 if (!tcp.readData((UCHAR*)&extraDataLength, sizeof(ULONG))) break;
204 extraDataLength = ntohl(extraDataLength);
205 if (extraDataLength > 200000) // a random sanity limit
207 log->log("Client", Log::ERR, "ExtraDataLength > 200000!");
213 data = (UCHAR*)malloc(extraDataLength);
216 log->log("Client", Log::ERR, "Extra data buffer malloc error");
220 if (!tcp.readData(data, extraDataLength))
222 log->log("Client", Log::ERR, "Could not read extradata");
232 log->log("Client", Log::DEBUG, "Received chan=%lu, ser=%lu, op=%lu, edl=%lu", channelID, requestID, opcode, extraDataLength);
234 if (!loggedIn && (opcode != 1))
236 log->log("Client", Log::ERR, "Not logged in and opcode != 1");
237 if (data) free(data);
241 RequestPacket* req = new RequestPacket(requestID, opcode, data, extraDataLength);
242 rrproc.recvRequest(req);
244 else if (channelID == 3)
246 if (!tcp.readData((UCHAR*)&kaTimeStamp, sizeof(ULONG))) break;
247 kaTimeStamp = ntohl(kaTimeStamp);
249 log->log("Client", Log::DEBUG, "Received chan=%lu kats=%lu", channelID, kaTimeStamp);
252 *(ULONG*)&buffer[0] = htonl(3); // KA CHANNEL
253 *(ULONG*)&buffer[4] = htonl(kaTimeStamp);
254 if (!tcp.sendPacket(buffer, 8))
256 log->log("Client", Log::ERR, "Could not send back KA reply");
262 log->log("Client", Log::ERR, "Incoming channel number unknown");
268 ULLONG VompClient::ntohll(ULLONG a)
273 ULLONG VompClient::htonll(ULLONG a)
275 #if BYTE_ORDER == BIG_ENDIAN
280 b = ((a << 56) & 0xFF00000000000000ULL)
281 | ((a << 40) & 0x00FF000000000000ULL)
282 | ((a << 24) & 0x0000FF0000000000ULL)
283 | ((a << 8) & 0x000000FF00000000ULL)
284 | ((a >> 8) & 0x00000000FF000000ULL)
285 | ((a >> 24) & 0x0000000000FF0000ULL)
286 | ((a >> 40) & 0x000000000000FF00ULL)
287 | ((a >> 56) & 0x00000000000000FFULL) ;
293 #ifndef VOMPSTANDALONE
295 cChannel* VompClient::channelFromNumber(ULONG channelNumber)
297 cChannel* channel = NULL;
299 for (channel = Channels.First(); channel; channel = Channels.Next(channel))
301 if (!channel->GroupSep())
303 log->log("Client", Log::DEBUG, "Looking for channel %lu::: number: %i name: '%s'", channelNumber, channel->Number(), channel->Name());
305 if (channel->Number() == (int)channelNumber)
307 int vpid = channel->Vpid();
308 #if VDRVERSNUM < 10300
309 int apid1 = channel->Apid1();
311 int apid1 = channel->Apid(0);
313 log->log("Client", Log::DEBUG, "Found channel number %lu, vpid = %i, apid1 = %i", channelNumber, vpid, apid1);
321 log->log("Client", Log::DEBUG, "Channel not found");
327 void VompClient::writeResumeData()
329 config.setValueLong("ResumeData",
330 (char*)recplayer->getCurrentRecording()->FileName(),
331 recplayer->frameNumberFromPosition(recplayer->getLastPosition()) );