From 4fadc029479e4c352647a68020d6297bfe7c1724 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Fri, 16 Aug 2019 22:32:41 +0200 Subject: [PATCH] Implement Wakeup --- gui/include/discoverymanager.h | 2 + gui/include/mainwindow.h | 1 + gui/include/serveritemwidget.h | 1 + gui/src/discoverymanager.cpp | 76 +++++++++++++++++++++++++++++++++- gui/src/mainwindow.cpp | 37 +++++++++++++++-- gui/src/serveritemwidget.cpp | 3 +- lib/include/chiaki/discovery.h | 4 +- lib/src/discovery.c | 14 +++++++ lib/src/regist.c | 2 +- 9 files changed, 132 insertions(+), 8 deletions(-) diff --git a/gui/include/discoverymanager.h b/gui/include/discoverymanager.h index f2b09de..471c61d 100644 --- a/gui/include/discoverymanager.h +++ b/gui/include/discoverymanager.h @@ -59,6 +59,8 @@ class DiscoveryManager : public QObject void SetActive(bool active); + void SendWakeup(const QString &host, const QByteArray ®ist_key); + const QList GetHosts() const { return hosts; } signals: diff --git a/gui/include/mainwindow.h b/gui/include/mainwindow.h index a43a4d3..a91c3c5 100644 --- a/gui/include/mainwindow.h +++ b/gui/include/mainwindow.h @@ -56,6 +56,7 @@ class MainWindow : public QMainWindow QList display_servers; DisplayServer *DisplayServerFromSender(); + void SendWakeup(const DisplayServer *server); private slots: void ServerItemWidgetSelected(); diff --git a/gui/include/serveritemwidget.h b/gui/include/serveritemwidget.h index 3acbee6..bae3032 100644 --- a/gui/include/serveritemwidget.h +++ b/gui/include/serveritemwidget.h @@ -37,6 +37,7 @@ class ServerItemWidget : public QFrame ServerIconWidget *icon_widget; QAction *delete_action; + QAction *wake_action; protected: void mousePressEvent(QMouseEvent *event) override; diff --git a/gui/src/discoverymanager.cpp b/gui/src/discoverymanager.cpp index 00f4585..28b97e1 100644 --- a/gui/src/discoverymanager.cpp +++ b/gui/src/discoverymanager.cpp @@ -1,5 +1,3 @@ -#include - /* * This file is part of Chiaki. * @@ -18,7 +16,9 @@ */ #include +#include +#include #include #define PING_MS 500 @@ -86,6 +86,78 @@ void DiscoveryManager::SetActive(bool active) } +void DiscoveryManager::SendWakeup(const QString &host, const QByteArray ®ist_key) +{ + addrinfo *addrinfos; + int r = getaddrinfo(host.toLocal8Bit().constData(), nullptr, nullptr, &addrinfos); + if(r != 0) + { + CHIAKI_LOGE(&log, "DiscoveryManager failed to getaddrinfo for wakeup"); + throw Exception("Failed to getaddrinfo"); + } + sockaddr addr = {}; + socklen_t addr_len = 0; + for(addrinfo *ai=addrinfos; ai; ai=ai->ai_next) + { + if(ai->ai_family != AF_INET) + continue; + if(ai->ai_protocol != IPPROTO_UDP) + continue; + if(ai->ai_addrlen > sizeof(addr)) + continue; + std::memcpy(&addr, ai->ai_addr, ai->ai_addrlen); + addr_len = ai->ai_addrlen; + break; + } + freeaddrinfo(addrinfos); + + if(!addr_len) + { + CHIAKI_LOGE(&log, "DiscoveryManager failed to get suitable address from getaddrinfo for wakeup"); + throw Exception("Failed to get addr from getaddrinfo"); + } + + ((sockaddr_in *)&addr)->sin_port = htons(CHIAKI_DISCOVERY_PORT); + + QByteArray key = regist_key; + for(size_t i=0; i 8 || !ok) + { + CHIAKI_LOGE(&log, "DiscoveryManager got invalid regist key for wakeup"); + throw Exception("Invalid regist key"); + } + + ChiakiDiscoveryPacket packet = {}; + packet.cmd = CHIAKI_DISCOVERY_CMD_WAKEUP; + packet.user_credential = credential; + + ChiakiErrorCode err; + if(service_active) + err = chiaki_discovery_send(&service.discovery, &packet, &addr, addr_len); + else + { + ChiakiDiscovery discovery; + err = chiaki_discovery_init(&discovery, &log, AF_INET); + if(err != CHIAKI_ERR_SUCCESS) + throw Exception(QString("Failed to init Discovery: %1").arg(chiaki_error_string(err))); + err = chiaki_discovery_send(&discovery, &packet, &addr, addr_len); + chiaki_discovery_fini(&discovery); + } + + if(err != CHIAKI_ERR_SUCCESS) + throw Exception(QString("Failed to send Packet: %1").arg(chiaki_error_string(err))); +} + void DiscoveryManager::DiscoveryServiceHosts(QList hosts) { this->hosts = std::move(hosts); diff --git a/gui/src/mainwindow.cpp b/gui/src/mainwindow.cpp index b70cc4b..c9c903e 100644 --- a/gui/src/mainwindow.cpp +++ b/gui/src/mainwindow.cpp @@ -121,6 +121,24 @@ DisplayServer *MainWindow::DisplayServerFromSender() return &display_servers[index]; } +void MainWindow::SendWakeup(const DisplayServer *server) +{ + if(!server->registered) + return; + + try + { + discovery_manager.SendWakeup(server->GetHostAddr(), server->registered_host.GetRPRegistKey()); + } + catch(const Exception &e) + { + QMessageBox::critical(this, tr("Wakeup failed"), tr("Failed to send Wakeup packet:\n%1").arg(e.what())); + return; + } + + QMessageBox::information(this, tr("Wakeup"), tr("Wakeup packet sent.")); +} + void MainWindow::ServerItemWidgetTriggered() { auto server = DisplayServerFromSender(); @@ -129,6 +147,21 @@ void MainWindow::ServerItemWidgetTriggered() if(server->registered) { + if(server->discovered && server->discovery_host.state == CHIAKI_DISCOVERY_HOST_STATE_STANDBY) + { + int r = QMessageBox::question(this, + tr("Start Stream"), + tr("The Console is currently in standby mode.\nShould we send a Wakeup packet instead of trying to connect immediately?"), + QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel); + if(r == QMessageBox::Yes) + { + SendWakeup(server); + return; + } + else if(r == QMessageBox::Cancel) + return; + } + QString host = server->GetHostAddr(); StreamSessionConnectInfo info(settings, host, server->registered_host.GetRPRegistKey(), server->registered_host.GetRPKey()); try @@ -165,9 +198,7 @@ void MainWindow::ServerItemWidgetWakeTriggered() auto server = DisplayServerFromSender(); if(!server) return; - - // TODO - printf("TODO: Wakeup\n"); + SendWakeup(server); } void MainWindow::UpdateDiscoveryEnabled() diff --git a/gui/src/serveritemwidget.cpp b/gui/src/serveritemwidget.cpp index 1419c0d..c789fca 100644 --- a/gui/src/serveritemwidget.cpp +++ b/gui/src/serveritemwidget.cpp @@ -51,7 +51,7 @@ ServerItemWidget::ServerItemWidget(QWidget *parent) : QFrame(parent) addAction(delete_action); connect(delete_action, &QAction::triggered, this, [this]{ emit DeleteTriggered(); }); - auto wake_action = new QAction(tr("Send Wakeup Packet"), this); + wake_action = new QAction(tr("Send Wakeup Packet"), this); addAction(wake_action); connect(wake_action, &QAction::triggered, this, [this]{ emit WakeTriggered(); }); @@ -83,6 +83,7 @@ void ServerItemWidget::SetSelected(bool selected) void ServerItemWidget::Update(const DisplayServer &display_server) { delete_action->setEnabled(!display_server.discovered); + wake_action->setEnabled(display_server.registered); icon_widget->SetState(display_server.discovered ? display_server.discovery_host.state : CHIAKI_DISCOVERY_HOST_STATE_UNKNOWN); diff --git a/lib/include/chiaki/discovery.h b/lib/include/chiaki/discovery.h index 3934667..dba5530 100644 --- a/lib/include/chiaki/discovery.h +++ b/lib/include/chiaki/discovery.h @@ -35,13 +35,15 @@ extern "C" { typedef enum chiaki_discovery_cmd_t { - CHIAKI_DISCOVERY_CMD_SRCH + CHIAKI_DISCOVERY_CMD_SRCH, + CHIAKI_DISCOVERY_CMD_WAKEUP } ChiakiDiscoveryCmd; typedef struct chiaki_discovery_packet_t { ChiakiDiscoveryCmd cmd; char *protocol_version; + uint64_t user_credential; // for wakeup, this is just the regist key interpreted as hex } ChiakiDiscoveryPacket; typedef enum chiaki_discovery_host_state_t diff --git a/lib/src/discovery.c b/lib/src/discovery.c index 3431220..460e125 100644 --- a/lib/src/discovery.c +++ b/lib/src/discovery.c @@ -26,6 +26,7 @@ #include #include #include +#include #include const char *chiaki_discovery_host_state_string(ChiakiDiscoveryHostState state) @@ -49,6 +50,16 @@ CHIAKI_EXPORT int chiaki_discovery_packet_fmt(char *buf, size_t buf_size, Chiaki case CHIAKI_DISCOVERY_CMD_SRCH: return snprintf(buf, buf_size, "SRCH * HTTP/1.1\ndevice-discovery-protocol-version:%s\n", version_str); + case CHIAKI_DISCOVERY_CMD_WAKEUP: + return snprintf(buf, buf_size, + "WAKEUP * HTTP/1.1\n" + "client-type:vr\n" + "auth-type:R\n" + "model:w\n" + "app-type:r\n" + "user-credential:%llu\n" + "device-discovery-protocol-version:%s\n", + (unsigned long long)packet->user_credential, version_str); default: return -1; } @@ -169,7 +180,10 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_discovery_send(ChiakiDiscovery *discovery, ssize_t rc = sendto(discovery->socket, buf, (size_t)len + 1, 0, addr, addr_size); if(rc < 0) + { + CHIAKI_LOGE(discovery->log, "Discovery failed to send: %s", strerror(errno)); return CHIAKI_ERR_NETWORK; + } return CHIAKI_ERR_SUCCESS; } diff --git a/lib/src/regist.c b/lib/src/regist.c index 2c160bb..e524855 100644 --- a/lib/src/regist.c +++ b/lib/src/regist.c @@ -346,7 +346,7 @@ static int regist_search_connect(ChiakiRegist *regist, struct addrinfo *addrinfo } in_addr_t ip = ((struct sockaddr_in *)send_addr)->sin_addr.s_addr; - ((struct sockaddr_in *)send_addr)->sin_addr.s_addr = INADDR_ANY; + ((struct sockaddr_in *)send_addr)->sin_addr.s_addr = htonl(INADDR_ANY); r = bind(sock, send_addr, *send_addr_len); ((struct sockaddr_in *)send_addr)->sin_addr.s_addr = ip; if(r < 0)