Commit c2a375e5 authored by Christoph Pfister's avatar Christoph Pfister

start implementing a (for now local) daemon

--> see NOTES
parent 2da9df1e
......@@ -25,6 +25,7 @@ if(NOT HAVE_DVB)
endif(NOT HAVE_DVB)
add_subdirectory(deviceactions)
add_subdirectory(dtvdaemon)
add_subdirectory(icons)
add_subdirectory(profiles)
add_subdirectory(src)
......
......@@ -4,6 +4,18 @@ About this file
This file covers various topics relevant to Kaffeine development.
---------
dtvdaemon
---------
dtvdaemon is intended as a small, standalone daemon to communicate with the digital TV devices
(supported by linuxtv.org or other projects). It provides a convenience layer (channels, epg, etc)
and should only depend on QtCore and QtNetwork. Currently the focus lies on a local daemon, which
runs only on demand, but it should be easy to make it accessible through TCP/IP.
One advantage is the possibility to run multiple instances of Kaffeine at the same time. While
implementing it, enhancements (e.g. support for new delivery systems) are also tried to achieve.
------------------------
DVB-T channel allocation
------------------------
......
set(dtvdaemon_SRCS
connection.cpp
dtvdaemon.cpp
log.cpp
main.cpp)
kde4_add_executable(dtvdaemon ${dtvdaemon_SRCS})
target_link_libraries(dtvdaemon ${QT_QTCORE_LIBRARY} ${QT_QTNETWORK_LIBRARY})
install(TARGETS dtvdaemon ${INSTALL_TARGETS_DEFAULT_ARGS})
/*
* connection.cpp
*
* Copyright (C) 2012 Christoph Pfister <christophpfister@gmail.com>
*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "connection.h"
#include <QLocalSocket>
#include <QtEndian>
#include "log.h"
Connection::Connection(QLocalSocket *socket_) : QObject(socket_), socket(socket_),
packetCommand(0), packetLength(0)
{
if (socket->state() != QLocalSocket::ConnectedState) {
socket->deleteLater();
return;
}
Log("Connection::Connection: opened connection") << quintptr(this);
connect(socket, SIGNAL(disconnected()), socket, SLOT(deleteLater()));
connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
}
Connection::~Connection()
{
Log("Connection::~Connection: closed connection") << quintptr(this);
}
void Connection::checkIdle(bool *idle)
{
*idle = false;
}
void Connection::readyRead()
{
while (true) {
if (packetCommand == 0) {
if (socket->bytesAvailable() < 8) {
break;
}
union {
struct {
quint32 command;
quint32 length;
} info;
char data[8];
} u;
memset(&u.info, 0, sizeof(u.info));
socket->read(u.data, 8);
quint32 command = qFromLittleEndian(u.info.command);
quint32 length = qFromLittleEndian(u.info.length);
if ((command == 0) || (length > (1024 * 1024))) {
Log("Connection::readyRead: invalid packet");
socket->abort();
return;
}
packetCommand = command;
packetLength = length;
} else {
if (socket->bytesAvailable() < packetLength) {
break;
}
handlePacket();
packetCommand = 0;
packetLength = 0;
}
}
}
void Connection::handlePacket()
{
bool ok = false;
switch (packetCommand) {
case GetVersion: {
QString version = QLatin1String("1.2.2"); // FIXME
writeHeader(GetVersionReply, sizeForString(version));
writeString(version);
ok = true;
break;
}
}
if (!ok) {
Log("Connection::handlePacket: invalid packet") << packetCommand;
} else if (packetLength != 0) {
Log("Connection::handlePacket: packet has wrong size") << packetCommand;
}
while (packetLength > 0) {
char buffer[4096];
int size = qMin(packetLength, int(sizeof(buffer)));
int bytesRead = socket->read(buffer, size);
if (bytesRead <= 0) {
Log("Connection::handlePacket: cannot empty buffer");
break;
}
packetLength -= bytesRead;
}
}
void Connection::writeHeader(quint32 command, quint32 length)
{
union {
struct {
quint32 command;
quint32 length;
} info;
char data[8];
} u;
u.info.command = qToLittleEndian(command);
u.info.length = qToLittleEndian(length);
socket->write(u.data, 8);
}
int Connection::sizeForString(const QString &string)
{
return (6 + 2 * string.size());
}
void Connection::writeString(const QString &string)
{
union {
struct {
quint32 size;
quint16 byteOrderMark;
} info;
char data[6];
} u;
u.info.size = qToLittleEndian(string.size());
u.info.byteOrderMark = 0xfeff;
socket->write(u.data, 6);
socket->write(reinterpret_cast<const char *>(string.constData()), 2 * string.size());
}
/*
* connection.h
*
* Copyright (C) 2012 Christoph Pfister <christophpfister@gmail.com>
*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef CONNECTION_H
#define CONNECTION_H
#include <QObject>
class QLocalSocket;
class Connection : public QObject
{
Q_OBJECT
public:
explicit Connection(QLocalSocket *socket_);
~Connection();
enum Request {
GetVersion = 0x67c60000
};
enum Reply {
GetVersionReply = 0x58e70000
};
private slots:
void checkIdle(bool *idle);
void readyRead();
private:
void handlePacket();
void writeHeader(quint32 command, quint32 length);
int sizeForString(const QString &string);
void writeString(const QString &string);
QLocalSocket *socket;
int packetCommand;
int packetLength;
};
#endif /* CONNECTION_H */
/*
* dtvdaemon.cpp
*
* Copyright (C) 2012 Christoph Pfister <christophpfister@gmail.com>
*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "dtvdaemon.h"
#include <QCoreApplication>
#include <QDir>
#include <QLocalSocket>
#include "connection.h"
#include "log.h"
DtvDaemon::DtvDaemon(QFile *lockfile_) : lockfile(lockfile_)
{
Log("DtvDaemon::DtvDaemon: started");
startTimer(54000);
QString path = QDir::homePath() + QLatin1String("/.local/share/dtvdaemon/socket");
QLocalServer::removeServer(path);
if (!server.listen(path)) {
Log("DtvDaemon::DtvDaemon: cannot listen on") << path << server.errorString();
}
connect(&server, SIGNAL(newConnection()), this, SLOT(newConnection()));
}
DtvDaemon::~DtvDaemon()
{
Log("DtvDaemon::~DtvDaemon: stopped");
}
void DtvDaemon::newConnection()
{
while (true) {
QLocalSocket *socket = server.nextPendingConnection();
if (socket == NULL) {
break;
}
Connection *connection = new Connection(socket);
connect(this, SIGNAL(checkIdle(bool*)), connection, SLOT(checkIdle(bool*)));
}
}
void DtvDaemon::timerEvent(QTimerEvent *)
{
bool idle = true;
emit checkIdle(&idle);
if (idle) {
lockfile->close();
server.close();
QCoreApplication::exit();
}
}
/*
* dtvdaemon.h
*
* Copyright (C) 2012 Christoph Pfister <christophpfister@gmail.com>
*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef DTVDAEMON_H
#define DTVDAEMON_H
#include <QMap>
#include <QObject>
#include <QLocalServer>
class QFile;
class DtvDaemon : public QObject
{
Q_OBJECT
public:
explicit DtvDaemon(QFile *lockfile_);
~DtvDaemon();
signals:
void checkIdle(bool *idle);
private slots:
void newConnection();
private:
void timerEvent(QTimerEvent *event);
QFile *lockfile;
QLocalServer server;
};
#endif /* DTVDAEMON_H */
#include "../src/log.cpp"
#include "../src/log.h"
/*
* main.cpp
*
* Copyright (C) 2012 Christoph Pfister <christophpfister@gmail.com>
*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <QCoreApplication>
#include <QDir>
#include <QFile>
#include <unistd.h>
#include "dtvdaemon.h"
#include "log.h"
int main(int argc, char *argv[])
{
QCoreApplication application(argc, argv);
QDir::home().mkpath(QLatin1String(".local/share/dtvdaemon"));
QFile file(QDir::homePath() + QLatin1String("/.local/share/dtvdaemon/lockfile"));
if (!file.open(QIODevice::WriteOnly)) {
Log("main: cannot open") << file.fileName();
return 1;
}
if (lockf(file.handle(), F_TLOCK, 0) != 0) {
// cannot lock file
return 0;
}
// closing the file or terminating the application releases the lock
DtvDaemon daemon(&file);
return application.exec();
}
......@@ -86,6 +86,7 @@ public:
QString Log::getLog()
{
if (data != NULL) {
QMutexLocker locker(&data->mutex);
return data->buffer;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment