spice-power.h is the API towards the consumer/implementor (e.g. QEMU),
while power-channel.* is the actual library-internal implementation. The
consumer interface is required to start the channel, and currently empty.
---
server/Makefile.am | 3 +++
server/meson.build | 3 +++
server/power-channel.cpp | 58 ++++++++++++++++++++++++++++++++++++++++
server/power-channel.h | 45 +++++++++++++++++++++++++++++++
server/reds.cpp | 9 +++++++
server/spice-power.h | 49 +++++++++++++++++++++++++++++++++
server/spice-wrapped.h | 1 +
server/spice.h | 1 +
server/utils.c | 1 +
9 files changed, 170 insertions(+)
diff --git a/server/Makefile.am b/server/Makefile.am
index 5260051b..63ef40dc 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -74,6 +74,7 @@ libspice_serverinclude_HEADERS = \
spice-core.h \
spice-input.h \
spice-migration.h \
+ spice-power.h \
spice-qxl.h \
spice-server.h \
spice-version.h \
@@ -141,6 +142,8 @@ libserver_la_SOURCES = \
pixmap-cache.cpp \
pixmap-cache.h \
pop-visibility.h \
+ power-channel.cpp \
+ power-channel.h \
push-visibility.h \
red-channel.cpp \
red-channel-capabilities.c \
diff --git a/server/meson.build b/server/meson.build
index a8da777f..568b00cd 100644
--- a/server/meson.build
+++ b/server/meson.build
@@ -48,6 +48,7 @@ spice_server_headers = [
'spice-core.h',
'spice-input.h',
'spice-migration.h',
+ 'spice-power.h',
'spice-qxl.h',
'spice-server.h',
'spice-replay.h',
@@ -121,6 +122,8 @@ spice_server_sources = [
'net-utils.h',
'pixmap-cache.cpp',
'pixmap-cache.h',
+ 'power-channel.cpp',
+ 'power-channel.h',
'red-channel.cpp',
'red-channel-capabilities.c',
'red-channel-capabilities.h',
diff --git a/server/power-channel.cpp b/server/power-channel.cpp
new file mode 100644
index 00000000..bdf390c6
--- /dev/null
+++ b/server/power-channel.cpp
@@ -0,0 +1,58 @@
+/*
+ Copyright (C) 2026 Red Hat, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+#include <config.h>
+
+#include "power-channel.h"
+#include "reds.h"
+#include "red-client.h"
+
+void PowerChannel::on_connect(RedClient *client, RedStream *stream, int
migration,
+ RedChannelCapabilities *caps)
+{
+ spice_debug("PowerChannel on_connect() called");
+ if (!red_stream_is_ssl(stream) && !client->during_migrate_at_target()) {
+ client->get_main()->push_notify("power channel is insecure");
+ }
+}
+
+red::shared_ptr<PowerChannel> power_channel_new(RedsState *reds)
+{
+ return red::make_shared<PowerChannel>(reds);
+}
+
+PowerChannel::PowerChannel(RedsState *reds):
+ RedChannel(reds, SPICE_CHANNEL_POWER, 0, RedChannel::MigrateAll)
+{
+ spice_debug("PowerChannel() called");
+ reds_register_channel(reds, this);
+}
+
+void power_attach(RedsState *reds, SpicePowerInstance *sin)
+{
+ sin->st = new PowerChannel(reds);
+}
+
+void power_detach(SpicePowerInstance *sin)
+{
+ PowerChannel *channel = sin->st;
+
+ if (!channel) {
+ return;
+ }
+
+ channel->destroy();
+}
diff --git a/server/power-channel.h b/server/power-channel.h
new file mode 100644
index 00000000..252a300f
--- /dev/null
+++ b/server/power-channel.h
@@ -0,0 +1,45 @@
+/*
+ Copyright (C) 2026 Red Hat, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef POWER_CHANNEL_H_
+#define POWER_CHANNEL_H_
+
+// Power channel, dealing with power-off and hard-reset.
+// This include should only be used by reds.cpp and power-channel.cpp
+
+#include "red-channel.h"
+
+#include "push-visibility.h"
+
+class PowerChannel final: public RedChannel
+{
+public:
+ PowerChannel(RedsState *reds);
+
+private:
+ void on_connect(RedClient *client, RedStream *stream, int migration,
+ RedChannelCapabilities *caps) override;
+};
+
+red::shared_ptr<PowerChannel> power_channel_new(RedsState *reds);
+
+void power_attach(RedsState *reds, SpicePowerInstance *sin);
+void power_detach(SpicePowerInstance *sin);
+
+#include "pop-visibility.h"
+
+#endif /* POWER_CHANNEL_H_ */
diff --git a/server/reds.cpp b/server/reds.cpp
index b0f1be6a..c13dce16 100644
--- a/server/reds.cpp
+++ b/server/reds.cpp
@@ -71,6 +71,7 @@
#ifdef USE_SMARTCARD
#include "smartcard.h"
#endif
+#include "power-channel.h"
#include "red-stream.h"
#include "red-client.h"
@@ -3347,6 +3348,14 @@ SPICE_GNUC_VISIBLE int
spice_server_add_interface(SpiceServer *reds,
reds->migration_interface = SPICE_UPCAST(SpiceMigrateInstance, sin);
reds->migration_interface->st =
reinterpret_cast<SpiceMigrateState *>(static_cast<intptr_t>(1));
// dummy pointer
+ } else if (strcmp(base_interface->type, SPICE_INTERFACE_POWER) == 0) {
+ spice_debug("SPICE_INTERFACE_POWER");
+ if (base_interface->major_version != SPICE_INTERFACE_POWER_MAJOR ||
+ base_interface->minor_version > SPICE_INTERFACE_POWER_MINOR) {
+ spice_warning("unsupported power interface");
+ return -1;
+ }
+ power_attach(reds, SPICE_UPCAST(SpicePowerInstance, sin));
}
return 0;
diff --git a/server/spice-power.h b/server/spice-power.h
new file mode 100644
index 00000000..48d42364
--- /dev/null
+++ b/server/spice-power.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2026 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
<http://www.gnu.org/licenses/>.
+ */
+
+#ifndef SPICE_POWER_H_
+#define SPICE_POWER_H_
+
+#if !defined(SPICE_H_INSIDE) && !defined(SPICE_SERVER_INTERNAL)
+#error "Only spice.h can be included directly."
+#endif
+
+#include "spice-core.h"
+
+SPICE_BEGIN_DECLS
+
+/* power interfaces */
+
+#define SPICE_INTERFACE_POWER "power"
+#define SPICE_INTERFACE_POWER_MAJOR 1
+#define SPICE_INTERFACE_POWER_MINOR 1
+typedef struct SpicePowerInterface SpicePowerInterface;
+typedef struct SpicePowerInstance SpicePowerInstance;
+typedef struct SpicePowerState SpicePowerState;
+
+struct SpicePowerInterface {
+ SpiceBaseInterface base;
+};
+
+struct SpicePowerInstance {
+ SpiceBaseInstance base;
+ SpicePowerState *st;
+};
+
+SPICE_END_DECLS
+
+#endif /* SPICE_POWER_H_ */
diff --git a/server/spice-wrapped.h b/server/spice-wrapped.h
index 769f652f..5fbd62c4 100644
--- a/server/spice-wrapped.h
+++ b/server/spice-wrapped.h
@@ -26,6 +26,7 @@
#define SpiceCharDeviceState RedCharDevice
#define SpicePlaybackState PlaybackChannel
#define SpiceRecordState RecordChannel
+#define SpicePowerState PowerChannel
#include "push-visibility.h"
struct RedCharDevice;
diff --git a/server/spice.h b/server/spice.h
index 901addf2..3a5dc798 100644
--- a/server/spice.h
+++ b/server/spice.h
@@ -29,6 +29,7 @@
#include "spice-char.h"
#include "spice-migration.h"
#include "spice-replay.h"
+#include "spice-power.h"
#undef SPICE_H_INSIDE
diff --git a/server/utils.c b/server/utils.c
index 6232991f..40f6c430 100644
--- a/server/utils.c
+++ b/server/utils.c
@@ -65,6 +65,7 @@ static const char *const channel_names[] = {
[ SPICE_CHANNEL_USBREDIR ] = "usbredir",
[ SPICE_CHANNEL_PORT ] = "port",
[ SPICE_CHANNEL_WEBDAV ] = "webdav",
+ [ SPICE_CHANNEL_POWER ] = "power",
};
/* Make sure the last channel in the protocol has a name.
--
2.52.0