diff options
author | Jonathon Jongsma <jjongsma@redhat.com> | 2016-05-18 11:58:51 +0100 |
---|---|---|
committer | Jonathon Jongsma <jjongsma@redhat.com> | 2016-09-01 17:34:16 -0500 |
commit | 3e06b80f6020c5d6e7c2c3e40480fac05b2192fb (patch) | |
tree | e1ea8553c7fe68db77565a6ceca13db63a25e5fe | |
parent | 97d0e07b4c9b39eb9d9cb73c747306ee7340bf95 (diff) |
Move CommonGraphicsChannel to a new file
Move out of red-worker.c. This requires a little bit of minor
refactoring to avoid accessing some RedWorker internals in the
constructor function, etc.
-rw-r--r-- | server/Makefile.am | 2 | ||||
-rw-r--r-- | server/common-graphics-channel.c | 129 | ||||
-rw-r--r-- | server/common-graphics-channel.h | 90 | ||||
-rw-r--r-- | server/cursor-channel-client.c | 1 | ||||
-rw-r--r-- | server/cursor-channel.c | 11 | ||||
-rw-r--r-- | server/cursor-channel.h | 5 | ||||
-rw-r--r-- | server/display-channel.c | 9 | ||||
-rw-r--r-- | server/display-channel.h | 6 | ||||
-rw-r--r-- | server/red-worker.c | 117 | ||||
-rw-r--r-- | server/red-worker.h | 65 |
10 files changed, 249 insertions, 186 deletions
diff --git a/server/Makefile.am b/server/Makefile.am index f217399b..3382946b 100644 --- a/server/Makefile.am +++ b/server/Makefile.am @@ -77,6 +77,8 @@ libserver_la_SOURCES = \ cache-item.h \ char-device.c \ char-device.h \ + common-graphics-channel.c \ + common-graphics-channel.h \ demarshallers.h \ event-loop.c \ glz-encoder.c \ diff --git a/server/common-graphics-channel.c b/server/common-graphics-channel.c new file mode 100644 index 00000000..625162c4 --- /dev/null +++ b/server/common-graphics-channel.c @@ -0,0 +1,129 @@ +/* + Copyright (C) 2009-2016 Red Hat, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <fcntl.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/tcp.h> + +#include "common-graphics-channel.h" +#include "dcc.h" +#include "main-channel-client.h" + +static uint8_t *common_alloc_recv_buf(RedChannelClient *rcc, uint16_t type, uint32_t size) +{ + RedChannel *channel = red_channel_client_get_channel(rcc); + CommonGraphicsChannel *common = SPICE_CONTAINEROF(channel, CommonGraphicsChannel, base); + + /* SPICE_MSGC_MIGRATE_DATA is the only client message whose size is dynamic */ + if (type == SPICE_MSGC_MIGRATE_DATA) { + return spice_malloc(size); + } + + if (size > CHANNEL_RECEIVE_BUF_SIZE) { + spice_critical("unexpected message size %u (max is %d)", size, CHANNEL_RECEIVE_BUF_SIZE); + return NULL; + } + return common->recv_buf; +} + +static void common_release_recv_buf(RedChannelClient *rcc, uint16_t type, uint32_t size, + uint8_t* msg) +{ + if (type == SPICE_MSGC_MIGRATE_DATA) { + free(msg); + } +} + +int common_channel_config_socket(RedChannelClient *rcc) +{ + RedClient *client = red_channel_client_get_client(rcc); + MainChannelClient *mcc = red_client_get_main(client); + RedsStream *stream = red_channel_client_get_stream(rcc); + int flags; + int delay_val; + gboolean is_low_bandwidth; + + if ((flags = fcntl(stream->socket, F_GETFL)) == -1) { + spice_warning("accept failed, %s", strerror(errno)); + return FALSE; + } + + if (fcntl(stream->socket, F_SETFL, flags | O_NONBLOCK) == -1) { + spice_warning("accept failed, %s", strerror(errno)); + return FALSE; + } + + // TODO - this should be dynamic, not one time at channel creation + is_low_bandwidth = main_channel_client_is_low_bandwidth(mcc); + delay_val = is_low_bandwidth ? 0 : 1; + /* FIXME: Using Nagle's Algorithm can lead to apparent delays, depending + * on the delayed ack timeout on the other side. + * Instead of using Nagle's, we need to implement message buffering on + * the application level. + * see: http://www.stuartcheshire.org/papers/NagleDelayedAck/ + */ + if (setsockopt(stream->socket, IPPROTO_TCP, TCP_NODELAY, &delay_val, + sizeof(delay_val)) == -1) { + if (errno != ENOTSUP) { + spice_warning("setsockopt failed, %s", strerror(errno)); + } + } + // TODO: move wide/narrow ack setting to red_channel. + red_channel_client_ack_set_client_window(rcc, + is_low_bandwidth ? + WIDE_CLIENT_ACK_WINDOW : NARROW_CLIENT_ACK_WINDOW); + return TRUE; +} + +CommonGraphicsChannel* common_graphics_channel_new(RedsState *server, + QXLInstance *qxl, + const SpiceCoreInterfaceInternal *core, + int size, uint32_t channel_type, + int migration_flags, + ChannelCbs *channel_cbs, + channel_handle_parsed_proc handle_parsed) +{ + RedChannel *channel = NULL; + CommonGraphicsChannel *common; + + spice_return_val_if_fail(channel_cbs, NULL); + spice_return_val_if_fail(!channel_cbs->alloc_recv_buf, NULL); + spice_return_val_if_fail(!channel_cbs->release_recv_buf, NULL); + + if (!channel_cbs->config_socket) + channel_cbs->config_socket = common_channel_config_socket; + channel_cbs->alloc_recv_buf = common_alloc_recv_buf; + channel_cbs->release_recv_buf = common_release_recv_buf; + + channel = red_channel_create_parser(size, server, + core, channel_type, + qxl->id, TRUE /* handle_acks */, + spice_get_client_channel_parser(channel_type, NULL), + handle_parsed, + channel_cbs, + migration_flags); + spice_return_val_if_fail(channel, NULL); + + common = (CommonGraphicsChannel *)channel; + common->qxl = qxl; + return common; +} + diff --git a/server/common-graphics-channel.h b/server/common-graphics-channel.h new file mode 100644 index 00000000..2a546424 --- /dev/null +++ b/server/common-graphics-channel.h @@ -0,0 +1,90 @@ +/* + Copyright (C) 2009-2016 Red Hat, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _COMMON_GRAPHICS_CHANNEL_H +#define _COMMON_GRAPHICS_CHANNEL_H + +#include "red-channel.h" +#include "red-worker.h" + +int common_channel_config_socket(RedChannelClient *rcc); + +#define COMMON_CLIENT_TIMEOUT (NSEC_PER_SEC * 30) + +#define CHANNEL_RECEIVE_BUF_SIZE 1024 +typedef struct CommonGraphicsChannel { + RedChannel base; // Must be the first thing + + QXLInstance *qxl; + uint8_t recv_buf[CHANNEL_RECEIVE_BUF_SIZE]; + uint32_t id_alloc; // bitfield. TODO - use this instead of shift scheme. + int during_target_migrate; /* TRUE when the client that is associated with the channel + is during migration. Turned off when the vm is started. + The flag is used to avoid sending messages that are artifacts + of the transition from stopped vm to loaded vm (e.g., recreation + of the primary surface) */ +} CommonGraphicsChannel; + +#define COMMON_GRAPHICS_CHANNEL(Channel) ((CommonGraphicsChannel*)(Channel)) + +enum { + RED_PIPE_ITEM_TYPE_VERB = RED_PIPE_ITEM_TYPE_CHANNEL_BASE, + RED_PIPE_ITEM_TYPE_INVAL_ONE, + + RED_PIPE_ITEM_TYPE_COMMON_LAST +}; + +typedef struct RedVerbItem { + RedPipeItem base; + uint16_t verb; +} RedVerbItem; + +static inline void red_marshall_verb(RedChannelClient *rcc, RedVerbItem *item) +{ + red_channel_client_init_send_data(rcc, item->verb, NULL); +} + +static inline void red_pipe_add_verb(RedChannelClient* rcc, uint16_t verb) +{ + RedVerbItem *item = spice_new(RedVerbItem, 1); + + red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_VERB); + item->verb = verb; + red_channel_client_pipe_add(rcc, &item->base); +} + +static inline void red_pipe_add_verb_proxy(RedChannelClient *rcc, gpointer data) +{ + uint16_t verb = GPOINTER_TO_UINT(data); + red_pipe_add_verb(rcc, verb); +} + + +static inline void red_pipes_add_verb(RedChannel *channel, uint16_t verb) +{ + red_channel_apply_clients_data(channel, red_pipe_add_verb_proxy, GUINT_TO_POINTER(verb)); +} + +CommonGraphicsChannel* common_graphics_channel_new(RedsState *server, + QXLInstance *qxl, + const SpiceCoreInterfaceInternal *core, + int size, uint32_t channel_type, + int migration_flags, + ChannelCbs *channel_cbs, + channel_handle_parsed_proc handle_parsed); + +#endif /* _COMMON_GRAPHICS_CHANNEL_H */ diff --git a/server/cursor-channel-client.c b/server/cursor-channel-client.c index b7cc6662..63795fd3 100644 --- a/server/cursor-channel-client.c +++ b/server/cursor-channel-client.c @@ -21,6 +21,7 @@ #include <common/generated_server_marshallers.h> +#include "common-graphics-channel.h" #include "red-channel-client.h" #include "cache-item.h" #include "cursor-channel.h" diff --git a/server/cursor-channel.c b/server/cursor-channel.c index 9976731b..d0337616 100644 --- a/server/cursor-channel.c +++ b/server/cursor-channel.c @@ -22,6 +22,7 @@ #include <glib.h> #include <common/generated_server_marshallers.h> +#include "common-graphics-channel.h" #include "cursor-channel.h" #include "cursor-channel-client.h" #include "reds.h" @@ -308,7 +309,8 @@ static void cursor_channel_send_item(RedChannelClient *rcc, RedPipeItem *pipe_it red_channel_client_begin_send_message(rcc); } -CursorChannel* cursor_channel_new(RedWorker *worker) +CursorChannel* cursor_channel_new(RedsState *server, QXLInstance *qxl, + const SpiceCoreInterfaceInternal *core) { CursorChannel *cursor_channel; CommonGraphicsChannel *channel = NULL; @@ -318,9 +320,10 @@ CursorChannel* cursor_channel_new(RedWorker *worker) }; spice_info("create cursor channel"); - channel = red_worker_new_channel(worker, sizeof(CursorChannel), "cursor_channel", - SPICE_CHANNEL_CURSOR, 0, - &cbs, red_channel_client_handle_message); + channel = common_graphics_channel_new(server, qxl, core, + sizeof(CursorChannel), + SPICE_CHANNEL_CURSOR, 0, + &cbs, red_channel_client_handle_message); cursor_channel = (CursorChannel *)channel; cursor_channel->cursor_visible = TRUE; diff --git a/server/cursor-channel.h b/server/cursor-channel.h index 6149e2dd..a3ddaa31 100644 --- a/server/cursor-channel.h +++ b/server/cursor-channel.h @@ -18,7 +18,7 @@ #ifndef CURSOR_CHANNEL_H_ # define CURSOR_CHANNEL_H_ -#include "red-worker.h" +#include "common-graphics-channel.h" /** * This type it's a RedChannel class which implement cursor (mouse) @@ -39,7 +39,8 @@ typedef struct CursorChannel CursorChannel; * provided as helper functions and should only be called from the * CursorChannel thread. */ -CursorChannel* cursor_channel_new (RedWorker *worker); +CursorChannel* cursor_channel_new (RedsState *server, QXLInstance *qxl, + const SpiceCoreInterfaceInternal *core); /** * Cause the channel to disconnect all clients diff --git a/server/display-channel.c b/server/display-channel.c index 95d3cc53..3b5edef9 100644 --- a/server/display-channel.c +++ b/server/display-channel.c @@ -1887,7 +1887,9 @@ static SpiceCanvas *image_surfaces_get(SpiceImageSurfaces *surfaces, uint32_t su return display->surfaces[surface_id].context.canvas; } -DisplayChannel* display_channel_new(SpiceServer *reds, RedWorker *worker, +DisplayChannel* display_channel_new(RedsState *reds, + QXLInstance *qxl, + const SpiceCoreInterfaceInternal *core, int migrate, int stream_video, GArray *video_codecs, uint32_t n_surfaces) @@ -1906,9 +1908,8 @@ DisplayChannel* display_channel_new(SpiceServer *reds, RedWorker *worker, }; spice_info("create display channel"); - display = (DisplayChannel *)red_worker_new_channel( - worker, sizeof(*display), "display_channel", - SPICE_CHANNEL_DISPLAY, + display = (DisplayChannel *)common_graphics_channel_new( + reds, qxl, core, sizeof(*display), SPICE_CHANNEL_DISPLAY, SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER, &cbs, dcc_handle_message); spice_return_val_if_fail(display, NULL); diff --git a/server/display-channel.h b/server/display-channel.h index 7b714807..a46cd0b0 100644 --- a/server/display-channel.h +++ b/server/display-channel.h @@ -43,6 +43,7 @@ #include "stream.h" #include "dcc.h" #include "image-encoders.h" +#include "common-graphics-channel.h" typedef struct DependItem { Drawable *drawable; @@ -225,8 +226,9 @@ typedef struct RedUpgradeItem { } RedUpgradeItem; -DisplayChannel* display_channel_new (SpiceServer *reds, - RedWorker *worker, +DisplayChannel* display_channel_new (RedsState *reds, + QXLInstance *qxl, + const SpiceCoreInterfaceInternal *core, int migrate, int stream_video, GArray *video_codecs, diff --git a/server/red-worker.c b/server/red-worker.c index 590412bc..3447286a 100644 --- a/server/red-worker.c +++ b/server/red-worker.c @@ -91,39 +91,12 @@ struct RedWorker { RedRecord *record; }; -static RedsState* red_worker_get_server(RedWorker *worker); - static int display_is_connected(RedWorker *worker) { return (worker->display_channel && red_channel_is_connected( &worker->display_channel->common.base)); } -static uint8_t *common_alloc_recv_buf(RedChannelClient *rcc, uint16_t type, uint32_t size) -{ - RedChannel *channel = red_channel_client_get_channel(rcc); - CommonGraphicsChannel *common = SPICE_CONTAINEROF(channel, CommonGraphicsChannel, base); - - /* SPICE_MSGC_MIGRATE_DATA is the only client message whose size is dynamic */ - if (type == SPICE_MSGC_MIGRATE_DATA) { - return spice_malloc(size); - } - - if (size > CHANNEL_RECEIVE_BUF_SIZE) { - spice_critical("unexpected message size %u (max is %d)", size, CHANNEL_RECEIVE_BUF_SIZE); - return NULL; - } - return common->recv_buf; -} - -static void common_release_recv_buf(RedChannelClient *rcc, uint16_t type, uint32_t size, - uint8_t* msg) -{ - if (type == SPICE_MSGC_MIGRATE_DATA) { - free(msg); - } -} - void red_drawable_unref(RedDrawable *red_drawable) { if (--red_drawable->refs) { @@ -401,82 +374,6 @@ static void flush_all_qxl_commands(RedWorker *worker) flush_cursor_commands(worker); } -int common_channel_config_socket(RedChannelClient *rcc) -{ - RedClient *client = red_channel_client_get_client(rcc); - MainChannelClient *mcc = red_client_get_main(client); - RedsStream *stream = red_channel_client_get_stream(rcc); - int flags; - int delay_val; - gboolean is_low_bandwidth; - - if ((flags = fcntl(stream->socket, F_GETFL)) == -1) { - spice_warning("accept failed, %s", strerror(errno)); - return FALSE; - } - - if (fcntl(stream->socket, F_SETFL, flags | O_NONBLOCK) == -1) { - spice_warning("accept failed, %s", strerror(errno)); - return FALSE; - } - - // TODO - this should be dynamic, not one time at channel creation - is_low_bandwidth = main_channel_client_is_low_bandwidth(mcc); - delay_val = is_low_bandwidth ? 0 : 1; - /* FIXME: Using Nagle's Algorithm can lead to apparent delays, depending - * on the delayed ack timeout on the other side. - * Instead of using Nagle's, we need to implement message buffering on - * the application level. - * see: http://www.stuartcheshire.org/papers/NagleDelayedAck/ - */ - if (setsockopt(stream->socket, IPPROTO_TCP, TCP_NODELAY, &delay_val, - sizeof(delay_val)) == -1) { - if (errno != ENOTSUP) { - spice_warning("setsockopt failed, %s", strerror(errno)); - } - } - // TODO: move wide/narrow ack setting to red_channel. - red_channel_client_ack_set_client_window(rcc, - is_low_bandwidth ? - WIDE_CLIENT_ACK_WINDOW : NARROW_CLIENT_ACK_WINDOW); - return TRUE; -} - -CommonGraphicsChannel *red_worker_new_channel(RedWorker *worker, int size, - const char *name, - uint32_t channel_type, int migration_flags, - ChannelCbs *channel_cbs, - channel_handle_parsed_proc handle_parsed) -{ - RedChannel *channel = NULL; - CommonGraphicsChannel *common; - - spice_return_val_if_fail(worker, NULL); - spice_return_val_if_fail(channel_cbs, NULL); - spice_return_val_if_fail(!channel_cbs->alloc_recv_buf, NULL); - spice_return_val_if_fail(!channel_cbs->release_recv_buf, NULL); - - if (!channel_cbs->config_socket) - channel_cbs->config_socket = common_channel_config_socket; - channel_cbs->alloc_recv_buf = common_alloc_recv_buf; - channel_cbs->release_recv_buf = common_release_recv_buf; - - channel = red_channel_create_parser(size, red_worker_get_server(worker), - &worker->core, channel_type, - worker->qxl->id, TRUE /* handle_acks */, - spice_get_client_channel_parser(channel_type, NULL), - handle_parsed, - channel_cbs, - migration_flags); - spice_return_val_if_fail(channel, NULL); - red_channel_set_stat_node(channel, stat_add_node(red_worker_get_server(worker), - worker->stat, name, TRUE)); - - common = (CommonGraphicsChannel *)channel; - common->qxl = worker->qxl; - return common; -} - static void guest_set_client_capabilities(RedWorker *worker) { int i; @@ -1501,18 +1398,23 @@ RedWorker* red_worker_new(QXLInstance *qxl, worker->event_timeout = INF_EVENT_WAIT; - worker->cursor_channel = cursor_channel_new(worker); + worker->cursor_channel = cursor_channel_new(reds, qxl, + &worker->core); channel = RED_CHANNEL(worker->cursor_channel); + red_channel_set_stat_node(channel, stat_add_node(reds, worker->stat, + "cursor_channel", TRUE)); red_channel_register_client_cbs(channel, client_cursor_cbs, dispatcher); reds_register_channel(reds, channel); // TODO: handle seemless migration. Temp, setting migrate to FALSE - worker->display_channel = display_channel_new(reds, worker, FALSE, + worker->display_channel = display_channel_new(reds, qxl, &worker->core, FALSE, reds_get_streaming_video(reds), reds_get_video_codecs(reds), init_info.n_surfaces); channel = RED_CHANNEL(worker->display_channel); + red_channel_set_stat_node(channel, stat_add_node(reds, worker->stat, + "display_channel", TRUE)); red_channel_register_client_cbs(channel, client_display_cbs, dispatcher); red_channel_set_cap(channel, SPICE_DISPLAY_CAP_MONITORS_CONFIG); red_channel_set_cap(channel, SPICE_DISPLAY_CAP_PREF_COMPRESSION); @@ -1562,8 +1464,3 @@ bool red_worker_run(RedWorker *worker) return r == 0; } - -static RedsState* red_worker_get_server(RedWorker *worker) -{ - return red_qxl_get_server(worker->qxl->st); -} diff --git a/server/red-worker.h b/server/red-worker.h index a0a327ac..370240fa 100644 --- a/server/red-worker.h +++ b/server/red-worker.h @@ -25,75 +25,12 @@ typedef struct RedWorker RedWorker; -int common_channel_config_socket(RedChannelClient *rcc); - -#define COMMON_CLIENT_TIMEOUT (NSEC_PER_SEC * 30) - -#define CHANNEL_RECEIVE_BUF_SIZE 1024 -typedef struct CommonGraphicsChannel { - RedChannel base; // Must be the first thing - - QXLInstance *qxl; - uint8_t recv_buf[CHANNEL_RECEIVE_BUF_SIZE]; - uint32_t id_alloc; // bitfield. TODO - use this instead of shift scheme. - int during_target_migrate; /* TRUE when the client that is associated with the channel - is during migration. Turned off when the vm is started. - The flag is used to avoid sending messages that are artifacts - of the transition from stopped vm to loaded vm (e.g., recreation - of the primary surface) */ -} CommonGraphicsChannel; - -#define COMMON_GRAPHICS_CHANNEL(Channel) ((CommonGraphicsChannel*)(Channel)) - -enum { - RED_PIPE_ITEM_TYPE_VERB = RED_PIPE_ITEM_TYPE_CHANNEL_BASE, - RED_PIPE_ITEM_TYPE_INVAL_ONE, - - RED_PIPE_ITEM_TYPE_COMMON_LAST -}; - -typedef struct RedVerbItem { - RedPipeItem base; - uint16_t verb; -} RedVerbItem; - -static inline void red_marshall_verb(RedChannelClient *rcc, RedVerbItem *item) -{ - red_channel_client_init_send_data(rcc, item->verb, NULL); -} - -static inline void red_pipe_add_verb(RedChannelClient* rcc, uint16_t verb) -{ - RedVerbItem *item = spice_new(RedVerbItem, 1); - - red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_VERB); - item->verb = verb; - red_channel_client_pipe_add(rcc, &item->base); -} - -static inline void red_pipe_add_verb_proxy(RedChannelClient *rcc, gpointer data) -{ - uint16_t verb = GPOINTER_TO_UINT(data); - red_pipe_add_verb(rcc, verb); -} - - -static inline void red_pipes_add_verb(RedChannel *channel, uint16_t verb) -{ - red_channel_apply_clients_data(channel, red_pipe_add_verb_proxy, GUINT_TO_POINTER(verb)); -} - RedWorker* red_worker_new(QXLInstance *qxl, const ClientCbs *client_cursor_cbs, const ClientCbs *client_display_cbs); bool red_worker_run(RedWorker *worker); +SpiceCoreInterfaceInternal* red_worker_get_core_interface(RedWorker *worker); void red_drawable_unref(RedDrawable *red_drawable); -CommonGraphicsChannel *red_worker_new_channel(RedWorker *worker, int size, - const char *name, - uint32_t channel_type, int migration_flags, - ChannelCbs *channel_cbs, - channel_handle_parsed_proc handle_parsed); - #endif |