Finish Discovery Service

This commit is contained in:
Florian Märkl 2019-08-13 16:35:42 +02:00
commit 70b2b3f009
No known key found for this signature in database
GPG key ID: 125BC8A5A6A1E857
9 changed files with 157 additions and 18 deletions

View file

@ -19,20 +19,42 @@
#define CHIAKI_DISCOVERYMANAGER_H #define CHIAKI_DISCOVERYMANAGER_H
#include <QObject> #include <QObject>
#include <QList>
#include <chiaki/discoveryservice.h> #include <chiaki/discoveryservice.h>
struct DiscoveryHost
{
ChiakiDiscoveryHostState state;
uint16_t host_request_port;
#define STRING_MEMBER(name) QString name;
CHIAKI_DISCOVERY_HOST_STRING_FOREACH(STRING_MEMBER)
#undef STRING_MEMBER
};
Q_DECLARE_METATYPE(DiscoveryHost)
class DiscoveryManager : public QObject class DiscoveryManager : public QObject
{ {
Q_OBJECT Q_OBJECT
friend class DiscoveryManagerPrivate;
private: private:
ChiakiDiscoveryService service; ChiakiDiscoveryService service;
QList<DiscoveryHost> hosts;
private slots:
void DiscoveryServiceHosts(QList<DiscoveryHost> hosts);
public: public:
explicit DiscoveryManager(QObject *parent = nullptr); explicit DiscoveryManager(QObject *parent = nullptr);
~DiscoveryManager(); ~DiscoveryManager();
const QList<DiscoveryHost> GetHosts() const { return hosts; }
signals:
void HostsUpdated();
}; };
#endif //CHIAKI_DISCOVERYMANAGER_H #endif //CHIAKI_DISCOVERYMANAGER_H

View file

@ -20,6 +20,8 @@
#include <QMainWindow> #include <QMainWindow>
#include "discoverymanager.h"
class DynamicGridWidget; class DynamicGridWidget;
class ServerItemWidget; class ServerItemWidget;
@ -31,6 +33,8 @@ class MainWindow : public QMainWindow
DynamicGridWidget *grid_widget; DynamicGridWidget *grid_widget;
QList<ServerItemWidget *> server_item_widgets; QList<ServerItemWidget *> server_item_widgets;
DiscoveryManager discovery_manager;
public: public:
explicit MainWindow(QWidget *parent = nullptr); explicit MainWindow(QWidget *parent = nullptr);
@ -40,6 +44,8 @@ class MainWindow : public QMainWindow
void RunDiscovery(); void RunDiscovery();
void ShowSettings(); void ShowSettings();
void DiscoveryHostsUpdated();
}; };
#endif //CHIAKI_MAINWINDOW_H #endif //CHIAKI_MAINWINDOW_H

View file

@ -1,3 +1,5 @@
#include <utility>
/* /*
* This file is part of Chiaki. * This file is part of Chiaki.
* *
@ -17,14 +19,29 @@
#include <discoverymanager.h> #include <discoverymanager.h>
#include <netinet/in.h>
#define PING_MS 500
#define HOSTS_MAX 16
#define DROP_PINGS 3
static void DiscoveryServiceHostsCallback(ChiakiDiscoveryHost *hosts, size_t hosts_count, void *user);
DiscoveryManager::DiscoveryManager(QObject *parent) : QObject(parent) DiscoveryManager::DiscoveryManager(QObject *parent) : QObject(parent)
{ {
ChiakiDiscoveryServiceOptions options; ChiakiDiscoveryServiceOptions options;
options.ping_ms = 500; options.ping_ms = PING_MS;
options.hosts_max = 16; options.hosts_max = HOSTS_MAX;
options.host_drop_pings = DROP_PINGS;
options.cb = DiscoveryServiceHostsCallback;
options.cb_user = this;
options.send_addr = nullptr; // TODO sockaddr_in addr = {};
options.send_addr_size = 0; // TODO addr.sin_family = AF_INET;
addr.sin_port = htons(CHIAKI_DISCOVERY_PORT);
addr.sin_addr.s_addr = 0xffffffff; // 255.255.255.255
options.send_addr = reinterpret_cast<sockaddr *>(&addr);
options.send_addr_size = sizeof(addr);
ChiakiErrorCode err = chiaki_discovery_service_init(&service, &options, nullptr /* TODO */); ChiakiErrorCode err = chiaki_discovery_service_init(&service, &options, nullptr /* TODO */);
if(err != CHIAKI_ERR_SUCCESS) if(err != CHIAKI_ERR_SUCCESS)
@ -35,3 +52,40 @@ DiscoveryManager::~DiscoveryManager()
{ {
chiaki_discovery_service_fini(&service); chiaki_discovery_service_fini(&service);
} }
void DiscoveryManager::DiscoveryServiceHosts(QList<DiscoveryHost> hosts)
{
this->hosts = std::move(hosts);
emit HostsUpdated();
}
#include <QDebug>
class DiscoveryManagerPrivate
{
public:
static void DiscoveryServiceHosts(DiscoveryManager *discovery_manager, const QList<DiscoveryHost> &hosts)
{
QMetaObject::invokeMethod(discovery_manager, "DiscoveryServiceHosts", Qt::ConnectionType::QueuedConnection, Q_ARG(QList<DiscoveryHost>, hosts));
}
};
static void DiscoveryServiceHostsCallback(ChiakiDiscoveryHost *hosts, size_t hosts_count, void *user)
{
QList<DiscoveryHost> hosts_list;
hosts_list.reserve(hosts_count);
for(size_t i=0; i<hosts_count; i++)
{
ChiakiDiscoveryHost *h = hosts + i;
DiscoveryHost o = {};
o.state = h->state;
o.host_request_port = o.host_request_port;
#define CONVERT_STRING(name) if(h->name) { o.name = QString::fromLocal8Bit(h->name); }
CHIAKI_DISCOVERY_HOST_STRING_FOREACH(CONVERT_STRING)
#undef CONVERT_STRING
hosts_list.append(o);
}
DiscoveryManagerPrivate::DiscoveryServiceHosts(reinterpret_cast<DiscoveryManager *>(user), hosts_list);
}

View file

@ -32,6 +32,7 @@ int RunMain(QApplication &app);
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
qRegisterMetaType<DiscoveryHost>();
qRegisterMetaType<ChiakiQuitReason>(); qRegisterMetaType<ChiakiQuitReason>();
ChiakiErrorCode err = chiaki_lib_init(); ChiakiErrorCode err = chiaki_lib_init();

View file

@ -74,6 +74,8 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
} }
resize(800, 600); resize(800, 600);
connect(&discovery_manager, &DiscoveryManager::HostsUpdated, this, &MainWindow::DiscoveryHostsUpdated);
} }
void MainWindow::ServerItemWidgetSelected() void MainWindow::ServerItemWidgetSelected()
@ -108,3 +110,8 @@ void MainWindow::ShowSettings()
{ {
qDebug() << "TODO: ShowSettings()"; qDebug() << "TODO: ShowSettings()";
} }
void MainWindow::DiscoveryHostsUpdated()
{
qDebug() << "updated hosts" << discovery_manager.GetHosts().count();
}

View file

@ -55,6 +55,7 @@ const char *chiaki_discovery_host_state_string(ChiakiDiscoveryHostState state);
typedef struct chiaki_discovery_host_t typedef struct chiaki_discovery_host_t
{ {
// All string members here must be in sync with CHIAKI_DISCOVERY_HOST_STRING_FOREACH
ChiakiDiscoveryHostState state; ChiakiDiscoveryHostState state;
const char *system_version; const char *system_version;
const char *device_discovery_protocol_version; const char *device_discovery_protocol_version;
@ -66,6 +67,18 @@ typedef struct chiaki_discovery_host_t
const char *running_app_name; const char *running_app_name;
} ChiakiDiscoveryHost; } ChiakiDiscoveryHost;
/**
* Apply A on all names of string members in ChiakiDiscoveryHost
*/
#define CHIAKI_DISCOVERY_HOST_STRING_FOREACH(A) \
A(system_version); \
A(device_discovery_protocol_version); \
A(host_name); \
A(host_type); \
A(host_id); \
A(running_app_titleid); \
A(running_app_name);
CHIAKI_EXPORT int chiaki_discovery_packet_fmt(char *buf, size_t buf_size, ChiakiDiscoveryPacket *packet); CHIAKI_EXPORT int chiaki_discovery_packet_fmt(char *buf, size_t buf_size, ChiakiDiscoveryPacket *packet);
typedef struct chiaki_discovery_t typedef struct chiaki_discovery_t

View file

@ -25,6 +25,8 @@
extern "C" { extern "C" {
#endif #endif
typedef void (*ChiakiDiscoveryServiceCb)(ChiakiDiscoveryHost *hosts, size_t hosts_count, void *user);
typedef struct chiaki_discovery_service_options_t typedef struct chiaki_discovery_service_options_t
{ {
size_t hosts_max; size_t hosts_max;
@ -32,6 +34,8 @@ typedef struct chiaki_discovery_service_options_t
uint64_t ping_ms; uint64_t ping_ms;
struct sockaddr *send_addr; struct sockaddr *send_addr;
size_t send_addr_size; size_t send_addr_size;
ChiakiDiscoveryServiceCb cb;
void *cb_user;
} ChiakiDiscoveryServiceOptions; } ChiakiDiscoveryServiceOptions;
typedef struct chiaki_discovery_service_host_discovery_info_t typedef struct chiaki_discovery_service_host_discovery_info_t

View file

@ -241,7 +241,7 @@ static void *discovery_thread_func(void *user)
buf[n] = '\00'; buf[n] = '\00';
CHIAKI_LOGV(discovery->log, "Discovery received:\n%s", buf); CHIAKI_LOGV(discovery->log, "Discovery received:\n%s", buf);
chiaki_log_hexdump_raw(discovery->log, CHIAKI_LOG_VERBOSE, (const uint8_t *)buf, n); //chiaki_log_hexdump_raw(discovery->log, CHIAKI_LOG_VERBOSE, (const uint8_t *)buf, n);
ChiakiDiscoveryHost response; ChiakiDiscoveryHost response;
err = chiaki_discovery_srch_response_parse(&response, buf, n); err = chiaki_discovery_srch_response_parse(&response, buf, n);

View file

@ -24,6 +24,7 @@ static void *discovery_service_thread_func(void *user);
static void discovery_service_ping(ChiakiDiscoveryService *service); static void discovery_service_ping(ChiakiDiscoveryService *service);
static void discovery_service_drop_old_hosts(ChiakiDiscoveryService *service); static void discovery_service_drop_old_hosts(ChiakiDiscoveryService *service);
static void discovery_service_host_received(ChiakiDiscoveryHost *host, void *user); static void discovery_service_host_received(ChiakiDiscoveryHost *host, void *user);
static void discovery_service_report_state(ChiakiDiscoveryService *service);
CHIAKI_EXPORT ChiakiErrorCode chiaki_discovery_service_init(ChiakiDiscoveryService *service, ChiakiDiscoveryServiceOptions *options, ChiakiLog *log) CHIAKI_EXPORT ChiakiErrorCode chiaki_discovery_service_init(ChiakiDiscoveryService *service, ChiakiDiscoveryServiceOptions *options, ChiakiLog *log)
{ {
@ -111,7 +112,7 @@ static void *discovery_service_thread_func(void *user)
if(err != CHIAKI_ERR_SUCCESS) if(err != CHIAKI_ERR_SUCCESS)
goto beach; goto beach;
while(service->stop_cond.pred) while(true)
{ {
err = chiaki_bool_pred_cond_timedwait(&service->stop_cond, service->options.ping_ms); err = chiaki_bool_pred_cond_timedwait(&service->stop_cond, service->options.ping_ms);
if(err != CHIAKI_ERR_TIMEOUT) if(err != CHIAKI_ERR_TIMEOUT)
@ -119,6 +120,8 @@ static void *discovery_service_thread_func(void *user)
discovery_service_ping(service); discovery_service_ping(service);
} }
chiaki_discovery_thread_stop(&discovery_thread);
beach: beach:
chiaki_bool_pred_cond_unlock(&service->stop_cond); chiaki_bool_pred_cond_unlock(&service->stop_cond);
return NULL; return NULL;
@ -137,25 +140,31 @@ static void discovery_service_ping(ChiakiDiscoveryService *service)
CHIAKI_LOGV(service->log, "Discovery Service sending ping"); CHIAKI_LOGV(service->log, "Discovery Service sending ping");
ChiakiDiscoveryPacket packet = { 0 }; ChiakiDiscoveryPacket packet = { 0 };
packet.cmd = CHIAKI_DISCOVERY_CMD_SRCH; packet.cmd = CHIAKI_DISCOVERY_CMD_SRCH;
chiaki_discovery_send(&service->discovery, &packet, service->options.send_addr, service->options.send_addr_size); err = chiaki_discovery_send(&service->discovery, &packet, service->options.send_addr, service->options.send_addr_size);
if(err != CHIAKI_ERR_SUCCESS)
CHIAKI_LOGE(service->log, "Discovery Service failed to send ping");
} }
static void discovery_service_drop_old_hosts(ChiakiDiscoveryService *service) static void discovery_service_drop_old_hosts(ChiakiDiscoveryService *service)
{ {
// service->state_mutex must be locked // service->state_mutex must be locked
bool change = false;
for(size_t i=0; i<service->hosts_count; i++) for(size_t i=0; i<service->hosts_count; i++)
{ {
if(service->host_discovery_infos[i].last_ping_index >= service->ping_index - service->options.host_drop_pings) if(service->host_discovery_infos[i].last_ping_index + service->options.host_drop_pings >= service->ping_index)
continue; continue;
CHIAKI_LOGI(service->log, "Discovery Service: Host with id %s is no longer available", service->hosts[i].host_id); ChiakiDiscoveryHost *host = &service->hosts[i];
CHIAKI_LOGI(service->log, "Discovery Service: Host with id %s is no longer available", host->host_id ? host->host_id : "");
// TODO: free inner strings of service->hosts[i] #define FREE_STRING(name) do { free((char *)host->name); } while(0)
CHIAKI_DISCOVERY_HOST_STRING_FOREACH(FREE_STRING)
#undef FREE_STRING
if(i < service->hosts_count - 1) if(i < service->hosts_count - 1)
{ {
// TODO: check again if correct
memmove(service->host_discovery_infos + i, memmove(service->host_discovery_infos + i,
service->host_discovery_infos + i + 1, service->host_discovery_infos + i + 1,
sizeof(ChiakiDiscoveryServiceHostDiscoveryInfo) * (service->hosts_count - i - 1)); sizeof(ChiakiDiscoveryServiceHostDiscoveryInfo) * (service->hosts_count - i - 1));
@ -165,9 +174,14 @@ static void discovery_service_drop_old_hosts(ChiakiDiscoveryService *service)
sizeof(ChiakiDiscoveryHost) * (service->hosts_count - i - 1)); sizeof(ChiakiDiscoveryHost) * (service->hosts_count - i - 1));
} }
change = true;
i--; i--;
service->hosts_count--; service->hosts_count--;
} }
if(change)
discovery_service_drop_old_hosts(service);
} }
static void discovery_service_host_received(ChiakiDiscoveryHost *host, void *user) static void discovery_service_host_received(ChiakiDiscoveryHost *host, void *user)
@ -180,9 +194,13 @@ static void discovery_service_host_received(ChiakiDiscoveryHost *host, void *use
return; return;
} }
CHIAKI_LOGV(service->log, "Discovery Service Received host with id %s", host->host_id);
ChiakiErrorCode err = chiaki_mutex_lock(&service->state_mutex); ChiakiErrorCode err = chiaki_mutex_lock(&service->state_mutex);
assert(err == CHIAKI_ERR_SUCCESS); assert(err == CHIAKI_ERR_SUCCESS);
bool change = false;
size_t index = SIZE_MAX; size_t index = SIZE_MAX;
for(size_t i=0; i<service->hosts_count; i++) for(size_t i=0; i<service->hosts_count; i++)
{ {
@ -204,6 +222,7 @@ static void discovery_service_host_received(ChiakiDiscoveryHost *host, void *use
goto r2con; goto r2con;
} }
change = true;
index = service->hosts_count++; index = service->hosts_count++;
memset(&service->hosts[index], 0, sizeof(ChiakiDiscoveryHost)); memset(&service->hosts[index], 0, sizeof(ChiakiDiscoveryHost));
} }
@ -211,12 +230,19 @@ static void discovery_service_host_received(ChiakiDiscoveryHost *host, void *use
service->host_discovery_infos[index].last_ping_index = service->ping_index; service->host_discovery_infos[index].last_ping_index = service->ping_index;
ChiakiDiscoveryHost *host_slot = &service->hosts[index]; ChiakiDiscoveryHost *host_slot = &service->hosts[index];
if(host_slot->state != host->state || host_slot->host_request_port != host->host_request_port)
change = true;
host_slot->state = host->state; host_slot->state = host->state;
host_slot->host_request_port = host->host_request_port; host_slot->host_request_port = host->host_request_port;
#define UPDATE_STRING(name) do { \ #define UPDATE_STRING(name) do { \
if(host_slot->name && host->name && strcmp(host_slot->name, host->name) == 0) \ if(host_slot->name && host->name && strcmp(host_slot->name, host->name) == 0) \
break; \
if(!host_slot->name && !host->name) \
break; \ break; \
change = true; \
if(host_slot->name) \ if(host_slot->name) \
free((char *)host_slot->name); \ free((char *)host_slot->name); \
if(host->name) \ if(host->name) \
@ -225,14 +251,20 @@ static void discovery_service_host_received(ChiakiDiscoveryHost *host, void *use
host_slot->name = NULL; \ host_slot->name = NULL; \
} while(0) } while(0)
UPDATE_STRING(system_version); CHIAKI_DISCOVERY_HOST_STRING_FOREACH(UPDATE_STRING)
UPDATE_STRING(device_discovery_protocol_version);
UPDATE_STRING(host_name); #undef UPDATE_STRING
UPDATE_STRING(host_type);
UPDATE_STRING(host_id); if(change)
UPDATE_STRING(running_app_titleid); discovery_service_report_state(service);
UPDATE_STRING(running_app_name);
r2con: r2con:
chiaki_mutex_unlock(&service->state_mutex); chiaki_mutex_unlock(&service->state_mutex);
}
static void discovery_service_report_state(ChiakiDiscoveryService *service)
{
// service->state_mutex must be locked
if(service->options.cb)
service->options.cb(service->hosts, service->hosts_count, service->options.cb_user);
} }