summaryrefslogtreecommitdiff
path: root/server/red-channel.h
blob: c4fd8a1d9dca2721e3271ec07d8f92267b0ba020 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
/*
    Copyright (C) 2009 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/>.


    Author:
        yhalperi@redhat.com
*/

#ifndef RED_CHANNEL_H_
#define RED_CHANNEL_H_

#include <pthread.h>
#include <limits.h>
#include <common/marshaller.h>
#include <common/demarshallers.h>

#include "spice-wrapped.h"
#include "red-common.h"
#include "red-stream.h"
#include "stat.h"
#include "red-pipe-item.h"
#include "red-channel-capabilities.h"
#include "utils.hpp"

#include "push-visibility.h"
class RedChannel;
struct RedChannelPrivate;
struct RedChannelClient;
struct RedClient;
struct MainChannelClient;
struct Dispatcher;

static inline gboolean test_capability(const uint32_t *caps, int num_caps, uint32_t cap)
{
    return VD_AGENT_HAS_CAPABILITY(caps, num_caps, cap);
}

#define FOREACH_CLIENT(_channel, _data) \
    GLIST_FOREACH(_channel->get_clients(), RedChannelClient, _data)

/* Red Channel interface */

struct RedChannel: public red::shared_ptr_counted
{
    typedef enum {
        FlagNone = 0,
        MigrateNeedFlush = SPICE_MIGRATE_NEED_FLUSH,
        MigrateNeedDataTransfer = SPICE_MIGRATE_NEED_DATA_TRANSFER,
        HandleAcks = 8,
        MigrateAll = MigrateNeedFlush|MigrateNeedDataTransfer,
    } CreationFlags;

    RedChannel(RedsState *reds, uint32_t type, uint32_t id, CreationFlags flags=FlagNone,
               SpiceCoreInterfaceInternal *core=nullptr, Dispatcher *dispatcher=nullptr);
    virtual ~RedChannel();

    uint32_t id() const;
    uint32_t type() const;
    uint32_t migration_flags() const;
    bool handle_acks() const;

    virtual void on_connect(RedClient *client, RedStream *stream, int migration,
                            RedChannelCapabilities *caps) = 0;

    uint8_t *parse(uint8_t *message, size_t message_size,
                   uint16_t message_type,
                   size_t *size_out, message_destructor_t *free_message) const;

    const char *get_name() const;

    void add_client(RedChannelClient *rcc);
    void remove_client(RedChannelClient *rcc);

    void init_stat_node(const RedStatNode *parent, const char *name);

    // caps are freed when the channel is destroyed
    void set_common_cap(uint32_t cap);
    void set_cap(uint32_t cap);

    int is_connected();

    /* seamless migration is supported for only one client. This routine
     * checks if the only channel client associated with channel is
     * waiting for migration data */
    bool is_waiting_for_migrate_data();

    /*
     * the disconnect callback is called from the channel's thread,
     * i.e., for display channels - red worker thread, for all the other - from the main thread.
     * RedChannel::destroy can be called only from channel thread.
     */

    void destroy();

    /* return true if all the channel clients support the cap */
    bool test_remote_cap(uint32_t cap);

    // helper to push a new item to all channels
    typedef RedPipeItemPtr (*new_pipe_item_t)(RedChannelClient *rcc, void *data, int num);
    int pipes_new_add(new_pipe_item_t creator, void *data);

    void pipes_add_type(int pipe_item_type);

    void pipes_add_empty_msg(int msg_type);

    /* Add an item to all the clients connected.
     * The same item is shared between all clients.
     * Function will take ownership of the item.
     */
    void pipes_add(RedPipeItemPtr&& item);

    /* return TRUE if all of the connected clients to this channel are blocked */
    bool all_blocked();

    // TODO: unstaticed for display/cursor channels. they do some specific pushes not through
    // adding elements or on events. but not sure if this is actually required (only result
    // should be that they ""try"" a little harder, but if the event system is correct it
    // should not make any difference.
    void push();
    // Again, used in various places outside of event handler context (or in other event handler
    // contexts):
    //  flush_display_commands/flush_cursor_commands
    //  display_channel_wait_for_init
    //  red_wait_outgoing_item
    //  red_wait_pipe_item_sent
    //  handle_channel_events - this is the only one that was used before, and was in red-channel.c
    void receive();
    // For red_worker
    void send();
    // For red_worker
    void disconnect();
    void connect(RedClient *client, RedStream *stream, int migration,
                 RedChannelCapabilities *caps);

    /* return the sum of all the rcc pipe size */
    uint32_t max_pipe_size();
    /* return the max size of all the rcc pipe */
    uint32_t sum_pipes_size();

    GList *get_clients();
    guint get_n_clients();
    struct RedsState* get_server();
    SpiceCoreInterfaceInternal* get_core_interface();

    /* channel callback function */
    void reset_thread_id();
    const RedStatNode *get_stat_node();

    const RedChannelCapabilities* get_local_capabilities();

    /*
     * blocking functions.
     *
     * timeout is in nano sec. -1 for no timeout.
     *
     * This method tries for up to @timeout nanoseconds to send all the
     * items which are currently queued. If the timeout elapses,
     * the RedChannelClient which are too slow (those which still have pending
     * items) will be disconnected.
     *
     * Return: TRUE if waiting succeeded. FALSE if timeout expired.
     */

    bool wait_all_sent(int64_t timeout);

    /* wrappers for client callbacks */
    void migrate_client(RedChannelClient *rcc);
    void disconnect_client(RedChannelClient *rcc);

    red::unique_link<RedChannelPrivate> priv;
};

inline RedChannel::CreationFlags operator|(RedChannel::CreationFlags a, RedChannel::CreationFlags b)
{
    return (RedChannel::CreationFlags) ((int)a|(int)b);
}

#define CHANNEL_BLOCKED_SLEEP_DURATION 10000 //micro

#define red_channel_log_generic(log_cb, channel, format, ...)                            \
    do {                                                                                 \
        auto channel_ = (channel);                                                       \
        uint32_t id_ = channel_->id();                                                   \
        log_cb("%s:%u (%p): " format, channel_->get_name(),                              \
                        id_, &*channel_, ## __VA_ARGS__);                                \
    } while (0)

#define red_channel_warning(...) red_channel_log_generic(g_warning, __VA_ARGS__)
#define red_channel_message(...) red_channel_log_generic(g_message, __VA_ARGS__)
#define red_channel_debug(...) red_channel_log_generic(g_debug, __VA_ARGS__)

#ifdef QUEUE_STAT
void queue_print_stats(void);
#else
static inline void queue_print_stats(void) {}
#endif

#include "pop-visibility.h"

#endif /* RED_CHANNEL_H_ */