From 20333da8516e5eccbb9b8f783b8abcfa27a141fd Mon Sep 17 00:00:00 2001 From: CentOS Buildsys Date: Jan 29 2014 17:41:57 +0000 Subject: import spice-0.12.4-5.el7.src.rpm --- diff --git a/SOURCES/0001-red_channel-prevent-adding-and-pushing-pipe-items-af.patch b/SOURCES/0001-red_channel-prevent-adding-and-pushing-pipe-items-af.patch index aab0d8e..0c6baf8 100644 --- a/SOURCES/0001-red_channel-prevent-adding-and-pushing-pipe-items-af.patch +++ b/SOURCES/0001-red_channel-prevent-adding-and-pushing-pipe-items-af.patch @@ -1,8 +1,8 @@ -From 47e722b85ccd0b6876ca189a3d6f6f05289fe3c3 Mon Sep 17 00:00:00 2001 +From a8c04050adea390fa183a117a8c092fb2ca70620 Mon Sep 17 00:00:00 2001 From: Yonit Halperin Date: Wed, 24 Jul 2013 14:54:23 -0400 -Subject: [PATCH 1/8] red_channel: prevent adding and pushing pipe items after - a channel_client has diconnected +Subject: [PATCH] red_channel: prevent adding and pushing pipe items after a + channel_client has diconnected Fixes: leaks of pipe items & "red_client_destroy: assertion `rcc->send_data.size == 0'" @@ -28,10 +28,10 @@ we should hit "spice_assert(rcc->pipe_size == 0)". 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/server/red_channel.c b/server/red_channel.c -index 33af388..0d74413 100644 +index 85d7ebc..fa4db7b 100644 --- a/server/red_channel.c +++ b/server/red_channel.c -@@ -1527,9 +1527,23 @@ void red_channel_pipe_item_init(RedChannel *channel, PipeItem *item, int type) +@@ -1515,9 +1515,23 @@ void red_channel_pipe_item_init(RedChannel *channel, PipeItem *item, int type) item->type = type; } @@ -56,7 +56,7 @@ index 33af388..0d74413 100644 rcc->pipe_size++; ring_add(&rcc->pipe, &item->link); } -@@ -1543,10 +1557,10 @@ void red_channel_client_pipe_add_push(RedChannelClient *rcc, PipeItem *item) +@@ -1531,10 +1545,10 @@ void red_channel_client_pipe_add_push(RedChannelClient *rcc, PipeItem *item) void red_channel_client_pipe_add_after(RedChannelClient *rcc, PipeItem *item, PipeItem *pos) { @@ -70,7 +70,7 @@ index 33af388..0d74413 100644 rcc->pipe_size++; ring_add_after(&item->link, &pos->link); } -@@ -1560,14 +1574,18 @@ int red_channel_client_pipe_item_is_linked(RedChannelClient *rcc, +@@ -1548,14 +1562,18 @@ int red_channel_client_pipe_item_is_linked(RedChannelClient *rcc, void red_channel_client_pipe_add_tail_no_push(RedChannelClient *rcc, PipeItem *item) { @@ -91,6 +91,3 @@ index 33af388..0d74413 100644 rcc->pipe_size++; ring_add_before(&item->link, &rcc->pipe); red_channel_client_push(rcc); --- -1.8.3.1 - diff --git a/SOURCES/0002-red_channel-add-ref-count-to-RedClient.patch b/SOURCES/0002-red_channel-add-ref-count-to-RedClient.patch index 10e24b9..2756a14 100644 --- a/SOURCES/0002-red_channel-add-ref-count-to-RedClient.patch +++ b/SOURCES/0002-red_channel-add-ref-count-to-RedClient.patch @@ -1,7 +1,7 @@ -From aab45618cc12799d5f7351ef8832ae73b33057c7 Mon Sep 17 00:00:00 2001 +From d30642a50a407974e809a62a771d5e0c107dc297 Mon Sep 17 00:00:00 2001 From: Yonit Halperin Date: Fri, 26 Jul 2013 13:45:16 -0400 -Subject: [PATCH 2/8] red_channel: add ref count to RedClient +Subject: [PATCH] red_channel: add ref count to RedClient --- server/red_channel.c | 23 ++++++++++++++++++++--- @@ -9,10 +9,10 @@ Subject: [PATCH 2/8] red_channel: add ref count to RedClient 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/server/red_channel.c b/server/red_channel.c -index 0d74413..9168b8a 100644 +index fa4db7b..9433bef 100644 --- a/server/red_channel.c +++ b/server/red_channel.c -@@ -1932,10 +1932,29 @@ RedClient *red_client_new(int migrated) +@@ -1920,10 +1920,29 @@ RedClient *red_client_new(int migrated) pthread_mutex_init(&client->lock, NULL); client->thread_id = pthread_self(); client->during_target_migrate = migrated; @@ -42,7 +42,7 @@ index 0d74413..9168b8a 100644 /* client mutex should be locked before this call */ static void red_channel_client_set_migration_seamless(RedChannelClient *rcc) { -@@ -2012,9 +2031,7 @@ void red_client_destroy(RedClient *client) +@@ -2000,9 +2019,7 @@ void red_client_destroy(RedClient *client) spice_assert(rcc->send_data.size == 0); red_channel_client_destroy(rcc); } @@ -91,6 +91,3 @@ index ba299b6..0dd73ea 100644 -void red_client_destroy(RedClient *client); #endif --- -1.8.3.1 - diff --git a/SOURCES/0003-main_dispatcher-add-ref-count-protection-to-RedClien.patch b/SOURCES/0003-main_dispatcher-add-ref-count-protection-to-RedClien.patch index fab6d5c..dc216e2 100644 --- a/SOURCES/0003-main_dispatcher-add-ref-count-protection-to-RedClien.patch +++ b/SOURCES/0003-main_dispatcher-add-ref-count-protection-to-RedClien.patch @@ -1,7 +1,7 @@ -From 06ba03b7b32a2f0c7f78c82d8f399242526a0b45 Mon Sep 17 00:00:00 2001 +From 72cefedc68dcd78d4b4220d850844bb9c0ee46ce Mon Sep 17 00:00:00 2001 From: Yonit Halperin Date: Fri, 26 Jul 2013 13:49:24 -0400 -Subject: [PATCH 3/8] main_dispatcher: add ref count protection to RedClient +Subject: [PATCH] main_dispatcher: add ref count protection to RedClient instances --- @@ -46,6 +46,3 @@ index e7a451a..bf160dd 100644 msg.latency = latency; dispatcher_send_message(&main_dispatcher.base, MAIN_DISPATCHER_SET_MM_TIME_LATENCY, &msg); --- -1.8.3.1 - diff --git a/SOURCES/0004-decouple-disconnection-of-the-main-channel-from-clie.patch b/SOURCES/0004-decouple-disconnection-of-the-main-channel-from-clie.patch index 85d70ec..3a59749 100644 --- a/SOURCES/0004-decouple-disconnection-of-the-main-channel-from-clie.patch +++ b/SOURCES/0004-decouple-disconnection-of-the-main-channel-from-clie.patch @@ -1,7 +1,7 @@ -From 8490f83e1f51ac8dbcac3c68c97827e0acb9ec4e Mon Sep 17 00:00:00 2001 +From 977a70e88992bfe56a03294d76b8478bf7dd7020 Mon Sep 17 00:00:00 2001 From: Yonit Halperin Date: Thu, 25 Jul 2013 14:19:21 -0400 -Subject: [PATCH 4/8] decouple disconnection of the main channel from client +Subject: [PATCH] decouple disconnection of the main channel from client destruction Fixes rhbz#918169 @@ -233,6 +233,3 @@ index c5c557d..1c5ae84 100644 void reds_client_disconnect(RedClient *client); // Temporary (?) for splitting main channel --- -1.8.3.1 - diff --git a/SOURCES/0005-reds-s-red_client_disconnect-red_channel_client_shut.patch b/SOURCES/0005-reds-s-red_client_disconnect-red_channel_client_shut.patch index 035f462..16652cd 100644 --- a/SOURCES/0005-reds-s-red_client_disconnect-red_channel_client_shut.patch +++ b/SOURCES/0005-reds-s-red_client_disconnect-red_channel_client_shut.patch @@ -1,7 +1,7 @@ -From 46c2ce8f1af0170a2c6a335cc743a3ddff2d96d0 Mon Sep 17 00:00:00 2001 +From 5dff0a2af2f5ecb697ea512d402df21fa5ba2540 Mon Sep 17 00:00:00 2001 From: Yonit Halperin Date: Thu, 25 Jul 2013 14:25:24 -0400 -Subject: [PATCH 5/8] reds: s/red_client_disconnect/red_channel_client_shutdown +Subject: [PATCH] reds: s/red_client_disconnect/red_channel_client_shutdown inside callbacks When we want to disconnect the main channel from a callback, it is @@ -51,6 +51,3 @@ index c66ddc4..ae87c90 100644 return; } --- -1.8.3.1 - diff --git a/SOURCES/0006-snd_worker-fix-memory-leak-of-PlaybackChannel.patch b/SOURCES/0006-snd_worker-fix-memory-leak-of-PlaybackChannel.patch index fc1ee51..14f2b51 100644 --- a/SOURCES/0006-snd_worker-fix-memory-leak-of-PlaybackChannel.patch +++ b/SOURCES/0006-snd_worker-fix-memory-leak-of-PlaybackChannel.patch @@ -1,7 +1,7 @@ -From 134b7f310de5120b233670d18641d32204f31318 Mon Sep 17 00:00:00 2001 +From 1021382d0d16d6e7944941f5b091639678ea1cad Mon Sep 17 00:00:00 2001 From: Yonit Halperin Date: Thu, 25 Jul 2013 14:49:33 -0400 -Subject: [PATCH 6/8] snd_worker: fix memory leak of PlaybackChannel +Subject: [PATCH] snd_worker: fix memory leak of PlaybackChannel When the sequence of calls bellow occurs, the PlaybackChannel is not released (snd_channel_put is not called for the @@ -37,6 +37,3 @@ index d6ec47a..849f002 100644 return; } spice_assert(playback_channel->base.active); --- -1.8.3.1 - diff --git a/SOURCES/0007-snd_worker-snd_disconnect_channel-don-t-call-snd_cha.patch b/SOURCES/0007-snd_worker-snd_disconnect_channel-don-t-call-snd_cha.patch index fd461be..c411ed6 100644 --- a/SOURCES/0007-snd_worker-snd_disconnect_channel-don-t-call-snd_cha.patch +++ b/SOURCES/0007-snd_worker-snd_disconnect_channel-don-t-call-snd_cha.patch @@ -1,8 +1,8 @@ -From 02f44c137df99ed2e89699e49b64c13673b0cd06 Mon Sep 17 00:00:00 2001 +From 0e568836a130a51ded1b905745e9079f44e801a5 Mon Sep 17 00:00:00 2001 From: Yonit Halperin Date: Thu, 25 Jul 2013 15:07:43 -0400 -Subject: [PATCH 7/8] snd_worker/snd_disconnect_channel: don't call - snd_channel_put if the channel has already been disconnected +Subject: [PATCH] snd_worker/snd_disconnect_channel: don't call snd_channel_put + if the channel has already been disconnected The snd channels has one reference as long as their socket is active. The playback channel has an additional reference for each frame that is @@ -57,6 +57,3 @@ index 849f002..3827416 100644 if ((flags = fcntl(stream->socket, F_GETFL)) == -1) { spice_printerr("accept failed, %s", strerror(errno)); goto error1; --- -1.8.3.1 - diff --git a/SOURCES/0008-log-improve-debug-information-related-to-client-disc.patch b/SOURCES/0008-log-improve-debug-information-related-to-client-disc.patch index 77a04ba..ba03db9 100644 --- a/SOURCES/0008-log-improve-debug-information-related-to-client-disc.patch +++ b/SOURCES/0008-log-improve-debug-information-related-to-client-disc.patch @@ -1,7 +1,7 @@ -From c2e46b926e0ee4226f0f93942e7fa2c5b409f73d Mon Sep 17 00:00:00 2001 +From 7e0c5e8da1526180086e2341780896613ef9d957 Mon Sep 17 00:00:00 2001 From: Yonit Halperin Date: Fri, 26 Jul 2013 12:15:00 -0400 -Subject: [PATCH 8/8] log: improve debug information related to client +Subject: [PATCH] log: improve debug information related to client disconnection --- @@ -10,10 +10,10 @@ Subject: [PATCH 8/8] log: improve debug information related to client 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/server/red_channel.c b/server/red_channel.c -index 9168b8a..d565634 100644 +index 9433bef..1a57db5 100644 --- a/server/red_channel.c +++ b/server/red_channel.c -@@ -1112,6 +1112,7 @@ static void red_channel_client_ref(RedChannelClient *rcc) +@@ -1100,6 +1100,7 @@ static void red_channel_client_ref(RedChannelClient *rcc) static void red_channel_client_unref(RedChannelClient *rcc) { if (!--rcc->refs) { @@ -21,7 +21,7 @@ index 9168b8a..d565634 100644 if (rcc->send_data.main.marshaller) { spice_marshaller_destroy(rcc->send_data.main.marshaller); } -@@ -1708,6 +1709,8 @@ static void red_channel_client_disconnect_dummy(RedChannelClient *rcc) +@@ -1696,6 +1697,8 @@ static void red_channel_client_disconnect_dummy(RedChannelClient *rcc) { spice_assert(rcc->dummy); if (ring_item_is_linked(&rcc->channel_link)) { @@ -30,7 +30,7 @@ index 9168b8a..d565634 100644 red_channel_remove_client(rcc); } rcc->dummy_connected = FALSE; -@@ -1715,8 +1718,6 @@ static void red_channel_client_disconnect_dummy(RedChannelClient *rcc) +@@ -1703,8 +1706,6 @@ static void red_channel_client_disconnect_dummy(RedChannelClient *rcc) void red_channel_client_disconnect(RedChannelClient *rcc) { @@ -39,7 +39,7 @@ index 9168b8a..d565634 100644 if (rcc->dummy) { red_channel_client_disconnect_dummy(rcc); return; -@@ -1724,6 +1725,8 @@ void red_channel_client_disconnect(RedChannelClient *rcc) +@@ -1712,6 +1713,8 @@ void red_channel_client_disconnect(RedChannelClient *rcc) if (!red_channel_client_is_connected(rcc)) { return; } @@ -48,7 +48,7 @@ index 9168b8a..d565634 100644 red_channel_client_pipe_clear(rcc); if (rcc->stream->watch) { rcc->channel->core->watch_remove(rcc->stream->watch); -@@ -2007,7 +2010,7 @@ void red_client_destroy(RedClient *client) +@@ -1995,7 +1998,7 @@ void red_client_destroy(RedClient *client) RingItem *link, *next; RedChannelClient *rcc; @@ -94,6 +94,3 @@ index 3827416..ebddfcd 100644 if (worker->connection) { spice_assert(worker->connection->channel_client == rcc); snd_disconnect_channel(worker->connection); --- -1.8.3.1 - diff --git a/SOURCES/0009-red_worker-decrease-the-timeout-when-flushing-comman.patch b/SOURCES/0009-red_worker-decrease-the-timeout-when-flushing-comman.patch index a37b32b..34748a9 100644 --- a/SOURCES/0009-red_worker-decrease-the-timeout-when-flushing-comman.patch +++ b/SOURCES/0009-red_worker-decrease-the-timeout-when-flushing-comman.patch @@ -1,8 +1,8 @@ -From 6ced0f698507de02a67cfcd25b7ab07e8c423fad Mon Sep 17 00:00:00 2001 -Message-Id: <6ced0f698507de02a67cfcd25b7ab07e8c423fad.1377595745.git.uril@redhat.com> +From acf8d75bb7226c8ed8f5d3e7c7c93fae35c7192e Mon Sep 17 00:00:00 2001 From: Yonit Halperin Date: Mon, 5 Aug 2013 12:10:15 -0400 -Subject: [PATCH] red_worker: decrease the timeout when flushing commands and waiting for the client. +Subject: [PATCH] red_worker: decrease the timeout when flushing commands and + waiting for the client. 150 seconds is way too long period for holding the guest driver and waiting for a response for the client. This timeout was 15 seconds, but @@ -27,11 +27,11 @@ during my tests. This bug is related to rhbz#964136 (but from rhbz#964136 info it is still not clear why the client wasn't responsive). --- - server/red_worker.c | 6 +++--- - 1 files changed, 3 insertions(+), 3 deletions(-) + server/red_worker.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/red_worker.c b/server/red_worker.c -index b45208b..9896696 100644 +index 73fe866..a4f0663 100644 --- a/server/red_worker.c +++ b/server/red_worker.c @@ -103,7 +103,7 @@ @@ -43,7 +43,7 @@ index b45208b..9896696 100644 #define DISPLAY_CLIENT_MIGRATE_DATA_TIMEOUT 10000000000ULL //nano, 10 sec #define DISPLAY_CLIENT_RETRY_INTERVAL 10000 //micro -@@ -9716,7 +9716,7 @@ static inline void flush_display_commands(RedWorker *worker) +@@ -9721,7 +9721,7 @@ static inline void flush_display_commands(RedWorker *worker) if (ring_is_empty) { break; } @@ -52,7 +52,7 @@ index b45208b..9896696 100644 int sleep_count = 0; for (;;) { red_channel_push(&worker->display_channel->common.base); -@@ -9760,7 +9760,7 @@ static inline void flush_cursor_commands(RedWorker *worker) +@@ -9765,7 +9765,7 @@ static inline void flush_cursor_commands(RedWorker *worker) if (ring_is_empty) { break; } @@ -61,6 +61,3 @@ index b45208b..9896696 100644 int sleep_count = 0; for (;;) { red_channel_push(&worker->cursor_channel->common.base); --- -1.7.1 - diff --git a/SOURCES/0010-Fix-buffer-overflow-when-decrypting-client-SPICE-tic.patch b/SOURCES/0010-Fix-buffer-overflow-when-decrypting-client-SPICE-tic.patch index 320296a..4e6b520 100644 --- a/SOURCES/0010-Fix-buffer-overflow-when-decrypting-client-SPICE-tic.patch +++ b/SOURCES/0010-Fix-buffer-overflow-when-decrypting-client-SPICE-tic.patch @@ -1,4 +1,4 @@ -From 3554c19d1c65c2bc4ae8cadb7296256c03215257 Mon Sep 17 00:00:00 2001 +From fb263d33f99b5d8c8f370df48a04c926eac5781e Mon Sep 17 00:00:00 2001 From: Christophe Fergeau Date: Fri, 23 Aug 2013 11:29:44 +0200 Subject: [PATCH] Fix buffer overflow when decrypting client SPICE ticket @@ -28,10 +28,10 @@ This fixes rhbz#999839 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/server/reds.c b/server/reds.c -index 0f81a32..7b7f262 100644 +index ae87c90..f9f185d 100644 --- a/server/reds.c +++ b/server/reds.c -@@ -1932,39 +1932,59 @@ static void reds_handle_link(RedLinkInfo *link) +@@ -1933,39 +1933,59 @@ static void reds_handle_link(RedLinkInfo *link) static void reds_handle_ticket(void *opaque) { RedLinkInfo *link = (RedLinkInfo *)opaque; @@ -103,6 +103,3 @@ index 0f81a32..7b7f262 100644 } static inline void async_read_clear_handlers(AsyncRead *obj) --- -1.8.3.1 - diff --git a/SOURCES/0011-server-move-three-functions-to-red_channel.patch b/SOURCES/0011-server-move-three-functions-to-red_channel.patch new file mode 100644 index 0000000..5eb019e --- /dev/null +++ b/SOURCES/0011-server-move-three-functions-to-red_channel.patch @@ -0,0 +1,382 @@ +From 2549affd7164634609ffe2796616a2195a3118a4 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Mon, 12 Aug 2013 15:01:42 +0300 +Subject: [PATCH] server: move three functions to red_channel + +Three blocking functions, one was split to leave the display channel +specific referencing of the DrawablePipeItem being sent inside +red_worker, but the rest (most) of the timeout logic was moved to +red_channel, including the associated constants. + +Moved functions: +red_channel_client_wait_pipe_item_sent +red_wait_outgoing_item +red_wait_all_sent + +Introduces red_time.h & red_time.c for a small helper function dealing +with time.h + +https://bugzilla.redhat.com/show_bug.cgi?id=1016795 +Conflicts: + server/red_worker.c +--- + server/red_channel.c | 106 ++++++++++++++++++++++++++++++++++++++++++++ + server/red_channel.h | 10 +++++ + server/red_time.c | 1 + + server/red_time.h | 15 +++++++ + server/red_worker.c | 121 +-------------------------------------------------- + 5 files changed, 134 insertions(+), 119 deletions(-) + create mode 100644 server/red_time.c + create mode 100644 server/red_time.h + +diff --git a/server/red_channel.c b/server/red_channel.c +index 1a57db5..555d376 100644 +--- a/server/red_channel.c ++++ b/server/red_channel.c +@@ -38,6 +38,7 @@ + #include "red_channel.h" + #include "reds.h" + #include "main_dispatcher.h" ++#include "red_time.h" + + typedef struct EmptyMsgPipeItem { + PipeItem base; +@@ -47,6 +48,12 @@ typedef struct EmptyMsgPipeItem { + #define PING_TEST_TIMEOUT_MS 15000 + #define PING_TEST_IDLE_NET_TIMEOUT_MS 100 + ++#define DETACH_TIMEOUT 15000000000ULL //nano ++#define DETACH_SLEEP_DURATION 10000 //micro ++ ++#define CHANNEL_PUSH_TIMEOUT 30000000000ULL //nano ++#define CHANNEL_PUSH_SLEEP_DURATION 10000 //micro ++ + enum QosPingState { + PING_STATE_NONE, + PING_STATE_TIMER, +@@ -2183,3 +2190,102 @@ uint32_t red_channel_sum_pipes_size(RedChannel *channel) + } + return sum; + } ++ ++void red_wait_outgoing_item(RedChannelClient *rcc) ++{ ++ uint64_t end_time; ++ int blocked; ++ ++ if (!red_channel_client_blocked(rcc)) { ++ return; ++ } ++ end_time = red_now() + DETACH_TIMEOUT; ++ spice_info("blocked"); ++ ++ do { ++ usleep(DETACH_SLEEP_DURATION); ++ red_channel_client_receive(rcc); ++ red_channel_client_send(rcc); ++ } while ((blocked = red_channel_client_blocked(rcc)) && red_now() < end_time); ++ ++ if (blocked) { ++ spice_warning("timeout"); ++ // TODO - shutting down the socket but we still need to trigger ++ // disconnection. Right now we wait for main channel to error for that. ++ red_channel_client_shutdown(rcc); ++ } else { ++ spice_assert(red_channel_client_no_item_being_sent(rcc)); ++ } ++} ++ ++/* TODO: more evil sync stuff. anything with the word wait in it's name. */ ++void red_channel_client_wait_pipe_item_sent(RedChannelClient *rcc, ++ PipeItem *item) ++{ ++ uint64_t end_time; ++ int item_in_pipe; ++ ++ spice_info(NULL); ++ ++ end_time = red_now() + CHANNEL_PUSH_TIMEOUT; ++ ++ rcc->channel->channel_cbs.hold_item(rcc, item); ++ ++ if (red_channel_client_blocked(rcc)) { ++ red_channel_client_receive(rcc); ++ red_channel_client_send(rcc); ++ } ++ red_channel_client_push(rcc); ++ ++ while((item_in_pipe = ring_item_is_linked(&item->link)) && (red_now() < end_time)) { ++ usleep(CHANNEL_PUSH_SLEEP_DURATION); ++ red_channel_client_receive(rcc); ++ red_channel_client_send(rcc); ++ red_channel_client_push(rcc); ++ } ++ ++ if (item_in_pipe) { ++ spice_warning("timeout"); ++ red_channel_client_disconnect(rcc); ++ } else { ++ red_wait_outgoing_item(rcc); ++ } ++ red_channel_client_release_item(rcc, item, TRUE); ++} ++ ++static void rcc_shutdown_if_pending_send(RedChannelClient *rcc) ++{ ++ if (red_channel_client_blocked(rcc) || rcc->pipe_size > 0) { ++ red_channel_client_shutdown(rcc); ++ } else { ++ spice_assert(red_channel_client_no_item_being_sent(rcc)); ++ } ++} ++ ++void red_wait_all_sent(RedChannel *channel) ++{ ++ uint64_t end_time; ++ uint32_t max_pipe_size; ++ int blocked = FALSE; ++ ++ end_time = red_now() + DETACH_TIMEOUT; ++ ++ red_channel_push(channel); ++ while (((max_pipe_size = red_channel_max_pipe_size(channel)) || ++ (blocked = red_channel_any_blocked(channel))) && ++ red_now() < end_time) { ++ spice_debug("pipe-size %u blocked %d", max_pipe_size, blocked); ++ usleep(DETACH_SLEEP_DURATION); ++ red_channel_receive(channel); ++ red_channel_send(channel); ++ red_channel_push(channel); ++ } ++ ++ if (max_pipe_size || blocked) { ++ spice_printerr("timeout: pending out messages exist (pipe-size %u, blocked %d)", ++ max_pipe_size, blocked); ++ red_channel_apply_clients(channel, rcc_shutdown_if_pending_send); ++ } else { ++ spice_assert(red_channel_no_item_being_sent(channel)); ++ } ++} +diff --git a/server/red_channel.h b/server/red_channel.h +index 0dd73ea..b2a3a6a 100644 +--- a/server/red_channel.h ++++ b/server/red_channel.h +@@ -596,4 +596,14 @@ int red_client_during_migrate_at_target(RedClient *client); + + void red_client_migrate(RedClient *client); + ++/* blocking function */ ++void red_channel_client_wait_pipe_item_sent(RedChannelClient *rcc, ++ PipeItem *item); ++ ++/* blocking function */ ++void red_wait_outgoing_item(RedChannelClient *rcc); ++ ++/* blocking function */ ++void red_wait_all_sent(RedChannel *channel); ++ + #endif +diff --git a/server/red_time.c b/server/red_time.c +new file mode 100644 +index 0000000..8b13789 +--- /dev/null ++++ b/server/red_time.c +@@ -0,0 +1 @@ ++ +diff --git a/server/red_time.h b/server/red_time.h +new file mode 100644 +index 0000000..ffa97f2 +--- /dev/null ++++ b/server/red_time.h +@@ -0,0 +1,15 @@ ++#ifndef H_RED_TIME ++#define H_RED_TIME ++ ++#include ++ ++static inline uint64_t red_now(void) ++{ ++ struct timespec time; ++ ++ clock_gettime(CLOCK_MONOTONIC, &time); ++ ++ return ((uint64_t) time.tv_sec) * 1000000000 + time.tv_nsec; ++} ++ ++#endif +diff --git a/server/red_worker.c b/server/red_worker.c +index a4f0663..b3a957e 100644 +--- a/server/red_worker.c ++++ b/server/red_worker.c +@@ -82,6 +82,7 @@ + #include "migration_protocol.h" + #include "spice_timer_queue.h" + #include "main_dispatcher.h" ++#include "red_time.h" + + //#define COMPRESS_STAT + //#define DUMP_BITMAP +@@ -97,12 +98,6 @@ + #define CMD_RING_POLL_TIMEOUT 10 //milli + #define CMD_RING_POLL_RETRIES 200 + +-#define DETACH_TIMEOUT 15000000000ULL //nano +-#define DETACH_SLEEP_DURATION 10000 //micro +- +-#define CHANNEL_PUSH_TIMEOUT 30000000000ULL //nano +-#define CHANNEL_PUSH_SLEEP_DURATION 10000 //micro +- + #define DISPLAY_CLIENT_TIMEOUT 30000000000ULL //nano + #define DISPLAY_CLIENT_MIGRATE_DATA_TIMEOUT 10000000000ULL //nano, 10 sec + #define DISPLAY_CLIENT_RETRY_INTERVAL 10000 //micro +@@ -1098,14 +1093,12 @@ static void cursor_channel_client_release_item_before_push(CursorChannelClient * + PipeItem *item); + static void cursor_channel_client_release_item_after_push(CursorChannelClient *ccc, + PipeItem *item); +-static void red_wait_pipe_item_sent(RedChannelClient *rcc, PipeItem *item); + + #ifdef DUMP_BITMAP + static void dump_bitmap(RedWorker *worker, SpiceBitmap *bitmap, uint32_t group_id); + #endif + + static void red_push_monitors_config(DisplayChannelClient *dcc); +-static inline uint64_t red_now(void); + + /* + * Macros to make iterating over stuff easier +@@ -2098,12 +2091,10 @@ static void red_clear_surface_drawables_from_pipe(DisplayChannelClient *dcc, int + } + + if (item) { +- red_wait_pipe_item_sent(&dcc->common.base, item); ++ red_channel_client_wait_pipe_item_sent(&dcc->common.base, item); + } + } + +-static void red_wait_outgoing_item(RedChannelClient *rcc); +- + static void red_clear_surface_drawables_from_pipes(RedWorker *worker, int surface_id, + int force, int wait_for_outgoing_item) + { +@@ -5088,15 +5079,6 @@ static void qxl_process_cursor(RedWorker *worker, RedCursorCmd *cursor_cmd, uint + red_release_cursor(worker, cursor_item); + } + +-static inline uint64_t red_now(void) +-{ +- struct timespec time; +- +- clock_gettime(CLOCK_MONOTONIC, &time); +- +- return ((uint64_t) time.tv_sec) * 1000000000 + time.tv_nsec; +-} +- + static int red_process_cursor(RedWorker *worker, uint32_t max_pipe_size, int *ring_is_empty) + { + QXLCommandExt ext_cmd; +@@ -10988,105 +10970,6 @@ typedef struct __attribute__ ((__packed__)) CursorData { + SpiceCursor _cursor; + } CursorData; + +-static void red_wait_outgoing_item(RedChannelClient *rcc) +-{ +- uint64_t end_time; +- int blocked; +- +- if (!red_channel_client_blocked(rcc)) { +- return; +- } +- end_time = red_now() + DETACH_TIMEOUT; +- spice_info("blocked"); +- +- do { +- usleep(DETACH_SLEEP_DURATION); +- red_channel_client_receive(rcc); +- red_channel_client_send(rcc); +- } while ((blocked = red_channel_client_blocked(rcc)) && red_now() < end_time); +- +- if (blocked) { +- spice_warning("timeout"); +- // TODO - shutting down the socket but we still need to trigger +- // disconnection. Right now we wait for main channel to error for that. +- red_channel_client_shutdown(rcc); +- } else { +- spice_assert(red_channel_client_no_item_being_sent(rcc)); +- } +-} +- +-static void rcc_shutdown_if_pending_send(RedChannelClient *rcc) +-{ +- if (red_channel_client_blocked(rcc) || rcc->pipe_size > 0) { +- red_channel_client_shutdown(rcc); +- } else { +- spice_assert(red_channel_client_no_item_being_sent(rcc)); +- } +-} +- +-static void red_wait_all_sent(RedChannel *channel) +-{ +- uint64_t end_time; +- uint32_t max_pipe_size; +- int blocked = FALSE; +- +- end_time = red_now() + DETACH_TIMEOUT; +- +- red_channel_push(channel); +- while (((max_pipe_size = red_channel_max_pipe_size(channel)) || +- (blocked = red_channel_any_blocked(channel))) && +- red_now() < end_time) { +- spice_debug("pipe-size %u blocked %d", max_pipe_size, blocked); +- usleep(DETACH_SLEEP_DURATION); +- red_channel_receive(channel); +- red_channel_send(channel); +- red_channel_push(channel); +- } +- +- if (max_pipe_size || blocked) { +- spice_printerr("timeout: pending out messages exist (pipe-size %u, blocked %d)", +- max_pipe_size, blocked); +- red_channel_apply_clients(channel, rcc_shutdown_if_pending_send); +- } else { +- spice_assert(red_channel_no_item_being_sent(channel)); +- } +-} +- +-/* TODO: more evil sync stuff. anything with the word wait in it's name. */ +-static void red_wait_pipe_item_sent(RedChannelClient *rcc, PipeItem *item) +-{ +- DrawablePipeItem *dpi; +- uint64_t end_time; +- int item_in_pipe; +- +- spice_info(NULL); +- dpi = SPICE_CONTAINEROF(item, DrawablePipeItem, dpi_pipe_item); +- ref_drawable_pipe_item(dpi); +- +- end_time = red_now() + CHANNEL_PUSH_TIMEOUT; +- +- if (red_channel_client_blocked(rcc)) { +- red_channel_client_receive(rcc); +- red_channel_client_send(rcc); +- } +- red_channel_client_push(rcc); +- +- while((item_in_pipe = ring_item_is_linked(&item->link)) && (red_now() < end_time)) { +- usleep(CHANNEL_PUSH_SLEEP_DURATION); +- red_channel_client_receive(rcc); +- red_channel_client_send(rcc); +- red_channel_client_push(rcc); +- } +- +- if (item_in_pipe) { +- spice_warning("timeout"); +- red_channel_client_disconnect(rcc); +- } else { +- red_wait_outgoing_item(rcc); +- } +- put_drawable_pipe_item(dpi); +-} +- + static void surface_dirty_region_to_rects(RedSurface *surface, + QXLRect *qxl_dirty_rects, + uint32_t num_dirty_rects, diff --git a/SOURCES/0012-server-s-red_wait_all_sent-red_channel_wait_all_sent.patch b/SOURCES/0012-server-s-red_wait_all_sent-red_channel_wait_all_sent.patch new file mode 100644 index 0000000..2c75a14 --- /dev/null +++ b/SOURCES/0012-server-s-red_wait_all_sent-red_channel_wait_all_sent.patch @@ -0,0 +1,62 @@ +From 9d9042d8530e975ef2dbc67da153b4d91e1099c7 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Mon, 12 Aug 2013 19:48:24 +0300 +Subject: [PATCH] server: s/red_wait_all_sent/red_channel_wait_all_sent/ + +https://bugzilla.redhat.com/show_bug.cgi?id=1016795 +(cherry picked from commit 9b8ff0428468b7f081fe6f2b27774af2d0b4dadf) +--- + server/red_channel.c | 2 +- + server/red_channel.h | 2 +- + server/red_worker.c | 6 +++--- + 3 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/server/red_channel.c b/server/red_channel.c +index 555d376..6e43e0a 100644 +--- a/server/red_channel.c ++++ b/server/red_channel.c +@@ -2262,7 +2262,7 @@ static void rcc_shutdown_if_pending_send(RedChannelClient *rcc) + } + } + +-void red_wait_all_sent(RedChannel *channel) ++void red_channel_wait_all_sent(RedChannel *channel) + { + uint64_t end_time; + uint32_t max_pipe_size; +diff --git a/server/red_channel.h b/server/red_channel.h +index b2a3a6a..9021b3f 100644 +--- a/server/red_channel.h ++++ b/server/red_channel.h +@@ -604,6 +604,6 @@ void red_channel_client_wait_pipe_item_sent(RedChannelClient *rcc, + void red_wait_outgoing_item(RedChannelClient *rcc); + + /* blocking function */ +-void red_wait_all_sent(RedChannel *channel); ++void red_channel_wait_all_sent(RedChannel *channel); + + #endif +diff --git a/server/red_worker.c b/server/red_worker.c +index b3a957e..b93796c 100644 +--- a/server/red_worker.c ++++ b/server/red_worker.c +@@ -11138,7 +11138,7 @@ static inline void red_cursor_reset(RedWorker *worker) + if (!worker->cursor_channel->common.during_target_migrate) { + red_pipes_add_verb(&worker->cursor_channel->common.base, SPICE_MSG_CURSOR_RESET); + } +- red_wait_all_sent(&worker->cursor_channel->common.base); ++ red_channel_wait_all_sent(&worker->cursor_channel->common.base); + } + } + +@@ -11421,8 +11421,8 @@ void handle_dev_stop(void *opaque, void *payload) + * purge the pipe, send destroy_all_surfaces + * to the client (there is no such message right now), and start + * from scratch on the destination side */ +- red_wait_all_sent(&worker->display_channel->common.base); +- red_wait_all_sent(&worker->cursor_channel->common.base); ++ red_channel_wait_all_sent(&worker->display_channel->common.base); ++ red_channel_wait_all_sent(&worker->cursor_channel->common.base); + } + + static int display_channel_wait_for_migrate_data(DisplayChannel *display) diff --git a/SOURCES/0013-red_worker-cleanup-red_clear_surface_drawables_from_.patch b/SOURCES/0013-red_worker-cleanup-red_clear_surface_drawables_from_.patch new file mode 100644 index 0000000..973899c --- /dev/null +++ b/SOURCES/0013-red_worker-cleanup-red_clear_surface_drawables_from_.patch @@ -0,0 +1,93 @@ +From 8d90b811ea77f80db914ffd153ee1d8954bf1cbb Mon Sep 17 00:00:00 2001 +From: Yonit Halperin +Date: Wed, 11 Sep 2013 13:39:35 -0400 +Subject: [PATCH] red_worker: cleanup red_clear_surface_drawables_from_pipes + +(1) merge 'force' and 'wait_for_outgoing_item' to one parameter. + 'wait_for_outgoing_item' is a derivative of 'force'. +(2) move the call to red_wait_outgoing_item to red_clear_surface_drawables_from_pipe + +https://bugzilla.redhat.com/show_bug.cgi?id=1016795 +--- + server/red_worker.c | 30 ++++++++++++++++++------------ + 1 file changed, 18 insertions(+), 12 deletions(-) + +diff --git a/server/red_worker.c b/server/red_worker.c +index b93796c..f2c9220 100644 +--- a/server/red_worker.c ++++ b/server/red_worker.c +@@ -2032,7 +2032,7 @@ static void red_current_clear(RedWorker *worker, int surface_id) + } + + static void red_clear_surface_drawables_from_pipe(DisplayChannelClient *dcc, int surface_id, +- int force) ++ int wait_if_used) + { + Ring *ring; + PipeItem *item; +@@ -2082,7 +2082,7 @@ static void red_clear_surface_drawables_from_pipe(DisplayChannelClient *dcc, int + + if (depend_found) { + spice_debug("surface %d dependent item found %p, %p", surface_id, drawable, item); +- if (force) { ++ if (wait_if_used) { + break; + } else { + return; +@@ -2090,24 +2090,30 @@ static void red_clear_surface_drawables_from_pipe(DisplayChannelClient *dcc, int + } + } + ++ if (!wait_if_used) { ++ return; ++ } ++ + if (item) { + red_channel_client_wait_pipe_item_sent(&dcc->common.base, item); ++ } else { ++ /* ++ * in case that the pipe didn't contain any item that is dependent on the surface, but ++ * there is one during sending. ++ */ ++ red_wait_outgoing_item(&dcc->common.base); + } + } + +-static void red_clear_surface_drawables_from_pipes(RedWorker *worker, int surface_id, +- int force, int wait_for_outgoing_item) ++static void red_clear_surface_drawables_from_pipes(RedWorker *worker, ++ int surface_id, ++ int wait_if_used) + { + RingItem *item, *next; + DisplayChannelClient *dcc; + + WORKER_FOREACH_DCC_SAFE(worker, item, next, dcc) { +- red_clear_surface_drawables_from_pipe(dcc, surface_id, force); +- if (wait_for_outgoing_item) { +- // in case that the pipe didn't contain any item that is dependent on the surface, but +- // there is one during sending. +- red_wait_outgoing_item(&dcc->common.base); +- } ++ red_clear_surface_drawables_from_pipe(dcc, surface_id, wait_if_used); + } + } + +@@ -4292,7 +4298,7 @@ static inline void red_process_surface(RedWorker *worker, RedSurfaceCmd *surface + otherwise "current" will hold items that other drawables may depend on, and then + red_current_clear will remove them from the pipe. */ + red_current_clear(worker, surface_id); +- red_clear_surface_drawables_from_pipes(worker, surface_id, FALSE, FALSE); ++ red_clear_surface_drawables_from_pipes(worker, surface_id, FALSE); + red_destroy_surface(worker, surface_id); + break; + default: +@@ -11099,7 +11105,7 @@ static inline void destroy_surface_wait(RedWorker *worker, int surface_id) + otherwise "current" will hold items that other drawables may depend on, and then + red_current_clear will remove them from the pipe. */ + red_current_clear(worker, surface_id); +- red_clear_surface_drawables_from_pipes(worker, surface_id, TRUE, TRUE); ++ red_clear_surface_drawables_from_pipes(worker, surface_id, TRUE); + } + + static void dev_destroy_surface_wait(RedWorker *worker, uint32_t surface_id) diff --git a/SOURCES/0014-red_channel-cleanup-of-red_channel_client-blocking-m.patch b/SOURCES/0014-red_channel-cleanup-of-red_channel_client-blocking-m.patch new file mode 100644 index 0000000..bad6c4b --- /dev/null +++ b/SOURCES/0014-red_channel-cleanup-of-red_channel_client-blocking-m.patch @@ -0,0 +1,330 @@ +From 3af85a04dc7639102f15bbc819b15489178aefbb Mon Sep 17 00:00:00 2001 +From: Yonit Halperin +Date: Wed, 11 Sep 2013 13:31:21 -0400 +Subject: [PATCH] red_channel: cleanup of red_channel_client blocking methods + +(1) receive timeout as a parameter. +(2) add a return value and pass the handling + of failures to the calling routine. + +https://bugzilla.redhat.com/show_bug.cgi?id=1016795 +(cherry picked from commit bcf9e64f134a6073c1e404efc8892c1cb453bd8a) +--- + server/red_channel.c | 73 ++++++++++++++++++++++++++-------------------------- + server/red_channel.h | 22 ++++++++++------ + server/red_worker.c | 55 ++++++++++++++++++++++++++++++--------- + 3 files changed, 93 insertions(+), 57 deletions(-) + +diff --git a/server/red_channel.c b/server/red_channel.c +index 6e43e0a..228669b 100644 +--- a/server/red_channel.c ++++ b/server/red_channel.c +@@ -48,11 +48,7 @@ typedef struct EmptyMsgPipeItem { + #define PING_TEST_TIMEOUT_MS 15000 + #define PING_TEST_IDLE_NET_TIMEOUT_MS 100 + +-#define DETACH_TIMEOUT 15000000000ULL //nano +-#define DETACH_SLEEP_DURATION 10000 //micro +- +-#define CHANNEL_PUSH_TIMEOUT 30000000000ULL //nano +-#define CHANNEL_PUSH_SLEEP_DURATION 10000 //micro ++#define CHANNEL_BLOCKED_SLEEP_DURATION 10000 //micro + + enum QosPingState { + PING_STATE_NONE, +@@ -2191,43 +2187,49 @@ uint32_t red_channel_sum_pipes_size(RedChannel *channel) + return sum; + } + +-void red_wait_outgoing_item(RedChannelClient *rcc) ++int red_channel_client_wait_outgoing_item(RedChannelClient *rcc, ++ int64_t timeout) + { + uint64_t end_time; + int blocked; + + if (!red_channel_client_blocked(rcc)) { +- return; ++ return TRUE; ++ } ++ if (timeout != -1) { ++ end_time = red_now() + timeout; + } +- end_time = red_now() + DETACH_TIMEOUT; + spice_info("blocked"); + + do { +- usleep(DETACH_SLEEP_DURATION); ++ usleep(CHANNEL_BLOCKED_SLEEP_DURATION); + red_channel_client_receive(rcc); + red_channel_client_send(rcc); +- } while ((blocked = red_channel_client_blocked(rcc)) && red_now() < end_time); ++ } while ((blocked = red_channel_client_blocked(rcc)) && ++ (timeout == -1 || red_now() < end_time)); + + if (blocked) { + spice_warning("timeout"); +- // TODO - shutting down the socket but we still need to trigger +- // disconnection. Right now we wait for main channel to error for that. +- red_channel_client_shutdown(rcc); ++ return FALSE; + } else { + spice_assert(red_channel_client_no_item_being_sent(rcc)); ++ return TRUE; + } + } + + /* TODO: more evil sync stuff. anything with the word wait in it's name. */ +-void red_channel_client_wait_pipe_item_sent(RedChannelClient *rcc, +- PipeItem *item) ++int red_channel_client_wait_pipe_item_sent(RedChannelClient *rcc, ++ PipeItem *item, ++ int64_t timeout) + { + uint64_t end_time; + int item_in_pipe; + + spice_info(NULL); + +- end_time = red_now() + CHANNEL_PUSH_TIMEOUT; ++ if (timeout != -1) { ++ end_time = red_now() + timeout; ++ } + + rcc->channel->channel_cbs.hold_item(rcc, item); + +@@ -2237,55 +2239,52 @@ void red_channel_client_wait_pipe_item_sent(RedChannelClient *rcc, + } + red_channel_client_push(rcc); + +- while((item_in_pipe = ring_item_is_linked(&item->link)) && (red_now() < end_time)) { +- usleep(CHANNEL_PUSH_SLEEP_DURATION); ++ while((item_in_pipe = ring_item_is_linked(&item->link)) && ++ (timeout == -1 || red_now() < end_time)) { ++ usleep(CHANNEL_BLOCKED_SLEEP_DURATION); + red_channel_client_receive(rcc); + red_channel_client_send(rcc); + red_channel_client_push(rcc); + } + ++ red_channel_client_release_item(rcc, item, TRUE); + if (item_in_pipe) { + spice_warning("timeout"); +- red_channel_client_disconnect(rcc); +- } else { +- red_wait_outgoing_item(rcc); +- } +- red_channel_client_release_item(rcc, item, TRUE); +-} +- +-static void rcc_shutdown_if_pending_send(RedChannelClient *rcc) +-{ +- if (red_channel_client_blocked(rcc) || rcc->pipe_size > 0) { +- red_channel_client_shutdown(rcc); ++ return FALSE; + } else { +- spice_assert(red_channel_client_no_item_being_sent(rcc)); ++ return red_channel_client_wait_outgoing_item(rcc, ++ timeout == -1 ? -1 : end_time - red_now()); + } + } + +-void red_channel_wait_all_sent(RedChannel *channel) ++int red_channel_wait_all_sent(RedChannel *channel, ++ int64_t timeout) + { + uint64_t end_time; + uint32_t max_pipe_size; + int blocked = FALSE; + +- end_time = red_now() + DETACH_TIMEOUT; ++ if (timeout != -1) { ++ end_time = red_now() + timeout; ++ } + + red_channel_push(channel); + while (((max_pipe_size = red_channel_max_pipe_size(channel)) || + (blocked = red_channel_any_blocked(channel))) && +- red_now() < end_time) { ++ (timeout == -1 || red_now() < end_time)) { + spice_debug("pipe-size %u blocked %d", max_pipe_size, blocked); +- usleep(DETACH_SLEEP_DURATION); ++ usleep(CHANNEL_BLOCKED_SLEEP_DURATION); + red_channel_receive(channel); + red_channel_send(channel); + red_channel_push(channel); + } + + if (max_pipe_size || blocked) { +- spice_printerr("timeout: pending out messages exist (pipe-size %u, blocked %d)", +- max_pipe_size, blocked); +- red_channel_apply_clients(channel, rcc_shutdown_if_pending_send); ++ spice_warning("timeout: pending out messages exist (pipe-size %u, blocked %d)", ++ max_pipe_size, blocked); ++ return FALSE; + } else { + spice_assert(red_channel_no_item_being_sent(channel)); ++ return TRUE; + } + } +diff --git a/server/red_channel.h b/server/red_channel.h +index 9021b3f..fa11505 100644 +--- a/server/red_channel.h ++++ b/server/red_channel.h +@@ -596,14 +596,20 @@ int red_client_during_migrate_at_target(RedClient *client); + + void red_client_migrate(RedClient *client); + +-/* blocking function */ +-void red_channel_client_wait_pipe_item_sent(RedChannelClient *rcc, +- PipeItem *item); +- +-/* blocking function */ +-void red_wait_outgoing_item(RedChannelClient *rcc); ++/* ++ * blocking functions. ++ * ++ * timeout is in nano sec. -1 for no timeout. ++ * ++ * Return: TRUE if waiting succeeded. FALSE if timeout expired. ++ */ + +-/* blocking function */ +-void red_channel_wait_all_sent(RedChannel *channel); ++int red_channel_client_wait_pipe_item_sent(RedChannelClient *rcc, ++ PipeItem *item, ++ int64_t timeout); ++int red_channel_client_wait_outgoing_item(RedChannelClient *rcc, ++ int64_t timeout); ++int red_channel_wait_all_sent(RedChannel *channel, ++ int64_t timeout); + + #endif +diff --git a/server/red_worker.c b/server/red_worker.c +index f2c9220..31f3cbb 100644 +--- a/server/red_worker.c ++++ b/server/red_worker.c +@@ -98,6 +98,7 @@ + #define CMD_RING_POLL_TIMEOUT 10 //milli + #define CMD_RING_POLL_RETRIES 200 + ++#define DISPLAY_CLIENT_SHORT_TIMEOUT 15000000000ULL //nano + #define DISPLAY_CLIENT_TIMEOUT 30000000000ULL //nano + #define DISPLAY_CLIENT_MIGRATE_DATA_TIMEOUT 10000000000ULL //nano, 10 sec + #define DISPLAY_CLIENT_RETRY_INTERVAL 10000 //micro +@@ -2031,8 +2032,12 @@ static void red_current_clear(RedWorker *worker, int surface_id) + } + } + +-static void red_clear_surface_drawables_from_pipe(DisplayChannelClient *dcc, int surface_id, +- int wait_if_used) ++/* ++ * Return: TRUE if wait_if_used == FALSE, or otherwise, if all of the pipe items that ++ * are related to the surface have been cleared (or sent) from the pipe. ++ */ ++static int red_clear_surface_drawables_from_pipe(DisplayChannelClient *dcc, int surface_id, ++ int wait_if_used) + { + Ring *ring; + PipeItem *item; +@@ -2040,7 +2045,7 @@ static void red_clear_surface_drawables_from_pipe(DisplayChannelClient *dcc, int + RedChannelClient *rcc; + + if (!dcc) { +- return; ++ return TRUE; + } + + /* removing the newest drawables that their destination is surface_id and +@@ -2085,24 +2090,27 @@ static void red_clear_surface_drawables_from_pipe(DisplayChannelClient *dcc, int + if (wait_if_used) { + break; + } else { +- return; ++ return TRUE; + } + } + } + + if (!wait_if_used) { +- return; ++ return TRUE; + } + + if (item) { +- red_channel_client_wait_pipe_item_sent(&dcc->common.base, item); ++ return red_channel_client_wait_pipe_item_sent(&dcc->common.base, item, ++ DISPLAY_CLIENT_TIMEOUT); + } else { + /* + * in case that the pipe didn't contain any item that is dependent on the surface, but +- * there is one during sending. ++ * there is one during sending. Use a shorter timeout, since it is just one item + */ +- red_wait_outgoing_item(&dcc->common.base); ++ return red_channel_client_wait_outgoing_item(&dcc->common.base, ++ DISPLAY_CLIENT_SHORT_TIMEOUT); + } ++ return TRUE; + } + + static void red_clear_surface_drawables_from_pipes(RedWorker *worker, +@@ -2113,7 +2121,9 @@ static void red_clear_surface_drawables_from_pipes(RedWorker *worker, + DisplayChannelClient *dcc; + + WORKER_FOREACH_DCC_SAFE(worker, item, next, dcc) { +- red_clear_surface_drawables_from_pipe(dcc, surface_id, wait_if_used); ++ if (!red_clear_surface_drawables_from_pipe(dcc, surface_id, wait_if_used)) { ++ red_channel_client_disconnect(&dcc->common.base); ++ } + } + } + +@@ -11127,6 +11137,15 @@ void handle_dev_destroy_surface_wait(void *opaque, void *payload) + dev_destroy_surface_wait(worker, msg->surface_id); + } + ++static void rcc_shutdown_if_pending_send(RedChannelClient *rcc) ++{ ++ if (red_channel_client_blocked(rcc) || rcc->pipe_size > 0) { ++ red_channel_client_shutdown(rcc); ++ } else { ++ spice_assert(red_channel_client_no_item_being_sent(rcc)); ++ } ++} ++ + static inline void red_cursor_reset(RedWorker *worker) + { + if (worker->cursor) { +@@ -11144,7 +11163,11 @@ static inline void red_cursor_reset(RedWorker *worker) + if (!worker->cursor_channel->common.during_target_migrate) { + red_pipes_add_verb(&worker->cursor_channel->common.base, SPICE_MSG_CURSOR_RESET); + } +- red_channel_wait_all_sent(&worker->cursor_channel->common.base); ++ if (!red_channel_wait_all_sent(&worker->cursor_channel->common.base, ++ DISPLAY_CLIENT_TIMEOUT)) { ++ red_channel_apply_clients(&worker->cursor_channel->common.base, ++ rcc_shutdown_if_pending_send); ++ } + } + } + +@@ -11427,8 +11450,16 @@ void handle_dev_stop(void *opaque, void *payload) + * purge the pipe, send destroy_all_surfaces + * to the client (there is no such message right now), and start + * from scratch on the destination side */ +- red_channel_wait_all_sent(&worker->display_channel->common.base); +- red_channel_wait_all_sent(&worker->cursor_channel->common.base); ++ if (!red_channel_wait_all_sent(&worker->display_channel->common.base, ++ DISPLAY_CLIENT_TIMEOUT)) { ++ red_channel_apply_clients(&worker->display_channel->common.base, ++ rcc_shutdown_if_pending_send); ++ } ++ if (!red_channel_wait_all_sent(&worker->cursor_channel->common.base, ++ DISPLAY_CLIENT_TIMEOUT)) { ++ red_channel_apply_clients(&worker->cursor_channel->common.base, ++ rcc_shutdown_if_pending_send); ++ } + } + + static int display_channel_wait_for_migrate_data(DisplayChannel *display) diff --git a/SOURCES/0015-red_worker-disconnect-the-channel-instead-of-shutdow.patch b/SOURCES/0015-red_worker-disconnect-the-channel-instead-of-shutdow.patch new file mode 100644 index 0000000..6fbb575 --- /dev/null +++ b/SOURCES/0015-red_worker-disconnect-the-channel-instead-of-shutdow.patch @@ -0,0 +1,84 @@ +From 7d044aae3ce063d901154a288106aa18703f7832 Mon Sep 17 00:00:00 2001 +From: Yonit Halperin +Date: Wed, 11 Sep 2013 15:02:23 -0400 +Subject: [PATCH] red_worker: disconnect the channel instead of shutdown in + case of a blocking method failure + +rhbz#1004443 + +The methods that trigger waitings on the client pipe require that +the waiting will succeed in order to continue, or otherwise, that +all the living pipe items will be released (e.g., when +we must destroy a surface, we need that all its related pipe items will +be released). Shutdown of the socket will eventually trigger +red_channel_client_disconnect (*), which will empty the pipe. However, +if the blocking method failed, we need to empty the pipe synchronously. +It is not safe(**) to call red_channel_client_disconnect from ChannelCbs +, but all the blocking calls in red_worker are done from callbacks that +are triggered from the device. +To summarize, calling red_channel_client_disconnect instead of calling +red_channel_client_shutdown will immediately release all the pipe items that are +held by the channel client (by calling red_channel_client_pipe_clear). +If red_clear_surface_drawables_from_pipe timeouts, +red_channel_client_disconnect will make sure that the surface we wish to +release is not referenced by any pipe-item. + +(*) After a shutdown of a socket, we expect that later, when +red_peer_handle_incoming is called, it will encounter a socket +error and will call the channel's on_error callback which calls +red_channel_client_disconnect. + +(**) I believe it was not safe before commit 2d2121a17038bc0 (before adding ref +count to ChannelClient). However, I think it might still be unsafe, because +red_channel_client_disconnect sets rcc->stream to NULL, and rcc->stream +may be referred later inside a red_channel_client method unsafely. So instead +of checking if (stream != NULL) after calling callbacks, we try to avoid +calling red_channel_client_disconnect from callbacks. + +https://bugzilla.redhat.com/show_bug.cgi?id=1016795 +(cherry picked from commit 90a4761249f84421b27d67a85262b1423b24fe04) +--- + server/red_worker.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/server/red_worker.c b/server/red_worker.c +index 31f3cbb..7a1c2d9 100644 +--- a/server/red_worker.c ++++ b/server/red_worker.c +@@ -11137,10 +11137,10 @@ void handle_dev_destroy_surface_wait(void *opaque, void *payload) + dev_destroy_surface_wait(worker, msg->surface_id); + } + +-static void rcc_shutdown_if_pending_send(RedChannelClient *rcc) ++static void rcc_disconnect_if_pending_send(RedChannelClient *rcc) + { + if (red_channel_client_blocked(rcc) || rcc->pipe_size > 0) { +- red_channel_client_shutdown(rcc); ++ red_channel_client_disconnect(rcc); + } else { + spice_assert(red_channel_client_no_item_being_sent(rcc)); + } +@@ -11166,7 +11166,7 @@ static inline void red_cursor_reset(RedWorker *worker) + if (!red_channel_wait_all_sent(&worker->cursor_channel->common.base, + DISPLAY_CLIENT_TIMEOUT)) { + red_channel_apply_clients(&worker->cursor_channel->common.base, +- rcc_shutdown_if_pending_send); ++ rcc_disconnect_if_pending_send); + } + } + } +@@ -11453,12 +11453,12 @@ void handle_dev_stop(void *opaque, void *payload) + if (!red_channel_wait_all_sent(&worker->display_channel->common.base, + DISPLAY_CLIENT_TIMEOUT)) { + red_channel_apply_clients(&worker->display_channel->common.base, +- rcc_shutdown_if_pending_send); ++ rcc_disconnect_if_pending_send); + } + if (!red_channel_wait_all_sent(&worker->cursor_channel->common.base, + DISPLAY_CLIENT_TIMEOUT)) { + red_channel_apply_clients(&worker->cursor_channel->common.base, +- rcc_shutdown_if_pending_send); ++ rcc_disconnect_if_pending_send); + } + } + diff --git a/SOURCES/0016-spice_timer_queue-don-t-call-timers-repeatedly.patch b/SOURCES/0016-spice_timer_queue-don-t-call-timers-repeatedly.patch new file mode 100644 index 0000000..7e47cbd --- /dev/null +++ b/SOURCES/0016-spice_timer_queue-don-t-call-timers-repeatedly.patch @@ -0,0 +1,33 @@ +From cc477ab18f925465d5ea33664128a2e29b3afcb2 Mon Sep 17 00:00:00 2001 +From: Yonit Halperin +Date: Tue, 13 Aug 2013 15:40:16 -0400 +Subject: [PATCH] spice_timer_queue: don't call timers repeatedly + +For channels that don't run as part of the main loop, we use +spice_timer_queue, while for the other channels we use +qemu timers support. The callbacks for setting timers are supplied to +red_channel via SpiceCoreInterface, and their behavior should be +consistent. qemu timers are called only once per each call to +timer_start. This patch assigns the same behaviour to spice_timer_queue. + +https://bugzilla.redhat.com/show_bug.cgi?id=1016790 +(cherry picked from commit c1c08c289883455f025836f14eda7bfd86442ed7) +--- + server/spice_timer_queue.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/server/spice_timer_queue.c b/server/spice_timer_queue.c +index 833ab1d..8f6e9c8 100644 +--- a/server/spice_timer_queue.c ++++ b/server/spice_timer_queue.c +@@ -261,9 +261,7 @@ void spice_timer_queue_cb(void) + break; + } else { + timer->func(timer->opaque); +- if (timer->is_active) { +- _spice_timer_set(timer, timer->ms, now_ms); +- } ++ spice_timer_cancel(timer); + } + } + } diff --git a/SOURCES/0017-red_channel-add-on_input-callback-for-tracing-incomi.patch b/SOURCES/0017-red_channel-add-on_input-callback-for-tracing-incomi.patch new file mode 100644 index 0000000..06b91be --- /dev/null +++ b/SOURCES/0017-red_channel-add-on_input-callback-for-tracing-incomi.patch @@ -0,0 +1,73 @@ +From af5b26baa47ced2f5e4822b66fb102e82f885e9a Mon Sep 17 00:00:00 2001 +From: Yonit Halperin +Date: Wed, 14 Aug 2013 09:38:12 -0400 +Subject: [PATCH] red_channel: add on_input callback for tracing incoming bytes + +The callback will be used in the next patch. + +https://bugzilla.redhat.com/show_bug.cgi?id=1016790 +(cherry picked from commit d1e7142a0f90e2b977d2a73d26dc5b09d7771826) +--- + server/red_channel.c | 7 +++++++ + server/red_channel.h | 2 ++ + 2 files changed, 9 insertions(+) + +diff --git a/server/red_channel.c b/server/red_channel.c +index 228669b..bc6ac8d 100644 +--- a/server/red_channel.c ++++ b/server/red_channel.c +@@ -244,6 +244,7 @@ static void red_peer_handle_incoming(RedsStream *stream, IncomingHandler *handle + handler->cb->on_error(handler->opaque); + return; + } ++ handler->cb->on_input(handler->opaque, bytes_read); + handler->header_pos += bytes_read; + + if (handler->header_pos != handler->header.header_size) { +@@ -271,6 +272,7 @@ static void red_peer_handle_incoming(RedsStream *stream, IncomingHandler *handle + handler->cb->on_error(handler->opaque); + return; + } ++ handler->cb->on_input(handler->opaque, bytes_read); + handler->msg_pos += bytes_read; + if (handler->msg_pos != msg_size) { + return; +@@ -383,6 +385,10 @@ static void red_channel_client_on_output(void *opaque, int n) + stat_inc_counter(rcc->channel->out_bytes_counter, n); + } + ++static void red_channel_client_on_input(void *opaque, int n) ++{ ++} ++ + static void red_channel_client_default_peer_on_error(RedChannelClient *rcc) + { + red_channel_client_disconnect(rcc); +@@ -919,6 +925,7 @@ RedChannel *red_channel_create(int size, + channel->incoming_cb.handle_message = (handle_message_proc)handle_message; + channel->incoming_cb.on_error = + (on_incoming_error_proc)red_channel_client_default_peer_on_error; ++ channel->incoming_cb.on_input = red_channel_client_on_input; + channel->outgoing_cb.get_msg_size = red_channel_client_peer_get_out_msg_size; + channel->outgoing_cb.prepare = red_channel_client_peer_prepare_out_msg; + channel->outgoing_cb.on_block = red_channel_client_peer_on_out_block; +diff --git a/server/red_channel.h b/server/red_channel.h +index fa11505..64befff 100644 +--- a/server/red_channel.h ++++ b/server/red_channel.h +@@ -74,6 +74,7 @@ typedef uint8_t *(*alloc_msg_recv_buf_proc)(void *opaque, uint16_t type, uint32_ + typedef void (*release_msg_recv_buf_proc)(void *opaque, + uint16_t type, uint32_t size, uint8_t *msg); + typedef void (*on_incoming_error_proc)(void *opaque); ++typedef void (*on_input_proc)(void *opaque, int n); + + typedef struct IncomingHandlerInterface { + handle_message_proc handle_message; +@@ -83,6 +84,7 @@ typedef struct IncomingHandlerInterface { + // The following is an optional alternative to handle_message, used if not null + spice_parse_channel_func_t parser; + handle_parsed_proc handle_parsed; ++ on_input_proc on_input; + } IncomingHandlerInterface; + + typedef struct IncomingHandler { diff --git a/SOURCES/0018-red_channel-add-option-to-monitor-whether-a-channel-.patch b/SOURCES/0018-red_channel-add-option-to-monitor-whether-a-channel-.patch new file mode 100644 index 0000000..32125a7 --- /dev/null +++ b/SOURCES/0018-red_channel-add-option-to-monitor-whether-a-channel-.patch @@ -0,0 +1,237 @@ +From c1a4637e0a6854fd67438bde2dfa7489cbc9e9c4 Mon Sep 17 00:00:00 2001 +From: Yonit Halperin +Date: Wed, 14 Aug 2013 10:10:37 -0400 +Subject: [PATCH] red_channel: add option to monitor whether a channel client + is alive + +rhbz#994175 + +When a client connection is closed surprisingly (i.e., without a FIN +segment), we cannot identify it by a socket error (which is the only +way by which we identified disconnections so far). +This patch allows a channel client to periodically check the state of +the connection and identify surprise disconnections. + +https://bugzilla.redhat.com/show_bug.cgi?id=1016790 +(cherry picked from commit c8b808bb8211e756a5e2280da173010984b71680) +--- + server/red_channel.c | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++ + server/red_channel.h | 14 ++++++ + 2 files changed, 133 insertions(+) + +diff --git a/server/red_channel.c b/server/red_channel.c +index bc6ac8d..5df8f14 100644 +--- a/server/red_channel.c ++++ b/server/red_channel.c +@@ -57,6 +57,13 @@ enum QosPingState { + PING_STATE_LATENCY, + }; + ++enum ConnectivityState { ++ CONNECTIVITY_STATE_CONNECTED, ++ CONNECTIVITY_STATE_BLOCKED, ++ CONNECTIVITY_STATE_WAIT_PONG, ++ CONNECTIVITY_STATE_DISCONNECTED, ++}; ++ + static void red_channel_client_start_ping_timer(RedChannelClient *rcc, uint32_t timeout); + static void red_channel_client_cancel_ping_timer(RedChannelClient *rcc); + static void red_channel_client_restart_ping_timer(RedChannelClient *rcc); +@@ -66,6 +73,7 @@ static void red_client_add_channel(RedClient *client, RedChannelClient *rcc); + static void red_client_remove_channel(RedChannelClient *rcc); + static RedChannelClient *red_client_get_channel(RedClient *client, int type, int id); + static void red_channel_client_restore_main_sender(RedChannelClient *rcc); ++static inline int red_channel_client_waiting_for_ack(RedChannelClient *rcc); + + /* + * Lifetime of RedChannel, RedChannelClient and RedClient: +@@ -382,11 +390,19 @@ static void red_channel_client_on_output(void *opaque, int n) + { + RedChannelClient *rcc = opaque; + ++ if (rcc->connectivity_monitor.timer) { ++ rcc->connectivity_monitor.out_bytes += n; ++ } + stat_inc_counter(rcc->channel->out_bytes_counter, n); + } + + static void red_channel_client_on_input(void *opaque, int n) + { ++ RedChannelClient *rcc = opaque; ++ ++ if (rcc->connectivity_monitor.timer) { ++ rcc->connectivity_monitor.in_bytes += n; ++ } + } + + static void red_channel_client_default_peer_on_error(RedChannelClient *rcc) +@@ -743,6 +759,97 @@ static void red_channel_client_ping_timer(void *opaque) + } + } + ++/* ++ * When a connection is not alive (and we can't detect it via a socket error), we ++ * reach one of these 2 states: ++ * (1) Sending msgs is blocked: either writes return EAGAIN ++ * or we are missing MSGC_ACK from the client. ++ * (2) MSG_PING was sent without receiving a MSGC_PONG in reply. ++ * ++ * The connectivity_timer callback tests if the channel's state matches one of the above. ++ * In case it does, on the next time the timer is called, it checks if the connection has ++ * been idle during the time that passed since the previous timer call. If the connection ++ * has been idle, we consider the client as disconnected. ++ */ ++static void red_channel_client_connectivity_timer(void *opaque) ++{ ++ RedChannelClient *rcc = opaque; ++ RedChannelClientConnectivityMonitor *monitor = &rcc->connectivity_monitor; ++ int is_alive = TRUE; ++ ++ if (monitor->state == CONNECTIVITY_STATE_BLOCKED) { ++ if (monitor->in_bytes == 0 && monitor->out_bytes == 0) { ++ if (!rcc->send_data.blocked && !red_channel_client_waiting_for_ack(rcc)) { ++ spice_error("mismatch between rcc-state and connectivity-state"); ++ } ++ spice_debug("rcc is blocked; connection is idle"); ++ is_alive = FALSE; ++ } ++ } else if (monitor->state == CONNECTIVITY_STATE_WAIT_PONG) { ++ if (monitor->in_bytes == 0) { ++ if (rcc->latency_monitor.state != PING_STATE_WARMUP && ++ rcc->latency_monitor.state != PING_STATE_LATENCY) { ++ spice_error("mismatch between rcc-state and connectivity-state"); ++ } ++ spice_debug("rcc waits for pong; connection is idle"); ++ is_alive = FALSE; ++ } ++ } ++ ++ if (is_alive) { ++ monitor->in_bytes = 0; ++ monitor->out_bytes = 0; ++ if (rcc->send_data.blocked || red_channel_client_waiting_for_ack(rcc)) { ++ monitor->state = CONNECTIVITY_STATE_BLOCKED; ++ } else if (rcc->latency_monitor.state == PING_STATE_WARMUP || ++ rcc->latency_monitor.state == PING_STATE_LATENCY) { ++ monitor->state = CONNECTIVITY_STATE_WAIT_PONG; ++ } else { ++ monitor->state = CONNECTIVITY_STATE_CONNECTED; ++ } ++ rcc->channel->core->timer_start(rcc->connectivity_monitor.timer, ++ rcc->connectivity_monitor.timeout); ++ } else { ++ monitor->state = CONNECTIVITY_STATE_DISCONNECTED; ++ spice_debug("rcc %p has not been responsive for more than %u ms, disconnecting", ++ rcc, monitor->timeout); ++ red_channel_client_disconnect(rcc); ++ } ++} ++ ++void red_channel_client_start_connectivity_monitoring(RedChannelClient *rcc, uint32_t timeout_ms) ++{ ++ if (!red_channel_client_is_connected(rcc)) { ++ return; ++ } ++ spice_debug(NULL); ++ spice_assert(timeout_ms > 0); ++ /* ++ * If latency_monitor is not active, we activate it in order to enable ++ * periodic ping messages so that we will be be able to identify a disconnected ++ * channel-client even if there are no ongoing channel specific messages ++ * on this channel. ++ */ ++ if (rcc->latency_monitor.timer == NULL) { ++ rcc->latency_monitor.timer = rcc->channel->core->timer_add( ++ red_channel_client_ping_timer, rcc); ++ if (!rcc->client->during_target_migrate) { ++ red_channel_client_start_ping_timer(rcc, PING_TEST_IDLE_NET_TIMEOUT_MS); ++ } ++ rcc->latency_monitor.roundtrip = -1; ++ } ++ if (rcc->connectivity_monitor.timer == NULL) { ++ rcc->connectivity_monitor.state = CONNECTIVITY_STATE_CONNECTED; ++ rcc->connectivity_monitor.timer = rcc->channel->core->timer_add( ++ red_channel_client_connectivity_timer, rcc); ++ rcc->connectivity_monitor.timeout = timeout_ms; ++ if (!rcc->client->during_target_migrate) { ++ rcc->channel->core->timer_start(rcc->connectivity_monitor.timer, ++ rcc->connectivity_monitor.timeout); ++ } ++ } ++} ++ + RedChannelClient *red_channel_client_create(int size, RedChannel *channel, RedClient *client, + RedsStream *stream, + int monitor_latency, +@@ -843,6 +950,10 @@ static void red_channel_client_seamless_migration_done(RedChannelClient *rcc) + if (rcc->latency_monitor.timer) { + red_channel_client_start_ping_timer(rcc, PING_TEST_IDLE_NET_TIMEOUT_MS); + } ++ if (rcc->connectivity_monitor.timer) { ++ rcc->channel->core->timer_start(rcc->connectivity_monitor.timer, ++ rcc->connectivity_monitor.timeout); ++ } + } + pthread_mutex_unlock(&rcc->client->lock); + } +@@ -889,6 +1000,10 @@ void red_channel_client_default_migrate(RedChannelClient *rcc) + rcc->channel->core->timer_remove(rcc->latency_monitor.timer); + rcc->latency_monitor.timer = NULL; + } ++ if (rcc->connectivity_monitor.timer) { ++ rcc->channel->core->timer_remove(rcc->connectivity_monitor.timer); ++ rcc->connectivity_monitor.timer = NULL; ++ } + red_channel_client_pipe_add_type(rcc, PIPE_ITEM_TYPE_MIGRATE); + } + +@@ -1736,6 +1851,10 @@ void red_channel_client_disconnect(RedChannelClient *rcc) + rcc->channel->core->timer_remove(rcc->latency_monitor.timer); + rcc->latency_monitor.timer = NULL; + } ++ if (rcc->connectivity_monitor.timer) { ++ rcc->channel->core->timer_remove(rcc->connectivity_monitor.timer); ++ rcc->connectivity_monitor.timer = NULL; ++ } + red_channel_remove_client(rcc); + rcc->channel->channel_cbs.on_disconnect(rcc); + } +diff --git a/server/red_channel.h b/server/red_channel.h +index 64befff..9e54dce 100644 +--- a/server/red_channel.h ++++ b/server/red_channel.h +@@ -236,6 +236,14 @@ typedef struct RedChannelClientLatencyMonitor { + int64_t roundtrip; + } RedChannelClientLatencyMonitor; + ++typedef struct RedChannelClientConnectivityMonitor { ++ int state; ++ uint32_t out_bytes; ++ uint32_t in_bytes; ++ uint32_t timeout; ++ SpiceTimer *timer; ++} RedChannelClientConnectivityMonitor; ++ + struct RedChannelClient { + RingItem channel_link; + RingItem client_link; +@@ -289,6 +297,7 @@ struct RedChannelClient { + int wait_migrate_flush_mark; + + RedChannelClientLatencyMonitor latency_monitor; ++ RedChannelClientConnectivityMonitor connectivity_monitor; + }; + + struct RedChannel { +@@ -448,6 +457,11 @@ SpiceMarshaller *red_channel_client_switch_to_urgent_sender(RedChannelClient *rc + /* returns -1 if we don't have an estimation */ + int red_channel_client_get_roundtrip_ms(RedChannelClient *rcc); + ++/* ++ * Checks periodically if the connection is still alive ++ */ ++void red_channel_client_start_connectivity_monitoring(RedChannelClient *rcc, uint32_t timeout_ms); ++ + void red_channel_pipe_item_init(RedChannel *channel, PipeItem *item, int type); + + // TODO: add back the channel_pipe_add functionality - by adding reference counting diff --git a/SOURCES/0019-main_channel-monitoring-client-connection-status.patch b/SOURCES/0019-main_channel-monitoring-client-connection-status.patch new file mode 100644 index 0000000..467e0bb --- /dev/null +++ b/SOURCES/0019-main_channel-monitoring-client-connection-status.patch @@ -0,0 +1,118 @@ +From 3d1c72b6da63f24aeaae45ec7681826520c1d404 Mon Sep 17 00:00:00 2001 +From: Yonit Halperin +Date: Wed, 14 Aug 2013 10:56:44 -0400 +Subject: [PATCH] main_channel: monitoring client connection status + +rhbz#994175 + +Start monitoring if the client connection is alive after completing +the bit-rate test. + +https://bugzilla.redhat.com/show_bug.cgi?id=1016790 +(cherry picked from commit ed1f70c6d16ff55adf73a08f063f5d7955f4c488) +--- + server/main_channel.c | 27 +++++++++++++++++++++------ + server/main_channel.h | 2 +- + server/reds.c | 3 +-- + 3 files changed, 23 insertions(+), 9 deletions(-) + +diff --git a/server/main_channel.c b/server/main_channel.c +index fe032a6..54718ba 100644 +--- a/server/main_channel.c ++++ b/server/main_channel.c +@@ -55,6 +55,8 @@ + + #define PING_INTERVAL (1000 * 10) + ++#define CLIENT_CONNECTIVITY_TIMEOUT (30*1000) // 30 seconds ++ + static uint8_t zero_page[ZERO_BUF_SIZE] = {0}; + + enum { +@@ -201,16 +203,20 @@ RedClient *main_channel_get_client_by_link_id(MainChannel *main_chan, uint32_t c + + static int main_channel_client_push_ping(MainChannelClient *mcc, int size); + +-void main_channel_client_start_net_test(MainChannelClient *mcc) ++void main_channel_client_start_net_test(MainChannelClient *mcc, int test_rate) + { + if (!mcc || mcc->net_test_id) { + return; + } +- if (main_channel_client_push_ping(mcc, NET_TEST_WARMUP_BYTES) +- && main_channel_client_push_ping(mcc, 0) +- && main_channel_client_push_ping(mcc, NET_TEST_BYTES)) { +- mcc->net_test_id = mcc->ping_id - 2; +- mcc->net_test_stage = NET_TEST_STAGE_WARMUP; ++ if (test_rate) { ++ if (main_channel_client_push_ping(mcc, NET_TEST_WARMUP_BYTES) ++ && main_channel_client_push_ping(mcc, 0) ++ && main_channel_client_push_ping(mcc, NET_TEST_BYTES)) { ++ mcc->net_test_id = mcc->ping_id - 2; ++ mcc->net_test_stage = NET_TEST_STAGE_WARMUP; ++ } ++ } else { ++ red_channel_client_start_connectivity_monitoring(&mcc->base, CLIENT_CONNECTIVITY_TIMEOUT); + } + } + +@@ -970,6 +976,8 @@ static int main_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, uint + spice_printerr("net test: invalid values, latency %" PRIu64 + " roundtrip %" PRIu64 ". assuming high" + "bandwidth", mcc->latency, roundtrip); ++ red_channel_client_start_connectivity_monitoring(&mcc->base, ++ CLIENT_CONNECTIVITY_TIMEOUT); + break; + } + mcc->bitrate_per_sec = (uint64_t)(NET_TEST_BYTES * 8) * 1000000 +@@ -980,6 +988,8 @@ static int main_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, uint + mcc->bitrate_per_sec, + (double)mcc->bitrate_per_sec / 1024 / 1024, + main_channel_client_is_low_bandwidth(mcc) ? " LOW BANDWIDTH" : ""); ++ red_channel_client_start_connectivity_monitoring(&mcc->base, ++ CLIENT_CONNECTIVITY_TIMEOUT); + break; + default: + spice_printerr("invalid net test stage, ping id %d test id %d stage %d", +@@ -989,6 +999,11 @@ static int main_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, uint + mcc->net_test_stage = NET_TEST_STAGE_INVALID; + } + break; ++ } else { ++ /* ++ * channel client monitors the connectivity using ping-pong messages ++ */ ++ red_channel_client_handle_message(rcc, size, type, message); + } + #ifdef RED_STATISTICS + reds_update_stat_value(roundtrip); +diff --git a/server/main_channel.h b/server/main_channel.h +index 27367a4..29eb8d4 100644 +--- a/server/main_channel.h ++++ b/server/main_channel.h +@@ -54,7 +54,7 @@ void main_channel_push_agent_disconnected(MainChannel *main_chan); + void main_channel_client_push_agent_tokens(MainChannelClient *mcc, uint32_t num_tokens); + void main_channel_client_push_agent_data(MainChannelClient *mcc, uint8_t* data, size_t len, + spice_marshaller_item_free_func free_data, void *opaque); +-void main_channel_client_start_net_test(MainChannelClient *mcc); ++void main_channel_client_start_net_test(MainChannelClient *mcc, int test_rate); + // TODO: huge. Consider making a reds_* interface for these functions + // and calling from main. + void main_channel_push_init(MainChannelClient *mcc, int display_channels_hint, +diff --git a/server/reds.c b/server/reds.c +index f9f185d..7b7f262 100644 +--- a/server/reds.c ++++ b/server/reds.c +@@ -1718,11 +1718,10 @@ static void reds_handle_main_link(RedLinkInfo *link) + main_channel_push_name(mcc, spice_name); + if (spice_uuid_is_set) + main_channel_push_uuid(mcc, spice_uuid); +- +- main_channel_client_start_net_test(mcc); + } else { + reds_mig_target_client_add(client); + } ++ main_channel_client_start_net_test(mcc, !mig_target); + } + + #define RED_MOUSE_STATE_TO_LOCAL(state) \ diff --git a/SPECS/spice.spec b/SPECS/spice.spec index 7706f02..3cbd532 100644 --- a/SPECS/spice.spec +++ b/SPECS/spice.spec @@ -1,21 +1,30 @@ Name: spice Version: 0.12.4 -Release: 3%{?dist} +Release: 5%{?dist} Summary: Implements the SPICE protocol Group: User Interface/Desktops License: LGPLv2+ URL: http://www.spice-space.org/ Source0: http://www.spice-space.org/download/releases/%{name}-%{version}.tar.bz2 -Patch1: 0001-red_channel-prevent-adding-and-pushing-pipe-items-af.patch -Patch2: 0002-red_channel-add-ref-count-to-RedClient.patch -Patch3: 0003-main_dispatcher-add-ref-count-protection-to-RedClien.patch -Patch4: 0004-decouple-disconnection-of-the-main-channel-from-clie.patch -Patch5: 0005-reds-s-red_client_disconnect-red_channel_client_shut.patch -Patch6: 0006-snd_worker-fix-memory-leak-of-PlaybackChannel.patch -Patch7: 0007-snd_worker-snd_disconnect_channel-don-t-call-snd_cha.patch -Patch8: 0008-log-improve-debug-information-related-to-client-disc.patch -Patch9: 0009-red_worker-decrease-the-timeout-when-flushing-comman.patch -Patch10: 0010-Fix-buffer-overflow-when-decrypting-client-SPICE-tic.patch +Patch1: 0001-red_channel-prevent-adding-and-pushing-pipe-items-af.patch +Patch2: 0002-red_channel-add-ref-count-to-RedClient.patch +Patch3: 0003-main_dispatcher-add-ref-count-protection-to-RedClien.patch +Patch4: 0004-decouple-disconnection-of-the-main-channel-from-clie.patch +Patch5: 0005-reds-s-red_client_disconnect-red_channel_client_shut.patch +Patch6: 0006-snd_worker-fix-memory-leak-of-PlaybackChannel.patch +Patch7: 0007-snd_worker-snd_disconnect_channel-don-t-call-snd_cha.patch +Patch8: 0008-log-improve-debug-information-related-to-client-disc.patch +Patch9: 0009-red_worker-decrease-the-timeout-when-flushing-comman.patch +Patch10: 0010-Fix-buffer-overflow-when-decrypting-client-SPICE-tic.patch +Patch11: 0011-server-move-three-functions-to-red_channel.patch +Patch12: 0012-server-s-red_wait_all_sent-red_channel_wait_all_sent.patch +Patch13: 0013-red_worker-cleanup-red_clear_surface_drawables_from_.patch +Patch14: 0014-red_channel-cleanup-of-red_channel_client-blocking-m.patch +Patch15: 0015-red_worker-disconnect-the-channel-instead-of-shutdow.patch +Patch16: 0016-spice_timer_queue-don-t-call-timers-repeatedly.patch +Patch17: 0017-red_channel-add-on_input-callback-for-tracing-incomi.patch +Patch18: 0018-red_channel-add-option-to-monitor-whether-a-channel-.patch +Patch19: 0019-main_channel-monitoring-client-connection-status.patch # https://bugzilla.redhat.com/show_bug.cgi?id=613529 %if 0%{?rhel} @@ -81,6 +90,15 @@ using spice-server, you will need to install spice-server-devel. %patch8 -p1 %patch9 -p1 %patch10 -p1 +%patch11 -p1 +%patch12 -p1 +%patch13 -p1 +%patch14 -p1 +%patch15 -p1 +%patch16 -p1 +%patch17 -p1 +%patch18 -p1 +%patch19 -p1 %build @@ -111,6 +129,12 @@ mkdir -p %{buildroot}%{_libexecdir} %changelog +* Wed Jan 29 2014 Christophe Fergeau 0.12.4-5 +- Fix qemu crash during migration with reboot + Resolves: rhbz#1016795 +- Monitor whether the client is alive + Resolves: rhbz#1016790 + * Tue Oct 15 2013 Christophe Fergeau 0.12.4-3 - Fix spice-server crash when client sends a password which is too long Resolves: CVE-2013-4282 @@ -122,7 +146,7 @@ mkdir -p %{buildroot}%{_libexecdir} - Add patches from upstream git to fix sound-channel-free crash (rhbz#986407) - Add Obsoletes for dropped spice-client sub-package -* Tue Jul 22 2013 Yonit Halperin 0.12.4-1 +* Mon Jul 22 2013 Yonit Halperin 0.12.4-1 - New upstream release 0.12.4 - Require libjpeg-turbo-devel instead of libjpeg-devel - Remove "BuildRequires: spice-protocol" from spice-server @@ -181,6 +205,9 @@ mkdir -p %{buildroot}%{_libexecdir} - Add double free fix. (#808936) %changelog +* Fri Dec 27 2013 Daniel Mach - 0.12.4-4 +- Mass rebuild 2013-12-27 + * Tue Apr 24 2012 Alon Levy - Add 32 bit fixes from git master. (#815717)