The channel itself is just a pipe pushing bytes. The client on top of
the channel is responsible for all the message handling.
---
 server/Makefile.am              |  2 +
 server/meson.build              |  2 +
 server/power-channel-client.cpp | 80 +++++++++++++++++++++++++++++++++
 server/power-channel-client.h   | 50 +++++++++++++++++++++
 server/power-channel.cpp        | 15 +++++++
 server/power-channel.h          |  6 +++
 server/spice-power.h            |  2 +
 7 files changed, 157 insertions(+)

diff --git a/server/Makefile.am b/server/Makefile.am
index 63ef40dc..a35d041c 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -144,6 +144,8 @@ libserver_la_SOURCES =                              \
        pop-visibility.h                        \
        power-channel.cpp                       \
        power-channel.h                         \
+       power-channel-client.cpp                \
+       power-channel-client.h                  \
        push-visibility.h                       \
        red-channel.cpp                         \
        red-channel-capabilities.c              \
diff --git a/server/meson.build b/server/meson.build
index 568b00cd..e590aadc 100644
--- a/server/meson.build
+++ b/server/meson.build
@@ -124,6 +124,8 @@ spice_server_sources = [
   'pixmap-cache.h',
   'power-channel.cpp',
   'power-channel.h',
+  'power-channel-client.cpp',
+  'power-channel-client.h',
   'red-channel.cpp',
   'red-channel-capabilities.c',
   'red-channel-capabilities.h',
diff --git a/server/power-channel-client.cpp b/server/power-channel-client.cpp
new file mode 100644
index 00000000..ee0b3a2d
--- /dev/null
+++ b/server/power-channel-client.cpp
@@ -0,0 +1,80 @@
+/*
+   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-client.h"
+#include "red-client.h"
+
+PowerChannelClient* power_channel_client_create(RedChannel *channel,
+                                                RedClient *client,
+                                                RedStream *stream,
+                                                RedChannelCapabilities *caps)
+{
+    spice_debug("power_channel_client_create() called");
+    auto rcc = red::make_shared<PowerChannelClient>(channel, client, stream, 
caps);
+    if (!rcc->init()) {
+        return nullptr;
+    }
+    return rcc.get();
+}
+
+uint8_t *PowerChannelClient::alloc_recv_buf(uint16_t type, uint32_t size)
+{
+    spice_debug("PowerChannelClient alloc_recv_buf() called");
+    if (size > sizeof(recv_buf)) {
+        red_channel_warning(get_channel(), "error: too large incoming 
message");
+        return nullptr;
+    }
+
+    return recv_buf;
+}
+
+void PowerChannelClient::release_recv_buf(uint16_t type, uint32_t size, 
uint8_t *msg)
+{
+    spice_debug("PowerChannelClient release_recv_buf() called");
+}
+
+bool PowerChannelClient::handle_message(uint16_t type, uint32_t size, void 
*message)
+{
+    spice_debug("PowerChannelClient handle_message() called");
+    PowerChannel *power_channel = get_channel();
+    SpicePowerInstance *sin = power_channel->sin;
+    SpicePowerInterface *sif;
+
+    if (!sin) {
+        spice_debug("PowerChannelClient handle_message() no interface");
+        return FALSE;
+    }
+    sif = SPICE_UPCAST(SpicePowerInterface, sin->base.sif);
+
+    switch (type) {
+        case SPICE_MSGC_POWER_RESET: {
+            spice_debug("Got a SPICE_MSGC_POWER_RESET message");
+            if (!sif->do_reset) {
+                spice_debug("PowerChannelClient handle_message() no reset 
impl");
+                this->get_client()->get_main()->push_notify("Server does not 
support power reset action.");
+                return TRUE;
+            }
+            sif->do_reset(sin);
+            break;
+        }
+        default:
+            return RedChannelClient::handle_message(type, size, message);
+    }
+
+    return TRUE;
+}
diff --git a/server/power-channel-client.h b/server/power-channel-client.h
new file mode 100644
index 00000000..fcc8f878
--- /dev/null
+++ b/server/power-channel-client.h
@@ -0,0 +1,50 @@
+/*
+   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_CLIENT_H_
+#define POWER_CHANNEL_CLIENT_H_
+
+#include "red-channel-client.h"
+#include "power-channel.h"
+
+#include "push-visibility.h"
+
+class PowerChannelClient final: public RedChannelClient
+{
+private:
+    using RedChannelClient::RedChannelClient;
+
+    virtual uint8_t *alloc_recv_buf(uint16_t type, uint32_t size) override;
+    virtual void release_recv_buf(uint16_t type, uint32_t size, uint8_t *msg) 
override;
+    virtual bool handle_message(uint16_t type, uint32_t size, void *message) 
override;
+
+    PowerChannel* get_channel()
+    {
+        return static_cast<PowerChannel*>(RedChannelClient::get_channel());
+    }
+
+    uint8_t recv_buf[1024];
+};
+
+PowerChannelClient* power_channel_client_create(RedChannel *channel,
+                                               RedClient *client,
+                                               RedStream *stream,
+                                               RedChannelCapabilities *caps);
+
+#include "pop-visibility.h"
+
+#endif /* POWER_CHANNEL_CLIENT_H_ */
diff --git a/server/power-channel.cpp b/server/power-channel.cpp
index bdf390c6..57f8951f 100644
--- a/server/power-channel.cpp
+++ b/server/power-channel.cpp
@@ -17,6 +17,7 @@
 #include <config.h>
 
 #include "power-channel.h"
+#include "power-channel-client.h"
 #include "reds.h"
 #include "red-client.h"
 
@@ -27,6 +28,8 @@ void PowerChannel::on_connect(RedClient *client, RedStream 
*stream, int migratio
     if (!red_stream_is_ssl(stream) && !client->during_migrate_at_target()) {
         client->get_main()->push_notify("power channel is insecure");
     }
+
+    power_channel_client_create(this, client, stream, caps);
 }
 
 red::shared_ptr<PowerChannel> power_channel_new(RedsState *reds)
@@ -41,9 +44,21 @@ PowerChannel::PowerChannel(RedsState *reds):
     reds_register_channel(reds, this);
 }
 
+int PowerChannel::set_instance(SpicePowerInstance *new_sin)
+{
+    if (sin) {
+        red_channel_warning(this, "already have interface");
+        return -1;
+    }
+
+    sin = new_sin;
+    return 0;
+}
+
 void power_attach(RedsState *reds, SpicePowerInstance *sin)
 {
     sin->st = new PowerChannel(reds);
+    sin->st->set_instance(sin);
 }
 
 void power_detach(SpicePowerInstance *sin)
diff --git a/server/power-channel.h b/server/power-channel.h
index 252a300f..a6fbf3ab 100644
--- a/server/power-channel.h
+++ b/server/power-channel.h
@@ -25,14 +25,20 @@
 
 #include "push-visibility.h"
 
+class PowerChannelClient;
+
 class PowerChannel final: public RedChannel
 {
+    friend class PowerChannelClient;
 public:
     PowerChannel(RedsState *reds);
 
+    int set_instance(SpicePowerInstance *sin);
 private:
     void on_connect(RedClient *client, RedStream *stream, int migration,
                     RedChannelCapabilities *caps) override;
+
+    SpicePowerInstance *sin;
 };
 
 red::shared_ptr<PowerChannel> power_channel_new(RedsState *reds);
diff --git a/server/spice-power.h b/server/spice-power.h
index 48d42364..27d26399 100644
--- a/server/spice-power.h
+++ b/server/spice-power.h
@@ -37,6 +37,8 @@ typedef struct SpicePowerState SpicePowerState;
 
 struct SpicePowerInterface {
     SpiceBaseInterface base;
+
+    void (*do_reset)(SpicePowerInstance *sin);
 };
 
 struct SpicePowerInstance {
-- 
2.52.0

Reply via email to