[Spice-commits] 17 commits - server/cache-item.tmpl.cpp server/char-device.cpp server/char-device.h server/common-graphics-channel.h server/cursor-channel.cpp server/cursor-channel.h server/dcc.cpp server/dcc.h server/dcc-send.cpp server/display-channel.cpp server/display-channel-private.h server/inputs-channel.cpp server/main-channel-client.cpp server/main-channel-client.h server/red-channel-client.cpp server/red-channel-client.h server/red-channel.cpp server/red-channel.h server/red-pipe-item.cpp server/red-pipe-item.h server/reds.cpp server/red-stream-device.cpp server/red-stream-device.h server/smartcard-channel-client.cpp server/smartcard.cpp server/smartcard.h server/sound.cpp server/spicevmc.cpp server/stream-channel.cpp server/stream-channel.h server/video-stream.cpp server/video-stream.h

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Mon Jul 13 18:49:54 UTC 2020


 server/cache-item.tmpl.cpp          |    4 
 server/char-device.cpp              |  124 +++++++++---------
 server/char-device.h                |    3 
 server/common-graphics-channel.h    |    3 
 server/cursor-channel.cpp           |   59 ++------
 server/cursor-channel.h             |    2 
 server/dcc-send.cpp                 |   68 ++++------
 server/dcc.cpp                      |  174 +++++++++----------------
 server/dcc.h                        |   43 ------
 server/display-channel-private.h    |   69 +++++++++-
 server/display-channel.cpp          |    4 
 server/inputs-channel.cpp           |   39 ++---
 server/main-channel-client.cpp      |  243 +++++++++++++-----------------------
 server/main-channel-client.h        |   15 +-
 server/red-channel-client.cpp       |  167 +++++++++++-------------
 server/red-channel-client.h         |   24 ++-
 server/red-channel.cpp              |   18 --
 server/red-channel.h                |    4 
 server/red-pipe-item.cpp            |   33 +---
 server/red-pipe-item.h              |   77 +++++++----
 server/red-stream-device.cpp        |    4 
 server/red-stream-device.h          |    2 
 server/reds.cpp                     |  123 ++++++------------
 server/smartcard-channel-client.cpp |   19 +-
 server/smartcard.cpp                |   60 +++-----
 server/smartcard.h                  |    2 
 server/sound.cpp                    |   40 ++---
 server/spicevmc.cpp                 |  150 +++++++++-------------
 server/stream-channel.cpp           |   40 ++---
 server/stream-channel.h             |    3 
 server/video-stream.cpp             |   98 +++++---------
 server/video-stream.h               |   33 +---
 32 files changed, 741 insertions(+), 1006 deletions(-)

New commits:
commit 10749220dd4f7784a753a601d7c60b8900922fcb
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Thu Jun 4 19:18:08 2020 +0100

    Encapsulate more pipe item initialisation in constructors
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
    Acked-by: Julien Ropé <jrope at gmail.com>

diff --git a/server/dcc.cpp b/server/dcc.cpp
index 2a2c17db..4920cb87 100644
--- a/server/dcc.cpp
+++ b/server/dcc.cpp
@@ -473,7 +473,7 @@ static void dcc_stop(DisplayChannelClient *dcc)
 
 void dcc_video_stream_agent_clip(DisplayChannelClient* dcc, VideoStreamAgent *agent)
 {
-    auto item = video_stream_clip_item_new(agent);
+    auto item = red::make_shared<VideoStreamClipItem>(agent);
 
     dcc->pipe_add(std::move(item));
 }
diff --git a/server/display-channel-private.h b/server/display-channel-private.h
index 709f8452..b612148c 100644
--- a/server/display-channel-private.h
+++ b/server/display-channel-private.h
@@ -226,8 +226,9 @@ struct RedDrawablePipeItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_DRAW> {
 /* This item is used to send a full quality image (lossless) of the area where the stream was.
  * This to avoid the artifacts due to the lossy compression. */
 struct RedUpgradeItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_UPGRADE> {
+    RedUpgradeItem(Drawable *drawable);
     ~RedUpgradeItem();
-    Drawable *drawable;
+    Drawable *const drawable;
     red::glib_unique_ptr<SpiceClipRects> rects;
 };
 
diff --git a/server/spicevmc.cpp b/server/spicevmc.cpp
index 074abc5a..fb7a2517 100644
--- a/server/spicevmc.cpp
+++ b/server/spicevmc.cpp
@@ -186,6 +186,8 @@ static red::shared_ptr<RedVmcChannel> red_vmc_channel_new(RedsState *reds, uint8
 }
 
 struct RedPortInitPipeItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_PORT_INIT> {
+    RedPortInitPipeItem(const char *name, uint8_t opened);
+
     red::glib_unique_ptr<char> name;
     uint8_t opened;
 };
@@ -273,14 +275,18 @@ RedCharDeviceSpiceVmc::read_one_msg_from_device()
     return RedPipeItemPtr();
 }
 
+RedPortInitPipeItem::RedPortInitPipeItem(const char *init_name, uint8_t init_opened):
+    name(g_strdup(init_name)),
+    opened(init_opened)
+{
+}
+
 static void spicevmc_port_send_init(VmcChannelClient *rcc)
 {
     RedVmcChannel *channel = rcc->get_channel();
     SpiceCharDeviceInstance *sin = channel->chardev_sin;
-    auto item = red::make_shared<RedPortInitPipeItem>();
+    auto item = red::make_shared<RedPortInitPipeItem>(sin->portname, channel->port_opened);
 
-    item->name.reset(g_strdup(sin->portname));
-    item->opened = channel->port_opened;
     rcc->pipe_add_push(std::move(item));
 }
 
diff --git a/server/video-stream.cpp b/server/video-stream.cpp
index 571d5141..67432da4 100644
--- a/server/video-stream.cpp
+++ b/server/video-stream.cpp
@@ -70,24 +70,21 @@ StreamCreateDestroyItem::~StreamCreateDestroyItem()
     video_stream_agent_unref(display, agent);
 }
 
-static RedPipeItemPtr
-video_stream_create_destroy_item_new(VideoStreamAgent *agent, int type)
+StreamCreateDestroyItem::StreamCreateDestroyItem(VideoStreamAgent *init_agent, int init_type):
+    RedPipeItem(init_type),
+    agent(init_agent)
 {
-    auto item = red::make_shared<StreamCreateDestroyItem>(type);
-
     agent->stream->refs++;
-    item->agent = agent;
-    return item;
 }
 
 static RedPipeItemPtr video_stream_create_item_new(VideoStreamAgent *agent)
 {
-    return video_stream_create_destroy_item_new(agent, RED_PIPE_ITEM_TYPE_STREAM_CREATE);
+    return red::make_shared<StreamCreateDestroyItem>(agent, RED_PIPE_ITEM_TYPE_STREAM_CREATE);
 }
 
 static RedPipeItemPtr video_stream_destroy_item_new(VideoStreamAgent *agent)
 {
-    return video_stream_create_destroy_item_new(agent, RED_PIPE_ITEM_TYPE_STREAM_DESTROY);
+    return red::make_shared<StreamCreateDestroyItem>(agent, RED_PIPE_ITEM_TYPE_STREAM_DESTROY);
 }
 
 
@@ -166,22 +163,18 @@ VideoStreamClipItem::~VideoStreamClipItem()
     video_stream_agent_unref(display, stream_agent);
 }
 
-red::shared_ptr<VideoStreamClipItem> video_stream_clip_item_new(VideoStreamAgent *agent)
+VideoStreamClipItem::VideoStreamClipItem(VideoStreamAgent *agent):
+    RedPipeItem(RED_PIPE_ITEM_TYPE_STREAM_CLIP),
+    stream_agent(agent),
+    clip_type(SPICE_CLIP_TYPE_RECTS)
 {
-    auto item = red::make_shared<VideoStreamClipItem>(RED_PIPE_ITEM_TYPE_STREAM_CLIP);
-
-    item->stream_agent = agent;
     agent->stream->refs++;
 
-    item->clip_type = SPICE_CLIP_TYPE_RECTS;
-
     int n_rects = pixman_region32_n_rects(&agent->clip);
-    item->rects.reset((SpiceClipRects*) g_malloc(sizeof(SpiceClipRects) +
-                                                 n_rects * sizeof(SpiceRect)));
-    item->rects->num_rects = n_rects;
-    region_ret_rects(&agent->clip, item->rects->rects, n_rects);
-
-    return item;
+    rects.reset((SpiceClipRects*) g_malloc(sizeof(SpiceClipRects) +
+                                           n_rects * sizeof(SpiceRect)));
+    rects->num_rects = n_rects;
+    region_ret_rects(&agent->clip, rects->rects, n_rects);
 }
 
 static int is_stream_start(Drawable *drawable)
@@ -804,6 +797,12 @@ RedUpgradeItem::~RedUpgradeItem()
     drawable_unref(drawable);
 }
 
+RedUpgradeItem::RedUpgradeItem(Drawable *init_drawable):
+    drawable(init_drawable)
+{
+    drawable->refs++;
+}
+
 /*
  * after dcc_detach_stream_gracefully is called for all the display channel clients,
  * video_stream_detach_drawable should be called. See comment (1).
@@ -839,9 +838,7 @@ static void dcc_detach_stream_gracefully(DisplayChannelClient *dcc,
         }
         spice_debug("stream %d: upgrade by drawable. box ==>", stream_id);
         rect_debug(&stream->current->red_drawable->bbox);
-        auto upgrade_item = red::make_shared<RedUpgradeItem>();
-        upgrade_item->drawable = stream->current;
-        upgrade_item->drawable->refs++;
+        auto upgrade_item = red::make_shared<RedUpgradeItem>(stream->current);
         n_rects = pixman_region32_n_rects(&upgrade_item->drawable->tree_item.base.rgn);
         upgrade_item->rects.reset((SpiceClipRects*) g_malloc(sizeof(SpiceClipRects) +
                                                              n_rects * sizeof(SpiceRect)));
diff --git a/server/video-stream.h b/server/video-stream.h
index bd5fd7d0..f6855ae6 100644
--- a/server/video-stream.h
+++ b/server/video-stream.h
@@ -82,17 +82,16 @@ typedef struct VideoStreamAgent {
 } VideoStreamAgent;
 
 struct VideoStreamClipItem: public RedPipeItem {
-    using RedPipeItem::RedPipeItem;
+    VideoStreamClipItem(VideoStreamAgent *agent);
     ~VideoStreamClipItem();
+
     VideoStreamAgent *stream_agent;
     int clip_type;
     red::glib_unique_ptr<SpiceClipRects> rects;
 };
 
-red::shared_ptr<VideoStreamClipItem> video_stream_clip_item_new(VideoStreamAgent *agent);
-
 struct StreamCreateDestroyItem: public RedPipeItem {
-    using RedPipeItem::RedPipeItem;
+    StreamCreateDestroyItem(VideoStreamAgent *agent, int type);
     ~StreamCreateDestroyItem();
     VideoStreamAgent *agent;
 };
commit 20408491fa44c0e35c8b68cf8bd2e5b12242690c
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Sun Jun 7 11:02:02 2020 +0100

    video-stream: Move some structure definition to use more RedPipeItemNum
    
    Users of structures needs enumeration definitions too.
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
    Acked-by: Julien Ropé <jrope at gmail.com>

diff --git a/server/display-channel-private.h b/server/display-channel-private.h
index 841c515d..709f8452 100644
--- a/server/display-channel-private.h
+++ b/server/display-channel-private.h
@@ -223,6 +223,21 @@ struct RedDrawablePipeItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_DRAW> {
     DisplayChannelClient *const dcc;
 };
 
+/* This item is used to send a full quality image (lossless) of the area where the stream was.
+ * This to avoid the artifacts due to the lossy compression. */
+struct RedUpgradeItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_UPGRADE> {
+    ~RedUpgradeItem();
+    Drawable *drawable;
+    red::glib_unique_ptr<SpiceClipRects> rects;
+};
+
+struct RedStreamActivateReportItem:
+    public RedPipeItemNum<RED_PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT>
+{
+    uint32_t stream_id;
+    uint32_t report_id;
+};
+
 static inline int is_equal_path(SpicePath *path1, SpicePath *path2)
 {
     SpicePathSeg *seg1, *seg2;
diff --git a/server/video-stream.cpp b/server/video-stream.cpp
index 24a2b920..571d5141 100644
--- a/server/video-stream.cpp
+++ b/server/video-stream.cpp
@@ -773,8 +773,7 @@ void dcc_create_stream(DisplayChannelClient *dcc, VideoStream *stream)
     dcc->pipe_add(video_stream_create_item_new(agent));
 
     if (dcc->test_remote_cap(SPICE_DISPLAY_CAP_STREAM_REPORT)) {
-        auto report_pipe_item =
-            red::make_shared<RedStreamActivateReportItem>(RED_PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT);
+        auto report_pipe_item = red::make_shared<RedStreamActivateReportItem>();
 
         agent->report_id = rand();
         report_pipe_item->stream_id = stream_id;
@@ -840,7 +839,7 @@ static void dcc_detach_stream_gracefully(DisplayChannelClient *dcc,
         }
         spice_debug("stream %d: upgrade by drawable. box ==>", stream_id);
         rect_debug(&stream->current->red_drawable->bbox);
-        auto upgrade_item = red::make_shared<RedUpgradeItem>(RED_PIPE_ITEM_TYPE_UPGRADE);
+        auto upgrade_item = red::make_shared<RedUpgradeItem>();
         upgrade_item->drawable = stream->current;
         upgrade_item->drawable->refs++;
         n_rects = pixman_region32_n_rects(&upgrade_item->drawable->tree_item.base.rgn);
diff --git a/server/video-stream.h b/server/video-stream.h
index 3006962e..bd5fd7d0 100644
--- a/server/video-stream.h
+++ b/server/video-stream.h
@@ -47,21 +47,6 @@ SPICE_BEGIN_DECLS
 
 typedef struct VideoStream VideoStream;
 
-/* This item is used to send a full quality image (lossless) of the area where the stream was.
- * This to avoid the artifacts due to the lossy compression. */
-struct RedUpgradeItem: public RedPipeItem {
-    using RedPipeItem::RedPipeItem;
-    ~RedUpgradeItem();
-    Drawable *drawable;
-    red::glib_unique_ptr<SpiceClipRects> rects;
-};
-
-struct RedStreamActivateReportItem: public RedPipeItem {
-    using RedPipeItem::RedPipeItem;
-    uint32_t stream_id;
-    uint32_t report_id;
-};
-
 #ifdef STREAM_STATS
 typedef struct StreamStats {
     uint64_t num_drops_pipe;
commit 228db683bad0717fc4286abc784d1e465917daf8
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Sun Jun 7 10:53:29 2020 +0100

    dcc: Move some structure definition to use more RedPipeItemNum
    
    Users of structures needs enumeration definitions too.
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
    Acked-by: Julien Ropé <jrope at gmail.com>

diff --git a/server/dcc.cpp b/server/dcc.cpp
index 1dcf1519..2a2c17db 100644
--- a/server/dcc.cpp
+++ b/server/dcc.cpp
@@ -74,8 +74,7 @@ RedSurfaceCreateItem::RedSurfaceCreateItem(uint32_t surface_id,
                                            uint32_t width,
                                            uint32_t height,
                                            uint32_t format,
-                                           uint32_t flags):
-    RedPipeItem(RED_PIPE_ITEM_TYPE_CREATE_SURFACE)
+                                           uint32_t flags)
 {
     surface_create.surface_id = surface_id;
     surface_create.width = width;
@@ -188,11 +187,6 @@ void dcc_create_surface(DisplayChannelClient *dcc, int surface_id)
     dcc->pipe_add(std::move(create));
 }
 
-RedImageItem::RedImageItem():
-    RedPipeItem(RED_PIPE_ITEM_TYPE_IMAGE)
-{
-}
-
 // adding the pipe item after pos. If pos == NULL, adding to head.
 void
 dcc_add_surface_area_image(DisplayChannelClient *dcc, int surface_id,
@@ -303,7 +297,6 @@ static void add_drawable_surface_images(DisplayChannelClient *dcc, Drawable *dra
 }
 
 RedDrawablePipeItem::RedDrawablePipeItem(DisplayChannelClient *init_dcc, Drawable *init_drawable):
-    RedPipeItem(RED_PIPE_ITEM_TYPE_DRAW),
     drawable(init_drawable),
     dcc(init_dcc)
 {
@@ -529,7 +522,7 @@ RedPipeItemPtr dcc_gl_scanout_item_new(RedChannelClient *rcc, void *data, int nu
         return RedPipeItemPtr();
     }
 
-    return red::make_shared<RedGlScanoutUnixItem>(RED_PIPE_ITEM_TYPE_GL_SCANOUT);
+    return red::make_shared<RedGlScanoutUnixItem>();
 }
 
 XXX_CAST(RedChannelClient, DisplayChannelClient, DISPLAY_CHANNEL_CLIENT);
@@ -548,7 +541,7 @@ RedPipeItemPtr dcc_gl_draw_item_new(RedChannelClient *rcc, void *data, int num)
     }
 
     dcc->priv->gl_draw_ongoing = TRUE;
-    auto item = red::make_shared<RedGlDrawItem>(RED_PIPE_ITEM_TYPE_GL_DRAW);
+    auto item = red::make_shared<RedGlDrawItem>();
     item->draw = *draw;
 
     return item;
diff --git a/server/dcc.h b/server/dcc.h
index a35849d5..8e463239 100644
--- a/server/dcc.h
+++ b/server/dcc.h
@@ -96,45 +96,6 @@ typedef struct FreeList {
 
 #define DCC_TO_DC(dcc) ((DisplayChannel*) dcc->get_channel())
 
-struct RedSurfaceCreateItem: public RedPipeItem {
-    RedSurfaceCreateItem(uint32_t surface_id,
-                         uint32_t width,
-                         uint32_t height,
-                         uint32_t format,
-                         uint32_t flags);
-    SpiceMsgSurfaceCreate surface_create;
-};
-
-struct RedGlScanoutUnixItem: public RedPipeItem {
-    using RedPipeItem::RedPipeItem;
-};
-
-struct RedGlDrawItem: public RedPipeItem {
-    using RedPipeItem::RedPipeItem;
-    SpiceMsgDisplayGlDraw draw;
-};
-
-struct RedImageItem final: public RedPipeItem {
-    RedImageItem();
-    SpicePoint pos;
-    int width;
-    int height;
-    int stride;
-    int top_down;
-    int surface_id;
-    int image_format;
-    uint32_t image_flags;
-    int can_lossy;
-    uint8_t data[0];
-};
-
-struct RedDrawablePipeItem: public RedPipeItem {
-    RedDrawablePipeItem(DisplayChannelClient *dcc, Drawable *drawable);
-    ~RedDrawablePipeItem();
-    Drawable *const drawable;
-    DisplayChannelClient *const dcc;
-};
-
 DisplayChannelClient*      dcc_new                                   (DisplayChannel *display,
                                                                       RedClient *client,
                                                                       RedStream *stream,
diff --git a/server/display-channel-private.h b/server/display-channel-private.h
index cf7d2dba..841c515d 100644
--- a/server/display-channel-private.h
+++ b/server/display-channel-private.h
@@ -187,6 +187,42 @@ struct RedSurfaceDestroyItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_DESTROY_S
     SpiceMsgSurfaceDestroy surface_destroy;
 };
 
+struct RedSurfaceCreateItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_CREATE_SURFACE> {
+    RedSurfaceCreateItem(uint32_t surface_id,
+                         uint32_t width,
+                         uint32_t height,
+                         uint32_t format,
+                         uint32_t flags);
+    SpiceMsgSurfaceCreate surface_create;
+};
+
+struct RedGlScanoutUnixItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_GL_SCANOUT> {
+};
+
+struct RedGlDrawItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_GL_DRAW> {
+    SpiceMsgDisplayGlDraw draw;
+};
+
+struct RedImageItem final: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_IMAGE> {
+    SpicePoint pos;
+    int width;
+    int height;
+    int stride;
+    int top_down;
+    int surface_id;
+    int image_format;
+    uint32_t image_flags;
+    int can_lossy;
+    uint8_t data[0];
+};
+
+struct RedDrawablePipeItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_DRAW> {
+    RedDrawablePipeItem(DisplayChannelClient *dcc, Drawable *drawable);
+    ~RedDrawablePipeItem();
+    Drawable *const drawable;
+    DisplayChannelClient *const dcc;
+};
+
 static inline int is_equal_path(SpicePath *path1, SpicePath *path2)
 {
     SpicePathSeg *seg1, *seg2;
commit f4bc555b6287152a3480455618396cf339cefdfc
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Mon Jun 8 11:45:49 2020 +0100

    dcc: Remove red_drawable_pipe_item_new, use constructor
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
    Acked-by: Julien Ropé <jrope at gmail.com>

diff --git a/server/dcc.cpp b/server/dcc.cpp
index 126598a0..1dcf1519 100644
--- a/server/dcc.cpp
+++ b/server/dcc.cpp
@@ -302,9 +302,13 @@ static void add_drawable_surface_images(DisplayChannelClient *dcc, Drawable *dra
     dcc_push_surface_image(dcc, drawable->surface_id);
 }
 
-RedDrawablePipeItem::RedDrawablePipeItem():
-    RedPipeItem(RED_PIPE_ITEM_TYPE_DRAW)
+RedDrawablePipeItem::RedDrawablePipeItem(DisplayChannelClient *init_dcc, Drawable *init_drawable):
+    RedPipeItem(RED_PIPE_ITEM_TYPE_DRAW),
+    drawable(init_drawable),
+    dcc(init_dcc)
 {
+    drawable->pipes = g_list_prepend(drawable->pipes, this);
+    drawable->refs++;
 }
 
 RedDrawablePipeItem::~RedDrawablePipeItem()
@@ -313,20 +317,9 @@ RedDrawablePipeItem::~RedDrawablePipeItem()
     drawable_unref(drawable);
 }
 
-static red::shared_ptr<RedDrawablePipeItem>
-red_drawable_pipe_item_new(DisplayChannelClient *dcc, Drawable *drawable)
-{
-    auto dpi = red::make_shared<RedDrawablePipeItem>();
-    dpi->drawable = drawable;
-    dpi->dcc = dcc;
-    drawable->pipes = g_list_prepend(drawable->pipes, dpi.get());
-    drawable->refs++;
-    return dpi;
-}
-
 void dcc_prepend_drawable(DisplayChannelClient *dcc, Drawable *drawable)
 {
-    auto dpi = red_drawable_pipe_item_new(dcc, drawable);
+    auto dpi = red::make_shared<RedDrawablePipeItem>(dcc, drawable);
 
     add_drawable_surface_images(dcc, drawable);
     dcc->pipe_add(std::move(dpi));
@@ -334,7 +327,7 @@ void dcc_prepend_drawable(DisplayChannelClient *dcc, Drawable *drawable)
 
 void dcc_append_drawable(DisplayChannelClient *dcc, Drawable *drawable)
 {
-    auto dpi = red_drawable_pipe_item_new(dcc, drawable);
+    auto dpi = red::make_shared<RedDrawablePipeItem>(dcc, drawable);
 
     add_drawable_surface_images(dcc, drawable);
     dcc->pipe_add_tail(std::move(dpi));
@@ -342,7 +335,7 @@ void dcc_append_drawable(DisplayChannelClient *dcc, Drawable *drawable)
 
 void dcc_add_drawable_after(DisplayChannelClient *dcc, Drawable *drawable, RedPipeItem *pos)
 {
-    auto dpi = red_drawable_pipe_item_new(dcc, drawable);
+    auto dpi = red::make_shared<RedDrawablePipeItem>(dcc, drawable);
 
     add_drawable_surface_images(dcc, drawable);
     dcc->pipe_add_after(std::move(dpi), pos);
diff --git a/server/dcc.h b/server/dcc.h
index 696f66af..a35849d5 100644
--- a/server/dcc.h
+++ b/server/dcc.h
@@ -129,10 +129,10 @@ struct RedImageItem final: public RedPipeItem {
 };
 
 struct RedDrawablePipeItem: public RedPipeItem {
-    RedDrawablePipeItem();
+    RedDrawablePipeItem(DisplayChannelClient *dcc, Drawable *drawable);
     ~RedDrawablePipeItem();
-    Drawable *drawable;
-    DisplayChannelClient *dcc;
+    Drawable *const drawable;
+    DisplayChannelClient *const dcc;
 };
 
 DisplayChannelClient*      dcc_new                                   (DisplayChannel *display,
commit fe9ad0d5ba4e5580720bed541f68195a48c6a6e5
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Sat Jun 6 12:44:29 2020 +0100

    red-pipe-item: Remove red_pipe_item_(un)ref
    
    Most code uses now red::shared_ptr
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
    Acked-by: Julien Ropé <jrope at gmail.com>

diff --git a/server/red-pipe-item.cpp b/server/red-pipe-item.cpp
index a871bfef..143f2e27 100644
--- a/server/red-pipe-item.cpp
+++ b/server/red-pipe-item.cpp
@@ -25,29 +25,15 @@ RedPipeItem::RedPipeItem(int init_type):
 {
 }
 
-RedPipeItem *red_pipe_item_ref(RedPipeItem *item)
-{
-    // this call should be replaced by shared_ptr instead
-    shared_ptr_add_ref(item);
-
-    return item;
-}
-
-void red_pipe_item_unref(RedPipeItem *item)
-{
-    // this call should be replaced by shared_ptr instead
-    shared_ptr_unref(item);
-}
-
 static void marshaller_unref_pipe_item(uint8_t *, void *opaque)
 {
     RedPipeItem *item = (RedPipeItem*) opaque;
-    red_pipe_item_unref(item);
+    shared_ptr_unref(item);
 }
 
 void RedPipeItem::add_to_marshaller(SpiceMarshaller *m, uint8_t *data, size_t size)
 {
-    red_pipe_item_ref(this);
+    shared_ptr_add_ref(this);
     spice_marshaller_add_by_ref_full(m, data, size,
                                      marshaller_unref_pipe_item, this);
 }
diff --git a/server/red-pipe-item.h b/server/red-pipe-item.h
index e77f241b..10e5a12c 100644
--- a/server/red-pipe-item.h
+++ b/server/red-pipe-item.h
@@ -66,9 +66,6 @@ struct RedPipeItem: public red::shared_ptr_counted
 
 typedef red::shared_ptr<RedPipeItem> RedPipeItemPtr;
 
-RedPipeItem *red_pipe_item_ref(RedPipeItem *item);
-void red_pipe_item_unref(RedPipeItem *item);
-
 /* Most of the time the type is constant and we just add fields,
  * make it easier to initialize just with declaration
  */
commit 8a0d9369bcc83f7519072a3718921ae624060e6d
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Sat Jun 6 12:43:48 2020 +0100

    char-device: Use list and shared pointers for RedCharDeviceClient queue
    
    Automatically handle ownership avoiding using red_pipe_item_(un)ref.
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
    Acked-by: Julien Ropé <jrope at gmail.com>

diff --git a/server/char-device.cpp b/server/char-device.cpp
index 82c04aad..fff650a4 100644
--- a/server/char-device.cpp
+++ b/server/char-device.cpp
@@ -22,9 +22,11 @@
 
 #include <config.h>
 #include <inttypes.h>
+#include <list>
 
 #include "char-device.h"
 #include "reds.h"
+#include "safe-list.hpp"
 
 #define CHAR_DEVICE_WRITE_TO_TIMEOUT 100
 #define RED_CHAR_DEVICE_WAIT_TOKENS_TIMEOUT 30000
@@ -46,6 +48,7 @@ struct RedCharDeviceWriteBufferPrivate {
 
 struct RedCharDeviceClient {
     SPICE_CXX_GLIB_ALLOCATOR
+    typedef std::list<RedPipeItemPtr, red::Mallocator<RedPipeItemPtr>> Queue;
 
     RedCharDeviceClient(RedCharDevice *dev,
                         RedsState *reds,
@@ -64,7 +67,7 @@ struct RedCharDeviceClient {
     uint64_t num_send_tokens; /* send to client */
     SpiceTimer *wait_for_tokens_timer;
     int wait_for_tokens_started;
-    GQueue *send_queue;
+    Queue send_queue;
     const uint32_t max_send_queue_size;
 };
 
@@ -124,7 +127,7 @@ static void red_char_device_client_free(RedCharDevice *dev,
     red_timer_remove(dev_client->wait_for_tokens_timer);
     dev_client->wait_for_tokens_timer = NULL;
 
-    g_queue_free_full(dev_client->send_queue, (GDestroyNotify)red_pipe_item_unref);
+    dev_client->send_queue.clear();
 
     /* remove write buffers that are associated with the client */
     spice_debug("write_queue_is_empty %d", g_queue_is_empty(&dev->priv->write_queue) && !dev->priv->cur_write_buf);
@@ -205,13 +208,12 @@ static uint64_t red_char_device_max_send_tokens(RedCharDevice *dev)
 static void red_char_device_add_msg_to_client_queue(RedCharDeviceClient *dev_client,
                                                     RedPipeItem *msg)
 {
-    if (g_queue_get_length(dev_client->send_queue) >= dev_client->max_send_queue_size) {
+    if (dev_client->send_queue.size() >= dev_client->max_send_queue_size) {
         red_char_device_handle_client_overflow(dev_client);
         return;
     }
 
-    red_pipe_item_ref(msg);
-    g_queue_push_head(dev_client->send_queue, msg);
+    dev_client->send_queue.push_front(RedPipeItemPtr(msg));
     if (!dev_client->wait_for_tokens_started) {
         red_timer_start(dev_client->wait_for_tokens_timer,
                         RED_CHAR_DEVICE_WAIT_TOKENS_TIMEOUT);
@@ -227,7 +229,7 @@ static void red_char_device_send_msg_to_clients(RedCharDevice *dev,
     GLIST_FOREACH(dev->priv->clients, RedCharDeviceClient, dev_client) {
         if (red_char_device_can_send_to_client(dev_client)) {
             dev_client->num_send_tokens--;
-            spice_assert(g_queue_is_empty(dev_client->send_queue));
+            spice_assert(dev_client->send_queue.empty());
             dev->send_msg_to_client(msg, dev_client->client);
 
             /* don't refer to dev_client anymore, it may have been released */
@@ -285,13 +287,13 @@ static bool red_char_device_read_from_device(RedCharDevice *dev)
 
 static void red_char_device_client_send_queue_push(RedCharDeviceClient *dev_client)
 {
-    while (!g_queue_is_empty(dev_client->send_queue) &&
+    while (!dev_client->send_queue.empty() &&
            red_char_device_can_send_to_client(dev_client)) {
-        RedPipeItem *msg = (RedPipeItem *) g_queue_pop_tail(dev_client->send_queue);
-        g_assert(msg != NULL);
+        RedPipeItemPtr msg = std::move(dev_client->send_queue.back());
+        dev_client->send_queue.pop_back();
+        g_assert(msg);
         dev_client->num_send_tokens--;
-        dev_client->dev->send_msg_to_client(msg, dev_client->client);
-        red_pipe_item_unref(msg);
+        dev_client->dev->send_msg_to_client(msg.get(), dev_client->client);
     }
 }
 
@@ -315,7 +317,7 @@ red_char_device_send_to_client_tokens_absorb(RedCharDevice *dev,
     }
     dev_client->num_send_tokens += tokens;
 
-    if (g_queue_get_length(dev_client->send_queue)) {
+    if (dev_client->send_queue.size()) {
         spice_assert(dev_client->num_send_tokens == tokens);
         red_char_device_client_send_queue_push(dev_client);
     }
@@ -324,7 +326,7 @@ red_char_device_send_to_client_tokens_absorb(RedCharDevice *dev,
         red_timer_cancel(dev_client->wait_for_tokens_timer);
         dev_client->wait_for_tokens_started = FALSE;
         red_char_device_read_from_device(dev_client->dev);
-    } else if (!g_queue_is_empty(dev_client->send_queue)) {
+    } else if (!dev_client->send_queue.empty()) {
         red_timer_start(dev_client->wait_for_tokens_timer,
                         RED_CHAR_DEVICE_WAIT_TOKENS_TIMEOUT);
         dev_client->wait_for_tokens_started = TRUE;
@@ -609,7 +611,6 @@ RedCharDeviceClient::RedCharDeviceClient(RedCharDevice *init_dev,
     dev(init_dev),
     client(init_client),
     do_flow_control(init_do_flow_control),
-    send_queue(g_queue_new()),
     max_send_queue_size(init_max_send_queue_size)
 {
     if (do_flow_control) {
@@ -720,10 +721,9 @@ void RedCharDevice::reset()
     write_buffer_release(&priv->cur_write_buf);
 
     GLIST_FOREACH(priv->clients, RedCharDeviceClient, dev_client) {
-        spice_debug("send_queue_empty %d", g_queue_is_empty(dev_client->send_queue));
-        dev_client->num_send_tokens += g_queue_get_length(dev_client->send_queue);
-        g_queue_free_full(dev_client->send_queue, (GDestroyNotify)red_pipe_item_unref);
-        dev_client->send_queue = g_queue_new();
+        spice_debug("send_queue_empty %d", dev_client->send_queue.empty());
+        dev_client->num_send_tokens += dev_client->send_queue.size();
+        dev_client->send_queue.clear();
 
         /* If device is reset, we must reset the tokens counters as well as we
          * don't hold any data from client and upon agent's reconnection we send
@@ -777,7 +777,7 @@ void RedCharDevice::migrate_data_marshall(SpiceMarshaller *m)
     /* FIXME: if there were more than one client before the marshalling,
      * it is possible that the send_queue length > 0, and the send data
      * should be migrated as well */
-    spice_assert(g_queue_is_empty(dev_client->send_queue));
+    spice_assert(dev_client->send_queue.empty());
     spice_marshaller_add_uint32(m, SPICE_MIGRATE_DATA_CHAR_DEVICE_VERSION);
     spice_marshaller_add_uint8(m, 1); /* connected */
     spice_marshaller_add_uint32(m, dev_client->num_client_tokens);
commit 76fe97a1574b9ce126d5f5fb2806b0c535a8e1dd
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Sat Jun 6 12:10:07 2020 +0100

    char-device: Make RedCharDeviceClient a proper class
    
    Provide constructor and destructor, use new/delete.
    This allows additional fields to be properly initialized if needed.
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
    Acked-by: Julien Ropé <jrope at gmail.com>

diff --git a/server/char-device.cpp b/server/char-device.cpp
index 9423820b..82c04aad 100644
--- a/server/char-device.cpp
+++ b/server/char-device.cpp
@@ -44,18 +44,28 @@ struct RedCharDeviceWriteBufferPrivate {
     uint32_t refs;
 };
 
-typedef struct RedCharDeviceClient RedCharDeviceClient;
 struct RedCharDeviceClient {
-    RedCharDevice *dev;
-    RedCharDeviceClientOpaque *client;
-    int do_flow_control;
+    SPICE_CXX_GLIB_ALLOCATOR
+
+    RedCharDeviceClient(RedCharDevice *dev,
+                        RedsState *reds,
+                        RedCharDeviceClientOpaque *client,
+                        bool do_flow_control,
+                        uint32_t max_send_queue_size,
+                        uint32_t num_client_tokens,
+                        uint32_t num_send_tokens);
+    ~RedCharDeviceClient();
+
+    RedCharDevice *const dev;
+    RedCharDeviceClientOpaque *const client;
+    const bool do_flow_control;
     uint64_t num_client_tokens;
     uint64_t num_client_tokens_free; /* client messages that were consumed by the device */
     uint64_t num_send_tokens; /* send to client */
     SpiceTimer *wait_for_tokens_timer;
     int wait_for_tokens_started;
     GQueue *send_queue;
-    uint32_t max_send_queue_size;
+    const uint32_t max_send_queue_size;
 };
 
 struct RedCharDevicePrivate {
@@ -138,7 +148,7 @@ static void red_char_device_client_free(RedCharDevice *dev,
     }
 
     dev->priv->clients = g_list_remove(dev->priv->clients, dev_client);
-    g_free(dev_client);
+    delete dev_client;
 }
 
 static void red_char_device_handle_client_overflow(RedCharDeviceClient *dev_client)
@@ -589,36 +599,35 @@ void RedCharDevice::reset_dev_instance(SpiceCharDeviceInstance *sin)
     }
 }
 
-static RedCharDeviceClient *
-red_char_device_client_new(RedsState *reds,
-                           RedCharDeviceClientOpaque *client,
-                           int do_flow_control,
-                           uint32_t max_send_queue_size,
-                           uint32_t num_client_tokens,
-                           uint32_t num_send_tokens)
+RedCharDeviceClient::RedCharDeviceClient(RedCharDevice *init_dev,
+                                         RedsState *reds,
+                                         RedCharDeviceClientOpaque *init_client,
+                                         bool init_do_flow_control,
+                                         uint32_t init_max_send_queue_size,
+                                         uint32_t init_num_client_tokens,
+                                         uint32_t init_num_send_tokens):
+    dev(init_dev),
+    client(init_client),
+    do_flow_control(init_do_flow_control),
+    send_queue(g_queue_new()),
+    max_send_queue_size(init_max_send_queue_size)
 {
-    RedCharDeviceClient *dev_client;
-
-    dev_client = g_new0(RedCharDeviceClient, 1);
-    dev_client->client = client;
-    dev_client->send_queue = g_queue_new();
-    dev_client->max_send_queue_size = max_send_queue_size;
-    dev_client->do_flow_control = do_flow_control;
     if (do_flow_control) {
-        dev_client->wait_for_tokens_timer =
-            reds_core_timer_add(reds, device_client_wait_for_tokens_timeout,
-                                dev_client);
-        if (!dev_client->wait_for_tokens_timer) {
+        wait_for_tokens_timer =
+            reds_core_timer_add(reds, device_client_wait_for_tokens_timeout, this);
+        if (!wait_for_tokens_timer) {
             spice_error("failed to create wait for tokens timer");
         }
-        dev_client->num_client_tokens = num_client_tokens;
-        dev_client->num_send_tokens = num_send_tokens;
+        num_client_tokens = init_num_client_tokens;
+        num_send_tokens = init_num_send_tokens;
     } else {
-        dev_client->num_client_tokens = ~0;
-        dev_client->num_send_tokens = ~0;
+        num_client_tokens = ~0;
+        num_send_tokens = ~0;
     }
+}
 
-    return dev_client;
+RedCharDeviceClient::~RedCharDeviceClient()
+{
 }
 
 bool RedCharDevice::client_add(RedCharDeviceClientOpaque *client,
@@ -642,13 +651,13 @@ bool RedCharDevice::client_add(RedCharDeviceClientOpaque *client,
     priv->wait_for_migrate_data = wait_for_migrate_data;
 
     spice_debug("char device %p, client %p", this, client);
-    dev_client = red_char_device_client_new(priv->reds,
-                                            client,
-                                            do_flow_control,
-                                            max_send_queue_size,
-                                            num_client_tokens,
-                                            num_send_tokens);
-    dev_client->dev = this;
+    dev_client = new RedCharDeviceClient(this,
+                                         priv->reds,
+                                         client,
+                                         !!do_flow_control,
+                                         max_send_queue_size,
+                                         num_client_tokens,
+                                         num_send_tokens);
     priv->clients = g_list_prepend(priv->clients, dev_client);
     /* Now that we have a client, forward any pending device data */
     wakeup();
commit 39efd79d533691fdcd4a3699d36b6da79f796960
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Mon Jun 8 12:42:20 2020 +0100

    spicevmc: Simplify code to compress messages
    
    Remove some conditional compilation.
    Make try_compress_lz4 return success or failure and change the
    messages making easier to read result from try_compress_lz4.
    Remove "n" parameter from try_compress_lz4, use message size
    instead.
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
    Acked-by: Julien Ropé <jrope at gmail.com>

diff --git a/server/spicevmc.cpp b/server/spicevmc.cpp
index c128bc3b..074abc5a 100644
--- a/server/spicevmc.cpp
+++ b/server/spicevmc.cpp
@@ -54,10 +54,10 @@ class VmcChannelClient;
 
 struct RedVmcPipeItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_SPICEVMC_DATA> {
     SpiceDataCompressionType type;
-    uint32_t uncompressed_data_size;
+    uint32_t uncompressed_data_size = 0;
     /* writes which don't fit this will get split, this is not a problem */
     uint8_t buf[BUF_SIZE];
-    uint32_t buf_used;
+    uint32_t buf_used = 0;
 };
 
 struct RedCharDeviceSpiceVmc: public RedCharDevice
@@ -194,32 +194,31 @@ struct RedPortEventPipeItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_PORT_EVENT
     uint8_t event;
 };
 
-/* n is the data size (uncompressed)
- * msg_item -- the current pipe item with the uncompressed data
+/* msg_item -- the current pipe item with the uncompressed data
  * This function returns:
- *  - NULL upon failure.
- *  - a new pipe item with the compressed data in it upon success
+ *  - false upon failure.
+ *  - true if compression succeeded
  */
-#ifdef USE_LZ4
-static red::shared_ptr<RedVmcPipeItem>
-try_compress_lz4(RedVmcChannel *channel, int n, RedVmcPipeItem *msg_item)
+static bool
+try_compress_lz4(RedVmcChannel *channel, red::shared_ptr<RedVmcPipeItem>& msg_item)
 {
-    red::shared_ptr<RedVmcPipeItem> msg_item_compressed;
+#ifdef USE_LZ4
     int compressed_data_count;
+    auto n = msg_item->buf_used;
 
     if (red_stream_get_family(channel->rcc->get_stream()) == AF_UNIX) {
         /* AF_LOCAL - data will not be compressed */
-        return msg_item_compressed;
+        return false;
     }
     if (n <= COMPRESS_THRESHOLD) {
         /* n <= threshold - data will not be compressed */
-        return msg_item_compressed;
+        return false;
     }
     if (!channel->rcc->test_remote_cap(SPICE_SPICEVMC_CAP_DATA_COMPRESS_LZ4)) {
         /* Client doesn't have compression cap - data will not be compressed */
-        return msg_item_compressed;
+        return false;
     }
-    msg_item_compressed = red::make_shared<RedVmcPipeItem>();
+    auto msg_item_compressed = red::make_shared<RedVmcPipeItem>();
     compressed_data_count = LZ4_compress_default((char*)&msg_item->buf,
                                                  (char*)&msg_item_compressed->buf,
                                                  n,
@@ -231,14 +230,14 @@ try_compress_lz4(RedVmcChannel *channel, int n, RedVmcPipeItem *msg_item)
         msg_item_compressed->type = SPICE_DATA_COMPRESSION_TYPE_LZ4;
         msg_item_compressed->uncompressed_data_size = n;
         msg_item_compressed->buf_used = compressed_data_count;
-        return msg_item_compressed;
+        msg_item = std::move(msg_item_compressed);
+        return true;
     }
 
     /* LZ4 compression failed or did non compress, fallback a non-compressed data is to be sent */
-    msg_item_compressed.reset();
-    return msg_item_compressed;
-}
 #endif
+    return false;
+}
 
 RedPipeItemPtr
 RedCharDeviceSpiceVmc::read_one_msg_from_device()
@@ -261,18 +260,12 @@ RedCharDeviceSpiceVmc::read_one_msg_from_device()
     n = read(msg_item->buf, sizeof(msg_item->buf));
     if (n > 0) {
         spice_debug("read from dev %d", n);
-#ifdef USE_LZ4
-        red::shared_ptr<RedVmcPipeItem> msg_item_compressed;
-
-        msg_item_compressed = try_compress_lz4(channel.get(), n, msg_item.get());
-        if (msg_item_compressed) {
-            spicevmc_red_channel_queue_data(channel.get(), std::move(msg_item_compressed));
-            return RedPipeItemPtr();
-        }
-#endif
-        stat_inc_counter(channel->out_data, n);
         msg_item->uncompressed_data_size = n;
         msg_item->buf_used = n;
+
+        if (!try_compress_lz4(channel.get(), msg_item)) {
+            stat_inc_counter(channel->out_data, n);
+        }
         spicevmc_red_channel_queue_data(channel.get(), std::move(msg_item));
         return RedPipeItemPtr();
     }
commit dd9b78fd7843b31886efb37454d4cdf0c63095e7
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Fri Jun 5 16:59:02 2020 +0100

    Use smart pointers for RedPipeItem
    
    Reduces usage of manual reference counting.
    Avoids usage of new and use instead red::make_shared to both
    create and own pipe items.
    Use move semantic to reduce useless copies.
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
    Acked-by: Julien Ropé <jrope at gmail.com>

diff --git a/server/cache-item.tmpl.cpp b/server/cache-item.tmpl.cpp
index 3a24ee33..781f3f53 100644
--- a/server/cache-item.tmpl.cpp
+++ b/server/cache-item.tmpl.cpp
@@ -78,7 +78,7 @@ static void FUNC_NAME(remove)(CHANNELCLIENT *channel_client, RedCacheItem *item)
 
     new (pipe_item) RedCachePipeItem();
     pipe_item->inval_one.id = id;
-    channel_client->pipe_add_tail(pipe_item); // for now
+    channel_client->pipe_add_tail(RedPipeItemPtr(pipe_item)); // for now
 }
 
 static int FUNC_NAME(add)(CHANNELCLIENT *channel_client, uint64_t id, size_t size)
diff --git a/server/char-device.cpp b/server/char-device.cpp
index 762a4939..9423820b 100644
--- a/server/char-device.cpp
+++ b/server/char-device.cpp
@@ -253,9 +253,7 @@ static bool red_char_device_read_from_device(RedCharDevice *dev)
      * All messages will be discarded if no client is attached to the device
      */
     while ((max_send_tokens || (dev->priv->clients == NULL)) && dev->priv->running) {
-        RedPipeItem *msg;
-
-        msg = dev->read_one_msg_from_device();
+        auto msg = dev->read_one_msg_from_device();
         if (!msg) {
             if (dev->priv->during_read_from_device > 1) {
                 dev->priv->during_read_from_device = 1;
@@ -265,8 +263,7 @@ static bool red_char_device_read_from_device(RedCharDevice *dev)
             break;
         }
         did_read = TRUE;
-        red_char_device_send_msg_to_clients(dev, msg);
-        red_pipe_item_unref(msg);
+        red_char_device_send_msg_to_clients(dev, msg.get());
         max_send_tokens--;
     }
     dev->priv->during_read_from_device = 0;
diff --git a/server/char-device.h b/server/char-device.h
index 3b0866b1..dce9ab8a 100644
--- a/server/char-device.h
+++ b/server/char-device.h
@@ -190,7 +190,8 @@ public:
 
     /* reads from the device till reaching a msg that should be sent to the client,
      * or till the reading fails */
-    virtual RedPipeItem* read_one_msg_from_device() = 0;
+    virtual RedPipeItemPtr read_one_msg_from_device() = 0;
+
     /* After this call, the message is unreferenced.
      * Can be NULL. */
     virtual void send_msg_to_client(RedPipeItem *msg, RedCharDeviceClientOpaque *client) {};
diff --git a/server/cursor-channel.cpp b/server/cursor-channel.cpp
index 2dd0a4be..f78dbba2 100644
--- a/server/cursor-channel.cpp
+++ b/server/cursor-channel.cpp
@@ -191,17 +191,16 @@ cursor_channel_new(RedsState *server, int id,
 
 void CursorChannel::process_cmd(RedCursorCmd *cursor_cmd)
 {
-    RedCursorPipeItem *cursor_pipe_item;
     bool cursor_show = false;
 
     spice_return_if_fail(cursor_cmd);
 
-    cursor_pipe_item = new RedCursorPipeItem(cursor_cmd);
+    auto cursor_pipe_item = red::make_shared<RedCursorPipeItem>(cursor_cmd);
 
     switch (cursor_cmd->type) {
     case QXL_CURSOR_SET:
         cursor_visible = !!cursor_cmd->u.set.visible;
-        cursor_channel_set_item(this, cursor_pipe_item);
+        cursor_channel_set_item(this, cursor_pipe_item.get());
         break;
     case QXL_CURSOR_MOVE:
         cursor_show = !cursor_visible;
@@ -217,7 +216,6 @@ void CursorChannel::process_cmd(RedCursorCmd *cursor_cmd)
         break;
     default:
         spice_warning("invalid cursor command %u", cursor_cmd->type);
-        red_pipe_item_unref(cursor_pipe_item);
         return;
     }
 
@@ -225,9 +223,7 @@ void CursorChannel::process_cmd(RedCursorCmd *cursor_cmd)
         (mouse_mode == SPICE_MOUSE_MODE_SERVER
          || cursor_cmd->type != QXL_CURSOR_MOVE
          || cursor_show)) {
-        pipes_add(cursor_pipe_item);
-    } else {
-        red_pipe_item_unref(cursor_pipe_item);
+        pipes_add(std::move(cursor_pipe_item));
     }
 }
 
diff --git a/server/dcc.cpp b/server/dcc.cpp
index d16da328..126598a0 100644
--- a/server/dcc.cpp
+++ b/server/dcc.cpp
@@ -166,7 +166,6 @@ void dcc_create_surface(DisplayChannelClient *dcc, int surface_id)
 {
     DisplayChannel *display;
     RedSurface *surface;
-    RedSurfaceCreateItem *create;
     uint32_t flags;
 
     if (!dcc) {
@@ -182,11 +181,11 @@ void dcc_create_surface(DisplayChannelClient *dcc, int surface_id)
         return;
     }
     surface = &display->priv->surfaces[surface_id];
-    create = new RedSurfaceCreateItem(surface_id, surface->context.width,
-                                      surface->context.height,
-                                      surface->context.format, flags);
+    auto create = red::make_shared<RedSurfaceCreateItem>(surface_id, surface->context.width,
+                                                         surface->context.height,
+                                                         surface->context.format, flags);
     dcc->priv->surface_client_created[surface_id] = TRUE;
-    dcc->pipe_add(create);
+    dcc->pipe_add(std::move(create));
 }
 
 RedImageItem::RedImageItem():
@@ -203,7 +202,6 @@ dcc_add_surface_area_image(DisplayChannelClient *dcc, int surface_id,
     DisplayChannel *display = DCC_TO_DC(dcc);
     RedSurface *surface = &display->priv->surfaces[surface_id];
     SpiceCanvas *canvas = surface->context.canvas;
-    RedImageItem *item;
     int stride;
     int width;
     int height;
@@ -217,7 +215,7 @@ dcc_add_surface_area_image(DisplayChannelClient *dcc, int surface_id,
     bpp = SPICE_SURFACE_FMT_DEPTH(surface->context.format) / 8;
     stride = width * bpp;
 
-    item = new (height * stride) RedImageItem();
+    red::shared_ptr<RedImageItem> item(new (height * stride) RedImageItem());
 
     item->surface_id = surface_id;
     item->image_format =
@@ -246,9 +244,9 @@ dcc_add_surface_area_image(DisplayChannelClient *dcc, int surface_id,
     }
 
     if (pipe_item_pos != dcc->get_pipe().end()) {
-        dcc->pipe_add_after_pos(item, pipe_item_pos);
+        dcc->pipe_add_after_pos(std::move(item), pipe_item_pos);
     } else {
-        dcc->pipe_add(item);
+        dcc->pipe_add(std::move(item));
     }
 }
 
@@ -315,41 +313,39 @@ RedDrawablePipeItem::~RedDrawablePipeItem()
     drawable_unref(drawable);
 }
 
-static RedDrawablePipeItem *red_drawable_pipe_item_new(DisplayChannelClient *dcc,
-                                                       Drawable *drawable)
+static red::shared_ptr<RedDrawablePipeItem>
+red_drawable_pipe_item_new(DisplayChannelClient *dcc, Drawable *drawable)
 {
-    RedDrawablePipeItem *dpi;
-
-    dpi = new RedDrawablePipeItem;
+    auto dpi = red::make_shared<RedDrawablePipeItem>();
     dpi->drawable = drawable;
     dpi->dcc = dcc;
-    drawable->pipes = g_list_prepend(drawable->pipes, dpi);
+    drawable->pipes = g_list_prepend(drawable->pipes, dpi.get());
     drawable->refs++;
     return dpi;
 }
 
 void dcc_prepend_drawable(DisplayChannelClient *dcc, Drawable *drawable)
 {
-    RedDrawablePipeItem *dpi = red_drawable_pipe_item_new(dcc, drawable);
+    auto dpi = red_drawable_pipe_item_new(dcc, drawable);
 
     add_drawable_surface_images(dcc, drawable);
-    dcc->pipe_add(dpi);
+    dcc->pipe_add(std::move(dpi));
 }
 
 void dcc_append_drawable(DisplayChannelClient *dcc, Drawable *drawable)
 {
-    RedDrawablePipeItem *dpi = red_drawable_pipe_item_new(dcc, drawable);
+    auto dpi = red_drawable_pipe_item_new(dcc, drawable);
 
     add_drawable_surface_images(dcc, drawable);
-    dcc->pipe_add_tail(dpi);
+    dcc->pipe_add_tail(std::move(dpi));
 }
 
 void dcc_add_drawable_after(DisplayChannelClient *dcc, Drawable *drawable, RedPipeItem *pos)
 {
-    RedDrawablePipeItem *dpi = red_drawable_pipe_item_new(dcc, drawable);
+    auto dpi = red_drawable_pipe_item_new(dcc, drawable);
 
     add_drawable_surface_images(dcc, drawable);
-    dcc->pipe_add_after(dpi, pos);
+    dcc->pipe_add_after(std::move(dpi), pos);
 }
 
 static void dcc_init_stream_agents(DisplayChannelClient *dcc)
@@ -491,9 +487,9 @@ static void dcc_stop(DisplayChannelClient *dcc)
 
 void dcc_video_stream_agent_clip(DisplayChannelClient* dcc, VideoStreamAgent *agent)
 {
-    VideoStreamClipItem *item = video_stream_clip_item_new(agent);
+    auto item = video_stream_clip_item_new(agent);
 
-    dcc->pipe_add(item);
+    dcc->pipe_add(std::move(item));
 }
 
 RedMonitorsConfigItem::~RedMonitorsConfigItem()
@@ -510,7 +506,6 @@ void dcc_push_monitors_config(DisplayChannelClient *dcc)
 {
     DisplayChannel *dc = DCC_TO_DC(dcc);
     MonitorsConfig *monitors_config = dc->priv->monitors_config;
-    RedMonitorsConfigItem *mci;
 
     if (monitors_config == NULL) {
         spice_warning("monitors_config is NULL");
@@ -521,8 +516,8 @@ void dcc_push_monitors_config(DisplayChannelClient *dcc)
         return;
     }
 
-    mci = new RedMonitorsConfigItem(monitors_config);
-    dcc->pipe_add(mci);
+    auto mci = red::make_shared<RedMonitorsConfigItem>(monitors_config);
+    dcc->pipe_add(std::move(mci));
 }
 
 RedSurfaceDestroyItem::RedSurfaceDestroyItem(uint32_t surface_id)
@@ -530,7 +525,7 @@ RedSurfaceDestroyItem::RedSurfaceDestroyItem(uint32_t surface_id)
     surface_destroy.surface_id = surface_id;
 }
 
-RedPipeItem *dcc_gl_scanout_item_new(RedChannelClient *rcc, void *data, int num)
+RedPipeItemPtr dcc_gl_scanout_item_new(RedChannelClient *rcc, void *data, int num)
 {
     /* FIXME: on !unix peer, start streaming with a video codec */
     if (!red_stream_is_plain_unix(rcc->get_stream()) ||
@@ -538,30 +533,29 @@ RedPipeItem *dcc_gl_scanout_item_new(RedChannelClient *rcc, void *data, int num)
         red_channel_warning(rcc->get_channel(),
                             "FIXME: client does not support GL scanout");
         rcc->disconnect();
-        return NULL;
+        return RedPipeItemPtr();
     }
 
-    return new RedGlScanoutUnixItem(RED_PIPE_ITEM_TYPE_GL_SCANOUT);
+    return red::make_shared<RedGlScanoutUnixItem>(RED_PIPE_ITEM_TYPE_GL_SCANOUT);
 }
 
 XXX_CAST(RedChannelClient, DisplayChannelClient, DISPLAY_CHANNEL_CLIENT);
 
-RedPipeItem *dcc_gl_draw_item_new(RedChannelClient *rcc, void *data, int num)
+RedPipeItemPtr dcc_gl_draw_item_new(RedChannelClient *rcc, void *data, int num)
 {
     DisplayChannelClient *dcc = DISPLAY_CHANNEL_CLIENT(rcc);
     const SpiceMsgDisplayGlDraw *draw = (const SpiceMsgDisplayGlDraw *) data;
-    RedGlDrawItem *item;
 
     if (!red_stream_is_plain_unix(rcc->get_stream()) ||
         !rcc->test_remote_cap(SPICE_DISPLAY_CAP_GL_SCANOUT)) {
         red_channel_warning(rcc->get_channel(),
                             "FIXME: client does not support GL scanout");
         rcc->disconnect();
-        return NULL;
+        return RedPipeItemPtr();
     }
 
     dcc->priv->gl_draw_ongoing = TRUE;
-    item = new RedGlDrawItem(RED_PIPE_ITEM_TYPE_GL_DRAW);
+    auto item = red::make_shared<RedGlDrawItem>(RED_PIPE_ITEM_TYPE_GL_DRAW);
     item->draw = *draw;
 
     return item;
@@ -570,7 +564,6 @@ RedPipeItem *dcc_gl_draw_item_new(RedChannelClient *rcc, void *data, int num)
 void dcc_destroy_surface(DisplayChannelClient *dcc, uint32_t surface_id)
 {
     DisplayChannel *display;
-    RedSurfaceDestroyItem *destroy;
 
     if (!dcc) {
         return;
@@ -584,8 +577,8 @@ void dcc_destroy_surface(DisplayChannelClient *dcc, uint32_t surface_id)
     }
 
     dcc->priv->surface_client_created[surface_id] = FALSE;
-    destroy = new RedSurfaceDestroyItem(surface_id);
-    dcc->pipe_add(destroy);
+    auto destroy = red::make_shared<RedSurfaceDestroyItem>(surface_id);
+    dcc->pipe_add(std::move(destroy));
 }
 
 #define MIN_DIMENSION_TO_QUIC 3
diff --git a/server/dcc.h b/server/dcc.h
index 002da283..696f66af 100644
--- a/server/dcc.h
+++ b/server/dcc.h
@@ -175,10 +175,6 @@ bool                       dcc_clear_surface_drawables_from_pipe     (DisplayCha
                                                                       int wait_if_used);
 bool                       dcc_drawable_is_in_pipe                   (DisplayChannelClient *dcc,
                                                                       Drawable *drawable);
-RedPipeItem *              dcc_gl_scanout_item_new                   (RedChannelClient *rcc,
-                                                                      void *data, int num);
-RedPipeItem *              dcc_gl_draw_item_new                      (RedChannelClient *rcc,
-                                                                      void *data, int num);
 
 int                        dcc_compress_image                        (DisplayChannelClient *dcc,
                                                                       SpiceImage *dest, SpiceBitmap *src, Drawable *drawable,
@@ -188,6 +184,8 @@ int                        dcc_compress_image                        (DisplayCha
 void dcc_add_surface_area_image(DisplayChannelClient *dcc, int surface_id,
                                 SpiceRect *area, RedChannelClient::Pipe::iterator pipe_item_pos,
                                 int can_lossy);
+RedPipeItemPtr dcc_gl_scanout_item_new(RedChannelClient *rcc, void *data, int num);
+RedPipeItemPtr dcc_gl_draw_item_new(RedChannelClient *rcc, void *data, int num);
 VideoStreamAgent *dcc_get_video_stream_agent(DisplayChannelClient *dcc, int stream_id);
 ImageEncoders *dcc_get_encoders(DisplayChannelClient *dcc);
 spice_wan_compression_t    dcc_get_jpeg_state                        (DisplayChannelClient *dcc);
diff --git a/server/inputs-channel.cpp b/server/inputs-channel.cpp
index b9df9d1a..f22421f3 100644
--- a/server/inputs-channel.cpp
+++ b/server/inputs-channel.cpp
@@ -436,7 +436,7 @@ RedInputsInitPipeItem::RedInputsInitPipeItem(uint8_t init_modifiers):
 void InputsChannelClient::pipe_add_init()
 {
     auto modifiers = kbd_get_leds(get_channel()->keyboard);
-    pipe_add_push(new RedInputsInitPipeItem(modifiers));
+    pipe_add_push(red::make_shared<RedInputsInitPipeItem>(modifiers));
 }
 
 void InputsChannel::on_connect(RedClient *client, RedStream *stream, int migration,
@@ -461,7 +461,7 @@ void InputsChannel::push_keyboard_modifiers()
     if (!is_connected() || src_during_migrate) {
         return;
     }
-    pipes_add(new RedKeyModifiersPipeItem(modifiers));
+    pipes_add(red::make_shared<RedKeyModifiersPipeItem>(modifiers));
 }
 
 SPICE_GNUC_VISIBLE int spice_server_kbd_leds(SpiceKbdInstance *sin, int leds)
diff --git a/server/main-channel-client.cpp b/server/main-channel-client.cpp
index eb82614c..32730b4c 100644
--- a/server/main-channel-client.cpp
+++ b/server/main-channel-client.cpp
@@ -142,9 +142,9 @@ void MainChannelClient::on_disconnect()
 
 static void main_channel_client_push_ping(MainChannelClient *mcc, int size);
 
-static RedPipeItem *main_notify_item_new(const char *msg, int num)
+static RedPipeItemPtr main_notify_item_new(const char *msg, int num)
 {
-    RedNotifyPipeItem *item = new RedNotifyPipeItem();
+    auto item = red::make_shared<RedNotifyPipeItem>();
 
     item->msg.reset(g_strdup(msg));
     return item;
@@ -169,9 +169,9 @@ void MainChannelClient::start_net_test(int test_rate)
     main_channel_client_push_ping(this, NET_TEST_BYTES);
 }
 
-static RedPipeItem *red_ping_item_new(int size)
+static RedPipeItemPtr red_ping_item_new(int size)
 {
-    RedPingPipeItem *item = new RedPingPipeItem();
+    auto item = red::make_shared<RedPingPipeItem>();
 
     item->size = size;
     return item;
@@ -179,13 +179,13 @@ static RedPipeItem *red_ping_item_new(int size)
 
 static void main_channel_client_push_ping(MainChannelClient *mcc, int size)
 {
-    RedPipeItem *item = red_ping_item_new(size);
-    mcc->pipe_add_push(item);
+    auto item = red_ping_item_new(size);
+    mcc->pipe_add_push(std::move(item));
 }
 
-static RedPipeItem *main_agent_tokens_item_new(uint32_t num_tokens)
+static RedPipeItemPtr main_agent_tokens_item_new(uint32_t num_tokens)
 {
-    RedTokensPipeItem *item = new RedTokensPipeItem();
+    auto item = red::make_shared<RedTokensPipeItem>();
 
     item->tokens = num_tokens;
     return item;
@@ -194,24 +194,25 @@ static RedPipeItem *main_agent_tokens_item_new(uint32_t num_tokens)
 
 void MainChannelClient::push_agent_tokens(uint32_t num_tokens)
 {
-    RedPipeItem *item = main_agent_tokens_item_new(num_tokens);
+    auto item = main_agent_tokens_item_new(num_tokens);
 
-    pipe_add_push(item);
+    pipe_add_push(std::move(item));
 }
 
-void MainChannelClient::push_agent_data(RedAgentDataPipeItem *item)
+void MainChannelClient::push_agent_data(red::shared_ptr<RedAgentDataPipeItem>&& item)
 {
-    pipe_add_push(item);
+    pipe_add_push(std::move(item));
 }
 
-static RedPipeItem *main_init_item_new(int connection_id,
-                                       int display_channels_hint,
-                                       SpiceMouseMode current_mouse_mode,
-                                       int is_client_mouse_allowed,
-                                       int multi_media_time,
-                                       int ram_hint)
+static RedPipeItemPtr
+main_init_item_new(int connection_id,
+                   int display_channels_hint,
+                   SpiceMouseMode current_mouse_mode,
+                   int is_client_mouse_allowed,
+                   int multi_media_time,
+                   int ram_hint)
 {
-    RedInitPipeItem *item = new RedInitPipeItem();
+    auto item = red::make_shared<RedInitPipeItem>();
 
     item->connection_id = connection_id;
     item->display_channels_hint = display_channels_hint;
@@ -227,37 +228,33 @@ void MainChannelClient::push_init(int display_channels_hint,
                                   int is_client_mouse_allowed,
                                   int multi_media_time, int ram_hint)
 {
-    RedPipeItem *item;
-
-    item = main_init_item_new(priv->connection_id, display_channels_hint,
-                              current_mouse_mode, is_client_mouse_allowed,
-                              multi_media_time, ram_hint);
-    pipe_add_push(item);
+    auto item = main_init_item_new(priv->connection_id, display_channels_hint,
+                                   current_mouse_mode, is_client_mouse_allowed,
+                                   multi_media_time, ram_hint);
+    pipe_add_push(std::move(item));
 }
 
-static RedPipeItem *main_name_item_new(const char *name)
+static RedPipeItemPtr main_name_item_new(const char *name)
 {
     RedNamePipeItem *item = new (strlen(name) + 1) RedNamePipeItem();
     item->msg.name_len = strlen(name) + 1;
     memcpy(&item->msg.name, name, item->msg.name_len);
 
-    return item;
+    return RedPipeItemPtr(item);
 }
 
 void MainChannelClient::push_name(const char *name)
 {
-    RedPipeItem *item;
-
     if (!test_remote_cap(SPICE_MAIN_CAP_NAME_AND_UUID))
         return;
 
-    item = main_name_item_new(name);
-    pipe_add_push(item);
+    auto item = main_name_item_new(name);
+    pipe_add_push(std::move(item));
 }
 
-static RedPipeItem *main_uuid_item_new(const uint8_t uuid[16])
+static RedPipeItemPtr main_uuid_item_new(const uint8_t uuid[16])
 {
-    RedUuidPipeItem *item = new RedUuidPipeItem();
+    auto item = red::make_shared<RedUuidPipeItem>();
 
     memcpy(item->msg.uuid, uuid, sizeof(item->msg.uuid));
 
@@ -266,44 +263,41 @@ static RedPipeItem *main_uuid_item_new(const uint8_t uuid[16])
 
 void MainChannelClient::push_uuid(const uint8_t uuid[16])
 {
-    RedPipeItem *item;
-
     if (!test_remote_cap(SPICE_MAIN_CAP_NAME_AND_UUID))
         return;
 
-    item = main_uuid_item_new(uuid);
-    pipe_add_push(item);
+    auto item = main_uuid_item_new(uuid);
+    pipe_add_push(std::move(item));
 }
 
 void MainChannelClient::push_notify(const char *msg)
 {
-    RedPipeItem *item = main_notify_item_new(msg, 1);
-    pipe_add_push(item);
+    auto item = main_notify_item_new(msg, 1);
+    pipe_add_push(std::move(item));
 }
 
-RedPipeItem *main_mouse_mode_item_new(SpiceMouseMode current_mode, int is_client_mouse_allowed)
+RedPipeItemPtr
+main_mouse_mode_item_new(SpiceMouseMode current_mode, int is_client_mouse_allowed)
 {
-    RedMouseModePipeItem *item = new RedMouseModePipeItem();
+    auto item = red::make_shared<RedMouseModePipeItem>();
 
     item->current_mode = current_mode;
     item->is_client_mouse_allowed = is_client_mouse_allowed;
     return item;
 }
 
-RedPipeItem *main_multi_media_time_item_new(uint32_t mm_time)
+RedPipeItemPtr
+main_multi_media_time_item_new(uint32_t mm_time)
 {
-    RedMultiMediaTimePipeItem *item;
-
-    item = new RedMultiMediaTimePipeItem();
+    auto item = red::make_shared<RedMultiMediaTimePipeItem>();
     item->time = mm_time;
     return item;
 }
 
-RedPipeItem *registered_channel_item_new(RedChannel *channel)
+RedPipeItemPtr
+registered_channel_item_new(RedChannel *channel)
 {
-    RedRegisteredChannelPipeItem *item;
-
-    item = new RedRegisteredChannelPipeItem();
+    auto item = red::make_shared<RedRegisteredChannelPipeItem>();
 
     item->channel_type = channel->type();
     item->channel_id = channel->id();
diff --git a/server/main-channel-client.h b/server/main-channel-client.h
index c7973d29..56401a8b 100644
--- a/server/main-channel-client.h
+++ b/server/main-channel-client.h
@@ -38,7 +38,7 @@ class MainChannelClient final: public RedChannelClient
 {
 public:
     void push_agent_tokens(uint32_t num_tokens);
-    void push_agent_data(RedAgentDataPipeItem *item);
+    void push_agent_data(red::shared_ptr<RedAgentDataPipeItem>&& item);
     // TODO: huge. Consider making a reds_* interface for these functions
     // and calling from main.
     void push_init(int display_channels_hint, SpiceMouseMode current_mouse_mode,
@@ -120,11 +120,11 @@ struct RedAgentDataPipeItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_MAIN_AGENT
     uint8_t data[SPICE_AGENT_MAX_DATA_SIZE];
 };
 
-RedPipeItem *main_mouse_mode_item_new(SpiceMouseMode current_mode, int is_client_mouse_allowed);
+RedPipeItemPtr main_mouse_mode_item_new(SpiceMouseMode current_mode, int is_client_mouse_allowed);
 
-RedPipeItem *main_multi_media_time_item_new(uint32_t mm_time);
+RedPipeItemPtr main_multi_media_time_item_new(uint32_t mm_time);
 
-RedPipeItem *registered_channel_item_new(RedChannel *channel);
+RedPipeItemPtr registered_channel_item_new(RedChannel *channel);
 
 #include "pop-visibility.h"
 
diff --git a/server/red-channel-client.cpp b/server/red-channel-client.cpp
index e8827911..850047a5 100644
--- a/server/red-channel-client.cpp
+++ b/server/red-channel-client.cpp
@@ -174,7 +174,7 @@ struct RedChannelClientPrivate
     RedStatCounter out_bytes;
 
     inline RedPipeItemPtr pipe_item_get();
-    inline bool pipe_remove(RedPipeItem *item);
+    inline void pipe_remove(RedPipeItem *item);
     void handle_pong(SpiceMsgPing *ping);
     inline void set_message_serial(uint64_t serial);
     void pipe_clear();
@@ -514,7 +514,6 @@ void RedChannelClient::send_any_item(RedPipeItem *item)
             send_item(item);
             break;
     }
-    red_pipe_item_unref(item);
 }
 
 inline void RedChannelClientPrivate::restore_main_sender()
@@ -565,14 +564,12 @@ find_pipe_item(RedChannelClient::Pipe &pipe, const RedPipeItem *item)
     });
 }
 
-bool RedChannelClientPrivate::pipe_remove(RedPipeItem *item)
+void RedChannelClientPrivate::pipe_remove(RedPipeItem *item)
 {
     auto i = find_pipe_item(pipe, item);
     if (i != pipe.end()) {
         pipe.erase(i);
-        return true;
     }
-    return false;
 }
 
 bool RedChannelClient::test_remote_common_cap(uint32_t cap) const
@@ -1137,8 +1134,6 @@ inline RedPipeItemPtr RedChannelClientPrivate::pipe_item_get()
 
 void RedChannelClient::push()
 {
-    RedPipeItemPtr pipe_item;
-
     if (priv->during_send) {
         return;
     }
@@ -1155,7 +1150,7 @@ void RedChannelClient::push()
                             "ERROR: an item waiting to be sent and not blocked");
     }
 
-    while ((pipe_item = priv->pipe_item_get())) {
+    while (auto pipe_item = priv->pipe_item_get()) {
         send_any_item(pipe_item.get());
     }
     /* prepare_pipe_add() will reenable WRITE events when the priv->pipe is empty
@@ -1370,7 +1365,6 @@ inline bool RedChannelClient::prepare_pipe_add(RedPipeItem *item)
     spice_assert(item);
     if (SPICE_UNLIKELY(!is_connected())) {
         spice_debug("rcc is disconnected %p", this);
-        red_pipe_item_unref(item);
         return false;
     }
     if (priv->pipe.empty()) {
@@ -1379,50 +1373,50 @@ inline bool RedChannelClient::prepare_pipe_add(RedPipeItem *item)
     return true;
 }
 
-void RedChannelClient::pipe_add(RedPipeItem *item)
+void RedChannelClient::pipe_add(RedPipeItemPtr&& item)
 {
-    if (!prepare_pipe_add(item)) {
+    if (!prepare_pipe_add(item.get())) {
         return;
     }
-    priv->pipe.push_front(RedPipeItemPtr(item));
+    priv->pipe.push_front(std::move(item));
 }
 
-void RedChannelClient::pipe_add_push(RedPipeItem *item)
+void RedChannelClient::pipe_add_push(RedPipeItemPtr&& item)
 {
-    pipe_add(item);
+    pipe_add(std::move(item));
     push();
 }
 
-void RedChannelClient::pipe_add_after_pos(RedPipeItem *item,
+void RedChannelClient::pipe_add_after_pos(RedPipeItemPtr&& item,
                                           Pipe::iterator pipe_item_pos)
 {
     spice_assert(pipe_item_pos != priv->pipe.end());
-    if (!prepare_pipe_add(item)) {
+    if (!prepare_pipe_add(item.get())) {
         return;
     }
 
     ++pipe_item_pos;
-    priv->pipe.insert(pipe_item_pos, RedPipeItemPtr(item));
+    priv->pipe.insert(pipe_item_pos, std::move(item));
 }
 
 void
-RedChannelClient::pipe_add_before_pos(RedPipeItem *item, Pipe::iterator pipe_item_pos)
+RedChannelClient::pipe_add_before_pos(RedPipeItemPtr&& item, Pipe::iterator pipe_item_pos)
 {
     spice_assert(pipe_item_pos != priv->pipe.end());
-    if (!prepare_pipe_add(item)) {
+    if (!prepare_pipe_add(item.get())) {
         return;
     }
 
-    priv->pipe.insert(pipe_item_pos, RedPipeItemPtr(item));
+    priv->pipe.insert(pipe_item_pos, std::move(item));
 }
 
-void RedChannelClient::pipe_add_after(RedPipeItem *item, RedPipeItem *pos)
+void RedChannelClient::pipe_add_after(RedPipeItemPtr&& item, RedPipeItem *pos)
 {
     spice_assert(pos);
     auto prev = find_pipe_item(priv->pipe, pos);
     g_return_if_fail(prev != priv->pipe.end());
 
-    pipe_add_after_pos(item, prev);
+    pipe_add_after_pos(std::move(item), prev);
 }
 
 int RedChannelClient::pipe_item_is_linked(RedPipeItem *item)
@@ -1430,24 +1424,24 @@ int RedChannelClient::pipe_item_is_linked(RedPipeItem *item)
     return find_pipe_item(priv->pipe, item) != priv->pipe.end();
 }
 
-void RedChannelClient::pipe_add_tail(RedPipeItem *item)
+void RedChannelClient::pipe_add_tail(RedPipeItemPtr&& item)
 {
-    if (!prepare_pipe_add(item)) {
+    if (!prepare_pipe_add(item.get())) {
         return;
     }
-    priv->pipe.push_back(RedPipeItemPtr(item));
+    priv->pipe.push_back(std::move(item));
 }
 
 void RedChannelClient::pipe_add_type(int pipe_item_type)
 {
-    RedPipeItem *item = new RedPipeItem(pipe_item_type);
+    auto item = red::make_shared<RedPipeItem>(pipe_item_type);
 
-    pipe_add(item);
+    pipe_add(std::move(item));
 }
 
-RedPipeItem *RedChannelClient::new_empty_msg(int msg_type)
+RedPipeItemPtr RedChannelClient::new_empty_msg(int msg_type)
 {
-    RedEmptyMsgPipeItem *item = new RedEmptyMsgPipeItem();
+    auto item = red::make_shared<RedEmptyMsgPipeItem>();
 
     item->msg = msg_type;
     return item;
@@ -1586,7 +1580,7 @@ bool RedChannelClient::wait_pipe_item_sent(Pipe::iterator item_pos, int64_t time
     auto mark_item = red::make_shared<MarkerPipeItem>();
 
     mark_item->item_sent = false;
-    pipe_add_before_pos(mark_item.get(), item_pos);
+    pipe_add_before_pos(RedPipeItemPtr(mark_item), item_pos);
 
     for (;;) {
         receive();
@@ -1643,9 +1637,7 @@ bool RedChannelClient::no_item_being_sent() const
 
 void RedChannelClient::pipe_remove_and_release(RedPipeItem *item)
 {
-    if (priv->pipe_remove(item)) {
-        red_pipe_item_unref(item);
-    }
+    priv->pipe_remove(item);
 }
 
 /* client mutex should be locked before this call */
diff --git a/server/red-channel-client.h b/server/red-channel-client.h
index 69099882..4f8c7b0d 100644
--- a/server/red-channel-client.h
+++ b/server/red-channel-client.h
@@ -85,16 +85,17 @@ protected:
 public:
     typedef std::list<RedPipeItemPtr, red::Mallocator<RedPipeItemPtr>> Pipe;
 
-    void pipe_add_push(RedPipeItem *item);
-    void pipe_add(RedPipeItem *item);
-    void pipe_add_after(RedPipeItem *item, RedPipeItem *pos);
-    void pipe_add_after_pos(RedPipeItem *item, RedChannelClient::Pipe::iterator pos);
+    void pipe_add_push(RedPipeItemPtr&& item);
+    void pipe_add(RedPipeItemPtr&& item);
+    void pipe_add_after(RedPipeItemPtr&& item, RedPipeItem *pos);
+    void pipe_add_after_pos(RedPipeItemPtr&& item,
+                            RedChannelClient::Pipe::iterator pos);
     int pipe_item_is_linked(RedPipeItem *item);
     void pipe_remove_and_release(RedPipeItem *item);
-    void pipe_add_tail(RedPipeItem *item);
+    void pipe_add_tail(RedPipeItemPtr&& item);
     /* for types that use this routine -> the pipe item should be freed */
     void pipe_add_type(int pipe_item_type);
-    static RedPipeItem *new_empty_msg(int msg_type);
+    static RedPipeItemPtr new_empty_msg(int msg_type);
     void pipe_add_empty_msg(int msg_type);
     gboolean pipe_is_empty();
     uint32_t get_pipe_size();
@@ -184,7 +185,7 @@ private:
     virtual void handle_migrate_flush_mark();
     void handle_migrate_data_early(uint32_t size, void *message);
     inline bool prepare_pipe_add(RedPipeItem *item);
-    void pipe_add_before_pos(RedPipeItem *item, RedChannelClient::Pipe::iterator pipe_item_pos);
+    void pipe_add_before_pos(RedPipeItemPtr&& item, RedChannelClient::Pipe::iterator pipe_item_pos);
     void send_set_ack();
     void send_migrate();
     void send_empty_msg(RedPipeItem *base);
diff --git a/server/red-channel.cpp b/server/red-channel.cpp
index bedb323a..dc577695 100644
--- a/server/red-channel.cpp
+++ b/server/red-channel.cpp
@@ -266,23 +266,20 @@ void RedChannel::push()
     red_channel_foreach_client(this, &RedChannelClient::push);
 }
 
-void RedChannel::pipes_add(RedPipeItem *item)
+void RedChannel::pipes_add(RedPipeItemPtr&& item)
 {
     RedChannelClient *rcc;
 
     FOREACH_CLIENT(this, rcc) {
-        red_pipe_item_ref(item);
-        rcc->pipe_add(item);
+        rcc->pipe_add(RedPipeItemPtr(item));
     }
-
-    red_pipe_item_unref(item);
 }
 
 void RedChannel::pipes_add_type(int pipe_item_type)
 {
-    RedPipeItem *item = new RedPipeItem(pipe_item_type);
+    auto item = red::make_shared<RedPipeItem>(pipe_item_type);
 
-    pipes_add(item);
+    pipes_add(std::move(item));
 }
 
 void RedChannel::pipes_add_empty_msg(int msg_type)
@@ -437,15 +434,14 @@ static bool red_channel_no_item_being_sent(RedChannel *channel)
 int RedChannel::pipes_new_add(new_pipe_item_t creator, void *data)
 {
     RedChannelClient *rcc;
-    RedPipeItem *item;
     int num = 0, n = 0;
 
     spice_assert(creator != NULL);
 
     FOREACH_CLIENT(this, rcc) {
-        item = (*creator)(rcc, data, num++);
+        auto item = (*creator)(rcc, data, num++);
         if (item) {
-            rcc->pipe_add(item);
+            rcc->pipe_add(std::move(item));
             n++;
         }
     }
diff --git a/server/red-channel.h b/server/red-channel.h
index af288a82..60fef188 100644
--- a/server/red-channel.h
+++ b/server/red-channel.h
@@ -109,7 +109,7 @@ struct RedChannel: public red::shared_ptr_counted
     bool test_remote_cap(uint32_t cap);
 
     // helper to push a new item to all channels
-    typedef RedPipeItem *(*new_pipe_item_t)(RedChannelClient *rcc, void *data, int num);
+    typedef RedPipeItemPtr (*new_pipe_item_t)(RedChannelClient *rcc, void *data, int num);
     int pipes_new_add(new_pipe_item_t creator, void *data);
 
     void pipes_add_type(int pipe_item_type);
@@ -120,7 +120,7 @@ struct RedChannel: public red::shared_ptr_counted
      * The same item is shared between all clients.
      * Function will take ownership of the item.
      */
-    void pipes_add(RedPipeItem *item);
+    void pipes_add(RedPipeItemPtr&& item);
 
     /* return TRUE if all of the connected clients to this channel are blocked */
     bool all_blocked();
diff --git a/server/red-pipe-item.cpp b/server/red-pipe-item.cpp
index 1aedd700..a871bfef 100644
--- a/server/red-pipe-item.cpp
+++ b/server/red-pipe-item.cpp
@@ -23,8 +23,6 @@
 RedPipeItem::RedPipeItem(int init_type):
     type(init_type)
 {
-    // compatibility with no shared_ptr reference counting
-    shared_ptr_add_ref(this);
 }
 
 RedPipeItem *red_pipe_item_ref(RedPipeItem *item)
diff --git a/server/red-stream-device.cpp b/server/red-stream-device.cpp
index d21c6e77..983e2b94 100644
--- a/server/red-stream-device.cpp
+++ b/server/red-stream-device.cpp
@@ -158,12 +158,12 @@ StreamDevice::partial_read()
     return false;
 }
 
-RedPipeItem* StreamDevice::read_one_msg_from_device()
+RedPipeItemPtr StreamDevice::read_one_msg_from_device()
 {
     while (partial_read()) {
         continue;
     }
-    return NULL;
+    return RedPipeItemPtr();
 }
 
 bool
diff --git a/server/red-stream-device.h b/server/red-stream-device.h
index c10e4beb..bf657878 100644
--- a/server/red-stream-device.h
+++ b/server/red-stream-device.h
@@ -90,7 +90,7 @@ private:
     StreamDeviceDisplayInfo device_display_info;
 
 private:
-    virtual RedPipeItem* read_one_msg_from_device() override;
+    virtual RedPipeItemPtr read_one_msg_from_device() override;
     virtual void remove_client(RedCharDeviceClientOpaque *client) override;
     virtual void port_event(uint8_t event) override;
 
diff --git a/server/reds.cpp b/server/reds.cpp
index 94a0d703..fb465c81 100644
--- a/server/reds.cpp
+++ b/server/reds.cpp
@@ -182,7 +182,7 @@ struct RedCharDeviceVDIPortPrivate {
     uint32_t message_receive_len;
     uint8_t *receive_pos;
     uint32_t receive_len;
-    RedVDIReadBuf *current_read_buf;
+    red::shared_ptr<RedVDIReadBuf> current_read_buf;
     AgentMsgFilter read_filter;
 
     VDIChunkHeader vdi_chunk_header;
@@ -210,7 +210,7 @@ struct RedCharDeviceVDIPort: public RedCharDevice
     RedCharDeviceVDIPort();
     ~RedCharDeviceVDIPort();
 
-    virtual RedPipeItem* read_one_msg_from_device() override;
+    virtual RedPipeItemPtr read_one_msg_from_device() override;
     virtual void send_msg_to_client(RedPipeItem *msg, RedCharDeviceClientOpaque *opaque) override;
     virtual void send_tokens_to_client(RedCharDeviceClientOpaque *opaque, uint32_t tokens) override;
     virtual void remove_client(RedCharDeviceClientOpaque *opaque);
@@ -235,7 +235,7 @@ static void reds_set_mouse_mode(RedsState *reds, SpiceMouseMode mode);
 static uint32_t reds_qxl_ram_size(RedsState *reds);
 static int calc_compression_level(RedsState *reds);
 
-static RedVDIReadBuf *vdi_port_get_read_buf(RedCharDeviceVDIPort *dev);
+static red::shared_ptr<RedVDIReadBuf> vdi_port_get_read_buf(RedCharDeviceVDIPort *dev);
 
 static ChannelSecurityOptions *reds_find_channel_security(RedsState *reds, int id)
 {
@@ -401,10 +401,8 @@ static void reds_reset_vdp(RedsState *reds)
     dev->priv->receive_pos = (uint8_t *)&dev->priv->vdi_chunk_header;
     dev->priv->receive_len = sizeof(dev->priv->vdi_chunk_header);
     dev->priv->message_receive_len = 0;
-    if (dev->priv->current_read_buf) {
-        red_pipe_item_unref(dev->priv->current_read_buf);
-        dev->priv->current_read_buf = NULL;
-    }
+    dev->priv->current_read_buf.reset();
+
     /* Reset read filter to start with clean state when the agent reconnects */
     agent_msg_filter_init(&dev->priv->read_filter, reds->config->agent_copypaste,
                           reds->config->agent_file_xfer,
@@ -659,11 +657,11 @@ static void reds_agent_remove(RedsState *reds)
         other values can be discarded
 */
 static AgentMsgFilterResult vdi_port_read_buf_process(RedCharDeviceVDIPort *dev,
-                                                      RedVDIReadBuf *buf)
+                                                      RedVDIReadBuf& buf)
 {
     switch (dev->priv->vdi_chunk_header.port) {
     case VDP_CLIENT_PORT:
-        return agent_msg_filter_process_data(&dev->priv->read_filter, buf->data, buf->len);
+        return agent_msg_filter_process_data(&dev->priv->read_filter, buf.data, buf.len);
     case VDP_SERVER_PORT:
         return AGENT_MSG_FILTER_DISCARD;
     default:
@@ -685,17 +683,17 @@ RedVDIReadBuf::~RedVDIReadBuf()
     }
 }
 
-static RedVDIReadBuf *vdi_read_buf_new(RedCharDeviceVDIPort *dev)
+static red::shared_ptr<RedVDIReadBuf> vdi_read_buf_new(RedCharDeviceVDIPort *dev)
 {
-    RedVDIReadBuf *buf = new RedVDIReadBuf();
+    auto buf = red::make_shared<RedVDIReadBuf>();
     buf->dev = dev;
     return buf;
 }
 
-static RedVDIReadBuf *vdi_port_get_read_buf(RedCharDeviceVDIPort *dev)
+static red::shared_ptr<RedVDIReadBuf> vdi_port_get_read_buf(RedCharDeviceVDIPort *dev)
 {
     if (dev->priv->num_read_buf >= REDS_VDI_PORT_NUM_RECEIVE_BUFFS) {
-        return NULL;
+        return red::shared_ptr<RedVDIReadBuf>();
     }
 
     dev->priv->num_read_buf++;
@@ -731,11 +729,10 @@ static void reds_adjust_agent_capabilities(RedsState *reds, VDAgentMessage *mess
 
 /* reads from the device till completes reading a message that is addressed to the client,
  * or otherwise, when reading from the device fails */
-RedPipeItem *
+RedPipeItemPtr
 RedCharDeviceVDIPort::read_one_msg_from_device()
 {
     RedsState *reds;
-    RedVDIReadBuf *dispatch_buf;
     int n;
 
     reds = get_server();
@@ -744,18 +741,18 @@ RedCharDeviceVDIPort::read_one_msg_from_device()
         case VDI_PORT_READ_STATE_READ_HEADER:
             n = read(priv->receive_pos, priv->receive_len);
             if (!n) {
-                return NULL;
+                return RedPipeItemPtr();
             }
             if ((priv->receive_len -= n)) {
                 priv->receive_pos += n;
-                return NULL;
+                return RedPipeItemPtr();
             }
             priv->message_receive_len = priv->vdi_chunk_header.size;
             priv->read_state = VDI_PORT_READ_STATE_GET_BUFF;
             /* fall through */
         case VDI_PORT_READ_STATE_GET_BUFF: {
             if (!(priv->current_read_buf = vdi_port_get_read_buf(this))) {
-                return NULL;
+                return RedPipeItemPtr();
             }
             priv->receive_pos = priv->current_read_buf->data;
             priv->receive_len = MIN(priv->message_receive_len,
@@ -768,14 +765,13 @@ RedCharDeviceVDIPort::read_one_msg_from_device()
         case VDI_PORT_READ_STATE_READ_DATA: {
             n = read(priv->receive_pos, priv->receive_len);
             if (!n) {
-                return NULL;
+                return RedPipeItemPtr();
             }
             if ((priv->receive_len -= n)) {
                 priv->receive_pos += n;
                 break;
             }
-            dispatch_buf = priv->current_read_buf;
-            priv->current_read_buf = NULL;
+            auto dispatch_buf = std::move(priv->current_read_buf);
             priv->receive_pos = NULL;
             if (priv->message_receive_len == 0) {
                 priv->read_state = VDI_PORT_READ_STATE_READ_HEADER;
@@ -784,7 +780,7 @@ RedCharDeviceVDIPort::read_one_msg_from_device()
             } else {
                 priv->read_state = VDI_PORT_READ_STATE_GET_BUFF;
             }
-            switch (vdi_port_read_buf_process(this, dispatch_buf)) {
+            switch (vdi_port_read_buf_process(this, *dispatch_buf)) {
             case AGENT_MSG_FILTER_OK:
                 reds_adjust_agent_capabilities(reds, (VDAgentMessage *) dispatch_buf->data);
                 return dispatch_buf;
@@ -794,12 +790,12 @@ RedCharDeviceVDIPort::read_one_msg_from_device()
             case AGENT_MSG_FILTER_MONITORS_CONFIG:
                 /* fall through */
             case AGENT_MSG_FILTER_DISCARD:
-                red_pipe_item_unref(dispatch_buf);
+                dispatch_buf.reset();
             }
         }
         } /* END switch */
     } /* END while */
-    return NULL;
+    return RedPipeItemPtr();
 }
 
 void reds_marshall_device_display_info(RedsState *reds, SpiceMarshaller *m)
@@ -893,8 +889,7 @@ void RedCharDeviceVDIPort::send_msg_to_client(RedPipeItem *msg, RedCharDeviceCli
     RedClient *client = (RedClient *) opaque;
     RedVDIReadBuf *agent_data_buf = static_cast<RedVDIReadBuf*>(msg);
 
-    red_pipe_item_ref(msg);
-    client->get_main()->push_agent_data(agent_data_buf);
+    client->get_main()->push_agent_data(red::shared_ptr<RedAgentDataPipeItem>(agent_data_buf));
 }
 
 void RedCharDeviceVDIPort::send_tokens_to_client(RedCharDeviceClientOpaque *opaque, uint32_t tokens)
@@ -1242,16 +1237,16 @@ void reds_on_main_channel_migrate(RedsState *reds, MainChannelClient *mcc)
 
     if (agent_dev->priv->read_filter.msg_data_to_read ||
         read_data_len > sizeof(VDAgentMessage)) { /* msg header has been read */
-        RedVDIReadBuf *read_buf = agent_dev->priv->current_read_buf;
+        red::shared_ptr<RedVDIReadBuf> read_buf = std::move(agent_dev->priv->current_read_buf);
 
         spice_debug("push partial read %u (msg first chunk? %d)", read_data_len,
                     !agent_dev->priv->read_filter.msg_data_to_read);
 
         read_buf->len = read_data_len;
-        switch (vdi_port_read_buf_process(agent_dev, read_buf)) {
+        switch (vdi_port_read_buf_process(agent_dev, *read_buf)) {
         case AGENT_MSG_FILTER_OK:
             reds_adjust_agent_capabilities(reds, (VDAgentMessage *)read_buf->data);
-            mcc->push_agent_data(read_buf);
+            mcc->push_agent_data(std::move(read_buf));
             break;
         case AGENT_MSG_FILTER_PROTO_ERROR:
             reds_agent_remove(reds);
@@ -1259,13 +1254,12 @@ void reds_on_main_channel_migrate(RedsState *reds, MainChannelClient *mcc)
         case AGENT_MSG_FILTER_MONITORS_CONFIG:
             /* fall through */
         case AGENT_MSG_FILTER_DISCARD:
-            red_pipe_item_unref(read_buf);
+            read_buf.reset();
         }
 
         spice_assert(agent_dev->priv->receive_len);
         agent_dev->priv->message_receive_len += agent_dev->priv->receive_len;
         agent_dev->priv->read_state = VDI_PORT_READ_STATE_GET_BUFF;
-        agent_dev->priv->current_read_buf = NULL;
         agent_dev->priv->receive_pos = NULL;
     }
 }
@@ -1395,7 +1389,7 @@ static int reds_agent_state_restore(RedsState *reds, SpiceMigrateDataMain *mig_d
         }
     } else {
             agent_dev->priv->read_state = VDI_PORT_READ_STATE_GET_BUFF;
-            agent_dev->priv->current_read_buf = NULL;
+            agent_dev->priv->current_read_buf.reset();
             agent_dev->priv->receive_pos = NULL;
             agent_dev->priv->read_filter.msg_data_to_read = mig_data->agent2client.msg_remaining;
             agent_dev->priv->read_filter.result = (AgentMsgFilterResult) mig_data->agent2client.msg_filter_result;
@@ -4447,10 +4441,7 @@ RedCharDeviceVDIPort::~RedCharDeviceVDIPort()
 {
     /* make sure we have no other references to RedVDIReadBuf buffers */
     reset();
-    if (priv->current_read_buf) {
-        red_pipe_item_unref(priv->current_read_buf);
-        priv->current_read_buf = NULL;
-    }
+    priv->current_read_buf.reset(); // needed to pass the assert below
     g_free(priv->mig_data);
     spice_extra_assert(priv->num_read_buf == 0);
 }
diff --git a/server/smartcard-channel-client.cpp b/server/smartcard-channel-client.cpp
index 051facd1..65c402f3 100644
--- a/server/smartcard-channel-client.cpp
+++ b/server/smartcard-channel-client.cpp
@@ -137,7 +137,7 @@ static void smartcard_channel_client_push_error(RedChannelClient *rcc,
                                                 uint32_t reader_id,
                                                 VSCErrorCode error)
 {
-    RedErrorItem *error_item = new RedErrorItem();
+    auto error_item = red::make_shared<RedErrorItem>();
 
     error_item->vheader.reader_id = reader_id;
     error_item->vheader.type = VSC_Error;
diff --git a/server/smartcard.cpp b/server/smartcard.cpp
index c33844dd..e76ec033 100644
--- a/server/smartcard.cpp
+++ b/server/smartcard.cpp
@@ -71,7 +71,8 @@ struct RedMsgItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_SMARTCARD_DATA> {
     red::glib_unique_ptr<VSCMsgHeader> vheader;
 };
 
-static RedMsgItem *smartcard_new_vsc_msg_item(unsigned int reader_id, const VSCMsgHeader *vheader);
+static red::shared_ptr<RedMsgItem>
+smartcard_new_vsc_msg_item(unsigned int reader_id, const VSCMsgHeader *vheader);
 
 static struct Readers {
     uint32_t num;
@@ -80,8 +81,8 @@ static struct Readers {
 
 static int smartcard_char_device_add_to_readers(RedsState *reds, SpiceCharDeviceInstance *sin);
 
-static RedMsgItem *smartcard_char_device_on_message_from_device(
-    RedCharDeviceSmartcard *dev, VSCMsgHeader *header);
+static red::shared_ptr<RedMsgItem>
+smartcard_char_device_on_message_from_device(RedCharDeviceSmartcard *dev, VSCMsgHeader *header);
 static void smartcard_init(RedsState *reds);
 
 static void smartcard_read_buf_prepare(RedCharDeviceSmartcard *dev, VSCMsgHeader *vheader)
@@ -95,7 +96,7 @@ static void smartcard_read_buf_prepare(RedCharDeviceSmartcard *dev, VSCMsgHeader
     }
 }
 
-RedPipeItem*
+RedPipeItemPtr
 RedCharDeviceSmartcard::read_one_msg_from_device()
 {
     RedCharDeviceSmartcard *dev = this;
@@ -104,8 +105,6 @@ RedCharDeviceSmartcard::read_one_msg_from_device()
     int actual_length;
 
     while (true) {
-        RedMsgItem *msg_to_client;
-
         // it's possible we already got a full message from a previous partial
         // read. In this case we don't need to read any byte
         if (dev->priv->buf_used < sizeof(VSCMsgHeader) ||
@@ -127,22 +126,18 @@ RedCharDeviceSmartcard::read_one_msg_from_device()
         if (dev->priv->buf_used - sizeof(VSCMsgHeader) < actual_length) {
             continue;
         }
-        msg_to_client = smartcard_char_device_on_message_from_device(dev, vheader);
+        auto msg_to_client = smartcard_char_device_on_message_from_device(dev, vheader);
         remaining = dev->priv->buf_used - sizeof(VSCMsgHeader) - actual_length;
         if (remaining > 0) {
             memmove(dev->priv->buf, dev->priv->buf_pos - remaining, remaining);
         }
         dev->priv->buf_pos = dev->priv->buf + remaining;
         dev->priv->buf_used = remaining;
-        if (msg_to_client) {
-            if (dev->priv->scc) {
-                dev->priv->scc->pipe_add_push(msg_to_client);
-            } else {
-                red_pipe_item_unref(msg_to_client);
-            }
+        if (msg_to_client && dev->priv->scc) {
+            dev->priv->scc->pipe_add_push(std::move(msg_to_client));
         }
     }
-    return NULL;
+    return RedPipeItemPtr();
 }
 
 void RedCharDeviceSmartcard::remove_client(RedCharDeviceClientOpaque *opaque)
@@ -153,15 +148,16 @@ void RedCharDeviceSmartcard::remove_client(RedCharDeviceClientOpaque *opaque)
     scc->shutdown();
 }
 
-RedMsgItem *smartcard_char_device_on_message_from_device(RedCharDeviceSmartcard *dev,
-                                                         VSCMsgHeader *vheader)
+red::shared_ptr<RedMsgItem>
+smartcard_char_device_on_message_from_device(RedCharDeviceSmartcard *dev,
+                                             VSCMsgHeader *vheader)
 {
     vheader->type = ntohl(vheader->type);
     vheader->length = ntohl(vheader->length);
     vheader->reader_id = ntohl(vheader->reader_id);
 
     if (vheader->type == VSC_Init) {
-        return NULL;
+        return red::shared_ptr<RedMsgItem>();
     }
     /* We pass any VSC_Error right now - might need to ignore some? */
     if (dev->priv->reader_id == VSCARD_UNDEFINED_READER_ID) {
@@ -170,7 +166,7 @@ RedMsgItem *smartcard_char_device_on_message_from_device(RedCharDeviceSmartcard
                             vheader->type);
     }
     if (dev->priv->scc == NULL) {
-        return NULL;
+        return red::shared_ptr<RedMsgItem>();
     }
     return smartcard_new_vsc_msg_item(dev->priv->reader_id, vheader);
 }
@@ -388,9 +384,10 @@ void SmartCardChannelClient::send_item(RedPipeItem *item)
     begin_send_message();
 }
 
-static RedMsgItem *smartcard_new_vsc_msg_item(unsigned int reader_id, const VSCMsgHeader *vheader)
+static red::shared_ptr<RedMsgItem>
+smartcard_new_vsc_msg_item(unsigned int reader_id, const VSCMsgHeader *vheader)
 {
-    RedMsgItem *msg_item = new RedMsgItem();
+    auto msg_item = red::make_shared<RedMsgItem>();
 
     msg_item->vheader.reset((VSCMsgHeader*) g_memdup(vheader, sizeof(*vheader) + vheader->length));
     /* We patch the reader_id, since the device only knows about itself, and
diff --git a/server/smartcard.h b/server/smartcard.h
index 242413d7..7ac7cc5a 100644
--- a/server/smartcard.h
+++ b/server/smartcard.h
@@ -34,7 +34,7 @@ public:
 protected:
     ~RedCharDeviceSmartcard();
 private:
-    RedPipeItem* read_one_msg_from_device() override;
+    RedPipeItemPtr read_one_msg_from_device() override;
     void remove_client(RedCharDeviceClientOpaque *client) override;
 public: // XXX make private
     red::unique_link<RedCharDeviceSmartcardPrivate> priv;
diff --git a/server/sound.cpp b/server/sound.cpp
index 386463e4..a7d7a11f 100644
--- a/server/sound.cpp
+++ b/server/sound.cpp
@@ -618,6 +618,8 @@ static bool playback_send_mode(PlaybackChannelClient *playback_client)
 
 PersistentPipeItem::PersistentPipeItem()
 {
+    // force this item to stay alive
+    shared_ptr_add_ref(this);
 }
 
 static void snd_send(SndChannelClient * client)
@@ -626,8 +628,8 @@ static void snd_send(SndChannelClient * client)
         return;
     }
     // just append a dummy item and push!
-    red_pipe_item_ref(&client->persistent_pipe_item);
-    client->pipe_add_push(&client->persistent_pipe_item);
+    RedPipeItemPtr item(&client->persistent_pipe_item);
+    client->pipe_add_push(std::move(item));
 }
 
 XXX_CAST(RedChannelClient, PlaybackChannelClient, PLAYBACK_CHANNEL_CLIENT)
diff --git a/server/spicevmc.cpp b/server/spicevmc.cpp
index a290bfbf..c128bc3b 100644
--- a/server/spicevmc.cpp
+++ b/server/spicevmc.cpp
@@ -65,7 +65,7 @@ struct RedCharDeviceSpiceVmc: public RedCharDevice
     RedCharDeviceSpiceVmc(SpiceCharDeviceInstance *sin, RedsState *reds, RedVmcChannel *channel);
     ~RedCharDeviceSpiceVmc();
 
-    virtual RedPipeItem* read_one_msg_from_device() override;
+    virtual RedPipeItemPtr read_one_msg_from_device() override;
     virtual void remove_client(RedCharDeviceClientOpaque *opaque) override;
     virtual void on_free_self_token() override;
     virtual void port_event(uint8_t event) override;
@@ -73,7 +73,7 @@ struct RedCharDeviceSpiceVmc: public RedCharDevice
     red::shared_ptr<RedVmcChannel> channel;
 };
 
-static void spicevmc_red_channel_queue_data(RedVmcChannel *channel, RedVmcPipeItem *item);
+static void spicevmc_red_channel_queue_data(RedVmcChannel *channel, red::shared_ptr<RedVmcPipeItem>&& item);
 
 struct RedVmcChannel: public RedChannel
 {
@@ -86,7 +86,7 @@ struct RedVmcChannel: public RedChannel
     VmcChannelClient *rcc;
     RedCharDevice *chardev; /* weak */
     SpiceCharDeviceInstance *chardev_sin;
-    RedVmcPipeItem *pipe_item;
+    red::shared_ptr<RedVmcPipeItem> pipe_item;
     RedCharDeviceWriteBuffer *recv_from_client_buf;
     uint8_t port_opened;
     uint32_t queued_data;
@@ -162,9 +162,6 @@ RedVmcChannel::RedVmcChannel(RedsState *reds, uint32_t type, uint32_t id):
 RedVmcChannel::~RedVmcChannel()
 {
     RedCharDevice::write_buffer_release(chardev, &recv_from_client_buf);
-    if (pipe_item) {
-        red_pipe_item_unref(pipe_item);
-    }
 }
 
 static red::shared_ptr<RedVmcChannel> red_vmc_channel_new(RedsState *reds, uint8_t channel_type)
@@ -204,24 +201,25 @@ struct RedPortEventPipeItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_PORT_EVENT
  *  - a new pipe item with the compressed data in it upon success
  */
 #ifdef USE_LZ4
-static RedVmcPipeItem* try_compress_lz4(RedVmcChannel *channel, int n, RedVmcPipeItem *msg_item)
+static red::shared_ptr<RedVmcPipeItem>
+try_compress_lz4(RedVmcChannel *channel, int n, RedVmcPipeItem *msg_item)
 {
-    RedVmcPipeItem *msg_item_compressed;
+    red::shared_ptr<RedVmcPipeItem> msg_item_compressed;
     int compressed_data_count;
 
     if (red_stream_get_family(channel->rcc->get_stream()) == AF_UNIX) {
         /* AF_LOCAL - data will not be compressed */
-        return NULL;
+        return msg_item_compressed;
     }
     if (n <= COMPRESS_THRESHOLD) {
         /* n <= threshold - data will not be compressed */
-        return NULL;
+        return msg_item_compressed;
     }
     if (!channel->rcc->test_remote_cap(SPICE_SPICEVMC_CAP_DATA_COMPRESS_LZ4)) {
         /* Client doesn't have compression cap - data will not be compressed */
-        return NULL;
+        return msg_item_compressed;
     }
-    msg_item_compressed = new RedVmcPipeItem();
+    msg_item_compressed = red::make_shared<RedVmcPipeItem>();
     compressed_data_count = LZ4_compress_default((char*)&msg_item->buf,
                                                  (char*)&msg_item_compressed->buf,
                                                  n,
@@ -233,73 +231,72 @@ static RedVmcPipeItem* try_compress_lz4(RedVmcChannel *channel, int n, RedVmcPip
         msg_item_compressed->type = SPICE_DATA_COMPRESSION_TYPE_LZ4;
         msg_item_compressed->uncompressed_data_size = n;
         msg_item_compressed->buf_used = compressed_data_count;
-        g_free(msg_item);
         return msg_item_compressed;
     }
 
     /* LZ4 compression failed or did non compress, fallback a non-compressed data is to be sent */
-    g_free(msg_item_compressed);
-    return NULL;
+    msg_item_compressed.reset();
+    return msg_item_compressed;
 }
 #endif
 
-RedPipeItem* RedCharDeviceSpiceVmc::read_one_msg_from_device()
+RedPipeItemPtr
+RedCharDeviceSpiceVmc::read_one_msg_from_device()
 {
-    RedVmcPipeItem *msg_item;
+    red::shared_ptr<RedVmcPipeItem> msg_item;
     int n;
 
     if (!channel->rcc || channel->queued_data >= QUEUED_DATA_LIMIT) {
-        return NULL;
+        return RedPipeItemPtr();
     }
 
     if (!channel->pipe_item) {
-        msg_item = new RedVmcPipeItem();
+        msg_item = red::make_shared<RedVmcPipeItem>();
         msg_item->type = SPICE_DATA_COMPRESSION_TYPE_NONE;
     } else {
         spice_assert(channel->pipe_item->buf_used == 0);
-        msg_item = channel->pipe_item;
-        channel->pipe_item = NULL;
+        msg_item = std::move(channel->pipe_item);
     }
 
     n = read(msg_item->buf, sizeof(msg_item->buf));
     if (n > 0) {
         spice_debug("read from dev %d", n);
 #ifdef USE_LZ4
-        RedVmcPipeItem *msg_item_compressed;
+        red::shared_ptr<RedVmcPipeItem> msg_item_compressed;
 
-        msg_item_compressed = try_compress_lz4(channel.get(), n, msg_item);
-        if (msg_item_compressed != NULL) {
-            spicevmc_red_channel_queue_data(channel.get(), msg_item_compressed);
-            return NULL;
+        msg_item_compressed = try_compress_lz4(channel.get(), n, msg_item.get());
+        if (msg_item_compressed) {
+            spicevmc_red_channel_queue_data(channel.get(), std::move(msg_item_compressed));
+            return RedPipeItemPtr();
         }
 #endif
         stat_inc_counter(channel->out_data, n);
         msg_item->uncompressed_data_size = n;
         msg_item->buf_used = n;
-        spicevmc_red_channel_queue_data(channel.get(), msg_item);
-        return NULL;
+        spicevmc_red_channel_queue_data(channel.get(), std::move(msg_item));
+        return RedPipeItemPtr();
     }
-    channel->pipe_item = msg_item;
-    return NULL;
+    channel->pipe_item = std::move(msg_item);
+    return RedPipeItemPtr();
 }
 
 static void spicevmc_port_send_init(VmcChannelClient *rcc)
 {
     RedVmcChannel *channel = rcc->get_channel();
     SpiceCharDeviceInstance *sin = channel->chardev_sin;
-    RedPortInitPipeItem *item = new RedPortInitPipeItem();
+    auto item = red::make_shared<RedPortInitPipeItem>();
 
     item->name.reset(g_strdup(sin->portname));
     item->opened = channel->port_opened;
-    rcc->pipe_add_push(item);
+    rcc->pipe_add_push(std::move(item));
 }
 
 static void spicevmc_port_send_event(RedChannelClient *rcc, uint8_t event)
 {
-    RedPortEventPipeItem *item = new RedPortEventPipeItem();
+    auto item = red::make_shared<RedPortEventPipeItem>();
 
     item->event = event;
-    rcc->pipe_add_push(item);
+    rcc->pipe_add_push(std::move(item));
 }
 
 void RedCharDeviceSpiceVmc::remove_client(RedCharDeviceClientOpaque *opaque)
@@ -491,10 +488,10 @@ void VmcChannelClient::release_recv_buf(uint16_t type, uint32_t size, uint8_t *m
 }
 
 static void
-spicevmc_red_channel_queue_data(RedVmcChannel *channel, RedVmcPipeItem *item)
+spicevmc_red_channel_queue_data(RedVmcChannel *channel, red::shared_ptr<RedVmcPipeItem>&& item)
 {
     channel->queued_data += item->buf_used;
-    channel->rcc->pipe_add_push(item);
+    channel->rcc->pipe_add_push(std::move(item));
 }
 
 static void spicevmc_red_channel_send_data(VmcChannelClient *rcc,
diff --git a/server/stream-channel.cpp b/server/stream-channel.cpp
index e9aac846..08285bf6 100644
--- a/server/stream-channel.cpp
+++ b/server/stream-channel.cpp
@@ -424,7 +424,7 @@ StreamChannel::change_format(const StreamMsgFormat *fmt)
     stream_id = (stream_id + 1) % NUM_STREAMS;
 
     // send create stream
-    StreamCreateItem *item = new StreamCreateItem();
+    auto item = red::make_shared<StreamCreateItem>();
     item->stream_create.id = stream_id;
     item->stream_create.flags = SPICE_STREAM_FLAGS_TOP_DOWN;
     item->stream_create.codec_type = fmt->codec;
@@ -434,7 +434,7 @@ StreamChannel::change_format(const StreamMsgFormat *fmt)
     item->stream_create.src_height = fmt->height;
     item->stream_create.dest = (SpiceRect) { 0, 0, fmt->width, fmt->height };
     item->stream_create.clip = (SpiceClip) { SPICE_CLIP_TYPE_NONE, NULL };
-    pipes_add(item);
+    pipes_add(std::move(item));
 
     // activate stream report if possible
     pipes_add_type(RED_PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT);
@@ -473,7 +473,7 @@ StreamChannel::send_data(const void *data, size_t size, uint32_t mm_time)
     update_queue_stat(1, size);
     // TODO try to optimize avoiding the copy
     memcpy(item->data.data, data, size);
-    pipes_add(item);
+    pipes_add(red::shared_ptr<StreamDataItem>(item));
 }
 
 void
diff --git a/server/video-stream.cpp b/server/video-stream.cpp
index 48deb7a9..24a2b920 100644
--- a/server/video-stream.cpp
+++ b/server/video-stream.cpp
@@ -70,22 +70,22 @@ StreamCreateDestroyItem::~StreamCreateDestroyItem()
     video_stream_agent_unref(display, agent);
 }
 
-static RedPipeItem *video_stream_create_destroy_item_new(VideoStreamAgent *agent,
-                                                         int type)
+static RedPipeItemPtr
+video_stream_create_destroy_item_new(VideoStreamAgent *agent, int type)
 {
-    StreamCreateDestroyItem *item = new StreamCreateDestroyItem(type);
+    auto item = red::make_shared<StreamCreateDestroyItem>(type);
 
     agent->stream->refs++;
     item->agent = agent;
     return item;
 }
 
-static RedPipeItem *video_stream_create_item_new(VideoStreamAgent *agent)
+static RedPipeItemPtr video_stream_create_item_new(VideoStreamAgent *agent)
 {
     return video_stream_create_destroy_item_new(agent, RED_PIPE_ITEM_TYPE_STREAM_CREATE);
 }
 
-static RedPipeItem *video_stream_destroy_item_new(VideoStreamAgent *agent)
+static RedPipeItemPtr video_stream_destroy_item_new(VideoStreamAgent *agent)
 {
     return video_stream_create_destroy_item_new(agent, RED_PIPE_ITEM_TYPE_STREAM_DESTROY);
 }
@@ -166,9 +166,9 @@ VideoStreamClipItem::~VideoStreamClipItem()
     video_stream_agent_unref(display, stream_agent);
 }
 
-VideoStreamClipItem *video_stream_clip_item_new(VideoStreamAgent *agent)
+red::shared_ptr<VideoStreamClipItem> video_stream_clip_item_new(VideoStreamAgent *agent)
 {
-    VideoStreamClipItem *item = new VideoStreamClipItem(RED_PIPE_ITEM_TYPE_STREAM_CLIP);
+    auto item = red::make_shared<VideoStreamClipItem>(RED_PIPE_ITEM_TYPE_STREAM_CLIP);
 
     item->stream_agent = agent;
     agent->stream->refs++;
@@ -773,8 +773,8 @@ void dcc_create_stream(DisplayChannelClient *dcc, VideoStream *stream)
     dcc->pipe_add(video_stream_create_item_new(agent));
 
     if (dcc->test_remote_cap(SPICE_DISPLAY_CAP_STREAM_REPORT)) {
-        RedStreamActivateReportItem *report_pipe_item =
-            new RedStreamActivateReportItem(RED_PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT);
+        auto report_pipe_item =
+            red::make_shared<RedStreamActivateReportItem>(RED_PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT);
 
         agent->report_id = rand();
         report_pipe_item->stream_id = stream_id;
@@ -828,7 +828,6 @@ static void dcc_detach_stream_gracefully(DisplayChannelClient *dcc,
 
     if (stream->current &&
         region_contains(&stream->current->tree_item.base.rgn, &agent->vis_region)) {
-        RedUpgradeItem *upgrade_item;
         int n_rects;
 
         /* (1) The caller should detach the drawable from the stream. This will
@@ -841,7 +840,7 @@ static void dcc_detach_stream_gracefully(DisplayChannelClient *dcc,
         }
         spice_debug("stream %d: upgrade by drawable. box ==>", stream_id);
         rect_debug(&stream->current->red_drawable->bbox);
-        upgrade_item = new RedUpgradeItem(RED_PIPE_ITEM_TYPE_UPGRADE);
+        auto upgrade_item = red::make_shared<RedUpgradeItem>(RED_PIPE_ITEM_TYPE_UPGRADE);
         upgrade_item->drawable = stream->current;
         upgrade_item->drawable->refs++;
         n_rects = pixman_region32_n_rects(&upgrade_item->drawable->tree_item.base.rgn);
@@ -850,7 +849,7 @@ static void dcc_detach_stream_gracefully(DisplayChannelClient *dcc,
         upgrade_item->rects->num_rects = n_rects;
         region_ret_rects(&upgrade_item->drawable->tree_item.base.rgn,
                          upgrade_item->rects->rects, n_rects);
-        dcc->pipe_add(upgrade_item);
+        dcc->pipe_add(std::move(upgrade_item));
 
     } else {
         SpiceRect upgrade_area;
diff --git a/server/video-stream.h b/server/video-stream.h
index 18ffe67d..3006962e 100644
--- a/server/video-stream.h
+++ b/server/video-stream.h
@@ -104,7 +104,7 @@ struct VideoStreamClipItem: public RedPipeItem {
     red::glib_unique_ptr<SpiceClipRects> rects;
 };
 
-VideoStreamClipItem *video_stream_clip_item_new(VideoStreamAgent *agent);
+red::shared_ptr<VideoStreamClipItem> video_stream_clip_item_new(VideoStreamAgent *agent);
 
 struct StreamCreateDestroyItem: public RedPipeItem {
     using RedPipeItem::RedPipeItem;
commit 22fc6a48e65b75fbd1dc90c63bdb0df54c6b72e1
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Fri Jun 5 16:33:21 2020 +0100

    red-channel-client: Change GQueue into a std::list
    
    Starts using smart pointers in the queue.
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
    Acked-by: Julien Ropé <jrope at gmail.com>

diff --git a/server/dcc-send.cpp b/server/dcc-send.cpp
index 80ef2da3..687fd70f 100644
--- a/server/dcc-send.cpp
+++ b/server/dcc-send.cpp
@@ -172,11 +172,6 @@ static bool is_brush_lossy(DisplayChannelClient *dcc, SpiceBrush *brush,
     }
 }
 
-static GList *dcc_get_tail(DisplayChannelClient *dcc)
-{
-    return dcc->get_pipe()->tail;
-}
-
 static void red_display_add_image_to_pixmap_cache(DisplayChannelClient *dcc,
                                                   SpiceImage *image, SpiceImage *io_image,
                                                   int is_lossy)
@@ -616,17 +611,14 @@ static bool pipe_rendered_drawables_intersect_with_areas(DisplayChannelClient *d
                                                          SpiceRect *surface_areas[],
                                                          int num_surfaces)
 {
-    GList *l;
-
     spice_assert(num_surfaces);
 
-    for (l = dcc->get_pipe()->head; l != NULL; l = l->next) {
+    for (const auto &pipe_item : dcc->get_pipe()) {
         Drawable *drawable;
-        RedPipeItem *pipe_item = (RedPipeItem *) l->data;
 
         if (pipe_item->type != RED_PIPE_ITEM_TYPE_DRAW)
             continue;
-        drawable = static_cast<RedDrawablePipeItem*>(pipe_item)->drawable;
+        drawable = static_cast<RedDrawablePipeItem*>(pipe_item.get())->drawable;
 
         if (ring_item_is_linked(&drawable->list_link))
             continue; // item hasn't been rendered
@@ -701,26 +693,22 @@ static void red_pipe_replace_rendered_drawables_with_images(DisplayChannelClient
     int resent_surface_ids[MAX_PIPE_SIZE];
     SpiceRect resent_areas[MAX_PIPE_SIZE]; // not pointers since drawables may be released
     int num_resent;
-    GList *l, *prev;
-    GQueue *pipe;
 
     resent_surface_ids[0] = first_surface_id;
     resent_areas[0] = *first_area;
     num_resent = 1;
 
-    pipe = dcc->get_pipe();
+    auto &pipe = dcc->get_pipe();
 
     // going from the oldest to the newest
-    for (l = pipe->tail; l != NULL; l = prev) {
-        RedPipeItem *pipe_item = (RedPipeItem *) l->data;
-        Drawable *drawable;
-        RedDrawablePipeItem *dpi;
+    for (auto l = pipe.end(); l != pipe.begin(); ) {
+        --l;
+        RedPipeItem *pipe_item = l->get();
 
-        prev = l->prev;
         if (pipe_item->type != RED_PIPE_ITEM_TYPE_DRAW)
             continue;
-        dpi = static_cast<RedDrawablePipeItem*>(pipe_item);
-        drawable = dpi->drawable;
+        auto dpi = static_cast<RedDrawablePipeItem*>(pipe_item);
+        auto drawable = dpi->drawable;
         if (ring_item_is_linked(&drawable->list_link))
             continue; // item hasn't been rendered
 
@@ -741,7 +729,7 @@ static void red_pipe_replace_rendered_drawables_with_images(DisplayChannelClient
         resent_areas[num_resent] = drawable->red_drawable->bbox;
         num_resent++;
 
-        dcc->pipe_remove_and_release_pos(l);
+        l = pipe.erase(l);
     }
 }
 
@@ -788,7 +776,7 @@ static void red_add_lossless_drawable_dependencies(DisplayChannelClient *dcc,
         // will be executed before the current drawable
         for (i = 0; i < num_deps; i++) {
             dcc_add_surface_area_image(dcc, deps_surfaces_ids[i], deps_areas[i],
-                                       dcc_get_tail(dcc), FALSE);
+                                       dcc->get_pipe().end(), FALSE);
 
         }
     } else {
@@ -809,7 +797,7 @@ static void red_add_lossless_drawable_dependencies(DisplayChannelClient *dcc,
         }
 
         dcc_add_surface_area_image(dcc, drawable->surface_id, &drawable->bbox,
-                                   dcc_get_tail(dcc), TRUE);
+                                   dcc->get_pipe().end(), TRUE);
     }
 }
 
diff --git a/server/dcc.cpp b/server/dcc.cpp
index c6fb3f61..d16da328 100644
--- a/server/dcc.cpp
+++ b/server/dcc.cpp
@@ -106,21 +106,21 @@ bool dcc_drawable_is_in_pipe(DisplayChannelClient *dcc, Drawable *drawable)
 bool dcc_clear_surface_drawables_from_pipe(DisplayChannelClient *dcc, int surface_id,
                                            int wait_if_used)
 {
-    GList *l;
     int x;
 
     spice_return_val_if_fail(dcc != NULL, TRUE);
     /* removing the newest drawables that their destination is surface_id and
        no other drawable depends on them */
 
-    for (l = dcc->get_pipe()->head; l != NULL; ) {
+    auto &pipe = dcc->get_pipe();
+    for (auto l = pipe.begin(); l != pipe.end(); ) {
         Drawable *drawable;
         RedDrawablePipeItem *dpi = NULL;
         int depend_found = FALSE;
-        RedPipeItem *item = (RedPipeItem *) l->data;
-        GList *item_pos = l;
+        RedPipeItem *item = l->get();
+        auto item_pos = l;
 
-        l = l->next;
+        ++l;
         if (item->type == RED_PIPE_ITEM_TYPE_DRAW) {
             dpi = static_cast<RedDrawablePipeItem*>(item);
             drawable = dpi->drawable;
@@ -131,7 +131,7 @@ bool dcc_clear_surface_drawables_from_pipe(DisplayChannelClient *dcc, int surfac
         }
 
         if (drawable->surface_id == surface_id) {
-            dcc->pipe_remove_and_release_pos(item_pos);
+            l = pipe.erase(item_pos);
             continue;
         }
 
@@ -197,7 +197,8 @@ RedImageItem::RedImageItem():
 // adding the pipe item after pos. If pos == NULL, adding to head.
 void
 dcc_add_surface_area_image(DisplayChannelClient *dcc, int surface_id,
-                           SpiceRect *area, GList *pipe_item_pos, int can_lossy)
+                           SpiceRect *area, RedChannelClient::Pipe::iterator pipe_item_pos,
+                           int can_lossy)
 {
     DisplayChannel *display = DCC_TO_DC(dcc);
     RedSurface *surface = &display->priv->surfaces[surface_id];
@@ -244,7 +245,7 @@ dcc_add_surface_area_image(DisplayChannelClient *dcc, int surface_id,
         }
     }
 
-    if (pipe_item_pos) {
+    if (pipe_item_pos != dcc->get_pipe().end()) {
         dcc->pipe_add_after_pos(item, pipe_item_pos);
     } else {
         dcc->pipe_add(item);
@@ -272,7 +273,7 @@ void dcc_push_surface_image(DisplayChannelClient *dcc, int surface_id)
 
     /* not allowing lossy compression because probably, especially if it is a primary surface,
        it combines both "picture-like" areas with areas that are more "artificial"*/
-    dcc_add_surface_area_image(dcc, surface_id, &area, NULL, FALSE);
+    dcc_add_surface_area_image(dcc, surface_id, &area, dcc->get_pipe().end(), FALSE);
 }
 
 static void add_drawable_surface_images(DisplayChannelClient *dcc, Drawable *drawable)
diff --git a/server/dcc.h b/server/dcc.h
index 3931686d..002da283 100644
--- a/server/dcc.h
+++ b/server/dcc.h
@@ -186,7 +186,8 @@ int                        dcc_compress_image                        (DisplayCha
                                                                       compress_send_data_t* o_comp_data);
 
 void dcc_add_surface_area_image(DisplayChannelClient *dcc, int surface_id,
-                                SpiceRect *area, GList *pipe_item_pos, int can_lossy);
+                                SpiceRect *area, RedChannelClient::Pipe::iterator pipe_item_pos,
+                                int can_lossy);
 VideoStreamAgent *dcc_get_video_stream_agent(DisplayChannelClient *dcc, int stream_id);
 ImageEncoders *dcc_get_encoders(DisplayChannelClient *dcc);
 spice_wan_compression_t    dcc_get_jpeg_state                        (DisplayChannelClient *dcc);
diff --git a/server/red-channel-client.cpp b/server/red-channel-client.cpp
index 017ff7e4..e8827911 100644
--- a/server/red-channel-client.cpp
+++ b/server/red-channel-client.cpp
@@ -156,7 +156,7 @@ struct RedChannelClientPrivate
 
     bool block_read;
     bool during_send;
-    GQueue pipe;
+    RedChannelClient::Pipe pipe;
 
     RedChannelCapabilities remote_caps;
     bool is_mini_header;
@@ -173,7 +173,7 @@ struct RedChannelClientPrivate
     RedStatCounter out_messages;
     RedStatCounter out_bytes;
 
-    inline RedPipeItem *pipe_item_get();
+    inline RedPipeItemPtr pipe_item_get();
     inline bool pipe_remove(RedPipeItem *item);
     void handle_pong(SpiceMsgPing *ping);
     inline void set_message_serial(uint64_t serial);
@@ -307,8 +307,6 @@ RedChannelClientPrivate::RedChannelClientPrivate(RedChannel *init_channel,
 
     send_data.marshaller = send_data.main.marshaller;
 
-    g_queue_init(&pipe);
-
     red_channel_capabilities_reset(&remote_caps);
     red_channel_capabilities_init(&remote_caps, caps);
 
@@ -550,7 +548,7 @@ void RedChannelClient::msg_sent()
         spice_assert(priv->send_data.header.data != NULL);
         begin_send_message();
     } else {
-        if (g_queue_is_empty(&priv->pipe)) {
+        if (priv->pipe.empty()) {
             /* It is possible that the socket will become idle, so we may be able to test latency */
             priv->restart_ping_timer();
         }
@@ -558,9 +556,23 @@ void RedChannelClient::msg_sent()
 
 }
 
+static RedChannelClient::Pipe::iterator
+find_pipe_item(RedChannelClient::Pipe &pipe, const RedPipeItem *item)
+{
+    return std::find_if(pipe.begin(), pipe.end(),
+                        [=](const RedPipeItemPtr& p) -> bool {
+                            return p.get() == item;
+    });
+}
+
 bool RedChannelClientPrivate::pipe_remove(RedPipeItem *item)
 {
-    return g_queue_remove(&pipe, item);
+    auto i = find_pipe_item(pipe, item);
+    if (i != pipe.end()) {
+        pipe.erase(i);
+        return true;
+    }
+    return false;
 }
 
 bool RedChannelClient::test_remote_common_cap(uint32_t cap) const
@@ -1111,17 +1123,21 @@ void RedChannelClient::send()
     handle_outgoing();
 }
 
-inline RedPipeItem *RedChannelClientPrivate::pipe_item_get()
+inline RedPipeItemPtr RedChannelClientPrivate::pipe_item_get()
 {
-    if (send_data.blocked || waiting_for_ack()) {
-        return NULL;
+    RedPipeItemPtr ret;
+
+    if (send_data.blocked || waiting_for_ack() || pipe.empty()) {
+        return ret;
     }
-    return (RedPipeItem*) g_queue_pop_tail(&pipe);
+    ret = std::move(pipe.back());
+    pipe.pop_back();
+    return ret;
 }
 
 void RedChannelClient::push()
 {
-    RedPipeItem *pipe_item;
+    RedPipeItemPtr pipe_item;
 
     if (priv->during_send) {
         return;
@@ -1140,7 +1156,7 @@ void RedChannelClient::push()
     }
 
     while ((pipe_item = priv->pipe_item_get())) {
-        send_any_item(pipe_item);
+        send_any_item(pipe_item.get());
     }
     /* prepare_pipe_add() will reenable WRITE events when the priv->pipe is empty
      * ack_zero_messages_window() will reenable WRITE events
@@ -1149,7 +1165,7 @@ void RedChannelClient::push()
      * notified that we can write and we then exit (see pipe_item_get) as we
      * are waiting for the ack consuming CPU in a tight loop
      */
-    if ((no_item_being_sent() && g_queue_is_empty(&priv->pipe)) ||
+    if ((no_item_being_sent() && priv->pipe.empty()) ||
         priv->waiting_for_ack()) {
         priv->watch_update_mask(SPICE_WATCH_EVENT_READ);
 
@@ -1357,7 +1373,7 @@ inline bool RedChannelClient::prepare_pipe_add(RedPipeItem *item)
         red_pipe_item_unref(item);
         return false;
     }
-    if (g_queue_is_empty(&priv->pipe)) {
+    if (priv->pipe.empty()) {
         priv->watch_update_mask(SPICE_WATCH_EVENT_READ | SPICE_WATCH_EVENT_WRITE);
     }
     return true;
@@ -1365,11 +1381,10 @@ inline bool RedChannelClient::prepare_pipe_add(RedPipeItem *item)
 
 void RedChannelClient::pipe_add(RedPipeItem *item)
 {
-
     if (!prepare_pipe_add(item)) {
         return;
     }
-    g_queue_push_head(&priv->pipe, item);
+    priv->pipe.push_front(RedPipeItemPtr(item));
 }
 
 void RedChannelClient::pipe_add_push(RedPipeItem *item)
@@ -1379,41 +1394,40 @@ void RedChannelClient::pipe_add_push(RedPipeItem *item)
 }
 
 void RedChannelClient::pipe_add_after_pos(RedPipeItem *item,
-                                          GList *pipe_item_pos)
+                                          Pipe::iterator pipe_item_pos)
 {
-    spice_assert(pipe_item_pos);
+    spice_assert(pipe_item_pos != priv->pipe.end());
     if (!prepare_pipe_add(item)) {
         return;
     }
 
-    g_queue_insert_after(&priv->pipe, pipe_item_pos, item);
+    ++pipe_item_pos;
+    priv->pipe.insert(pipe_item_pos, RedPipeItemPtr(item));
 }
 
 void
-RedChannelClient::pipe_add_before_pos(RedPipeItem *item, GList *pipe_item_pos)
+RedChannelClient::pipe_add_before_pos(RedPipeItem *item, Pipe::iterator pipe_item_pos)
 {
-    spice_assert(pipe_item_pos);
+    spice_assert(pipe_item_pos != priv->pipe.end());
     if (!prepare_pipe_add(item)) {
         return;
     }
 
-    g_queue_insert_before(&priv->pipe, pipe_item_pos, item);
+    priv->pipe.insert(pipe_item_pos, RedPipeItemPtr(item));
 }
 
 void RedChannelClient::pipe_add_after(RedPipeItem *item, RedPipeItem *pos)
 {
-    GList *prev;
-
     spice_assert(pos);
-    prev = g_queue_find(&priv->pipe, pos);
-    g_return_if_fail(prev != NULL);
+    auto prev = find_pipe_item(priv->pipe, pos);
+    g_return_if_fail(prev != priv->pipe.end());
 
     pipe_add_after_pos(item, prev);
 }
 
 int RedChannelClient::pipe_item_is_linked(RedPipeItem *item)
 {
-    return g_queue_find(&priv->pipe, item) != NULL;
+    return find_pipe_item(priv->pipe, item) != priv->pipe.end();
 }
 
 void RedChannelClient::pipe_add_tail(RedPipeItem *item)
@@ -1421,7 +1435,7 @@ void RedChannelClient::pipe_add_tail(RedPipeItem *item)
     if (!prepare_pipe_add(item)) {
         return;
     }
-    g_queue_push_tail(&priv->pipe, item);
+    priv->pipe.push_back(RedPipeItemPtr(item));
 }
 
 void RedChannelClient::pipe_add_type(int pipe_item_type)
@@ -1446,17 +1460,17 @@ void RedChannelClient::pipe_add_empty_msg(int msg_type)
 
 gboolean RedChannelClient::pipe_is_empty()
 {
-    return g_queue_is_empty(&priv->pipe);
+    return priv->pipe.empty();
 }
 
 uint32_t RedChannelClient::get_pipe_size()
 {
-    return g_queue_get_length(&priv->pipe);
+    return priv->pipe.size();
 }
 
-GQueue* RedChannelClient::get_pipe()
+RedChannelClient::Pipe& RedChannelClient::get_pipe()
 {
-    return &priv->pipe;
+    return priv->pipe;
 }
 
 bool RedChannelClient::is_mini_header() const
@@ -1481,12 +1495,8 @@ void RedChannelClientPrivate::clear_sent_item()
 // are we reading from an fd here? arghh
 void RedChannelClientPrivate::pipe_clear()
 {
-    RedPipeItem *item;
-
     clear_sent_item();
-    while ((item = (RedPipeItem*) g_queue_pop_head(&pipe)) != NULL) {
-        red_pipe_item_unref(item);
-    }
+    pipe.clear();
 }
 
 void RedChannelClient::ack_zero_messages_window()
@@ -1561,7 +1571,7 @@ void RedChannelClient::set_header_sub_list(uint32_t sub_list)
 }
 
 /* TODO: more evil sync stuff. anything with the word wait in it's name. */
-bool RedChannelClient::wait_pipe_item_sent(GList *item_pos, int64_t timeout)
+bool RedChannelClient::wait_pipe_item_sent(Pipe::iterator item_pos, int64_t timeout)
 {
     uint64_t end_time;
 
@@ -1638,14 +1648,6 @@ void RedChannelClient::pipe_remove_and_release(RedPipeItem *item)
     }
 }
 
-void RedChannelClient::pipe_remove_and_release_pos(GList *item_pos)
-{
-    RedPipeItem *item = (RedPipeItem*) item_pos->data;
-
-    g_queue_delete_link(&priv->pipe, item_pos);
-    red_pipe_item_unref(item);
-}
-
 /* client mutex should be locked before this call */
 bool RedChannelClient::set_migration_seamless()
 {
diff --git a/server/red-channel-client.h b/server/red-channel-client.h
index 5092f2f0..69099882 100644
--- a/server/red-channel-client.h
+++ b/server/red-channel-client.h
@@ -18,12 +18,14 @@
 #ifndef RED_CHANNEL_CLIENT_H_
 #define RED_CHANNEL_CLIENT_H_
 
+#include <list>
 #include <common/marshaller.h>
 
 #include "red-pipe-item.h"
 #include "red-stream.h"
 #include "red-channel.h"
 #include "utils.hpp"
+#include "safe-list.hpp"
 
 #include "push-visibility.h"
 
@@ -81,13 +83,14 @@ protected:
     void start_connectivity_monitoring(uint32_t timeout_ms);
 
 public:
+    typedef std::list<RedPipeItemPtr, red::Mallocator<RedPipeItemPtr>> Pipe;
+
     void pipe_add_push(RedPipeItem *item);
     void pipe_add(RedPipeItem *item);
     void pipe_add_after(RedPipeItem *item, RedPipeItem *pos);
-    void pipe_add_after_pos(RedPipeItem *item, GList *pos);
+    void pipe_add_after_pos(RedPipeItem *item, RedChannelClient::Pipe::iterator pos);
     int pipe_item_is_linked(RedPipeItem *item);
     void pipe_remove_and_release(RedPipeItem *item);
-    void pipe_remove_and_release_pos(GList *item_pos);
     void pipe_add_tail(RedPipeItem *item);
     /* for types that use this routine -> the pipe item should be freed */
     void pipe_add_type(int pipe_item_type);
@@ -95,7 +98,7 @@ public:
     void pipe_add_empty_msg(int msg_type);
     gboolean pipe_is_empty();
     uint32_t get_pipe_size();
-    GQueue* get_pipe();
+    Pipe& get_pipe();
     bool is_mini_header() const;
 
     void ack_zero_messages_window();
@@ -130,7 +133,7 @@ public:
      * Return: TRUE if waiting succeeded. FALSE if timeout expired.
      */
 
-    bool wait_pipe_item_sent(GList *item_pos, int64_t timeout);
+    bool wait_pipe_item_sent(RedChannelClient::Pipe::iterator item_pos, int64_t timeout);
     bool wait_outgoing_item(int64_t timeout);
 
     RedChannel* get_channel();
@@ -181,7 +184,7 @@ private:
     virtual void handle_migrate_flush_mark();
     void handle_migrate_data_early(uint32_t size, void *message);
     inline bool prepare_pipe_add(RedPipeItem *item);
-    void pipe_add_before_pos(RedPipeItem *item, GList *pipe_item_pos);
+    void pipe_add_before_pos(RedPipeItem *item, RedChannelClient::Pipe::iterator pipe_item_pos);
     void send_set_ack();
     void send_migrate();
     void send_empty_msg(RedPipeItem *base);
diff --git a/server/red-pipe-item.h b/server/red-pipe-item.h
index e0c5c630..e77f241b 100644
--- a/server/red-pipe-item.h
+++ b/server/red-pipe-item.h
@@ -64,6 +64,8 @@ struct RedPipeItem: public red::shared_ptr_counted
     void add_to_marshaller(SpiceMarshaller *m, uint8_t *data, size_t size);
 };
 
+typedef red::shared_ptr<RedPipeItem> RedPipeItemPtr;
+
 RedPipeItem *red_pipe_item_ref(RedPipeItem *item);
 void red_pipe_item_unref(RedPipeItem *item);
 
diff --git a/server/video-stream.cpp b/server/video-stream.cpp
index 578afae7..48deb7a9 100644
--- a/server/video-stream.cpp
+++ b/server/video-stream.cpp
@@ -864,7 +864,7 @@ static void dcc_detach_stream_gracefully(DisplayChannelClient *dcc,
         } else {
             display_channel_draw(display, &upgrade_area, 0);
         }
-        dcc_add_surface_area_image(dcc, 0, &upgrade_area, NULL, FALSE);
+        dcc_add_surface_area_image(dcc, 0, &upgrade_area, dcc->get_pipe().end(), FALSE);
     }
 clear_vis_region:
     region_clear(&agent->vis_region);
commit 586e45f185ccee31f30516a9525923f4dbdd63bd
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Mon Jun 8 10:32:52 2020 +0100

    cursor-channel: Remove cursor_pipe_item_new function, use constructor
    
    This is a preparation to move to smart pointers.
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
    Acked-by: Julien Ropé <jrope at gmail.com>

diff --git a/server/cursor-channel.cpp b/server/cursor-channel.cpp
index 33c3cb7f..2dd0a4be 100644
--- a/server/cursor-channel.cpp
+++ b/server/cursor-channel.cpp
@@ -26,19 +26,14 @@
 #include "reds.h"
 
 struct RedCursorPipeItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_CURSOR> {
+    RedCursorPipeItem(RedCursorCmd *cmd);
     ~RedCursorPipeItem();
     RedCursorCmd *red_cursor;
 };
 
-static RedCursorPipeItem *cursor_pipe_item_new(RedCursorCmd *cmd)
+RedCursorPipeItem::RedCursorPipeItem(RedCursorCmd *cmd):
+    red_cursor(red_cursor_cmd_ref(cmd))
 {
-    RedCursorPipeItem *item = new RedCursorPipeItem();
-
-    spice_return_val_if_fail(cmd != NULL, NULL);
-
-    item->red_cursor = red_cursor_cmd_ref(cmd);
-
-    return item;
 }
 
 RedCursorPipeItem::~RedCursorPipeItem()
@@ -201,7 +196,7 @@ void CursorChannel::process_cmd(RedCursorCmd *cursor_cmd)
 
     spice_return_if_fail(cursor_cmd);
 
-    cursor_pipe_item = cursor_pipe_item_new(cursor_cmd);
+    cursor_pipe_item = new RedCursorPipeItem(cursor_cmd);
 
     switch (cursor_cmd->type) {
     case QXL_CURSOR_SET:
commit bd6d0431520873ecc5ffdb2688f519d1fcead6d1
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Fri Jun 5 15:27:03 2020 +0100

    Remove some red_pipe_item_(un)ref usage
    
    Replace with smart pointers instead.
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
    Acked-by: Julien Ropé <jrope at gmail.com>

diff --git a/server/cursor-channel.cpp b/server/cursor-channel.cpp
index 99748025..33c3cb7f 100644
--- a/server/cursor-channel.cpp
+++ b/server/cursor-channel.cpp
@@ -48,13 +48,7 @@ RedCursorPipeItem::~RedCursorPipeItem()
 
 static void cursor_channel_set_item(CursorChannel *cursor, RedCursorPipeItem *item)
 {
-    if (item) {
-        red_pipe_item_ref(item);
-    }
-    if (cursor->item) {
-        red_pipe_item_unref(cursor->item);
-    }
-    cursor->item = item;
+    cursor->item.reset(item);
 }
 
 static void cursor_fill(CursorChannelClient *ccc, RedCursorPipeItem *cursor,
@@ -101,7 +95,7 @@ static void red_marshall_cursor_init(CursorChannelClient *ccc, SpiceMarshaller *
     msg.trail_length = cursor_channel->cursor_trail_length;
     msg.trail_frequency = cursor_channel->cursor_trail_frequency;
 
-    cursor_fill(ccc, cursor_channel->item, &msg.cursor, base_marshaller);
+    cursor_fill(ccc, cursor_channel->item.get(), &msg.cursor, base_marshaller);
     spice_marshall_msg_cursor_init(base_marshaller, &msg);
 }
 
@@ -308,9 +302,6 @@ void CursorChannel::on_connect(RedClient *client, RedStream *stream, int migrati
 
 CursorChannel::~CursorChannel()
 {
-    if (item) {
-        red_pipe_item_unref(item);
-    }
 }
 
 CursorChannel::CursorChannel(RedsState *reds, uint32_t id,
diff --git a/server/cursor-channel.h b/server/cursor-channel.h
index d223c965..f0f59436 100644
--- a/server/cursor-channel.h
+++ b/server/cursor-channel.h
@@ -43,7 +43,7 @@ struct CursorChannel final: public CommonGraphicsChannel
     void on_connect(RedClient *client, RedStream *stream, int migration,
                     RedChannelCapabilities *caps) override;
 
-    RedCursorPipeItem *item;
+    red::shared_ptr<RedCursorPipeItem> item;
     bool cursor_visible = true;
     SpicePoint16 cursor_position;
     uint16_t cursor_trail_length;
diff --git a/server/red-channel-client.cpp b/server/red-channel-client.cpp
index 900d6eaf..017ff7e4 100644
--- a/server/red-channel-client.cpp
+++ b/server/red-channel-client.cpp
@@ -1564,7 +1564,6 @@ void RedChannelClient::set_header_sub_list(uint32_t sub_list)
 bool RedChannelClient::wait_pipe_item_sent(GList *item_pos, int64_t timeout)
 {
     uint64_t end_time;
-    bool item_sent;
 
     spice_debug("trace");
 
@@ -1574,11 +1573,10 @@ bool RedChannelClient::wait_pipe_item_sent(GList *item_pos, int64_t timeout)
         end_time = UINT64_MAX;
     }
 
-    MarkerPipeItem *mark_item = new MarkerPipeItem();
+    auto mark_item = red::make_shared<MarkerPipeItem>();
 
     mark_item->item_sent = false;
-    red_pipe_item_ref(mark_item);
-    pipe_add_before_pos(mark_item, item_pos);
+    pipe_add_before_pos(mark_item.get(), item_pos);
 
     for (;;) {
         receive();
@@ -1590,15 +1588,11 @@ bool RedChannelClient::wait_pipe_item_sent(GList *item_pos, int64_t timeout)
         usleep(CHANNEL_BLOCKED_SLEEP_DURATION);
     }
 
-    item_sent = mark_item->item_sent;
-    red_pipe_item_unref(mark_item);
-
-    if (!item_sent) {
+    if (!mark_item->item_sent) {
         // still on the queue
         spice_warning("timeout");
-        return FALSE;
     }
-    return TRUE;
+    return mark_item->item_sent;
 }
 
 bool RedChannelClient::wait_outgoing_item(int64_t timeout)
commit 93405ae3c64212c751c24ec9d466ab605b3fadd8
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Tue May 5 04:54:46 2020 +0100

    Automatically release some pipe item resources
    
    Now that items are managed by constructors/destructors avoid some
    manual releases.
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
    Acked-by: Julien Ropé <jrope at gmail.com>

diff --git a/server/dcc-send.cpp b/server/dcc-send.cpp
index 641b8c06..80ef2da3 100644
--- a/server/dcc-send.cpp
+++ b/server/dcc-send.cpp
@@ -2158,7 +2158,7 @@ static void marshall_stream_clip(DisplayChannelClient *dcc,
 
     stream_clip.id = display_channel_get_video_stream_id(DCC_TO_DC(dcc), agent->stream);
     stream_clip.clip.type = item->clip_type;
-    stream_clip.clip.rects = item->rects;
+    stream_clip.clip.rects = item->rects.get();
 
     spice_marshall_msg_display_stream_clip(base_marshaller, &stream_clip);
 }
@@ -2194,7 +2194,7 @@ static void marshall_upgrade(DisplayChannelClient *dcc, SpiceMarshaller *m,
     copy.base.surface_id = 0;
     copy.base.box = red_drawable->bbox;
     copy.base.clip.type = SPICE_CLIP_TYPE_RECTS;
-    copy.base.clip.rects = item->rects;
+    copy.base.clip.rects = item->rects.get();
     copy.data = red_drawable->u.copy;
 
     spice_marshall_msg_display_draw_copy(m, &copy,
diff --git a/server/main-channel-client.cpp b/server/main-channel-client.cpp
index 6423ecc0..eb82614c 100644
--- a/server/main-channel-client.cpp
+++ b/server/main-channel-client.cpp
@@ -87,8 +87,7 @@ struct RedUuidPipeItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_MAIN_UUID> {
 };
 
 struct RedNotifyPipeItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_MAIN_NOTIFY> {
-    ~RedNotifyPipeItem();
-    char *msg;
+    red::glib_unique_ptr<char> msg;
 };
 
 struct RedMouseModePipeItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_MAIN_MOUSE_MODE> {
@@ -143,16 +142,11 @@ void MainChannelClient::on_disconnect()
 
 static void main_channel_client_push_ping(MainChannelClient *mcc, int size);
 
-RedNotifyPipeItem::~RedNotifyPipeItem()
-{
-    g_free(msg);
-}
-
 static RedPipeItem *main_notify_item_new(const char *msg, int num)
 {
     RedNotifyPipeItem *item = new RedNotifyPipeItem();
 
-    item->msg = g_strdup(msg);
+    item->msg.reset(g_strdup(msg));
     return item;
 }
 
@@ -675,9 +669,9 @@ static void main_channel_marshall_notify(RedChannelClient *rcc,
     notify.severity = SPICE_NOTIFY_SEVERITY_WARN;
     notify.visibilty = SPICE_NOTIFY_VISIBILITY_HIGH;
     notify.what = SPICE_WARN_GENERAL;
-    notify.message_len = strlen(item->msg);
+    notify.message_len = strlen(item->msg.get());
     spice_marshall_msg_notify(m, &notify);
-    spice_marshaller_add(m, (uint8_t *)item->msg, notify.message_len + 1);
+    spice_marshaller_add(m, (uint8_t *)item->msg.get(), notify.message_len + 1);
 }
 
 static void main_channel_fill_migrate_dst_info(MainChannel *main_channel,
diff --git a/server/smartcard.cpp b/server/smartcard.cpp
index f968c6ed..c33844dd 100644
--- a/server/smartcard.cpp
+++ b/server/smartcard.cpp
@@ -68,8 +68,7 @@ struct RedCharDeviceSmartcardPrivate {
 };
 
 struct RedMsgItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_SMARTCARD_DATA> {
-    ~RedMsgItem();
-    VSCMsgHeader* vheader;
+    red::glib_unique_ptr<VSCMsgHeader> vheader;
 };
 
 static RedMsgItem *smartcard_new_vsc_msg_item(unsigned int reader_id, const VSCMsgHeader *vheader);
@@ -339,7 +338,7 @@ static void smartcard_channel_send_msg(RedChannelClient *rcc,
 {
     RedMsgItem* msg_item = static_cast<RedMsgItem*>(item);
 
-    smartcard_channel_client_send_data(rcc, m, item, msg_item->vheader);
+    smartcard_channel_client_send_data(rcc, m, item, msg_item->vheader.get());
 }
 
 static void smartcard_channel_send_migrate_data(SmartCardChannelClient *scc,
@@ -389,16 +388,11 @@ void SmartCardChannelClient::send_item(RedPipeItem *item)
     begin_send_message();
 }
 
-RedMsgItem::~RedMsgItem()
-{
-    g_free(vheader);
-}
-
 static RedMsgItem *smartcard_new_vsc_msg_item(unsigned int reader_id, const VSCMsgHeader *vheader)
 {
     RedMsgItem *msg_item = new RedMsgItem();
 
-    msg_item->vheader = (VSCMsgHeader*) g_memdup(vheader, sizeof(*vheader) + vheader->length);
+    msg_item->vheader.reset((VSCMsgHeader*) g_memdup(vheader, sizeof(*vheader) + vheader->length));
     /* We patch the reader_id, since the device only knows about itself, and
      * we know about the sum of readers. */
     msg_item->vheader->reader_id = reader_id;
diff --git a/server/spicevmc.cpp b/server/spicevmc.cpp
index 8919cc4f..a290bfbf 100644
--- a/server/spicevmc.cpp
+++ b/server/spicevmc.cpp
@@ -189,9 +189,7 @@ static red::shared_ptr<RedVmcChannel> red_vmc_channel_new(RedsState *reds, uint8
 }
 
 struct RedPortInitPipeItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_PORT_INIT> {
-    ~RedPortInitPipeItem();
-
-    char* name;
+    red::glib_unique_ptr<char> name;
     uint8_t opened;
 };
 
@@ -285,18 +283,13 @@ RedPipeItem* RedCharDeviceSpiceVmc::read_one_msg_from_device()
     return NULL;
 }
 
-RedPortInitPipeItem::~RedPortInitPipeItem()
-{
-    g_free(name);
-}
-
 static void spicevmc_port_send_init(VmcChannelClient *rcc)
 {
     RedVmcChannel *channel = rcc->get_channel();
     SpiceCharDeviceInstance *sin = channel->chardev_sin;
     RedPortInitPipeItem *item = new RedPortInitPipeItem();
 
-    item->name = g_strdup(sin->portname);
+    item->name.reset(g_strdup(sin->portname));
     item->opened = channel->port_opened;
     rcc->pipe_add_push(item);
 }
@@ -556,8 +549,8 @@ static void spicevmc_red_channel_send_port_init(RedChannelClient *rcc,
     SpiceMsgPortInit init;
 
     rcc->init_send_data(SPICE_MSG_PORT_INIT);
-    init.name = (uint8_t *)i->name;
-    init.name_size = strlen(i->name) + 1;
+    init.name = (uint8_t *)i->name.get();
+    init.name_size = strlen(i->name.get()) + 1;
     init.opened = i->opened;
     spice_marshall_msg_port_init(m, &init);
 }
diff --git a/server/video-stream.cpp b/server/video-stream.cpp
index 02d01e32..578afae7 100644
--- a/server/video-stream.cpp
+++ b/server/video-stream.cpp
@@ -164,7 +164,6 @@ VideoStreamClipItem::~VideoStreamClipItem()
     DisplayChannel *display = DCC_TO_DC(stream_agent->dcc);
 
     video_stream_agent_unref(display, stream_agent);
-    g_free(rects);
 }
 
 VideoStreamClipItem *video_stream_clip_item_new(VideoStreamAgent *agent)
@@ -177,7 +176,8 @@ VideoStreamClipItem *video_stream_clip_item_new(VideoStreamAgent *agent)
     item->clip_type = SPICE_CLIP_TYPE_RECTS;
 
     int n_rects = pixman_region32_n_rects(&agent->clip);
-    item->rects = (SpiceClipRects*) g_malloc(sizeof(SpiceClipRects) + n_rects * sizeof(SpiceRect));
+    item->rects.reset((SpiceClipRects*) g_malloc(sizeof(SpiceClipRects) +
+                                                 n_rects * sizeof(SpiceRect)));
     item->rects->num_rects = n_rects;
     region_ret_rects(&agent->clip, item->rects->rects, n_rects);
 
@@ -803,7 +803,6 @@ void video_stream_agent_stop(VideoStreamAgent *agent)
 RedUpgradeItem::~RedUpgradeItem()
 {
     drawable_unref(drawable);
-    g_free(rects);
 }
 
 /*
@@ -846,7 +845,8 @@ static void dcc_detach_stream_gracefully(DisplayChannelClient *dcc,
         upgrade_item->drawable = stream->current;
         upgrade_item->drawable->refs++;
         n_rects = pixman_region32_n_rects(&upgrade_item->drawable->tree_item.base.rgn);
-        upgrade_item->rects = (SpiceClipRects*) g_malloc(sizeof(SpiceClipRects) + n_rects * sizeof(SpiceRect));
+        upgrade_item->rects.reset((SpiceClipRects*) g_malloc(sizeof(SpiceClipRects) +
+                                                             n_rects * sizeof(SpiceRect)));
         upgrade_item->rects->num_rects = n_rects;
         region_ret_rects(&upgrade_item->drawable->tree_item.base.rgn,
                          upgrade_item->rects->rects, n_rects);
diff --git a/server/video-stream.h b/server/video-stream.h
index e35d740f..18ffe67d 100644
--- a/server/video-stream.h
+++ b/server/video-stream.h
@@ -53,7 +53,7 @@ struct RedUpgradeItem: public RedPipeItem {
     using RedPipeItem::RedPipeItem;
     ~RedUpgradeItem();
     Drawable *drawable;
-    SpiceClipRects *rects;
+    red::glib_unique_ptr<SpiceClipRects> rects;
 };
 
 struct RedStreamActivateReportItem: public RedPipeItem {
@@ -101,7 +101,7 @@ struct VideoStreamClipItem: public RedPipeItem {
     ~VideoStreamClipItem();
     VideoStreamAgent *stream_agent;
     int clip_type;
-    SpiceClipRects *rects;
+    red::glib_unique_ptr<SpiceClipRects> rects;
 };
 
 VideoStreamClipItem *video_stream_clip_item_new(VideoStreamAgent *agent);
commit fa404f73d89488c9bdbe0424292969f9e180bb1e
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Sun Jun 7 11:38:56 2020 +0100

    main-channel-client: Pass directly a RedPipeItem from VDI
    
    Provides a base class to allows RedCharDeviceVDIPort to pass
    a RedPipeItem to MainChannelClient instead of having to wrap
    into another item.
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
    Acked-by: Julien Ropé <jrope at gmail.com>

diff --git a/server/main-channel-client.cpp b/server/main-channel-client.cpp
index 67b82c07..6423ecc0 100644
--- a/server/main-channel-client.cpp
+++ b/server/main-channel-client.cpp
@@ -69,14 +69,6 @@ struct RedTokensPipeItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_MAIN_AGENT_TO
     int tokens;
 };
 
-struct RedAgentDataPipeItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_MAIN_AGENT_DATA> {
-    ~RedAgentDataPipeItem();
-    uint8_t* data;
-    size_t len;
-    spice_marshaller_item_free_func free_data;
-    void *opaque;
-};
-
 struct RedInitPipeItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_MAIN_INIT> {
     int connection_id;
     int display_channels_hint;
@@ -213,31 +205,8 @@ void MainChannelClient::push_agent_tokens(uint32_t num_tokens)
     pipe_add_push(item);
 }
 
-RedAgentDataPipeItem::~RedAgentDataPipeItem()
-{
-    free_data(data, opaque);
-}
-
-static RedPipeItem *main_agent_data_item_new(uint8_t* data, size_t len,
-                                             spice_marshaller_item_free_func free_data,
-                                             void *opaque)
-{
-    RedAgentDataPipeItem *item = new RedAgentDataPipeItem();
-
-    item->data = data;
-    item->len = len;
-    item->free_data = free_data;
-    item->opaque = opaque;
-    return item;
-}
-
-void MainChannelClient::push_agent_data(uint8_t *data, size_t len,
-                                        spice_marshaller_item_free_func free_data,
-                                        void *opaque)
+void MainChannelClient::push_agent_data(RedAgentDataPipeItem *item)
 {
-    RedPipeItem *item;
-
-    item = main_agent_data_item_new(data, len, free_data, opaque);
     pipe_add_push(item);
 }
 
diff --git a/server/main-channel-client.h b/server/main-channel-client.h
index 59324669..c7973d29 100644
--- a/server/main-channel-client.h
+++ b/server/main-channel-client.h
@@ -32,13 +32,13 @@ MainChannelClient *main_channel_client_create(MainChannel *main_chan, RedClient
                                               RedStream *stream, uint32_t connection_id,
                                               RedChannelCapabilities *caps);
 
+struct RedAgentDataPipeItem;
 
 class MainChannelClient final: public RedChannelClient
 {
 public:
     void push_agent_tokens(uint32_t num_tokens);
-    void push_agent_data(uint8_t *data, size_t len,
-                         spice_marshaller_item_free_func free_data, void *opaque);
+    void push_agent_data(RedAgentDataPipeItem *item);
     // TODO: huge. Consider making a reds_* interface for these functions
     // and calling from main.
     void push_init(int display_channels_hint, SpiceMouseMode current_mouse_mode,
@@ -115,6 +115,11 @@ enum {
     RED_PIPE_ITEM_TYPE_MAIN_REGISTERED_CHANNEL,
 };
 
+struct RedAgentDataPipeItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_MAIN_AGENT_DATA> {
+    int len = 0;
+    uint8_t data[SPICE_AGENT_MAX_DATA_SIZE];
+};
+
 RedPipeItem *main_mouse_mode_item_new(SpiceMouseMode current_mode, int is_client_mouse_allowed);
 
 RedPipeItem *main_multi_media_time_item_new(uint32_t mm_time);
diff --git a/server/reds.cpp b/server/reds.cpp
index ade19487..94a0d703 100644
--- a/server/reds.cpp
+++ b/server/reds.cpp
@@ -153,16 +153,10 @@ struct ChannelSecurityOptions {
     ChannelSecurityOptions *next;
 };
 
-/* Bogus pipe item type, we only need the RingItem and refcounting
- * from the base class and are not going to use the type
- */
-struct RedVDIReadBuf final: public RedPipeItemNum<-1> {
+struct RedVDIReadBuf final: public RedAgentDataPipeItem {
     ~RedVDIReadBuf();
 
     RedCharDeviceVDIPort *dev;
-
-    int len;
-    uint8_t data[SPICE_AGENT_MAX_DATA_SIZE];
 };
 
 typedef enum {
@@ -658,12 +652,6 @@ static void reds_agent_remove(RedsState *reds)
     }
 }
 
-static void vdi_port_read_buf_release(uint8_t *data, void *opaque)
-{
-    RedVDIReadBuf *read_buf = (RedVDIReadBuf *)opaque;
-    red_pipe_item_unref(read_buf);
-}
-
 /*
     returns the #AgentMsgFilterResult value:
         AGENT_MSG_FILTER_OK if the buffer can be forwarded,
@@ -701,7 +689,6 @@ static RedVDIReadBuf *vdi_read_buf_new(RedCharDeviceVDIPort *dev)
 {
     RedVDIReadBuf *buf = new RedVDIReadBuf();
     buf->dev = dev;
-    buf->len = 0;
     return buf;
 }
 
@@ -907,10 +894,7 @@ void RedCharDeviceVDIPort::send_msg_to_client(RedPipeItem *msg, RedCharDeviceCli
     RedVDIReadBuf *agent_data_buf = static_cast<RedVDIReadBuf*>(msg);
 
     red_pipe_item_ref(msg);
-    client->get_main()->push_agent_data(agent_data_buf->data,
-                                        agent_data_buf->len,
-                                        vdi_port_read_buf_release,
-                                        agent_data_buf);
+    client->get_main()->push_agent_data(agent_data_buf);
 }
 
 void RedCharDeviceVDIPort::send_tokens_to_client(RedCharDeviceClientOpaque *opaque, uint32_t tokens)
@@ -1267,8 +1251,7 @@ void reds_on_main_channel_migrate(RedsState *reds, MainChannelClient *mcc)
         switch (vdi_port_read_buf_process(agent_dev, read_buf)) {
         case AGENT_MSG_FILTER_OK:
             reds_adjust_agent_capabilities(reds, (VDAgentMessage *)read_buf->data);
-            mcc->push_agent_data(read_buf->data, read_buf->len,
-                                 vdi_port_read_buf_release, read_buf);
+            mcc->push_agent_data(read_buf);
             break;
         case AGENT_MSG_FILTER_PROTO_ERROR:
             reds_agent_remove(reds);
commit d55c8837f87018404c7224c04d78d88c906ebd8b
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Tue May 5 04:54:46 2020 +0100

    red-pipe-item: Add and use a small utility class for easier initialization
    
    Most of the times each class has an associated constant so
    allows to be able to define the constant at declaration time.
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
    Acked-by: Julien Ropé <jrope at gmail.com>

diff --git a/server/common-graphics-channel.cpp b/server/common-graphics-channel.cpp
index 2a415d65..c7cac7e9 100644
--- a/server/common-graphics-channel.cpp
+++ b/server/common-graphics-channel.cpp
@@ -65,8 +65,3 @@ bool CommonGraphicsChannelClient::config_socket()
     ack_set_client_window(is_low_bandwidth ? WIDE_CLIENT_ACK_WINDOW : NARROW_CLIENT_ACK_WINDOW);
     return true;
 }
-
-RedCachePipeItem::RedCachePipeItem():
-    RedPipeItem(RED_PIPE_ITEM_TYPE_INVAL_ONE)
-{
-}
diff --git a/server/common-graphics-channel.h b/server/common-graphics-channel.h
index 4029b59e..16ebf148 100644
--- a/server/common-graphics-channel.h
+++ b/server/common-graphics-channel.h
@@ -69,8 +69,7 @@ protected:
 };
 
 /* pipe item used to release a specific cached item on the client */
-struct RedCachePipeItem final: public RedPipeItem {
-    RedCachePipeItem();
+struct RedCachePipeItem final: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_INVAL_ONE> {
     SpiceMsgDisplayInvalOne inval_one;
 };
 
diff --git a/server/cursor-channel.cpp b/server/cursor-channel.cpp
index 9fc8f44d..99748025 100644
--- a/server/cursor-channel.cpp
+++ b/server/cursor-channel.cpp
@@ -25,15 +25,14 @@
 #include "cursor-channel-client.h"
 #include "reds.h"
 
-struct RedCursorPipeItem: public RedPipeItem {
-    using RedPipeItem::RedPipeItem;
+struct RedCursorPipeItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_CURSOR> {
     ~RedCursorPipeItem();
     RedCursorCmd *red_cursor;
 };
 
 static RedCursorPipeItem *cursor_pipe_item_new(RedCursorCmd *cmd)
 {
-    RedCursorPipeItem *item = new RedCursorPipeItem(RED_PIPE_ITEM_TYPE_CURSOR);
+    RedCursorPipeItem *item = new RedCursorPipeItem();
 
     spice_return_val_if_fail(cmd != NULL, NULL);
 
diff --git a/server/dcc.cpp b/server/dcc.cpp
index 16539726..c6fb3f61 100644
--- a/server/dcc.cpp
+++ b/server/dcc.cpp
@@ -500,8 +500,7 @@ RedMonitorsConfigItem::~RedMonitorsConfigItem()
     monitors_config_unref(monitors_config);
 }
 
-RedMonitorsConfigItem::RedMonitorsConfigItem(MonitorsConfig *init_monitors_config):
-    RedPipeItem(RED_PIPE_ITEM_TYPE_MONITORS_CONFIG)
+RedMonitorsConfigItem::RedMonitorsConfigItem(MonitorsConfig *init_monitors_config)
 {
     monitors_config = monitors_config_ref(init_monitors_config);
 }
@@ -525,8 +524,7 @@ void dcc_push_monitors_config(DisplayChannelClient *dcc)
     dcc->pipe_add(mci);
 }
 
-RedSurfaceDestroyItem::RedSurfaceDestroyItem(uint32_t surface_id):
-    RedPipeItem(RED_PIPE_ITEM_TYPE_DESTROY_SURFACE)
+RedSurfaceDestroyItem::RedSurfaceDestroyItem(uint32_t surface_id)
 {
     surface_destroy.surface_id = surface_id;
 }
diff --git a/server/display-channel-private.h b/server/display-channel-private.h
index 04552776..cf7d2dba 100644
--- a/server/display-channel-private.h
+++ b/server/display-channel-private.h
@@ -139,12 +139,6 @@ struct DisplayChannelPrivate
     GLIST_FOREACH((_channel ? _channel->get_clients() : NULL), \
                   DisplayChannelClient, _data)
 
-struct RedMonitorsConfigItem: public RedPipeItem {
-    RedMonitorsConfigItem(MonitorsConfig *monitors_config);
-    ~RedMonitorsConfigItem();
-    MonitorsConfig *monitors_config;
-};
-
 enum {
     RED_PIPE_ITEM_TYPE_DRAW = RED_PIPE_ITEM_TYPE_COMMON_LAST,
     RED_PIPE_ITEM_TYPE_IMAGE,
@@ -164,6 +158,12 @@ enum {
     RED_PIPE_ITEM_TYPE_GL_DRAW,
 };
 
+struct RedMonitorsConfigItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_MONITORS_CONFIG> {
+    RedMonitorsConfigItem(MonitorsConfig *monitors_config);
+    ~RedMonitorsConfigItem();
+    MonitorsConfig *monitors_config;
+};
+
 void drawable_unref(Drawable *drawable);
 
 MonitorsConfig *monitors_config_ref(MonitorsConfig *config);
@@ -182,7 +182,7 @@ uint32_t display_channel_generate_uid(DisplayChannel *display);
 int display_channel_get_video_stream_id(DisplayChannel *display, VideoStream *stream);
 VideoStream *display_channel_get_nth_video_stream(DisplayChannel *display, gint i);
 
-struct RedSurfaceDestroyItem: public RedPipeItem {
+struct RedSurfaceDestroyItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_DESTROY_SURFACE> {
     RedSurfaceDestroyItem(uint32_t surface_id);
     SpiceMsgSurfaceDestroy surface_destroy;
 };
diff --git a/server/inputs-channel.cpp b/server/inputs-channel.cpp
index aede5c2a..b9df9d1a 100644
--- a/server/inputs-channel.cpp
+++ b/server/inputs-channel.cpp
@@ -86,12 +86,12 @@ RedsState* spice_tablet_state_get_server(SpiceTabletState *st)
     return st->reds;
 }
 
-struct RedKeyModifiersPipeItem: public RedPipeItem {
+struct RedKeyModifiersPipeItem: public RedPipeItemNum<RED_PIPE_ITEM_KEY_MODIFIERS> {
     RedKeyModifiersPipeItem(uint8_t modifiers);
     uint8_t modifiers;
 };
 
-struct RedInputsInitPipeItem: public RedPipeItem {
+struct RedInputsInitPipeItem: public RedPipeItemNum<RED_PIPE_ITEM_INPUTS_INIT> {
     RedInputsInitPipeItem(uint8_t modifiers);
     uint8_t modifiers;
 };
@@ -195,7 +195,6 @@ static uint8_t kbd_get_leds(SpiceKbdInstance *sin)
 }
 
 RedKeyModifiersPipeItem::RedKeyModifiersPipeItem(uint8_t init_modifiers):
-    RedPipeItem(RED_PIPE_ITEM_KEY_MODIFIERS),
     modifiers(init_modifiers)
 {
 }
@@ -430,7 +429,6 @@ void InputsChannel::release_keys()
 }
 
 RedInputsInitPipeItem::RedInputsInitPipeItem(uint8_t init_modifiers):
-    RedPipeItem(RED_PIPE_ITEM_INPUTS_INIT),
     modifiers(init_modifiers)
 {
 }
diff --git a/server/main-channel-client.cpp b/server/main-channel-client.cpp
index 139d2a34..67b82c07 100644
--- a/server/main-channel-client.cpp
+++ b/server/main-channel-client.cpp
@@ -61,18 +61,15 @@ struct MainChannelClientPrivate {
     uint8_t recv_buf[MAIN_CHANNEL_RECEIVE_BUF_SIZE];
 };
 
-struct RedPingPipeItem: public RedPipeItem {
-    using RedPipeItem::RedPipeItem;
+struct RedPingPipeItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_MAIN_PING> {
     int size;
 };
 
-struct RedTokensPipeItem: public RedPipeItem {
-    using RedPipeItem::RedPipeItem;
+struct RedTokensPipeItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_MAIN_AGENT_TOKEN> {
     int tokens;
 };
 
-struct RedAgentDataPipeItem: public RedPipeItem {
-    using RedPipeItem::RedPipeItem;
+struct RedAgentDataPipeItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_MAIN_AGENT_DATA> {
     ~RedAgentDataPipeItem();
     uint8_t* data;
     size_t len;
@@ -80,8 +77,7 @@ struct RedAgentDataPipeItem: public RedPipeItem {
     void *opaque;
 };
 
-struct RedInitPipeItem: public RedPipeItem {
-    using RedPipeItem::RedPipeItem;
+struct RedInitPipeItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_MAIN_INIT> {
     int connection_id;
     int display_channels_hint;
     int current_mouse_mode;
@@ -90,35 +86,31 @@ struct RedInitPipeItem: public RedPipeItem {
     int ram_hint;
 };
 
-struct RedNamePipeItem: public RedPipeItem {
-    using RedPipeItem::RedPipeItem;
+struct RedNamePipeItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_MAIN_NAME> {
     SpiceMsgMainName msg;
 };
 
-struct RedUuidPipeItem: public RedPipeItem {
-    using RedPipeItem::RedPipeItem;
+struct RedUuidPipeItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_MAIN_UUID> {
     SpiceMsgMainUuid msg;
 };
 
-struct RedNotifyPipeItem: public RedPipeItem {
-    using RedPipeItem::RedPipeItem;
+struct RedNotifyPipeItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_MAIN_NOTIFY> {
     ~RedNotifyPipeItem();
     char *msg;
 };
 
-struct RedMouseModePipeItem: public RedPipeItem {
-    using RedPipeItem::RedPipeItem;
+struct RedMouseModePipeItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_MAIN_MOUSE_MODE> {
     SpiceMouseMode current_mode;
     int is_client_mouse_allowed;
 };
 
-struct RedMultiMediaTimePipeItem: public RedPipeItem {
-    using RedPipeItem::RedPipeItem;
+struct RedMultiMediaTimePipeItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_MAIN_MULTI_MEDIA_TIME> {
     uint32_t time;
 };
 
-struct RedRegisteredChannelPipeItem: public RedPipeItem {
-    using RedPipeItem::RedPipeItem;
+struct RedRegisteredChannelPipeItem:
+    public RedPipeItemNum<RED_PIPE_ITEM_TYPE_MAIN_REGISTERED_CHANNEL>
+{
     uint32_t channel_type;
     uint32_t channel_id;
 };
@@ -166,7 +158,7 @@ RedNotifyPipeItem::~RedNotifyPipeItem()
 
 static RedPipeItem *main_notify_item_new(const char *msg, int num)
 {
-    RedNotifyPipeItem *item = new RedNotifyPipeItem(RED_PIPE_ITEM_TYPE_MAIN_NOTIFY);
+    RedNotifyPipeItem *item = new RedNotifyPipeItem();
 
     item->msg = g_strdup(msg);
     return item;
@@ -193,7 +185,7 @@ void MainChannelClient::start_net_test(int test_rate)
 
 static RedPipeItem *red_ping_item_new(int size)
 {
-    RedPingPipeItem *item = new RedPingPipeItem(RED_PIPE_ITEM_TYPE_MAIN_PING);
+    RedPingPipeItem *item = new RedPingPipeItem();
 
     item->size = size;
     return item;
@@ -207,7 +199,7 @@ static void main_channel_client_push_ping(MainChannelClient *mcc, int size)
 
 static RedPipeItem *main_agent_tokens_item_new(uint32_t num_tokens)
 {
-    RedTokensPipeItem *item = new RedTokensPipeItem(RED_PIPE_ITEM_TYPE_MAIN_AGENT_TOKEN);
+    RedTokensPipeItem *item = new RedTokensPipeItem();
 
     item->tokens = num_tokens;
     return item;
@@ -230,7 +222,7 @@ static RedPipeItem *main_agent_data_item_new(uint8_t* data, size_t len,
                                              spice_marshaller_item_free_func free_data,
                                              void *opaque)
 {
-    RedAgentDataPipeItem *item = new RedAgentDataPipeItem(RED_PIPE_ITEM_TYPE_MAIN_AGENT_DATA);
+    RedAgentDataPipeItem *item = new RedAgentDataPipeItem();
 
     item->data = data;
     item->len = len;
@@ -256,7 +248,7 @@ static RedPipeItem *main_init_item_new(int connection_id,
                                        int multi_media_time,
                                        int ram_hint)
 {
-    RedInitPipeItem *item = new RedInitPipeItem(RED_PIPE_ITEM_TYPE_MAIN_INIT);
+    RedInitPipeItem *item = new RedInitPipeItem();
 
     item->connection_id = connection_id;
     item->display_channels_hint = display_channels_hint;
@@ -282,7 +274,7 @@ void MainChannelClient::push_init(int display_channels_hint,
 
 static RedPipeItem *main_name_item_new(const char *name)
 {
-    RedNamePipeItem *item = new (strlen(name) + 1) RedNamePipeItem(RED_PIPE_ITEM_TYPE_MAIN_NAME);
+    RedNamePipeItem *item = new (strlen(name) + 1) RedNamePipeItem();
     item->msg.name_len = strlen(name) + 1;
     memcpy(&item->msg.name, name, item->msg.name_len);
 
@@ -302,7 +294,7 @@ void MainChannelClient::push_name(const char *name)
 
 static RedPipeItem *main_uuid_item_new(const uint8_t uuid[16])
 {
-    RedUuidPipeItem *item = new RedUuidPipeItem(RED_PIPE_ITEM_TYPE_MAIN_UUID);
+    RedUuidPipeItem *item = new RedUuidPipeItem();
 
     memcpy(item->msg.uuid, uuid, sizeof(item->msg.uuid));
 
@@ -328,7 +320,7 @@ void MainChannelClient::push_notify(const char *msg)
 
 RedPipeItem *main_mouse_mode_item_new(SpiceMouseMode current_mode, int is_client_mouse_allowed)
 {
-    RedMouseModePipeItem *item = new RedMouseModePipeItem(RED_PIPE_ITEM_TYPE_MAIN_MOUSE_MODE);
+    RedMouseModePipeItem *item = new RedMouseModePipeItem();
 
     item->current_mode = current_mode;
     item->is_client_mouse_allowed = is_client_mouse_allowed;
@@ -339,7 +331,7 @@ RedPipeItem *main_multi_media_time_item_new(uint32_t mm_time)
 {
     RedMultiMediaTimePipeItem *item;
 
-    item = new RedMultiMediaTimePipeItem(RED_PIPE_ITEM_TYPE_MAIN_MULTI_MEDIA_TIME);
+    item = new RedMultiMediaTimePipeItem();
     item->time = mm_time;
     return item;
 }
@@ -348,7 +340,7 @@ RedPipeItem *registered_channel_item_new(RedChannel *channel)
 {
     RedRegisteredChannelPipeItem *item;
 
-    item = new RedRegisteredChannelPipeItem(RED_PIPE_ITEM_TYPE_MAIN_REGISTERED_CHANNEL);
+    item = new RedRegisteredChannelPipeItem();
 
     item->channel_type = channel->type();
     item->channel_id = channel->id();
diff --git a/server/red-channel-client.cpp b/server/red-channel-client.cpp
index eed6a53a..900d6eaf 100644
--- a/server/red-channel-client.cpp
+++ b/server/red-channel-client.cpp
@@ -239,13 +239,11 @@ static const SpiceDataHeaderOpaque mini_header_wrapper = {NULL, sizeof(SpiceMini
 #define PING_TEST_LONG_TIMEOUT_MS (MSEC_PER_SEC * 60 * 5)
 #define PING_TEST_IDLE_NET_TIMEOUT_MS (MSEC_PER_SEC / 10)
 
-struct RedEmptyMsgPipeItem: public RedPipeItem {
-    using RedPipeItem::RedPipeItem;
+struct RedEmptyMsgPipeItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_EMPTY_MSG> {
     int msg;
 };
 
-struct MarkerPipeItem: public RedPipeItem {
-    using RedPipeItem::RedPipeItem;
+struct MarkerPipeItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_MARKER> {
     bool item_sent;
 };
 
@@ -1435,7 +1433,7 @@ void RedChannelClient::pipe_add_type(int pipe_item_type)
 
 RedPipeItem *RedChannelClient::new_empty_msg(int msg_type)
 {
-    RedEmptyMsgPipeItem *item = new RedEmptyMsgPipeItem(RED_PIPE_ITEM_TYPE_EMPTY_MSG);
+    RedEmptyMsgPipeItem *item = new RedEmptyMsgPipeItem();
 
     item->msg = msg_type;
     return item;
@@ -1576,7 +1574,7 @@ bool RedChannelClient::wait_pipe_item_sent(GList *item_pos, int64_t timeout)
         end_time = UINT64_MAX;
     }
 
-    MarkerPipeItem *mark_item = new MarkerPipeItem(RED_PIPE_ITEM_TYPE_MARKER);
+    MarkerPipeItem *mark_item = new MarkerPipeItem();
 
     mark_item->item_sent = false;
     red_pipe_item_ref(mark_item);
diff --git a/server/red-pipe-item.h b/server/red-pipe-item.h
index 2bad0d8e..e0c5c630 100644
--- a/server/red-pipe-item.h
+++ b/server/red-pipe-item.h
@@ -67,6 +67,18 @@ struct RedPipeItem: public red::shared_ptr_counted
 RedPipeItem *red_pipe_item_ref(RedPipeItem *item);
 void red_pipe_item_unref(RedPipeItem *item);
 
+/* Most of the time the type is constant and we just add fields,
+ * make it easier to initialize just with declaration
+ */
+template <int initial_type>
+struct RedPipeItemNum: public RedPipeItem
+{
+    RedPipeItemNum():
+        RedPipeItem(initial_type)
+    {
+    }
+};
+
 #include "pop-visibility.h"
 
 #endif /* RED_PIPE_ITEM_H_ */
diff --git a/server/reds.cpp b/server/reds.cpp
index 900dbe73..ade19487 100644
--- a/server/reds.cpp
+++ b/server/reds.cpp
@@ -153,8 +153,10 @@ struct ChannelSecurityOptions {
     ChannelSecurityOptions *next;
 };
 
-struct RedVDIReadBuf final: public RedPipeItem {
-    using RedPipeItem::RedPipeItem;
+/* Bogus pipe item type, we only need the RingItem and refcounting
+ * from the base class and are not going to use the type
+ */
+struct RedVDIReadBuf final: public RedPipeItemNum<-1> {
     ~RedVDIReadBuf();
 
     RedCharDeviceVDIPort *dev;
@@ -697,10 +699,7 @@ RedVDIReadBuf::~RedVDIReadBuf()
 
 static RedVDIReadBuf *vdi_read_buf_new(RedCharDeviceVDIPort *dev)
 {
-    /* Bogus pipe item type, we only need the RingItem and refcounting
-     * from the base class and are not going to use the type
-     */
-    RedVDIReadBuf *buf = new RedVDIReadBuf(-1);
+    RedVDIReadBuf *buf = new RedVDIReadBuf();
     buf->dev = dev;
     buf->len = 0;
     return buf;
diff --git a/server/smartcard-channel-client.cpp b/server/smartcard-channel-client.cpp
index 7a8166d7..051facd1 100644
--- a/server/smartcard-channel-client.cpp
+++ b/server/smartcard-channel-client.cpp
@@ -32,8 +32,7 @@ struct SmartCardChannelClientPrivate
     bool msg_in_write_buf = false;
 };
 
-struct RedErrorItem: public RedPipeItem {
-    using RedPipeItem::RedPipeItem;
+struct RedErrorItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_ERROR> {
     VSCMsgHeader vheader;
     VSCMsgError  error;
 };
@@ -138,7 +137,7 @@ static void smartcard_channel_client_push_error(RedChannelClient *rcc,
                                                 uint32_t reader_id,
                                                 VSCErrorCode error)
 {
-    RedErrorItem *error_item = new RedErrorItem(RED_PIPE_ITEM_TYPE_ERROR);
+    RedErrorItem *error_item = new RedErrorItem();
 
     error_item->vheader.reader_id = reader_id;
     error_item->vheader.type = VSC_Error;
diff --git a/server/smartcard.cpp b/server/smartcard.cpp
index 39d46da7..f968c6ed 100644
--- a/server/smartcard.cpp
+++ b/server/smartcard.cpp
@@ -67,8 +67,7 @@ struct RedCharDeviceSmartcardPrivate {
     int                  reader_added; // has reader_add been sent to the device
 };
 
-struct RedMsgItem: public RedPipeItem {
-    using RedPipeItem::RedPipeItem;
+struct RedMsgItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_SMARTCARD_DATA> {
     ~RedMsgItem();
     VSCMsgHeader* vheader;
 };
@@ -397,7 +396,7 @@ RedMsgItem::~RedMsgItem()
 
 static RedMsgItem *smartcard_new_vsc_msg_item(unsigned int reader_id, const VSCMsgHeader *vheader)
 {
-    RedMsgItem *msg_item = new RedMsgItem(RED_PIPE_ITEM_TYPE_SMARTCARD_DATA);
+    RedMsgItem *msg_item = new RedMsgItem();
 
     msg_item->vheader = (VSCMsgHeader*) g_memdup(vheader, sizeof(*vheader) + vheader->length);
     /* We patch the reader_id, since the device only knows about itself, and
diff --git a/server/sound.cpp b/server/sound.cpp
index a35d6753..386463e4 100644
--- a/server/sound.cpp
+++ b/server/sound.cpp
@@ -74,6 +74,10 @@ struct RecordChannelClient;
 struct AudioFrame;
 struct AudioFrameContainer;
 
+enum {
+    RED_PIPE_ITEM_PERSISTENT = RED_PIPE_ITEM_TYPE_CHANNEL_BASE,
+};
+
 /* This pipe item is never deleted and added to the queue when messages
  * have to be sent.
  * This is used to have a simple item in RedChannelClient queue but to send
@@ -82,7 +86,7 @@ struct AudioFrameContainer;
  * much data or having retransmission preferring instead loosing some
  * samples.
  */
-struct PersistentPipeItem final: public RedPipeItem
+struct PersistentPipeItem final: public RedPipeItemNum<RED_PIPE_ITEM_PERSISTENT>
 {
     PersistentPipeItem();
 };
@@ -115,10 +119,6 @@ private:
 
 static void snd_playback_alloc_frames(PlaybackChannelClient *playback);
 
-enum {
-    RED_PIPE_ITEM_PERSISTENT = RED_PIPE_ITEM_TYPE_CHANNEL_BASE,
-};
-
 
 struct AudioFrame {
     uint32_t time;
@@ -616,8 +616,7 @@ static bool playback_send_mode(PlaybackChannelClient *playback_client)
     return true;
 }
 
-PersistentPipeItem::PersistentPipeItem():
-    RedPipeItem(RED_PIPE_ITEM_PERSISTENT)
+PersistentPipeItem::PersistentPipeItem()
 {
 }
 
diff --git a/server/spicevmc.cpp b/server/spicevmc.cpp
index 6eb34ae8..8919cc4f 100644
--- a/server/spicevmc.cpp
+++ b/server/spicevmc.cpp
@@ -42,12 +42,17 @@
 // avoid DoS
 #define QUEUED_DATA_LIMIT (1024*1024)
 
+enum {
+    RED_PIPE_ITEM_TYPE_SPICEVMC_DATA = RED_PIPE_ITEM_TYPE_CHANNEL_BASE,
+    RED_PIPE_ITEM_TYPE_SPICEVMC_MIGRATE_DATA,
+    RED_PIPE_ITEM_TYPE_PORT_INIT,
+    RED_PIPE_ITEM_TYPE_PORT_EVENT,
+};
+
 struct RedVmcChannel;
 class VmcChannelClient;
 
-struct RedVmcPipeItem: public RedPipeItem {
-    using RedPipeItem::RedPipeItem;
-
+struct RedVmcPipeItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_SPICEVMC_DATA> {
     SpiceDataCompressionType type;
     uint32_t uncompressed_data_size;
     /* writes which don't fit this will get split, this is not a problem */
@@ -183,27 +188,17 @@ static red::shared_ptr<RedVmcChannel> red_vmc_channel_new(RedsState *reds, uint8
     return red::make_shared<RedVmcChannel>(reds, channel_type, id);
 }
 
-struct RedPortInitPipeItem: public RedPipeItem {
-    using RedPipeItem::RedPipeItem;
+struct RedPortInitPipeItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_PORT_INIT> {
     ~RedPortInitPipeItem();
 
     char* name;
     uint8_t opened;
 };
 
-struct RedPortEventPipeItem: public RedPipeItem {
-    using RedPipeItem::RedPipeItem;
-
+struct RedPortEventPipeItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_PORT_EVENT> {
     uint8_t event;
 };
 
-enum {
-    RED_PIPE_ITEM_TYPE_SPICEVMC_DATA = RED_PIPE_ITEM_TYPE_CHANNEL_BASE,
-    RED_PIPE_ITEM_TYPE_SPICEVMC_MIGRATE_DATA,
-    RED_PIPE_ITEM_TYPE_PORT_INIT,
-    RED_PIPE_ITEM_TYPE_PORT_EVENT,
-};
-
 /* n is the data size (uncompressed)
  * msg_item -- the current pipe item with the uncompressed data
  * This function returns:
@@ -228,7 +223,7 @@ static RedVmcPipeItem* try_compress_lz4(RedVmcChannel *channel, int n, RedVmcPip
         /* Client doesn't have compression cap - data will not be compressed */
         return NULL;
     }
-    msg_item_compressed = new RedVmcPipeItem(RED_PIPE_ITEM_TYPE_SPICEVMC_DATA);
+    msg_item_compressed = new RedVmcPipeItem();
     compressed_data_count = LZ4_compress_default((char*)&msg_item->buf,
                                                  (char*)&msg_item_compressed->buf,
                                                  n,
@@ -260,7 +255,7 @@ RedPipeItem* RedCharDeviceSpiceVmc::read_one_msg_from_device()
     }
 
     if (!channel->pipe_item) {
-        msg_item = new RedVmcPipeItem(RED_PIPE_ITEM_TYPE_SPICEVMC_DATA);
+        msg_item = new RedVmcPipeItem();
         msg_item->type = SPICE_DATA_COMPRESSION_TYPE_NONE;
     } else {
         spice_assert(channel->pipe_item->buf_used == 0);
@@ -299,7 +294,7 @@ static void spicevmc_port_send_init(VmcChannelClient *rcc)
 {
     RedVmcChannel *channel = rcc->get_channel();
     SpiceCharDeviceInstance *sin = channel->chardev_sin;
-    RedPortInitPipeItem *item = new RedPortInitPipeItem(RED_PIPE_ITEM_TYPE_PORT_INIT);
+    RedPortInitPipeItem *item = new RedPortInitPipeItem();
 
     item->name = g_strdup(sin->portname);
     item->opened = channel->port_opened;
@@ -308,7 +303,7 @@ static void spicevmc_port_send_init(VmcChannelClient *rcc)
 
 static void spicevmc_port_send_event(RedChannelClient *rcc, uint8_t event)
 {
-    RedPortEventPipeItem *item = new RedPortEventPipeItem(RED_PIPE_ITEM_TYPE_PORT_EVENT);
+    RedPortEventPipeItem *item = new RedPortEventPipeItem();
 
     item->event = event;
     rcc->pipe_add_push(item);
diff --git a/server/stream-channel.cpp b/server/stream-channel.cpp
index 9fe527c4..e9aac846 100644
--- a/server/stream-channel.cpp
+++ b/server/stream-channel.cpp
@@ -67,13 +67,11 @@ enum {
     RED_PIPE_ITEM_TYPE_MONITORS_CONFIG,
 };
 
-struct StreamCreateItem: public RedPipeItem {
-    using RedPipeItem::RedPipeItem;
+struct StreamCreateItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_STREAM_CREATE> {
     SpiceMsgDisplayStreamCreate stream_create;
 };
 
-struct StreamDataItem: public RedPipeItem {
-    using RedPipeItem::RedPipeItem;
+struct StreamDataItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_STREAM_DATA> {
     ~StreamDataItem();
 
     StreamChannel *channel;
@@ -426,7 +424,7 @@ StreamChannel::change_format(const StreamMsgFormat *fmt)
     stream_id = (stream_id + 1) % NUM_STREAMS;
 
     // send create stream
-    StreamCreateItem *item = new StreamCreateItem(RED_PIPE_ITEM_TYPE_STREAM_CREATE);
+    StreamCreateItem *item = new StreamCreateItem();
     item->stream_create.id = stream_id;
     item->stream_create.flags = SPICE_STREAM_FLAGS_TOP_DOWN;
     item->stream_create.codec_type = fmt->codec;
@@ -467,7 +465,7 @@ StreamChannel::send_data(const void *data, size_t size, uint32_t mm_time)
         return;
     }
 
-    StreamDataItem *item = new (size) StreamDataItem(RED_PIPE_ITEM_TYPE_STREAM_DATA);
+    StreamDataItem *item = new (size) StreamDataItem();
     item->data.base.id = stream_id;
     item->data.base.multi_media_time = mm_time;
     item->data.data_size = size;
commit a30df693cfa3c7c32339b5db4033831111ff798e
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Thu Jun 4 21:31:05 2020 +0100

    red-pipe-item: Use inheritance on RedPipeItem
    
    This allows to:
    - reuse reference counting;
    - avoid having to manually call g_free to release item memory;
    - assure item is initialized;
    - avoids some manual casts.
    
    It will also allows to use smart pointers.
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
    Acked-by: Julien Ropé <jrope at gmail.com>

diff --git a/server/cache-item.tmpl.cpp b/server/cache-item.tmpl.cpp
index 2b4755f3..3a24ee33 100644
--- a/server/cache-item.tmpl.cpp
+++ b/server/cache-item.tmpl.cpp
@@ -76,9 +76,9 @@ static void FUNC_NAME(remove)(CHANNELCLIENT *channel_client, RedCacheItem *item)
     auto id = item->id;
     RedCachePipeItem *pipe_item = reinterpret_cast<RedCachePipeItem*>(item);
 
-    red_pipe_item_init(&pipe_item->base, RED_PIPE_ITEM_TYPE_INVAL_ONE);
+    new (pipe_item) RedCachePipeItem();
     pipe_item->inval_one.id = id;
-    channel_client->pipe_add_tail(&pipe_item->base); // for now
+    channel_client->pipe_add_tail(pipe_item); // for now
 }
 
 static int FUNC_NAME(add)(CHANNELCLIENT *channel_client, uint64_t id, size_t size)
diff --git a/server/common-graphics-channel.cpp b/server/common-graphics-channel.cpp
index c7cac7e9..2a415d65 100644
--- a/server/common-graphics-channel.cpp
+++ b/server/common-graphics-channel.cpp
@@ -65,3 +65,8 @@ bool CommonGraphicsChannelClient::config_socket()
     ack_set_client_window(is_low_bandwidth ? WIDE_CLIENT_ACK_WINDOW : NARROW_CLIENT_ACK_WINDOW);
     return true;
 }
+
+RedCachePipeItem::RedCachePipeItem():
+    RedPipeItem(RED_PIPE_ITEM_TYPE_INVAL_ONE)
+{
+}
diff --git a/server/common-graphics-channel.h b/server/common-graphics-channel.h
index 455e2d05..4029b59e 100644
--- a/server/common-graphics-channel.h
+++ b/server/common-graphics-channel.h
@@ -69,8 +69,8 @@ protected:
 };
 
 /* pipe item used to release a specific cached item on the client */
-struct RedCachePipeItem {
-    RedPipeItem base;
+struct RedCachePipeItem final: public RedPipeItem {
+    RedCachePipeItem();
     SpiceMsgDisplayInvalOne inval_one;
 };
 
diff --git a/server/cursor-channel.cpp b/server/cursor-channel.cpp
index 835597f4..9fc8f44d 100644
--- a/server/cursor-channel.cpp
+++ b/server/cursor-channel.cpp
@@ -25,41 +25,35 @@
 #include "cursor-channel-client.h"
 #include "reds.h"
 
-typedef struct RedCursorPipeItem {
-    RedPipeItem base;
+struct RedCursorPipeItem: public RedPipeItem {
+    using RedPipeItem::RedPipeItem;
+    ~RedCursorPipeItem();
     RedCursorCmd *red_cursor;
-} RedCursorPipeItem;
-
-static void cursor_pipe_item_free(RedPipeItem *pipe_item);
+};
 
 static RedCursorPipeItem *cursor_pipe_item_new(RedCursorCmd *cmd)
 {
-    RedCursorPipeItem *item = g_new0(RedCursorPipeItem, 1);
+    RedCursorPipeItem *item = new RedCursorPipeItem(RED_PIPE_ITEM_TYPE_CURSOR);
 
     spice_return_val_if_fail(cmd != NULL, NULL);
 
-    red_pipe_item_init_full(&item->base, RED_PIPE_ITEM_TYPE_CURSOR,
-                            cursor_pipe_item_free);
     item->red_cursor = red_cursor_cmd_ref(cmd);
 
     return item;
 }
 
-static void cursor_pipe_item_free(RedPipeItem *base)
+RedCursorPipeItem::~RedCursorPipeItem()
 {
-    RedCursorPipeItem *pipe_item = SPICE_UPCAST(RedCursorPipeItem, base);
-
-    red_cursor_cmd_unref(pipe_item->red_cursor);
-    g_free(pipe_item);
+    red_cursor_cmd_unref(red_cursor);
 }
 
 static void cursor_channel_set_item(CursorChannel *cursor, RedCursorPipeItem *item)
 {
     if (item) {
-        red_pipe_item_ref(&item->base);
+        red_pipe_item_ref(item);
     }
     if (cursor->item) {
-        red_pipe_item_unref(&cursor->item->base);
+        red_pipe_item_unref(cursor->item);
     }
     cursor->item = item;
 }
@@ -89,7 +83,7 @@ static void cursor_fill(CursorChannelClient *ccc, RedCursorPipeItem *cursor,
 
     if (red_cursor->data_size) {
         SpiceMarshaller *m2 = spice_marshaller_get_submarshaller(m);
-        cursor->base.add_to_marshaller(m2, red_cursor->data, red_cursor->data_size);
+        cursor->add_to_marshaller(m2, red_cursor->data, red_cursor->data_size);
     }
 }
 
@@ -178,10 +172,10 @@ void CursorChannelClient::send_item(RedPipeItem *pipe_item)
 
     switch (pipe_item->type) {
     case RED_PIPE_ITEM_TYPE_CURSOR:
-        red_marshall_cursor(ccc, m, SPICE_UPCAST(RedCursorPipeItem, pipe_item));
+        red_marshall_cursor(ccc, m, static_cast<RedCursorPipeItem*>(pipe_item));
         break;
     case RED_PIPE_ITEM_TYPE_INVAL_ONE:
-        red_marshall_inval(this, m, SPICE_UPCAST(RedCachePipeItem, pipe_item));
+        red_marshall_inval(this, m, static_cast<RedCachePipeItem*>(pipe_item));
         break;
     case RED_PIPE_ITEM_TYPE_CURSOR_INIT:
         reset_cursor_cache();
@@ -235,7 +229,7 @@ void CursorChannel::process_cmd(RedCursorCmd *cursor_cmd)
         break;
     default:
         spice_warning("invalid cursor command %u", cursor_cmd->type);
-        red_pipe_item_unref(&cursor_pipe_item->base);
+        red_pipe_item_unref(cursor_pipe_item);
         return;
     }
 
@@ -243,9 +237,9 @@ void CursorChannel::process_cmd(RedCursorCmd *cursor_cmd)
         (mouse_mode == SPICE_MOUSE_MODE_SERVER
          || cursor_cmd->type != QXL_CURSOR_MOVE
          || cursor_show)) {
-        pipes_add(&cursor_pipe_item->base);
+        pipes_add(cursor_pipe_item);
     } else {
-        red_pipe_item_unref(&cursor_pipe_item->base);
+        red_pipe_item_unref(cursor_pipe_item);
     }
 }
 
@@ -316,7 +310,7 @@ void CursorChannel::on_connect(RedClient *client, RedStream *stream, int migrati
 CursorChannel::~CursorChannel()
 {
     if (item) {
-        red_pipe_item_unref(&item->base);
+        red_pipe_item_unref(item);
     }
 }
 
diff --git a/server/dcc-send.cpp b/server/dcc-send.cpp
index 7c070f3a..641b8c06 100644
--- a/server/dcc-send.cpp
+++ b/server/dcc-send.cpp
@@ -626,7 +626,7 @@ static bool pipe_rendered_drawables_intersect_with_areas(DisplayChannelClient *d
 
         if (pipe_item->type != RED_PIPE_ITEM_TYPE_DRAW)
             continue;
-        drawable = SPICE_UPCAST(RedDrawablePipeItem, pipe_item)->drawable;
+        drawable = static_cast<RedDrawablePipeItem*>(pipe_item)->drawable;
 
         if (ring_item_is_linked(&drawable->list_link))
             continue; // item hasn't been rendered
@@ -719,7 +719,7 @@ static void red_pipe_replace_rendered_drawables_with_images(DisplayChannelClient
         prev = l->prev;
         if (pipe_item->type != RED_PIPE_ITEM_TYPE_DRAW)
             continue;
-        dpi = SPICE_UPCAST(RedDrawablePipeItem, pipe_item);
+        dpi = static_cast<RedDrawablePipeItem*>(pipe_item);
         drawable = dpi->drawable;
         if (ring_item_is_linked(&drawable->list_link))
             continue; // item hasn't been rendered
@@ -1969,8 +1969,8 @@ static void red_marshall_image(DisplayChannelClient *dcc,
 
         spice_marshall_Image(src_bitmap_out, &red_image,
                              &bitmap_palette_out, &lzplt_palette_out);
-        item->base.add_to_marshaller(src_bitmap_out, item->data,
-                                     bitmap.y * bitmap.stride);
+        item->add_to_marshaller(src_bitmap_out, item->data,
+                                bitmap.y * bitmap.stride);
         region_remove(surface_lossy_region, &copy.base.box);
     }
     spice_chunks_destroy(chunks);
@@ -2286,7 +2286,7 @@ static void marshall_gl_draw(RedChannelClient *rcc,
                              SpiceMarshaller *m,
                              RedPipeItem *item)
 {
-    RedGlDrawItem *p = SPICE_UPCAST(RedGlDrawItem, item);
+    RedGlDrawItem *p = static_cast<RedGlDrawItem*>(item);
 
     rcc->init_send_data(SPICE_MSG_DISPLAY_GL_DRAW);
     spice_marshall_msg_display_gl_draw(m, &p->draw);
@@ -2335,34 +2335,34 @@ void DisplayChannelClient::send_item(RedPipeItem *pipe_item)
     ::reset_send_data(dcc);
     switch (pipe_item->type) {
     case RED_PIPE_ITEM_TYPE_DRAW: {
-        RedDrawablePipeItem *dpi = SPICE_UPCAST(RedDrawablePipeItem, pipe_item);
+        RedDrawablePipeItem *dpi = static_cast<RedDrawablePipeItem*>(pipe_item);
         marshall_qxl_drawable(this, m, dpi);
         break;
     }
     case RED_PIPE_ITEM_TYPE_INVAL_ONE:
-        marshall_inval_palette(this, m, SPICE_UPCAST(RedCachePipeItem, pipe_item));
+        marshall_inval_palette(this, m, static_cast<RedCachePipeItem*>(pipe_item));
         break;
     case RED_PIPE_ITEM_TYPE_STREAM_CREATE: {
-        StreamCreateDestroyItem *item = SPICE_UPCAST(StreamCreateDestroyItem, pipe_item);
+        StreamCreateDestroyItem *item = static_cast<StreamCreateDestroyItem*>(pipe_item);
         marshall_stream_start(this, m, item->agent);
         break;
     }
     case RED_PIPE_ITEM_TYPE_STREAM_CLIP:
-        marshall_stream_clip(this, m, SPICE_UPCAST(VideoStreamClipItem, pipe_item));
+        marshall_stream_clip(this, m, static_cast<VideoStreamClipItem*>(pipe_item));
         break;
     case RED_PIPE_ITEM_TYPE_STREAM_DESTROY: {
-        StreamCreateDestroyItem *item = SPICE_UPCAST(StreamCreateDestroyItem, pipe_item);
+        StreamCreateDestroyItem *item = static_cast<StreamCreateDestroyItem*>(pipe_item);
         marshall_stream_end(this, m, item->agent);
         break;
     }
     case RED_PIPE_ITEM_TYPE_UPGRADE:
-        marshall_upgrade(this, m, SPICE_UPCAST(RedUpgradeItem, pipe_item));
+        marshall_upgrade(this, m, static_cast<RedUpgradeItem*>(pipe_item));
         break;
     case RED_PIPE_ITEM_TYPE_MIGRATE_DATA:
         display_channel_marshall_migrate_data(this, m);
         break;
     case RED_PIPE_ITEM_TYPE_IMAGE:
-        red_marshall_image(this, m, SPICE_UPCAST(RedImageItem, pipe_item));
+        red_marshall_image(this, m, static_cast<RedImageItem*>(pipe_item));
         break;
     case RED_PIPE_ITEM_TYPE_PIXMAP_SYNC:
         display_channel_marshall_pixmap_sync(this, m);
@@ -2375,23 +2375,23 @@ void DisplayChannelClient::send_item(RedPipeItem *pipe_item)
         init_send_data(SPICE_MSG_DISPLAY_INVAL_ALL_PALETTES);
         break;
     case RED_PIPE_ITEM_TYPE_CREATE_SURFACE: {
-        RedSurfaceCreateItem *surface_create = SPICE_UPCAST(RedSurfaceCreateItem, pipe_item);
+        RedSurfaceCreateItem *surface_create = static_cast<RedSurfaceCreateItem*>(pipe_item);
         marshall_surface_create(this, m, &surface_create->surface_create);
         break;
     }
     case RED_PIPE_ITEM_TYPE_DESTROY_SURFACE: {
-        RedSurfaceDestroyItem *surface_destroy = SPICE_UPCAST(RedSurfaceDestroyItem, pipe_item);
+        RedSurfaceDestroyItem *surface_destroy = static_cast<RedSurfaceDestroyItem*>(pipe_item);
         marshall_surface_destroy(this, m, surface_destroy->surface_destroy.surface_id);
         break;
     }
     case RED_PIPE_ITEM_TYPE_MONITORS_CONFIG: {
-        RedMonitorsConfigItem *monconf_item = SPICE_UPCAST(RedMonitorsConfigItem, pipe_item);
+        RedMonitorsConfigItem *monconf_item = static_cast<RedMonitorsConfigItem*>(pipe_item);
         marshall_monitors_config(this, m, monconf_item->monitors_config);
         break;
     }
     case RED_PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT: {
         RedStreamActivateReportItem *report_item =
-            SPICE_UPCAST(RedStreamActivateReportItem, pipe_item);
+            static_cast<RedStreamActivateReportItem*>(pipe_item);
         marshall_stream_activate_report(this, m, report_item);
         break;
     }
diff --git a/server/dcc.cpp b/server/dcc.cpp
index 3fd58535..16539726 100644
--- a/server/dcc.cpp
+++ b/server/dcc.cpp
@@ -70,25 +70,18 @@ DisplayChannelClient::~DisplayChannelClient()
     g_clear_pointer(&priv->client_preferred_video_codecs, g_array_unref);
 }
 
-static RedSurfaceCreateItem *red_surface_create_item_new(RedChannel* channel,
-                                                         uint32_t surface_id,
-                                                         uint32_t width,
-                                                         uint32_t height,
-                                                         uint32_t format,
-                                                         uint32_t flags)
+RedSurfaceCreateItem::RedSurfaceCreateItem(uint32_t surface_id,
+                                           uint32_t width,
+                                           uint32_t height,
+                                           uint32_t format,
+                                           uint32_t flags):
+    RedPipeItem(RED_PIPE_ITEM_TYPE_CREATE_SURFACE)
 {
-    RedSurfaceCreateItem *create;
-
-    create = g_new(RedSurfaceCreateItem, 1);
-
-    create->surface_create.surface_id = surface_id;
-    create->surface_create.width = width;
-    create->surface_create.height = height;
-    create->surface_create.flags = flags;
-    create->surface_create.format = format;
-
-    red_pipe_item_init(&create->base, RED_PIPE_ITEM_TYPE_CREATE_SURFACE);
-    return create;
+    surface_create.surface_id = surface_id;
+    surface_create.width = width;
+    surface_create.height = height;
+    surface_create.flags = flags;
+    surface_create.format = format;
 }
 
 bool dcc_drawable_is_in_pipe(DisplayChannelClient *dcc, Drawable *drawable)
@@ -129,10 +122,10 @@ bool dcc_clear_surface_drawables_from_pipe(DisplayChannelClient *dcc, int surfac
 
         l = l->next;
         if (item->type == RED_PIPE_ITEM_TYPE_DRAW) {
-            dpi = SPICE_UPCAST(RedDrawablePipeItem, item);
+            dpi = static_cast<RedDrawablePipeItem*>(item);
             drawable = dpi->drawable;
         } else if (item->type == RED_PIPE_ITEM_TYPE_UPGRADE) {
-            drawable = SPICE_UPCAST(RedUpgradeItem, item)->drawable;
+            drawable = static_cast<RedUpgradeItem*>(item)->drawable;
         } else {
             continue;
         }
@@ -189,12 +182,16 @@ void dcc_create_surface(DisplayChannelClient *dcc, int surface_id)
         return;
     }
     surface = &display->priv->surfaces[surface_id];
-    create = red_surface_create_item_new(display,
-                                         surface_id, surface->context.width,
-                                         surface->context.height,
-                                         surface->context.format, flags);
+    create = new RedSurfaceCreateItem(surface_id, surface->context.width,
+                                      surface->context.height,
+                                      surface->context.format, flags);
     dcc->priv->surface_client_created[surface_id] = TRUE;
-    dcc->pipe_add(&create->base);
+    dcc->pipe_add(create);
+}
+
+RedImageItem::RedImageItem():
+    RedPipeItem(RED_PIPE_ITEM_TYPE_IMAGE)
+{
 }
 
 // adding the pipe item after pos. If pos == NULL, adding to head.
@@ -219,9 +216,7 @@ dcc_add_surface_area_image(DisplayChannelClient *dcc, int surface_id,
     bpp = SPICE_SURFACE_FMT_DEPTH(surface->context.format) / 8;
     stride = width * bpp;
 
-    item = (RedImageItem *)g_malloc(height * stride + sizeof(RedImageItem));
-
-    red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_IMAGE);
+    item = new (height * stride) RedImageItem();
 
     item->surface_id = surface_id;
     item->image_format =
@@ -250,9 +245,9 @@ dcc_add_surface_area_image(DisplayChannelClient *dcc, int surface_id,
     }
 
     if (pipe_item_pos) {
-        dcc->pipe_add_after_pos(&item->base, pipe_item_pos);
+        dcc->pipe_add_after_pos(item, pipe_item_pos);
     } else {
-        dcc->pipe_add(&item->base);
+        dcc->pipe_add(item);
     }
 }
 
@@ -308,14 +303,15 @@ static void add_drawable_surface_images(DisplayChannelClient *dcc, Drawable *dra
     dcc_push_surface_image(dcc, drawable->surface_id);
 }
 
-static void red_drawable_pipe_item_free(RedPipeItem *item)
+RedDrawablePipeItem::RedDrawablePipeItem():
+    RedPipeItem(RED_PIPE_ITEM_TYPE_DRAW)
 {
-    RedDrawablePipeItem *dpi = SPICE_UPCAST(RedDrawablePipeItem, item);
-    spice_assert(item->refcount == 0);
+}
 
-    dpi->drawable->pipes = g_list_remove(dpi->drawable->pipes, dpi);
-    drawable_unref(dpi->drawable);
-    g_free(dpi);
+RedDrawablePipeItem::~RedDrawablePipeItem()
+{
+    drawable->pipes = g_list_remove(drawable->pipes, this);
+    drawable_unref(drawable);
 }
 
 static RedDrawablePipeItem *red_drawable_pipe_item_new(DisplayChannelClient *dcc,
@@ -323,12 +319,10 @@ static RedDrawablePipeItem *red_drawable_pipe_item_new(DisplayChannelClient *dcc
 {
     RedDrawablePipeItem *dpi;
 
-    dpi = g_new0(RedDrawablePipeItem, 1);
+    dpi = new RedDrawablePipeItem;
     dpi->drawable = drawable;
     dpi->dcc = dcc;
     drawable->pipes = g_list_prepend(drawable->pipes, dpi);
-    red_pipe_item_init_full(&dpi->base, RED_PIPE_ITEM_TYPE_DRAW,
-                            red_drawable_pipe_item_free);
     drawable->refs++;
     return dpi;
 }
@@ -338,7 +332,7 @@ void dcc_prepend_drawable(DisplayChannelClient *dcc, Drawable *drawable)
     RedDrawablePipeItem *dpi = red_drawable_pipe_item_new(dcc, drawable);
 
     add_drawable_surface_images(dcc, drawable);
-    dcc->pipe_add(&dpi->base);
+    dcc->pipe_add(dpi);
 }
 
 void dcc_append_drawable(DisplayChannelClient *dcc, Drawable *drawable)
@@ -346,7 +340,7 @@ void dcc_append_drawable(DisplayChannelClient *dcc, Drawable *drawable)
     RedDrawablePipeItem *dpi = red_drawable_pipe_item_new(dcc, drawable);
 
     add_drawable_surface_images(dcc, drawable);
-    dcc->pipe_add_tail(&dpi->base);
+    dcc->pipe_add_tail(dpi);
 }
 
 void dcc_add_drawable_after(DisplayChannelClient *dcc, Drawable *drawable, RedPipeItem *pos)
@@ -354,7 +348,7 @@ void dcc_add_drawable_after(DisplayChannelClient *dcc, Drawable *drawable, RedPi
     RedDrawablePipeItem *dpi = red_drawable_pipe_item_new(dcc, drawable);
 
     add_drawable_surface_images(dcc, drawable);
-    dcc->pipe_add_after(&dpi->base, pos);
+    dcc->pipe_add_after(dpi, pos);
 }
 
 static void dcc_init_stream_agents(DisplayChannelClient *dcc)
@@ -498,28 +492,18 @@ void dcc_video_stream_agent_clip(DisplayChannelClient* dcc, VideoStreamAgent *ag
 {
     VideoStreamClipItem *item = video_stream_clip_item_new(agent);
 
-    dcc->pipe_add(&item->base);
+    dcc->pipe_add(item);
 }
 
-static void red_monitors_config_item_free(RedPipeItem *pipe_item)
+RedMonitorsConfigItem::~RedMonitorsConfigItem()
 {
-    RedMonitorsConfigItem *item = SPICE_UPCAST(RedMonitorsConfigItem, pipe_item);
-
-    monitors_config_unref(item->monitors_config);
-    g_free(item);
+    monitors_config_unref(monitors_config);
 }
 
-static RedMonitorsConfigItem *red_monitors_config_item_new(RedChannel* channel,
-                                                           MonitorsConfig *monitors_config)
+RedMonitorsConfigItem::RedMonitorsConfigItem(MonitorsConfig *init_monitors_config):
+    RedPipeItem(RED_PIPE_ITEM_TYPE_MONITORS_CONFIG)
 {
-    RedMonitorsConfigItem *mci;
-
-    mci = g_new(RedMonitorsConfigItem, 1);
-    mci->monitors_config = monitors_config_ref(monitors_config);
-
-    red_pipe_item_init_full(&mci->base, RED_PIPE_ITEM_TYPE_MONITORS_CONFIG,
-                            red_monitors_config_item_free);
-    return mci;
+    monitors_config = monitors_config_ref(init_monitors_config);
 }
 
 void dcc_push_monitors_config(DisplayChannelClient *dcc)
@@ -537,26 +521,18 @@ void dcc_push_monitors_config(DisplayChannelClient *dcc)
         return;
     }
 
-    mci = red_monitors_config_item_new(dcc->get_channel(),
-                                       monitors_config);
-    dcc->pipe_add(&mci->base);
+    mci = new RedMonitorsConfigItem(monitors_config);
+    dcc->pipe_add(mci);
 }
 
-static RedSurfaceDestroyItem *red_surface_destroy_item_new(uint32_t surface_id)
+RedSurfaceDestroyItem::RedSurfaceDestroyItem(uint32_t surface_id):
+    RedPipeItem(RED_PIPE_ITEM_TYPE_DESTROY_SURFACE)
 {
-    RedSurfaceDestroyItem *destroy;
-
-    destroy = g_new(RedSurfaceDestroyItem, 1);
-    destroy->surface_destroy.surface_id = surface_id;
-    red_pipe_item_init(&destroy->base, RED_PIPE_ITEM_TYPE_DESTROY_SURFACE);
-
-    return destroy;
+    surface_destroy.surface_id = surface_id;
 }
 
 RedPipeItem *dcc_gl_scanout_item_new(RedChannelClient *rcc, void *data, int num)
 {
-    RedGlScanoutUnixItem *item;
-
     /* FIXME: on !unix peer, start streaming with a video codec */
     if (!red_stream_is_plain_unix(rcc->get_stream()) ||
         !rcc->test_remote_cap(SPICE_DISPLAY_CAP_GL_SCANOUT)) {
@@ -566,10 +542,7 @@ RedPipeItem *dcc_gl_scanout_item_new(RedChannelClient *rcc, void *data, int num)
         return NULL;
     }
 
-    item = g_new(RedGlScanoutUnixItem, 1);
-    red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_GL_SCANOUT);
-
-    return &item->base;
+    return new RedGlScanoutUnixItem(RED_PIPE_ITEM_TYPE_GL_SCANOUT);
 }
 
 XXX_CAST(RedChannelClient, DisplayChannelClient, DISPLAY_CHANNEL_CLIENT);
@@ -589,11 +562,10 @@ RedPipeItem *dcc_gl_draw_item_new(RedChannelClient *rcc, void *data, int num)
     }
 
     dcc->priv->gl_draw_ongoing = TRUE;
-    item = g_new(RedGlDrawItem, 1);
+    item = new RedGlDrawItem(RED_PIPE_ITEM_TYPE_GL_DRAW);
     item->draw = *draw;
-    red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_GL_DRAW);
 
-    return &item->base;
+    return item;
 }
 
 void dcc_destroy_surface(DisplayChannelClient *dcc, uint32_t surface_id)
@@ -613,8 +585,8 @@ void dcc_destroy_surface(DisplayChannelClient *dcc, uint32_t surface_id)
     }
 
     dcc->priv->surface_client_created[surface_id] = FALSE;
-    destroy = red_surface_destroy_item_new(surface_id);
-    dcc->pipe_add(&destroy->base);
+    destroy = new RedSurfaceDestroyItem(surface_id);
+    dcc->pipe_add(destroy);
 }
 
 #define MIN_DIMENSION_TO_QUIC 3
diff --git a/server/dcc.h b/server/dcc.h
index 3172ba1b..3931686d 100644
--- a/server/dcc.h
+++ b/server/dcc.h
@@ -96,22 +96,26 @@ typedef struct FreeList {
 
 #define DCC_TO_DC(dcc) ((DisplayChannel*) dcc->get_channel())
 
-typedef struct RedSurfaceCreateItem {
-    RedPipeItem base;
+struct RedSurfaceCreateItem: public RedPipeItem {
+    RedSurfaceCreateItem(uint32_t surface_id,
+                         uint32_t width,
+                         uint32_t height,
+                         uint32_t format,
+                         uint32_t flags);
     SpiceMsgSurfaceCreate surface_create;
-} RedSurfaceCreateItem;
+};
 
-typedef struct RedGlScanoutUnixItem {
-    RedPipeItem base;
-} RedGlScanoutUnixItem;
+struct RedGlScanoutUnixItem: public RedPipeItem {
+    using RedPipeItem::RedPipeItem;
+};
 
-typedef struct RedGlDrawItem {
-    RedPipeItem base;
+struct RedGlDrawItem: public RedPipeItem {
+    using RedPipeItem::RedPipeItem;
     SpiceMsgDisplayGlDraw draw;
-} RedGlDrawItem;
+};
 
-typedef struct RedImageItem {
-    RedPipeItem base;
+struct RedImageItem final: public RedPipeItem {
+    RedImageItem();
     SpicePoint pos;
     int width;
     int height;
@@ -122,13 +126,14 @@ typedef struct RedImageItem {
     uint32_t image_flags;
     int can_lossy;
     uint8_t data[0];
-} RedImageItem;
+};
 
-typedef struct RedDrawablePipeItem {
-    RedPipeItem base;
+struct RedDrawablePipeItem: public RedPipeItem {
+    RedDrawablePipeItem();
+    ~RedDrawablePipeItem();
     Drawable *drawable;
     DisplayChannelClient *dcc;
-} RedDrawablePipeItem;
+};
 
 DisplayChannelClient*      dcc_new                                   (DisplayChannel *display,
                                                                       RedClient *client,
diff --git a/server/display-channel-private.h b/server/display-channel-private.h
index 8e8ee683..04552776 100644
--- a/server/display-channel-private.h
+++ b/server/display-channel-private.h
@@ -139,10 +139,11 @@ struct DisplayChannelPrivate
     GLIST_FOREACH((_channel ? _channel->get_clients() : NULL), \
                   DisplayChannelClient, _data)
 
-typedef struct RedMonitorsConfigItem {
-    RedPipeItem base;
+struct RedMonitorsConfigItem: public RedPipeItem {
+    RedMonitorsConfigItem(MonitorsConfig *monitors_config);
+    ~RedMonitorsConfigItem();
     MonitorsConfig *monitors_config;
-} RedMonitorsConfigItem;
+};
 
 enum {
     RED_PIPE_ITEM_TYPE_DRAW = RED_PIPE_ITEM_TYPE_COMMON_LAST,
@@ -181,10 +182,10 @@ uint32_t display_channel_generate_uid(DisplayChannel *display);
 int display_channel_get_video_stream_id(DisplayChannel *display, VideoStream *stream);
 VideoStream *display_channel_get_nth_video_stream(DisplayChannel *display, gint i);
 
-typedef struct RedSurfaceDestroyItem {
-    RedPipeItem base;
+struct RedSurfaceDestroyItem: public RedPipeItem {
+    RedSurfaceDestroyItem(uint32_t surface_id);
     SpiceMsgSurfaceDestroy surface_destroy;
-} RedSurfaceDestroyItem;
+};
 
 static inline int is_equal_path(SpicePath *path1, SpicePath *path2)
 {
diff --git a/server/display-channel.cpp b/server/display-channel.cpp
index 5261b348..79679c4d 100644
--- a/server/display-channel.cpp
+++ b/server/display-channel.cpp
@@ -327,7 +327,7 @@ static void pipes_add_drawable_after(DisplayChannel *display,
         dpi_pos_after = (RedDrawablePipeItem*) l->data;
 
         num_other_linked++;
-        dcc_add_drawable_after(dpi_pos_after->dcc, drawable, &dpi_pos_after->base);
+        dcc_add_drawable_after(dpi_pos_after->dcc, drawable, dpi_pos_after);
     }
 
     if (num_other_linked == 0) {
@@ -387,7 +387,7 @@ static void drawable_remove_from_pipes(Drawable *drawable)
         RedChannelClient *rcc;
 
         rcc = dpi->dcc;
-        rcc->pipe_remove_and_release(&dpi->base);
+        rcc->pipe_remove_and_release(dpi);
     }
 }
 
diff --git a/server/inputs-channel.cpp b/server/inputs-channel.cpp
index d712220f..aede5c2a 100644
--- a/server/inputs-channel.cpp
+++ b/server/inputs-channel.cpp
@@ -86,15 +86,15 @@ RedsState* spice_tablet_state_get_server(SpiceTabletState *st)
     return st->reds;
 }
 
-typedef struct RedKeyModifiersPipeItem {
-    RedPipeItem base;
+struct RedKeyModifiersPipeItem: public RedPipeItem {
+    RedKeyModifiersPipeItem(uint8_t modifiers);
     uint8_t modifiers;
-} RedKeyModifiersPipeItem;
+};
 
-typedef struct RedInputsInitPipeItem {
-    RedPipeItem base;
+struct RedInputsInitPipeItem: public RedPipeItem {
+    RedInputsInitPipeItem(uint8_t modifiers);
     uint8_t modifiers;
-} RedInputsInitPipeItem;
+};
 
 
 #define KEY_MODIFIERS_TTL (MSEC_PER_SEC * 2)
@@ -194,13 +194,10 @@ static uint8_t kbd_get_leds(SpiceKbdInstance *sin)
     return sif->get_leds(sin);
 }
 
-static RedPipeItem *red_inputs_key_modifiers_item_new(uint8_t modifiers)
+RedKeyModifiersPipeItem::RedKeyModifiersPipeItem(uint8_t init_modifiers):
+    RedPipeItem(RED_PIPE_ITEM_KEY_MODIFIERS),
+    modifiers(init_modifiers)
 {
-    RedKeyModifiersPipeItem *item = g_new(RedKeyModifiersPipeItem, 1);
-
-    red_pipe_item_init(&item->base, RED_PIPE_ITEM_KEY_MODIFIERS);
-    item->modifiers = modifiers;
-    return &item->base;
 }
 
 void InputsChannelClient::send_item(RedPipeItem *base)
@@ -214,7 +211,7 @@ void InputsChannelClient::send_item(RedPipeItem *base)
 
             init_send_data(SPICE_MSG_INPUTS_KEY_MODIFIERS);
             key_modifiers.modifiers =
-                SPICE_UPCAST(RedKeyModifiersPipeItem, base)->modifiers;
+                static_cast<RedKeyModifiersPipeItem*>(base)->modifiers;
             spice_marshall_msg_inputs_key_modifiers(m, &key_modifiers);
             break;
         }
@@ -224,7 +221,7 @@ void InputsChannelClient::send_item(RedPipeItem *base)
 
             init_send_data(SPICE_MSG_INPUTS_INIT);
             inputs_init.keyboard_modifiers =
-                SPICE_UPCAST(RedInputsInitPipeItem, base)->modifiers;
+                static_cast<RedInputsInitPipeItem*>(base)->modifiers;
             spice_marshall_msg_inputs_init(m, &inputs_init);
             break;
         }
@@ -432,14 +429,16 @@ void InputsChannel::release_keys()
     }
 }
 
-void InputsChannelClient::pipe_add_init()
+RedInputsInitPipeItem::RedInputsInitPipeItem(uint8_t init_modifiers):
+    RedPipeItem(RED_PIPE_ITEM_INPUTS_INIT),
+    modifiers(init_modifiers)
 {
-    RedInputsInitPipeItem *item = g_new(RedInputsInitPipeItem, 1);
-    InputsChannel *inputs = get_channel();
+}
 
-    red_pipe_item_init(&item->base, RED_PIPE_ITEM_INPUTS_INIT);
-    item->modifiers = kbd_get_leds(inputs->keyboard);
-    pipe_add_push(&item->base);
+void InputsChannelClient::pipe_add_init()
+{
+    auto modifiers = kbd_get_leds(get_channel()->keyboard);
+    pipe_add_push(new RedInputsInitPipeItem(modifiers));
 }
 
 void InputsChannel::on_connect(RedClient *client, RedStream *stream, int migration,
@@ -464,7 +463,7 @@ void InputsChannel::push_keyboard_modifiers()
     if (!is_connected() || src_during_migrate) {
         return;
     }
-    pipes_add(red_inputs_key_modifiers_item_new(modifiers));
+    pipes_add(new RedKeyModifiersPipeItem(modifiers));
 }
 
 SPICE_GNUC_VISIBLE int spice_server_kbd_leds(SpiceKbdInstance *sin, int leds)
diff --git a/server/main-channel-client.cpp b/server/main-channel-client.cpp
index 90df5704..139d2a34 100644
--- a/server/main-channel-client.cpp
+++ b/server/main-channel-client.cpp
@@ -61,65 +61,67 @@ struct MainChannelClientPrivate {
     uint8_t recv_buf[MAIN_CHANNEL_RECEIVE_BUF_SIZE];
 };
 
-typedef struct RedPingPipeItem {
-    RedPipeItem base;
+struct RedPingPipeItem: public RedPipeItem {
+    using RedPipeItem::RedPipeItem;
     int size;
-} RedPingPipeItem;
+};
 
-typedef struct RedTokensPipeItem {
-    RedPipeItem base;
+struct RedTokensPipeItem: public RedPipeItem {
+    using RedPipeItem::RedPipeItem;
     int tokens;
-} RedTokensPipeItem;
+};
 
-typedef struct RedAgentDataPipeItem {
-    RedPipeItem base;
+struct RedAgentDataPipeItem: public RedPipeItem {
+    using RedPipeItem::RedPipeItem;
+    ~RedAgentDataPipeItem();
     uint8_t* data;
     size_t len;
     spice_marshaller_item_free_func free_data;
     void *opaque;
-} RedAgentDataPipeItem;
+};
 
-typedef struct RedInitPipeItem {
-    RedPipeItem base;
+struct RedInitPipeItem: public RedPipeItem {
+    using RedPipeItem::RedPipeItem;
     int connection_id;
     int display_channels_hint;
     int current_mouse_mode;
     int is_client_mouse_allowed;
     int multi_media_time;
     int ram_hint;
-} RedInitPipeItem;
+};
 
-typedef struct RedNamePipeItem {
-    RedPipeItem base;
+struct RedNamePipeItem: public RedPipeItem {
+    using RedPipeItem::RedPipeItem;
     SpiceMsgMainName msg;
-} RedNamePipeItem;
+};
 
-typedef struct RedUuidPipeItem {
-    RedPipeItem base;
+struct RedUuidPipeItem: public RedPipeItem {
+    using RedPipeItem::RedPipeItem;
     SpiceMsgMainUuid msg;
-} RedUuidPipeItem;
+};
 
-typedef struct RedNotifyPipeItem {
-    RedPipeItem base;
+struct RedNotifyPipeItem: public RedPipeItem {
+    using RedPipeItem::RedPipeItem;
+    ~RedNotifyPipeItem();
     char *msg;
-} RedNotifyPipeItem;
+};
 
-typedef struct RedMouseModePipeItem {
-    RedPipeItem base;
+struct RedMouseModePipeItem: public RedPipeItem {
+    using RedPipeItem::RedPipeItem;
     SpiceMouseMode current_mode;
     int is_client_mouse_allowed;
-} RedMouseModePipeItem;
+};
 
-typedef struct RedMultiMediaTimePipeItem {
-    RedPipeItem base;
+struct RedMultiMediaTimePipeItem: public RedPipeItem {
+    using RedPipeItem::RedPipeItem;
     uint32_t time;
-} RedMultiMediaTimePipeItem;
+};
 
-typedef struct RedRegisteredChannelPipeItem {
-    RedPipeItem base;
+struct RedRegisteredChannelPipeItem: public RedPipeItem {
+    using RedPipeItem::RedPipeItem;
     uint32_t channel_type;
     uint32_t channel_id;
-} RedRegisteredChannelPipeItem;
+};
 
 #define ZERO_BUF_SIZE 4096
 
@@ -157,21 +159,17 @@ void MainChannelClient::on_disconnect()
 
 static void main_channel_client_push_ping(MainChannelClient *mcc, int size);
 
-static void main_notify_item_free(RedPipeItem *base)
+RedNotifyPipeItem::~RedNotifyPipeItem()
 {
-    RedNotifyPipeItem *data = SPICE_UPCAST(RedNotifyPipeItem, base);
-    g_free(data->msg);
-    g_free(data);
+    g_free(msg);
 }
 
 static RedPipeItem *main_notify_item_new(const char *msg, int num)
 {
-    RedNotifyPipeItem *item = g_new(RedNotifyPipeItem, 1);
+    RedNotifyPipeItem *item = new RedNotifyPipeItem(RED_PIPE_ITEM_TYPE_MAIN_NOTIFY);
 
-    red_pipe_item_init_full(&item->base, RED_PIPE_ITEM_TYPE_MAIN_NOTIFY,
-                            main_notify_item_free);
     item->msg = g_strdup(msg);
-    return &item->base;
+    return item;
 }
 
 void MainChannelClient::start_net_test(int test_rate)
@@ -195,11 +193,10 @@ void MainChannelClient::start_net_test(int test_rate)
 
 static RedPipeItem *red_ping_item_new(int size)
 {
-    RedPingPipeItem *item = g_new(RedPingPipeItem, 1);
+    RedPingPipeItem *item = new RedPingPipeItem(RED_PIPE_ITEM_TYPE_MAIN_PING);
 
-    red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_MAIN_PING);
     item->size = size;
-    return &item->base;
+    return item;
 }
 
 static void main_channel_client_push_ping(MainChannelClient *mcc, int size)
@@ -210,11 +207,10 @@ static void main_channel_client_push_ping(MainChannelClient *mcc, int size)
 
 static RedPipeItem *main_agent_tokens_item_new(uint32_t num_tokens)
 {
-    RedTokensPipeItem *item = g_new(RedTokensPipeItem, 1);
+    RedTokensPipeItem *item = new RedTokensPipeItem(RED_PIPE_ITEM_TYPE_MAIN_AGENT_TOKEN);
 
-    red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_MAIN_AGENT_TOKEN);
     item->tokens = num_tokens;
-    return &item->base;
+    return item;
 }
 
 
@@ -225,26 +221,22 @@ void MainChannelClient::push_agent_tokens(uint32_t num_tokens)
     pipe_add_push(item);
 }
 
-static void main_agent_data_item_free(RedPipeItem *base)
+RedAgentDataPipeItem::~RedAgentDataPipeItem()
 {
-    RedAgentDataPipeItem *item = SPICE_UPCAST(RedAgentDataPipeItem, base);
-    item->free_data(item->data, item->opaque);
-    g_free(item);
+    free_data(data, opaque);
 }
 
 static RedPipeItem *main_agent_data_item_new(uint8_t* data, size_t len,
                                              spice_marshaller_item_free_func free_data,
                                              void *opaque)
 {
-    RedAgentDataPipeItem *item = g_new(RedAgentDataPipeItem, 1);
+    RedAgentDataPipeItem *item = new RedAgentDataPipeItem(RED_PIPE_ITEM_TYPE_MAIN_AGENT_DATA);
 
-    red_pipe_item_init_full(&item->base, RED_PIPE_ITEM_TYPE_MAIN_AGENT_DATA,
-                            main_agent_data_item_free);
     item->data = data;
     item->len = len;
     item->free_data = free_data;
     item->opaque = opaque;
-    return &item->base;
+    return item;
 }
 
 void MainChannelClient::push_agent_data(uint8_t *data, size_t len,
@@ -264,16 +256,15 @@ static RedPipeItem *main_init_item_new(int connection_id,
                                        int multi_media_time,
                                        int ram_hint)
 {
-    RedInitPipeItem *item = g_new(RedInitPipeItem, 1);
+    RedInitPipeItem *item = new RedInitPipeItem(RED_PIPE_ITEM_TYPE_MAIN_INIT);
 
-    red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_MAIN_INIT);
     item->connection_id = connection_id;
     item->display_channels_hint = display_channels_hint;
     item->current_mouse_mode = current_mouse_mode;
     item->is_client_mouse_allowed = is_client_mouse_allowed;
     item->multi_media_time = multi_media_time;
     item->ram_hint = ram_hint;
-    return &item->base;
+    return item;
 }
 
 void MainChannelClient::push_init(int display_channels_hint,
@@ -291,13 +282,11 @@ void MainChannelClient::push_init(int display_channels_hint,
 
 static RedPipeItem *main_name_item_new(const char *name)
 {
-    RedNamePipeItem *item = (RedNamePipeItem*) g_malloc(sizeof(RedNamePipeItem) + strlen(name) + 1);
-
-    red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_MAIN_NAME);
+    RedNamePipeItem *item = new (strlen(name) + 1) RedNamePipeItem(RED_PIPE_ITEM_TYPE_MAIN_NAME);
     item->msg.name_len = strlen(name) + 1;
     memcpy(&item->msg.name, name, item->msg.name_len);
 
-    return &item->base;
+    return item;
 }
 
 void MainChannelClient::push_name(const char *name)
@@ -313,12 +302,11 @@ void MainChannelClient::push_name(const char *name)
 
 static RedPipeItem *main_uuid_item_new(const uint8_t uuid[16])
 {
-    RedUuidPipeItem *item = g_new(RedUuidPipeItem, 1);
+    RedUuidPipeItem *item = new RedUuidPipeItem(RED_PIPE_ITEM_TYPE_MAIN_UUID);
 
-    red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_MAIN_UUID);
     memcpy(item->msg.uuid, uuid, sizeof(item->msg.uuid));
 
-    return &item->base;
+    return item;
 }
 
 void MainChannelClient::push_uuid(const uint8_t uuid[16])
@@ -340,34 +328,31 @@ void MainChannelClient::push_notify(const char *msg)
 
 RedPipeItem *main_mouse_mode_item_new(SpiceMouseMode current_mode, int is_client_mouse_allowed)
 {
-    RedMouseModePipeItem *item = g_new(RedMouseModePipeItem, 1);
+    RedMouseModePipeItem *item = new RedMouseModePipeItem(RED_PIPE_ITEM_TYPE_MAIN_MOUSE_MODE);
 
-    red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_MAIN_MOUSE_MODE);
     item->current_mode = current_mode;
     item->is_client_mouse_allowed = is_client_mouse_allowed;
-    return &item->base;
+    return item;
 }
 
 RedPipeItem *main_multi_media_time_item_new(uint32_t mm_time)
 {
     RedMultiMediaTimePipeItem *item;
 
-    item = g_new(RedMultiMediaTimePipeItem, 1);
-    red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_MAIN_MULTI_MEDIA_TIME);
+    item = new RedMultiMediaTimePipeItem(RED_PIPE_ITEM_TYPE_MAIN_MULTI_MEDIA_TIME);
     item->time = mm_time;
-    return &item->base;
+    return item;
 }
 
 RedPipeItem *registered_channel_item_new(RedChannel *channel)
 {
     RedRegisteredChannelPipeItem *item;
 
-    item = g_new0(RedRegisteredChannelPipeItem, 1);
-    red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_MAIN_REGISTERED_CHANNEL);
+    item = new RedRegisteredChannelPipeItem(RED_PIPE_ITEM_TYPE_MAIN_REGISTERED_CHANNEL);
 
     item->channel_type = channel->type();
     item->channel_id = channel->id();
-    return &item->base;
+    return item;
 }
 
 void MainChannelClient::handle_migrate_connected(int success, int seamless)
@@ -684,7 +669,7 @@ static void main_channel_marshall_agent_data(RedChannelClient *rcc,
 {
     rcc->init_send_data(SPICE_MSG_MAIN_AGENT_DATA);
     /* since pipe item owns the data, keep it alive until it's sent */
-    item->base.add_to_marshaller(m, item->data, item->len);
+    item->add_to_marshaller(m, item->data, item->len);
 }
 
 static void main_channel_marshall_migrate_data_item(RedChannelClient *rcc,
@@ -863,22 +848,22 @@ void MainChannelClient::send_item(RedPipeItem *base)
             break;
         case RED_PIPE_ITEM_TYPE_MAIN_PING:
             main_channel_marshall_ping(this, m,
-                SPICE_UPCAST(RedPingPipeItem, base));
+                static_cast<RedPingPipeItem*>(base));
             break;
         case RED_PIPE_ITEM_TYPE_MAIN_MOUSE_MODE:
             main_channel_marshall_mouse_mode(this, m,
-                SPICE_UPCAST(RedMouseModePipeItem, base));
+                static_cast<RedMouseModePipeItem*>(base));
             break;
         case RED_PIPE_ITEM_TYPE_MAIN_AGENT_DISCONNECTED:
             main_channel_marshall_agent_disconnected(this, m, base);
             break;
         case RED_PIPE_ITEM_TYPE_MAIN_AGENT_TOKEN:
             main_channel_marshall_tokens(this, m,
-                SPICE_UPCAST(RedTokensPipeItem, base));
+                static_cast<RedTokensPipeItem*>(base));
             break;
         case RED_PIPE_ITEM_TYPE_MAIN_AGENT_DATA:
             main_channel_marshall_agent_data(this, m,
-                SPICE_UPCAST(RedAgentDataPipeItem, base));
+                static_cast<RedAgentDataPipeItem*>(base));
             break;
         case RED_PIPE_ITEM_TYPE_MAIN_MIGRATE_DATA:
             main_channel_marshall_migrate_data_item(this, m, base);
@@ -886,11 +871,11 @@ void MainChannelClient::send_item(RedPipeItem *base)
         case RED_PIPE_ITEM_TYPE_MAIN_INIT:
             priv->init_sent = TRUE;
             main_channel_marshall_init(this, m,
-                SPICE_UPCAST(RedInitPipeItem, base));
+                static_cast<RedInitPipeItem*>(base));
             break;
         case RED_PIPE_ITEM_TYPE_MAIN_NOTIFY:
             main_channel_marshall_notify(this, m,
-                SPICE_UPCAST(RedNotifyPipeItem, base));
+                static_cast<RedNotifyPipeItem*>(base));
             break;
         case RED_PIPE_ITEM_TYPE_MAIN_MIGRATE_BEGIN:
             main_channel_marshall_migrate_begin(m, this, base);
@@ -900,18 +885,18 @@ void MainChannelClient::send_item(RedPipeItem *base)
             break;
         case RED_PIPE_ITEM_TYPE_MAIN_MULTI_MEDIA_TIME:
             main_channel_marshall_multi_media_time(this, m,
-                SPICE_UPCAST(RedMultiMediaTimePipeItem, base));
+                static_cast<RedMultiMediaTimePipeItem*>(base));
             break;
         case RED_PIPE_ITEM_TYPE_MAIN_MIGRATE_SWITCH_HOST:
             main_channel_marshall_migrate_switch(m, this, base);
             break;
         case RED_PIPE_ITEM_TYPE_MAIN_NAME:
             init_send_data(SPICE_MSG_MAIN_NAME);
-            spice_marshall_msg_main_name(m, &SPICE_UPCAST(RedNamePipeItem, base)->msg);
+            spice_marshall_msg_main_name(m, &static_cast<RedNamePipeItem*>(base)->msg);
             break;
         case RED_PIPE_ITEM_TYPE_MAIN_UUID:
             init_send_data(SPICE_MSG_MAIN_UUID);
-            spice_marshall_msg_main_uuid(m, &SPICE_UPCAST(RedUuidPipeItem, base)->msg);
+            spice_marshall_msg_main_uuid(m, &static_cast<RedUuidPipeItem*>(base)->msg);
             break;
         case RED_PIPE_ITEM_TYPE_MAIN_AGENT_CONNECTED_TOKENS:
             main_channel_marshall_agent_connected(m, this, base);
@@ -925,7 +910,7 @@ void MainChannelClient::send_item(RedPipeItem *base)
                 return;
             }
             main_channel_marshall_registered_channel(this, m,
-                SPICE_UPCAST(RedRegisteredChannelPipeItem, base));
+                static_cast<RedRegisteredChannelPipeItem*>(base));
             break;
         default:
             break;
diff --git a/server/red-channel-client.cpp b/server/red-channel-client.cpp
index 38934db5..eed6a53a 100644
--- a/server/red-channel-client.cpp
+++ b/server/red-channel-client.cpp
@@ -239,15 +239,15 @@ static const SpiceDataHeaderOpaque mini_header_wrapper = {NULL, sizeof(SpiceMini
 #define PING_TEST_LONG_TIMEOUT_MS (MSEC_PER_SEC * 60 * 5)
 #define PING_TEST_IDLE_NET_TIMEOUT_MS (MSEC_PER_SEC / 10)
 
-typedef struct RedEmptyMsgPipeItem {
-    RedPipeItem base;
+struct RedEmptyMsgPipeItem: public RedPipeItem {
+    using RedPipeItem::RedPipeItem;
     int msg;
-} RedEmptyMsgPipeItem;
+};
 
-typedef struct MarkerPipeItem {
-    RedPipeItem base;
+struct MarkerPipeItem: public RedPipeItem {
+    using RedPipeItem::RedPipeItem;
     bool item_sent;
-} MarkerPipeItem;
+};
 
 void RedChannelClientPrivate::start_ping_timer(uint32_t timeout)
 {
@@ -488,7 +488,7 @@ void RedChannelClient::send_ping()
 
 void RedChannelClient::send_empty_msg(RedPipeItem *base)
 {
-    RedEmptyMsgPipeItem *msg_pipe_item = SPICE_UPCAST(RedEmptyMsgPipeItem, base);
+    RedEmptyMsgPipeItem *msg_pipe_item = static_cast<RedEmptyMsgPipeItem*>(base);
 
     init_send_data(msg_pipe_item->msg);
     begin_send_message();
@@ -512,7 +512,7 @@ void RedChannelClient::send_any_item(RedPipeItem *item)
             send_ping();
             break;
         case RED_PIPE_ITEM_TYPE_MARKER:
-            SPICE_UPCAST(MarkerPipeItem, item)->item_sent = true;
+            static_cast<MarkerPipeItem*>(item)->item_sent = true;
             break;
         default:
             send_item(item);
@@ -1428,19 +1428,17 @@ void RedChannelClient::pipe_add_tail(RedPipeItem *item)
 
 void RedChannelClient::pipe_add_type(int pipe_item_type)
 {
-    RedPipeItem *item = g_new(RedPipeItem, 1);
+    RedPipeItem *item = new RedPipeItem(pipe_item_type);
 
-    red_pipe_item_init(item, pipe_item_type);
     pipe_add(item);
 }
 
 RedPipeItem *RedChannelClient::new_empty_msg(int msg_type)
 {
-    RedEmptyMsgPipeItem *item = g_new(RedEmptyMsgPipeItem, 1);
+    RedEmptyMsgPipeItem *item = new RedEmptyMsgPipeItem(RED_PIPE_ITEM_TYPE_EMPTY_MSG);
 
-    red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_EMPTY_MSG);
     item->msg = msg_type;
-    return &item->base;
+    return item;
 }
 
 void RedChannelClient::pipe_add_empty_msg(int msg_type)
@@ -1578,12 +1576,11 @@ bool RedChannelClient::wait_pipe_item_sent(GList *item_pos, int64_t timeout)
         end_time = UINT64_MAX;
     }
 
-    MarkerPipeItem *mark_item = g_new0(MarkerPipeItem, 1);
+    MarkerPipeItem *mark_item = new MarkerPipeItem(RED_PIPE_ITEM_TYPE_MARKER);
 
-    red_pipe_item_init(&mark_item->base, RED_PIPE_ITEM_TYPE_MARKER);
     mark_item->item_sent = false;
-    red_pipe_item_ref(&mark_item->base);
-    pipe_add_before_pos(&mark_item->base, item_pos);
+    red_pipe_item_ref(mark_item);
+    pipe_add_before_pos(mark_item, item_pos);
 
     for (;;) {
         receive();
@@ -1596,7 +1593,7 @@ bool RedChannelClient::wait_pipe_item_sent(GList *item_pos, int64_t timeout)
     }
 
     item_sent = mark_item->item_sent;
-    red_pipe_item_unref(&mark_item->base);
+    red_pipe_item_unref(mark_item);
 
     if (!item_sent) {
         // still on the queue
diff --git a/server/red-channel.cpp b/server/red-channel.cpp
index cfe2e606..bedb323a 100644
--- a/server/red-channel.cpp
+++ b/server/red-channel.cpp
@@ -280,9 +280,7 @@ void RedChannel::pipes_add(RedPipeItem *item)
 
 void RedChannel::pipes_add_type(int pipe_item_type)
 {
-    RedPipeItem *item = g_new(RedPipeItem, 1);
-
-    red_pipe_item_init(item, pipe_item_type);
+    RedPipeItem *item = new RedPipeItem(pipe_item_type);
 
     pipes_add(item);
 }
diff --git a/server/red-pipe-item.cpp b/server/red-pipe-item.cpp
index 9d1ff8c4..1aedd700 100644
--- a/server/red-pipe-item.cpp
+++ b/server/red-pipe-item.cpp
@@ -20,31 +20,25 @@
 #include "red-channel.h"
 #include "red-pipe-item.h"
 
-RedPipeItem *red_pipe_item_ref(RedPipeItem *item)
+RedPipeItem::RedPipeItem(int init_type):
+    type(init_type)
 {
-    g_return_val_if_fail(item->refcount > 0, NULL);
-
-    g_atomic_int_inc(&item->refcount);
-
-    return item;
+    // compatibility with no shared_ptr reference counting
+    shared_ptr_add_ref(this);
 }
 
-void red_pipe_item_unref(RedPipeItem *item)
+RedPipeItem *red_pipe_item_ref(RedPipeItem *item)
 {
-    g_return_if_fail(item->refcount > 0);
+    // this call should be replaced by shared_ptr instead
+    shared_ptr_add_ref(item);
 
-    if (g_atomic_int_dec_and_test(&item->refcount)) {
-        item->free_func(item);
-    }
+    return item;
 }
 
-void red_pipe_item_init_full(RedPipeItem *item,
-                             gint type,
-                             red_pipe_item_free_t *free_func)
+void red_pipe_item_unref(RedPipeItem *item)
 {
-    item->type = type;
-    item->refcount = 1;
-    item->free_func = free_func ? free_func : (red_pipe_item_free_t *)g_free;
+    // this call should be replaced by shared_ptr instead
+    shared_ptr_unref(item);
 }
 
 static void marshaller_unref_pipe_item(uint8_t *, void *opaque)
diff --git a/server/red-pipe-item.h b/server/red-pipe-item.h
index 5d81aacb..2bad0d8e 100644
--- a/server/red-pipe-item.h
+++ b/server/red-pipe-item.h
@@ -16,40 +16,57 @@
    License along with this library; if not, see <http://www.gnu.org/licenses/>.
 */
 
+/**
+ * @file red-pipe-item.h
+ * Generic declaration for objects contained in RedChannelClient pipe.
+ */
 #ifndef RED_PIPE_ITEM_H_
 #define RED_PIPE_ITEM_H_
 
-#include <stddef.h>
-#include <inttypes.h>
-
-#include "common/marshaller.h"
+#include "red-common.h"
+#include "utils.hpp"
 
 #include "push-visibility.h"
 
-typedef struct RedPipeItem RedPipeItem;
-
-typedef void red_pipe_item_free_t(RedPipeItem *item);
-
-struct RedPipeItem {
-    int type;
+/**
+ * Base class for objects contained in RedChannelClient pipe
+ */
+struct RedPipeItem: public red::shared_ptr_counted
+{
+    SPICE_CXX_GLIB_ALLOCATOR
+    void *operator new(size_t len, void *p)
+    {
+        return p;
+    }
+
+    /**
+     * Allows to allocate a pipe item with additional space at the end.
+     *
+     * Used with structures like
+     * @code{.cpp}
+     * struct NameItem: public RedPipeItem {
+     *   ...
+     *   char name[];
+     * }
+     * ...
+     * auto name_item = red::shared_ptr<NameItem>(new (6) NameItem(...));
+     * strcpy(name_item->name, "hello");
+     * @endcode
+     */
+    void *operator new(size_t size, size_t additional)
+    {
+        return g_malloc(size + additional);
+    }
+
+    RedPipeItem(int type);
+    const int type;
 
     void add_to_marshaller(SpiceMarshaller *m, uint8_t *data, size_t size);
-
-    /* private */
-    int refcount;
-
-    red_pipe_item_free_t *free_func;
 };
 
-void red_pipe_item_init_full(RedPipeItem *item, int type, red_pipe_item_free_t free_func);
 RedPipeItem *red_pipe_item_ref(RedPipeItem *item);
 void red_pipe_item_unref(RedPipeItem *item);
 
-static inline void red_pipe_item_init(RedPipeItem *item, int type)
-{
-    red_pipe_item_init_full(item, type, NULL);
-}
-
 #include "pop-visibility.h"
 
 #endif /* RED_PIPE_ITEM_H_ */
diff --git a/server/reds.cpp b/server/reds.cpp
index a4d4e837..900dbe73 100644
--- a/server/reds.cpp
+++ b/server/reds.cpp
@@ -153,13 +153,15 @@ struct ChannelSecurityOptions {
     ChannelSecurityOptions *next;
 };
 
-typedef struct RedVDIReadBuf {
-    RedPipeItem base;
+struct RedVDIReadBuf final: public RedPipeItem {
+    using RedPipeItem::RedPipeItem;
+    ~RedVDIReadBuf();
+
     RedCharDeviceVDIPort *dev;
 
     int len;
     uint8_t data[SPICE_AGENT_MAX_DATA_SIZE];
-} RedVDIReadBuf;
+};
 
 typedef enum {
     VDI_PORT_READ_STATE_READ_HEADER,
@@ -238,7 +240,6 @@ static uint32_t reds_qxl_ram_size(RedsState *reds);
 static int calc_compression_level(RedsState *reds);
 
 static RedVDIReadBuf *vdi_port_get_read_buf(RedCharDeviceVDIPort *dev);
-static red_pipe_item_free_t vdi_port_read_buf_free;
 
 static ChannelSecurityOptions *reds_find_channel_security(RedsState *reds, int id)
 {
@@ -405,7 +406,7 @@ static void reds_reset_vdp(RedsState *reds)
     dev->priv->receive_len = sizeof(dev->priv->vdi_chunk_header);
     dev->priv->message_receive_len = 0;
     if (dev->priv->current_read_buf) {
-        red_pipe_item_unref(&dev->priv->current_read_buf->base);
+        red_pipe_item_unref(dev->priv->current_read_buf);
         dev->priv->current_read_buf = NULL;
     }
     /* Reset read filter to start with clean state when the agent reconnects */
@@ -658,7 +659,7 @@ static void reds_agent_remove(RedsState *reds)
 static void vdi_port_read_buf_release(uint8_t *data, void *opaque)
 {
     RedVDIReadBuf *read_buf = (RedVDIReadBuf *)opaque;
-    red_pipe_item_unref(&read_buf->base);
+    red_pipe_item_unref(read_buf);
 }
 
 /*
@@ -681,15 +682,25 @@ static AgentMsgFilterResult vdi_port_read_buf_process(RedCharDeviceVDIPort *dev,
     }
 }
 
-static RedVDIReadBuf *vdi_read_buf_new(RedCharDeviceVDIPort *dev)
+RedVDIReadBuf::~RedVDIReadBuf()
 {
-    RedVDIReadBuf *buf = g_new(RedVDIReadBuf, 1);
+    dev->priv->num_read_buf--;
 
+    /* read_one_msg_from_vdi_port may have never completed because we
+       reached buffer limit. So we call it again so it can complete its work if
+       necessary. Note that since we can be called from red_char_device_wakeup
+       this can cause recursion, but we have protection for that */
+    if (dev->priv->agent_attached) {
+       dev->wakeup();
+    }
+}
+
+static RedVDIReadBuf *vdi_read_buf_new(RedCharDeviceVDIPort *dev)
+{
     /* Bogus pipe item type, we only need the RingItem and refcounting
      * from the base class and are not going to use the type
      */
-    red_pipe_item_init_full(&buf->base, -1,
-                            vdi_port_read_buf_free);
+    RedVDIReadBuf *buf = new RedVDIReadBuf(-1);
     buf->dev = dev;
     buf->len = 0;
     return buf;
@@ -705,23 +716,6 @@ static RedVDIReadBuf *vdi_port_get_read_buf(RedCharDeviceVDIPort *dev)
     return vdi_read_buf_new(dev);
 }
 
-static void vdi_port_read_buf_free(RedPipeItem *base)
-{
-    RedVDIReadBuf *buf = SPICE_UPCAST(RedVDIReadBuf, base);
-
-    g_warn_if_fail(buf->base.refcount == 0);
-    buf->dev->priv->num_read_buf--;
-
-    /* read_one_msg_from_vdi_port may have never completed because we
-       reached buffer limit. So we call it again so it can complete its work if
-       necessary. Note that since we can be called from red_char_device_wakeup
-       this can cause recursion, but we have protection for that */
-    if (buf->dev->priv->agent_attached) {
-       buf->dev->wakeup();
-    }
-    g_free(buf);
-}
-
 /* certain agent capabilities can be overridden and disabled in the server. In these cases, unset
  * these capabilities before sending them on to the client */
 static void reds_adjust_agent_capabilities(RedsState *reds, VDAgentMessage *message)
@@ -807,14 +801,14 @@ RedCharDeviceVDIPort::read_one_msg_from_device()
             switch (vdi_port_read_buf_process(this, dispatch_buf)) {
             case AGENT_MSG_FILTER_OK:
                 reds_adjust_agent_capabilities(reds, (VDAgentMessage *) dispatch_buf->data);
-                return &dispatch_buf->base;
+                return dispatch_buf;
             case AGENT_MSG_FILTER_PROTO_ERROR:
                 reds_agent_remove(reds);
                 /* fall through */
             case AGENT_MSG_FILTER_MONITORS_CONFIG:
                 /* fall through */
             case AGENT_MSG_FILTER_DISCARD:
-                red_pipe_item_unref(&dispatch_buf->base);
+                red_pipe_item_unref(dispatch_buf);
             }
         }
         } /* END switch */
@@ -911,7 +905,7 @@ void reds_send_device_display_info(RedsState *reds)
 void RedCharDeviceVDIPort::send_msg_to_client(RedPipeItem *msg, RedCharDeviceClientOpaque *opaque)
 {
     RedClient *client = (RedClient *) opaque;
-    RedVDIReadBuf *agent_data_buf = (RedVDIReadBuf *)msg;
+    RedVDIReadBuf *agent_data_buf = static_cast<RedVDIReadBuf*>(msg);
 
     red_pipe_item_ref(msg);
     client->get_main()->push_agent_data(agent_data_buf->data,
@@ -1283,7 +1277,7 @@ void reds_on_main_channel_migrate(RedsState *reds, MainChannelClient *mcc)
         case AGENT_MSG_FILTER_MONITORS_CONFIG:
             /* fall through */
         case AGENT_MSG_FILTER_DISCARD:
-            red_pipe_item_unref(&read_buf->base);
+            red_pipe_item_unref(read_buf);
         }
 
         spice_assert(agent_dev->priv->receive_len);
@@ -4472,7 +4466,7 @@ RedCharDeviceVDIPort::~RedCharDeviceVDIPort()
     /* make sure we have no other references to RedVDIReadBuf buffers */
     reset();
     if (priv->current_read_buf) {
-        red_pipe_item_unref(&priv->current_read_buf->base);
+        red_pipe_item_unref(priv->current_read_buf);
         priv->current_read_buf = NULL;
     }
     g_free(priv->mig_data);
diff --git a/server/smartcard-channel-client.cpp b/server/smartcard-channel-client.cpp
index 40d98989..7a8166d7 100644
--- a/server/smartcard-channel-client.cpp
+++ b/server/smartcard-channel-client.cpp
@@ -32,11 +32,11 @@ struct SmartCardChannelClientPrivate
     bool msg_in_write_buf = false;
 };
 
-typedef struct RedErrorItem {
-    RedPipeItem base;
+struct RedErrorItem: public RedPipeItem {
+    using RedPipeItem::RedPipeItem;
     VSCMsgHeader vheader;
     VSCMsgError  error;
-} RedErrorItem;
+};
 
 SmartCardChannelClient::SmartCardChannelClient(RedChannel *channel,
                                                RedClient *client,
@@ -129,7 +129,7 @@ void smartcard_channel_client_send_data(RedChannelClient *rcc,
 
 void smartcard_channel_client_send_error(RedChannelClient *rcc, SpiceMarshaller *m, RedPipeItem *item)
 {
-    RedErrorItem* error_item = SPICE_UPCAST(RedErrorItem, item);
+    RedErrorItem* error_item = static_cast<RedErrorItem*>(item);
 
     smartcard_channel_client_send_data(rcc, m, item, &error_item->vheader);
 }
@@ -138,15 +138,13 @@ static void smartcard_channel_client_push_error(RedChannelClient *rcc,
                                                 uint32_t reader_id,
                                                 VSCErrorCode error)
 {
-    RedErrorItem *error_item = g_new0(RedErrorItem, 1);
-
-    red_pipe_item_init(&error_item->base, RED_PIPE_ITEM_TYPE_ERROR);
+    RedErrorItem *error_item = new RedErrorItem(RED_PIPE_ITEM_TYPE_ERROR);
 
     error_item->vheader.reader_id = reader_id;
     error_item->vheader.type = VSC_Error;
     error_item->vheader.length = sizeof(error_item->error);
     error_item->error.code = error;
-    rcc->pipe_add_push(&error_item->base);
+    rcc->pipe_add_push(error_item);
 }
 
 static void smartcard_channel_client_add_reader(SmartCardChannelClient *scc)
diff --git a/server/smartcard.cpp b/server/smartcard.cpp
index 4af60c63..39d46da7 100644
--- a/server/smartcard.cpp
+++ b/server/smartcard.cpp
@@ -67,11 +67,11 @@ struct RedCharDeviceSmartcardPrivate {
     int                  reader_added; // has reader_add been sent to the device
 };
 
-typedef struct RedMsgItem {
-    RedPipeItem base;
-
+struct RedMsgItem: public RedPipeItem {
+    using RedPipeItem::RedPipeItem;
+    ~RedMsgItem();
     VSCMsgHeader* vheader;
-} RedMsgItem;
+};
 
 static RedMsgItem *smartcard_new_vsc_msg_item(unsigned int reader_id, const VSCMsgHeader *vheader);
 
@@ -138,9 +138,9 @@ RedCharDeviceSmartcard::read_one_msg_from_device()
         dev->priv->buf_used = remaining;
         if (msg_to_client) {
             if (dev->priv->scc) {
-                dev->priv->scc->pipe_add_push(&msg_to_client->base);
+                dev->priv->scc->pipe_add_push(msg_to_client);
             } else {
-                red_pipe_item_unref(&msg_to_client->base);
+                red_pipe_item_unref(msg_to_client);
             }
         }
     }
@@ -338,7 +338,7 @@ SmartCardChannelClient* smartcard_char_device_get_client(RedCharDeviceSmartcard
 static void smartcard_channel_send_msg(RedChannelClient *rcc,
                                        SpiceMarshaller *m, RedPipeItem *item)
 {
-    RedMsgItem* msg_item = SPICE_UPCAST(RedMsgItem, item);
+    RedMsgItem* msg_item = static_cast<RedMsgItem*>(item);
 
     smartcard_channel_client_send_data(rcc, m, item, msg_item->vheader);
 }
@@ -390,19 +390,15 @@ void SmartCardChannelClient::send_item(RedPipeItem *item)
     begin_send_message();
 }
 
-static void smartcard_free_vsc_msg_item(RedPipeItem *base)
+RedMsgItem::~RedMsgItem()
 {
-    RedMsgItem *item = SPICE_UPCAST(RedMsgItem, base);
-    g_free(item->vheader);
-    g_free(item);
+    g_free(vheader);
 }
 
 static RedMsgItem *smartcard_new_vsc_msg_item(unsigned int reader_id, const VSCMsgHeader *vheader)
 {
-    RedMsgItem *msg_item = g_new0(RedMsgItem, 1);
+    RedMsgItem *msg_item = new RedMsgItem(RED_PIPE_ITEM_TYPE_SMARTCARD_DATA);
 
-    red_pipe_item_init_full(&msg_item->base, RED_PIPE_ITEM_TYPE_SMARTCARD_DATA,
-                            smartcard_free_vsc_msg_item);
     msg_item->vheader = (VSCMsgHeader*) g_memdup(vheader, sizeof(*vheader) + vheader->length);
     /* We patch the reader_id, since the device only knows about itself, and
      * we know about the sum of readers. */
diff --git a/server/sound.cpp b/server/sound.cpp
index bfcf5124..a35d6753 100644
--- a/server/sound.cpp
+++ b/server/sound.cpp
@@ -74,11 +74,17 @@ struct RecordChannelClient;
 struct AudioFrame;
 struct AudioFrameContainer;
 
-struct PersistentPipeItem: public RedPipeItem
+/* This pipe item is never deleted and added to the queue when messages
+ * have to be sent.
+ * This is used to have a simple item in RedChannelClient queue but to send
+ * multiple messages in a row if possible.
+ * During realtime sound transmission you usually don't want to queue too
+ * much data or having retransmission preferring instead loosing some
+ * samples.
+ */
+struct PersistentPipeItem final: public RedPipeItem
 {
     PersistentPipeItem();
-private:
-    static void item_free(RedPipeItem *item);
 };
 
 /* Connects an audio client to a Spice client */
@@ -610,21 +616,8 @@ static bool playback_send_mode(PlaybackChannelClient *playback_client)
     return true;
 }
 
-PersistentPipeItem::PersistentPipeItem()
-{
-    red_pipe_item_init_full(this, RED_PIPE_ITEM_PERSISTENT, item_free);
-}
-
-/* This function is called when the "persistent" item is removed from the
- * queue. Note that there is not free call as the item is allocated into
- * SndChannelClient.
- * This is used to have a simple item in RedChannelClient queue but to send
- * multiple messages in a row if possible.
- * During realtime sound transmission you usually don't want to queue too
- * much data or having retransmission preferring instead loosing some
- * samples.
- */
-void PersistentPipeItem::item_free(RedPipeItem *item)
+PersistentPipeItem::PersistentPipeItem():
+    RedPipeItem(RED_PIPE_ITEM_PERSISTENT)
 {
 }
 
diff --git a/server/spicevmc.cpp b/server/spicevmc.cpp
index bb7a0216..6eb34ae8 100644
--- a/server/spicevmc.cpp
+++ b/server/spicevmc.cpp
@@ -45,15 +45,15 @@
 struct RedVmcChannel;
 class VmcChannelClient;
 
-typedef struct RedVmcPipeItem {
-    RedPipeItem base;
+struct RedVmcPipeItem: public RedPipeItem {
+    using RedPipeItem::RedPipeItem;
 
     SpiceDataCompressionType type;
     uint32_t uncompressed_data_size;
     /* writes which don't fit this will get split, this is not a problem */
     uint8_t buf[BUF_SIZE];
     uint32_t buf_used;
-} RedVmcPipeItem;
+};
 
 struct RedCharDeviceSpiceVmc: public RedCharDevice
 {
@@ -158,7 +158,7 @@ RedVmcChannel::~RedVmcChannel()
 {
     RedCharDevice::write_buffer_release(chardev, &recv_from_client_buf);
     if (pipe_item) {
-        red_pipe_item_unref(&pipe_item->base);
+        red_pipe_item_unref(pipe_item);
     }
 }
 
@@ -183,16 +183,19 @@ static red::shared_ptr<RedVmcChannel> red_vmc_channel_new(RedsState *reds, uint8
     return red::make_shared<RedVmcChannel>(reds, channel_type, id);
 }
 
-typedef struct RedPortInitPipeItem {
-    RedPipeItem base;
+struct RedPortInitPipeItem: public RedPipeItem {
+    using RedPipeItem::RedPipeItem;
+    ~RedPortInitPipeItem();
+
     char* name;
     uint8_t opened;
-} RedPortInitPipeItem;
+};
+
+struct RedPortEventPipeItem: public RedPipeItem {
+    using RedPipeItem::RedPipeItem;
 
-typedef struct RedPortEventPipeItem {
-    RedPipeItem base;
     uint8_t event;
-} RedPortEventPipeItem;
+};
 
 enum {
     RED_PIPE_ITEM_TYPE_SPICEVMC_DATA = RED_PIPE_ITEM_TYPE_CHANNEL_BASE,
@@ -225,8 +228,7 @@ static RedVmcPipeItem* try_compress_lz4(RedVmcChannel *channel, int n, RedVmcPip
         /* Client doesn't have compression cap - data will not be compressed */
         return NULL;
     }
-    msg_item_compressed = g_new0(RedVmcPipeItem, 1);
-    red_pipe_item_init(&msg_item_compressed->base, RED_PIPE_ITEM_TYPE_SPICEVMC_DATA);
+    msg_item_compressed = new RedVmcPipeItem(RED_PIPE_ITEM_TYPE_SPICEVMC_DATA);
     compressed_data_count = LZ4_compress_default((char*)&msg_item->buf,
                                                  (char*)&msg_item_compressed->buf,
                                                  n,
@@ -258,9 +260,8 @@ RedPipeItem* RedCharDeviceSpiceVmc::read_one_msg_from_device()
     }
 
     if (!channel->pipe_item) {
-        msg_item = g_new0(RedVmcPipeItem, 1);
+        msg_item = new RedVmcPipeItem(RED_PIPE_ITEM_TYPE_SPICEVMC_DATA);
         msg_item->type = SPICE_DATA_COMPRESSION_TYPE_NONE;
-        red_pipe_item_init(&msg_item->base, RED_PIPE_ITEM_TYPE_SPICEVMC_DATA);
     } else {
         spice_assert(channel->pipe_item->buf_used == 0);
         msg_item = channel->pipe_item;
@@ -289,33 +290,28 @@ RedPipeItem* RedCharDeviceSpiceVmc::read_one_msg_from_device()
     return NULL;
 }
 
-static void red_port_init_item_free(struct RedPipeItem *base)
+RedPortInitPipeItem::~RedPortInitPipeItem()
 {
-    RedPortInitPipeItem *item = SPICE_UPCAST(RedPortInitPipeItem, base);
-
-    g_free(item->name);
-    g_free(item);
+    g_free(name);
 }
 
 static void spicevmc_port_send_init(VmcChannelClient *rcc)
 {
     RedVmcChannel *channel = rcc->get_channel();
     SpiceCharDeviceInstance *sin = channel->chardev_sin;
-    RedPortInitPipeItem *item = g_new(RedPortInitPipeItem, 1);
+    RedPortInitPipeItem *item = new RedPortInitPipeItem(RED_PIPE_ITEM_TYPE_PORT_INIT);
 
-    red_pipe_item_init_full(&item->base, RED_PIPE_ITEM_TYPE_PORT_INIT, red_port_init_item_free);
     item->name = g_strdup(sin->portname);
     item->opened = channel->port_opened;
-    rcc->pipe_add_push(&item->base);
+    rcc->pipe_add_push(item);
 }
 
 static void spicevmc_port_send_event(RedChannelClient *rcc, uint8_t event)
 {
-    RedPortEventPipeItem *item = g_new(RedPortEventPipeItem, 1);
+    RedPortEventPipeItem *item = new RedPortEventPipeItem(RED_PIPE_ITEM_TYPE_PORT_EVENT);
 
-    red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_PORT_EVENT);
     item->event = event;
-    rcc->pipe_add_push(&item->base);
+    rcc->pipe_add_push(item);
 }
 
 void RedCharDeviceSpiceVmc::remove_client(RedCharDeviceClientOpaque *opaque)
@@ -510,14 +506,14 @@ static void
 spicevmc_red_channel_queue_data(RedVmcChannel *channel, RedVmcPipeItem *item)
 {
     channel->queued_data += item->buf_used;
-    channel->rcc->pipe_add_push(&item->base);
+    channel->rcc->pipe_add_push(item);
 }
 
 static void spicevmc_red_channel_send_data(VmcChannelClient *rcc,
                                            SpiceMarshaller *m,
                                            RedPipeItem *item)
 {
-    RedVmcPipeItem *i = SPICE_UPCAST(RedVmcPipeItem, item);
+    RedVmcPipeItem *i = static_cast<RedVmcPipeItem*>(item);
     RedVmcChannel *channel = rcc->get_channel();
 
     /* for compatibility send using not compressed data message */
@@ -561,7 +557,7 @@ static void spicevmc_red_channel_send_port_init(RedChannelClient *rcc,
                                                 SpiceMarshaller *m,
                                                 RedPipeItem *item)
 {
-    RedPortInitPipeItem *i = SPICE_UPCAST(RedPortInitPipeItem, item);
+    RedPortInitPipeItem *i = static_cast<RedPortInitPipeItem*>(item);
     SpiceMsgPortInit init;
 
     rcc->init_send_data(SPICE_MSG_PORT_INIT);
@@ -575,7 +571,7 @@ static void spicevmc_red_channel_send_port_event(RedChannelClient *rcc,
                                                  SpiceMarshaller *m,
                                                  RedPipeItem *item)
 {
-    RedPortEventPipeItem *i = SPICE_UPCAST(RedPortEventPipeItem, item);
+    RedPortEventPipeItem *i = static_cast<RedPortEventPipeItem*>(item);
     SpiceMsgPortEvent event;
 
     rcc->init_send_data(SPICE_MSG_PORT_EVENT);
diff --git a/server/stream-channel.cpp b/server/stream-channel.cpp
index bcccbe5d..9fe527c4 100644
--- a/server/stream-channel.cpp
+++ b/server/stream-channel.cpp
@@ -67,17 +67,19 @@ enum {
     RED_PIPE_ITEM_TYPE_MONITORS_CONFIG,
 };
 
-typedef struct StreamCreateItem {
-    RedPipeItem base;
+struct StreamCreateItem: public RedPipeItem {
+    using RedPipeItem::RedPipeItem;
     SpiceMsgDisplayStreamCreate stream_create;
-} StreamCreateItem;
+};
+
+struct StreamDataItem: public RedPipeItem {
+    using RedPipeItem::RedPipeItem;
+    ~StreamDataItem();
 
-typedef struct StreamDataItem {
-    RedPipeItem base;
     StreamChannel *channel;
     // NOTE: this must be the last field in the structure
     SpiceMsgDisplayStreamData data;
-} StreamDataItem;
+};
 
 #define PRIMARY_SURFACE_ID 0
 
@@ -210,7 +212,7 @@ void StreamChannelClient::send_item(RedPipeItem *pipe_item)
         break;
     }
     case RED_PIPE_ITEM_TYPE_STREAM_CREATE: {
-        StreamCreateItem *item = SPICE_UPCAST(StreamCreateItem, pipe_item);
+        StreamCreateItem *item = static_cast<StreamCreateItem*>(pipe_item);
         stream_id = item->stream_create.id;
         init_send_data(SPICE_MSG_DISPLAY_STREAM_CREATE);
         spice_marshall_msg_display_stream_create(m, &item->stream_create);
@@ -231,7 +233,7 @@ void StreamChannelClient::send_item(RedPipeItem *pipe_item)
         break;
     }
     case RED_PIPE_ITEM_TYPE_STREAM_DATA: {
-        StreamDataItem *item = SPICE_UPCAST(StreamDataItem, pipe_item);
+        StreamDataItem *item = static_cast<StreamDataItem*>(pipe_item);
         init_send_data(SPICE_MSG_DISPLAY_STREAM_DATA);
         spice_marshall_msg_display_stream_data(m, &item->data);
         pipe_item->add_to_marshaller(m, item->data.data, item->data.data_size);
@@ -424,8 +426,7 @@ StreamChannel::change_format(const StreamMsgFormat *fmt)
     stream_id = (stream_id + 1) % NUM_STREAMS;
 
     // send create stream
-    StreamCreateItem *item = g_new0(StreamCreateItem, 1);
-    red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_STREAM_CREATE);
+    StreamCreateItem *item = new StreamCreateItem(RED_PIPE_ITEM_TYPE_STREAM_CREATE);
     item->stream_create.id = stream_id;
     item->stream_create.flags = SPICE_STREAM_FLAGS_TOP_DOWN;
     item->stream_create.codec_type = fmt->codec;
@@ -435,7 +436,7 @@ StreamChannel::change_format(const StreamMsgFormat *fmt)
     item->stream_create.src_height = fmt->height;
     item->stream_create.dest = (SpiceRect) { 0, 0, fmt->width, fmt->height };
     item->stream_create.clip = (SpiceClip) { SPICE_CLIP_TYPE_NONE, NULL };
-    pipes_add(&item->base);
+    pipes_add(item);
 
     // activate stream report if possible
     pipes_add_type(RED_PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT);
@@ -451,14 +452,9 @@ StreamChannel::update_queue_stat(int32_t num_diff, int32_t size_diff)
     }
 }
 
-void
-StreamChannel::data_item_free(RedPipeItem *base)
+StreamDataItem::~StreamDataItem()
 {
-    StreamDataItem *pipe_item = SPICE_UPCAST(StreamDataItem, base);
-
-    pipe_item->channel->update_queue_stat(-1, -pipe_item->data.data_size);
-
-    g_free(pipe_item);
+    channel->update_queue_stat(-1, -data.data_size);
 }
 
 void
@@ -471,9 +467,7 @@ StreamChannel::send_data(const void *data, size_t size, uint32_t mm_time)
         return;
     }
 
-    StreamDataItem *item = (StreamDataItem*) g_malloc(sizeof(*item) + size);
-    red_pipe_item_init_full(&item->base, RED_PIPE_ITEM_TYPE_STREAM_DATA,
-                            data_item_free);
+    StreamDataItem *item = new (size) StreamDataItem(RED_PIPE_ITEM_TYPE_STREAM_DATA);
     item->data.base.id = stream_id;
     item->data.base.multi_media_time = mm_time;
     item->data.data_size = size;
@@ -481,7 +475,7 @@ StreamChannel::send_data(const void *data, size_t size, uint32_t mm_time)
     update_queue_stat(1, size);
     // TODO try to optimize avoiding the copy
     memcpy(item->data.data, data, size);
-    pipes_add(&item->base);
+    pipes_add(item);
 }
 
 void
diff --git a/server/stream-channel.h b/server/stream-channel.h
index 6b4c76e3..9a65460f 100644
--- a/server/stream-channel.h
+++ b/server/stream-channel.h
@@ -50,10 +50,12 @@ struct StreamQueueStat {
 typedef void (*stream_channel_queue_stat_proc)(void *opaque, const StreamQueueStat *stats,
                                                StreamChannel *channel);
 
+struct StreamDataItem;
 struct StreamChannelClient;
 struct StreamChannel final: public RedChannel
 {
     friend struct StreamChannelClient;
+    friend struct StreamDataItem;
     StreamChannel(RedsState *reds, uint32_t id);
 
     /**
@@ -73,7 +75,6 @@ private:
 
     inline void update_queue_stat(int32_t num_diff, int32_t size_diff);
     void request_new_stream(StreamMsgStartStop *start);
-    static void data_item_free(RedPipeItem *base);
 
     /* current video stream id, <0 if not initialized or
      * we are not sending a stream */
diff --git a/server/video-stream.cpp b/server/video-stream.cpp
index 9a6df289..02d01e32 100644
--- a/server/video-stream.cpp
+++ b/server/video-stream.cpp
@@ -64,24 +64,20 @@ static void video_stream_agent_stats_print(VideoStreamAgent *agent)
 #endif
 }
 
-static void video_stream_create_destroy_item_release(RedPipeItem *base)
+StreamCreateDestroyItem::~StreamCreateDestroyItem()
 {
-    StreamCreateDestroyItem *item = SPICE_UPCAST(StreamCreateDestroyItem, base);
-    DisplayChannel *display = DCC_TO_DC(item->agent->dcc);
-    video_stream_agent_unref(display, item->agent);
-    g_free(item);
+    DisplayChannel *display = DCC_TO_DC(agent->dcc);
+    video_stream_agent_unref(display, agent);
 }
 
 static RedPipeItem *video_stream_create_destroy_item_new(VideoStreamAgent *agent,
-                                                         gint type)
+                                                         int type)
 {
-    StreamCreateDestroyItem *item = g_new0(StreamCreateDestroyItem, 1);
+    StreamCreateDestroyItem *item = new StreamCreateDestroyItem(type);
 
-    red_pipe_item_init_full(&item->base, type,
-                            video_stream_create_destroy_item_release);
     agent->stream->refs++;
     item->agent = agent;
-    return &item->base;
+    return item;
 }
 
 static RedPipeItem *video_stream_create_item_new(VideoStreamAgent *agent)
@@ -163,24 +159,17 @@ void video_stream_agent_unref(DisplayChannel *display, VideoStreamAgent *agent)
     video_stream_unref(display, agent->stream);
 }
 
-static void video_stream_clip_item_free(RedPipeItem *base)
+VideoStreamClipItem::~VideoStreamClipItem()
 {
-    g_return_if_fail(base != NULL);
-    VideoStreamClipItem *item = SPICE_UPCAST(VideoStreamClipItem, base);
-    DisplayChannel *display = DCC_TO_DC(item->stream_agent->dcc);
-
-    g_return_if_fail(item->base.refcount == 0);
+    DisplayChannel *display = DCC_TO_DC(stream_agent->dcc);
 
-    video_stream_agent_unref(display, item->stream_agent);
-    g_free(item->rects);
-    g_free(item);
+    video_stream_agent_unref(display, stream_agent);
+    g_free(rects);
 }
 
 VideoStreamClipItem *video_stream_clip_item_new(VideoStreamAgent *agent)
 {
-    VideoStreamClipItem *item = g_new(VideoStreamClipItem, 1);
-    red_pipe_item_init_full(&item->base, RED_PIPE_ITEM_TYPE_STREAM_CLIP,
-                            video_stream_clip_item_free);
+    VideoStreamClipItem *item = new VideoStreamClipItem(RED_PIPE_ITEM_TYPE_STREAM_CLIP);
 
     item->stream_agent = agent;
     agent->stream->refs++;
@@ -364,7 +353,7 @@ static void before_reattach_stream(DisplayChannel *display,
         dcc = dpi->dcc;
         agent = dcc_get_video_stream_agent(dcc, index);
 
-        if (dcc->pipe_item_is_linked(&dpi->base)) {
+        if (dcc->pipe_item_is_linked(dpi)) {
 #ifdef STREAM_STATS
             agent->stats.num_drops_pipe++;
 #endif
@@ -784,14 +773,13 @@ void dcc_create_stream(DisplayChannelClient *dcc, VideoStream *stream)
     dcc->pipe_add(video_stream_create_item_new(agent));
 
     if (dcc->test_remote_cap(SPICE_DISPLAY_CAP_STREAM_REPORT)) {
-        RedStreamActivateReportItem *report_pipe_item = g_new0(RedStreamActivateReportItem, 1);
+        RedStreamActivateReportItem *report_pipe_item =
+            new RedStreamActivateReportItem(RED_PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT);
 
         agent->report_id = rand();
-        red_pipe_item_init(&report_pipe_item->base,
-                           RED_PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT);
         report_pipe_item->stream_id = stream_id;
         report_pipe_item->report_id = agent->report_id;
-        dcc->pipe_add(&report_pipe_item->base);
+        dcc->pipe_add(report_pipe_item);
     }
 #ifdef STREAM_STATS
     memset(&agent->stats, 0, sizeof(StreamStats));
@@ -812,17 +800,10 @@ void video_stream_agent_stop(VideoStreamAgent *agent)
     }
 }
 
-static void red_upgrade_item_free(RedPipeItem *base)
+RedUpgradeItem::~RedUpgradeItem()
 {
-    g_return_if_fail(base != NULL);
-
-    RedUpgradeItem *item = SPICE_UPCAST(RedUpgradeItem, base);
-
-    g_return_if_fail(item->base.refcount == 0);
-
-    drawable_unref(item->drawable);
-    g_free(item->rects);
-    g_free(item);
+    drawable_unref(drawable);
+    g_free(rects);
 }
 
 /*
@@ -861,9 +842,7 @@ static void dcc_detach_stream_gracefully(DisplayChannelClient *dcc,
         }
         spice_debug("stream %d: upgrade by drawable. box ==>", stream_id);
         rect_debug(&stream->current->red_drawable->bbox);
-        upgrade_item = g_new(RedUpgradeItem, 1);
-        red_pipe_item_init_full(&upgrade_item->base, RED_PIPE_ITEM_TYPE_UPGRADE,
-                                red_upgrade_item_free);
+        upgrade_item = new RedUpgradeItem(RED_PIPE_ITEM_TYPE_UPGRADE);
         upgrade_item->drawable = stream->current;
         upgrade_item->drawable->refs++;
         n_rects = pixman_region32_n_rects(&upgrade_item->drawable->tree_item.base.rgn);
@@ -871,7 +850,7 @@ static void dcc_detach_stream_gracefully(DisplayChannelClient *dcc,
         upgrade_item->rects->num_rects = n_rects;
         region_ret_rects(&upgrade_item->drawable->tree_item.base.rgn,
                          upgrade_item->rects->rects, n_rects);
-        dcc->pipe_add(&upgrade_item->base);
+        dcc->pipe_add(upgrade_item);
 
     } else {
         SpiceRect upgrade_area;
diff --git a/server/video-stream.h b/server/video-stream.h
index b12e24a0..e35d740f 100644
--- a/server/video-stream.h
+++ b/server/video-stream.h
@@ -49,17 +49,18 @@ typedef struct VideoStream VideoStream;
 
 /* This item is used to send a full quality image (lossless) of the area where the stream was.
  * This to avoid the artifacts due to the lossy compression. */
-typedef struct RedUpgradeItem {
-    RedPipeItem base;
+struct RedUpgradeItem: public RedPipeItem {
+    using RedPipeItem::RedPipeItem;
+    ~RedUpgradeItem();
     Drawable *drawable;
     SpiceClipRects *rects;
-} RedUpgradeItem;
+};
 
-typedef struct RedStreamActivateReportItem {
-    RedPipeItem base;
+struct RedStreamActivateReportItem: public RedPipeItem {
+    using RedPipeItem::RedPipeItem;
     uint32_t stream_id;
     uint32_t report_id;
-} RedStreamActivateReportItem;
+};
 
 #ifdef STREAM_STATS
 typedef struct StreamStats {
@@ -95,19 +96,21 @@ typedef struct VideoStreamAgent {
 #endif
 } VideoStreamAgent;
 
-typedef struct VideoStreamClipItem {
-    RedPipeItem base;
+struct VideoStreamClipItem: public RedPipeItem {
+    using RedPipeItem::RedPipeItem;
+    ~VideoStreamClipItem();
     VideoStreamAgent *stream_agent;
     int clip_type;
     SpiceClipRects *rects;
-} VideoStreamClipItem;
+};
 
 VideoStreamClipItem *video_stream_clip_item_new(VideoStreamAgent *agent);
 
-typedef struct StreamCreateDestroyItem {
-    RedPipeItem base;
+struct StreamCreateDestroyItem: public RedPipeItem {
+    using RedPipeItem::RedPipeItem;
+    ~StreamCreateDestroyItem();
     VideoStreamAgent *agent;
-} StreamCreateDestroyItem;
+};
 
 typedef struct ItemTrace {
     red_time_t time;
commit 45e964dc5a2e2f86437da0ef3d31ddb650109f40
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Fri Jun 5 14:03:35 2020 +0100

    red-pipe-item: Better encapsulate marshaller_unref_pipe_item
    
    To avoid memory errors marshaller_unref_pipe_item should be
    matched with a previous call to red_pipe_item_ref.
    This is correctly done but to reduce the possibility of breaking
    this rule move both referencing and unreferencing into a new
    RedPipeItem::add_to_marshaller method.
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
    Acked-by: Julien Ropé <jrope at gmail.com>

diff --git a/server/cursor-channel.cpp b/server/cursor-channel.cpp
index 05b7228a..835597f4 100644
--- a/server/cursor-channel.cpp
+++ b/server/cursor-channel.cpp
@@ -89,9 +89,7 @@ static void cursor_fill(CursorChannelClient *ccc, RedCursorPipeItem *cursor,
 
     if (red_cursor->data_size) {
         SpiceMarshaller *m2 = spice_marshaller_get_submarshaller(m);
-        red_pipe_item_ref(&cursor->base);
-        spice_marshaller_add_by_ref_full(m2, red_cursor->data, red_cursor->data_size,
-                                         marshaller_unref_pipe_item, &cursor->base);
+        cursor->base.add_to_marshaller(m2, red_cursor->data, red_cursor->data_size);
     }
 }
 
diff --git a/server/dcc-send.cpp b/server/dcc-send.cpp
index 727507fb..7c070f3a 100644
--- a/server/dcc-send.cpp
+++ b/server/dcc-send.cpp
@@ -1969,10 +1969,8 @@ static void red_marshall_image(DisplayChannelClient *dcc,
 
         spice_marshall_Image(src_bitmap_out, &red_image,
                              &bitmap_palette_out, &lzplt_palette_out);
-        red_pipe_item_ref(&item->base);
-        spice_marshaller_add_by_ref_full(src_bitmap_out, item->data,
-                                         bitmap.y * bitmap.stride,
-                                         marshaller_unref_pipe_item, item);
+        item->base.add_to_marshaller(src_bitmap_out, item->data,
+                                     bitmap.y * bitmap.stride);
         region_remove(surface_lossy_region, &copy.base.box);
     }
     spice_chunks_destroy(chunks);
diff --git a/server/main-channel-client.cpp b/server/main-channel-client.cpp
index 6c0a8200..90df5704 100644
--- a/server/main-channel-client.cpp
+++ b/server/main-channel-client.cpp
@@ -684,8 +684,7 @@ static void main_channel_marshall_agent_data(RedChannelClient *rcc,
 {
     rcc->init_send_data(SPICE_MSG_MAIN_AGENT_DATA);
     /* since pipe item owns the data, keep it alive until it's sent */
-    red_pipe_item_ref(&item->base);
-    spice_marshaller_add_by_ref_full(m, item->data, item->len, marshaller_unref_pipe_item, item);
+    item->base.add_to_marshaller(m, item->data, item->len);
 }
 
 static void main_channel_marshall_migrate_data_item(RedChannelClient *rcc,
diff --git a/server/red-pipe-item.cpp b/server/red-pipe-item.cpp
index 4581b94b..9d1ff8c4 100644
--- a/server/red-pipe-item.cpp
+++ b/server/red-pipe-item.cpp
@@ -47,8 +47,15 @@ void red_pipe_item_init_full(RedPipeItem *item,
     item->free_func = free_func ? free_func : (red_pipe_item_free_t *)g_free;
 }
 
-void marshaller_unref_pipe_item(uint8_t *data G_GNUC_UNUSED, void *opaque)
+static void marshaller_unref_pipe_item(uint8_t *, void *opaque)
 {
     RedPipeItem *item = (RedPipeItem*) opaque;
     red_pipe_item_unref(item);
 }
+
+void RedPipeItem::add_to_marshaller(SpiceMarshaller *m, uint8_t *data, size_t size)
+{
+    red_pipe_item_ref(this);
+    spice_marshaller_add_by_ref_full(m, data, size,
+                                     marshaller_unref_pipe_item, this);
+}
diff --git a/server/red-pipe-item.h b/server/red-pipe-item.h
index 42a29926..5d81aacb 100644
--- a/server/red-pipe-item.h
+++ b/server/red-pipe-item.h
@@ -22,7 +22,9 @@
 #include <stddef.h>
 #include <inttypes.h>
 
-SPICE_BEGIN_DECLS
+#include "common/marshaller.h"
+
+#include "push-visibility.h"
 
 typedef struct RedPipeItem RedPipeItem;
 
@@ -31,6 +33,8 @@ typedef void red_pipe_item_free_t(RedPipeItem *item);
 struct RedPipeItem {
     int type;
 
+    void add_to_marshaller(SpiceMarshaller *m, uint8_t *data, size_t size);
+
     /* private */
     int refcount;
 
@@ -46,9 +50,6 @@ static inline void red_pipe_item_init(RedPipeItem *item, int type)
     red_pipe_item_init_full(item, type, NULL);
 }
 
-/* a convenience function for unreffing a pipe item after it has been sent */
-void marshaller_unref_pipe_item(uint8_t *data, void *opaque);
-
-SPICE_END_DECLS
+#include "pop-visibility.h"
 
 #endif /* RED_PIPE_ITEM_H_ */
diff --git a/server/smartcard-channel-client.cpp b/server/smartcard-channel-client.cpp
index 6ee692e0..40d98989 100644
--- a/server/smartcard-channel-client.cpp
+++ b/server/smartcard-channel-client.cpp
@@ -121,12 +121,10 @@ void smartcard_channel_client_send_data(RedChannelClient *rcc,
 {
     spice_assert(rcc);
     spice_assert(vheader);
+    rcc->init_send_data(SPICE_MSG_SMARTCARD_DATA);
     /* NOTE: 'vheader' is assumed to be owned by 'item' so we keep the pipe
      * item valid until the message is actually sent. */
-    red_pipe_item_ref(item);
-    rcc->init_send_data(SPICE_MSG_SMARTCARD_DATA);
-    spice_marshaller_add_by_ref_full(m, (uint8_t*)vheader, sizeof(VSCMsgHeader) + vheader->length,
-                                     marshaller_unref_pipe_item, item);
+    item->add_to_marshaller(m, (uint8_t*)vheader, sizeof(VSCMsgHeader) + vheader->length);
 }
 
 void smartcard_channel_client_send_error(RedChannelClient *rcc, SpiceMarshaller *m, RedPipeItem *item)
diff --git a/server/spicevmc.cpp b/server/spicevmc.cpp
index 8f1d8cfb..bb7a0216 100644
--- a/server/spicevmc.cpp
+++ b/server/spicevmc.cpp
@@ -532,9 +532,7 @@ static void spicevmc_red_channel_send_data(VmcChannelClient *rcc,
         };
         spice_marshall_SpiceMsgCompressedData(m, &compressed_msg);
     }
-    red_pipe_item_ref(item);
-    spice_marshaller_add_by_ref_full(m, i->buf, i->buf_used,
-                                     marshaller_unref_pipe_item, item);
+    item->add_to_marshaller(m, i->buf, i->buf_used);
 
     // account for sent data and wake up device if was blocked
     uint32_t old_queued_data = channel->queued_data;
diff --git a/server/stream-channel.cpp b/server/stream-channel.cpp
index 81fb1ce7..bcccbe5d 100644
--- a/server/stream-channel.cpp
+++ b/server/stream-channel.cpp
@@ -234,9 +234,7 @@ void StreamChannelClient::send_item(RedPipeItem *pipe_item)
         StreamDataItem *item = SPICE_UPCAST(StreamDataItem, pipe_item);
         init_send_data(SPICE_MSG_DISPLAY_STREAM_DATA);
         spice_marshall_msg_display_stream_data(m, &item->data);
-        red_pipe_item_ref(pipe_item);
-        spice_marshaller_add_by_ref_full(m, item->data.data, item->data.data_size,
-                                         marshaller_unref_pipe_item, pipe_item);
+        pipe_item->add_to_marshaller(m, item->data.data, item->data.data_size);
         record(stream_channel_data, "Stream data packet size %u mm_time %u",
                item->data.data_size, item->data.base.multi_media_time);
         break;


More information about the Spice-commits mailing list