From 6290f187696b97c6f7dd055f69065aa534d91210 Mon Sep 17 00:00:00 2001 From: MattKC <34096995+itsmattkc@users.noreply.github.com> Date: Fri, 2 Aug 2024 10:46:16 -0700 Subject: [PATCH] implemented UDP mode --- app/CMakeLists.txt | 1 + app/backend.cpp | 443 +++++++++++++++++++++++-------------- app/backend.h | 152 +++++++++++-- app/backendinitdialog.cpp | 11 + app/backendinitdialog.h | 13 ++ app/mainwindow.cpp | 120 +++++++--- app/mainwindow.h | 7 + app/syncdialog.cpp | 5 +- app/syncdialog.h | 3 +- app/syncprogressdialog.cpp | 4 +- app/syncprogressdialog.h | 3 +- pipe/main.c | 188 +++++++--------- pipe/pipe.h | 59 ++++- 13 files changed, 673 insertions(+), 336 deletions(-) create mode 100644 app/backendinitdialog.cpp create mode 100644 app/backendinitdialog.h diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 6b33425..557ba02 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -9,6 +9,7 @@ set(CMAKE_AUTORCC ON) add_executable(vanilla-gui audiohandler.cpp backend.cpp + backendinitdialog.cpp gamepadhandler.cpp keymap.cpp inputconfigdialog.cpp diff --git a/app/backend.cpp b/app/backend.cpp index 25ebc71..90f4281 100644 --- a/app/backend.cpp +++ b/app/backend.cpp @@ -3,7 +3,9 @@ #include #include #include +#include +#include #include #include #include @@ -30,216 +32,226 @@ void vanillaEventHandler(void *context, int type, const char *data, size_t dataL Backend::Backend(QObject *parent) : QObject(parent) { - m_pipe = nullptr; +} + +void Backend::init() +{ + emit ready(); +} + +BackendViaLocalRoot::BackendViaLocalRoot(const QString &wirelessInterface, QObject *parent) : Backend(parent) +{ + m_wirelessInterface = wirelessInterface; +} + +BackendViaPipe::BackendViaPipe(QObject *parent) : Backend(parent) +{ +} + +BackendViaNamedPipe::BackendViaNamedPipe(const QString &wirelessInterface, QObject *parent) : BackendViaPipe(parent) +{ m_pipeIn = -1; m_pipeOut = -1; - m_interrupt = 0; - - // If not running as root, use pipe - if ((geteuid() != 0)) { - m_pipeThread = new QThread(this); - m_pipeThread->start(); - - m_pipe = new BackendPipe(); - m_pipe->moveToThread(m_pipeThread); - - connect(m_pipe, &BackendPipe::pipesAvailable, this, &Backend::setUpPipes); - - QMetaObject::invokeMethod(m_pipe, &BackendPipe::start, Qt::QueuedConnection); - } + 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); } -Backend::~Backend() +void BackendViaNamedPipe::init() { - if (m_pipe) { - m_pipeMutex.lock(); - uint8_t cc = VANILLA_PIPE_IN_QUIT; - write(m_pipeOut, &cc, sizeof(cc)); - m_pipeMutex.unlock(); - - m_pipe->deleteLater(); - m_pipeThread->quit(); - m_pipeThread->wait(); - } + m_pipe->setParent(nullptr); + m_pipeThread->start(); + m_pipe->moveToThread(m_pipeThread); + QMetaObject::invokeMethod(m_pipe, &BackendPipe::start, Qt::QueuedConnection); } -void ignoreByte(int pipe) +BackendViaUdp::BackendViaUdp(const QHostAddress &backendAddr, quint16 backendPort, QObject *parent) : BackendViaPipe(parent) { - uint8_t ignore; - read(pipe, &ignore, sizeof(ignore)); + m_socket = new BackendUdpWrapper(backendAddr, backendPort, this); + connect(m_socket, &BackendUdpWrapper::socketReady, this, &BackendViaUdp::socketReady); + connect(m_socket, &BackendUdpWrapper::receivedData, this, &BackendViaUdp::receivedData, Qt::DirectConnection); + connect(m_socket, &BackendUdpWrapper::closed, this, &BackendViaUdp::closed); + connect(m_socket, &BackendUdpWrapper::error, this, &BackendViaUdp::error); + + m_socketThread = new QThread(this); } -void writeByte(int pipe, uint8_t byte) +BackendViaUdp::~BackendViaUdp() { - write(pipe, &byte, sizeof(byte)); + m_socket->deleteLater(); + m_socketThread->quit(); + m_socketThread->wait(); } -void Backend::interrupt() +void BackendViaUdp::init() { - if (m_pipe) { - m_pipeMutex.lock(); - uint8_t cc = VANILLA_PIPE_IN_INTERRUPT; - write(m_pipeOut, &cc, sizeof(cc)); - m_pipeMutex.unlock(); - } else { - vanilla_stop(); - } + m_socketThread->start(); + m_socket->setParent(nullptr); + m_socket->moveToThread(m_socketThread); + QMetaObject::invokeMethod(m_socket, &BackendUdpWrapper::start, Qt::QueuedConnection); } -void writeNullTermString(int pipe, const QString &s) +void BackendViaPipe::quitPipe() { - QByteArray sc = s.toUtf8(); - write(pipe, sc.constData(), sc.size()); - writeByte(pipe, 0); + pipe_control_code cmd; + cmd.code = VANILLA_PIPE_IN_QUIT; + writeToPipe(&cmd, sizeof(cmd)); } -void Backend::requestIDR() +BackendViaNamedPipe::~BackendViaNamedPipe() { - if (m_pipe) { - m_pipeMutex.lock(); - writeByte(m_pipeOut, VANILLA_PIPE_IN_REQ_IDR); - m_pipeMutex.unlock(); - } else { - vanilla_request_idr(); - } + quitPipe(); + + m_pipe->deleteLater(); + m_pipeThread->quit(); + m_pipeThread->wait(); } -void Backend::connectToConsole(const QString &wirelessInterface) +void BackendViaLocalRoot::interrupt() { - if (m_pipe) { - // Request pipe to connect - m_pipeMutex.lock(); - writeByte(m_pipeOut, VANILLA_PIPE_IN_CONNECT); - writeNullTermString(m_pipeOut, wirelessInterface); - m_pipeMutex.unlock(); - - uint8_t cc; - while (true) { - ssize_t read_size = read(m_pipeIn, &cc, sizeof(cc)); - if (read_size == 0) { - continue; - } - - if (cc == VANILLA_PIPE_OUT_EOF) { - break; - } else if (cc == VANILLA_PIPE_OUT_DATA) { - // Read event - read(m_pipeIn, &cc, sizeof(cc)); - - // Read data size - uint64_t data_size; - read(m_pipeIn, &data_size, sizeof(data_size)); - - void *buf = malloc(data_size); - read(m_pipeIn, buf, data_size); - - vanillaEventHandler(this, cc, (const char *) buf, data_size); - - free(buf); - } - } - } else { - QByteArray wirelessInterfaceC = wirelessInterface.toUtf8(); - vanilla_connect_to_console(wirelessInterfaceC.constData(), vanillaEventHandler, this); - } + vanilla_stop(); } -void Backend::updateTouch(int x, int y) +void BackendViaPipe::interrupt() { - if (m_pipe) { - m_pipeMutex.lock(); - writeByte(m_pipeOut, VANILLA_PIPE_IN_TOUCH); - int32_t touchX = x; - int32_t touchY = y; - write(m_pipeOut, &x, sizeof(x)); - write(m_pipeOut, &y, sizeof(y)); - m_pipeMutex.unlock(); - } else { - vanilla_set_touch(x, y); - } + pipe_control_code cmd; + cmd.code = VANILLA_PIPE_IN_INTERRUPT; + writeToPipe(&cmd, sizeof(cmd)); } -void Backend::setButton(int button, int32_t value) +void BackendViaLocalRoot::requestIDR() { - if (m_pipe) { - m_pipeMutex.lock(); - writeByte(m_pipeOut, VANILLA_PIPE_IN_BUTTON); - int32_t buttonSized = button; - write(m_pipeOut, &buttonSized, sizeof(buttonSized)); - write(m_pipeOut, &value, sizeof(value)); - m_pipeMutex.unlock(); - } else { - vanilla_set_button(button, value); - } + vanilla_request_idr(); } -void Backend::setRegion(int region) +void BackendViaPipe::requestIDR() { - if (m_pipe) { - m_pipeMutex.lock(); - writeByte(m_pipeOut, VANILLA_PIPE_IN_REGION); - int8_t regionSized = region; - write(m_pipeOut, ®ionSized, sizeof(regionSized)); - m_pipeMutex.unlock(); - } else { - vanilla_set_region(region); - } + pipe_control_code cmd; + cmd.code = VANILLA_PIPE_IN_REQ_IDR; + writeToPipe(&cmd, sizeof(cmd)); } -void Backend::setBatteryStatus(int status) +void BackendViaLocalRoot::connectToConsole() { - if (m_pipe) { - m_pipeMutex.lock(); - writeByte(m_pipeOut, VANILLA_PIPE_IN_BATTERY); - int8_t batterySized = status; - write(m_pipeOut, &batterySized, sizeof(batterySized)); - m_pipeMutex.unlock(); - } else { - vanilla_set_battery_status(status); - } + QByteArray wirelessInterfaceC = m_wirelessInterface.toUtf8(); + vanilla_connect_to_console(wirelessInterfaceC.constData(), vanillaEventHandler, this); } -void Backend::sync(const QString &wirelessInterface, uint16_t code) +void BackendViaPipe::connectToConsole() { - if (m_pipe) { - // Request pipe to sync - m_pipeMutex.lock(); - - // Write control code - writeByte(m_pipeOut, VANILLA_PIPE_IN_SYNC); + // Request pipe to connect + pipe_control_code conn_cmd; + conn_cmd.code = VANILLA_PIPE_IN_CONNECT; + writeToPipe(&conn_cmd, sizeof(conn_cmd)); - // Write WPS code - write(m_pipeOut, &code, sizeof(code)); - - // Write wireless interface - writeNullTermString(m_pipeOut, wirelessInterface); - - m_pipeMutex.unlock(); - - // See if pipe accepted our request to sync - uint8_t cc; - read(m_pipeIn, &cc, sizeof(cc)); - if (cc != VANILLA_PIPE_ERR_SUCCESS) { - emit syncCompleted(false); - return; + uint8_t cmd[UINT16_MAX]; + while (true) { + ssize_t read_size = readFromPipe(cmd, sizeof(cmd)); + if (read_size == 0) { + continue; } - // Wait for sync status - read(m_pipeIn, &cc, sizeof(cc)); - if (cc == VANILLA_PIPE_OUT_SYNC_STATE) { - read(m_pipeIn, &cc, sizeof(cc)); - emit syncCompleted(cc == VANILLA_SUCCESS); - } else { - emit syncCompleted(false); + 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); } - } else { - QByteArray wirelessInterfaceC = wirelessInterface.toUtf8(); - int r = vanilla_sync_with_console(wirelessInterfaceC.constData(), code); - emit syncCompleted(r == VANILLA_SUCCESS); } } -void Backend::setUpPipes(const QString &in, const QString &out) +void BackendViaLocalRoot::updateTouch(int x, int y) +{ + vanilla_set_touch(x, y); +} + +void BackendViaPipe::updateTouch(int x, int y) +{ + pipe_touch_command cmd; + cmd.base.code = VANILLA_PIPE_IN_TOUCH; + cmd.x = htonl(x); + cmd.y = htonl(y); + writeToPipe(&cmd, sizeof(cmd)); +} + +void BackendViaLocalRoot::setButton(int button, int32_t value) +{ + vanilla_set_button(button, value); +} + +void BackendViaPipe::setButton(int button, int32_t value) +{ + pipe_button_command cmd; + cmd.base.code = VANILLA_PIPE_IN_BUTTON; + cmd.id = htonl(button); + cmd.value = htonl(value); + writeToPipe(&cmd, sizeof(cmd)); +} + +void BackendViaLocalRoot::setRegion(int region) +{ + vanilla_set_region(region); +} + +void BackendViaPipe::setRegion(int region) +{ + pipe_region_command cmd; + cmd.base.code = VANILLA_PIPE_IN_REGION; + cmd.region = region; + writeToPipe(&cmd, sizeof(cmd)); +} + +void BackendViaLocalRoot::setBatteryStatus(int status) +{ + vanilla_set_battery_status(status); +} + +void BackendViaPipe::setBatteryStatus(int status) +{ + pipe_battery_command cmd; + cmd.base.code = VANILLA_PIPE_IN_BATTERY; + cmd.battery = status; + writeToPipe(&cmd, sizeof(cmd)); +} + +void BackendViaLocalRoot::sync(uint16_t code) +{ + QByteArray wirelessInterfaceC = m_wirelessInterface.toUtf8(); + int r = vanilla_sync_with_console(wirelessInterfaceC.constData(), code); + emit syncCompleted(r == VANILLA_SUCCESS); +} + +void BackendViaPipe::sync(uint16_t code) +{ + // Request pipe to sync + pipe_sync_command cmd; + cmd.base.code = VANILLA_PIPE_IN_SYNC; + cmd.code = code; + 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(); @@ -253,11 +265,13 @@ void Backend::setUpPipes(const QString &in, const QString &out) } printf("Established connection with backend\n"); + emit ready(); } -BackendPipe::BackendPipe(QObject *parent) : QObject(parent) +BackendPipe::BackendPipe(const QString &wirelessInterface, QObject *parent) : QObject(parent) { m_process = nullptr; + m_wirelessInterface = wirelessInterface; } BackendPipe::~BackendPipe() @@ -281,12 +295,12 @@ void BackendPipe::start() m_process = new QProcess(this); m_process->setReadChannel(QProcess::StandardError); connect(m_process, &QProcess::readyReadStandardError, this, &BackendPipe::receivedData); - //connect(m_pipe, &QProcess::finished, this, [this](int code){printf("closed??? %i\n", code);}); + connect(m_process, &QProcess::finished, this, &BackendPipe::closed); m_pipeOutFilename = QStringLiteral("/tmp/vanilla-fifo-in-%0").arg(QString::number(QDateTime::currentMSecsSinceEpoch())); m_pipeInFilename = QStringLiteral("/tmp/vanilla-fifo-out-%0").arg(QString::number(QDateTime::currentMSecsSinceEpoch())); - m_process->start(QStringLiteral("pkexec"), {pipe_bin, QStringLiteral("-pipe"), m_pipeOutFilename, m_pipeInFilename}); + m_process->start(QStringLiteral("pkexec"), {pipe_bin, m_wirelessInterface, QStringLiteral("-pipe"), m_pipeOutFilename, m_pipeInFilename}); } void BackendPipe::receivedData() @@ -299,4 +313,97 @@ void BackendPipe::receivedData() printf("%s\n", a.constData()); } } +} + +ssize_t BackendViaNamedPipe::readFromPipe(void *data, size_t length) +{ + 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()) { + QNetworkDatagram datagram = m_socket->receiveDatagram(); + emit receivedData(datagram.data()); + } +} + +void BackendUdpWrapper::write(const QByteArray &data) +{ + m_socket->writeDatagram(data, m_backendAddress, m_backendPort); +} + +ssize_t BackendViaUdp::readFromPipe(void *data, size_t length) +{ + m_readMutex.lock(); + if (m_buffer.size() < length) { + m_readWaitCond.wait(&m_readMutex); + } + memcpy(data, m_buffer.constData(), length); + m_buffer.remove(0, length); + m_readMutex.unlock(); + return length; +} + +ssize_t BackendViaUdp::writeToPipe(const void *data, size_t length) +{ + QMetaObject::invokeMethod(m_socket, "write", Q_ARG(QByteArray, QByteArray((const char *) data, length))); + return length; +} + +void BackendViaUdp::receivedData(const QByteArray &data) +{ + m_readMutex.lock(); + m_buffer.append(data); + m_readWaitCond.wakeAll(); + m_readMutex.unlock(); +} + +void BackendViaUdp::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(); + } } \ No newline at end of file diff --git a/app/backend.h b/app/backend.h index 0552a50..98b0dc5 100644 --- a/app/backend.h +++ b/app/backend.h @@ -1,16 +1,19 @@ #ifndef BACKEND_H #define BACKEND_H +#include #include #include #include #include +#include +#include class BackendPipe : public QObject { Q_OBJECT public: - BackendPipe(QObject *parent = nullptr); + BackendPipe(const QString &wirelessInterface, QObject *parent = nullptr); virtual ~BackendPipe() override; @@ -22,6 +25,7 @@ public slots: signals: void pipesAvailable(const QString &in, const QString &out); void portAvailable(uint16_t port); + void closed(); private slots: void receivedData(); @@ -32,6 +36,7 @@ private: QString m_pipeInFilename; uint16_t m_serverPort; uint16_t m_clientPort; + QString m_wirelessInterface; }; @@ -41,9 +46,13 @@ class Backend : public QObject public: Backend(QObject *parent = nullptr); - virtual ~Backend() override; - - void interrupt(); + // These are all commands that can be issued to the backend. They are re-entrant and can be called at any time. + virtual void interrupt() = 0; + virtual void updateTouch(int x, int y) = 0; + virtual void setButton(int button, int32_t value) = 0; + virtual void requestIDR() = 0; + virtual void setRegion(int region) = 0; + virtual void setBatteryStatus(int status) = 0; signals: void videoAvailable(const QByteArray &packet); @@ -51,27 +60,144 @@ signals: void vibrate(bool on); void errorOccurred(); void syncCompleted(bool success); + void ready(); + void closed(); + void error(const QString &err); public slots: - void sync(const QString &wirelessInterface, uint16_t code); - void connectToConsole(const QString &wirelessInterface); - void updateTouch(int x, int y); - void setButton(int button, int32_t value); - void requestIDR(); - void setRegion(int region); - void setBatteryStatus(int status); + // These slots must be called with Qt::QueuedConnection to start the event loops in the backend's thread + virtual void init(); + virtual void sync(uint16_t code) = 0; + virtual void connectToConsole() = 0; + +}; + +class BackendViaLocalRoot : public Backend +{ + Q_OBJECT +public: + BackendViaLocalRoot(const QString &wirelessInterface, QObject *parent = nullptr); + + virtual void interrupt() override; + virtual void updateTouch(int x, int y) override; + virtual void setButton(int button, int32_t value) override; + virtual void requestIDR() override; + virtual void setRegion(int region) override; + virtual void setBatteryStatus(int status) override; + +public slots: + virtual void sync(uint16_t code) override; + virtual void connectToConsole() override; + +private: + QString m_wirelessInterface; + +}; + +class BackendViaPipe : public Backend +{ + Q_OBJECT +public: + BackendViaPipe(QObject *parent = nullptr); + + virtual void interrupt() override; + virtual void updateTouch(int x, int y) override; + virtual void setButton(int button, int32_t value) override; + virtual void requestIDR() override; + virtual void setRegion(int region) override; + virtual void setBatteryStatus(int status) override; + +public slots: + virtual void sync(uint16_t code) override; + virtual void connectToConsole() override; + +protected slots: + virtual ssize_t readFromPipe(void *data, size_t length) = 0; + virtual ssize_t writeToPipe(const void *data, size_t length) = 0; + + void quitPipe(); + +}; + +class BackendViaNamedPipe : public BackendViaPipe +{ + Q_OBJECT +public: + BackendViaNamedPipe(const QString &wirelessInterface, QObject *parent = nullptr); + virtual ~BackendViaNamedPipe() override; + +public slots: + virtual void init() override; private: BackendPipe *m_pipe; QThread *m_pipeThread; int m_pipeIn; int m_pipeOut; - QMutex m_pipeMutex; - QAtomicInt m_interrupt; + +protected slots: + virtual ssize_t readFromPipe(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: + QUdpSocket *m_socket; + QHostAddress m_backendAddress; + quint16 m_frontendPort; + quint16 m_backendPort; + +private slots: + void readPendingDatagrams(); + +}; + +class BackendViaUdp : public BackendViaPipe +{ + Q_OBJECT +public: + BackendViaUdp(const QHostAddress &backendAddr, quint16 backendPort, QObject *parent = nullptr); + virtual ~BackendViaUdp() 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 \ No newline at end of file diff --git a/app/backendinitdialog.cpp b/app/backendinitdialog.cpp new file mode 100644 index 0000000..eb49210 --- /dev/null +++ b/app/backendinitdialog.cpp @@ -0,0 +1,11 @@ +#include "backendinitdialog.h" + +#include +#include + +BackendInitDialog::BackendInitDialog(QWidget *parent) : QDialog(parent) +{ + QVBoxLayout *l = new QVBoxLayout(this); + + l->addWidget(new QLabel(tr("Initializing backend..."))); +} diff --git a/app/backendinitdialog.h b/app/backendinitdialog.h new file mode 100644 index 0000000..76bdb78 --- /dev/null +++ b/app/backendinitdialog.h @@ -0,0 +1,13 @@ +#ifndef BACKEND_INIT_DIALOG_H +#define BACKEND_INIT_DIALOG_H + +#include + +class BackendInitDialog : public QDialog +{ + Q_OBJECT +public: + BackendInitDialog(QWidget *parent = nullptr); +}; + +#endif // BACKEND_INIT_DIALOG_H \ No newline at end of file diff --git a/app/mainwindow.cpp b/app/mainwindow.cpp index 5458558..140c4c5 100644 --- a/app/mainwindow.cpp +++ b/app/mainwindow.cpp @@ -25,6 +25,7 @@ #include #include +#include "backendinitdialog.h" #include "inputconfigdialog.h" #include "keymap.h" #include "syncdialog.h" @@ -35,6 +36,8 @@ MainWindow::MainWindow(QWidget *parent) : QWidget(parent) QMessageBox::critical(this, tr("SDL2 Error"), tr("SDL2 failed to initialize. Controller support will be unavailable.")); } + m_backend = nullptr; + qRegisterMetaType("uint16_t"); QHBoxLayout *layout = new QHBoxLayout(this); @@ -71,6 +74,7 @@ MainWindow::MainWindow(QWidget *parent) : QWidget(parent) configLayout->addWidget(new QLabel(tr("Wi-Fi Adapter: "), connectionConfigGroupBox), row, 0); m_wirelessInterfaceComboBox = new QComboBox(connectionConfigGroupBox); + connect(m_wirelessInterfaceComboBox, &QComboBox::currentIndexChanged, this, &MainWindow::closeBackend); configLayout->addWidget(m_wirelessInterfaceComboBox, row, 1); row++; @@ -84,7 +88,6 @@ MainWindow::MainWindow(QWidget *parent) : QWidget(parent) m_connectBtn = new QPushButton(connectionConfigGroupBox); m_connectBtn->setCheckable(true); //m_connectBtn->setEnabled(vanilla_has_config()); // TODO: Implement this properly through the pipe at some point - m_backend = nullptr; setConnectedState(false); connect(m_connectBtn, &QPushButton::clicked, this, &MainWindow::setConnectedState); configLayout->addWidget(m_connectBtn, row, 0, 1, 2); @@ -209,9 +212,6 @@ MainWindow::MainWindow(QWidget *parent) : QWidget(parent) configOuterLayout->addStretch(); - m_backend = new Backend(); - startObjectOnThread(m_backend); - m_videoDecoder = new VideoDecoder(); connect(m_recordBtn, &QPushButton::clicked, m_videoDecoder, &VideoDecoder::enableRecording); startObjectOnThread(m_videoDecoder); @@ -224,18 +224,10 @@ MainWindow::MainWindow(QWidget *parent) : QWidget(parent) startObjectOnThread(m_audioHandler); QMetaObject::invokeMethod(m_audioHandler, &AudioHandler::run, Qt::QueuedConnection); - connect(m_backend, &Backend::videoAvailable, m_videoDecoder, &VideoDecoder::sendPacket); - connect(m_backend, &Backend::audioAvailable, m_videoDecoder, &VideoDecoder::sendAudio); - connect(m_backend, &Backend::syncCompleted, this, [this](bool e){if (e) m_connectBtn->setEnabled(true);}); connect(m_videoDecoder, &VideoDecoder::frameReady, m_viewer, &Viewer::setImage); connect(m_videoDecoder, &VideoDecoder::recordingError, this, &MainWindow::recordingError); connect(m_videoDecoder, &VideoDecoder::recordingFinished, this, &MainWindow::recordingFinished); - connect(m_videoDecoder, &VideoDecoder::requestIDR, m_backend, &Backend::requestIDR, Qt::DirectConnection); - connect(m_backend, &Backend::audioAvailable, m_audioHandler, &AudioHandler::write); - connect(m_backend, &Backend::vibrate, m_gamepadHandler, &GamepadHandler::vibrate, Qt::DirectConnection); - connect(m_viewer, &Viewer::touch, m_backend, &Backend::updateTouch, Qt::DirectConnection); connect(m_gamepadHandler, &GamepadHandler::gamepadsChanged, this, &MainWindow::populateControllers); - connect(m_gamepadHandler, &GamepadHandler::buttonStateChanged, m_backend, &Backend::setButton, Qt::DirectConnection); connect(m_viewer, &Viewer::keyPressed, m_gamepadHandler, &GamepadHandler::keyPressed, Qt::DirectConnection); connect(m_viewer, &Viewer::keyReleased, m_gamepadHandler, &GamepadHandler::keyReleased, Qt::DirectConnection); @@ -258,8 +250,7 @@ MainWindow::~MainWindow() m_videoDecoder->deleteLater(); - m_backend->interrupt(); - m_backend->deleteLater(); + closeBackend(); for (QThread *t : m_threadMap) { t->quit(); @@ -305,14 +296,22 @@ void MainWindow::populateWirelessInterfaces() while (tmp) { if (tmp->ifa_addr && tmp->ifa_addr->sa_family == AF_PACKET) { - if (isWireless(tmp->ifa_name, nullptr)) - m_wirelessInterfaceComboBox->addItem(tmp->ifa_name); + if (isWireless(tmp->ifa_name, nullptr)) { + QString s = tmp->ifa_name; + m_wirelessInterfaceComboBox->addItem(s, s); + } } tmp = tmp->ifa_next; } freeifaddrs(addrs); + + if (m_wirelessInterfaceComboBox->count() > 0) { + m_wirelessInterfaceComboBox->insertSeparator(m_wirelessInterfaceComboBox->count()); + } + + m_wirelessInterfaceComboBox->addItem(tr("External Server...")); } void MainWindow::populateMicrophones() @@ -340,33 +339,77 @@ void MainWindow::populateControllers() } } +template +void MainWindow::initBackend(T func) +{ + if (!m_backend) { + BackendInitDialog *d = new BackendInitDialog(this); + d->open(); + + QString localWirelessIntf = m_wirelessInterfaceComboBox->currentData().toString(); + if (localWirelessIntf.isEmpty()) { + // TODO: Prompt for UDP server address + m_backend = new BackendViaUdp(QHostAddress::LocalHost, 10200); + } else if ((geteuid() != 0)) { + // If not root, use named pipe + m_backend = new BackendViaNamedPipe(localWirelessIntf); + } else { + // If root, use lib locally + m_backend = new BackendViaLocalRoot(localWirelessIntf); + } + + connect(m_backend, &Backend::closed, d, &BackendInitDialog::deleteLater); + connect(m_backend, &Backend::ready, d, &BackendInitDialog::deleteLater); + + connect(m_backend, &Backend::closed, this, &MainWindow::closeBackend); + connect(m_backend, &Backend::ready, this, func); + connect(m_backend, &Backend::error, this, &MainWindow::showBackendError); + + connect(m_backend, &Backend::videoAvailable, m_videoDecoder, &VideoDecoder::sendPacket); + connect(m_backend, &Backend::audioAvailable, m_videoDecoder, &VideoDecoder::sendAudio); + connect(m_backend, &Backend::syncCompleted, this, [this](bool e){if (e) m_connectBtn->setEnabled(true);}); + connect(m_videoDecoder, &VideoDecoder::requestIDR, m_backend, &Backend::requestIDR, Qt::DirectConnection); + connect(m_backend, &Backend::audioAvailable, m_audioHandler, &AudioHandler::write); + connect(m_backend, &Backend::vibrate, m_gamepadHandler, &GamepadHandler::vibrate, Qt::DirectConnection); + connect(m_viewer, &Viewer::touch, m_backend, &Backend::updateTouch, Qt::DirectConnection); + connect(m_gamepadHandler, &GamepadHandler::buttonStateChanged, m_backend, &Backend::setButton, Qt::DirectConnection); + + startObjectOnThread(m_backend); + QMetaObject::invokeMethod(m_backend, &Backend::init, Qt::QueuedConnection); + } else { + func(); + } +} + void MainWindow::showSyncDialog() { - SyncDialog *d = new SyncDialog(this); - d->setup(m_backend, m_wirelessInterfaceComboBox->currentText()); - connect(d, &SyncDialog::finished, d, &SyncDialog::deleteLater); - d->open(); + initBackend([this]{ + SyncDialog *d = new SyncDialog(this); + d->setup(m_backend); + connect(d, &SyncDialog::finished, d, &SyncDialog::deleteLater); + d->open(); + }); } void MainWindow::setConnectedState(bool on) { m_wirelessInterfaceComboBox->setEnabled(!on); m_syncBtn->setEnabled(!on); + m_connectBtn->setChecked(on); + m_connectBtn->setText(on ? tr("Disconnect") : tr("Connect")); if (on) { - m_connectBtn->setText(tr("Disconnect")); + initBackend([this]{ + QMetaObject::invokeMethod(m_backend, &Backend::connectToConsole, Qt::QueuedConnection); - QMetaObject::invokeMethod(m_backend, "connectToConsole", Qt::QueuedConnection, Q_ARG(QString, m_wirelessInterfaceComboBox->currentText())); - - updateVolumeAxis(); - updateRegion(); - updateBatteryStatus(); + updateVolumeAxis(); + updateRegion(); + updateBatteryStatus(); + }); } else { if (m_backend) { m_backend->interrupt(); } - m_connectBtn->setText(tr("Connect")); - m_viewer->setImage(QImage()); } } @@ -390,7 +433,7 @@ void MainWindow::exitFullScreen() void MainWindow::updateVolumeAxis() { - m_backend->setButton(VANILLA_AXIS_VOLUME, m_volumeSlider->value() * 0xFF / m_volumeSlider->maximum()); + if (m_backend) m_backend->setButton(VANILLA_AXIS_VOLUME, m_volumeSlider->value() * 0xFF / m_volumeSlider->maximum()); } void MainWindow::volumeChanged(int v) @@ -471,10 +514,25 @@ void MainWindow::updateRegionFromComboBox() void MainWindow::updateRegion() { - m_backend->setRegion(m_regionComboBox->currentData().toInt()); + if (m_backend) m_backend->setRegion(m_regionComboBox->currentData().toInt()); } void MainWindow::updateBatteryStatus() { - m_backend->setBatteryStatus(m_batteryStatusComboBox->currentData().toInt()); + if (m_backend) m_backend->setBatteryStatus(m_batteryStatusComboBox->currentData().toInt()); +} + +void MainWindow::closeBackend() +{ + setConnectedState(false); + if (m_backend) { + m_backend->interrupt(); + m_backend->deleteLater(); + m_backend = nullptr; + } +} + +void MainWindow::showBackendError(const QString &err) +{ + QMessageBox::critical(this, tr("Backend Error"), err); } \ No newline at end of file diff --git a/app/mainwindow.h b/app/mainwindow.h index 19f80d0..73a05cb 100644 --- a/app/mainwindow.h +++ b/app/mainwindow.h @@ -32,6 +32,9 @@ private: void updateVolumeAxis(); + template + void initBackend(T func); + Viewer *m_viewer; QComboBox *m_wirelessInterfaceComboBox; @@ -82,6 +85,10 @@ private slots: void takeScreenshot(); + void closeBackend(); + + void showBackendError(const QString &err); + }; #endif // MAINWINDOW_H diff --git a/app/syncdialog.cpp b/app/syncdialog.cpp index b1e7d4f..15752f1 100644 --- a/app/syncdialog.cpp +++ b/app/syncdialog.cpp @@ -139,14 +139,13 @@ void SyncDialog::launchSync() code += m_code[i] * intPow(10, g_symbolCount - 1 - i); } - SyncProgressDialog *progressDialog = new SyncProgressDialog(m_backend, m_wirelessInterface, code, this->parentWidget()); + SyncProgressDialog *progressDialog = new SyncProgressDialog(m_backend, code, this->parentWidget()); progressDialog->open(); connect(progressDialog, &SyncProgressDialog::finished, this, &SyncProgressDialog::deleteLater); this->close(); } -void SyncDialog::setup(Backend *backend, const QString &wirelessInterface) +void SyncDialog::setup(Backend *backend) { m_backend = backend; - m_wirelessInterface = wirelessInterface; } diff --git a/app/syncdialog.h b/app/syncdialog.h index d4a4a1c..8515163 100644 --- a/app/syncdialog.h +++ b/app/syncdialog.h @@ -13,7 +13,7 @@ class SyncDialog : public QDialog public: SyncDialog(QWidget *parent = nullptr); - void setup(Backend *backend, const QString &wirelessInterface); + void setup(Backend *backend); private: void updateLabels(); @@ -28,7 +28,6 @@ private: QHBoxLayout *m_buttonLayout; Backend *m_backend; - QString m_wirelessInterface; private slots: void buttonClicked(); diff --git a/app/syncprogressdialog.cpp b/app/syncprogressdialog.cpp index 26cea18..4bce9f2 100644 --- a/app/syncprogressdialog.cpp +++ b/app/syncprogressdialog.cpp @@ -8,7 +8,7 @@ #include "mainwindow.h" -SyncProgressDialog::SyncProgressDialog(Backend *backend, const QString &wirelessInterface, uint16_t code, QWidget *parent) : QDialog(parent) +SyncProgressDialog::SyncProgressDialog(Backend *backend, uint16_t code, QWidget *parent) : QDialog(parent) { QVBoxLayout *layout = new QVBoxLayout(this); @@ -53,7 +53,7 @@ SyncProgressDialog::SyncProgressDialog(Backend *backend, const QString &wireless m_backend = backend; connect(m_backend, &Backend::syncCompleted, this, &SyncProgressDialog::syncReturned); - QMetaObject::invokeMethod(m_backend, "sync", Q_ARG(QString, wirelessInterface), Q_ARG(uint16_t, code)); + QMetaObject::invokeMethod(m_backend, "sync", Q_ARG(uint16_t, code)); } void SyncProgressDialog::syncReturned(bool success) diff --git a/app/syncprogressdialog.h b/app/syncprogressdialog.h index ad3789c..2122069 100644 --- a/app/syncprogressdialog.h +++ b/app/syncprogressdialog.h @@ -12,7 +12,7 @@ class SyncProgressDialog : public QDialog { Q_OBJECT public: - SyncProgressDialog(Backend *backend, const QString &wirelessInterface, uint16_t code, QWidget *parent = nullptr); + SyncProgressDialog(Backend *backend, uint16_t code, QWidget *parent = nullptr); protected: virtual void done(int r) override; @@ -22,7 +22,6 @@ private: Backend *m_backend; QLabel *m_headerLabel; QLabel *m_statusLabel; - QString m_wirelessInterface; uint16_t m_wpsCode; bool m_cancelled; diff --git a/pipe/main.c b/pipe/main.c index d4b364b..3820f8f 100644 --- a/pipe/main.c +++ b/pipe/main.c @@ -32,84 +32,46 @@ int open_fifo(const char *name, int mode) return f; } -uint8_t buffer[1048576]; -size_t buffer_pos = 0; -pthread_mutex_t buffer_mutex; int fd_in = 0, fd_out = 0; -in_addr_t udp_client_addr = 0; -in_port_t udp_client_port = 0; +struct sockaddr_in udp_client = {0}; -void buffer_start() +ssize_t write_pipe(const void *buf, size_t size) { - pthread_mutex_lock(&buffer_mutex); -} - -void buffer_write(const void *data, size_t length) -{ - memcpy(buffer + buffer_pos, data, length); - buffer_pos += length; -} - -void buffer_finish() -{ - if (fd_out != 0) { - write(fd_out, buffer, buffer_pos); - } - - if (udp_client_addr != 0 && udp_client_port != 0) { - struct sockaddr_in address; - address.sin_family = AF_INET; - address.sin_addr.s_addr = udp_client_addr; - address.sin_port = htons(udp_client_port); - sendto(fd_in, buffer, buffer_pos, 0, (const struct sockaddr *) &address, sizeof(address)); - } - - buffer_pos = 0; - pthread_mutex_unlock(&buffer_mutex); -} - -void buffer_write_single(void *data, size_t length) -{ - buffer_start(); - buffer_write(data, length); - buffer_finish(); + sendto(fd_in, buf, size, 0, (const struct sockaddr *) &udp_client, sizeof(udp_client)); } pthread_mutex_t action_mutex; int action_ended = 0; int write_control_code(uint8_t code) { - buffer_write_single(&code, 1); + struct pipe_control_code cmd; + cmd.code = code; + write_pipe(&cmd, sizeof(cmd)); } void event_handler(void *context, int event_type, const char *data, size_t data_size) { - uint8_t event_sized = event_type; - uint64_t data_size_sized = data_size; - uint8_t control_code = VANILLA_PIPE_OUT_DATA; + struct pipe_data_command cmd; - buffer_start(); - buffer_write(&control_code, sizeof(control_code)); - buffer_write(&event_sized, sizeof(event_sized)); - buffer_write(&data_size_sized, sizeof(data_size_sized)); - buffer_write(data, data_size); - buffer_finish(); + cmd.base.code = VANILLA_PIPE_OUT_DATA; + cmd.event_type = event_type; + cmd.data_size = htons(data_size); + memcpy(cmd.data, data, data_size); + + write_pipe(&cmd, sizeof(cmd)-sizeof(cmd.data)+data_size); } void write_sync_state(uint8_t success) { - uint8_t cc = VANILLA_PIPE_OUT_SYNC_STATE; - - buffer_start(); - buffer_write(&cc, sizeof(cc)); - buffer_write(&success, sizeof(success)); - buffer_finish(); + struct pipe_sync_state_command cmd; + cmd.base.code = VANILLA_PIPE_OUT_SYNC_STATE; + cmd.state = success; + write_pipe(&cmd, sizeof(cmd)); } -#define WIRELESS_INTERFACE_MAX_LEN 100 struct sync_args { - char wireless_interface[WIRELESS_INTERFACE_MAX_LEN]; + const char *wireless_interface; uint16_t code; }; void *sync_command(void *a) @@ -128,7 +90,7 @@ void *sync_command(void *a) struct connect_args { - char wireless_interface[WIRELESS_INTERFACE_MAX_LEN]; + const char *wireless_interface; }; void *connect_command(void *a) { @@ -144,16 +106,6 @@ void *connect_command(void *a) return (void *) (size_t) r; } -void read_string(int fd, char *buf, size_t max) -{ - for (size_t i = 0; i < max; i++) { - read(fd, &buf[i], 1); - if (buf[i] == 0) { - break; - } - } -} - void lib_logger(const char *fmt, va_list args) { vfprintf(stderr, fmt, args); @@ -180,18 +132,20 @@ void vapipelog(const char *str, ...) int main(int argc, char **argv) { - if (argc < 2) { + if (argc < 3) { goto show_help; } - if (!strcmp(argv[1], "-pipe")) { - if (argc < 4) { + const char *wireless_interface = argv[1]; + + if (!strcmp(argv[2], "-pipe")) { + if (argc < 5) { printf("-pipe requires and \n"); goto show_help; } - const char *pipe_in_filename = argv[2]; - const char *pipe_out_filename = argv[3]; + const char *pipe_in_filename = argv[3]; + const char *pipe_out_filename = argv[4]; umask(0000); @@ -202,30 +156,18 @@ int main(int argc, char **argv) if ((fd_out = open_fifo(pipe_out_filename, O_WRONLY)) == -1) return 1; if ((fd_in = open_fifo(pipe_in_filename, O_RDONLY)) == -1) return 1; - } else if (!strcmp(argv[1], "-udp")) { - if (argc < 5) { - printf("-udp requires \n"); + } else if (!strcmp(argv[2], "-udp")) { + if (argc < 4) { + printf("-udp requires \n"); goto show_help; } - uint16_t server_port = atoi(argv[2]); + uint16_t server_port = atoi(argv[3]); if (server_port == 0) { printf("UDP port provided was invalid\n"); goto show_help; } - udp_client_addr = inet_addr(argv[3]); - if (udp_client_addr == 0) { - printf("Client IP provided was invalid\n"); - goto show_help; - } - - udp_client_port = atoi(argv[4]); - if (udp_client_port == 0) { - printf("Client port provided was invalid\n"); - goto show_help; - } - struct sockaddr_in address; address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; @@ -239,22 +181,23 @@ int main(int argc, char **argv) fprintf(stderr, "READY\n"); } else { - printf("Unknown mode '%s'\n", argv[1]); + printf("Unknown mode '%s'\n", argv[2]); goto show_help; } - uint8_t control_code; + char read_buffer[2048]; ssize_t read_size; pthread_t current_action = 0; int m_quit = 0; vanilla_install_logger(lib_logger); - pthread_mutex_init(&buffer_mutex, NULL); pthread_mutex_init(&action_mutex, NULL); while (!m_quit) { - read_size = read(fd_in, &control_code, 1); + struct sockaddr_in sender_addr; + socklen_t sender_addr_len = sizeof(sender_addr); + read_size = recvfrom(fd_in, read_buffer, sizeof(read_buffer), 0, (struct sockaddr *) &sender_addr, &sender_addr_len); if (read_size == 0) { continue; } @@ -268,16 +211,22 @@ int main(int argc, char **argv) } pthread_mutex_unlock(&action_mutex); - switch (control_code) { + struct pipe_control_code *control_code = (struct pipe_control_code *) read_buffer; + switch (control_code->code) { case VANILLA_PIPE_IN_SYNC: { if (current_action != 0) { write_control_code(VANILLA_PIPE_ERR_BUSY); } else { + struct pipe_sync_command *sync_cmd = (struct pipe_sync_command *) read_buffer; + sync_cmd->code = ntohs(sync_cmd->code); + struct sync_args *args = (struct sync_args *) malloc(sizeof(struct sync_args)); - read(fd_in, &args->code, sizeof(args->code)); - read_string(fd_in, args->wireless_interface, sizeof(args->wireless_interface)); + args->code = sync_cmd->code; + args->wireless_interface = wireless_interface; + write_control_code(VANILLA_PIPE_ERR_SUCCESS); + pthread_create(¤t_action, NULL, sync_command, args); } break; @@ -288,7 +237,7 @@ int main(int argc, char **argv) write_control_code(VANILLA_PIPE_ERR_BUSY); } else { struct connect_args *args = (struct connect_args *) malloc(sizeof(struct connect_args)); - read_string(fd_in, args->wireless_interface, sizeof(args->wireless_interface)); + args->wireless_interface = wireless_interface; write_control_code(VANILLA_PIPE_ERR_SUCCESS); pthread_create(¤t_action, NULL, connect_command, args); } @@ -296,20 +245,18 @@ int main(int argc, char **argv) } case VANILLA_PIPE_IN_BUTTON: { - int32_t button_id; - int32_t button_value; - read(fd_in, &button_id, sizeof(button_id)); - read(fd_in, &button_value, sizeof(button_value)); - vanilla_set_button(button_id, button_value); + struct pipe_button_command *btn_cmd = (struct pipe_button_command *) read_buffer; + btn_cmd->id = ntohl(btn_cmd->id); + btn_cmd->value = ntohl(btn_cmd->value); + vanilla_set_button(btn_cmd->id, btn_cmd->value); break; } case VANILLA_PIPE_IN_TOUCH: { - int32_t touch_x; - int32_t touch_y; - read(fd_in, &touch_x, sizeof(touch_x)); - read(fd_in, &touch_y, sizeof(touch_y)); - vanilla_set_touch(touch_x, touch_y); + struct pipe_touch_command *touch_cmd = (struct pipe_touch_command *) read_buffer; + touch_cmd->x = ntohl(touch_cmd->x); + touch_cmd->y = ntohl(touch_cmd->y); + vanilla_set_touch(touch_cmd->x, touch_cmd->y); break; } case VANILLA_PIPE_IN_INTERRUPT: @@ -327,26 +274,39 @@ int main(int argc, char **argv) } case VANILLA_PIPE_IN_REGION: { - int8_t region; - read(fd_in, ®ion, sizeof(region)); - vanilla_set_region(region); + struct pipe_region_command *region_cmd = (struct pipe_region_command *) read_buffer; + vanilla_set_region(region_cmd->region); break; } case VANILLA_PIPE_IN_BATTERY: { - int8_t battery; - read(fd_in, &battery, sizeof(battery)); - vanilla_set_battery_status(battery); + struct pipe_battery_command *battery_cmd = (struct pipe_battery_command *) read_buffer; + vanilla_set_battery_status(battery_cmd->battery); break; } case VANILLA_PIPE_IN_QUIT: m_quit = 1; break; + case VANILLA_PIPE_IN_BIND: + { + struct pipe_bind_command *bind_cmd = (struct pipe_bind_command *) read_buffer; + + // Send success message back to client + uint8_t cc = VANILLA_PIPE_OUT_BOUND_SUCCESSFUL; + sendto(fd_in, &cc, sizeof(cc), 0, (const struct sockaddr *) &sender_addr, sizeof(sender_addr)); + + // Add client to list + udp_client = sender_addr; + + char addr_buf[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &udp_client.sin_addr.s_addr, addr_buf, INET_ADDRSTRLEN); + printf("BIND %s:%u\n", addr_buf, ntohs(udp_client.sin_port)); + break; + } } } pthread_mutex_destroy(&action_mutex); - pthread_mutex_destroy(&buffer_mutex); close(fd_in); close(fd_out); @@ -354,7 +314,7 @@ int main(int argc, char **argv) return 0; show_help: - printf("Usage: %s [args]\n\n", argv[0]); + printf("Usage: %s [args]\n\n", argv[0]); printf("vanilla-pipe provides a way to connect a frontend to Vanilla's backend when they\n"); printf("aren't able to run on the same device or in the same environment (e.g. when the \n"); printf("backend must run as root but the frontend must run as user).\n\n"); diff --git a/pipe/pipe.h b/pipe/pipe.h index 35fdf60..d860716 100644 --- a/pipe/pipe.h +++ b/pipe/pipe.h @@ -2,7 +2,7 @@ #define VANILLA_PIPE_H // Control codes that our pipe will receive -enum PipeOpCodes +enum pipe_opcodes { VANILLA_PIPE_IN_SYNC = 1, VANILLA_PIPE_IN_CONNECT, @@ -11,12 +11,14 @@ enum PipeOpCodes VANILLA_PIPE_IN_REQ_IDR, VANILLA_PIPE_IN_REGION, VANILLA_PIPE_IN_BATTERY, + VANILLA_PIPE_IN_BIND, VANILLA_PIPE_IN_INTERRUPT = 0x1E, VANILLA_PIPE_IN_QUIT = 0x1F, VANILLA_PIPE_OUT_DATA = 0x20, VANILLA_PIPE_OUT_SYNC_STATE, + VANILLA_PIPE_OUT_BOUND_SUCCESSFUL, VANILLA_PIPE_OUT_EOF, // Errors that our pipe will send @@ -26,4 +28,59 @@ enum PipeOpCodes VANILLA_PIPE_ERR_BUSY }; +#pragma pack(push, 1) + +struct pipe_control_code +{ + uint8_t code; +}; + +struct pipe_sync_command +{ + struct pipe_control_code base; + uint16_t code; +}; + +struct pipe_button_command +{ + struct pipe_control_code base; + int32_t id; + int32_t value; +}; + +struct pipe_touch_command +{ + struct pipe_control_code base; + int32_t x; + int32_t y; +}; + +struct pipe_region_command +{ + struct pipe_control_code base; + int8_t region; +}; + +struct pipe_battery_command +{ + struct pipe_control_code base; + int8_t battery; +}; + +struct pipe_sync_state_command +{ + struct pipe_control_code base; + uint8_t state; +}; + +struct pipe_data_command +{ + struct pipe_control_code base; + uint8_t event_type; + uint16_t data_size; + uint8_t data[UINT16_MAX]; +}; + +#pragma pack(pop) + #endif // VANILLA_PIPE_H \ No newline at end of file