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