From da1c6058c56059c064f55b81586d6079677fa1b4 Mon Sep 17 00:00:00 2001 From: lado Date: Mon, 1 Apr 2013 00:11:19 +0200 Subject: Feature #790 --- vdr-vdrmanager/HISTORY | 8 +- vdr-vdrmanager/Makefile | 2 +- vdr-vdrmanager/compressor.cpp | 164 ++++++++++++++++++++++++++++++++++++ vdr-vdrmanager/compressor.h | 32 +++++++ vdr-vdrmanager/handler.cpp | 16 +++- vdr-vdrmanager/helpers.h | 2 - vdr-vdrmanager/sock.cpp | 136 ++++++++++++++++++++++++------ vdr-vdrmanager/sock.h | 15 +++- vdr-vdrmanager/vdrmanager.cpp | 34 ++++---- vdr-vdrmanager/vdrmanagerthread.cpp | 5 +- vdr-vdrmanager/vdrmanagerthread.h | 3 +- 11 files changed, 365 insertions(+), 52 deletions(-) create mode 100644 vdr-vdrmanager/compressor.cpp create mode 100644 vdr-vdrmanager/compressor.h (limited to 'vdr-vdrmanager') diff --git a/vdr-vdrmanager/HISTORY b/vdr-vdrmanager/HISTORY index 34ed4d1..e62cb01 100644 --- a/vdr-vdrmanager/HISTORY +++ b/vdr-vdrmanager/HISTORY @@ -1,5 +1,11 @@ VDR Plugin 'vdrmanager' Revision History ------------------------------------ + +2013-04-xx: Version 0.10 (http://projects.vdr-developer.org/versions/show/328) +- Bug #1314: -f has not function, remove it. Deleting timers is always beeing forced +- Feature #790: use some compression (zlib, gzip) to compress responses server sides +- Feature #1319: Recording Folders + 2013-01-xx: Version 0.9 (http://projects.vdr-developer.org/versions/show/312) - Improved Timer/Recording deletion - Improved recording information (recordings command) @@ -39,7 +45,7 @@ VDR Plugin 'vdrmanager' Revision History 2011-11-06: Version 0.3 - Check against svdrphosts.conf file only if a) forced via command line argument -s or no password was specified via -P -- arguments parsing by getopts +- arguments parsing by getopts 2011-10-12: Version 0.2 - Recording Info via recordings command diff --git a/vdr-vdrmanager/Makefile b/vdr-vdrmanager/Makefile index 4fae6b6..c43fa6a 100644 --- a/vdr-vdrmanager/Makefile +++ b/vdr-vdrmanager/Makefile @@ -47,7 +47,7 @@ SOFILE = libvdr-$(PLUGIN).so ### The object files (add further files here): -OBJS = $(PLUGIN).o sock.o vdrmanagerthread.o select.o handler.o helpers.o +OBJS = $(PLUGIN).o sock.o vdrmanagerthread.o select.o handler.o helpers.o compressor.o ### The main target: diff --git a/vdr-vdrmanager/compressor.cpp b/vdr-vdrmanager/compressor.cpp new file mode 100644 index 0000000..6a479f3 --- /dev/null +++ b/vdr-vdrmanager/compressor.cpp @@ -0,0 +1,164 @@ +/* + * compressor.cpp + * + * Created on: 23.03.2013 + * Author: bju + */ + +#include "compressor.h" + +#include +#include +#include +#include + +#define CHUNK 16384 + +cCompressor::cCompressor() { + size = 0; + data = NULL; +} + +cCompressor::~cCompressor() { + +} + +bool cCompressor::CompressGzip(string text) { + + int in_fd[2]; + if (pipe(in_fd) < 0) { + return false; + } + + int out_fd[2]; + if (pipe(out_fd) < 0) { + return false; + } + + int pid = fork(); + if (pid < 0) { + return false; + } + + if (pid == 0) { + // child + close(in_fd[1]); + close(out_fd[0]); + dup2(in_fd[0], 0); + dup2(out_fd[1], 1); + + execlp("gzip", "gzip", "-c", "-9", NULL); + + exit(-1); + + } else { + // parent + close(in_fd[0]); + close(out_fd[1]); + + write(in_fd[1], text.c_str(), text.length()); + close(in_fd[1]); + + char buf[32*1024]; + + for(;;) { + int count = read(out_fd[0], buf, sizeof(buf)); + if (count < 0) { + close(out_fd[0]); + return false; + } + if (count == 0) + break; + + char * newdata = (char *)malloc(size + count); + if (data != NULL) { + memcpy(newdata, data, size); + } + memcpy(newdata + size, buf, count); + if (data != NULL) { + free(data); + } + data = newdata; + size += count; + } + + close(out_fd[0]); + } + + return true; +} + +bool cCompressor::CompressZlib(string text) { + + int ret, flush; + unsigned have; + z_stream strm; + unsigned char in[CHUNK]; + unsigned char out[CHUNK]; + int level = 9; + + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + ret = deflateInit(&strm, level); + if (ret != Z_OK) + return false; + + string input = text; + uInt len; + + do { + len = input.length(); + if (len > CHUNK) { + len = CHUNK; + } + flush = len > 0 ? Z_NO_FLUSH : Z_FINISH; + + strm.avail_in = len; + strm.next_in = (unsigned char *)input.c_str(); + + do { + strm.avail_out = CHUNK; + strm.next_out = out; + + ret = deflate(&strm, flush); + if (ret < 0) { + if (data != NULL) { + free(data); + } + return false; + } + + have = CHUNK - strm.avail_out; + + char * newdata = (char *)malloc(size + have); + if (data != NULL) { + memcpy(newdata, data, size); + } + memcpy(newdata + size, out, have); + if (data != NULL) { + free(data); + } + data = newdata; + size += have; + + } while (strm.avail_out == 0); + + input = input.substr(len); + + } while (flush != Z_FINISH); + + // clean up and return + (void)deflateEnd(&strm); + + return true; +} + +char * cCompressor::GetData() { + return data; +} + +size_t cCompressor::getDataSize() { + return size; +} + diff --git a/vdr-vdrmanager/compressor.h b/vdr-vdrmanager/compressor.h new file mode 100644 index 0000000..fbcc14f --- /dev/null +++ b/vdr-vdrmanager/compressor.h @@ -0,0 +1,32 @@ +/* + * compressor.h + * + * Created on: 23.03.2013 + * Author: bju + */ + +#ifndef COMPRESSOR_H_ +#define COMPRESSOR_H_ + +#include + +#define COMPRESSION_NONE 0 +#define COMPRESSION_ZLIB 1 +#define COMPRESSION_GZIP 2 + +using namespace std; + +class cCompressor { +private: + char * data; + size_t size; +public: + cCompressor(); + virtual ~cCompressor(); + bool CompressGzip(string text); + bool CompressZlib(string text); + char * GetData(); + size_t getDataSize(); +}; +#endif /* COMPRESSOR_H_ */ + diff --git a/vdr-vdrmanager/handler.cpp b/vdr-vdrmanager/handler.cpp index 43b500a..ea15296 100644 --- a/vdr-vdrmanager/handler.cpp +++ b/vdr-vdrmanager/handler.cpp @@ -17,6 +17,8 @@ bool cHandler::HandleNewClient(cVdrmanagerClientSocket * sock) bool cHandler::HandleClientRequest(cVdrmanagerClientSocket * sock) { + bool closeSocket = true; + while(sock->Read()) { // get lines @@ -48,6 +50,12 @@ bool cHandler::HandleClientRequest(cVdrmanagerClientSocket * sock) sock->SetLoggedIn(); sock->PutLine("!OK\r\n"); } + closeSocket = false; + } + else if (cmd == "COMPRESS") + { + sock->ActivateCompression(); + closeSocket = false; } else if (cmd == "TIMERS") { @@ -97,9 +105,15 @@ bool cHandler::HandleClientRequest(cVdrmanagerClientSocket * sock) else if (cmd == "QUIT") { // close socket - sock->PutLine(string("Good bye! :-)\n")); + sock->PutLine(string("Good bye! :-)\r\n")); sock->Disconnect(); } + + if (closeSocket) { + sock->Disconnect(); + } + + sock->Flush(); } } diff --git a/vdr-vdrmanager/helpers.h b/vdr-vdrmanager/helpers.h index b9ebee5..18576be 100644 --- a/vdr-vdrmanager/helpers.h +++ b/vdr-vdrmanager/helpers.h @@ -31,8 +31,6 @@ public: static string ToUpper(string text); static string ToLower(string text); static string Trim(string text); - static string decompress_string(const string& str); - static string compress_string(const string& str, int compressionlevel = Z_BEST_COMPRESSION); static long Duration(cRecording* recording); private: static string SafeCall(string (*)()); diff --git a/vdr-vdrmanager/sock.cpp b/vdr-vdrmanager/sock.cpp index 1d17ee2..2102c36 100644 --- a/vdr-vdrmanager/sock.cpp +++ b/vdr-vdrmanager/sock.cpp @@ -5,6 +5,7 @@ #include #include "sock.h" #include "helpers.h" +#include "compressor.h" static int clientno = 0; @@ -60,10 +61,12 @@ cVdrmanagerServerSocket::cVdrmanagerServerSocket() : cVdrmanagerServerSocket::~cVdrmanagerServerSocket() { } -bool cVdrmanagerServerSocket::Create(int port, const char * password, bool forceCheckSvrp) { - // save password - this->password = password; +bool cVdrmanagerServerSocket::Create(int port, const char * password, bool forceCheckSvrp, int compressionMode) { + + this->password = password; this->forceCheckSvdrp = forceCheckSvrp; + this->compressionMode = compressionMode; + // create socket sock = socket(PF_INET, SOCK_STREAM, 0); if (sock < 0) { @@ -111,7 +114,7 @@ cVdrmanagerClientSocket * cVdrmanagerServerSocket::Accept() { int newsock = accept(sock, (struct sockaddr *) &clientname, &size); if (newsock > 0) { // create client socket - newsocket = new cVdrmanagerClientSocket(password); + newsocket = new cVdrmanagerClientSocket(password, compressionMode); if (!newsocket->Attach(newsock)) { delete newsocket; return NULL; @@ -138,12 +141,20 @@ cVdrmanagerClientSocket * cVdrmanagerServerSocket::Accept() { /* * cVdrmonClientSocket */ -cVdrmanagerClientSocket::cVdrmanagerClientSocket(const char * password) { - readbuf = writebuf = ""; +cVdrmanagerClientSocket::cVdrmanagerClientSocket(const char * password, int compressionMode) { + readbuf = ""; + writebuf = ""; + sendbuf = NULL; + sendsize = 0; + sendoffset = 0; disconnected = false; + initDisconnect = false; client = ++clientno; this->password = password; + this->compressionMode = compressionMode; login = false; + compression = false; + initCompression = false; } cVdrmanagerClientSocket::~cVdrmanagerClientSocket() { @@ -212,42 +223,74 @@ bool cVdrmanagerClientSocket::Disconnected() { } void cVdrmanagerClientSocket::Disconnect() { - disconnected = true; + initDisconnect = true; } bool cVdrmanagerClientSocket::PutLine(string line) { - //TODO http://projects.vdr-developer.org/issues/790 - //string line2 = cHelpers::compress_string(line); - //unsigned long l = line.size(); - //unsigned long l2 = line2.size(); - //if(l2 == 0){ - //l2 = 1; - //} - //dsyslog("[vdrmanager] PutLine, line size is %lu, with zlib it would be %lu (factor %lu)", l, l2, l/l2); - // add line to write buffer - writebuf += line; - - // data present? - if (writebuf.length() > 0) { + + // fill writebuf + if (line.length() > 0) { + writebuf += line; + return true; + } + + // initialize sendbuf if needed + if (sendbuf == NULL) { + if (!compression) { + sendbuf = (char *)malloc(writebuf.length()+1); + strcpy(sendbuf, writebuf.c_str()); + sendsize = writebuf.length(); + } else { + Compress(); + } + sendoffset = 0; + writebuf.clear(); + } + + // send data + if (sendsize > 0) { + // write so many bytes as possible - int rc = write(sock, writebuf.c_str(), writebuf.length()); + int rc = write(sock, sendbuf + sendoffset, sendsize); if (rc < 0 && errno != EAGAIN) { LOG_ERROR; + + if (sendbuf != NULL) { + free(sendbuf); + sendbuf = NULL; + } + return false; } + sendsize -= rc; + sendoffset += rc; + } + + if (sendsize == 0) { - // move the remainder - if (rc > 0) - writebuf = writebuf.substr(rc, writebuf.length() - rc); + if (sendbuf != NULL) { + free(sendbuf); + sendbuf = NULL; + } + + if (initCompression) { + isyslog("Compression is activated now"); + initCompression = false; + compression = true; + } + + if (initDisconnect) { + initDisconnect = false; + disconnected = true; + } } return true; } bool cVdrmanagerClientSocket::Flush() { - string empty = ""; - return PutLine(empty); + return PutLine(""); } bool cVdrmanagerClientSocket::Attach(int fd) { @@ -260,7 +303,7 @@ int cVdrmanagerClientSocket::GetClientId() { } bool cVdrmanagerClientSocket::WritePending() { - return writebuf.length() > 0; + return sendoffset < sendsize; } bool cVdrmanagerClientSocket::IsLoggedIn() { @@ -270,3 +313,42 @@ bool cVdrmanagerClientSocket::IsLoggedIn() { void cVdrmanagerClientSocket::SetLoggedIn() { login = true; } + +void cVdrmanagerClientSocket::ActivateCompression() { + + string mode = "NONE"; + switch (compressionMode) { + case COMPRESSION_GZIP: + mode = "GZIP"; + initCompression = true; + break; + case COMPRESSION_ZLIB: + mode = "ZLIB"; + initCompression = true; + break; + default: + mode = "NONE"; + break; + } + + PutLine("!OK " + mode + "\r\n"); +} + +void cVdrmanagerClientSocket::Compress() { + cCompressor compressor = cCompressor(); + + switch (compressionMode) { + case COMPRESSION_GZIP: + compressor.CompressGzip(writebuf); + break; + case COMPRESSION_ZLIB: + compressor.CompressZlib(writebuf); + break; + } + + sendbuf = compressor.GetData(); + sendsize = compressor.getDataSize(); + + double ratio = 1.0 * writebuf.length() / sendsize; + isyslog("Compression stats: raw %ld, compressed %ld, ratio %f:1", writebuf.length(), sendsize, ratio); +} diff --git a/vdr-vdrmanager/sock.h b/vdr-vdrmanager/sock.h index 0234afc..25a7b83 100644 --- a/vdr-vdrmanager/sock.h +++ b/vdr-vdrmanager/sock.h @@ -5,6 +5,7 @@ #ifndef _VDRMON_SOCK #define _VDRMON_SOCK +#include #include #include #include @@ -17,6 +18,7 @@ protected: int sock; const char * password; bool forceCheckSvdrp; + int compressionMode; protected: cVdrmanagerSocket(); bool IsPasswordSet(); @@ -33,11 +35,18 @@ class cVdrmanagerClientSocket : public cVdrmanagerSocket private: string readbuf; string writebuf; + char * sendbuf; + size_t sendsize; + size_t sendoffset; bool disconnected; + bool initDisconnect; int client; bool login; + bool compression; + bool initCompression; + int compressionMode; public: - cVdrmanagerClientSocket(const char * password); + cVdrmanagerClientSocket(const char * password, int compressionMode); virtual ~cVdrmanagerClientSocket(); bool Attach(int fd); bool IsLineComplete(); @@ -51,6 +60,8 @@ public: bool WritePending(); bool IsLoggedIn(); void SetLoggedIn(); + void ActivateCompression(); + void Compress(); }; class cVdrmanagerServerSocket : public cVdrmanagerSocket @@ -58,7 +69,7 @@ class cVdrmanagerServerSocket : public cVdrmanagerSocket public: cVdrmanagerServerSocket(); virtual ~cVdrmanagerServerSocket(); - bool Create(int port, const char * password, bool forceCheckSvdrp); + bool Create(int port, const char * password, bool forceCheckSvdrp, int compressionMode); cVdrmanagerClientSocket * Accept(); }; diff --git a/vdr-vdrmanager/vdrmanager.cpp b/vdr-vdrmanager/vdrmanager.cpp index 2b81464..0d26963 100644 --- a/vdr-vdrmanager/vdrmanager.cpp +++ b/vdr-vdrmanager/vdrmanager.cpp @@ -12,6 +12,7 @@ #include #include #include "vdrmanagerthread.h" +#include "compressor.h" #define VDRMANAGER_PORT 6420 @@ -24,8 +25,8 @@ private: cVdrManagerThread * Thread; int port; const char * password; - bool forceCheckSvdrp; - bool forceDelete; + bool forceCheckSvdrp = false; + int compressionMode = COMPRESSION_NONE; protected: public: cVdrManager(void); @@ -57,7 +58,6 @@ cVdrManager::cVdrManager(void) { port = VDRMANAGER_PORT; password = ""; forceCheckSvdrp = false; - forceDelete = false; } cVdrManager::~cVdrManager() { @@ -73,12 +73,16 @@ cMenuSetupPage * cVdrManager::SetupMenu(void) { } const char * cVdrManager::CommandLineHelp(void) { - return " -p port port number to listen to\n -P password password (none if not given). No password forces check against svdrphosts.conf.\n -s force check against svdrphosts.conf, even if a password was given\n -f force delete of a timer or a recording even if they are active\n"; + return + " -p port port number to listen to\n" + " -P password password (none if not given). No password forces check against svdrphosts.conf.\n" + " -s force check against svdrphosts.conf, even if a password was given\n" + " -c compression selects the compression mode to use (zlib or gzip). Default is zlib"; } bool cVdrManager::ProcessArgs(int argc, char *argv[]) { int c; - while ((c = getopt(argc, argv, "p:P:s:f")) != -1) + while ((c = getopt(argc, argv, "c:p:P:sf")) != -1) switch (c) { case 'p': port = atoi(optarg); @@ -89,16 +93,16 @@ bool cVdrManager::ProcessArgs(int argc, char *argv[]) { case 's': forceCheckSvdrp = true; break; - case 'f': - forceDelete = true; - break; + case 'c': + if (optarg[0] == 'g') { + compressionMode = COMPRESSION_GZIP; + } else if (optarg[0] == 'z') { + compressionMode = COMPRESSION_ZLIB; + } else { + compressionMode = COMPRESSION_ZLIB; + } + break; case '?': - if (optopt == 'c') { - fprintf(stderr, "Option -%c requires an argument.\n", optopt); - } else if (isprint(optopt)) - fprintf(stderr, "Unknown option `-%c'.\n", optopt); - else - fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt); return false; default: return false; @@ -115,7 +119,7 @@ bool cVdrManager::Initialize(void) { // Initialize any background activities the plugin shall perform. // Start any background activities the plugin shall perform. - Thread = new cVdrManagerThread(port, password, forceCheckSvdrp); + Thread = new cVdrManagerThread(port, password, forceCheckSvdrp, compressionMode); return Thread != NULL; } diff --git a/vdr-vdrmanager/vdrmanagerthread.cpp b/vdr-vdrmanager/vdrmanagerthread.cpp index 2a4ca64..51301e5 100644 --- a/vdr-vdrmanager/vdrmanagerthread.cpp +++ b/vdr-vdrmanager/vdrmanagerthread.cpp @@ -8,12 +8,13 @@ #include "select.h" #include "helpers.h" -cVdrManagerThread::cVdrManagerThread(int port, const char * password, bool forceCheckSvdrp) +cVdrManagerThread::cVdrManagerThread(int port, const char * password, bool forceCheckSvdrp, int compressionMode) { select = NULL; this -> port = port; this -> password = password; this -> forceCheckSvdrp = forceCheckSvdrp; + this -> compressionMode = compressionMode; } cVdrManagerThread::~cVdrManagerThread() @@ -43,7 +44,7 @@ bool cVdrManagerThread::Init() // create server socket cVdrmanagerServerSocket * sock = new cVdrmanagerServerSocket(); - if (sock == NULL || !sock->Create(port, password, forceCheckSvdrp)) + if (sock == NULL || !sock->Create(port, password, forceCheckSvdrp, compressionMode)) return false; // register server socket diff --git a/vdr-vdrmanager/vdrmanagerthread.h b/vdr-vdrmanager/vdrmanagerthread.h index 83f5f31..0dd3646 100644 --- a/vdr-vdrmanager/vdrmanagerthread.h +++ b/vdr-vdrmanager/vdrmanagerthread.h @@ -22,8 +22,9 @@ private: int port; const char * password; bool forceCheckSvdrp; + int compressionMode; public: - cVdrManagerThread(int port, const char * password, bool forceCheckSvdrp); + cVdrManagerThread(int port, const char * password, bool forceCheckSvdrp, int compressionMode); virtual void Action(void); void Shutdown(); private: -- cgit v1.2.3