mirror of
https://github.com/vanilla-wiiu/vanilla.git
synced 2025-01-22 16:21:48 -05:00
rework UDP backend for more event based system
This commit is contained in:
parent
195e314c9b
commit
64de9e9b08
4 changed files with 81 additions and 248 deletions
242
app/backend.cpp
242
app/backend.cpp
|
@ -1,5 +1,6 @@
|
||||||
#include "backend.h"
|
#include "backend.h"
|
||||||
|
|
||||||
|
#include <QBuffer>
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
@ -49,48 +50,39 @@ BackendViaPipe::BackendViaPipe(QObject *parent) : Backend(parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
BackendViaNamedPipe::BackendViaNamedPipe(const QString &wirelessInterface, QObject *parent) : BackendViaPipe(parent)
|
|
||||||
{
|
|
||||||
m_pipeIn = -1;
|
|
||||||
m_pipeOut = -1;
|
|
||||||
m_pipeThread = new QThread(this);
|
|
||||||
m_pipe = new BackendPipe(wirelessInterface, this);
|
|
||||||
connect(m_pipe, &BackendPipe::pipesAvailable, this, &BackendViaNamedPipe::setUpPipes);
|
|
||||||
connect(m_pipe, &BackendPipe::closed, this, &BackendViaNamedPipe::closed);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BackendViaNamedPipe::init()
|
|
||||||
{
|
|
||||||
m_pipe->setParent(nullptr);
|
|
||||||
m_pipeThread->start();
|
|
||||||
m_pipe->moveToThread(m_pipeThread);
|
|
||||||
QMetaObject::invokeMethod(m_pipe, &BackendPipe::start, Qt::QueuedConnection);
|
|
||||||
}
|
|
||||||
|
|
||||||
BackendViaSocket::BackendViaSocket(const QHostAddress &backendAddr, quint16 backendPort, QObject *parent) : BackendViaPipe(parent)
|
BackendViaSocket::BackendViaSocket(const QHostAddress &backendAddr, quint16 backendPort, QObject *parent) : BackendViaPipe(parent)
|
||||||
{
|
{
|
||||||
m_socket = new BackendUdpWrapper(backendAddr, backendPort, this);
|
m_backendAddress = backendAddr;
|
||||||
connect(m_socket, &BackendUdpWrapper::socketReady, this, &BackendViaSocket::socketReady);
|
m_backendPort = backendPort;
|
||||||
connect(m_socket, &BackendUdpWrapper::receivedData, this, &BackendViaSocket::receivedData, Qt::DirectConnection);
|
|
||||||
connect(m_socket, &BackendUdpWrapper::closed, this, &BackendViaSocket::closed);
|
|
||||||
connect(m_socket, &BackendUdpWrapper::error, this, &BackendViaSocket::error);
|
|
||||||
|
|
||||||
m_socketThread = new QThread(this);
|
m_socket = new QUdpSocket(this);
|
||||||
}
|
connect(m_socket, &QUdpSocket::readyRead, this, &BackendViaSocket::readPendingDatagrams);
|
||||||
|
connect(m_socket, &QUdpSocket::disconnected, this, &BackendViaSocket::closed);
|
||||||
BackendViaSocket::~BackendViaSocket()
|
|
||||||
{
|
|
||||||
m_socket->deleteLater();
|
|
||||||
m_socketThread->quit();
|
|
||||||
m_socketThread->wait();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackendViaSocket::init()
|
void BackendViaSocket::init()
|
||||||
{
|
{
|
||||||
m_socketThread->start();
|
bool connected = false;
|
||||||
m_socket->setParent(nullptr);
|
|
||||||
m_socket->moveToThread(m_socketThread);
|
for (m_frontendPort = 10100; m_frontendPort < 10200; m_frontendPort++) {
|
||||||
QMetaObject::invokeMethod(m_socket, &BackendUdpWrapper::start, Qt::QueuedConnection);
|
printf("Trying to bind to port %u\n", m_frontendPort);
|
||||||
|
if (m_socket->bind(QHostAddress::Any, m_frontendPort)) {
|
||||||
|
printf("Bound to port %u\n", m_frontendPort);
|
||||||
|
connected = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connected) {
|
||||||
|
// Send bind command to backend
|
||||||
|
pipe_control_code cmd;
|
||||||
|
cmd.code = VANILLA_PIPE_IN_BIND;
|
||||||
|
writeToPipe(&cmd, sizeof(cmd));
|
||||||
|
} else {
|
||||||
|
printf("Failed to bind to port\n");
|
||||||
|
emit error(tr("Failed to bind to UDP port"));
|
||||||
|
emit closed();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackendViaPipe::quitPipe()
|
void BackendViaPipe::quitPipe()
|
||||||
|
@ -100,15 +92,6 @@ void BackendViaPipe::quitPipe()
|
||||||
writeToPipe(&cmd, sizeof(cmd));
|
writeToPipe(&cmd, sizeof(cmd));
|
||||||
}
|
}
|
||||||
|
|
||||||
BackendViaNamedPipe::~BackendViaNamedPipe()
|
|
||||||
{
|
|
||||||
quitPipe();
|
|
||||||
|
|
||||||
m_pipe->deleteLater();
|
|
||||||
m_pipeThread->quit();
|
|
||||||
m_pipeThread->wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
void BackendViaLocalRoot::interrupt()
|
void BackendViaLocalRoot::interrupt()
|
||||||
{
|
{
|
||||||
vanilla_stop();
|
vanilla_stop();
|
||||||
|
@ -144,30 +127,42 @@ int BackendViaLocalRoot::connectInternal(BackendViaLocalRoot *instance, const QS
|
||||||
return vanilla_connect_to_console(wirelessInterfaceC.constData(), vanillaEventHandler, instance);
|
return vanilla_connect_to_console(wirelessInterfaceC.constData(), vanillaEventHandler, instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BackendViaPipe::processPacket(const QByteArray &arr)
|
||||||
|
{
|
||||||
|
const pipe_control_code *cc = (const pipe_control_code *) arr.data();
|
||||||
|
|
||||||
|
switch (cc->code) {
|
||||||
|
case VANILLA_PIPE_OUT_EOF:
|
||||||
|
// Do nothing?
|
||||||
|
break;
|
||||||
|
case VANILLA_PIPE_OUT_DATA:
|
||||||
|
{
|
||||||
|
pipe_data_command *event = (pipe_data_command *) cc;
|
||||||
|
event->data_size = ntohs(event->data_size);
|
||||||
|
vanillaEventHandler(this, event->event_type, (const char *) event->data, event->data_size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case VANILLA_PIPE_OUT_BOUND_SUCCESSFUL:
|
||||||
|
emit ready();
|
||||||
|
break;
|
||||||
|
case VANILLA_PIPE_ERR_SUCCESS:
|
||||||
|
printf("ERR_SUCCESS code\n");
|
||||||
|
break;
|
||||||
|
case VANILLA_PIPE_OUT_SYNC_STATE:
|
||||||
|
{
|
||||||
|
const pipe_sync_state_command *ss = (const pipe_sync_state_command *) cc;
|
||||||
|
emit syncCompleted(ss->state == VANILLA_SUCCESS);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void BackendViaPipe::connectToConsole()
|
void BackendViaPipe::connectToConsole()
|
||||||
{
|
{
|
||||||
// Request pipe to connect
|
// Request pipe to connect
|
||||||
pipe_control_code conn_cmd;
|
pipe_control_code conn_cmd;
|
||||||
conn_cmd.code = VANILLA_PIPE_IN_CONNECT;
|
conn_cmd.code = VANILLA_PIPE_IN_CONNECT;
|
||||||
writeToPipe(&conn_cmd, sizeof(conn_cmd));
|
writeToPipe(&conn_cmd, sizeof(conn_cmd));
|
||||||
|
|
||||||
uint8_t cmd[UINT16_MAX];
|
|
||||||
while (true) {
|
|
||||||
ssize_t read_size = readFromPipe(cmd, sizeof(cmd));
|
|
||||||
if (read_size == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
pipe_control_code *cc = (pipe_control_code *) cmd;
|
|
||||||
|
|
||||||
if (cc->code == VANILLA_PIPE_OUT_EOF) {
|
|
||||||
break;
|
|
||||||
} else if (cc->code == VANILLA_PIPE_OUT_DATA) {
|
|
||||||
pipe_data_command *event = (pipe_data_command *) cmd;
|
|
||||||
event->data_size = ntohs(event->data_size);
|
|
||||||
vanillaEventHandler(this, event->event_type, (const char *) event->data, event->data_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackendViaLocalRoot::updateTouch(int x, int y)
|
void BackendViaLocalRoot::updateTouch(int x, int y)
|
||||||
|
@ -252,40 +247,6 @@ void BackendViaPipe::sync(uint16_t code)
|
||||||
cmd.base.code = VANILLA_PIPE_IN_SYNC;
|
cmd.base.code = VANILLA_PIPE_IN_SYNC;
|
||||||
cmd.code = htons(code);
|
cmd.code = htons(code);
|
||||||
writeToPipe(&cmd, sizeof(cmd));
|
writeToPipe(&cmd, sizeof(cmd));
|
||||||
|
|
||||||
// See if pipe accepted our request to sync
|
|
||||||
uint8_t cc;
|
|
||||||
readFromPipe(&cc, sizeof(cc));
|
|
||||||
if (cc != VANILLA_PIPE_ERR_SUCCESS) {
|
|
||||||
emit syncCompleted(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for sync status
|
|
||||||
readFromPipe(&cc, sizeof(cc));
|
|
||||||
if (cc == VANILLA_PIPE_OUT_SYNC_STATE) {
|
|
||||||
readFromPipe(&cc, sizeof(cc));
|
|
||||||
emit syncCompleted(cc == VANILLA_SUCCESS);
|
|
||||||
} else {
|
|
||||||
emit syncCompleted(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BackendViaNamedPipe::setUpPipes(const QString &in, const QString &out)
|
|
||||||
{
|
|
||||||
QByteArray inUtf8 = in.toUtf8();
|
|
||||||
QByteArray outUtf8 = out.toUtf8();
|
|
||||||
m_pipeIn = open(inUtf8.constData(), O_RDONLY);
|
|
||||||
if (m_pipeIn == -1) {
|
|
||||||
QMessageBox::critical(nullptr, tr("Pipe Error"), tr("Failed to create in pipe: %1").arg(strerror(errno)));
|
|
||||||
}
|
|
||||||
m_pipeOut = open(outUtf8.constData(), O_WRONLY);
|
|
||||||
if (m_pipeOut == -1) {
|
|
||||||
QMessageBox::critical(nullptr, tr("Pipe Error"), tr("Failed to create out pipe: %1").arg(strerror(errno)));
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Established connection with backend\n");
|
|
||||||
emit ready();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BackendPipe::BackendPipe(const QString &wirelessInterface, QObject *parent) : QObject(parent)
|
BackendPipe::BackendPipe(const QString &wirelessInterface, QObject *parent) : QObject(parent)
|
||||||
|
@ -335,98 +296,15 @@ void BackendPipe::receivedData()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t BackendViaNamedPipe::readFromPipe(void *data, size_t length)
|
void BackendViaSocket::readPendingDatagrams()
|
||||||
{
|
|
||||||
return read(m_pipeIn, data, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t BackendViaNamedPipe::writeToPipe(const void *data, size_t length)
|
|
||||||
{
|
|
||||||
return write(m_pipeOut, data, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
BackendUdpWrapper::BackendUdpWrapper(const QHostAddress &backendAddr, quint16 backendPort, QObject *parent) : QObject(parent)
|
|
||||||
{
|
|
||||||
m_backendAddress = backendAddr;
|
|
||||||
m_backendPort = backendPort;
|
|
||||||
|
|
||||||
m_socket = new QUdpSocket(this);
|
|
||||||
connect(m_socket, &QUdpSocket::readyRead, this, &BackendUdpWrapper::readPendingDatagrams);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BackendUdpWrapper::start()
|
|
||||||
{
|
|
||||||
bool connected = false;
|
|
||||||
|
|
||||||
for (m_frontendPort = 10100; m_frontendPort < 10200; m_frontendPort++) {
|
|
||||||
printf("Trying to bind to port %u\n", m_frontendPort);
|
|
||||||
if (m_socket->bind(QHostAddress::Any, m_frontendPort)) {
|
|
||||||
printf("Bound to port %u\n", m_frontendPort);
|
|
||||||
connected = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (connected) {
|
|
||||||
emit socketReady(m_frontendPort);
|
|
||||||
} else {
|
|
||||||
printf("Failed to bind to port\n");
|
|
||||||
emit error(tr("Failed to bind to UDP port"));
|
|
||||||
emit closed();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BackendUdpWrapper::readPendingDatagrams()
|
|
||||||
{
|
{
|
||||||
while (m_socket->hasPendingDatagrams()) {
|
while (m_socket->hasPendingDatagrams()) {
|
||||||
QNetworkDatagram datagram = m_socket->receiveDatagram();
|
QNetworkDatagram datagram = m_socket->receiveDatagram();
|
||||||
emit receivedData(datagram.data());
|
processPacket(datagram.data());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackendUdpWrapper::write(const QByteArray &data)
|
|
||||||
{
|
|
||||||
m_socket->writeDatagram(data, m_backendAddress, m_backendPort);
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t BackendViaSocket::readFromPipe(void *data, size_t length)
|
|
||||||
{
|
|
||||||
m_readMutex.lock();
|
|
||||||
if (m_buffer.isEmpty()) {
|
|
||||||
m_readWaitCond.wait(&m_readMutex);
|
|
||||||
}
|
|
||||||
if (m_buffer.size() < length) {
|
|
||||||
length = m_buffer.size();
|
|
||||||
}
|
|
||||||
memcpy(data, m_buffer.constData(), length);
|
|
||||||
m_buffer.remove(0, length);
|
|
||||||
m_readMutex.unlock();
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t BackendViaSocket::writeToPipe(const void *data, size_t length)
|
ssize_t BackendViaSocket::writeToPipe(const void *data, size_t length)
|
||||||
{
|
{
|
||||||
QMetaObject::invokeMethod(m_socket, "write", Q_ARG(QByteArray, QByteArray((const char *) data, length)));
|
return m_socket->writeDatagram((const char *) data, length, m_backendAddress, m_backendPort);
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BackendViaSocket::receivedData(const QByteArray &data)
|
|
||||||
{
|
|
||||||
m_readMutex.lock();
|
|
||||||
m_buffer.append(data);
|
|
||||||
m_readWaitCond.wakeAll();
|
|
||||||
m_readMutex.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void BackendViaSocket::socketReady(quint16 port)
|
|
||||||
{
|
|
||||||
pipe_control_code cmd;
|
|
||||||
cmd.code = VANILLA_PIPE_IN_BIND;
|
|
||||||
writeToPipe(&cmd, sizeof(cmd));
|
|
||||||
|
|
||||||
uint8_t cc;
|
|
||||||
readFromPipe(&cc, sizeof(cc));
|
|
||||||
if (cc == VANILLA_PIPE_OUT_BOUND_SUCCESSFUL) {
|
|
||||||
emit ready();
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -103,6 +103,13 @@ class BackendViaPipe : public Backend
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
enum ListenState {
|
||||||
|
IDLE,
|
||||||
|
WAITING_FOR_SYNC_RESULT,
|
||||||
|
WAITING_FOR_BIND_RESULT,
|
||||||
|
RECEIVING_DATA
|
||||||
|
};
|
||||||
|
|
||||||
BackendViaPipe(QObject *parent = nullptr);
|
BackendViaPipe(QObject *parent = nullptr);
|
||||||
|
|
||||||
virtual void interrupt() override;
|
virtual void interrupt() override;
|
||||||
|
@ -116,55 +123,29 @@ public slots:
|
||||||
virtual void sync(uint16_t code) override;
|
virtual void sync(uint16_t code) override;
|
||||||
virtual void connectToConsole() override;
|
virtual void connectToConsole() override;
|
||||||
|
|
||||||
protected slots:
|
void quitPipe();
|
||||||
virtual ssize_t readFromPipe(void *data, size_t length) = 0;
|
|
||||||
|
protected:
|
||||||
|
void processPacket(const QByteArray &arr);
|
||||||
virtual ssize_t writeToPipe(const void *data, size_t length) = 0;
|
virtual ssize_t writeToPipe(const void *data, size_t length) = 0;
|
||||||
|
|
||||||
void quitPipe();
|
private:
|
||||||
|
ListenState m_listenState;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class BackendViaNamedPipe : public BackendViaPipe
|
class BackendViaSocket : public BackendViaPipe
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
BackendViaNamedPipe(const QString &wirelessInterface, QObject *parent = nullptr);
|
BackendViaSocket(const QHostAddress &backendAddr, quint16 backendPort, QObject *parent = nullptr);
|
||||||
virtual ~BackendViaNamedPipe() override;
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
virtual void init() override;
|
virtual void init() override;
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
BackendPipe *m_pipe;
|
|
||||||
QThread *m_pipeThread;
|
|
||||||
int m_pipeIn;
|
|
||||||
int m_pipeOut;
|
|
||||||
|
|
||||||
protected slots:
|
|
||||||
virtual ssize_t readFromPipe(void *data, size_t length) override;
|
|
||||||
virtual ssize_t writeToPipe(const void *data, size_t length) override;
|
virtual ssize_t writeToPipe(const void *data, size_t length) override;
|
||||||
|
|
||||||
private slots:
|
|
||||||
void setUpPipes(const QString &in, const QString &out);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class BackendUdpWrapper : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
BackendUdpWrapper(const QHostAddress &backendAddr, quint16 backendPort, QObject *parent = nullptr);
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void start();
|
|
||||||
void write(const QByteArray &data);
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void receivedData(const QByteArray &data);
|
|
||||||
void socketReady(quint16 port);
|
|
||||||
void closed();
|
|
||||||
void error(const QString &err);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QUdpSocket *m_socket;
|
QUdpSocket *m_socket;
|
||||||
QHostAddress m_backendAddress;
|
QHostAddress m_backendAddress;
|
||||||
|
@ -176,33 +157,4 @@ private slots:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class BackendViaSocket : public BackendViaPipe
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
BackendViaSocket(const QHostAddress &backendAddr, quint16 backendPort, QObject *parent = nullptr);
|
|
||||||
virtual ~BackendViaSocket() override;
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
virtual void init() override;
|
|
||||||
|
|
||||||
protected slots:
|
|
||||||
virtual ssize_t readFromPipe(void *data, size_t length) override;
|
|
||||||
virtual ssize_t writeToPipe(const void *data, size_t length) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
BackendUdpWrapper *m_socket;
|
|
||||||
QThread *m_socketThread;
|
|
||||||
|
|
||||||
QByteArray m_buffer;
|
|
||||||
|
|
||||||
QMutex m_readMutex;
|
|
||||||
QWaitCondition m_readWaitCond;
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void receivedData(const QByteArray &data);
|
|
||||||
void socketReady(quint16 port);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // BACKEND_H
|
#endif // BACKEND_H
|
|
@ -358,7 +358,10 @@ void MainWindow::initBackend(T func)
|
||||||
}
|
}
|
||||||
} else if ((geteuid() != 0)) {
|
} else if ((geteuid() != 0)) {
|
||||||
// If not root, use named pipe
|
// If not root, use named pipe
|
||||||
m_backend = new BackendViaNamedPipe(localWirelessIntf);
|
QMessageBox::critical(this, QString(), tr("Unimplemented..."));
|
||||||
|
d->deleteLater();
|
||||||
|
return;
|
||||||
|
//m_backend = new BackendViaNamedPipe(localWirelessIntf);
|
||||||
} else {
|
} else {
|
||||||
// If root, use lib locally
|
// If root, use lib locally
|
||||||
m_backend = new BackendViaLocalRoot(localWirelessIntf);
|
m_backend = new BackendViaLocalRoot(localWirelessIntf);
|
||||||
|
|
|
@ -78,7 +78,7 @@ struct pipe_data_command
|
||||||
struct pipe_control_code base;
|
struct pipe_control_code base;
|
||||||
uint8_t event_type;
|
uint8_t event_type;
|
||||||
uint16_t data_size;
|
uint16_t data_size;
|
||||||
uint8_t data[UINT16_MAX];
|
uint8_t data[2048];
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
Loading…
Reference in a new issue