summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbju <bju@maxi.fritz.box>2013-03-24 03:14:45 (GMT)
committerbju <bju@maxi.fritz.box>2013-03-24 22:44:04 (GMT)
commit3cc7911fedcbea2337237a04658495b369c73d35 (patch)
treeb2671551f65d6b2c02cad2ee0bb072fac45f0ff4
parentdbf28d356eb97b3075229bbc42a8a3ccf1c94ec0 (diff)
downloadvdr-manager-compression.tar.gz
vdr-manager-compression.tar.bz2
the answer traffic is now compressed if enabled on the server using zip or gzipcompression
-rw-r--r--vdr-vdrmanager/Makefile2
-rw-r--r--vdr-vdrmanager/compressor.cpp164
-rw-r--r--vdr-vdrmanager/compressor.h32
-rw-r--r--vdr-vdrmanager/handler.cpp16
-rw-r--r--vdr-vdrmanager/helpers.cpp80
-rw-r--r--vdr-vdrmanager/helpers.h2
-rw-r--r--vdr-vdrmanager/sock.cpp136
-rw-r--r--vdr-vdrmanager/sock.h15
-rw-r--r--vdr-vdrmanager/vdrmanager.cpp28
-rw-r--r--vdr-vdrmanager/vdrmanagerthread.cpp5
-rw-r--r--vdr-vdrmanager/vdrmanagerthread.h3
-rw-r--r--vdrmanager/src/de/bjusystems/vdrmanager/utils/svdrp/SvdrpClient.java928
12 files changed, 835 insertions, 576 deletions
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 <zlib.h>
+#include <malloc.h>
+#include <string.h>
+#include <stdlib.h>
+
+#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 <string>
+
+#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.cpp b/vdr-vdrmanager/helpers.cpp
index 80721f3..b83eba0 100644
--- a/vdr-vdrmanager/helpers.cpp
+++ b/vdr-vdrmanager/helpers.cpp
@@ -1066,86 +1066,6 @@ int cHelpers::RecordingLengthInSeconds(cRecording* recording) {
return Duration(recording) * 60;
}
-/** Compress a STL string using zlib with given compression level and return
- * the binary data. */
-string cHelpers::compress_string(const string& str, int compressionlevel) {
- z_stream zs; // z_stream is zlib's control structure
- memset(&zs, 0, sizeof(zs));
-
- if (deflateInit(&zs, compressionlevel) != Z_OK)
- throw(runtime_error("deflateInit failed while compressing."));
-
- zs.next_in = (Bytef*) str.data();
- zs.avail_in = str.size(); // set the z_stream's input
-
- int ret;
- char outbuffer[32768];
- string outstring;
-
-// retrieve the compressed bytes blockwise
- do {
- zs.next_out = reinterpret_cast<Bytef*>(outbuffer);
- zs.avail_out = sizeof(outbuffer);
-
- ret = deflate(&zs, Z_FINISH);
-
- if (outstring.size() < zs.total_out) {
- // append the block to the output string
- outstring.append(outbuffer, zs.total_out - outstring.size());
- }
- } while (ret == Z_OK);
-
- deflateEnd(&zs);
-
- if (ret != Z_STREAM_END) { // an error occurred that was not EOF
- ostringstream oss;
- oss << "Exception during zlib compression: (" << ret << ") " << zs.msg;
- throw(runtime_error(oss.str()));
- }
-
- return outstring;
-}
-
-/** Decompress an STL string using zlib and return the original data. */
-string cHelpers::decompress_string(const string& str) {
- z_stream zs; // z_stream is zlib's control structure
- memset(&zs, 0, sizeof(zs));
-
- if (inflateInit(&zs) != Z_OK)
- throw(runtime_error("inflateInit failed while decompressing."));
-
- zs.next_in = (Bytef*) str.data();
- zs.avail_in = str.size();
-
- int ret;
- char outbuffer[32768];
- string outstring;
-
-// get the decompressed bytes blockwise using repeated calls to inflate
- do {
- zs.next_out = reinterpret_cast<Bytef*>(outbuffer);
- zs.avail_out = sizeof(outbuffer);
-
- ret = inflate(&zs, 0);
-
- if (outstring.size() < zs.total_out) {
- outstring.append(outbuffer, zs.total_out - outstring.size());
- }
-
- } while (ret == Z_OK);
-
- inflateEnd(&zs);
-
- if (ret != Z_STREAM_END) { // an error occurred that was not EOF
- ostringstream oss;
- oss << "Exception during zlib decompression: (" << ret << ") "
- << zs.msg;
- throw(runtime_error(oss.str()));
- }
-
- return outstring;
-}
-
//These three methodes were stolen from vdr-restfulapi project. Thanks!
std::queue<int> cHelpers::ConvertToBinary(int v) {
int b;
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 <vdr/plugin.h>
#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 <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string>
@@ -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..4d00f41 100644
--- a/vdr-vdrmanager/vdrmanager.cpp
+++ b/vdr-vdrmanager/vdrmanager.cpp
@@ -12,6 +12,7 @@
#include <vdr/device.h>
#include <vdr/player.h>
#include "vdrmanagerthread.h"
+#include "compressor.h"
#define VDRMANAGER_PORT 6420
@@ -26,6 +27,7 @@ private:
const char * password;
bool forceCheckSvdrp;
bool forceDelete;
+ int compressionMode;
protected:
public:
cVdrManager(void);
@@ -73,12 +75,17 @@ 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"
+ " -f force delete of a timer or a recording even if they are active\n"
+ " -c compression selects the compression mode to use (zlib, gzip or none)";
}
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);
@@ -92,13 +99,16 @@ bool cVdrManager::ProcessArgs(int argc, char *argv[]) {
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_NONE;
+ }
+ 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 +125,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:
diff --git a/vdrmanager/src/de/bjusystems/vdrmanager/utils/svdrp/SvdrpClient.java b/vdrmanager/src/de/bjusystems/vdrmanager/utils/svdrp/SvdrpClient.java
index f6307f5..5c33981 100644
--- a/vdrmanager/src/de/bjusystems/vdrmanager/utils/svdrp/SvdrpClient.java
+++ b/vdrmanager/src/de/bjusystems/vdrmanager/utils/svdrp/SvdrpClient.java
@@ -12,8 +12,9 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.InflaterInputStream;
-import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import android.util.Log;
@@ -28,455 +29,480 @@ import de.bjusystems.vdrmanager.data.Preferences;
*/
public abstract class SvdrpClient<Result> {
- private final String TAG = getClass().getName();
-
- /** Socket for connection to SVDRP */
- private Socket socket;
- /** Output stream for sending commands */
- private OutputStream outputStream;
- /** Input stream for reading answer lines */
- private InputStream inputStream;
- /** flag for stopping the current request */
- private boolean abort;
- /** listener */
- private final List<SvdrpListener> svdrpListeners = new ArrayList<SvdrpListener>();
-
- private final List<SvdrpResultListener<Result>> svdrpResultListeners = new ArrayList<SvdrpResultListener<Result>>();
-
- private final List<SvdrpExceptionListener> svdrpExceptionListeners = new ArrayList<SvdrpExceptionListener>();
-
- private final List<SvdrpFinishedListener<Result>> svdrpFinishedListeners = new ArrayList<SvdrpFinishedListener<Result>>();
-
- /** list of results */
- // private final List<Result> results = new ArrayList<Result>();
- /** should the listener be informed about each received result */
- // private boolean resultInfoEnabled = false;
- /**
- * @return true if the client has result
- */
- // public boolean hasResults(){
- // return results.isEmpty() == false;
- // }
-
- private Timer watchDog = new Timer();
-
- // private NativeDES crypt = new NativeDES();
-
- public boolean isConnected() {
- if (socket == null) {
- return false;
- }
- return socket.isConnected();
- }
-
- /**
- * Parse received answer line
- *
- * @param line
- * line
- * @return received data object or null if not completed yet
- */
- protected abstract Result parseAnswer(String line);
-
- public abstract int getProgressTextId();
-
- public abstract void run();
-
- /**
- * Constructor
- *
- * @param prefs
- * Preferences
- */
- protected SvdrpClient() {
- // results.clear();
- }
-
- /**
- * Remove all listeners
- */
- public void clearListener() {
- svdrpExceptionListeners.clear();
- svdrpListeners.clear();
- svdrpResultListeners.clear();
- }
-
- /**
- * Adds the listener to the list of listeners
- *
- * @param listener
- * listener
- */
- public void addSvdrpListener(final SvdrpListener listener) {
- svdrpListeners.add(listener);
- }
-
- /**
- * Adds the listener to the list of listeners
- *
- * @param listener
- * listener
- */
- public void addSvdrpResultListener(
- final SvdrpResultListener<Result> listener) {
- svdrpResultListeners.add(listener);
- }
-
- /**
- * Adds the listener to the list of listeners
- *
- * @param listener
- * listener
- */
- public void addSvdrpFinishedListener(
- final SvdrpFinishedListener<Result> listener) {
- svdrpFinishedListeners.add(listener);
- }
-
- /**
- * Adds the listener to the list of listeners
- *
- * @param listener
- * listener
- */
- public void addSvdrpExceptionListener(final SvdrpExceptionListener listener) {
- svdrpExceptionListeners.add(listener);
- }
-
- /**
- * Removes the listener from the list of listeners
- *
- * @param listener
- * listener
- */
- public void removeSvdrpListener(final SvdrpListener listener) {
- svdrpListeners.remove(listener);
- }
-
- public void removeSvdrpResultListener(
- final SvdrpResultListener<Result> listener) {
- svdrpResultListeners.remove(listener);
- }
-
- public void removeSvdrpExceptionListener(
- final SvdrpExceptionListener listener) {
- svdrpExceptionListeners.remove(listener);
- }
-
- /**
- * Cancel the current request
- */
- public void abort() {
- abort = true;
- try {
- if (isConnected()) {
- socket.shutdownInput();
- socket.shutdownOutput();
- socket.close();
- }
- } catch (Exception ex) {
- Log.w(TAG, ex);
- }
-
- }
-
- // /**
- // * Gets the list of results
- // *
- // * @return results
- // */
- // public List<Result> getResults() {
- // return results;
- // }
-
- /**
- * Connect to SVDRP
- *
- * @param host
- * host
- * @param port
- * port
- * @param ssl
- * use SSL
- * @throws IOException
- * on errors
- */
- protected boolean connect() throws IOException {
-
- final Preferences prefs = Preferences.get();
- try {
- // connect
- informListener(SvdrpEvent.CONNECTING);
-
- if (false && Preferences.get().isSecure()) {
-
- SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory
- .getDefault(); // Erzeugt eine SSLSocketFactory mit
- // Standartkonfiguration
- socket = (SSLSocket) factory.createSocket();
- } else {
- socket = new Socket();
- }
-
- socket.connect(
- new InetSocketAddress(prefs.getSvdrpHost(), prefs
- .getSvdrpPort()),
- prefs.getConnectionTimeout() * 1000);// 8 secs for connect
- if (abort) {
- informListener(SvdrpEvent.ABORTED);
- }
- //
- socket.setSoTimeout(prefs.getReadTimeout() * 1000);// 15 sec for
- // each read
- final long delay = C.ONE_MINUTE_IN_MILLIS * prefs.getTimeout() * 60; // in
- // 3
- // minutes
- // we
- // abort
- // the
- // communication
- watchDog.schedule(new TimerTask() {
- @Override
- public void run() {
- Log.w(TAG, "Aborted after " + delay + " ms");
- abort = true;
- }
- }, delay);
- informListener(SvdrpEvent.CONNECTED);
- } catch (final SocketTimeoutException sote) {
- Log.w(TAG, sote);
- if (abort) {
- informListener(SvdrpEvent.ABORTED);
- } else {
- informListener(SvdrpEvent.CONNECTION_TIMEOUT);
- }
- return false;
- } catch (final Exception e) {
-
- Log.w(TAG, e);
- if (abort) {
- informListener(SvdrpEvent.ABORTED);
- } else {
- informListener(SvdrpEvent.CONNECT_ERROR);
- }
- return false;
- }
-
- // create streams
- outputStream = socket.getOutputStream();
- inputStream = socket.getInputStream();
- // TODO http://projects.vdr-developer.org/issues/790
- // inputStream = new InflaterInputStream(socket.getInputStream())
-
- // password needed?
- informListener(SvdrpEvent.LOGIN);
- writeLine("passwd " + prefs.getPassword());
- if (!readLine().startsWith("!OK")) {
- informListener(SvdrpEvent.LOGIN_ERROR);
- disconnect();
- return false;
- } else {
- informListener(SvdrpEvent.LOGGED_IN);
- }
- return true;
- }
-
- /**
- * Disconnect from SVDRP if connected
- *
- * @throws IOException
- * on errors
- */
- protected void disconnect() throws IOException {
- informListener(SvdrpEvent.DISCONNECTING);
- if (socket != null && socket.isConnected()) {
- socket.close();
- socket = null;
- }
- informListener(SvdrpEvent.DISCONNECTED);
- }
-
- /**
- * Sends one line to SVDRP
- *
- * @param line
- * line of text
- * @throws IOException
- * on errors
- */
- protected void writeLine(final String line) throws IOException {
-
- String command = line + "\r\n";
- // if (false && Preferences.get().isSecure()) {
- // command = crypt.encrypt(command, Preferences.get().getPassword());
- // }
- final byte[] bytes = command.getBytes("utf-8");
- outputStream.write(bytes);
- outputStream.flush();
- }
-
- /**
- * Reads one line from SVDRP
- *
- * @return line read
- * @throws IOException
- * on errors
- */
- protected String readLine() throws IOException {
-
- // handle not gzipped input
- final ByteArrayOutputStream lineBytes = new ByteArrayOutputStream();
-
- for (;;) {
-
- // read next char
- final int d = inputStream.read();
- if (d < 0) {
- break;
- }
- final char c = (char) d;
-
- // skip '\r'
- if (c == '\r') {
- continue;
- }
-
- // with '\n' the line is completed
- if (c == '\n') {
- break;
- }
-
- // remember char
- lineBytes.write(c);
- }
-
- String line = null;
- try {
- line = lineBytes.toString(Preferences.get().getEncoding());
- } catch (UnsupportedEncodingException usex) {
- Log.w(TAG, usex);
- line = lineBytes.toString();
- }
- // if (false && Preferences.get().isSecure()) {
- // line = crypt.decrypt(line, Preferences.get().getPassword());
- // }
- return line;
- }
-
- public void runCommand(final String command) {
-
- try {
-
- // reset cancel flag
- abort = false;
-
- // clear results
- // results.clear();
-
- // connect
- final boolean connected = connect();
- if (!connected) {
- return;
- }
-
- // send command
- informListener(SvdrpEvent.COMMAND_SENDING);
- writeLine(command);
- informListener(SvdrpEvent.COMMAND_SENT);
- Log.i(TAG, SvdrpEvent.COMMAND_SENT + ":" + command);
-
- // read first line
- String line = readLine();
- if (!line.startsWith("START")) {
- Log.w(TAG, line);
- throw new IOException("Answer not wellformed: " + line);
- }
-
- // read answer lines
- for (; !abort;) {
-
- // get next line
- line = readLine();
- if (line.length() == 0) {
- break;
- }
-
- // last line?
- if (line.startsWith("END")) {
- break;
- }
-
- // error?
- if (line.startsWith("!ERROR")) {
- Log.w(TAG, line);
- String msg;
- if (line.startsWith("!ERROR:")) {
- msg = line.substring(7);
- } else {
- msg = line;
- }
- disconnect();
- informListener(SvdrpEvent.ERROR, new SvdrpException(msg));
- break;
- }
-
- // delegate analysis
- Result result = null;
- try {
- result = parseAnswer(line);
-
- } catch (Exception ex) {
- Log.w(TAG, ex);
- disconnect();
- Log.w(TAG, "line: " + line);
- informListener(SvdrpEvent.ERROR, ex);
- return;
- }
- if (result != null) {
- informListener(result);
- // results.add(result);
- // if (resultInfoEnabled) {
-
- // }
- }
-
- }
-
- // disconnect
- disconnect();
-
- if (abort) {
- informListener(SvdrpEvent.ABORTED);
- } else {
- informListener(SvdrpEvent.FINISHED_SUCCESS);
- }
-
- } catch (final Exception e) {
- Log.w(TAG, e);
- informListener(SvdrpEvent.FINISHED_ABNORMALY, e);
- }
- }
-
- // public void setResultInfoEnabled(final boolean resultInfoEnabled) {
- // this.resultInfoEnabled = resultInfoEnabled;
- // }
-
- protected void informListener(final SvdrpEvent event, final Throwable e) {
- for (final SvdrpExceptionListener listener : svdrpExceptionListeners) {
- listener.svdrpEvent(event, e);
- }
- }
-
- protected void informListener(final SvdrpEvent event) {
- for (final SvdrpListener listener : svdrpListeners) {
- listener.svdrpEvent(event);
- }
- }
-
- protected void informListener(final Result result) {
- for (final SvdrpResultListener<Result> listener : svdrpResultListeners) {
- listener.svdrpEvent(result);
- }
- }
+ private final String TAG = getClass().getName();
+
+ /** Socket for connection to SVDRP */
+ private Socket socket;
+ /** Output stream for sending commands */
+ private OutputStream outputStream;
+ /** Input stream for reading answer lines */
+ private InputStream inputStream;
+ /** flag for stopping the current request */
+ private boolean abort;
+ /** listener */
+ private final List<SvdrpListener> svdrpListeners = new ArrayList<SvdrpListener>();
+
+ private final List<SvdrpResultListener<Result>> svdrpResultListeners = new ArrayList<SvdrpResultListener<Result>>();
+
+ private final List<SvdrpExceptionListener> svdrpExceptionListeners = new ArrayList<SvdrpExceptionListener>();
+
+ private final List<SvdrpFinishedListener<Result>> svdrpFinishedListeners = new ArrayList<SvdrpFinishedListener<Result>>();
+
+ /** list of results */
+ // private final List<Result> results = new ArrayList<Result>();
+ /** should the listener be informed about each received result */
+ // private boolean resultInfoEnabled = false;
+ /**
+ * @return true if the client has result
+ */
+ // public boolean hasResults(){
+ // return results.isEmpty() == false;
+ // }
+
+ private final Timer watchDog = new Timer();
+
+ // private NativeDES crypt = new NativeDES();
+
+ public boolean isConnected() {
+ if (socket == null) {
+ return false;
+ }
+ return socket.isConnected();
+ }
+
+ /**
+ * Parse received answer line
+ *
+ * @param line
+ * line
+ * @return received data object or null if not completed yet
+ */
+ protected abstract Result parseAnswer(String line);
+
+ public abstract int getProgressTextId();
+
+ public abstract void run();
+
+ /**
+ * Constructor
+ *
+ * @param prefs
+ * Preferences
+ */
+ protected SvdrpClient() {
+ // results.clear();
+ }
+
+ /**
+ * Remove all listeners
+ */
+ public void clearListener() {
+ svdrpExceptionListeners.clear();
+ svdrpListeners.clear();
+ svdrpResultListeners.clear();
+ }
+
+ /**
+ * Adds the listener to the list of listeners
+ *
+ * @param listener
+ * listener
+ */
+ public void addSvdrpListener(final SvdrpListener listener) {
+ svdrpListeners.add(listener);
+ }
+
+ /**
+ * Adds the listener to the list of listeners
+ *
+ * @param listener
+ * listener
+ */
+ public void addSvdrpResultListener(
+ final SvdrpResultListener<Result> listener) {
+ svdrpResultListeners.add(listener);
+ }
+
+ /**
+ * Adds the listener to the list of listeners
+ *
+ * @param listener
+ * listener
+ */
+ public void addSvdrpFinishedListener(
+ final SvdrpFinishedListener<Result> listener) {
+ svdrpFinishedListeners.add(listener);
+ }
+
+ /**
+ * Adds the listener to the list of listeners
+ *
+ * @param listener
+ * listener
+ */
+ public void addSvdrpExceptionListener(final SvdrpExceptionListener listener) {
+ svdrpExceptionListeners.add(listener);
+ }
+
+ /**
+ * Removes the listener from the list of listeners
+ *
+ * @param listener
+ * listener
+ */
+ public void removeSvdrpListener(final SvdrpListener listener) {
+ svdrpListeners.remove(listener);
+ }
+
+ public void removeSvdrpResultListener(
+ final SvdrpResultListener<Result> listener) {
+ svdrpResultListeners.remove(listener);
+ }
+
+ public void removeSvdrpExceptionListener(
+ final SvdrpExceptionListener listener) {
+ svdrpExceptionListeners.remove(listener);
+ }
+
+ /**
+ * Cancel the current request
+ */
+ public void abort() {
+ abort = true;
+ try {
+ if (isConnected()) {
+ socket.shutdownInput();
+ socket.shutdownOutput();
+ socket.close();
+ }
+ } catch (final Exception ex) {
+ Log.w(TAG, ex);
+ }
+
+ }
+
+ // /**
+ // * Gets the list of results
+ // *
+ // * @return results
+ // */
+ // public List<Result> getResults() {
+ // return results;
+ // }
+
+ /**
+ * Connect to SVDRP
+ *
+ * @param host
+ * host
+ * @param port
+ * port
+ * @param ssl
+ * use SSL
+ * @throws IOException
+ * on errors
+ */
+ protected boolean connect() throws IOException {
+
+ final Preferences prefs = Preferences.get();
+ try {
+ // connect
+ informListener(SvdrpEvent.CONNECTING);
+
+ if (false && Preferences.get().isSecure()) {
+
+ final SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory
+ .getDefault(); // Erzeugt eine SSLSocketFactory mit
+ // Standartkonfiguration
+ socket = factory.createSocket();
+ } else {
+ socket = new Socket();
+ }
+
+ socket.connect(
+ new InetSocketAddress(prefs.getSvdrpHost(), prefs
+ .getSvdrpPort()),
+ prefs.getConnectionTimeout() * 1000);// 8 secs for connect
+ if (abort) {
+ informListener(SvdrpEvent.ABORTED);
+ }
+ //
+ socket.setSoTimeout(prefs.getReadTimeout() * 1000);// 15 sec for
+ // each read
+ final long delay = C.ONE_MINUTE_IN_MILLIS * prefs.getTimeout() * 60; // in
+ // 3
+ // minutes
+ // we
+ // abort
+ // the
+ // communication
+ watchDog.schedule(new TimerTask() {
+ @Override
+ public void run() {
+ Log.w(TAG, "Aborted after " + delay + " ms");
+ abort = true;
+ }
+ }, delay);
+ informListener(SvdrpEvent.CONNECTED);
+ } catch (final SocketTimeoutException sote) {
+ Log.w(TAG, sote);
+ if (abort) {
+ informListener(SvdrpEvent.ABORTED);
+ } else {
+ informListener(SvdrpEvent.CONNECTION_TIMEOUT);
+ }
+ return false;
+ } catch (final Exception e) {
+
+ Log.w(TAG, e);
+ if (abort) {
+ informListener(SvdrpEvent.ABORTED);
+ } else {
+ informListener(SvdrpEvent.CONNECT_ERROR);
+ }
+ return false;
+ }
+
+ // create streams
+ outputStream = socket.getOutputStream();
+ inputStream = socket.getInputStream();
+ // TODO http://projects.vdr-developer.org/issues/790
+ // inputStream = new InflaterInputStream(socket.getInputStream())
+
+ // password needed?
+ informListener(SvdrpEvent.LOGIN);
+ writeLine("passwd " + prefs.getPassword());
+ if (!readLine().startsWith("!OK")) {
+ informListener(SvdrpEvent.LOGIN_ERROR);
+ disconnect();
+ return false;
+ } else {
+ informListener(SvdrpEvent.LOGGED_IN);
+ }
+ return true;
+ }
+
+ /**
+ * Disconnect from SVDRP if connected
+ *
+ * @throws IOException
+ * on errors
+ */
+ protected void disconnect() throws IOException {
+ informListener(SvdrpEvent.DISCONNECTING);
+ if (socket != null && socket.isConnected()) {
+ socket.close();
+ socket = null;
+ }
+ informListener(SvdrpEvent.DISCONNECTED);
+ }
+
+ /**
+ * Sends one line to SVDRP
+ *
+ * @param line
+ * line of text
+ * @throws IOException
+ * on errors
+ */
+ protected void writeLine(final String line) throws IOException {
+
+ final String command = line + "\r\n";
+ // if (false && Preferences.get().isSecure()) {
+ // command = crypt.encrypt(command, Preferences.get().getPassword());
+ // }
+ final byte[] bytes = command.getBytes("utf-8");
+ outputStream.write(bytes);
+ outputStream.flush();
+ }
+
+ /**
+ * Reads one line from SVDRP
+ *
+ * @return line read
+ * @throws IOException
+ * on errors
+ */
+ protected String readLine() throws IOException {
+
+ // handle not gzipped input
+ final ByteArrayOutputStream lineBytes = new ByteArrayOutputStream();
+
+ for (;;) {
+
+ // read next char
+ final int d = inputStream.read();
+ if (d < 0) {
+ break;
+ }
+ final char c = (char) d;
+
+ // skip '\r'
+ if (c == '\r') {
+ continue;
+ }
+
+ // with '\n' the line is completed
+ if (c == '\n') {
+ break;
+ }
+
+ // remember char
+ lineBytes.write(c);
+ }
+
+ String line = null;
+ try {
+ line = lineBytes.toString(Preferences.get().getEncoding());
+ } catch (final UnsupportedEncodingException usex) {
+ Log.w(TAG, usex);
+ line = lineBytes.toString();
+ }
+ // if (false && Preferences.get().isSecure()) {
+ // line = crypt.decrypt(line, Preferences.get().getPassword());
+ // }
+ return line;
+ }
+
+ public void runCommand(final String command) {
+
+ try {
+
+ // reset cancel flag
+ abort = false;
+
+ // clear results
+ // results.clear();
+
+ // connect
+ final boolean connected = connect();
+ if (!connected) {
+ return;
+ }
+
+ // activate compression
+ Log.i(TAG, "Activate compression");
+ writeLine("compress");
+
+ // send command
+ informListener(SvdrpEvent.COMMAND_SENDING);
+ writeLine(command);
+ informListener(SvdrpEvent.COMMAND_SENT);
+ Log.i(TAG, SvdrpEvent.COMMAND_SENT + ":" + command);
+
+ // get the answer for the compress command or
+ // the first line of the answer for the command
+ String line = readLine();
+ if (line.startsWith("!OK")) {
+ final String[] words = line.split(" ");
+ if (words.length > 1) {
+ final String mode = words[1].toUpperCase();
+ if (mode.equals("ZLIB")) {
+ Log.i(TAG, "ZLIB compression activated");
+ inputStream = new InflaterInputStream(inputStream);
+ } else if (mode.equals("GZIP")) {
+ Log.i(TAG, "GZIP compression activated");
+ inputStream = new GZIPInputStream(inputStream);
+ } else {
+ Log.i(TAG, "NO compression activated");
+ }
+ }
+ line = readLine();
+ } else {
+ Log.i(TAG, "NO compression activated");
+ }
+
+ // correct answer?
+ if (!line.startsWith("START")) {
+ Log.w(TAG, line);
+ throw new IOException("Answer not wellformed: " + line);
+ }
+
+ // read answer lines
+ for (; !abort;) {
+
+ // get next line
+ line = readLine();
+ if (line.length() == 0) {
+ break;
+ }
+
+ // last line?
+ if (line.startsWith("END")) {
+ break;
+ }
+
+ // error?
+ if (line.startsWith("!ERROR")) {
+ Log.w(TAG, line);
+ String msg;
+ if (line.startsWith("!ERROR:")) {
+ msg = line.substring(7);
+ } else {
+ msg = line;
+ }
+ disconnect();
+ informListener(SvdrpEvent.ERROR, new SvdrpException(msg));
+ break;
+ }
+
+ // delegate analysis
+ Result result = null;
+ try {
+ result = parseAnswer(line);
+
+ } catch (final Exception ex) {
+ Log.w(TAG, ex);
+ disconnect();
+ Log.w(TAG, "line: " + line);
+ informListener(SvdrpEvent.ERROR, ex);
+ return;
+ }
+ if (result != null) {
+ informListener(result);
+ // results.add(result);
+ // if (resultInfoEnabled) {
+
+ // }
+ }
+
+ }
+
+ // disconnect
+ disconnect();
+
+ if (abort) {
+ informListener(SvdrpEvent.ABORTED);
+ } else {
+ informListener(SvdrpEvent.FINISHED_SUCCESS);
+ }
+
+ } catch (final Exception e) {
+ Log.w(TAG, e);
+ informListener(SvdrpEvent.FINISHED_ABNORMALY, e);
+ }
+ }
+
+ // public void setResultInfoEnabled(final boolean resultInfoEnabled) {
+ // this.resultInfoEnabled = resultInfoEnabled;
+ // }
+
+ protected void informListener(final SvdrpEvent event, final Throwable e) {
+ for (final SvdrpExceptionListener listener : svdrpExceptionListeners) {
+ listener.svdrpEvent(event, e);
+ }
+ }
+
+ protected void informListener(final SvdrpEvent event) {
+ for (final SvdrpListener listener : svdrpListeners) {
+ listener.svdrpEvent(event);
+ }
+ }
+
+ protected void informListener(final Result result) {
+ for (final SvdrpResultListener<Result> listener : svdrpResultListeners) {
+ listener.svdrpEvent(result);
+ }
+ }
}