1 /*
2 Copyright (C) 2009 Red Hat, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, see <http://www.gnu.org/licenses/>.
16
17
18 Author:
19 yhalperi@redhat.com
20 */
21
22 #ifndef RED_CHANNEL_H_
23 #define RED_CHANNEL_H_
24
25 #include <pthread.h>
26 #include <limits.h>
27 #include <common/marshaller.h>
28 #include <common/demarshallers.h>
29
30 #include "spice-wrapped.h"
31 #include "red-common.h"
32 #include "red-stream.h"
33 #include "stat.h"
34 #include "red-pipe-item.h"
35 #include "red-channel-capabilities.h"
36 #include "utils.hpp"
37
38 #include "push-visibility.h"
39 class RedChannel;
40 struct RedChannelPrivate;
41 struct RedChannelClient;
42 struct RedClient;
43 struct MainChannelClient;
44 struct Dispatcher;
45
test_capability(const uint32_t * caps,int num_caps,uint32_t cap)46 static inline gboolean test_capability(const uint32_t *caps, int num_caps, uint32_t cap)
47 {
48 return VD_AGENT_HAS_CAPABILITY(caps, num_caps, cap);
49 }
50
51 #define FOREACH_CLIENT(_channel, _data) \
52 GLIST_FOREACH(_channel->get_clients(), RedChannelClient, _data)
53
54 /* Red Channel interface */
55
56 struct RedChannel: public red::shared_ptr_counted
57 {
58 typedef enum {
59 FlagNone = 0,
60 MigrateNeedFlush = SPICE_MIGRATE_NEED_FLUSH,
61 MigrateNeedDataTransfer = SPICE_MIGRATE_NEED_DATA_TRANSFER,
62 HandleAcks = 8,
63 MigrateAll = MigrateNeedFlush|MigrateNeedDataTransfer,
64 } CreationFlags;
65
66 RedChannel(RedsState *reds, uint32_t type, uint32_t id, CreationFlags flags=FlagNone,
67 SpiceCoreInterfaceInternal *core=nullptr, Dispatcher *dispatcher=nullptr);
68 virtual ~RedChannel();
69
70 uint32_t id() const;
71 uint32_t type() const;
72 uint32_t migration_flags() const;
73 bool handle_acks() const;
74
75 virtual void on_connect(RedClient *client, RedStream *stream, int migration,
76 RedChannelCapabilities *caps) = 0;
77
78 uint8_t *parse(uint8_t *message, size_t message_size,
79 uint16_t message_type,
80 size_t *size_out, message_destructor_t *free_message) const;
81
82 const char *get_name() const;
83
84 void add_client(RedChannelClient *rcc);
85 void remove_client(RedChannelClient *rcc);
86
87 void init_stat_node(const RedStatNode *parent, const char *name);
88
89 // caps are freed when the channel is destroyed
90 void set_common_cap(uint32_t cap);
91 void set_cap(uint32_t cap);
92
93 int is_connected();
94
95 /* seamless migration is supported for only one client. This routine
96 * checks if the only channel client associated with channel is
97 * waiting for migration data */
98 bool is_waiting_for_migrate_data();
99
100 /*
101 * the disconnect callback is called from the channel's thread,
102 * i.e., for display channels - red worker thread, for all the other - from the main thread.
103 * RedChannel::destroy can be called only from channel thread.
104 */
105
106 void destroy();
107
108 /* return true if all the channel clients support the cap */
109 bool test_remote_cap(uint32_t cap);
110
111 // helper to push a new item to all channels
112 typedef RedPipeItemPtr (*new_pipe_item_t)(RedChannelClient *rcc, void *data, int num);
113 int pipes_new_add(new_pipe_item_t creator, void *data);
114
115 void pipes_add_type(int pipe_item_type);
116
117 void pipes_add_empty_msg(int msg_type);
118
119 /* Add an item to all the clients connected.
120 * The same item is shared between all clients.
121 * Function will take ownership of the item.
122 */
123 void pipes_add(RedPipeItemPtr&& item);
124
125 /* return TRUE if all of the connected clients to this channel are blocked */
126 bool all_blocked();
127
128 // TODO: unstaticed for display/cursor channels. they do some specific pushes not through
129 // adding elements or on events. but not sure if this is actually required (only result
130 // should be that they ""try"" a little harder, but if the event system is correct it
131 // should not make any difference.
132 void push();
133 // Again, used in various places outside of event handler context (or in other event handler
134 // contexts):
135 // flush_display_commands/flush_cursor_commands
136 // display_channel_wait_for_init
137 // red_wait_outgoing_item
138 // red_wait_pipe_item_sent
139 // handle_channel_events - this is the only one that was used before, and was in red-channel.c
140 void receive();
141 // For red_worker
142 void send();
143 // For red_worker
144 void disconnect();
145 void connect(RedClient *client, RedStream *stream, int migration,
146 RedChannelCapabilities *caps);
147
148 /* return the sum of all the rcc pipe size */
149 uint32_t max_pipe_size();
150 /* return the max size of all the rcc pipe */
151 uint32_t sum_pipes_size();
152
153 GList *get_clients();
154 guint get_n_clients();
155 struct RedsState* get_server();
156 SpiceCoreInterfaceInternal* get_core_interface();
157
158 /* channel callback function */
159 void reset_thread_id();
160 const RedStatNode *get_stat_node();
161
162 const RedChannelCapabilities* get_local_capabilities();
163
164 /*
165 * blocking functions.
166 *
167 * timeout is in nano sec. -1 for no timeout.
168 *
169 * This method tries for up to @timeout nanoseconds to send all the
170 * items which are currently queued. If the timeout elapses,
171 * the RedChannelClient which are too slow (those which still have pending
172 * items) will be disconnected.
173 *
174 * Return: TRUE if waiting succeeded. FALSE if timeout expired.
175 */
176
177 bool wait_all_sent(int64_t timeout);
178
179 /* wrappers for client callbacks */
180 void migrate_client(RedChannelClient *rcc);
181 void disconnect_client(RedChannelClient *rcc);
182
183 red::unique_link<RedChannelPrivate> priv;
184 };
185
186 inline RedChannel::CreationFlags operator|(RedChannel::CreationFlags a, RedChannel::CreationFlags b)
187 {
188 return (RedChannel::CreationFlags) ((int)a|(int)b);
189 }
190
191 #define CHANNEL_BLOCKED_SLEEP_DURATION 10000 //micro
192
193 #define red_channel_log_generic(log_cb, channel, format, ...) \
194 do { \
195 auto channel_ = (channel); \
196 uint32_t id_ = channel_->id(); \
197 log_cb("%s:%u (%p): " format, channel_->get_name(), \
198 id_, &*channel_, ## __VA_ARGS__); \
199 } while (0)
200
201 #define red_channel_warning(...) red_channel_log_generic(g_warning, __VA_ARGS__)
202 #define red_channel_message(...) red_channel_log_generic(g_message, __VA_ARGS__)
203 #define red_channel_debug(...) red_channel_log_generic(g_debug, __VA_ARGS__)
204
205 #include "pop-visibility.h"
206
207 #endif /* RED_CHANNEL_H_ */
208