Implement Wakeup

This commit is contained in:
Florian Märkl 2019-08-16 22:32:41 +02:00
commit 4fadc02947
No known key found for this signature in database
GPG key ID: 125BC8A5A6A1E857
9 changed files with 132 additions and 8 deletions

View file

@ -59,6 +59,8 @@ class DiscoveryManager : public QObject
void SetActive(bool active);
void SendWakeup(const QString &host, const QByteArray &regist_key);
const QList<DiscoveryHost> GetHosts() const { return hosts; }
signals:

View file

@ -56,6 +56,7 @@ class MainWindow : public QMainWindow
QList<DisplayServer> display_servers;
DisplayServer *DisplayServerFromSender();
void SendWakeup(const DisplayServer *server);
private slots:
void ServerItemWidgetSelected();

View file

@ -37,6 +37,7 @@ class ServerItemWidget : public QFrame
ServerIconWidget *icon_widget;
QAction *delete_action;
QAction *wake_action;
protected:
void mousePressEvent(QMouseEvent *event) override;

View file

@ -1,5 +1,3 @@
#include <utility>
/*
* This file is part of Chiaki.
*
@ -18,7 +16,9 @@
*/
#include <discoverymanager.h>
#include <exception.h>
#include <cstring>
#include <netinet/in.h>
#define PING_MS 500
@ -86,6 +86,78 @@ void DiscoveryManager::SetActive(bool active)
}
void DiscoveryManager::SendWakeup(const QString &host, const QByteArray &regist_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<key.size(); i++)
{
if(!key.at(i))
{
key.resize(i);
break;
}
}
bool ok;
uint64_t credential = (uint64_t)QString::fromUtf8(key).toULongLong(&ok, 16);
if(key.size() > 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<DiscoveryHost> hosts)
{
this->hosts = std::move(hosts);

View file

@ -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()

View file

@ -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);

View file

@ -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

View file

@ -26,6 +26,7 @@
#include <netdb.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <arpa/inet.h>
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;
}

View file

@ -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)