This patch allocates VMC IDs by finding the first ID not used instead of using a global variable and incrementing the value for each channel created. This solves some potential issues: - remove the global state potentially making possible to use multiple SpiceServer on the same process; - don't potentially overflow the variable. This can happen if channels are allocated/deallocated multiple times (currently not done by Qemu). Signed-off-by: Frediano Ziglio <fziglio@xxxxxxxxxx> --- server/reds.c | 32 ++++++++++++++++++++++++++++++++ server/reds.h | 1 + server/spicevmc.c | 10 ++++++++-- 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/server/reds.c b/server/reds.c index a738afc3..b6ecc6c6 100644 --- a/server/reds.c +++ b/server/reds.c @@ -408,6 +408,38 @@ RedChannel *reds_find_channel(RedsState *reds, uint32_t type, uint32_t id) return NULL; } +/* Search for first free channel id for a specific channel type. + * Return first id free or <0 if not found. */ +int reds_get_free_channel_id(RedsState *reds, uint32_t type) +{ + RedChannel *channel; + + // this mark if some IDs are used. + // The size of the array limits the possible id returned but + // usually the IDs used for a channel type are not much. + bool used_ids[256]; + + unsigned n; + + // mark id used for the specific channel type + memset(used_ids, 0, sizeof(used_ids)); + GLIST_FOREACH(reds->channels, RedChannel, channel) { + uint32_t this_type, this_id; + g_object_get(channel, "channel-type", &this_type, "id", &this_id, NULL); + if (this_type == type && this_id < SPICE_N_ELEMENTS(used_ids)) { + used_ids[this_id] = true; + } + } + + // find first ID not marked as used + for (n = 0; n < SPICE_N_ELEMENTS(used_ids); ++n) { + if (!used_ids[n]) { + return n; + } + } + return -1; +} + static void reds_mig_cleanup(RedsState *reds) { if (reds->mig_inprogress) { diff --git a/server/reds.h b/server/reds.h index ee5a46c0..4f5fc28c 100644 --- a/server/reds.h +++ b/server/reds.h @@ -48,6 +48,7 @@ uint32_t reds_get_mm_time(void); void reds_register_channel(RedsState *reds, RedChannel *channel); void reds_unregister_channel(RedsState *reds, RedChannel *channel); RedChannel *reds_find_channel(RedsState *reds, uint32_t type, uint32_t id); +int reds_get_free_channel_id(RedsState *reds, uint32_t type); SpiceMouseMode reds_get_mouse_mode(RedsState *reds); // used by inputs_channel gboolean reds_config_get_agent_mouse(const RedsState *reds); // used by inputs_channel int reds_has_vdagent(RedsState *reds); // used by inputs channel diff --git a/server/spicevmc.c b/server/spicevmc.c index 9305c9b4..08d9954b 100644 --- a/server/spicevmc.c +++ b/server/spicevmc.c @@ -272,7 +272,6 @@ red_vmc_channel_finalize(GObject *object) static RedVmcChannel *red_vmc_channel_new(RedsState *reds, uint8_t channel_type) { GType gtype = G_TYPE_NONE; - static uint8_t id[SPICE_END_CHANNEL] = { 0, }; switch (channel_type) { case SPICE_CHANNEL_USBREDIR: @@ -288,11 +287,18 @@ static RedVmcChannel *red_vmc_channel_new(RedsState *reds, uint8_t channel_type) g_error("Unsupported channel_type for red_vmc_channel_new(): %u", channel_type); return NULL; } + + int id = reds_get_free_channel_id(reds, channel_type); + if (id < 0) { + g_warning("Free ID not found creating new VMC channel"); + return NULL; + } + return g_object_new(gtype, "spice-server", reds, "core-interface", reds_get_core_interface(reds), "channel-type", channel_type, - "id", id[channel_type]++, + "id", id, "handle-acks", FALSE, "migration-flags", (SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER), -- 2.13.5 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/spice-devel