From 7ca8c63c6bdba8fea1f832bceb845b8b977aeb26 Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Sun, 18 Nov 2007 17:14:19 +0000 Subject: [PATCH] Change to thread sleep type waits in VDR --- eventdispatcher.cc | 182 +++++++++++++++++++++++++++++++++++++++++++ eventdispatcher.h | 90 +++++++++++++++++++++ vdr.cc | 166 ++++++++++++++++++++++++++++----------- vdr.h | 33 +++++++- vdrrequestpacket.cc | 11 ++- vdrrequestpacket.h | 7 +- vdrresponsepacket.cc | 2 +- vdrresponsepacket.h | 1 + 8 files changed, 442 insertions(+), 50 deletions(-) create mode 100644 eventdispatcher.cc create mode 100644 eventdispatcher.h diff --git a/eventdispatcher.cc b/eventdispatcher.cc new file mode 100644 index 0000000..08efeb3 --- /dev/null +++ b/eventdispatcher.cc @@ -0,0 +1,182 @@ +/* + Copyright 2007 Chris Tallon + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "eventdispatcher.h" + +EventDispatcher::EventDispatcher() +{ +#ifndef WIN32 + pthread_mutex_init(&mutex, NULL); +#else + mutex = CreateMutex(NULL, FALSE, NULL); +#endif +} + +void EventDispatcher::edRegister(EDReceiver* edr) +{ + edLock(); + receivers.push_back(edr); + edUnlock(); +} + +bool EventDispatcher::edFindAndCall(void* userTag) +{ + edLock(); + + EDReceiver* edr; + EDRL::iterator i; + for(i = receivers.begin(); i != receivers.end(); i++) + { + if (ed_cb_find(*i, userTag)) + { + edr = *i; + break; // found (by asking the EventDispatcher implementor to check if userTag is for *i + } + } + + if ((i == receivers.end()) || edr->callinprogress || edr->nomorecalls) + { + edUnlock(); + return false; + } + + edr->callinprogress = true; + edUnlock(); + bool edrType = edr->call(userTag); + edLock(); + edr->callinprogress = false; + + if (edrType == false) // it's a multicall + { + if (edr->nomorecalls) // External has called unRegister - probably the receiver + { + // wake up the thread waiting in unregister + #ifndef WIN32 + pthread_cond_signal(&edr->cond); + #else + // FIXME + #endif + } + } + else // It's a single call. The receiver should be removed from the list. There will be a thread to wake up + { + for(i = receivers.begin(); i != receivers.end(); i++) + { + if (*i == edr) + { + receivers.erase(i); + break; + } + } + if (i == receivers.end()) abort(); // should never happen + + #ifndef WIN32 + pthread_cond_signal(&edr->cond); + #else + // FIXME + #endif + } + + edUnlock(); + return true; +} + +void EventDispatcher::edUnregister(EDReceiver* edr) +{ + edLock(); + + EDRL::iterator i; + for(i = receivers.begin(); i != receivers.end(); i++) + { + if (*i == edr) break; // found + } + + if (i == receivers.end()) abort(); // should never happen + + if (!edr->callinprogress) + { + receivers.erase(i); + edUnlock(); + return; + } + + edr->nomorecalls = true; + + // edUnlock, wait for callinprogres=false (cond to be signalled), lock +#ifndef WIN32 + pthread_cond_wait(&edr->cond, &mutex); +#else + // FIXME +#endif + + for(i = receivers.begin(); i != receivers.end(); i++) + { + if (*i == edr) break; // found + } + + if (i == receivers.end()) abort(); // should never happen + + receivers.erase(i); + edUnlock(); +} + +// --------------------------------------- + +void EventDispatcher::edLock() +{ +#ifndef WIN32 + pthread_mutex_lock(&mutex); +#else + WaitForSingleObject(mutex, INFINITE); +#endif +} + +void EventDispatcher::edUnlock() +{ +#ifndef WIN32 + pthread_mutex_unlock(&mutex); +#else + ReleaseMutex(mutex); +#endif +} + +// --------------------------------------- + +void EventDispatcher::edSleepThisReceiver(EDReceiver* edr) +{ + // For blocking version, not callback version. Call with edLock locked + +#ifndef WIN32 + pthread_cond_init(&edr->cond, NULL); + pthread_cond_wait(&edr->cond, &mutex); +#else + // FIXME +#endif +} + +// -------------- EDReceiver implementation + +EDReceiver::EDReceiver() +{ + nomorecalls = false; + callinprogress = false; +} + + diff --git a/eventdispatcher.h b/eventdispatcher.h new file mode 100644 index 0000000..9f32160 --- /dev/null +++ b/eventdispatcher.h @@ -0,0 +1,90 @@ +/* + Copyright 2007 Chris Tallon + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef EVENTDISPATCHER_H +#define EVENTDISPATCHER_H + +#include +#include + +#ifndef WIN32 +#include "threadp.h" +#else +#include "threadwin.h" +#endif + +#include "defines.h" + +using namespace std; + + +class EDReceiver //(implementation in eventdispatcher.cc) +{ + friend class EventDispatcher; + + public: + EDReceiver(); + virtual ~EDReceiver() {}; + + protected: + virtual bool call(void* userTag)=0; // Implementor must override this and do the actual call + // return true to have EventDispatcher remove receiver from list after call + bool nomorecalls; + bool callinprogress; + +#ifndef WIN32 + pthread_cond_t cond; +#else + // FIXME +#endif +}; + +class EventDispatcher +{ + typedef list EDRL; + + public: + EventDispatcher(); + virtual ~EventDispatcher() {}; + + protected: + void edRegister(EDReceiver* edr); + void edUnregister(EDReceiver* edr); + bool edFindAndCall(void* userTag); + void edLock(); + void edUnlock(); + void edSleepThisReceiver(EDReceiver* edr); + + // EventDispatcher implementor must override the following. When edFindAndCall is called, + // The EventDispatcher class will call ed_cb_find() on each receiver until the implementor + // returns true = this is the receiver to call. + virtual bool ed_cb_find(EDReceiver* edr, void* userTag)=0; + + private: + EDRL receivers; + +#ifndef WIN32 + pthread_mutex_t mutex; +#else + HANDLE mutex; +#endif +}; + +#endif diff --git a/vdr.cc b/vdr.cc index 00aba3b..bfb281d 100644 --- a/vdr.cc +++ b/vdr.cc @@ -171,6 +171,7 @@ int VDR::connect() if (tcp->connectTo(serverIP, 3024)) { connected = true; + threadStart(); return 1; } else @@ -181,6 +182,7 @@ int VDR::connect() void VDR::disconnect() { + threadCancel(); if (tcp) delete tcp; tcp = NULL; connected = false; @@ -196,42 +198,118 @@ void VDR::setReceiveWindow(size_t size) void VDR::threadMethod() { + threadSetKillable(); + + UCHAR* packet; + ULONG packetLength; + VDR_ResponsePacket* vresp; + + while(1) + { + packet = (UCHAR*)tcp->receivePacket(); // cancellation point + + vresp = new VDR_ResponsePacket(); + if (packet) + { + packetLength = (ULONG)tcp->getDataLength(); + vresp->set(packet, packetLength); + } + + if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() ) + { + // If edFindAndCall returns true, edr was called and vresp was handed off. + // else, delete vresp here. + delete vresp; + } + + // Who deletes vresp? + // If RR, the individual protocol functions must delete vresp. + // If stream, the data and length is taken out in ed_cb_call and vresp is deleted there. + } +} + +bool VDR::ed_cb_find(EDReceiver* edr, void* userTag) +{ + // edr is a VDR_PacketReceiver object made in VDR::RequestResponse + // userTag is a VDR_ResponsePacket made in threadMethod + + VDR_PacketReceiver* vdrpr = (VDR_PacketReceiver*)edr; + VDR_ResponsePacket* vresp = (VDR_ResponsePacket*)userTag; + + // Is vresp for vdrpr ? + + // Not written yet. will be true + if (vdrpr); + if (vresp); + + return true; } VDR_ResponsePacket* VDR::RequestResponse(VDR_RequestPacket* vrp) { logger->log("VDR", Log::DEBUG, "RR"); - MUTEX_LOCK(&mutex); - + if (!connected) { - MUTEX_UNLOCK(&mutex); - return NULL; + VDR_ResponsePacket* vresp = new VDR_ResponsePacket(); + return vresp; // "no-response" return } - waitingRequestThread = Thread_TYPE::thisThreadID(); + // ED make new VDR and register + // make a VDR_PacketReceiver + // - init with serial number of request packet + + VDR_PacketReceiver* vdrpr = new VDR_PacketReceiver(); + vdrpr->receiverChannel = VDR::CHANNEL_REQUEST_RESPONSE; + vdrpr->requestSerialNumber = vrp->getSerial(); + edRegister(vdrpr); + + edLock(); if ((ULONG)tcp->sendPacket(vrp->getPtr(), vrp->getLen()) != vrp->getLen()) { - disconnect(); - MUTEX_UNLOCK(&mutex); - return NULL; + edUnlock(); + VDR_ResponsePacket* vresp = new VDR_ResponsePacket(); + return vresp; // "no-response" return } - UCHAR* packet = (UCHAR*)tcp->receivePacket(); - if (!packet) - { - disconnect(); - MUTEX_UNLOCK(&mutex); - return NULL; - } - ULONG packetLength = (ULONG)tcp->getDataLength(); + // Sleep and block this thread. The sleep unlocks the mutex + logger->log("VDR", Log::DEBUG, "RR sleep"); + edSleepThisReceiver(vdrpr); + logger->log("VDR", Log::DEBUG, "RR unsleep"); + + // Woken because a response packet has arrived, mutex will be locked - MUTEX_UNLOCK(&mutex); + edUnlock(); - VDR_ResponsePacket* vresp = new VDR_ResponsePacket(); - vresp->set(packet, packetLength); + VDR_ResponsePacket* toReturn = vdrpr->save_vresp; + delete vdrpr; + return toReturn; +} + +///////////////////////////////////////////////////////////////////////////// + +// Here VDR takes a break for the VDR_PacketReceiver helper class + +bool VDR_PacketReceiver::call(void* userTag) +{ + if (receiverChannel == VDR::CHANNEL_REQUEST_RESPONSE) + { + // It's a RR. Save vresp and, signal the waiting thread and return. + // VDR::RequestResponse will be blocking waiting for this to happen. + // That function has a pointer to this object and can read save_vresp. + save_vresp = (VDR_ResponsePacket*)userTag; + return true; // Signals ED to remove edr from receivers and wake up edr thread + } - return vresp; + if (receiverChannel == VDR::CHANNEL_STREAM) + { + // It's a stream packet. + streamReceiver->receiveData(NULL, 0); + delete (VDR_ResponsePacket*)userTag; + return false; + } + + abort(); // unknown receiverChannel, should not happen } ///////////////////////////////////////////////////////////////////////////// @@ -246,7 +324,7 @@ int VDR::doLogin() if (!vrp.copyin((UCHAR*)mactemp, 6)) return 0; VDR_ResponsePacket* vresp = RequestResponse(&vrp); - if (!vresp) return 0; + if (vresp->noResponse()) { delete vresp; return 0; } ULONG vdrTime = vresp->extractULONG(); logger->log("VDR", Log::DEBUG, "vdrtime = %lu", vdrTime); @@ -299,7 +377,7 @@ bool VDR::getRecordingsList(RecMan* recman) if (!vrp.init(VDR_GETRECORDINGLIST, true, 0)) return false; VDR_ResponsePacket* vresp = RequestResponse(&vrp); - if (!vresp) return false; + if (vresp->noResponse()) { delete vresp; return false; } ULONG totalSpace = vresp->extractULONG(); ULONG freeSpace = vresp->extractULONG(); @@ -334,7 +412,7 @@ int VDR::deleteRecording(char* fileName) if (!vrp.addString(fileName)) return 0; VDR_ResponsePacket* vresp = RequestResponse(&vrp); - if (!vresp) return 0; + if (vresp->noResponse()) { delete vresp; return 0; } int toReturn = (int)vresp->extractULONG(); delete vresp; @@ -350,7 +428,7 @@ char* VDR::moveRecording(char* fileName, char* newPath) if (!vrp.addString(newPath)) return NULL; VDR_ResponsePacket* vresp = RequestResponse(&vrp); - if (!vresp) return NULL; + if (vresp->noResponse()) { delete vresp; return NULL; } char* toReturn = NULL; int success = (int)vresp->extractULONG(); @@ -370,7 +448,7 @@ ChannelList* VDR::getChannelsList(ULONG type) if (!vrp.init(VDR_GETCHANNELLIST, true, 0)) return NULL; VDR_ResponsePacket* vresp = RequestResponse(&vrp); - if (!vresp) return NULL; + if (vresp->noResponse()) { delete vresp; return NULL; } ChannelList* chanList = new ChannelList(); @@ -418,7 +496,7 @@ int VDR::streamChannel(ULONG number) if (!vrp.addULONG(number)) return 0; VDR_ResponsePacket* vresp = RequestResponse(&vrp); - if (!vresp) return 0; + if (vresp->noResponse()) { delete vresp; return 0; } int toReturn = (int)vresp->extractULONG(); delete vresp; @@ -432,7 +510,7 @@ int VDR::stopStreaming() if (!vrp.init(VDR_STOPSTREAMING, true, 0)) return 0; VDR_ResponsePacket* vresp = RequestResponse(&vrp); - if (!vresp) return 0; + if (vresp->noResponse()) { delete vresp; return 0; } int toReturn = (int)vresp->extractULONG(); delete vresp; @@ -458,7 +536,7 @@ UCHAR* VDR::getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived, ULON if (!vrp.addULONG(maxAmount)) return NULL; VDR_ResponsePacket* vresp = RequestResponse(&vrp); - if (!vresp) return NULL; + if (vresp->noResponse()) { delete vresp; return NULL; } if (vresp->serverError()) { @@ -483,7 +561,7 @@ ULLONG VDR::streamRecording(char* fileName, ULONG* totalFrames) if (!vrp.addString(fileName)) return 0; VDR_ResponsePacket* vresp = RequestResponse(&vrp); - if (!vresp) return 0; + if (vresp->noResponse()) { delete vresp; return 0; } ULLONG lengthBytes = vresp->extractULLONG(); ULONG lengthFrames = vresp->extractULONG(); @@ -502,7 +580,7 @@ ULLONG VDR::positionFromFrameNumber(ULONG frameNumber) if (!vrp.addULONG(frameNumber)) return 0; VDR_ResponsePacket* vresp = RequestResponse(&vrp); - if (!vresp) return 0; + if (vresp->noResponse()) { delete vresp; return 0; } ULLONG position = vresp->extractULLONG(); delete vresp; @@ -519,7 +597,7 @@ ULONG VDR::frameNumberFromPosition(ULLONG position) if (!vrp.addULLONG(position)) return 0; VDR_ResponsePacket* vresp = RequestResponse(&vrp); - if (!vresp) return 0; + if (vresp->noResponse()) { delete vresp; return 0; } ULONG framenumber = vresp->extractULONG(); delete vresp; @@ -537,7 +615,7 @@ bool VDR::getNextIFrame(ULONG frameNumber, ULONG direction, ULLONG* rfilePositio if (!vrp.addULONG(direction)) return false; VDR_ResponsePacket* vresp = RequestResponse(&vrp); - if (!vresp) return false; + if (vresp->noResponse()) { delete vresp; return false; } if (vresp->serverError()) { @@ -575,7 +653,7 @@ EventList* VDR::getChannelSchedule(ULONG number, time_t start, ULONG duration) if (!vrp.addULONG(duration)) return NULL; VDR_ResponsePacket* vresp = RequestResponse(&vrp); - if (!vresp) return NULL; + if (vresp->noResponse()) { delete vresp; return NULL; } // received a ulong(0) - schedules error in the plugin if (vresp->serverError()) @@ -613,7 +691,7 @@ int VDR::configSave(const char* section, const char* key, const char* value) if (!vrp.addString(value)) return 0; VDR_ResponsePacket* vresp = RequestResponse(&vrp); - if (!vresp) return 0; + if (vresp->noResponse()) { delete vresp; return 0; } int toReturn = (int)vresp->extractULONG(); delete vresp; @@ -629,7 +707,7 @@ char* VDR::configLoad(const char* section, const char* key) if (!vrp.addString(key)) return NULL; VDR_ResponsePacket* vresp = RequestResponse(&vrp); - if (!vresp) return NULL; + if (vresp->noResponse()) { delete vresp; return NULL; } char* toReturn = vresp->extractString(); delete vresp; @@ -643,7 +721,7 @@ RecTimerList* VDR::getRecTimersList() if (!vrp.init(VDR_GETTIMERS, true, 0)) return NULL; VDR_ResponsePacket* vresp = RequestResponse(&vrp); - if (!vresp) return NULL; + if (vresp->noResponse()) { delete vresp; return NULL; } RecTimerList* recTimerList = new RecTimerList(); @@ -692,7 +770,7 @@ ULONG VDR::setEventTimer(char* timerString) if (!vrp.addString(timerString)) return 0; VDR_ResponsePacket* vresp = RequestResponse(&vrp); - if (!vresp) return 0; + if (vresp->noResponse()) { delete vresp; return 0; } ULONG toReturn = vresp->extractULONG(); delete vresp; @@ -707,7 +785,7 @@ RecInfo* VDR::getRecInfo(char* fileName) if (!vrp.addString(fileName)) return NULL; VDR_ResponsePacket* vresp = RequestResponse(&vrp); - if (!vresp) return NULL; + if (vresp->noResponse()) { delete vresp; return NULL; } if (vresp->serverError()) { @@ -749,7 +827,7 @@ ULLONG VDR::rescanRecording(ULONG* totalFrames) if (!vrp.init(VDR_RESCANRECORDING, true, 0)) return 0; VDR_ResponsePacket* vresp = RequestResponse(&vrp); - if (!vresp) return 0; + if (vresp->noResponse()) { delete vresp; return 0; } ULLONG lengthBytes = vresp->extractULLONG(); ULONG lengthFrames = vresp->extractULONG(); @@ -768,7 +846,7 @@ MarkList* VDR::getMarks(char* fileName) if (!vrp.addString(fileName)) return NULL; VDR_ResponsePacket* vresp = RequestResponse(&vrp); - if (!vresp) return NULL; + if (vresp->noResponse()) { delete vresp; return NULL; } if (vresp->serverError()) { @@ -799,7 +877,7 @@ void VDR::getChannelPids(Channel* channel) if (!vrp.addULONG(channel->number)) return ; VDR_ResponsePacket* vresp = RequestResponse(&vrp); - if (!vresp) return ; + if (vresp->noResponse()) { delete vresp; return ; } // Format of response // vpid @@ -856,7 +934,7 @@ MediaList* VDR::getMediaList(const char* parent,int mediaType) } VDR_ResponsePacket* vresp = RequestResponse(&vrp); - if (!vresp) return NULL; + if (vresp->noResponse()) { delete vresp; return NULL; } if (vresp->serverError()) { @@ -931,7 +1009,7 @@ ULONG VDR::loadImage(const char* fileName, ULONG x, ULONG y) if (!vrp.addString(fileName)) return 0; VDR_ResponsePacket* vresp = RequestResponse(&vrp); - if (!vresp) return 0; + if (vresp->noResponse()) { delete vresp; return 0; } ULONG cmd = vresp->extractULONG(); ULONG lengthBytes = vresp->extractULONG(); @@ -954,7 +1032,7 @@ int VDR::deleteTimer(RecTimer* delTimer) if (!vrp.addULONG(delTimer->stopTime)) return 0; VDR_ResponsePacket* vresp = RequestResponse(&vrp); - if (!vresp) return 0; + if (vresp->noResponse()) { delete vresp; return 0; } int toReturn = (int)vresp->extractULONG(); delete vresp; diff --git a/vdr.h b/vdr.h index 6fcfe88..68f53ed 100644 --- a/vdr.h +++ b/vdr.h @@ -35,6 +35,7 @@ #include "rectimer.h" #include "mark.h" #include "media.h" +#include "eventdispatcher.h" class TCP; class Log; @@ -75,13 +76,37 @@ struct ServerSorter class RecMan; -class VDR +class StreamReceiver +{ + public: + void receiveData(void*, ULONG) {}; +}; + +class VDR_PacketReceiver : public EDReceiver // implementation in vdr.cc +{ + public: + virtual bool call(void* userTag); + + ULONG receiverChannel; + + // If receiverChannel == 1: + ULONG requestSerialNumber; // set by RequestResponse, used in ed_cb_find + VDR_ResponsePacket* save_vresp; // set by ed_cb_call, used in RequestResponse + + // If receiverChannel == 2: + StreamReceiver* streamReceiver; +}; + +class VDR : public Thread_TYPE, public EventDispatcher { public: const static ULONG VIDEO = 1; const static ULONG RADIO = 2; + const static ULONG CHANNEL_REQUEST_RESPONSE = 1; + const static ULONG CHANNEL_STREAM = 2; + VDR(); ~VDR(); static VDR* getInstance(); @@ -217,7 +242,13 @@ class VDR const static ULONG VDR_GETIMAGEBLOCK = 32; protected: + + // Thread void threadMethod(); + void threadPostStopCleanup() {}; + + // EventDispatcher + virtual bool ed_cb_find(EDReceiver* edr, void* userTag); }; #endif diff --git a/vdrrequestpacket.cc b/vdrrequestpacket.cc index 125b756..25ce2cb 100644 --- a/vdrrequestpacket.cc +++ b/vdrrequestpacket.cc @@ -33,7 +33,7 @@ ? bytes = rest of packet. depends on packet */ -ULONG VDR_RequestPacket::serialNumber = 1; +ULONG VDR_RequestPacket::serialNumberCounter = 1; VDR_RequestPacket::VDR_RequestPacket() { @@ -41,6 +41,7 @@ VDR_RequestPacket::VDR_RequestPacket() bufSize = 0; bufUsed = 0; lengthSet = false; + serialNumber = 0; } VDR_RequestPacket::~VDR_RequestPacket() @@ -65,8 +66,12 @@ bool VDR_RequestPacket::init(ULONG opcode, bool setUserDataLength, ULONG userDat buffer = (UCHAR*)malloc(bufSize); if (!buffer) return false; - *(ULONG*)&buffer[0] = htonl(1); - *(ULONG*)&buffer[4] = htonl(serialNumber++); + + channel = VDR::CHANNEL_REQUEST_RESPONSE; + serialNumber = serialNumberCounter++; + + *(ULONG*)&buffer[0] = htonl(channel); + *(ULONG*)&buffer[4] = htonl(serialNumber); *(ULONG*)&buffer[8] = htonl(opcode); *(ULONG*)&buffer[12] = htonl(userDataLength); bufUsed = headerLength; diff --git a/vdrrequestpacket.h b/vdrrequestpacket.h index 52d2d06..3642ba6 100644 --- a/vdrrequestpacket.h +++ b/vdrrequestpacket.h @@ -41,14 +41,19 @@ class VDR_RequestPacket UCHAR* getPtr() { return buffer; } ULONG getLen() { return bufUsed; } + ULONG getChannel() { return channel; } + ULONG getSerial() { return serialNumber; } private: - static ULONG serialNumber; + static ULONG serialNumberCounter; UCHAR* buffer; ULONG bufSize; ULONG bufUsed; bool lengthSet; + + ULONG channel; + ULONG serialNumber; bool checkExtend(ULONG by); diff --git a/vdrresponsepacket.cc b/vdrresponsepacket.cc index abf167c..121a587 100644 --- a/vdrresponsepacket.cc +++ b/vdrresponsepacket.cc @@ -32,7 +32,7 @@ VDR_ResponsePacket::~VDR_ResponsePacket() { if (getBlockRelease) return; // don't free if it's a getblock - free(packet); + if (packet) free(packet); } void VDR_ResponsePacket::set(UCHAR* tpacket, ULONG tpacketLength) diff --git a/vdrresponsepacket.h b/vdrresponsepacket.h index b1f6e8e..a750551 100644 --- a/vdrresponsepacket.h +++ b/vdrresponsepacket.h @@ -35,6 +35,7 @@ class VDR_ResponsePacket void set(UCHAR* packet, ULONG packetLength); + bool noResponse() { return (packet == NULL); }; int serverError(); ULONG getLength(); -- 2.39.2