mirror of
https://github.com/vanilla-wiiu/vanilla.git
synced 2025-01-22 08:11:47 -05:00
started pipe rewrite
This commit is contained in:
parent
64de9e9b08
commit
ce98f9d923
11 changed files with 176 additions and 713 deletions
156
app/backend.cpp
156
app/backend.cpp
|
@ -13,8 +13,6 @@
|
|||
#include <unistd.h>
|
||||
#include <vanilla.h>
|
||||
|
||||
#include "../pipe/pipe.h"
|
||||
|
||||
void vanillaEventHandler(void *context, int type, const char *data, size_t dataLength)
|
||||
{
|
||||
Backend *backend = static_cast<Backend*>(context);
|
||||
|
@ -46,76 +44,16 @@ BackendViaLocalRoot::BackendViaLocalRoot(const QString &wirelessInterface, QObje
|
|||
m_wirelessInterface = wirelessInterface;
|
||||
}
|
||||
|
||||
BackendViaPipe::BackendViaPipe(QObject *parent) : Backend(parent)
|
||||
{
|
||||
}
|
||||
|
||||
BackendViaSocket::BackendViaSocket(const QHostAddress &backendAddr, quint16 backendPort, QObject *parent) : BackendViaPipe(parent)
|
||||
{
|
||||
m_backendAddress = backendAddr;
|
||||
m_backendPort = backendPort;
|
||||
|
||||
m_socket = new QUdpSocket(this);
|
||||
connect(m_socket, &QUdpSocket::readyRead, this, &BackendViaSocket::readPendingDatagrams);
|
||||
connect(m_socket, &QUdpSocket::disconnected, this, &BackendViaSocket::closed);
|
||||
}
|
||||
|
||||
void BackendViaSocket::init()
|
||||
{
|
||||
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) {
|
||||
// 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()
|
||||
{
|
||||
pipe_control_code cmd;
|
||||
cmd.code = VANILLA_PIPE_IN_QUIT;
|
||||
writeToPipe(&cmd, sizeof(cmd));
|
||||
}
|
||||
|
||||
void BackendViaLocalRoot::interrupt()
|
||||
{
|
||||
vanilla_stop();
|
||||
}
|
||||
|
||||
void BackendViaPipe::interrupt()
|
||||
{
|
||||
pipe_control_code cmd;
|
||||
cmd.code = VANILLA_PIPE_IN_INTERRUPT;
|
||||
writeToPipe(&cmd, sizeof(cmd));
|
||||
}
|
||||
|
||||
void BackendViaLocalRoot::requestIDR()
|
||||
{
|
||||
vanilla_request_idr();
|
||||
}
|
||||
|
||||
void BackendViaPipe::requestIDR()
|
||||
{
|
||||
pipe_control_code cmd;
|
||||
cmd.code = VANILLA_PIPE_IN_REQ_IDR;
|
||||
writeToPipe(&cmd, sizeof(cmd));
|
||||
}
|
||||
|
||||
void BackendViaLocalRoot::connectToConsole()
|
||||
{
|
||||
QtConcurrent::run(connectInternal, this, m_wirelessInterface);
|
||||
|
@ -127,98 +65,26 @@ int BackendViaLocalRoot::connectInternal(BackendViaLocalRoot *instance, const QS
|
|||
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()
|
||||
{
|
||||
// Request pipe to connect
|
||||
pipe_control_code conn_cmd;
|
||||
conn_cmd.code = VANILLA_PIPE_IN_CONNECT;
|
||||
writeToPipe(&conn_cmd, sizeof(conn_cmd));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
QFutureWatcher<int> *watcher = new QFutureWatcher<int>(this);
|
||||
|
@ -240,15 +106,6 @@ void BackendViaLocalRoot::syncFutureCompleted()
|
|||
watcher->deleteLater();
|
||||
}
|
||||
|
||||
void BackendViaPipe::sync(uint16_t code)
|
||||
{
|
||||
// Request pipe to sync
|
||||
pipe_sync_command cmd;
|
||||
cmd.base.code = VANILLA_PIPE_IN_SYNC;
|
||||
cmd.code = htons(code);
|
||||
writeToPipe(&cmd, sizeof(cmd));
|
||||
}
|
||||
|
||||
BackendPipe::BackendPipe(const QString &wirelessInterface, QObject *parent) : QObject(parent)
|
||||
{
|
||||
m_process = nullptr;
|
||||
|
@ -295,16 +152,3 @@ void BackendPipe::receivedData()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BackendViaSocket::readPendingDatagrams()
|
||||
{
|
||||
while (m_socket->hasPendingDatagrams()) {
|
||||
QNetworkDatagram datagram = m_socket->receiveDatagram();
|
||||
processPacket(datagram.data());
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t BackendViaSocket::writeToPipe(const void *data, size_t length)
|
||||
{
|
||||
return m_socket->writeDatagram((const char *) data, length, m_backendAddress, m_backendPort);
|
||||
}
|
|
@ -99,62 +99,4 @@ private slots:
|
|||
|
||||
};
|
||||
|
||||
class BackendViaPipe : public Backend
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum ListenState {
|
||||
IDLE,
|
||||
WAITING_FOR_SYNC_RESULT,
|
||||
WAITING_FOR_BIND_RESULT,
|
||||
RECEIVING_DATA
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
void quitPipe();
|
||||
|
||||
protected:
|
||||
void processPacket(const QByteArray &arr);
|
||||
virtual ssize_t writeToPipe(const void *data, size_t length) = 0;
|
||||
|
||||
private:
|
||||
ListenState m_listenState;
|
||||
|
||||
};
|
||||
|
||||
class BackendViaSocket : public BackendViaPipe
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
BackendViaSocket(const QHostAddress &backendAddr, quint16 backendPort, QObject *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
virtual void init() override;
|
||||
|
||||
protected:
|
||||
virtual ssize_t writeToPipe(const void *data, size_t length) override;
|
||||
|
||||
private:
|
||||
QUdpSocket *m_socket;
|
||||
QHostAddress m_backendAddress;
|
||||
quint16 m_frontendPort;
|
||||
quint16 m_backendPort;
|
||||
|
||||
private slots:
|
||||
void readPendingDatagrams();
|
||||
|
||||
};
|
||||
|
||||
#endif // BACKEND_H
|
|
@ -348,20 +348,15 @@ void MainWindow::initBackend(T func)
|
|||
d->open();
|
||||
|
||||
QString localWirelessIntf = m_wirelessInterfaceComboBox->currentData().toString();
|
||||
if (localWirelessIntf.isEmpty()) {
|
||||
if (0 && localWirelessIntf.isEmpty()) {
|
||||
UdpAddressDialog udpDiag(this);
|
||||
if (udpDiag.exec() == QDialog::Accepted) {
|
||||
m_backend = new BackendViaSocket(udpDiag.acceptedAddress(), udpDiag.acceptedPort());
|
||||
// m_backend = new BackendViaSocket(udpDiag.acceptedAddress(), udpDiag.acceptedPort());
|
||||
} else {
|
||||
d->deleteLater();
|
||||
closeBackend();
|
||||
return;
|
||||
}
|
||||
} else if ((geteuid() != 0)) {
|
||||
// If not root, use named pipe
|
||||
QMessageBox::critical(this, QString(), tr("Unimplemented..."));
|
||||
d->deleteLater();
|
||||
return;
|
||||
//m_backend = new BackendViaNamedPipe(localWirelessIntf);
|
||||
} else {
|
||||
// If root, use lib locally
|
||||
m_backend = new BackendViaLocalRoot(localWirelessIntf);
|
||||
|
|
|
@ -1,16 +1,11 @@
|
|||
#ifndef VANILLA_GAMEPAD_H
|
||||
#define VANILLA_GAMEPAD_H
|
||||
|
||||
#include "ports.h"
|
||||
#include "vanilla.h"
|
||||
|
||||
struct wpa_ctrl;
|
||||
|
||||
static const uint16_t PORT_MSG = 50110;
|
||||
static const uint16_t PORT_VID = 50120;
|
||||
static const uint16_t PORT_AUD = 50121;
|
||||
static const uint16_t PORT_HID = 50122;
|
||||
static const uint16_t PORT_CMD = 50123;
|
||||
|
||||
struct gamepad_thread_context
|
||||
{
|
||||
vanilla_event_handler_t event_handler;
|
||||
|
|
12
lib/gamepad/ports.h
Normal file
12
lib/gamepad/ports.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#ifndef GAMEPAD_PORTS_H
|
||||
#define GAMEPAD_PORTS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
static const uint16_t PORT_MSG = 50110;
|
||||
static const uint16_t PORT_VID = 50120;
|
||||
static const uint16_t PORT_AUD = 50121;
|
||||
static const uint16_t PORT_HID = 50122;
|
||||
static const uint16_t PORT_CMD = 50123;
|
||||
|
||||
#endif // GAMEPAD_PORTS_H
|
|
@ -9,12 +9,12 @@ extern "C" {
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define VANILLA_SUCCESS 0
|
||||
#define VANILLA_ERROR -1
|
||||
#define VANILLA_READY -2
|
||||
#define VANILLA_INFO -3
|
||||
#define VANILLA_UNKNOWN_COMMAND -4
|
||||
#define VANILLA_INVALID_ARGUMENT -5
|
||||
static const int VANILLA_SUCCESS = 0;
|
||||
static const int VANILLA_ERROR = -1;
|
||||
static const int VANILLA_READY = -2;
|
||||
static const int VANILLA_INFO = -3;
|
||||
static const int VANILLA_UNKNOWN_COMMAND = -4;
|
||||
static const int VANILLA_INVALID_ARGUMENT = -5;
|
||||
|
||||
enum VanillaGamepadButtons
|
||||
{
|
||||
|
|
|
@ -1,14 +1 @@
|
|||
add_executable(vanilla-pipe
|
||||
main.c
|
||||
)
|
||||
|
||||
target_link_libraries(vanilla-pipe PRIVATE
|
||||
vanilla
|
||||
pthread
|
||||
)
|
||||
|
||||
target_include_directories(vanilla-pipe PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/lib
|
||||
)
|
||||
|
||||
install(TARGETS vanilla-pipe)
|
||||
add_subdirectory(linux)
|
5
pipe/linux/CMakeLists.txt
Normal file
5
pipe/linux/CMakeLists.txt
Normal file
|
@ -0,0 +1,5 @@
|
|||
add_executable(vanilla-pipe
|
||||
main.c
|
||||
)
|
||||
|
||||
install(TARGETS vanilla-pipe)
|
148
pipe/linux/main.c
Normal file
148
pipe/linux/main.c
Normal file
|
@ -0,0 +1,148 @@
|
|||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../../lib/gamepad/ports.h"
|
||||
|
||||
typedef struct {
|
||||
int from;
|
||||
int to;
|
||||
} relay_ports;
|
||||
|
||||
struct in_addr client_address = {0};
|
||||
|
||||
void* do_relay(void *data)
|
||||
{
|
||||
relay_ports *ports = (relay_ports *) data;
|
||||
char buf[2048];
|
||||
ssize_t read_size;
|
||||
while ((read_size = recv(ports->from, buf, sizeof(buf), 0)) != -1) {
|
||||
struct sockaddr_in forward = {0};
|
||||
forward.sin_family = AF_INET;
|
||||
forward.sin_addr = client_address;
|
||||
forward.sin_port = ports->to;
|
||||
sendto(ports->to, buf, read_size, 0, (const struct sockaddr *) &forward, sizeof(forward));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int open_socket(in_port_t port)
|
||||
{
|
||||
struct sockaddr_in in = {0};
|
||||
in.sin_family = AF_INET;
|
||||
in.sin_addr.s_addr = INADDR_ANY;
|
||||
in.sin_port = htons(port);
|
||||
|
||||
int skt = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (skt == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (bind(skt, (const struct sockaddr *) &in, sizeof(in)) == -1) {
|
||||
printf("FAILED TO BIND PORT %u: %i\n", port, errno);
|
||||
close(skt);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return skt;
|
||||
}
|
||||
|
||||
void *open_relay(void *data)
|
||||
{
|
||||
in_port_t port = (in_port_t) data;
|
||||
int ret = -1;
|
||||
|
||||
// Open an incoming port from the console
|
||||
int from_console = open_socket(port);
|
||||
if (from_console == -1) {
|
||||
goto close;
|
||||
}
|
||||
|
||||
// Open an incoming port from the frontend
|
||||
int from_frontend = open_socket(port + 100);
|
||||
if (from_frontend == -1) {
|
||||
goto close_console_connection;
|
||||
}
|
||||
|
||||
relay_ports a_ports, b_ports;
|
||||
|
||||
a_ports.from = from_console;
|
||||
a_ports.to = from_frontend;
|
||||
|
||||
b_ports.from = from_frontend;
|
||||
b_ports.to = from_console;
|
||||
|
||||
pthread_t a_thread, b_thread;
|
||||
pthread_create(&a_thread, NULL, do_relay, &a_ports);
|
||||
pthread_create(&b_thread, NULL, do_relay, &b_ports);
|
||||
|
||||
pthread_join(a_thread, NULL);
|
||||
pthread_join(b_thread, NULL);
|
||||
|
||||
ret = 0;
|
||||
|
||||
close_frontend_connection:
|
||||
close(from_frontend);
|
||||
|
||||
close_console_connection:
|
||||
close(from_console);
|
||||
|
||||
close:
|
||||
return (void *) ret;
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
if (argc != 3) {
|
||||
goto show_help;
|
||||
}
|
||||
|
||||
if (!strcmp("-sync", argv[1])) {
|
||||
int code = atoi(argv[2]);
|
||||
if (code == 0) {
|
||||
printf("ERROR: Invalid sync code\n\n");
|
||||
goto show_help;
|
||||
}
|
||||
|
||||
|
||||
} else if (!strcmp("-connect", argv[1])) {
|
||||
inet_pton(AF_INET, argv[2], &client_address);
|
||||
|
||||
pthread_t vid_thread, aud_thread, msg_thread, cmd_thread, hid_thread;
|
||||
|
||||
pthread_create(&vid_thread, NULL, open_relay, (void *) PORT_VID);
|
||||
pthread_create(&aud_thread, NULL, open_relay, (void *) PORT_AUD);
|
||||
pthread_create(&msg_thread, NULL, open_relay, (void *) PORT_MSG);
|
||||
pthread_create(&cmd_thread, NULL, open_relay, (void *) PORT_CMD);
|
||||
pthread_create(&hid_thread, NULL, open_relay, (void *) PORT_HID);
|
||||
|
||||
printf("READY\n");
|
||||
|
||||
pthread_join(vid_thread, NULL);
|
||||
pthread_join(aud_thread, NULL);
|
||||
pthread_join(msg_thread, NULL);
|
||||
pthread_join(cmd_thread, NULL);
|
||||
pthread_join(hid_thread, NULL);
|
||||
} else {
|
||||
printf("ERROR: Invalid mode\n\n");
|
||||
goto show_help;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
show_help:
|
||||
printf("vanilla-pipe - brokers a connection between Vanilla and the Wii U\n");
|
||||
printf("\n");
|
||||
printf("Usage: %s <mode> <args>\n", argv[0]);
|
||||
printf("\n");
|
||||
printf("Modes: \n");
|
||||
printf(" -sync <code> Sync/authenticate with the Wii U\n");
|
||||
printf(" -connect <client-address> Connect to the Wii U (requires syncing prior)\n");
|
||||
printf("\n");
|
||||
|
||||
return 1;
|
||||
}
|
379
pipe/main.c
379
pipe/main.c
|
@ -1,379 +0,0 @@
|
|||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
#include <vanilla.h>
|
||||
|
||||
#include "pipe.h"
|
||||
|
||||
int create_fifo(const char *name)
|
||||
{
|
||||
int f = mkfifo(name, 0777);
|
||||
if (f == -1) {
|
||||
printf("Failed to create FIFO: %s (%i)\n", name, errno);
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
int open_fifo(const char *name, int mode)
|
||||
{
|
||||
int f = open(name, mode);
|
||||
if (f == -1) {
|
||||
printf("Failed to open FIFO: %s (%i)\n", name, errno);
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
int fd_in = 0, fd_out = 0;
|
||||
uint8_t client_addr[128] = {0};
|
||||
|
||||
ssize_t write_pipe(const void *buf, size_t size)
|
||||
{
|
||||
sendto(fd_in, buf, size, 0, (const struct sockaddr *) client_addr, sizeof(client_addr));
|
||||
}
|
||||
|
||||
pthread_mutex_t action_mutex;
|
||||
int action_ended = 0;
|
||||
int write_control_code(uint8_t code)
|
||||
{
|
||||
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)
|
||||
{
|
||||
struct pipe_data_command cmd;
|
||||
|
||||
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)
|
||||
{
|
||||
struct pipe_sync_state_command cmd;
|
||||
cmd.base.code = VANILLA_PIPE_OUT_SYNC_STATE;
|
||||
cmd.state = success;
|
||||
write_pipe(&cmd, sizeof(cmd));
|
||||
}
|
||||
|
||||
struct sync_args
|
||||
{
|
||||
const char *wireless_interface;
|
||||
uint16_t code;
|
||||
};
|
||||
void *sync_command(void *a)
|
||||
{
|
||||
struct sync_args *args = (struct sync_args *)a;
|
||||
int r = vanilla_sync_with_console(args->wireless_interface, args->code);
|
||||
free(args);
|
||||
write_sync_state(r);
|
||||
|
||||
pthread_mutex_lock(&action_mutex);
|
||||
action_ended = 1;
|
||||
pthread_mutex_unlock(&action_mutex);
|
||||
|
||||
return (void *) (size_t) r;
|
||||
}
|
||||
|
||||
struct connect_args
|
||||
{
|
||||
const char *wireless_interface;
|
||||
};
|
||||
void *connect_command(void *a)
|
||||
{
|
||||
struct connect_args *args = (struct connect_args *) a;
|
||||
int r = vanilla_connect_to_console(args->wireless_interface, event_handler, NULL);
|
||||
free(args);
|
||||
write_control_code(VANILLA_PIPE_OUT_EOF);
|
||||
|
||||
pthread_mutex_lock(&action_mutex);
|
||||
action_ended = 1;
|
||||
pthread_mutex_unlock(&action_mutex);
|
||||
|
||||
return (void *) (size_t) r;
|
||||
}
|
||||
|
||||
void lib_logger(const char *fmt, va_list args)
|
||||
{
|
||||
vfprintf(stderr, fmt, args);
|
||||
// FILE *fff = fopen("/home/matt/Desktop/temp.log", "a");
|
||||
// vfprintf(fff, fmt, args);
|
||||
// fclose(fff);
|
||||
}
|
||||
|
||||
void vapipelog(const char *str, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, str);
|
||||
|
||||
vfprintf(stderr, str, va);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
// FILE *fff = fopen("/home/matt/Desktop/temp.log", "a");
|
||||
// vfprintf(fff, str, va);
|
||||
// fprintf(fff, "\n");
|
||||
// fclose(fff);
|
||||
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
const char *get_positional_arg(int argc, const char **argv, int index)
|
||||
{
|
||||
int cur_index = 0;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (argv[i][0] == '-') {
|
||||
i++;
|
||||
} else if (cur_index == index) {
|
||||
return argv[i];
|
||||
} else {
|
||||
cur_index++;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *get_optional_arg(int argc, const char **argv, const char *opt_arg_name, int *exists)
|
||||
{
|
||||
*exists = 0;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (!strcmp(argv[i], opt_arg_name)) {
|
||||
*exists = 1;
|
||||
if (i + 1 < argc) {
|
||||
return argv[i + 1];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
if (argc < 3) {
|
||||
goto show_help;
|
||||
}
|
||||
|
||||
const char *wireless_interface = get_positional_arg(argc, argv, 0);
|
||||
if (!wireless_interface) {
|
||||
printf("No wireless interface specified\n");
|
||||
goto show_help;
|
||||
}
|
||||
|
||||
int pipe_exists, udp_exists;
|
||||
const char *pipe_mode = get_optional_arg(argc, argv, "-pipe", &pipe_exists);
|
||||
const char *udp_mode = get_optional_arg(argc, argv, "-udp", &udp_exists);
|
||||
|
||||
uint8_t address[128] = {0};
|
||||
socklen_t address_len;
|
||||
|
||||
if (pipe_exists && udp_exists) {
|
||||
printf("-pipe and -udp cannot both be specified\n");
|
||||
return 1;
|
||||
} else if (pipe_mode) {
|
||||
address_len = sizeof(struct sockaddr_un);
|
||||
} else if (udp_mode) {
|
||||
address_len = sizeof(struct sockaddr_in);
|
||||
} else if (pipe_exists) {
|
||||
printf("-pipe requires <fifo-path>\n");
|
||||
return 1;
|
||||
} else if (udp_exists) {
|
||||
printf("-udp requires <server-port>\n");
|
||||
return 1;
|
||||
} else {
|
||||
printf("No mode or mode option specified\n");
|
||||
goto show_help;
|
||||
}
|
||||
|
||||
if (pipe_mode) {
|
||||
struct sockaddr_un *sa = (struct sockaddr_un *) address;
|
||||
int len = strlen(pipe_mode);
|
||||
if (len+1 > sizeof(sa->sun_path)) {
|
||||
printf("<fifo-path> is too long, must be less than 108 chars including null-term\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
sa->sun_family = AF_UNIX;
|
||||
strncpy(sa->sun_path, pipe_mode, sizeof(sa->sun_path)-1);
|
||||
|
||||
fd_in = socket(AF_UNIX, SOCK_DGRAM, 0);
|
||||
} else {
|
||||
uint16_t server_port = atoi(udp_mode);
|
||||
if (server_port == 0) {
|
||||
printf("UDP port provided was invalid\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct sockaddr_in *in = (struct sockaddr_in *) address;
|
||||
in->sin_family = AF_INET;
|
||||
in->sin_addr.s_addr = INADDR_ANY;
|
||||
in->sin_port = htons(server_port);
|
||||
|
||||
fd_in = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
}
|
||||
|
||||
if (bind(fd_in, (const struct sockaddr *) address, address_len) == -1) {
|
||||
printf("Failed to bind to socket\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
fprintf(stderr, "READY\n");
|
||||
|
||||
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(&action_mutex, NULL);
|
||||
|
||||
while (!m_quit) {
|
||||
uint8_t sender_addr[sizeof(client_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;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&action_mutex);
|
||||
if (action_ended) {
|
||||
void *ret;
|
||||
pthread_join(current_action, &ret);
|
||||
action_ended = 0;
|
||||
current_action = 0;
|
||||
}
|
||||
pthread_mutex_unlock(&action_mutex);
|
||||
|
||||
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));
|
||||
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;
|
||||
}
|
||||
case VANILLA_PIPE_IN_CONNECT:
|
||||
{
|
||||
if (current_action != 0) {
|
||||
write_control_code(VANILLA_PIPE_ERR_BUSY);
|
||||
} else {
|
||||
struct connect_args *args = (struct connect_args *) malloc(sizeof(struct connect_args));
|
||||
args->wireless_interface = wireless_interface;
|
||||
write_control_code(VANILLA_PIPE_ERR_SUCCESS);
|
||||
pthread_create(¤t_action, NULL, connect_command, args);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VANILLA_PIPE_IN_BUTTON:
|
||||
{
|
||||
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:
|
||||
{
|
||||
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:
|
||||
{
|
||||
if (current_action != 0) {
|
||||
void *ret;
|
||||
vanilla_stop();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VANILLA_PIPE_IN_REQ_IDR:
|
||||
{
|
||||
vanilla_request_idr();
|
||||
break;
|
||||
}
|
||||
case VANILLA_PIPE_IN_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:
|
||||
{
|
||||
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_command_code *bind_cmd = (struct pipe_command_code *) 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
|
||||
memcpy(client_addr, sender_addr, sizeof(client_addr));
|
||||
|
||||
struct sockaddr_in *udp_client = (struct sockaddr_in *) client_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);
|
||||
|
||||
close(fd_in);
|
||||
close(fd_out);
|
||||
|
||||
return 0;
|
||||
|
||||
show_help:
|
||||
printf("Usage: %s <wireless-interface> <mode> [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");
|
||||
printf("Modes:\n\n");
|
||||
printf(" -pipe <fifo>\n");
|
||||
printf(" Set up communication through Unix FIFO pipes. This is the most reliable\n");
|
||||
printf(" solution if you're running the frontend and backend on the same device.\n\n");
|
||||
printf(" -udp <port>\n\n");
|
||||
printf(" Set up communication through networked UDP port. This is the best option\n");
|
||||
printf(" if the frontend and backend are on separate devices.\n\n");
|
||||
return 1;
|
||||
}
|
86
pipe/pipe.h
86
pipe/pipe.h
|
@ -1,86 +0,0 @@
|
|||
#ifndef VANILLA_PIPE_H
|
||||
#define VANILLA_PIPE_H
|
||||
|
||||
// Control codes that our pipe will receive
|
||||
enum pipe_opcodes
|
||||
{
|
||||
VANILLA_PIPE_IN_SYNC = 1,
|
||||
VANILLA_PIPE_IN_CONNECT,
|
||||
VANILLA_PIPE_IN_BUTTON,
|
||||
VANILLA_PIPE_IN_TOUCH,
|
||||
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
|
||||
VANILLA_PIPE_ERR_SUCCESS = 0x30,
|
||||
VANILLA_PIPE_ERR_UNK,
|
||||
VANILLA_PIPE_ERR_INVALID,
|
||||
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[2048];
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif // VANILLA_PIPE_H
|
Loading…
Reference in a new issue