~ubuntu-branches/ubuntu/trusty/spice/trusty-proposed

« back to all changes in this revision

Viewing changes to server/reds.c

  • Committer: Package Import Robot
  • Author(s): Liang Guo
  • Date: 2013-05-10 09:10:16 UTC
  • mfrom: (7.1.3 experimental)
  • Revision ID: package-import@ubuntu.com-20130510091016-jpqqitwsvhqq9eub
Tags: 0.12.2-0nocelt3
Upload to unstable

Show diffs side-by-side

added added

removed removed

Lines of Context:
47
47
#include <sasl/sasl.h>
48
48
#endif
49
49
 
 
50
#include <glib.h>
 
51
 
50
52
#include <spice/protocol.h>
51
53
#include <spice/vd_agent.h>
52
54
#include <spice/stats.h>
67
69
#include "stat.h"
68
70
#include "demarshallers.h"
69
71
#include "char_device.h"
 
72
#include "migration_protocol.h"
70
73
#ifdef USE_TUNNEL
71
74
#include "red_tunnel_worker.h"
72
75
#endif
74
77
#include "smartcard.h"
75
78
#endif
76
79
 
 
80
#include "reds-private.h"
 
81
 
77
82
SpiceCoreInterface *core = NULL;
78
83
static SpiceCharDeviceInstance *vdagent = NULL;
79
84
static SpiceMigrateInstance *migration_interface = NULL;
92
97
#define REDS_TOKENS_TO_SEND 5
93
98
#define REDS_VDI_PORT_NUM_RECEIVE_BUFFS 5
94
99
 
 
100
static TicketAuthentication taTicket;
 
101
 
95
102
static int spice_port = -1;
96
103
static int spice_secure_port = -1;
97
104
static int spice_listen_socket_fd = -1;
118
125
#endif
119
126
int agent_mouse = TRUE;
120
127
int agent_copypaste = TRUE;
121
 
 
122
 
#define MIGRATE_TIMEOUT (1000 * 10) /* 10sec */
123
 
#define MM_TIMER_GRANULARITY_MS (1000 / 30)
124
 
#define MM_TIME_DELTA 400 /*ms*/
125
 
#define VDI_PORT_WRITE_RETRY_TIMEOUT 100 /*ms*/
126
 
 
127
 
 
128
 
typedef struct TicketAuthentication {
129
 
    char password[SPICE_MAX_PASSWORD_LENGTH];
130
 
    time_t expiration_time;
131
 
} TicketAuthentication;
132
 
 
133
 
static TicketAuthentication taTicket;
134
 
 
135
 
typedef struct TicketInfo {
136
 
    RSA *rsa;
137
 
    int rsa_size;
138
 
    BIGNUM *bn;
139
 
    SpiceLinkEncryptedTicket encrypted_ticket;
140
 
} TicketInfo;
141
 
 
142
 
typedef struct MonitorMode {
143
 
    uint32_t x_res;
144
 
    uint32_t y_res;
145
 
} MonitorMode;
146
 
 
147
 
typedef struct VDIReadBuf {
148
 
    RingItem link;
149
 
    int len;
150
 
    uint8_t data[SPICE_AGENT_MAX_DATA_SIZE];
151
 
} VDIReadBuf;
152
 
 
153
 
enum {
154
 
    VDI_PORT_READ_STATE_READ_HADER,
155
 
    VDI_PORT_READ_STATE_GET_BUFF,
156
 
    VDI_PORT_READ_STATE_READ_DATA,
157
 
};
158
 
 
159
 
void vdagent_char_device_wakeup(SpiceCharDeviceInstance *sin);
160
 
struct SpiceCharDeviceState vdagent_char_device_state = {
161
 
    .wakeup = &vdagent_char_device_wakeup,
162
 
};
163
 
 
164
 
typedef struct VDIPortState {
165
 
    uint32_t plug_generation;
166
 
 
167
 
    uint32_t num_tokens;
168
 
    uint32_t num_client_tokens;
169
 
    Ring external_bufs;
170
 
    Ring internal_bufs;
171
 
    Ring write_queue;
172
 
    AgentMsgFilter write_filter;
173
 
 
174
 
    Ring read_bufs;
175
 
    uint32_t read_state;
176
 
    uint32_t message_recive_len;
177
 
    uint8_t *recive_pos;
178
 
    uint32_t recive_len;
179
 
    VDIReadBuf *current_read_buf;
180
 
    AgentMsgFilter read_filter;
181
 
 
182
 
    VDIChunkHeader vdi_chunk_header;
183
 
} VDIPortState;
184
 
 
185
 
#ifdef RED_STATISTICS
186
 
 
187
 
#define REDS_MAX_STAT_NODES 100
188
 
#define REDS_STAT_SHM_SIZE (sizeof(SpiceStat) + REDS_MAX_STAT_NODES * sizeof(SpiceStatNode))
189
 
 
190
 
typedef struct RedsStatValue {
191
 
    uint32_t value;
192
 
    uint32_t min;
193
 
    uint32_t max;
194
 
    uint32_t average;
195
 
    uint32_t count;
196
 
} RedsStatValue;
197
 
 
198
 
#endif
199
 
 
200
 
typedef struct RedsMigPendingLink {
201
 
    RingItem ring_link; // list of links that belongs to the same client
202
 
    SpiceLinkMess *link_msg;
203
 
    RedsStream *stream;
204
 
} RedsMigPendingLink;
205
 
 
206
 
typedef struct RedsMigTargetClient {
207
 
    RingItem link;
208
 
    RedClient *client;
209
 
    Ring pending_links;
210
 
} RedsMigTargetClient;
211
 
 
212
 
typedef struct RedsState {
213
 
    int listen_socket;
214
 
    int secure_listen_socket;
215
 
    SpiceWatch *listen_watch;
216
 
    SpiceWatch *secure_listen_watch;
217
 
    VDIPortState agent_state;
218
 
    int pending_mouse_event;
219
 
    Ring clients;
220
 
    int num_clients;
221
 
    MainChannel *main_channel;
222
 
 
223
 
    int mig_wait_connect;
224
 
    int mig_wait_disconnect;
225
 
    int mig_inprogress;
226
 
    int expect_migrate;
227
 
    Ring mig_target_clients;
228
 
    int num_mig_target_clients;
229
 
    RedsMigSpice *mig_spice;
230
 
    int num_of_channels;
231
 
    Ring channels;
232
 
    int mouse_mode;
233
 
    int is_client_mouse_allowed;
234
 
    int dispatcher_allows_client_mouse;
235
 
    MonitorMode monitor_mode;
236
 
    SpiceTimer *mig_timer;
237
 
    SpiceTimer *mm_timer;
238
 
    SpiceTimer *vdi_port_write_timer;
239
 
    int vdi_port_write_timer_started;
240
 
 
241
 
    SSL_CTX *ctx;
242
 
 
243
 
#ifdef RED_STATISTICS
244
 
    char *stat_shm_name;
245
 
    SpiceStat *stat;
246
 
    pthread_mutex_t stat_lock;
247
 
    RedsStatValue roundtrip_stat;
248
 
#endif
249
 
    int peer_minor_version;
250
 
    int allow_multiple_clients;
251
 
} RedsState;
 
128
static bool exit_on_disconnect = FALSE;
252
129
 
253
130
static RedsState *reds = NULL;
254
131
 
272
149
    int skip_auth;
273
150
} RedLinkInfo;
274
151
 
275
 
typedef struct VDIPortBuf VDIPortBuf;
276
 
struct  __attribute__ ((__packed__)) VDIPortBuf {
277
 
    RingItem link;
278
 
    uint8_t *now;
279
 
    int write_len;
280
 
    void (*free)(VDIPortBuf *buf);
281
 
    VDIChunkHeader chunk_header; //start send from &chunk_header
282
 
};
283
 
 
284
 
typedef struct __attribute__ ((__packed__)) VDAgentExtBuf {
285
 
    VDIPortBuf base;
286
 
    uint8_t buf[SPICE_AGENT_MAX_DATA_SIZE];
287
 
    VDIChunkHeader migrate_overflow;
288
 
} VDAgentExtBuf;
289
 
 
290
 
typedef struct __attribute__ ((__packed__)) VDInternalBuf {
291
 
    VDIPortBuf base;
292
 
    VDAgentMessage header;
293
 
    union {
294
 
        VDAgentMouseState mouse_state;
295
 
    }
296
 
    u;
297
 
    VDIChunkHeader migrate_overflow;
298
 
} VDInternalBuf;
299
 
 
300
152
typedef struct RedSSLParameters {
301
153
    char keyfile_password[256];
302
154
    char certs_file[256];
316
168
static void migrate_timeout(void *opaque);
317
169
static RedsMigTargetClient* reds_mig_target_client_find(RedClient *client);
318
170
static void reds_mig_target_client_free(RedsMigTargetClient *mig_client);
 
171
static void reds_mig_cleanup_wait_disconnect(void);
 
172
static void reds_mig_remove_wait_disconnect_client(RedClient *client);
 
173
static void reds_char_device_add_state(SpiceCharDeviceState *st);
 
174
static void reds_char_device_remove_state(SpiceCharDeviceState *st);
319
175
 
320
176
static ChannelSecurityOptions *channels_security = NULL;
321
177
static int default_channel_security =
498
354
    spice_assert(!(node->flags & SPICE_STAT_NODE_FLAG_ENABLED));
499
355
    node->value = 0;
500
356
    node->flags = SPICE_STAT_NODE_FLAG_ENABLED | (visible ? SPICE_STAT_NODE_FLAG_VISIBLE : 0);
501
 
    strncpy(node->name, name, sizeof(node->name));
 
357
    g_strlcpy(node->name, name, sizeof(node->name));
502
358
    insert_stat_node(parent, ref);
503
359
    pthread_mutex_unlock(&reds->stat_lock);
504
360
    return ref;
563
419
        ring_remove(&channel->link);
564
420
        reds->num_of_channels--;
565
421
    } else {
566
 
        spice_printerr("not found");
 
422
        spice_warning("not found");
567
423
    }
568
424
}
569
425
 
583
439
static void reds_mig_cleanup(void)
584
440
{
585
441
    if (reds->mig_inprogress) {
586
 
        if (reds->mig_wait_connect) {
 
442
 
 
443
        if (reds->mig_wait_connect || reds->mig_wait_disconnect) {
587
444
            SpiceMigrateInterface *sif;
588
445
            spice_assert(migration_interface);
589
446
            sif = SPICE_CONTAINEROF(migration_interface->base.sif, SpiceMigrateInterface, base);
590
 
            sif->migrate_connect_complete(migration_interface);
 
447
            if (reds->mig_wait_connect) {
 
448
                sif->migrate_connect_complete(migration_interface);
 
449
            } else {
 
450
                if (sif->migrate_end_complete) {
 
451
                    sif->migrate_end_complete(migration_interface);
 
452
                }
 
453
            }
591
454
        }
592
455
        reds->mig_inprogress = FALSE;
593
456
        reds->mig_wait_connect = FALSE;
594
457
        reds->mig_wait_disconnect = FALSE;
595
458
        core->timer_cancel(reds->mig_timer);
 
459
        reds_mig_cleanup_wait_disconnect();
596
460
    }
597
461
}
598
462
 
601
465
    VDIPortState *state = &reds->agent_state;
602
466
    SpiceCharDeviceInterface *sif;
603
467
 
604
 
    while (!ring_is_empty(&state->write_queue)) {
605
 
        VDIPortBuf *buf;
606
 
        RingItem *item;
607
 
 
608
 
        item = ring_get_tail(&state->write_queue);
609
 
        ring_remove(item);
610
 
        buf = (VDIPortBuf *)item;
611
 
        buf->free(buf);
612
 
    }
613
 
    state->read_state = VDI_PORT_READ_STATE_READ_HADER;
 
468
    state->read_state = VDI_PORT_READ_STATE_READ_HEADER;
614
469
    state->recive_pos = (uint8_t *)&state->vdi_chunk_header;
615
470
    state->recive_len = sizeof(state->vdi_chunk_header);
616
471
    state->message_recive_len = 0;
617
472
    if (state->current_read_buf) {
618
 
        ring_add(&state->read_bufs, &state->current_read_buf->link);
 
473
        vdi_port_read_buf_unref(state->current_read_buf);
619
474
        state->current_read_buf = NULL;
620
475
    }
621
476
    /* Reset read filter to start with clean state when the agent reconnects */
622
477
    agent_msg_filter_init(&state->read_filter, agent_copypaste, TRUE);
623
478
    /* Throw away pending chunks from the current (if any) and future
624
 
       messages written by the client */
 
479
     * messages written by the client.
 
480
     * TODO: client should clear its agent messages queue when the agent
 
481
     * is disconnect. Currently, when and agent gets disconnected and reconnected,
 
482
     * messeges that were directed to the previous instance of the agent continues
 
483
     * to be sent from the client. This TODO will require server, protocol, and client changes */
625
484
    state->write_filter.result = AGENT_MSG_FILTER_DISCARD;
626
485
    state->write_filter.discard_all = TRUE;
 
486
    state->client_agent_started = FALSE;
 
487
 
 
488
    /* reseting and not destroying the state as a workaround for a bad
 
489
     * tokens management in the vdagent protocol:
 
490
     *  The client tokens' are set only once, when the main channel is initialized.
 
491
     *  Instead, it would have been more appropriate to reset them upon AGEN_CONNECT.
 
492
     *  The client tokens are tracked as part of the SpiceCharDeviceClientState. Thus,
 
493
     *  in order to be backward compatible with the client, we need to track the tokens
 
494
     *  even if the agent is detached. We don't destroy the the char_device state, and
 
495
     *  instead we just reset it.
 
496
     *  In addition, there used to be a misshandling of AGENT_TOKENS message in spice-gtk: it
 
497
     *  overrides the amount of tokens, instead of adding the given amount.
 
498
     */
 
499
    if (red_channel_test_remote_cap(&reds->main_channel->base,
 
500
                                    SPICE_MAIN_CAP_AGENT_CONNECTED_TOKENS)) {
 
501
        spice_char_device_state_destroy(state->base);
 
502
        state->base = NULL;
 
503
    } else {
 
504
        spice_char_device_reset(state->base);
 
505
    }
627
506
 
628
507
    sif = SPICE_CONTAINEROF(vdagent->base.sif, SpiceCharDeviceInterface, base);
629
508
    if (sif->state) {
640
519
{
641
520
    RedsMigTargetClient *mig_client;
642
521
 
 
522
    if (exit_on_disconnect)
 
523
    {
 
524
        spice_info("Exiting server because of client disconnect.\n");
 
525
        exit(0);
 
526
    }
 
527
 
643
528
    if (!client || client->disconnecting) {
644
529
        return;
645
530
    }
646
531
 
647
 
    spice_printerr("");
 
532
    spice_info(NULL);
648
533
    /* disconnecting is set to prevent recursion because of the following:
649
534
     * main_channel_client_on_disconnect->
650
535
     *  reds_client_disconnect->red_client_destroy->main_channel...
658
543
    if (mig_client) {
659
544
        reds_mig_target_client_free(mig_client);
660
545
    }
 
546
 
 
547
    if (reds->mig_wait_disconnect) {
 
548
        reds_mig_remove_wait_disconnect_client(client);
 
549
    }
 
550
 
 
551
    if (reds->agent_state.base) {
 
552
        /* note that vdagent might be NULL, if the vdagent was once
 
553
         * up and than was removed */
 
554
        if (spice_char_device_client_exists(reds->agent_state.base, client)) {
 
555
            spice_char_device_client_remove(reds->agent_state.base, client);
 
556
        }
 
557
    }
 
558
 
661
559
    ring_remove(&client->link);
662
560
    reds->num_clients--;
663
561
    red_client_destroy(client);
673
571
         *  messages read from the agent */
674
572
        reds->agent_state.read_filter.result = AGENT_MSG_FILTER_DISCARD;
675
573
        reds->agent_state.read_filter.discard_all = TRUE;
 
574
        free(reds->agent_state.mig_data);
 
575
        reds->agent_state.mig_data = NULL;
676
576
 
677
577
        reds_mig_cleanup();
678
578
    }
684
584
{
685
585
    RingItem *link, *next;
686
586
 
687
 
    spice_printerr("");
 
587
    spice_info(NULL);
688
588
    RING_FOREACH_SAFE(link, next, &reds->clients) {
689
589
        reds_client_disconnect(SPICE_CONTAINEROF(link, RedClient, link));
690
590
    }
750
650
 
751
651
    vdagent = NULL;
752
652
    reds_update_mouse_mode();
753
 
 
754
 
    if (reds_main_channel_connected()) {
 
653
    if (reds_main_channel_connected() &&
 
654
        !red_channel_waits_for_migrate_data(&reds->main_channel->base)) {
755
655
        main_channel_push_agent_disconnected(reds->main_channel);
756
656
    }
757
657
}
758
658
 
759
 
static void reds_push_tokens(void)
760
 
{
761
 
    reds->agent_state.num_client_tokens += reds->agent_state.num_tokens;
762
 
    spice_assert(reds->agent_state.num_client_tokens <= REDS_AGENT_WINDOW_SIZE);
763
 
    main_channel_push_tokens(reds->main_channel, reds->agent_state.num_tokens);
764
 
    reds->agent_state.num_tokens = 0;
765
 
}
766
 
 
767
 
static int write_to_vdi_port(void);
768
 
 
769
 
static void vdi_port_write_timer_start(void)
770
 
{
771
 
    if (reds->vdi_port_write_timer_started) {
772
 
        return;
773
 
    }
774
 
    reds->vdi_port_write_timer_started = TRUE;
775
 
    core->timer_start(reds->vdi_port_write_timer,
776
 
                      VDI_PORT_WRITE_RETRY_TIMEOUT);
777
 
}
778
 
 
779
 
static void vdi_port_write_retry(void *opaque)
780
 
{
781
 
    reds->vdi_port_write_timer_started = FALSE;
782
 
    write_to_vdi_port();
783
 
}
784
 
 
785
 
static int write_to_vdi_port(void)
786
 
{
787
 
    VDIPortState *state = &reds->agent_state;
788
 
    SpiceCharDeviceInterface *sif;
789
 
    RingItem *ring_item;
790
 
    VDIPortBuf *buf;
791
 
    int total = 0;
792
 
    int n;
793
 
 
794
 
    if (!vdagent) {
795
 
        return 0;
796
 
    }
797
 
 
798
 
    sif = SPICE_CONTAINEROF(vdagent->base.sif, SpiceCharDeviceInterface, base);
799
 
    while (vdagent) {
800
 
        if (!(ring_item = ring_get_tail(&state->write_queue))) {
801
 
            break;
802
 
        }
803
 
        buf = (VDIPortBuf *)ring_item;
804
 
        n = sif->write(vdagent, buf->now, buf->write_len);
805
 
        if (n == 0) {
806
 
            break;
807
 
        }
808
 
        total += n;
809
 
        buf->write_len -= n;
810
 
        if (!buf->write_len) {
811
 
            ring_remove(ring_item);
812
 
            buf->free(buf);
813
 
            continue;
814
 
        }
815
 
        buf->now += n;
816
 
    }
817
 
    // Workaround for lack of proper sif write_possible callback (RHBZ 616772)
818
 
    if (ring_item != NULL) {
819
 
        vdi_port_write_timer_start();
820
 
    }
821
 
    return total;
822
 
}
823
 
 
824
 
static int read_from_vdi_port(void);
825
 
 
826
 
static void vdi_read_buf_release(uint8_t *data, void *opaque)
 
659
/*******************************
 
660
 * Char device state callbacks *
 
661
 * *****************************/
 
662
 
 
663
static void vdi_port_read_buf_release(uint8_t *data, void *opaque)
827
664
{
828
665
    VDIReadBuf *buf = (VDIReadBuf *)opaque;
829
666
 
830
 
    ring_add(&reds->agent_state.read_bufs, &buf->link);
831
 
    /* read_from_vdi_port() may have never completed because the read_bufs
832
 
       ring was empty. So we call it again so it can complete its work if
833
 
       necessary. Note since we can be called from read_from_vdi_port ourselves
834
 
       this can cause recursion, read_from_vdi_port() contains code protecting
835
 
       it against this. */
836
 
    while (read_from_vdi_port());
 
667
    vdi_port_read_buf_unref(buf);
837
668
}
838
669
 
839
 
static void dispatch_vdi_port_data(int port, VDIReadBuf *buf)
 
670
/* returns TRUE if the buffer can be forwarded */
 
671
static int vdi_port_read_buf_process(int port, VDIReadBuf *buf)
840
672
{
841
673
    VDIPortState *state = &reds->agent_state;
842
674
    int res;
847
679
                                            buf->data, buf->len);
848
680
        switch (res) {
849
681
        case AGENT_MSG_FILTER_OK:
850
 
            break;
 
682
            return TRUE;
851
683
        case AGENT_MSG_FILTER_DISCARD:
852
 
            ring_add(&state->read_bufs, &buf->link);
853
 
            return;
 
684
            return FALSE;
854
685
        case AGENT_MSG_FILTER_PROTO_ERROR:
855
 
            ring_add(&state->read_bufs, &buf->link);
856
686
            reds_agent_remove();
857
 
            return;
 
687
            return FALSE;
858
688
        }
859
 
        main_channel_push_agent_data(reds->main_channel, buf->data, buf->len,
860
 
                                     vdi_read_buf_release, buf);
861
 
        break;
862
689
    }
863
690
    case VDP_SERVER_PORT:
864
 
        ring_add(&state->read_bufs, &buf->link);
865
 
        break;
 
691
        return FALSE;
866
692
    default:
867
 
        ring_add(&state->read_bufs, &buf->link);
868
 
        spice_printerr("invalid port");
 
693
        spice_warning("invalid port");
869
694
        reds_agent_remove();
870
 
    }
871
 
}
872
 
 
873
 
/* Note this function MUST always be called in a while loop until it
874
 
   returns 0. This is needed because it can cause new data available events
875
 
   and its recursion protection causes those to get lost. Calling it until
876
 
   it returns 0 ensures that all data has been consumed. */
877
 
static int read_from_vdi_port(void)
878
 
{
879
 
    /* There are 2 scenarios where we can get called recursively:
880
 
       1) spice-vmc vmc_read triggering flush of throttled data, recalling us
881
 
       2) the buf we push to the client may be send immediately without
882
 
          blocking, in which case its free function will recall us
883
 
       This messes up the state machine, so ignore recursive calls.
884
 
       This is why we always must be called in a loop. */
885
 
    static int inside_call = 0;
886
 
    int quit_loop = 0;
 
695
        return FALSE;
 
696
    }
 
697
}
 
698
 
 
699
static VDIReadBuf *vdi_port_read_buf_get(void)
 
700
{
 
701
    VDIPortState *state = &reds->agent_state;
 
702
    RingItem *item;
 
703
    VDIReadBuf *buf;
 
704
 
 
705
    if (!(item = ring_get_head(&state->read_bufs))) {
 
706
        return NULL;
 
707
    }
 
708
 
 
709
    ring_remove(item);
 
710
    buf = SPICE_CONTAINEROF(item, VDIReadBuf, link);
 
711
 
 
712
    buf->refs = 1;
 
713
    return buf;
 
714
}
 
715
 
 
716
static VDIReadBuf* vdi_port_read_buf_ref(VDIReadBuf *buf)
 
717
{
 
718
    buf->refs++;
 
719
    return buf;
 
720
}
 
721
 
 
722
static void vdi_port_read_buf_unref(VDIReadBuf *buf)
 
723
{
 
724
    if (!--buf->refs) {
 
725
        ring_add(&reds->agent_state.read_bufs, &buf->link);
 
726
 
 
727
        /* read_one_msg_from_vdi_port may have never completed because the read_bufs
 
728
        ring was empty. So we call it again so it can complete its work if
 
729
        necessary. Note that since we can be called from spice_char_device_wakeup
 
730
        this can cause recursion, but we have protection for that */
 
731
        if (reds->agent_state.base) {
 
732
            spice_char_device_wakeup(reds->agent_state.base);
 
733
        }
 
734
    }
 
735
}
 
736
 
 
737
/* reads from the device till completes reading a message that is addressed to the client,
 
738
 * or otherwise, when reading from the device fails */
 
739
static SpiceCharDeviceMsgToClient *vdi_port_read_one_msg_from_device(SpiceCharDeviceInstance *sin,
 
740
                                                                     void *opaque)
 
741
{
887
742
    VDIPortState *state = &reds->agent_state;
888
743
    SpiceCharDeviceInterface *sif;
889
744
    VDIReadBuf *dispatch_buf;
890
 
    int total = 0;
891
745
    int n;
892
746
 
893
 
    if (inside_call) {
894
 
        return 0;
895
 
    }
896
 
    inside_call = 1;
897
 
 
898
747
    if (!vdagent) {
899
 
        // discard data only if we are migrating (?) or vdagent has not been
900
 
        // initialized.
901
 
        inside_call = 0;
902
 
        return 0;
 
748
        return NULL;
903
749
    }
904
 
 
 
750
    spice_assert(vdagent == sin);
905
751
    sif = SPICE_CONTAINEROF(vdagent->base.sif, SpiceCharDeviceInterface, base);
906
 
    while (!quit_loop && vdagent) {
 
752
    while (vdagent) {
907
753
        switch (state->read_state) {
908
 
        case VDI_PORT_READ_STATE_READ_HADER:
 
754
        case VDI_PORT_READ_STATE_READ_HEADER:
909
755
            n = sif->read(vdagent, state->recive_pos, state->recive_len);
910
756
            if (!n) {
911
 
                quit_loop = 1;
912
 
                break;
 
757
                return NULL;
913
758
            }
914
 
            total += n;
915
759
            if ((state->recive_len -= n)) {
916
760
                state->recive_pos += n;
917
 
                quit_loop = 1;
918
 
                break;
 
761
                return NULL;
919
762
            }
920
763
            state->message_recive_len = state->vdi_chunk_header.size;
921
764
            state->read_state = VDI_PORT_READ_STATE_GET_BUFF;
922
765
        case VDI_PORT_READ_STATE_GET_BUFF: {
923
 
            RingItem *item;
924
 
 
925
 
            if (!(item = ring_get_head(&state->read_bufs))) {
926
 
                quit_loop = 1;
927
 
                break;
 
766
            if (!(state->current_read_buf = vdi_port_read_buf_get())) {
 
767
                return NULL;
928
768
            }
929
 
 
930
 
            ring_remove(item);
931
 
            state->current_read_buf = (VDIReadBuf *)item;
932
769
            state->recive_pos = state->current_read_buf->data;
933
770
            state->recive_len = MIN(state->message_recive_len,
934
771
                                    sizeof(state->current_read_buf->data));
939
776
        case VDI_PORT_READ_STATE_READ_DATA:
940
777
            n = sif->read(vdagent, state->recive_pos, state->recive_len);
941
778
            if (!n) {
942
 
                quit_loop = 1;
943
 
                break;
 
779
                return NULL;
944
780
            }
945
 
            total += n;
946
781
            if ((state->recive_len -= n)) {
947
782
                state->recive_pos += n;
948
783
                break;
951
786
            state->current_read_buf = NULL;
952
787
            state->recive_pos = NULL;
953
788
            if (state->message_recive_len == 0) {
954
 
                state->read_state = VDI_PORT_READ_STATE_READ_HADER;
 
789
                state->read_state = VDI_PORT_READ_STATE_READ_HEADER;
955
790
                state->recive_pos = (uint8_t *)&state->vdi_chunk_header;
956
791
                state->recive_len = sizeof(state->vdi_chunk_header);
957
792
            } else {
958
793
                state->read_state = VDI_PORT_READ_STATE_GET_BUFF;
959
794
            }
960
 
            dispatch_vdi_port_data(state->vdi_chunk_header.port, dispatch_buf);
961
 
        }
 
795
            if (vdi_port_read_buf_process(state->vdi_chunk_header.port, dispatch_buf)) {
 
796
                return dispatch_buf;
 
797
            } else {
 
798
                vdi_port_read_buf_unref(dispatch_buf);
 
799
            }
 
800
        } /* END switch */
 
801
    } /* END while */
 
802
    return NULL;
 
803
}
 
804
 
 
805
static SpiceCharDeviceMsgToClient *vdi_port_ref_msg_to_client(SpiceCharDeviceMsgToClient *msg,
 
806
                                                       void *opaque)
 
807
{
 
808
    return vdi_port_read_buf_ref(msg);
 
809
}
 
810
 
 
811
static void vdi_port_unref_msg_to_client(SpiceCharDeviceMsgToClient *msg,
 
812
                                  void *opaque)
 
813
{
 
814
    vdi_port_read_buf_unref(msg);
 
815
}
 
816
 
 
817
/* after calling this, we unref the message, and the ref is in the instance side */
 
818
static void vdi_port_send_msg_to_client(SpiceCharDeviceMsgToClient *msg,
 
819
                                        RedClient *client,
 
820
                                        void *opaque)
 
821
{
 
822
    VDIReadBuf *agent_data_buf = msg;
 
823
 
 
824
    main_channel_client_push_agent_data(red_client_get_main(client),
 
825
                                        agent_data_buf->data,
 
826
                                        agent_data_buf->len,
 
827
                                        vdi_port_read_buf_release,
 
828
                                        vdi_port_read_buf_ref(agent_data_buf));
 
829
}
 
830
 
 
831
static void vdi_port_send_tokens_to_client(RedClient *client, uint32_t tokens, void *opaque)
 
832
{
 
833
    main_channel_client_push_agent_tokens(red_client_get_main(client),
 
834
                                          tokens);
 
835
}
 
836
 
 
837
static void vdi_port_on_free_self_token(void *opaque)
 
838
{
 
839
 
 
840
    if (inputs_inited() && reds->pending_mouse_event) {
 
841
        spice_debug("pending mouse event");
 
842
        reds_handle_agent_mouse_event(inputs_get_mouse_state());
962
843
    }
963
 
    inside_call = 0;
964
 
    return total;
965
844
}
966
845
 
967
 
void vdagent_char_device_wakeup(SpiceCharDeviceInstance *sin)
 
846
static void vdi_port_remove_client(RedClient *client, void *opaque)
968
847
{
969
 
    while (read_from_vdi_port());
 
848
    reds_client_disconnect(client);
970
849
}
971
850
 
 
851
/****************************************************************************/
 
852
 
972
853
int reds_has_vdagent(void)
973
854
{
974
855
    return !!vdagent;
976
857
 
977
858
void reds_handle_agent_mouse_event(const VDAgentMouseState *mouse_state)
978
859
{
979
 
    RingItem *ring_item;
980
 
    VDInternalBuf *buf;
 
860
    SpiceCharDeviceWriteBuffer *char_dev_buf;
 
861
    VDInternalBuf *internal_buf;
 
862
    uint32_t total_msg_size;
981
863
 
982
 
    if (!inputs_inited()) {
 
864
    if (!inputs_inited() || !reds->agent_state.base) {
983
865
        return;
984
866
    }
985
 
    if (!(ring_item = ring_get_head(&reds->agent_state.internal_bufs))) {
 
867
 
 
868
    total_msg_size = sizeof(VDIChunkHeader) + sizeof(VDAgentMessage) +
 
869
                     sizeof(VDAgentMouseState);
 
870
    char_dev_buf = spice_char_device_write_buffer_get(reds->agent_state.base,
 
871
                                                      NULL,
 
872
                                                      total_msg_size);
 
873
 
 
874
    if (!char_dev_buf) {
986
875
        reds->pending_mouse_event = TRUE;
987
 
        vdi_port_write_timer_start();
 
876
 
988
877
        return;
989
878
    }
990
879
    reds->pending_mouse_event = FALSE;
991
 
    ring_remove(ring_item);
992
 
    buf = (VDInternalBuf *)ring_item;
993
 
    buf->base.now = (uint8_t *)&buf->base.chunk_header;
994
 
    buf->base.write_len = sizeof(VDIChunkHeader) + sizeof(VDAgentMessage) +
995
 
                          sizeof(VDAgentMouseState);
996
 
    buf->u.mouse_state = *mouse_state;
997
 
    ring_add(&reds->agent_state.write_queue, &buf->base.link);
998
 
    write_to_vdi_port();
999
 
}
1000
 
 
1001
 
static void add_token(void)
1002
 
{
1003
 
    VDIPortState *state = &reds->agent_state;
1004
 
 
1005
 
    if (++state->num_tokens == REDS_TOKENS_TO_SEND) {
1006
 
        reds_push_tokens();
1007
 
    }
 
880
 
 
881
    internal_buf = (VDInternalBuf *)char_dev_buf->buf;
 
882
    internal_buf->chunk_header.port = VDP_SERVER_PORT;
 
883
    internal_buf->chunk_header.size = sizeof(VDAgentMessage) + sizeof(VDAgentMouseState);
 
884
    internal_buf->header.protocol = VD_AGENT_PROTOCOL;
 
885
    internal_buf->header.type = VD_AGENT_MOUSE_STATE;
 
886
    internal_buf->header.opaque = 0;
 
887
    internal_buf->header.size = sizeof(VDAgentMouseState);
 
888
    internal_buf->u.mouse_state = *mouse_state;
 
889
 
 
890
    char_dev_buf->buf_used = total_msg_size;
 
891
    spice_char_device_write_buffer_add(reds->agent_state.base, char_dev_buf);
1008
892
}
1009
893
 
1010
894
int reds_num_of_channels(void)
1012
896
    return reds ? reds->num_of_channels : 0;
1013
897
}
1014
898
 
 
899
 
1015
900
int reds_num_of_clients(void)
1016
901
{
1017
902
    return reds ? reds->num_clients : 0;
1055
940
 
1056
941
    channels_info->num_of_channels = used_channels;
1057
942
    if (used_channels != reds->num_of_channels) {
1058
 
        spice_printerr("sent %d out of %d", used_channels, reds->num_of_channels);
 
943
        spice_warning("sent %d out of %d", used_channels, reds->num_of_channels);
1059
944
    }
1060
945
}
1061
946
 
1062
 
void reds_on_main_agent_start(void)
 
947
void reds_on_main_agent_start(MainChannelClient *mcc, uint32_t num_tokens)
1063
948
{
 
949
    SpiceCharDeviceState *dev_state = reds->agent_state.base;
 
950
    RedChannelClient *rcc;
 
951
 
1064
952
    if (!vdagent) {
1065
953
        return;
1066
954
    }
 
955
    spice_assert(vdagent->st && vdagent->st == dev_state);
 
956
    rcc = main_channel_client_get_base(mcc);
 
957
    reds->agent_state.client_agent_started = TRUE;
 
958
    /*
 
959
     * Note that in older releases, send_tokens were set to ~0 on both client
 
960
     * and server. The server ignored the client given tokens.
 
961
     * Thanks to that, when an old client is connected to a new server,
 
962
     * and vice versa, the sending from the server to the client won't have
 
963
     * flow control, but will have no other problem.
 
964
     */
 
965
    if (!spice_char_device_client_exists(dev_state, rcc->client)) {
 
966
        int client_added;
 
967
 
 
968
        client_added = spice_char_device_client_add(dev_state,
 
969
                                                    rcc->client,
 
970
                                                    TRUE, /* flow control */
 
971
                                                    REDS_VDI_PORT_NUM_RECEIVE_BUFFS,
 
972
                                                    REDS_AGENT_WINDOW_SIZE,
 
973
                                                    num_tokens,
 
974
                                                    red_channel_client_waits_for_migrate_data(rcc));
 
975
 
 
976
        if (!client_added) {
 
977
            spice_warning("failed to add client to agent");
 
978
            reds_client_disconnect(rcc->client);
 
979
            return;
 
980
        }
 
981
    } else {
 
982
        spice_char_device_send_to_client_tokens_set(dev_state,
 
983
                                                    rcc->client,
 
984
                                                    num_tokens);
 
985
    }
1067
986
    reds->agent_state.write_filter.discard_all = FALSE;
1068
987
}
1069
988
 
 
989
void reds_on_main_agent_tokens(MainChannelClient *mcc, uint32_t num_tokens)
 
990
{
 
991
    if (!vdagent) {
 
992
        return;
 
993
    }
 
994
    spice_assert(vdagent->st);
 
995
    spice_char_device_send_to_client_tokens_add(vdagent->st,
 
996
                                                main_channel_client_get_base(mcc)->client,
 
997
                                                num_tokens);
 
998
}
 
999
 
 
1000
uint8_t *reds_get_agent_data_buffer(MainChannelClient *mcc, size_t size)
 
1001
{
 
1002
    VDIPortState *dev_state = &reds->agent_state;
 
1003
    RedClient *client;
 
1004
 
 
1005
    if (!dev_state->client_agent_started) {
 
1006
        /*
 
1007
         * agent got disconnected, and possibly got reconnected, but we still can receive
 
1008
         * msgs that are addressed to the agent's old instance, in case they were
 
1009
         * sent by the client before it received the AGENT_DISCONNECTED msg.
 
1010
         * In such case, we will receive and discard the msgs (reds_reset_vdp takes care
 
1011
         * of setting state->write_filter.result = AGENT_MSG_FILTER_DISCARD).
 
1012
         */
 
1013
        return spice_malloc(size);
 
1014
    }
 
1015
 
 
1016
    spice_assert(dev_state->recv_from_client_buf == NULL);
 
1017
    client = main_channel_client_get_base(mcc)->client;
 
1018
    dev_state->recv_from_client_buf = spice_char_device_write_buffer_get(dev_state->base,
 
1019
                                                                         client,
 
1020
                                                                         size + sizeof(VDIChunkHeader));
 
1021
    dev_state->recv_from_client_buf_pushed = FALSE;
 
1022
    return dev_state->recv_from_client_buf->buf + sizeof(VDIChunkHeader);
 
1023
}
 
1024
 
 
1025
void reds_release_agent_data_buffer(uint8_t *buf)
 
1026
{
 
1027
    VDIPortState *dev_state = &reds->agent_state;
 
1028
 
 
1029
    if (!dev_state->recv_from_client_buf) {
 
1030
        free(buf);
 
1031
        return;
 
1032
    }
 
1033
 
 
1034
    spice_assert(buf == dev_state->recv_from_client_buf->buf + sizeof(VDIChunkHeader));
 
1035
    if (!dev_state->recv_from_client_buf_pushed) {
 
1036
        spice_char_device_write_buffer_release(reds->agent_state.base,
 
1037
                                               dev_state->recv_from_client_buf);
 
1038
    }
 
1039
    dev_state->recv_from_client_buf = NULL;
 
1040
    dev_state->recv_from_client_buf_pushed = FALSE;
 
1041
}
 
1042
 
 
1043
static void reds_client_monitors_config_cleanup(void)
 
1044
{
 
1045
    RedsClientMonitorsConfig *cmc = &reds->client_monitors_config;
 
1046
 
 
1047
    cmc->buffer_size = cmc->buffer_pos = 0;
 
1048
    free(cmc->buffer);
 
1049
    cmc->buffer = NULL;
 
1050
    cmc->mcc = NULL;
 
1051
}
 
1052
 
 
1053
static void reds_on_main_agent_monitors_config(
 
1054
        MainChannelClient *mcc, void *message, size_t size)
 
1055
{
 
1056
    VDAgentMessage *msg_header;
 
1057
    VDAgentMonitorsConfig *monitors_config;
 
1058
    RedsClientMonitorsConfig *cmc = &reds->client_monitors_config;
 
1059
 
 
1060
    cmc->buffer_size += size;
 
1061
    cmc->buffer = realloc(cmc->buffer, cmc->buffer_size);
 
1062
    spice_assert(cmc->buffer);
 
1063
    cmc->mcc = mcc;
 
1064
    memcpy(cmc->buffer + cmc->buffer_pos, message, size);
 
1065
    cmc->buffer_pos += size;
 
1066
    msg_header = (VDAgentMessage *)cmc->buffer;
 
1067
    if (sizeof(VDAgentMessage) > cmc->buffer_size ||
 
1068
            msg_header->size > cmc->buffer_size - sizeof(VDAgentMessage)) {
 
1069
        spice_debug("not enough data yet. %d\n", cmc->buffer_size);
 
1070
        return;
 
1071
    }
 
1072
    monitors_config = (VDAgentMonitorsConfig *)(cmc->buffer + sizeof(*msg_header));
 
1073
    spice_debug("%s: %d\n", __func__, monitors_config->num_of_monitors);
 
1074
    red_dispatcher_client_monitors_config(monitors_config);
 
1075
    reds_client_monitors_config_cleanup();
 
1076
}
 
1077
 
1070
1078
void reds_on_main_agent_data(MainChannelClient *mcc, void *message, size_t size)
1071
1079
{
1072
 
    // TODO - use mcc (and start tracking agent data per channel. probably just move the whole
1073
 
    // tokens accounting to mainchannel.
1074
 
    RingItem *ring_item;
1075
 
    VDAgentExtBuf *buf;
 
1080
    VDIPortState *dev_state = &reds->agent_state;
 
1081
    VDIChunkHeader *header;
1076
1082
    int res;
1077
1083
 
1078
 
    if (!reds->agent_state.num_client_tokens) {
1079
 
        spice_printerr("token violation");
1080
 
        reds_disconnect();
1081
 
        return;
1082
 
    }
1083
 
    --reds->agent_state.num_client_tokens;
1084
 
 
1085
1084
    res = agent_msg_filter_process_data(&reds->agent_state.write_filter,
1086
1085
                                        message, size);
1087
1086
    switch (res) {
1088
1087
    case AGENT_MSG_FILTER_OK:
1089
1088
        break;
1090
1089
    case AGENT_MSG_FILTER_DISCARD:
1091
 
        add_token();
 
1090
        return;
 
1091
    case AGENT_MSG_FILTER_MONITORS_CONFIG:
 
1092
        reds_on_main_agent_monitors_config(mcc, message, size);
1092
1093
        return;
1093
1094
    case AGENT_MSG_FILTER_PROTO_ERROR:
1094
1095
        reds_disconnect();
1095
1096
        return;
1096
1097
    }
1097
1098
 
1098
 
    if (!(ring_item = ring_get_head(&reds->agent_state.external_bufs))) {
1099
 
        spice_printerr("no agent free bufs");
1100
 
        reds_disconnect();
1101
 
        return;
1102
 
    }
1103
 
    ring_remove(ring_item);
1104
 
    buf = (VDAgentExtBuf *)ring_item;
1105
 
    buf->base.now = (uint8_t *)&buf->base.chunk_header.port;
1106
 
    buf->base.write_len = size + sizeof(VDIChunkHeader);
1107
 
    buf->base.chunk_header.size = size;
1108
 
    memcpy(buf->buf, message, size);
1109
 
    ring_add(&reds->agent_state.write_queue, ring_item);
1110
 
    write_to_vdi_port();
 
1099
    spice_assert(reds->agent_state.recv_from_client_buf);
 
1100
    spice_assert(message == reds->agent_state.recv_from_client_buf->buf + sizeof(VDIChunkHeader));
 
1101
    // TODO - start tracking agent data per channel
 
1102
    header =  (VDIChunkHeader *)dev_state->recv_from_client_buf->buf;
 
1103
    header->port = VDP_CLIENT_PORT;
 
1104
    header->size = size;
 
1105
    dev_state->recv_from_client_buf->buf_used = sizeof(VDIChunkHeader) + size;
 
1106
 
 
1107
    dev_state->recv_from_client_buf_pushed = TRUE;
 
1108
    spice_char_device_write_buffer_add(reds->agent_state.base, dev_state->recv_from_client_buf);
1111
1109
}
1112
1110
 
1113
 
void reds_on_main_migrate_connected(void)
 
1111
void reds_on_main_migrate_connected(int seamless)
1114
1112
{
 
1113
    reds->src_do_seamless_migrate = seamless;
1115
1114
    if (reds->mig_wait_connect) {
1116
1115
        reds_mig_cleanup();
1117
1116
    }
1124
1123
        if (reds->is_client_mouse_allowed) {
1125
1124
            reds_set_mouse_mode(SPICE_MOUSE_MODE_CLIENT);
1126
1125
        } else {
1127
 
            spice_printerr("client mouse is disabled");
 
1126
            spice_info("client mouse is disabled");
1128
1127
        }
1129
1128
        break;
1130
1129
    case SPICE_MOUSE_MODE_SERVER:
1131
1130
        reds_set_mouse_mode(SPICE_MOUSE_MODE_SERVER);
1132
1131
        break;
1133
1132
    default:
1134
 
        spice_printerr("unsupported mouse mode");
1135
 
    }
1136
 
}
1137
 
 
1138
 
#define MAIN_CHANNEL_MIG_DATA_VERSION 1
1139
 
 
1140
 
typedef struct WriteQueueInfo {
1141
 
    uint32_t port;
1142
 
    uint32_t len;
1143
 
} WriteQueueInfo;
1144
 
 
1145
 
void reds_marshall_migrate_data_item(SpiceMarshaller *m, MainMigrateData *data)
1146
 
{
1147
 
    VDIPortState *state = &reds->agent_state;
1148
 
    int buf_index;
1149
 
    RingItem *now;
1150
 
 
1151
 
    data->version = MAIN_CHANNEL_MIG_DATA_VERSION;
1152
 
 
1153
 
    data->agent_connected = !!vdagent;
1154
 
    data->client_agent_started = !state->write_filter.discard_all;
1155
 
    data->num_client_tokens = state->num_client_tokens;
1156
 
    data->send_tokens = ~0;
1157
 
 
1158
 
    data->read_state = state->read_state;
1159
 
    data->vdi_chunk_header = state->vdi_chunk_header;
1160
 
    data->recive_len = state->recive_len;
1161
 
    data->message_recive_len = state->message_recive_len;
1162
 
 
1163
 
    if (state->current_read_buf) {
1164
 
        data->read_buf_len = state->current_read_buf->len;
1165
 
 
1166
 
        if (data->read_buf_len - data->recive_len) {
1167
 
            spice_marshaller_add_ref(m,
1168
 
                                     state->current_read_buf->data,
1169
 
                                     data->read_buf_len - data->recive_len);
1170
 
        }
1171
 
    } else {
1172
 
        data->read_buf_len = 0;
1173
 
    }
1174
 
 
1175
 
    now = &state->write_queue;
1176
 
    data->write_queue_size = 0;
1177
 
    while ((now = ring_prev(&state->write_queue, now))) {
1178
 
        data->write_queue_size++;
1179
 
    }
1180
 
    if (data->write_queue_size) {
1181
 
        WriteQueueInfo *queue_info;
1182
 
 
1183
 
        queue_info = (WriteQueueInfo *)
1184
 
            spice_marshaller_reserve_space(m,
1185
 
                                           data->write_queue_size * sizeof(queue_info[0]));
1186
 
 
1187
 
        buf_index = 0;
1188
 
        now = &state->write_queue;
1189
 
        while ((now = ring_prev(&state->write_queue, now))) {
1190
 
            VDIPortBuf *buf = (VDIPortBuf *)now;
1191
 
            queue_info[buf_index].port = buf->chunk_header.port;
1192
 
            queue_info[buf_index++].len = buf->write_len;
1193
 
            spice_marshaller_add_ref(m, buf->now, buf->write_len);
1194
 
        }
1195
 
    }
1196
 
}
1197
 
 
1198
 
 
1199
 
static int reds_main_channel_restore_vdi_read_state(MainMigrateData *data, uint8_t **in_pos,
1200
 
                                               uint8_t *end)
1201
 
{
1202
 
    VDIPortState *state = &reds->agent_state;
1203
 
    uint8_t *pos = *in_pos;
1204
 
    RingItem *ring_item;
1205
 
 
1206
 
    state->read_state = data->read_state;
1207
 
    state->vdi_chunk_header = data->vdi_chunk_header;
1208
 
    state->recive_len = data->recive_len;
1209
 
    state->message_recive_len = data->message_recive_len;
1210
 
 
1211
 
    switch (state->read_state) {
1212
 
    case VDI_PORT_READ_STATE_READ_HADER:
1213
 
        if (data->read_buf_len) {
1214
 
            spice_printerr("unexpected receive buf");
1215
 
            reds_disconnect();
1216
 
            return FALSE;
1217
 
        }
1218
 
        state->recive_pos = (uint8_t *)(&state->vdi_chunk_header + 1) - state->recive_len;
1219
 
        break;
1220
 
    case VDI_PORT_READ_STATE_GET_BUFF:
1221
 
        if (state->message_recive_len > state->vdi_chunk_header.size) {
1222
 
            spice_printerr("invalid message receive len");
1223
 
            reds_disconnect();
1224
 
            return FALSE;
1225
 
        }
1226
 
 
1227
 
        if (data->read_buf_len) {
1228
 
            spice_printerr("unexpected receive buf");
1229
 
            reds_disconnect();
1230
 
            return FALSE;
1231
 
        }
1232
 
        break;
1233
 
    case VDI_PORT_READ_STATE_READ_DATA: {
1234
 
        VDIReadBuf *buff;
1235
 
        uint32_t n;
1236
 
 
1237
 
        if (!data->read_buf_len) {
1238
 
            spice_printerr("read state and read_buf_len == 0");
1239
 
            reds_disconnect();
1240
 
            return FALSE;
1241
 
        }
1242
 
 
1243
 
        if (state->message_recive_len > state->vdi_chunk_header.size) {
1244
 
            spice_printerr("invalid message receive len");
1245
 
            reds_disconnect();
1246
 
            return FALSE;
1247
 
        }
1248
 
 
1249
 
 
1250
 
        if (!(ring_item = ring_get_head(&state->read_bufs))) {
1251
 
            spice_printerr("get read buf failed");
1252
 
            reds_disconnect();
1253
 
            return FALSE;
1254
 
        }
1255
 
 
1256
 
        ring_remove(ring_item);
1257
 
        buff = state->current_read_buf = (VDIReadBuf *)ring_item;
1258
 
        buff->len = data->read_buf_len;
1259
 
        n = buff->len - state->recive_len;
1260
 
        if (buff->len > SPICE_AGENT_MAX_DATA_SIZE || n > SPICE_AGENT_MAX_DATA_SIZE) {
1261
 
            spice_printerr("bad read position");
1262
 
            reds_disconnect();
1263
 
            return FALSE;
1264
 
        }
1265
 
        memcpy(buff->data, pos, n);
1266
 
        pos += n;
1267
 
        state->recive_pos = buff->data + n;
1268
 
        break;
1269
 
    }
1270
 
    default:
1271
 
        spice_printerr("invalid read state");
1272
 
        reds_disconnect();
1273
 
        return FALSE;
1274
 
    }
1275
 
    *in_pos = pos;
1276
 
    return TRUE;
1277
 
}
1278
 
 
1279
 
static void free_tmp_internal_buf(VDIPortBuf *buf)
1280
 
{
1281
 
    free(buf);
1282
 
}
1283
 
 
1284
 
static int reds_main_channel_restore_vdi_wqueue(MainMigrateData *data, uint8_t *pos, uint8_t *end)
1285
 
{
1286
 
    VDIPortState *state = &reds->agent_state;
1287
 
    WriteQueueInfo *inf;
1288
 
    WriteQueueInfo *inf_end;
1289
 
    RingItem *ring_item;
1290
 
 
1291
 
    if (!data->write_queue_size) {
1292
 
        return TRUE;
1293
 
    }
1294
 
 
1295
 
    inf = (WriteQueueInfo *)pos;
1296
 
    inf_end = inf + data->write_queue_size;
1297
 
    pos = (uint8_t *)inf_end;
1298
 
    if (pos > end) {
1299
 
        spice_printerr("access violation");
1300
 
        reds_disconnect();
1301
 
        return FALSE;
1302
 
    }
1303
 
 
1304
 
    for (; inf < inf_end; inf++) {
1305
 
        if (pos + inf->len > end) {
1306
 
            spice_printerr("access violation");
1307
 
            reds_disconnect();
1308
 
            return FALSE;
1309
 
        }
1310
 
        if (inf->port == VDP_SERVER_PORT) {
1311
 
            VDInternalBuf *buf;
1312
 
 
1313
 
            if (inf->len > sizeof(*buf) - SPICE_OFFSETOF(VDInternalBuf, header)) {
1314
 
                spice_printerr("bad buffer len");
1315
 
                reds_disconnect();
1316
 
                return FALSE;
1317
 
            }
1318
 
            buf = spice_new(VDInternalBuf, 1);
1319
 
            ring_item_init(&buf->base.link);
1320
 
            buf->base.free = free_tmp_internal_buf;
1321
 
            buf->base.now = (uint8_t *)&buf->base.chunk_header;
1322
 
            buf->base.write_len = inf->len;
1323
 
            memcpy(buf->base.now, pos, buf->base.write_len);
1324
 
            ring_add(&reds->agent_state.write_queue, &buf->base.link);
1325
 
        } else if (inf->port == VDP_CLIENT_PORT) {
1326
 
            VDAgentExtBuf *buf;
1327
 
 
1328
 
            state->num_tokens--;
1329
 
            if (inf->len > sizeof(*buf) - SPICE_OFFSETOF(VDAgentExtBuf, buf)) {
1330
 
                spice_printerr("bad buffer len");
1331
 
                reds_disconnect();
1332
 
                return FALSE;
1333
 
            }
1334
 
            if (!(ring_item = ring_get_head(&reds->agent_state.external_bufs))) {
1335
 
                spice_printerr("no external buff");
1336
 
                reds_disconnect();
1337
 
                return FALSE;
1338
 
            }
1339
 
            ring_remove(ring_item);
1340
 
            buf = (VDAgentExtBuf *)ring_item;
1341
 
            memcpy(&buf->buf, pos, inf->len);
1342
 
            buf->base.now = (uint8_t *)buf->buf;
1343
 
            buf->base.write_len = inf->len;
1344
 
            ring_add(&reds->agent_state.write_queue, &buf->base.link);
1345
 
        } else {
1346
 
            spice_printerr("invalid data");
1347
 
            reds_disconnect();
1348
 
            return FALSE;
1349
 
        }
1350
 
        pos += inf->len;
1351
 
    }
1352
 
    return TRUE;
1353
 
}
1354
 
 
1355
 
void reds_on_main_receive_migrate_data(MainMigrateData *data, uint8_t *end)
1356
 
{
1357
 
    VDIPortState *state = &reds->agent_state;
1358
 
    uint8_t *pos;
1359
 
 
1360
 
    if (data->version != MAIN_CHANNEL_MIG_DATA_VERSION) {
1361
 
        spice_printerr("version mismatch");
1362
 
        reds_disconnect();
1363
 
        return;
1364
 
    }
1365
 
 
1366
 
    state->num_client_tokens = data->num_client_tokens;
1367
 
    spice_assert(state->num_client_tokens + data->write_queue_size <= REDS_AGENT_WINDOW_SIZE +
1368
 
                                                                REDS_NUM_INTERNAL_AGENT_MESSAGES);
1369
 
    state->num_tokens = REDS_AGENT_WINDOW_SIZE - state->num_client_tokens;
1370
 
 
1371
 
    if (!data->agent_connected) {
 
1133
        spice_warning("unsupported mouse mode");
 
1134
    }
 
1135
}
 
1136
 
 
1137
/*
 
1138
 * Push partial agent data, even if not all the chunk was consumend,
 
1139
 * in order to avoid the roundtrip (src-server->client->dest-server)
 
1140
 */
 
1141
void reds_on_main_channel_migrate(MainChannelClient *mcc)
 
1142
{
 
1143
    VDIPortState *agent_state = &reds->agent_state;
 
1144
    uint32_t read_data_len;
 
1145
 
 
1146
    spice_assert(reds->num_clients == 1);
 
1147
 
 
1148
    if (agent_state->read_state != VDI_PORT_READ_STATE_READ_DATA) {
 
1149
        return;
 
1150
    }
 
1151
    spice_assert(agent_state->current_read_buf->data &&
 
1152
                 agent_state->recive_pos > agent_state->current_read_buf->data);
 
1153
    read_data_len = agent_state->recive_pos - agent_state->current_read_buf->data;
 
1154
 
 
1155
    if (agent_state->read_filter.msg_data_to_read ||
 
1156
        read_data_len > sizeof(VDAgentMessage)) { /* msg header has been read */
 
1157
        VDIReadBuf *read_buf = agent_state->current_read_buf;
 
1158
 
 
1159
        spice_debug("push partial read %u (msg first chunk? %d)", read_data_len,
 
1160
                    !agent_state->read_filter.msg_data_to_read);
 
1161
 
 
1162
        read_buf->len = read_data_len;
 
1163
        if (vdi_port_read_buf_process(agent_state->vdi_chunk_header.port, read_buf)) {
 
1164
            main_channel_client_push_agent_data(mcc,
 
1165
                                                read_buf->data,
 
1166
                                                read_buf->len,
 
1167
                                                vdi_port_read_buf_release,
 
1168
                                                read_buf);
 
1169
        } else {
 
1170
            vdi_port_read_buf_unref(read_buf);
 
1171
        }
 
1172
 
 
1173
        spice_assert(agent_state->recive_len);
 
1174
        agent_state->message_recive_len += agent_state->recive_len;
 
1175
        agent_state->read_state = VDI_PORT_READ_STATE_GET_BUFF;
 
1176
        agent_state->current_read_buf = NULL;
 
1177
        agent_state->recive_pos = NULL;
 
1178
    }
 
1179
}
 
1180
 
 
1181
void reds_marshall_migrate_data(SpiceMarshaller *m)
 
1182
{
 
1183
    SpiceMigrateDataMain mig_data;
 
1184
    VDIPortState *agent_state = &reds->agent_state;
 
1185
    SpiceMarshaller *m2;
 
1186
 
 
1187
    memset(&mig_data, 0, sizeof(mig_data));
 
1188
    spice_marshaller_add_uint32(m, SPICE_MIGRATE_DATA_MAIN_MAGIC);
 
1189
    spice_marshaller_add_uint32(m, SPICE_MIGRATE_DATA_MAIN_VERSION);
 
1190
 
 
1191
    if (!vdagent) {
 
1192
        uint8_t *null_agent_mig_data;
 
1193
 
 
1194
        spice_assert(!agent_state->base); /* MSG_AGENT_CONNECTED_TOKENS is supported by the client
 
1195
                                             (see spice_server_migrate_connect), so SpiceCharDeviceState
 
1196
                                             is destroyed when the agent is disconnected and
 
1197
                                             there is no need to track the client tokens
 
1198
                                             (see reds_reset_vdp) */
 
1199
        spice_char_device_state_migrate_data_marshall_empty(m);
 
1200
        null_agent_mig_data = spice_marshaller_reserve_space(m,
 
1201
                                                             sizeof(SpiceMigrateDataMain) -
 
1202
                                                             sizeof(SpiceMigrateDataCharDevice));
 
1203
        memset(null_agent_mig_data,
 
1204
               0,
 
1205
               sizeof(SpiceMigrateDataMain) - sizeof(SpiceMigrateDataCharDevice));
 
1206
        return;
 
1207
    }
 
1208
 
 
1209
    spice_char_device_state_migrate_data_marshall(reds->agent_state.base, m);
 
1210
    spice_marshaller_add_uint8(m, reds->agent_state.client_agent_started);
 
1211
 
 
1212
    mig_data.agent2client.chunk_header = agent_state->vdi_chunk_header;
 
1213
 
 
1214
    /* agent to client partial msg */
 
1215
    if (agent_state->read_state == VDI_PORT_READ_STATE_READ_HEADER) {
 
1216
        mig_data.agent2client.chunk_header_size = agent_state->recive_pos -
 
1217
            (uint8_t *)&agent_state->vdi_chunk_header;
 
1218
 
 
1219
        mig_data.agent2client.msg_header_done = FALSE;
 
1220
        mig_data.agent2client.msg_header_partial_len = 0;
 
1221
        spice_assert(!agent_state->read_filter.msg_data_to_read);
 
1222
    } else {
 
1223
        mig_data.agent2client.chunk_header_size = sizeof(VDIChunkHeader);
 
1224
        mig_data.agent2client.chunk_header.size = agent_state->message_recive_len;
 
1225
        if (agent_state->read_state == VDI_PORT_READ_STATE_READ_DATA) {
 
1226
            /* in the middle of reading the message header (see reds_on_main_channel_migrate) */
 
1227
            mig_data.agent2client.msg_header_done = FALSE;
 
1228
            mig_data.agent2client.msg_header_partial_len =
 
1229
                agent_state->recive_pos - agent_state->current_read_buf->data;
 
1230
            spice_assert(mig_data.agent2client.msg_header_partial_len < sizeof(VDAgentMessage));
 
1231
            spice_assert(!agent_state->read_filter.msg_data_to_read);
 
1232
        } else {
 
1233
            mig_data.agent2client.msg_header_done =  TRUE;
 
1234
            mig_data.agent2client.msg_remaining = agent_state->read_filter.msg_data_to_read;
 
1235
            mig_data.agent2client.msg_filter_result = agent_state->read_filter.result;
 
1236
        }
 
1237
    }
 
1238
    spice_marshaller_add_uint32(m, mig_data.agent2client.chunk_header_size);
 
1239
    spice_marshaller_add(m,
 
1240
                         (uint8_t *)&mig_data.agent2client.chunk_header,
 
1241
                         sizeof(VDIChunkHeader));
 
1242
    spice_marshaller_add_uint8(m, mig_data.agent2client.msg_header_done);
 
1243
    spice_marshaller_add_uint32(m, mig_data.agent2client.msg_header_partial_len);
 
1244
    m2 = spice_marshaller_get_ptr_submarshaller(m, 0);
 
1245
    spice_marshaller_add(m2, agent_state->current_read_buf->data,
 
1246
                         mig_data.agent2client.msg_header_partial_len);
 
1247
    spice_marshaller_add_uint32(m, mig_data.agent2client.msg_remaining);
 
1248
    spice_marshaller_add_uint8(m, mig_data.agent2client.msg_filter_result);
 
1249
 
 
1250
    mig_data.client2agent.msg_remaining = agent_state->write_filter.msg_data_to_read;
 
1251
    mig_data.client2agent.msg_filter_result = agent_state->write_filter.result;
 
1252
    spice_marshaller_add_uint32(m, mig_data.client2agent.msg_remaining);
 
1253
    spice_marshaller_add_uint8(m, mig_data.client2agent.msg_filter_result);
 
1254
    spice_debug("from agent filter: discard all %d, wait_msg %u, msg_filter_result %d",
 
1255
                agent_state->read_filter.discard_all,
 
1256
                agent_state->read_filter.msg_data_to_read,
 
1257
                 agent_state->read_filter.result);
 
1258
    spice_debug("to agent filter: discard all %d, wait_msg %u, msg_filter_result %d",
 
1259
                agent_state->write_filter.discard_all,
 
1260
                agent_state->write_filter.msg_data_to_read,
 
1261
                 agent_state->write_filter.result);
 
1262
}
 
1263
 
 
1264
static int reds_agent_state_restore(SpiceMigrateDataMain *mig_data)
 
1265
{
 
1266
    VDIPortState *agent_state = &reds->agent_state;
 
1267
    uint32_t chunk_header_remaining;
 
1268
 
 
1269
    agent_state->vdi_chunk_header = mig_data->agent2client.chunk_header;
 
1270
    spice_assert(mig_data->agent2client.chunk_header_size <= sizeof(VDIChunkHeader));
 
1271
    chunk_header_remaining = sizeof(VDIChunkHeader) - mig_data->agent2client.chunk_header_size;
 
1272
    if (chunk_header_remaining) {
 
1273
        agent_state->read_state = VDI_PORT_READ_STATE_READ_HEADER;
 
1274
        agent_state->recive_pos = (uint8_t *)&agent_state->vdi_chunk_header +
 
1275
            mig_data->agent2client.chunk_header_size;
 
1276
        agent_state->recive_len = chunk_header_remaining;
 
1277
    } else {
 
1278
        agent_state->message_recive_len = agent_state->vdi_chunk_header.size;
 
1279
    }
 
1280
 
 
1281
    if (!mig_data->agent2client.msg_header_done) {
 
1282
        uint8_t *partial_msg_header;
 
1283
 
 
1284
        if (!chunk_header_remaining) {
 
1285
            uint32_t cur_buf_size;
 
1286
 
 
1287
            agent_state->read_state = VDI_PORT_READ_STATE_READ_DATA;
 
1288
            agent_state->current_read_buf = vdi_port_read_buf_get();
 
1289
            spice_assert(agent_state->current_read_buf);
 
1290
            partial_msg_header = (uint8_t *)mig_data + mig_data->agent2client.msg_header_ptr -
 
1291
                sizeof(SpiceMiniDataHeader);
 
1292
            memcpy(agent_state->current_read_buf->data,
 
1293
                   partial_msg_header,
 
1294
                   mig_data->agent2client.msg_header_partial_len);
 
1295
            agent_state->recive_pos = agent_state->current_read_buf->data +
 
1296
                                      mig_data->agent2client.msg_header_partial_len;
 
1297
            cur_buf_size = sizeof(agent_state->current_read_buf->data) -
 
1298
                           mig_data->agent2client.msg_header_partial_len;
 
1299
            agent_state->recive_len = MIN(agent_state->message_recive_len, cur_buf_size);
 
1300
            agent_state->current_read_buf->len = agent_state->recive_len +
 
1301
                                                 mig_data->agent2client.msg_header_partial_len;
 
1302
            agent_state->message_recive_len -= agent_state->recive_len;
 
1303
        } else {
 
1304
            spice_assert(mig_data->agent2client.msg_header_partial_len == 0);
 
1305
        }
 
1306
    } else {
 
1307
            agent_state->read_state = VDI_PORT_READ_STATE_GET_BUFF;
 
1308
            agent_state->current_read_buf = NULL;
 
1309
            agent_state->recive_pos = NULL;
 
1310
            agent_state->read_filter.msg_data_to_read = mig_data->agent2client.msg_remaining;
 
1311
            agent_state->read_filter.result = mig_data->agent2client.msg_filter_result;
 
1312
    }
 
1313
 
 
1314
    agent_state->read_filter.discard_all = FALSE;
 
1315
    agent_state->write_filter.discard_all = !mig_data->client_agent_started;
 
1316
    agent_state->client_agent_started = mig_data->client_agent_started;
 
1317
 
 
1318
    agent_state->write_filter.msg_data_to_read = mig_data->client2agent.msg_remaining;
 
1319
    agent_state->write_filter.result = mig_data->client2agent.msg_filter_result;
 
1320
 
 
1321
    spice_debug("to agent filter: discard all %d, wait_msg %u, msg_filter_result %d",
 
1322
                agent_state->write_filter.discard_all,
 
1323
                agent_state->write_filter.msg_data_to_read,
 
1324
                 agent_state->write_filter.result);
 
1325
    spice_debug("from agent filter: discard all %d, wait_msg %u, msg_filter_result %d",
 
1326
                agent_state->read_filter.discard_all,
 
1327
                agent_state->read_filter.msg_data_to_read,
 
1328
                 agent_state->read_filter.result);
 
1329
    return spice_char_device_state_restore(agent_state->base, &mig_data->agent_base);
 
1330
}
 
1331
 
 
1332
/*
 
1333
 * The agent device is not attached to the dest before migration is completed. It is
 
1334
 * attached only after the vm is started. It might be attached before or after
 
1335
 * the migration data has reached the server.
 
1336
 */
 
1337
int reds_handle_migrate_data(MainChannelClient *mcc, SpiceMigrateDataMain *mig_data, uint32_t size)
 
1338
{
 
1339
    VDIPortState *agent_state = &reds->agent_state;
 
1340
 
 
1341
    if (mig_data->agent_base.connected) {
 
1342
        if (agent_state->base) { // agent was attached before migration data has arrived
 
1343
            if (!vdagent) {
 
1344
                spice_assert(agent_state->plug_generation > 0);
 
1345
                main_channel_push_agent_disconnected(reds->main_channel);
 
1346
                spice_debug("agent is no longer connected");
 
1347
            } else {
 
1348
                if (agent_state->plug_generation > 1) {
 
1349
                    /* spice_char_device_state_reset takes care of not making the device wait for migration data */
 
1350
                    spice_debug("agent has been detached and reattached before receiving migration data");
 
1351
                    main_channel_push_agent_disconnected(reds->main_channel);
 
1352
                    main_channel_push_agent_connected(reds->main_channel);
 
1353
                } else {
 
1354
                    return reds_agent_state_restore(mig_data);
 
1355
                }
 
1356
            }
 
1357
        } else {
 
1358
            /* restore agent starte when the agent gets attached */
 
1359
            spice_assert(agent_state->plug_generation == 0);
 
1360
            agent_state->mig_data = spice_memdup(mig_data, size);
 
1361
        }
 
1362
    } else {
1372
1363
        if (vdagent) {
 
1364
            /* spice_char_device_client_remove disables waiting for migration data */
 
1365
            spice_char_device_client_remove(agent_state->base,
 
1366
                                            main_channel_client_get_base(mcc)->client);
1373
1367
            main_channel_push_agent_connected(reds->main_channel);
1374
1368
        }
1375
 
        return;
1376
 
    }
1377
 
 
1378
 
    if (!vdagent) {
1379
 
        main_channel_push_agent_disconnected(reds->main_channel);
1380
 
        return;
1381
 
    }
1382
 
 
1383
 
    if (state->plug_generation > 1) {
1384
 
        main_channel_push_agent_disconnected(reds->main_channel);
1385
 
        main_channel_push_agent_connected(reds->main_channel);
1386
 
        return;
1387
 
    }
1388
 
 
1389
 
    state->write_filter.discard_all = !data->client_agent_started;
1390
 
 
1391
 
    pos = (uint8_t *)(data + 1);
1392
 
 
1393
 
    if (!reds_main_channel_restore_vdi_read_state(data, &pos, end)) {
1394
 
        return;
1395
 
    }
1396
 
 
1397
 
    reds_main_channel_restore_vdi_wqueue(data, pos, end);
1398
 
    spice_assert(state->num_client_tokens + state->num_tokens == REDS_AGENT_WINDOW_SIZE);
1399
 
 
1400
 
    while (write_to_vdi_port() || read_from_vdi_port());
 
1369
    }
 
1370
 
 
1371
    return TRUE;
1401
1372
}
1402
1373
 
1403
1374
static int sync_write(RedsStream *stream, const void *in_buf, size_t n)
1461
1432
    ack.caps_offset = sizeof(SpiceLinkReply);
1462
1433
 
1463
1434
    if (!(link->tiTicketing.rsa = RSA_new())) {
1464
 
        spice_printerr("RSA nes failed");
 
1435
        spice_warning("RSA nes failed");
1465
1436
        return FALSE;
1466
1437
    }
1467
1438
 
1468
1439
    if (!(bio = BIO_new(BIO_s_mem()))) {
1469
 
        spice_printerr("BIO new failed");
 
1440
        spice_warning("BIO new failed");
1470
1441
        return FALSE;
1471
1442
    }
1472
1443
 
1509
1480
                                                                         sizeof(reply));
1510
1481
}
1511
1482
 
1512
 
static void reds_show_new_channel(RedLinkInfo *link, int connection_id)
 
1483
static void reds_info_new_channel(RedLinkInfo *link, int connection_id)
1513
1484
{
1514
 
    spice_printerr("channel %d:%d, connected successfully, over %s link",
 
1485
    spice_info("channel %d:%d, connected successfully, over %s link",
1515
1486
               link->link_mess->channel_type,
1516
1487
               link->link_mess->channel_id,
1517
1488
               link->stream->ssl == NULL ? "Non Secure" : "Secure");
1532
1503
 
1533
1504
int reds_expects_link_id(uint32_t connection_id)
1534
1505
{
1535
 
    spice_printerr("TODO: keep a list of connection_id's from migration, compare to them");
 
1506
    spice_info("TODO: keep a list of connection_id's from migration, compare to them");
1536
1507
    return 1;
1537
1508
}
1538
1509
 
1541
1512
    RedsMigTargetClient *mig_client;
1542
1513
 
1543
1514
    spice_assert(reds);
1544
 
    spice_printerr("");
 
1515
    spice_info(NULL);
1545
1516
    mig_client = spice_malloc0(sizeof(RedsMigTargetClient));
1546
1517
    mig_client->client = client;
1547
1518
    ring_init(&mig_client->pending_links);
1605
1576
    }
1606
1577
}
1607
1578
 
 
1579
static int reds_find_client(RedClient *client)
 
1580
{
 
1581
    RingItem *item;
 
1582
 
 
1583
    RING_FOREACH(item, &reds->clients) {
 
1584
        RedClient *list_client;
 
1585
 
 
1586
        list_client = SPICE_CONTAINEROF(item, RedClient, link);
 
1587
        if (list_client == client) {
 
1588
            return TRUE;
 
1589
        }
 
1590
    }
 
1591
    return FALSE;
 
1592
}
 
1593
 
 
1594
/* should be used only when there is one client */
 
1595
static RedClient *reds_get_client(void)
 
1596
{
 
1597
    spice_assert(reds->num_clients <= 1);
 
1598
 
 
1599
    if (reds->num_clients == 0) {
 
1600
        return NULL;
 
1601
    }
 
1602
 
 
1603
    return SPICE_CONTAINEROF(ring_get_head(&reds->clients), RedClient, link);
 
1604
}
 
1605
 
1608
1606
// TODO: now that main is a separate channel this should
1609
1607
// actually be joined with reds_handle_other_links, become reds_handle_link
1610
1608
static void reds_handle_main_link(RedLinkInfo *link)
1617
1615
    MainChannelClient *mcc;
1618
1616
    int mig_target = FALSE;
1619
1617
 
1620
 
    spice_printerr("");
 
1618
    spice_info(NULL);
1621
1619
    spice_assert(reds->main_channel);
1622
1620
 
1623
1621
    link_mess = link->link_mess;
1628
1626
    if (link_mess->connection_id == 0) {
1629
1627
        reds_send_link_result(link, SPICE_LINK_ERR_OK);
1630
1628
        while((connection_id = rand()) == 0);
1631
 
        reds->agent_state.num_tokens = 0;
1632
1629
        mig_target = FALSE;
1633
1630
    } else {
1634
1631
        // TODO: make sure link_mess->connection_id is the same
1642
1639
    reds->mig_wait_connect = FALSE;
1643
1640
    reds->mig_wait_disconnect = FALSE;
1644
1641
 
1645
 
    reds_show_new_channel(link, connection_id);
 
1642
    reds_info_new_channel(link, connection_id);
1646
1643
    stream = link->stream;
1647
1644
    reds_stream_remove_watch(stream);
1648
1645
    link->stream = NULL;
1657
1654
                            link_mess->num_common_caps,
1658
1655
                            link_mess->num_common_caps ? caps : NULL, link_mess->num_channel_caps,
1659
1656
                            link_mess->num_channel_caps ? caps + link_mess->num_common_caps : NULL);
1660
 
    spice_printerr("NEW Client %p mcc %p connect-id %d", client, mcc, connection_id);
 
1657
    spice_info("NEW Client %p mcc %p connect-id %d", client, mcc, connection_id);
1661
1658
    free(link_mess);
1662
1659
    red_client_set_main(client, mcc);
1663
1660
 
1664
1661
    if (vdagent) {
 
1662
        if (mig_target) {
 
1663
            spice_warning("unexpected: vdagent attached to destination during migration");
 
1664
        }
1665
1665
        reds->agent_state.read_filter.discard_all = FALSE;
1666
1666
        reds->agent_state.plug_generation++;
1667
1667
    }
1668
1668
 
1669
 
    reds->agent_state.num_client_tokens = REDS_AGENT_WINDOW_SIZE;
1670
 
 
1671
1669
    if (!mig_target) {
1672
1670
        main_channel_push_init(mcc, red_dispatcher_count(),
1673
1671
            reds->mouse_mode, reds->is_client_mouse_allowed,
1679
1677
            main_channel_push_uuid(mcc, spice_uuid);
1680
1678
 
1681
1679
        main_channel_client_start_net_test(mcc);
1682
 
        /* Now that we have a client, forward any pending agent data */
1683
 
        while (read_from_vdi_port());
1684
1680
    } else {
1685
1681
        reds_mig_target_client_add(client);
1686
1682
    }
1745
1741
                                caps + link_msg->num_common_caps : NULL);
1746
1742
}
1747
1743
 
1748
 
void reds_on_client_migrate_complete(RedClient *client)
 
1744
/*
 
1745
 * migration target side:
 
1746
 * In semi-seamless migration, we activate the channels only
 
1747
 * after migration is completed.
 
1748
 * In seamless migration, in order to keep the continuousness, and
 
1749
 * not lose any data, we activate the target channels before
 
1750
 * migration completes, as soon as we receive SPICE_MSGC_MAIN_MIGRATE_DST_DO_SEAMLESS
 
1751
 */
 
1752
static int reds_link_mig_target_channels(RedClient *client)
1749
1753
{
1750
1754
    RedsMigTargetClient *mig_client;
1751
 
    MainChannelClient *mcc;
1752
1755
    RingItem *item;
1753
1756
 
1754
 
    spice_printerr("%p", client);
1755
 
    mcc = red_client_get_main(client);
 
1757
    spice_info("%p", client);
1756
1758
    mig_client = reds_mig_target_client_find(client);
1757
1759
    if (!mig_client) {
1758
 
        spice_printerr("Error: mig target client was not found");
1759
 
        return;
 
1760
        spice_info("Error: mig target client was not found");
 
1761
        return FALSE;
1760
1762
    }
1761
1763
 
1762
 
    // TODO: not doing net test. consider doing it on client_migrate_info
1763
 
    main_channel_push_init(mcc, red_dispatcher_count(),
1764
 
                           reds->mouse_mode, reds->is_client_mouse_allowed,
1765
 
                           reds_get_mm_time() - MM_TIME_DELTA,
1766
 
                           red_dispatcher_qxl_ram_size());
1767
 
 
 
1764
    /* Each channel should check if we are during migration, and
 
1765
     * act accordingly. */
1768
1766
    RING_FOREACH(item, &mig_client->pending_links) {
1769
1767
        RedsMigPendingLink *mig_link;
1770
1768
        RedChannel *channel;
1773
1771
        channel = reds_find_channel(mig_link->link_msg->channel_type,
1774
1772
                                    mig_link->link_msg->channel_id);
1775
1773
        if (!channel) {
1776
 
            spice_printerr("warning: client %p channel (%d, %d) (type, id) wasn't found",
1777
 
                       client,
1778
 
                       mig_link->link_msg->channel_type,
1779
 
                       mig_link->link_msg->channel_id);
 
1774
            spice_warning("client %p channel (%d, %d) (type, id) wasn't found",
 
1775
                          client,
 
1776
                          mig_link->link_msg->channel_type,
 
1777
                          mig_link->link_msg->channel_id);
1780
1778
            continue;
1781
1779
        }
1782
1780
        reds_channel_do_link(channel, client, mig_link->link_msg, mig_link->stream);
1784
1782
 
1785
1783
    reds_mig_target_client_free(mig_client);
1786
1784
 
1787
 
    /* Now that we have a client, forward any pending agent data */
1788
 
    while (read_from_vdi_port());
 
1785
    return TRUE;
 
1786
}
 
1787
 
 
1788
int reds_on_migrate_dst_set_seamless(MainChannelClient *mcc, uint32_t src_version)
 
1789
{
 
1790
    /* seamless migration is not supported with multiple clients*/
 
1791
    if (reds->allow_multiple_clients  || src_version > SPICE_MIGRATION_PROTOCOL_VERSION) {
 
1792
        reds->dst_do_seamless_migrate = FALSE;
 
1793
    } else {
 
1794
        RedChannelClient *rcc = main_channel_client_get_base(mcc);
 
1795
 
 
1796
        red_client_set_migration_seamless(rcc->client);
 
1797
        /* linking all the channels that have been connected before migration handshake */
 
1798
        reds->dst_do_seamless_migrate = reds_link_mig_target_channels(rcc->client);
 
1799
    }
 
1800
    return reds->dst_do_seamless_migrate;
 
1801
}
 
1802
 
 
1803
void reds_on_client_seamless_migrate_complete(RedClient *client)
 
1804
{
 
1805
    spice_debug(NULL);
 
1806
    if (!reds_find_client(client)) {
 
1807
        spice_info("client no longer exists");
 
1808
        return;
 
1809
    }
 
1810
    main_channel_migrate_dst_complete(red_client_get_main(client));
 
1811
}
 
1812
 
 
1813
void reds_on_client_semi_seamless_migrate_complete(RedClient *client)
 
1814
{
 
1815
    MainChannelClient *mcc;
 
1816
 
 
1817
    spice_info("%p", client);
 
1818
    mcc = red_client_get_main(client);
 
1819
 
 
1820
    // TODO: not doing net test. consider doing it on client_migrate_info
 
1821
    main_channel_push_init(mcc, red_dispatcher_count(),
 
1822
                           reds->mouse_mode, reds->is_client_mouse_allowed,
 
1823
                           reds_get_mm_time() - MM_TIME_DELTA,
 
1824
                           red_dispatcher_qxl_ram_size());
 
1825
    reds_link_mig_target_channels(client);
 
1826
    main_channel_migrate_dst_complete(mcc);
1789
1827
}
1790
1828
 
1791
1829
static void reds_handle_other_links(RedLinkInfo *link)
1819
1857
    }
1820
1858
 
1821
1859
    reds_send_link_result(link, SPICE_LINK_ERR_OK);
1822
 
    reds_show_new_channel(link, link_mess->connection_id);
 
1860
    reds_info_new_channel(link, link_mess->connection_id);
1823
1861
    reds_stream_remove_watch(link->stream);
1824
1862
 
1825
1863
    mig_client = reds_mig_target_client_find(client);
1826
 
    if (red_client_during_migrate_at_target(client)) {
 
1864
    /*
 
1865
     * In semi-seamless migration, we activate the channels only
 
1866
     * after migration is completed. Since, the session starts almost from
 
1867
     * scratch we don't mind if we skip some messages in between the src session end and
 
1868
     * dst session start.
 
1869
     * In seamless migration, in order to keep the continuousness of the session, and
 
1870
     * in order not to lose any data, we activate the target channels before
 
1871
     * migration completes, as soon as we receive SPICE_MSGC_MAIN_MIGRATE_DST_DO_SEAMLESS.
 
1872
     * If a channel connects before receiving SPICE_MSGC_MAIN_MIGRATE_DST_DO_SEAMLESS,
 
1873
     * reds_on_migrate_dst_set_seamless will take care of activating it */
 
1874
    if (red_client_during_migrate_at_target(client) && !reds->dst_do_seamless_migrate) {
1827
1875
        spice_assert(mig_client);
1828
1876
        reds_mig_target_client_add_pending_link(mig_client, link_mess, link->stream);
1829
1877
    } else {
1862
1910
 
1863
1911
        if (strlen(taTicket.password) == 0) {
1864
1912
            reds_send_link_result(link, SPICE_LINK_ERR_PERMISSION_DENIED);
1865
 
            spice_printerr("Ticketing is enabled, but no password is set. "
1866
 
                       "please set a ticket first");
 
1913
            spice_warning("Ticketing is enabled, but no password is set. "
 
1914
                        "please set a ticket first");
1867
1915
            reds_link_free(link);
1868
1916
            return;
1869
1917
        }
1870
1918
 
1871
1919
        if (expired || strncmp(password, taTicket.password, SPICE_MAX_PASSWORD_LENGTH) != 0) {
1872
1920
            if (expired) {
1873
 
                spice_printerr("Ticket has expired");
 
1921
                spice_warning("Ticket has expired");
1874
1922
            } else {
1875
 
                spice_printerr("Invalid password");
 
1923
                spice_warning("Invalid password");
1876
1924
            }
1877
1925
            reds_send_link_result(link, SPICE_LINK_ERR_PERMISSION_DENIED);
1878
1926
            reds_link_free(link);
1913
1961
                          (const char **)&s->sasl.encoded,
1914
1962
                          &s->sasl.encodedLength);
1915
1963
        if (err != SASL_OK) {
1916
 
            spice_printerr("sasl_encode error: %d", err);
 
1964
            spice_warning("sasl_encode error: %d", err);
1917
1965
            return -1;
1918
1966
        }
1919
1967
 
1922
1970
        }
1923
1971
 
1924
1972
        if (!s->sasl.encoded) {
1925
 
            spice_printerr("sasl_encode didn't return a buffer!");
 
1973
            spice_warning("sasl_encode didn't return a buffer!");
1926
1974
            return 0;
1927
1975
        }
1928
1976
 
1974
2022
                      (char *)encoded, n,
1975
2023
                      &decoded, &decodedlen);
1976
2024
    if (err != SASL_OK) {
1977
 
        spice_printerr("sasl_decode error: %d", err);
 
2025
        spice_warning("sasl_decode error: %d", err);
1978
2026
        return -1;
1979
2027
    }
1980
2028
 
2056
2104
                           host, sizeof(host),
2057
2105
                           serv, sizeof(serv),
2058
2106
                           NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
2059
 
        spice_printerr("Cannot resolve address %d: %s",
2060
 
                   err, gai_strerror(err));
 
2107
        spice_warning("Cannot resolve address %d: %s",
 
2108
                      err, gai_strerror(err));
2061
2109
        return NULL;
2062
2110
    }
2063
2111
 
2087
2135
    }
2088
2136
 
2089
2137
    ssf = *(const int *)val;
2090
 
    spice_printerr("negotiated an SSF of %d", ssf);
 
2138
    spice_info("negotiated an SSF of %d", ssf);
2091
2139
    if (ssf < 56) {
2092
2140
        return 0; /* 56 is good for Kerberos */
2093
2141
    }
2134
2182
        datalen--; /* Don't count NULL byte when passing to _start() */
2135
2183
    }
2136
2184
 
2137
 
    spice_printerr("Step using SASL Data %p (%d bytes)",
 
2185
    spice_info("Step using SASL Data %p (%d bytes)",
2138
2186
               clientdata, datalen);
2139
2187
    err = sasl_server_step(sasl->conn,
2140
2188
                           clientdata,
2143
2191
                           &serveroutlen);
2144
2192
    if (err != SASL_OK &&
2145
2193
        err != SASL_CONTINUE) {
2146
 
        spice_printerr("sasl step failed %d (%s)",
2147
 
                   err, sasl_errdetail(sasl->conn));
 
2194
        spice_warning("sasl step failed %d (%s)",
 
2195
                      err, sasl_errdetail(sasl->conn));
2148
2196
        goto authabort;
2149
2197
    }
2150
2198
 
2151
2199
    if (serveroutlen > SASL_DATA_MAX_LEN) {
2152
 
        spice_printerr("sasl step reply data too long %d",
2153
 
                   serveroutlen);
 
2200
        spice_warning("sasl step reply data too long %d",
 
2201
                      serveroutlen);
2154
2202
        goto authabort;
2155
2203
    }
2156
2204
 
2157
 
    spice_printerr("SASL return data %d bytes, %p", serveroutlen, serverout);
 
2205
    spice_info("SASL return data %d bytes, %p", serveroutlen, serverout);
2158
2206
 
2159
2207
    if (serveroutlen) {
2160
2208
        serveroutlen += 1;
2168
2216
    sync_write_u8(link->stream, err == SASL_CONTINUE ? 0 : 1);
2169
2217
 
2170
2218
    if (err == SASL_CONTINUE) {
2171
 
        spice_printerr("%s", "Authentication must continue (step)");
 
2219
        spice_info("%s", "Authentication must continue (step)");
2172
2220
        /* Wait for step length */
2173
2221
        obj->now = (uint8_t *)&sasl->len;
2174
2222
        obj->end = obj->now + sizeof(uint32_t);
2178
2226
        int ssf;
2179
2227
 
2180
2228
        if (auth_sasl_check_ssf(sasl, &ssf) == 0) {
2181
 
            spice_printerr("Authentication rejected for weak SSF");
 
2229
            spice_warning("Authentication rejected for weak SSF");
2182
2230
            goto authreject;
2183
2231
        }
2184
2232
 
2185
 
        spice_printerr("Authentication successful");
 
2233
        spice_info("Authentication successful");
2186
2234
        sync_write_u32(link->stream, SPICE_LINK_ERR_OK); /* Accept auth */
2187
2235
 
2188
2236
        /*
2212
2260
    AsyncRead *obj = &link->asyc_read;
2213
2261
    RedsSASL *sasl = &link->stream->sasl;
2214
2262
 
2215
 
    spice_printerr("Got steplen %d", sasl->len);
 
2263
    spice_info("Got steplen %d", sasl->len);
2216
2264
    if (sasl->len > SASL_DATA_MAX_LEN) {
2217
 
        spice_printerr("Too much SASL data %d", sasl->len);
 
2265
        spice_warning("Too much SASL data %d", sasl->len);
2218
2266
        reds_link_free(link);
2219
2267
        return;
2220
2268
    }
2264
2312
        datalen--; /* Don't count NULL byte when passing to _start() */
2265
2313
    }
2266
2314
 
2267
 
    spice_printerr("Start SASL auth with mechanism %s. Data %p (%d bytes)",
2268
 
              sasl->mechlist, clientdata, datalen);
 
2315
    spice_info("Start SASL auth with mechanism %s. Data %p (%d bytes)",
 
2316
               sasl->mechlist, clientdata, datalen);
2269
2317
    err = sasl_server_start(sasl->conn,
2270
2318
                            sasl->mechlist,
2271
2319
                            clientdata,
2274
2322
                            &serveroutlen);
2275
2323
    if (err != SASL_OK &&
2276
2324
        err != SASL_CONTINUE) {
2277
 
        spice_printerr("sasl start failed %d (%s)",
2278
 
                   err, sasl_errdetail(sasl->conn));
 
2325
        spice_warning("sasl start failed %d (%s)",
 
2326
                    err, sasl_errdetail(sasl->conn));
2279
2327
        goto authabort;
2280
2328
    }
2281
2329
 
2282
2330
    if (serveroutlen > SASL_DATA_MAX_LEN) {
2283
 
        spice_printerr("sasl start reply data too long %d",
2284
 
                   serveroutlen);
 
2331
        spice_warning("sasl start reply data too long %d",
 
2332
                    serveroutlen);
2285
2333
        goto authabort;
2286
2334
    }
2287
2335
 
2288
 
    spice_printerr("SASL return data %d bytes, %p", serveroutlen, serverout);
 
2336
    spice_info("SASL return data %d bytes, %p", serveroutlen, serverout);
2289
2337
 
2290
2338
    if (serveroutlen) {
2291
2339
        serveroutlen += 1;
2299
2347
    sync_write_u8(link->stream, err == SASL_CONTINUE ? 0 : 1);
2300
2348
 
2301
2349
    if (err == SASL_CONTINUE) {
2302
 
        spice_printerr("%s", "Authentication must continue (start)");
 
2350
        spice_info("%s", "Authentication must continue (start)");
2303
2351
        /* Wait for step length */
2304
2352
        obj->now = (uint8_t *)&sasl->len;
2305
2353
        obj->end = obj->now + sizeof(uint32_t);
2309
2357
        int ssf;
2310
2358
 
2311
2359
        if (auth_sasl_check_ssf(sasl, &ssf) == 0) {
2312
 
            spice_printerr("Authentication rejected for weak SSF");
 
2360
            spice_warning("Authentication rejected for weak SSF");
2313
2361
            goto authreject;
2314
2362
        }
2315
2363
 
2316
 
        spice_printerr("Authentication successful");
 
2364
        spice_info("Authentication successful");
2317
2365
        sync_write_u32(link->stream, SPICE_LINK_ERR_OK); /* Accept auth */
2318
2366
 
2319
2367
        /*
2343
2391
    AsyncRead *obj = &link->asyc_read;
2344
2392
    RedsSASL *sasl = &link->stream->sasl;
2345
2393
 
2346
 
    spice_printerr("Got client start len %d", sasl->len);
 
2394
    spice_info("Got client start len %d", sasl->len);
2347
2395
    if (sasl->len > SASL_DATA_MAX_LEN) {
2348
 
        spice_printerr("Too much SASL data %d", sasl->len);
 
2396
        spice_warning("Too much SASL data %d", sasl->len);
2349
2397
        reds_send_link_error(link, SPICE_LINK_ERR_INVALID_DATA);
2350
2398
        reds_link_free(link);
2351
2399
        return;
2370
2418
    RedsSASL *sasl = &link->stream->sasl;
2371
2419
 
2372
2420
    sasl->mechname[sasl->len] = '\0';
2373
 
    spice_printerr("Got client mechname '%s' check against '%s'",
 
2421
    spice_info("Got client mechname '%s' check against '%s'",
2374
2422
               sasl->mechname, sasl->mechlist);
2375
2423
 
2376
2424
    if (strncmp(sasl->mechlist, sasl->mechname, sasl->len) == 0) {
2377
2425
        if (sasl->mechlist[sasl->len] != '\0' &&
2378
2426
            sasl->mechlist[sasl->len] != ',') {
2379
 
            spice_printerr("One %d", sasl->mechlist[sasl->len]);
 
2427
            spice_info("One %d", sasl->mechlist[sasl->len]);
2380
2428
            reds_link_free(link);
2381
2429
            return;
2382
2430
        }
2383
2431
    } else {
2384
2432
        char *offset = strstr(sasl->mechlist, sasl->mechname);
2385
 
        spice_printerr("Two %p", offset);
 
2433
        spice_info("Two %p", offset);
2386
2434
        if (!offset) {
2387
2435
            reds_send_link_error(link, SPICE_LINK_ERR_INVALID_DATA);
2388
2436
            return;
2389
2437
        }
2390
 
        spice_printerr("Two '%s'", offset);
 
2438
        spice_info("Two '%s'", offset);
2391
2439
        if (offset[-1] != ',' ||
2392
2440
            (offset[sasl->len] != '\0'&&
2393
2441
             offset[sasl->len] != ',')) {
2399
2447
    free(sasl->mechlist);
2400
2448
    sasl->mechlist = spice_strdup(sasl->mechname);
2401
2449
 
2402
 
    spice_printerr("Validated mechname '%s'", sasl->mechname);
 
2450
    spice_info("Validated mechname '%s'", sasl->mechname);
2403
2451
 
2404
2452
    obj->now = (uint8_t *)&sasl->len;
2405
2453
    obj->end = obj->now + sizeof(uint32_t);
2416
2464
    RedsSASL *sasl = &link->stream->sasl;
2417
2465
 
2418
2466
    if (sasl->len < 1 || sasl->len > 100) {
2419
 
        spice_printerr("Got bad client mechname len %d", sasl->len);
 
2467
        spice_warning("Got bad client mechname len %d", sasl->len);
2420
2468
        reds_link_free(link);
2421
2469
        return;
2422
2470
    }
2423
2471
 
2424
2472
    sasl->mechname = spice_malloc(sasl->len + 1);
2425
2473
 
2426
 
    spice_printerr("Wait for client mechname");
 
2474
    spice_info("Wait for client mechname");
2427
2475
    obj->now = (uint8_t *)sasl->mechname;
2428
2476
    obj->end = obj->now + sasl->len;
2429
2477
    obj->done = reds_handle_auth_mechname;
2465
2513
    localAddr = remoteAddr = NULL;
2466
2514
 
2467
2515
    if (err != SASL_OK) {
2468
 
        spice_printerr("sasl context setup failed %d (%s)",
2469
 
                   err, sasl_errstring(err, NULL, NULL));
 
2516
        spice_warning("sasl context setup failed %d (%s)",
 
2517
                    err, sasl_errstring(err, NULL, NULL));
2470
2518
        sasl->conn = NULL;
2471
2519
        goto error;
2472
2520
    }
2478
2526
        ssf = SSL_get_cipher_bits(link->stream->ssl, NULL);
2479
2527
        err = sasl_setprop(sasl->conn, SASL_SSF_EXTERNAL, &ssf);
2480
2528
        if (err != SASL_OK) {
2481
 
            spice_printerr("cannot set SASL external SSF %d (%s)",
2482
 
                       err, sasl_errstring(err, NULL, NULL));
 
2529
            spice_warning("cannot set SASL external SSF %d (%s)",
 
2530
                        err, sasl_errstring(err, NULL, NULL));
2483
2531
            goto error_dispose;
2484
2532
        }
2485
2533
    } else {
2506
2554
 
2507
2555
    err = sasl_setprop(sasl->conn, SASL_SEC_PROPS, &secprops);
2508
2556
    if (err != SASL_OK) {
2509
 
        spice_printerr("cannot set SASL security props %d (%s)",
2510
 
                   err, sasl_errstring(err, NULL, NULL));
 
2557
        spice_warning("cannot set SASL security props %d (%s)",
 
2558
                      err, sasl_errstring(err, NULL, NULL));
2511
2559
        goto error_dispose;
2512
2560
    }
2513
2561
 
2520
2568
                        NULL,
2521
2569
                        NULL);
2522
2570
    if (err != SASL_OK || mechlist == NULL) {
2523
 
        spice_printerr("cannot list SASL mechanisms %d (%s)",
2524
 
                   err, sasl_errdetail(sasl->conn));
 
2571
        spice_warning("cannot list SASL mechanisms %d (%s)",
 
2572
                      err, sasl_errdetail(sasl->conn));
2525
2573
        goto error_dispose;
2526
2574
    }
2527
2575
 
2528
 
    spice_printerr("Available mechanisms for client: '%s'", mechlist);
 
2576
    spice_info("Available mechanisms for client: '%s'", mechlist);
2529
2577
 
2530
2578
    sasl->mechlist = spice_strdup(mechlist);
2531
2579
 
2532
2580
    mechlistlen = strlen(mechlist);
2533
2581
    if (!sync_write(link->stream, &mechlistlen, sizeof(uint32_t))
2534
2582
        || !sync_write(link->stream, sasl->mechlist, mechlistlen)) {
2535
 
        spice_printerr("SASL mechanisms write error");
 
2583
        spice_warning("SASL mechanisms write error");
2536
2584
        goto error;
2537
2585
    }
2538
2586
 
2539
 
    spice_printerr("Wait for client mechname length");
 
2587
    spice_info("Wait for client mechname length");
2540
2588
    obj->now = (uint8_t *)&sasl->len;
2541
2589
    obj->end = obj->now + sizeof(uint32_t);
2542
2590
    obj->done = reds_handle_auth_mechlen;
2557
2605
{
2558
2606
    RedLinkInfo *link = (RedLinkInfo *)opaque;
2559
2607
 
2560
 
    spice_printerr("Auth method: %d", link->auth_mechanism.auth_mechanism);
 
2608
    spice_info("Auth method: %d", link->auth_mechanism.auth_mechanism);
2561
2609
 
2562
2610
    if (link->auth_mechanism.auth_mechanism == SPICE_COMMON_CAP_AUTH_SPICE
2563
2611
        && !sasl_enabled
2565
2613
        reds_get_spice_ticket(link);
2566
2614
#if HAVE_SASL
2567
2615
    } else if (link->auth_mechanism.auth_mechanism == SPICE_COMMON_CAP_AUTH_SASL) {
2568
 
        spice_printerr("Starting SASL");
 
2616
        spice_info("Starting SASL");
2569
2617
        reds_start_auth_sasl(link);
2570
2618
#endif
2571
2619
    } else {
2572
 
        spice_printerr("Unknown auth method, disconnecting");
 
2620
        spice_warning("Unknown auth method, disconnecting");
2573
2621
        if (sasl_enabled) {
2574
 
            spice_printerr("Your client doesn't handle SASL?");
 
2622
            spice_warning("Your client doesn't handle SASL?");
2575
2623
        }
2576
2624
        reds_send_link_error(link, SPICE_LINK_ERR_INVALID_DATA);
2577
2625
        reds_link_free(link);
2608
2656
 
2609
2657
    if (!reds_security_check(link)) {
2610
2658
        if (link->stream->ssl) {
2611
 
            spice_printerr("spice channels %d should not be encrypted", link_mess->channel_type);
 
2659
            spice_warning("spice channels %d should not be encrypted", link_mess->channel_type);
2612
2660
            reds_send_link_error(link, SPICE_LINK_ERR_NEED_UNSECURED);
2613
2661
        } else {
2614
 
            spice_printerr("spice channels %d should be encrypted", link_mess->channel_type);
 
2662
            spice_warning("spice channels %d should be encrypted", link_mess->channel_type);
2615
2663
            reds_send_link_error(link, SPICE_LINK_ERR_NEED_SECURED);
2616
2664
        }
2617
2665
        reds_link_free(link);
2625
2673
 
2626
2674
    if (!auth_selection) {
2627
2675
        if (sasl_enabled && !link->skip_auth) {
2628
 
            spice_printerr("SASL enabled, but peer supports only spice authentication");
 
2676
            spice_warning("SASL enabled, but peer supports only spice authentication");
2629
2677
            reds_send_link_error(link, SPICE_LINK_ERR_VERSION_MISMATCH);
2630
2678
            return;
2631
2679
        }
2632
 
        spice_printerr("Peer doesn't support AUTH selection");
 
2680
        spice_warning("Peer doesn't support AUTH selection");
2633
2681
        reds_get_spice_ticket(link);
2634
2682
    } else {
2635
2683
        obj->now = (uint8_t *)&link->auth_mechanism;
2647
2695
    case EPIPE:
2648
2696
        break;
2649
2697
    default:
2650
 
        spice_printerr("%s", strerror(errno));
 
2698
        spice_warning("%s", strerror(errno));
2651
2699
        break;
2652
2700
    }
2653
2701
    reds_link_free(link);
2670
2718
            reds_send_link_error(link, SPICE_LINK_ERR_VERSION_MISMATCH);
2671
2719
        }
2672
2720
 
2673
 
        spice_printerr("version mismatch");
 
2721
        spice_warning("version mismatch");
2674
2722
        reds_link_free(link);
2675
2723
        return;
2676
2724
    }
2679
2727
 
2680
2728
    if (header->size < sizeof(SpiceLinkMess)) {
2681
2729
        reds_send_link_error(link, SPICE_LINK_ERR_INVALID_DATA);
2682
 
        spice_printerr("bad size %u", header->size);
 
2730
        spice_warning("bad size %u", header->size);
2683
2731
        reds_link_free(link);
2684
2732
        return;
2685
2733
    }
2712
2760
    if ((return_code = SSL_accept(link->stream->ssl)) != 1) {
2713
2761
        int ssl_error = SSL_get_error(link->stream->ssl, return_code);
2714
2762
        if (ssl_error != SSL_ERROR_WANT_READ && ssl_error != SSL_ERROR_WANT_WRITE) {
2715
 
            spice_printerr("SSL_accept failed, error=%d", ssl_error);
 
2763
            spice_warning("SSL_accept failed, error=%d", ssl_error);
2716
2764
            reds_link_free(link);
2717
2765
        } else {
2718
2766
            if (ssl_error == SSL_ERROR_WANT_READ) {
2735
2783
    int flags;
2736
2784
 
2737
2785
    if ((flags = fcntl(socket, F_GETFL)) == -1) {
2738
 
        spice_printerr("accept failed, %s", strerror(errno));
 
2786
        spice_warning("accept failed, %s", strerror(errno));
2739
2787
        goto error;
2740
2788
    }
2741
2789
 
2742
2790
    if (fcntl(socket, F_SETFL, flags | O_NONBLOCK) == -1) {
2743
 
        spice_printerr("accept failed, %s", strerror(errno));
 
2791
        spice_warning("accept failed, %s", strerror(errno));
2744
2792
        goto error;
2745
2793
    }
2746
2794
 
2747
2795
    if (setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, &delay_val, sizeof(delay_val)) == -1) {
2748
2796
        if (errno != ENOTSUP) {
2749
 
            spice_printerr("setsockopt failed, %s", strerror(errno));
 
2797
            spice_warning("setsockopt failed, %s", strerror(errno));
2750
2798
        }
2751
2799
    }
2752
2800
 
2796
2844
 
2797
2845
    // Handle SSL handshaking
2798
2846
    if (!(sbio = BIO_new_socket(link->stream->socket, BIO_NOCLOSE))) {
2799
 
        spice_printerr("could not allocate ssl bio socket");
 
2847
        spice_warning("could not allocate ssl bio socket");
2800
2848
        goto error;
2801
2849
    }
2802
2850
 
2803
2851
    link->stream->ssl = SSL_new(reds->ctx);
2804
2852
    if (!link->stream->ssl) {
2805
 
        spice_printerr("could not allocate ssl context");
 
2853
        spice_warning("could not allocate ssl context");
2806
2854
        BIO_free(sbio);
2807
2855
        goto error;
2808
2856
    }
2830
2878
    }
2831
2879
 
2832
2880
    ERR_print_errors_fp(stderr);
2833
 
    spice_printerr("SSL_accept failed, error=%d", ssl_error);
 
2881
    spice_warning("SSL_accept failed, error=%d", ssl_error);
2834
2882
    SSL_free(link->stream->ssl);
2835
2883
 
2836
2884
error:
2846
2894
    int socket;
2847
2895
 
2848
2896
    if ((socket = accept(reds->secure_listen_socket, NULL, 0)) == -1) {
2849
 
        spice_printerr("accept failed, %s", strerror(errno));
 
2897
        spice_warning("accept failed, %s", strerror(errno));
2850
2898
        return;
2851
2899
    }
2852
2900
 
2862
2910
    int socket;
2863
2911
 
2864
2912
    if ((socket = accept(reds->listen_socket, NULL, 0)) == -1) {
2865
 
        spice_printerr("accept failed, %s", strerror(errno));
 
2913
        spice_warning("accept failed, %s", strerror(errno));
2866
2914
        return;
2867
2915
    }
2868
2916
 
2878
2926
 
2879
2927
    spice_assert(reds == s);
2880
2928
    if (!(link = reds_init_client_connection(socket))) {
2881
 
        spice_printerr("accept failed");
 
2929
        spice_warning("accept failed");
2882
2930
        return -1;
2883
2931
    }
2884
2932
 
2925
2973
    snprintf(port, sizeof(port), "%d", portnr);
2926
2974
    rc = getaddrinfo(strlen(addr) ? addr : NULL, port, &ai, &res);
2927
2975
    if (rc != 0) {
2928
 
        spice_error("getaddrinfo(%s,%s): %s", addr, port,
2929
 
                  gai_strerror(rc));
 
2976
        spice_warning("getaddrinfo(%s,%s): %s", addr, port,
 
2977
                      gai_strerror(rc));
 
2978
        return -1;
2930
2979
    }
2931
2980
 
2932
2981
    for (e = res; e != NULL; e = e->ai_next) {
2951
3000
        }
2952
3001
        close(slisten);
2953
3002
    }
2954
 
    spice_printerr("%s: binding socket to %s:%d failed", __FUNCTION__,
2955
 
               addr, portnr);
 
3003
    spice_warning("%s: binding socket to %s:%d failed", __FUNCTION__,
 
3004
                  addr, portnr);
2956
3005
    freeaddrinfo(res);
2957
3006
    return -1;
2958
3007
 
2959
3008
listen:
2960
3009
    freeaddrinfo(res);
2961
3010
    if (listen(slisten,1) != 0) {
2962
 
        spice_error("listen: %s", strerror(errno));
 
3011
        spice_warning("listen: %s", strerror(errno));
2963
3012
        close(slisten);
2964
3013
        return -1;
2965
3014
    }
2977
3026
                                             SPICE_WATCH_EVENT_READ,
2978
3027
                                             reds_accept, NULL);
2979
3028
        if (reds->listen_watch == NULL) {
2980
 
            spice_error("set fd handle failed");
 
3029
            spice_warning("set fd handle failed");
 
3030
            return -1;
2981
3031
        }
2982
3032
    }
2983
3033
 
2991
3041
                                                    SPICE_WATCH_EVENT_READ,
2992
3042
                                                    reds_accept_ssl_connection, NULL);
2993
3043
        if (reds->secure_listen_watch == NULL) {
2994
 
            spice_error("set fd handle failed");
 
3044
            spice_warning("set fd handle failed");
 
3045
            return -1;
2995
3046
        }
2996
3047
    }
2997
3048
 
3001
3052
                                             SPICE_WATCH_EVENT_READ,
3002
3053
                                             reds_accept, NULL);
3003
3054
        if (reds->listen_watch == NULL) {
3004
 
            spice_error("set fd handle failed");
 
3055
            spice_warning("set fd handle failed");
 
3056
            return -1;
3005
3057
        }
3006
3058
    }
3007
3059
    return 0;
3008
3060
}
3009
3061
 
3010
 
static void load_dh_params(SSL_CTX *ctx, char *file)
 
3062
static int load_dh_params(SSL_CTX *ctx, char *file)
3011
3063
{
3012
3064
    DH *ret = 0;
3013
3065
    BIO *bio;
3014
3066
 
3015
3067
    if ((bio = BIO_new_file(file, "r")) == NULL) {
3016
 
        spice_error("Could not open DH file");
 
3068
        spice_warning("Could not open DH file");
 
3069
        return -1;
3017
3070
    }
3018
3071
 
3019
3072
    ret = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
 
3073
    BIO_free(bio);
3020
3074
    if (ret == 0) {
3021
 
        spice_error("Could not read DH params");
 
3075
        spice_warning("Could not read DH params");
 
3076
        return -1;
3022
3077
    }
3023
3078
 
3024
 
    BIO_free(bio);
3025
3079
 
3026
3080
    if (SSL_CTX_set_tmp_dh(ctx, ret) < 0) {
3027
 
        spice_error("Could not set DH params");
 
3081
        spice_warning("Could not set DH params");
 
3082
        return -1;
3028
3083
    }
 
3084
 
 
3085
    return 0;
3029
3086
}
3030
3087
 
3031
3088
/*The password code is not thread safe*/
3074
3131
    CRYPTO_set_locking_callback(pthreads_locking_callback);
3075
3132
}
3076
3133
 
3077
 
static void reds_init_ssl(void)
 
3134
static int reds_init_ssl(void)
3078
3135
{
3079
3136
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
3080
3137
    const SSL_METHOD *ssl_method;
3092
3149
    ssl_method = TLSv1_method();
3093
3150
    reds->ctx = SSL_CTX_new(ssl_method);
3094
3151
    if (!reds->ctx) {
3095
 
        spice_error("Could not allocate new SSL context");
 
3152
        spice_warning("Could not allocate new SSL context");
 
3153
        return -1;
3096
3154
    }
3097
3155
 
3098
3156
    /* Limit connection to TLSv1 only */
3104
3162
    /* Load our keys and certificates*/
3105
3163
    return_code = SSL_CTX_use_certificate_chain_file(reds->ctx, ssl_parameters.certs_file);
3106
3164
    if (return_code == 1) {
3107
 
        spice_printerr("Loaded certificates from %s", ssl_parameters.certs_file);
 
3165
        spice_info("Loaded certificates from %s", ssl_parameters.certs_file);
3108
3166
    } else {
3109
 
        spice_error("Could not load certificates from %s", ssl_parameters.certs_file);
 
3167
        spice_warning("Could not load certificates from %s", ssl_parameters.certs_file);
 
3168
        return -1;
3110
3169
    }
3111
3170
 
3112
3171
    SSL_CTX_set_default_passwd_cb(reds->ctx, ssl_password_cb);
3114
3173
    return_code = SSL_CTX_use_PrivateKey_file(reds->ctx, ssl_parameters.private_key_file,
3115
3174
                                              SSL_FILETYPE_PEM);
3116
3175
    if (return_code == 1) {
3117
 
        spice_printerr("Using private key from %s", ssl_parameters.private_key_file);
 
3176
        spice_info("Using private key from %s", ssl_parameters.private_key_file);
3118
3177
    } else {
3119
 
        spice_error("Could not use private key file");
 
3178
        spice_warning("Could not use private key file");
 
3179
        return -1;
3120
3180
    }
3121
3181
 
3122
3182
    /* Load the CAs we trust*/
3123
3183
    return_code = SSL_CTX_load_verify_locations(reds->ctx, ssl_parameters.ca_certificate_file, 0);
3124
3184
    if (return_code == 1) {
3125
 
        spice_printerr("Loaded CA certificates from %s", ssl_parameters.ca_certificate_file);
 
3185
        spice_info("Loaded CA certificates from %s", ssl_parameters.ca_certificate_file);
3126
3186
    } else {
3127
 
        spice_error("Could not use CA file %s", ssl_parameters.ca_certificate_file);
 
3187
        spice_warning("Could not use CA file %s", ssl_parameters.ca_certificate_file);
 
3188
        return -1;
3128
3189
    }
3129
3190
 
3130
3191
#if (OPENSSL_VERSION_NUMBER < 0x00905100L)
3132
3193
#endif
3133
3194
 
3134
3195
    if (strlen(ssl_parameters.dh_key_file) > 0) {
3135
 
        load_dh_params(reds->ctx, ssl_parameters.dh_key_file);
 
3196
        if (load_dh_params(reds->ctx, ssl_parameters.dh_key_file) < 0) {
 
3197
            return -1;
 
3198
        }
3136
3199
    }
3137
3200
 
3138
3201
    SSL_CTX_set_session_id_context(reds->ctx, (const unsigned char *)"SPICE", 5);
3139
3202
    if (strlen(ssl_parameters.ciphersuite) > 0) {
3140
 
        SSL_CTX_set_cipher_list(reds->ctx, ssl_parameters.ciphersuite);
 
3203
        if (!SSL_CTX_set_cipher_list(reds->ctx, ssl_parameters.ciphersuite)) {
 
3204
            return -1;
 
3205
        }
3141
3206
    }
3142
3207
 
3143
3208
    openssl_thread_setup();
3146
3211
    STACK *cmp_stack = SSL_COMP_get_compression_methods();
3147
3212
    sk_zero(cmp_stack);
3148
3213
#endif
 
3214
 
 
3215
    return 0;
3149
3216
}
3150
3217
 
3151
3218
static void reds_exit(void)
3195
3262
static inline void on_activating_ticketing(void)
3196
3263
{
3197
3264
    if (!ticketing_enabled && reds_main_channel_connected()) {
3198
 
        spice_printerr("disconnecting");
 
3265
        spice_warning("disconnecting");
3199
3266
        reds_disconnect();
3200
3267
    }
3201
3268
}
3247
3314
 
3248
3315
static void reds_mig_started(void)
3249
3316
{
3250
 
    spice_printerr("");
 
3317
    spice_info(NULL);
3251
3318
    spice_assert(reds->mig_spice);
3252
3319
 
3253
3320
    reds->mig_inprogress = TRUE;
3255
3322
    core->timer_start(reds->mig_timer, MIGRATE_TIMEOUT);
3256
3323
}
3257
3324
 
 
3325
static void reds_mig_fill_wait_disconnect(void)
 
3326
{
 
3327
    RingItem *client_item;
 
3328
 
 
3329
    spice_assert(reds->num_clients > 0);
 
3330
    /* tracking the clients, in order to ignore disconnection
 
3331
     * of clients that got connected to the src after migration completion.*/
 
3332
    RING_FOREACH(client_item, &reds->clients) {
 
3333
        RedClient *client = SPICE_CONTAINEROF(client_item, RedClient, link);
 
3334
        RedsMigWaitDisconnectClient *wait_client;
 
3335
 
 
3336
        wait_client = spice_new0(RedsMigWaitDisconnectClient, 1);
 
3337
        wait_client->client = client;
 
3338
        ring_add(&reds->mig_wait_disconnect_clients, &wait_client->link);
 
3339
    }
 
3340
    reds->mig_wait_disconnect = TRUE;
 
3341
    core->timer_start(reds->mig_timer, MIGRATE_TIMEOUT);
 
3342
}
 
3343
 
 
3344
static void reds_mig_cleanup_wait_disconnect(void)
 
3345
{
 
3346
    RingItem *wait_client_item;
 
3347
 
 
3348
    while ((wait_client_item = ring_get_tail(&reds->mig_wait_disconnect_clients))) {
 
3349
        RedsMigWaitDisconnectClient *wait_client;
 
3350
 
 
3351
        wait_client = SPICE_CONTAINEROF(wait_client_item, RedsMigWaitDisconnectClient, link);
 
3352
        ring_remove(wait_client_item);
 
3353
        free(wait_client);
 
3354
    }
 
3355
    reds->mig_wait_disconnect = FALSE;
 
3356
}
 
3357
 
 
3358
static void reds_mig_remove_wait_disconnect_client(RedClient *client)
 
3359
{
 
3360
    RingItem *wait_client_item;
 
3361
 
 
3362
    RING_FOREACH(wait_client_item, &reds->mig_wait_disconnect_clients) {
 
3363
        RedsMigWaitDisconnectClient *wait_client;
 
3364
 
 
3365
        wait_client = SPICE_CONTAINEROF(wait_client_item, RedsMigWaitDisconnectClient, link);
 
3366
        if (wait_client->client == client) {
 
3367
            ring_remove(wait_client_item);
 
3368
            free(wait_client);
 
3369
            if (ring_is_empty(&reds->mig_wait_disconnect_clients)) {
 
3370
                reds_mig_cleanup();
 
3371
            }
 
3372
            return;
 
3373
        }
 
3374
    }
 
3375
    spice_warning("client not found %p", client);
 
3376
}
 
3377
 
 
3378
static void reds_migrate_channels_seamless(void)
 
3379
{
 
3380
    RedClient *client;
 
3381
 
 
3382
    /* seamless migration is supported for only one client for now */
 
3383
    client = reds_get_client();
 
3384
    red_client_migrate(client);
 
3385
}
 
3386
 
3258
3387
static void reds_mig_finished(int completed)
3259
3388
{
3260
 
    spice_printerr("");
 
3389
    spice_info(NULL);
3261
3390
 
3262
 
    if (!reds_main_channel_connected()) {
3263
 
        spice_printerr("no peer connected");
3264
 
        return;
3265
 
    }
3266
3391
    reds->mig_inprogress = TRUE;
3267
3392
 
3268
 
    if (main_channel_migrate_complete(reds->main_channel, completed)) {
3269
 
        reds->mig_wait_disconnect = TRUE;
3270
 
        core->timer_start(reds->mig_timer, MIGRATE_TIMEOUT);
 
3393
    if (reds->src_do_seamless_migrate && completed) {
 
3394
        reds_migrate_channels_seamless();
 
3395
    } else {
 
3396
        main_channel_migrate_src_complete(reds->main_channel, completed);
 
3397
    }
 
3398
 
 
3399
    if (completed) {
 
3400
        reds_mig_fill_wait_disconnect();
3271
3401
    } else {
3272
3402
        reds_mig_cleanup();
3273
3403
    }
3277
3407
static void reds_mig_switch(void)
3278
3408
{
3279
3409
    if (!reds->mig_spice) {
3280
 
        spice_printerr("warning: reds_mig_switch called without migrate_info set");
 
3410
        spice_warning("reds_mig_switch called without migrate_info set");
3281
3411
        return;
3282
3412
    }
3283
3413
    main_channel_migrate_switch(reds->main_channel, reds->mig_spice);
3286
3416
 
3287
3417
static void migrate_timeout(void *opaque)
3288
3418
{
3289
 
    spice_printerr("");
 
3419
    spice_info(NULL);
3290
3420
    spice_assert(reds->mig_wait_connect || reds->mig_wait_disconnect);
3291
3421
    if (reds->mig_wait_connect) {
3292
3422
        /* we will fall back to the switch host scheme when migration completes */
3331
3461
    core->timer_start(reds->mm_timer, MM_TIMER_GRANULARITY_MS);
3332
3462
}
3333
3463
 
3334
 
static void attach_to_red_agent(SpiceCharDeviceInstance *sin)
 
3464
static SpiceCharDeviceState *attach_to_red_agent(SpiceCharDeviceInstance *sin)
3335
3465
{
3336
3466
    VDIPortState *state = &reds->agent_state;
3337
3467
    SpiceCharDeviceInterface *sif;
 
3468
    SpiceCharDeviceCallbacks char_dev_state_cbs;
 
3469
 
 
3470
    if (!state->base) {
 
3471
        char_dev_state_cbs.read_one_msg_from_device = vdi_port_read_one_msg_from_device;
 
3472
        char_dev_state_cbs.ref_msg_to_client = vdi_port_ref_msg_to_client;
 
3473
        char_dev_state_cbs.unref_msg_to_client = vdi_port_unref_msg_to_client;
 
3474
        char_dev_state_cbs.send_msg_to_client = vdi_port_send_msg_to_client;
 
3475
        char_dev_state_cbs.send_tokens_to_client = vdi_port_send_tokens_to_client;
 
3476
        char_dev_state_cbs.remove_client = vdi_port_remove_client;
 
3477
        char_dev_state_cbs.on_free_self_token = vdi_port_on_free_self_token;
 
3478
 
 
3479
        state->base = spice_char_device_state_create(sin,
 
3480
                                                     REDS_TOKENS_TO_SEND,
 
3481
                                                     REDS_NUM_INTERNAL_AGENT_MESSAGES,
 
3482
                                                     &char_dev_state_cbs,
 
3483
                                                     NULL);
 
3484
    } else {
 
3485
        spice_char_device_state_reset_dev_instance(state->base, sin);
 
3486
    }
3338
3487
 
3339
3488
    vdagent = sin;
3340
3489
    reds_update_mouse_mode();
3345
3494
    }
3346
3495
 
3347
3496
    if (!reds_main_channel_connected()) {
3348
 
        return;
 
3497
        return state->base;
3349
3498
    }
3350
3499
 
3351
3500
    state->read_filter.discard_all = FALSE;
3352
3501
    reds->agent_state.plug_generation++;
3353
3502
 
3354
 
    main_channel_push_agent_connected(reds->main_channel);
 
3503
    if (reds->agent_state.mig_data) {
 
3504
        spice_assert(reds->agent_state.plug_generation == 1);
 
3505
        reds_agent_state_restore(reds->agent_state.mig_data);
 
3506
        free(reds->agent_state.mig_data);
 
3507
        reds->agent_state.mig_data = NULL;
 
3508
    } else if (!red_channel_waits_for_migrate_data(&reds->main_channel->base)) {
 
3509
        /* we will assoicate the client with the char device, upon reds_on_main_agent_start,
 
3510
         * in response to MSGC_AGENT_START */
 
3511
        main_channel_push_agent_connected(reds->main_channel);
 
3512
    } else {
 
3513
       spice_debug("waiting for migration data");
 
3514
        if (!spice_char_device_client_exists(reds->agent_state.base, reds_get_client())) {
 
3515
            int client_added;
 
3516
 
 
3517
            client_added = spice_char_device_client_add(reds->agent_state.base,
 
3518
                                                        reds_get_client(),
 
3519
                                                        TRUE, /* flow control */
 
3520
                                                        REDS_VDI_PORT_NUM_RECEIVE_BUFFS,
 
3521
                                                        REDS_AGENT_WINDOW_SIZE,
 
3522
                                                        ~0,
 
3523
                                                        TRUE);
 
3524
 
 
3525
            if (!client_added) {
 
3526
                spice_warning("failed to add client to agent");
 
3527
                reds_disconnect();
 
3528
            }
 
3529
 
 
3530
        }
 
3531
    }
 
3532
    return state->base;
3355
3533
}
3356
3534
 
3357
3535
SPICE_GNUC_VISIBLE void spice_server_char_device_wakeup(SpiceCharDeviceInstance* sin)
3358
3536
{
3359
 
    (*sin->st->wakeup)(sin);
 
3537
    if (!sin->st) {
 
3538
        spice_warning("no SpiceCharDeviceState attached to instance %p", sin);
 
3539
        return;
 
3540
    }
 
3541
    spice_char_device_wakeup(sin->st);
3360
3542
}
3361
3543
 
3362
3544
#define SUBTYPE_VDAGENT "vdagent"
3363
3545
#define SUBTYPE_SMARTCARD "smartcard"
3364
3546
#define SUBTYPE_USBREDIR "usbredir"
 
3547
#define SUBTYPE_PORT "port"
3365
3548
 
3366
3549
const char *spice_server_char_device_recognized_subtypes_list[] = {
3367
3550
    SUBTYPE_VDAGENT,
3377
3560
    return spice_server_char_device_recognized_subtypes_list;
3378
3561
}
3379
3562
 
 
3563
static void reds_char_device_add_state(SpiceCharDeviceState *st)
 
3564
{
 
3565
    SpiceCharDeviceStateItem *item = spice_new0(SpiceCharDeviceStateItem, 1);
 
3566
 
 
3567
    item->st = st;
 
3568
 
 
3569
    ring_add(&reds->char_devs_states, &item->link);
 
3570
}
 
3571
 
 
3572
static void reds_char_device_remove_state(SpiceCharDeviceState *st)
 
3573
{
 
3574
    RingItem *item;
 
3575
 
 
3576
    RING_FOREACH(item, &reds->char_devs_states) {
 
3577
        SpiceCharDeviceStateItem *st_item;
 
3578
 
 
3579
        st_item = SPICE_CONTAINEROF(item, SpiceCharDeviceStateItem, link);
 
3580
        if (st_item->st == st) {
 
3581
            ring_remove(item);
 
3582
            free(st_item);
 
3583
            return;
 
3584
        }
 
3585
    }
 
3586
    spice_error("char dev state not found %p", st);
 
3587
}
 
3588
 
 
3589
void reds_on_char_device_state_destroy(SpiceCharDeviceState *dev)
 
3590
{
 
3591
    reds_char_device_remove_state(dev);
 
3592
}
 
3593
 
3380
3594
static int spice_server_char_device_add_interface(SpiceServer *s,
3381
3595
                                           SpiceBaseInstance *sin)
3382
3596
{
3383
3597
    SpiceCharDeviceInstance* char_device =
3384
3598
            SPICE_CONTAINEROF(sin, SpiceCharDeviceInstance, base);
3385
 
 
3386
 
    spice_printerr("CHAR_DEVICE %s", char_device->subtype);
 
3599
    SpiceCharDeviceState *dev_state = NULL;
 
3600
 
 
3601
    spice_assert(s == reds);
 
3602
 
 
3603
    spice_info("CHAR_DEVICE %s", char_device->subtype);
3387
3604
    if (strcmp(char_device->subtype, SUBTYPE_VDAGENT) == 0) {
3388
3605
        if (vdagent) {
3389
 
            spice_printerr("vdagent already attached");
 
3606
            spice_warning("vdagent already attached");
3390
3607
            return -1;
3391
3608
        }
3392
 
        char_device->st = &vdagent_char_device_state;
3393
 
        attach_to_red_agent(char_device);
 
3609
        dev_state = attach_to_red_agent(char_device);
3394
3610
    }
3395
3611
#ifdef USE_SMARTCARD
3396
3612
    else if (strcmp(char_device->subtype, SUBTYPE_SMARTCARD) == 0) {
3397
 
        if (smartcard_device_connect(char_device) == -1) {
 
3613
        if (!(dev_state = smartcard_device_connect(char_device))) {
3398
3614
            return -1;
3399
3615
        }
3400
3616
    }
3401
3617
#endif
3402
3618
    else if (strcmp(char_device->subtype, SUBTYPE_USBREDIR) == 0) {
3403
 
        spicevmc_device_connect(char_device, SPICE_CHANNEL_USBREDIR);
 
3619
        dev_state = spicevmc_device_connect(char_device, SPICE_CHANNEL_USBREDIR);
 
3620
    }
 
3621
    else if (strcmp(char_device->subtype, SUBTYPE_PORT) == 0) {
 
3622
        dev_state = spicevmc_device_connect(char_device, SPICE_CHANNEL_PORT);
 
3623
    }
 
3624
 
 
3625
    if (dev_state) {
 
3626
        spice_assert(char_device->st);
 
3627
        /* setting the char_device state to "started" for backward compatibily with
 
3628
         * qemu releases that don't call spice api for start/stop (not implemented yet) */
 
3629
        if (reds->vm_running) {
 
3630
            spice_char_device_start(char_device->st);
 
3631
        }
 
3632
        reds_char_device_add_state(char_device->st);
 
3633
    } else {
 
3634
        spice_warning("failed to create device state for %s", char_device->subtype);
 
3635
        return -1;
3404
3636
    }
3405
3637
    return 0;
3406
3638
}
3410
3642
    SpiceCharDeviceInstance* char_device =
3411
3643
            SPICE_CONTAINEROF(sin, SpiceCharDeviceInstance, base);
3412
3644
 
3413
 
    spice_printerr("remove CHAR_DEVICE %s", char_device->subtype);
 
3645
    spice_info("remove CHAR_DEVICE %s", char_device->subtype);
3414
3646
    if (strcmp(char_device->subtype, SUBTYPE_VDAGENT) == 0) {
3415
3647
        if (vdagent) {
3416
3648
            reds_agent_remove();
3421
3653
        smartcard_device_disconnect(char_device);
3422
3654
    }
3423
3655
#endif
3424
 
    else if (strcmp(char_device->subtype, SUBTYPE_USBREDIR) == 0) {
 
3656
    else if (strcmp(char_device->subtype, SUBTYPE_USBREDIR) == 0 ||
 
3657
             strcmp(char_device->subtype, SUBTYPE_PORT) == 0) {
3425
3658
        spicevmc_device_disconnect(char_device);
 
3659
    } else {
 
3660
        spice_warning("failed to remove char device %s", char_device->subtype);
3426
3661
    }
 
3662
 
 
3663
    char_device->st = NULL;
3427
3664
}
3428
3665
 
3429
3666
SPICE_GNUC_VISIBLE int spice_server_add_interface(SpiceServer *s,
3434
3671
    spice_assert(reds == s);
3435
3672
 
3436
3673
    if (strcmp(interface->type, SPICE_INTERFACE_KEYBOARD) == 0) {
3437
 
        spice_printerr("SPICE_INTERFACE_KEYBOARD");
 
3674
        spice_info("SPICE_INTERFACE_KEYBOARD");
3438
3675
        if (interface->major_version != SPICE_INTERFACE_KEYBOARD_MAJOR ||
3439
3676
            interface->minor_version > SPICE_INTERFACE_KEYBOARD_MINOR) {
3440
 
            spice_printerr("unsupported keyboard interface");
 
3677
            spice_warning("unsupported keyboard interface");
3441
3678
            return -1;
3442
3679
        }
3443
3680
        if (inputs_set_keyboard(SPICE_CONTAINEROF(sin, SpiceKbdInstance, base)) != 0) {
3444
3681
            return -1;
3445
3682
        }
3446
3683
    } else if (strcmp(interface->type, SPICE_INTERFACE_MOUSE) == 0) {
3447
 
        spice_printerr("SPICE_INTERFACE_MOUSE");
 
3684
        spice_info("SPICE_INTERFACE_MOUSE");
3448
3685
        if (interface->major_version != SPICE_INTERFACE_MOUSE_MAJOR ||
3449
3686
            interface->minor_version > SPICE_INTERFACE_MOUSE_MINOR) {
3450
 
            spice_printerr("unsupported mouse interface");
 
3687
            spice_warning("unsupported mouse interface");
3451
3688
            return -1;
3452
3689
        }
3453
3690
        if (inputs_set_mouse(SPICE_CONTAINEROF(sin, SpiceMouseInstance, base)) != 0) {
3456
3693
    } else if (strcmp(interface->type, SPICE_INTERFACE_QXL) == 0) {
3457
3694
        QXLInstance *qxl;
3458
3695
 
3459
 
        spice_printerr("SPICE_INTERFACE_QXL");
 
3696
        spice_info("SPICE_INTERFACE_QXL");
3460
3697
        if (interface->major_version != SPICE_INTERFACE_QXL_MAJOR ||
3461
3698
            interface->minor_version > SPICE_INTERFACE_QXL_MINOR) {
3462
 
            spice_printerr("unsupported qxl interface");
 
3699
            spice_warning("unsupported qxl interface");
3463
3700
            return -1;
3464
3701
        }
3465
3702
 
3469
3706
        qxl->st->dispatcher = red_dispatcher_init(qxl);
3470
3707
 
3471
3708
    } else if (strcmp(interface->type, SPICE_INTERFACE_TABLET) == 0) {
3472
 
        spice_printerr("SPICE_INTERFACE_TABLET");
 
3709
        spice_info("SPICE_INTERFACE_TABLET");
3473
3710
        if (interface->major_version != SPICE_INTERFACE_TABLET_MAJOR ||
3474
3711
            interface->minor_version > SPICE_INTERFACE_TABLET_MINOR) {
3475
 
            spice_printerr("unsupported tablet interface");
 
3712
            spice_warning("unsupported tablet interface");
3476
3713
            return -1;
3477
3714
        }
3478
3715
        if (inputs_set_tablet(SPICE_CONTAINEROF(sin, SpiceTabletInstance, base)) != 0) {
3484
3721
        }
3485
3722
 
3486
3723
    } else if (strcmp(interface->type, SPICE_INTERFACE_PLAYBACK) == 0) {
3487
 
        spice_printerr("SPICE_INTERFACE_PLAYBACK");
 
3724
        spice_info("SPICE_INTERFACE_PLAYBACK");
3488
3725
        if (interface->major_version != SPICE_INTERFACE_PLAYBACK_MAJOR ||
3489
3726
            interface->minor_version > SPICE_INTERFACE_PLAYBACK_MINOR) {
3490
 
            spice_printerr("unsupported playback interface");
 
3727
            spice_warning("unsupported playback interface");
3491
3728
            return -1;
3492
3729
        }
3493
3730
        snd_attach_playback(SPICE_CONTAINEROF(sin, SpicePlaybackInstance, base));
3494
3731
 
3495
3732
    } else if (strcmp(interface->type, SPICE_INTERFACE_RECORD) == 0) {
3496
 
        spice_printerr("SPICE_INTERFACE_RECORD");
 
3733
        spice_info("SPICE_INTERFACE_RECORD");
3497
3734
        if (interface->major_version != SPICE_INTERFACE_RECORD_MAJOR ||
3498
3735
            interface->minor_version > SPICE_INTERFACE_RECORD_MINOR) {
3499
 
            spice_printerr("unsupported record interface");
 
3736
            spice_warning("unsupported record interface");
3500
3737
            return -1;
3501
3738
        }
3502
3739
        snd_attach_record(SPICE_CONTAINEROF(sin, SpiceRecordInstance, base));
3504
3741
    } else if (strcmp(interface->type, SPICE_INTERFACE_CHAR_DEVICE) == 0) {
3505
3742
        if (interface->major_version != SPICE_INTERFACE_CHAR_DEVICE_MAJOR ||
3506
3743
            interface->minor_version > SPICE_INTERFACE_CHAR_DEVICE_MINOR) {
3507
 
            spice_printerr("unsupported char device interface");
 
3744
            spice_warning("unsupported char device interface");
3508
3745
            return -1;
3509
3746
        }
3510
3747
        spice_server_char_device_add_interface(s, sin);
3512
3749
    } else if (strcmp(interface->type, SPICE_INTERFACE_NET_WIRE) == 0) {
3513
3750
#ifdef USE_TUNNEL
3514
3751
        SpiceNetWireInstance *net;
3515
 
        spice_printerr("SPICE_INTERFACE_NET_WIRE");
 
3752
        spice_info("SPICE_INTERFACE_NET_WIRE");
3516
3753
        if (red_tunnel) {
3517
 
            spice_printerr("net wire already attached");
 
3754
            spice_warning("net wire already attached");
3518
3755
            return -1;
3519
3756
        }
3520
3757
        if (interface->major_version != SPICE_INTERFACE_NET_WIRE_MAJOR ||
3521
3758
            interface->minor_version > SPICE_INTERFACE_NET_WIRE_MINOR) {
3522
 
            spice_printerr("unsupported net wire interface");
 
3759
            spice_warning("unsupported net wire interface");
3523
3760
            return -1;
3524
3761
        }
3525
3762
        net = SPICE_CONTAINEROF(sin, SpiceNetWireInstance, base);
3526
3763
        net->st = spice_new0(SpiceNetWireState, 1);
3527
3764
        red_tunnel = red_tunnel_attach(core, net);
3528
3765
#else
3529
 
        spice_printerr("unsupported net wire interface");
 
3766
        spice_warning("unsupported net wire interface");
3530
3767
        return -1;
3531
3768
#endif
3532
3769
    } else if (strcmp(interface->type, SPICE_INTERFACE_MIGRATION) == 0) {
3533
 
        spice_printerr("SPICE_INTERFACE_MIGRATION");
 
3770
        spice_info("SPICE_INTERFACE_MIGRATION");
3534
3771
        if (migration_interface) {
3535
 
            spice_printerr("already have migration");
 
3772
            spice_warning("already have migration");
3536
3773
            return -1;
3537
3774
        }
3538
3775
 
3539
3776
        if (interface->major_version != SPICE_INTERFACE_MIGRATION_MAJOR ||
3540
3777
            interface->minor_version > SPICE_INTERFACE_MIGRATION_MINOR) {
3541
 
            spice_printerr("unsupported migration interface");
 
3778
            spice_warning("unsupported migration interface");
3542
3779
            return -1;
3543
3780
        }
3544
3781
        migration_interface = SPICE_CONTAINEROF(sin, SpiceMigrateInstance, base);
3553
3790
    const SpiceBaseInterface *interface = sin->sif;
3554
3791
 
3555
3792
    if (strcmp(interface->type, SPICE_INTERFACE_TABLET) == 0) {
3556
 
        spice_printerr("remove SPICE_INTERFACE_TABLET");
 
3793
        spice_info("remove SPICE_INTERFACE_TABLET");
3557
3794
        inputs_detach_tablet(SPICE_CONTAINEROF(sin, SpiceTabletInstance, base));
3558
3795
        reds_update_mouse_mode();
3559
3796
    } else if (strcmp(interface->type, SPICE_INTERFACE_PLAYBACK) == 0) {
3560
 
        spice_printerr("remove SPICE_INTERFACE_PLAYBACK");
 
3797
        spice_info("remove SPICE_INTERFACE_PLAYBACK");
3561
3798
        snd_detach_playback(SPICE_CONTAINEROF(sin, SpicePlaybackInstance, base));
3562
 
 
3563
3799
    } else if (strcmp(interface->type, SPICE_INTERFACE_RECORD) == 0) {
3564
 
        spice_printerr("remove SPICE_INTERFACE_RECORD");
 
3800
        spice_info("remove SPICE_INTERFACE_RECORD");
3565
3801
        snd_detach_record(SPICE_CONTAINEROF(sin, SpiceRecordInstance, base));
3566
 
 
3567
3802
    } else if (strcmp(interface->type, SPICE_INTERFACE_CHAR_DEVICE) == 0) {
3568
3803
        spice_server_char_device_remove_interface(sin);
3569
3804
    } else {
3570
 
        spice_error("VD_INTERFACE_REMOVING unsupported");
 
3805
        spice_warning("VD_INTERFACE_REMOVING unsupported");
3571
3806
        return -1;
3572
3807
    }
3573
3808
 
3574
3809
    return 0;
3575
3810
}
3576
3811
 
3577
 
static void free_external_agent_buff(VDIPortBuf *in_buf)
3578
 
{
3579
 
    VDIPortState *state = &reds->agent_state;
3580
 
 
3581
 
    ring_add(&state->external_bufs, &in_buf->link);
3582
 
    add_token();
3583
 
}
3584
 
 
3585
 
static void free_internal_agent_buff(VDIPortBuf *in_buf)
3586
 
{
3587
 
    VDIPortState *state = &reds->agent_state;
3588
 
 
3589
 
    ring_add(&state->internal_bufs, &in_buf->link);
3590
 
    if (inputs_inited() && reds->pending_mouse_event) {
3591
 
        reds_handle_agent_mouse_event(inputs_get_mouse_state());
3592
 
    }
3593
 
}
3594
 
 
3595
3812
static void init_vd_agent_resources(void)
3596
3813
{
3597
3814
    VDIPortState *state = &reds->agent_state;
3598
3815
    int i;
3599
3816
 
3600
 
    ring_init(&state->external_bufs);
3601
 
    ring_init(&state->internal_bufs);
3602
 
    ring_init(&state->write_queue);
3603
3817
    ring_init(&state->read_bufs);
3604
3818
    agent_msg_filter_init(&state->write_filter, agent_copypaste, TRUE);
3605
3819
    agent_msg_filter_init(&state->read_filter, agent_copypaste, TRUE);
3606
3820
 
3607
 
    state->read_state = VDI_PORT_READ_STATE_READ_HADER;
 
3821
    state->read_state = VDI_PORT_READ_STATE_READ_HEADER;
3608
3822
    state->recive_pos = (uint8_t *)&state->vdi_chunk_header;
3609
3823
    state->recive_len = sizeof(state->vdi_chunk_header);
3610
3824
 
3611
 
    for (i = 0; i < REDS_AGENT_WINDOW_SIZE; i++) {
3612
 
        VDAgentExtBuf *buf = spice_new0(VDAgentExtBuf, 1);
3613
 
        ring_item_init(&buf->base.link);
3614
 
        buf->base.chunk_header.port = VDP_CLIENT_PORT;
3615
 
        buf->base.free = free_external_agent_buff;
3616
 
        ring_add(&reds->agent_state.external_bufs, &buf->base.link);
3617
 
    }
3618
 
 
3619
 
    for (i = 0; i < REDS_NUM_INTERNAL_AGENT_MESSAGES; i++) {
3620
 
        VDInternalBuf *buf = spice_new0(VDInternalBuf, 1);
3621
 
        ring_item_init(&buf->base.link);
3622
 
        buf->base.free = free_internal_agent_buff;
3623
 
        buf->base.chunk_header.port = VDP_SERVER_PORT;
3624
 
        buf->base.chunk_header.size = sizeof(VDAgentMessage) + sizeof(VDAgentMouseState);
3625
 
        buf->header.protocol = VD_AGENT_PROTOCOL;
3626
 
        buf->header.type = VD_AGENT_MOUSE_STATE;
3627
 
        buf->header.opaque = 0;
3628
 
        buf->header.size = sizeof(VDAgentMouseState);
3629
 
        ring_add(&reds->agent_state.internal_bufs, &buf->base.link);
3630
 
    }
3631
 
 
3632
3825
    for (i = 0; i < REDS_VDI_PORT_NUM_RECEIVE_BUFFS; i++) {
3633
3826
        VDIReadBuf *buf = spice_new0(VDIReadBuf, 1);
3634
3827
        ring_item_init(&buf->link);
3640
3833
 
3641
3834
static int do_spice_init(SpiceCoreInterface *core_interface)
3642
3835
{
3643
 
    spice_printerr("starting %s", version_string);
 
3836
    spice_info("starting %s", version_string);
3644
3837
 
3645
3838
    if (core_interface->base.major_version != SPICE_INTERFACE_CORE_MAJOR) {
3646
 
        spice_printerr("bad core interface version");
 
3839
        spice_warning("bad core interface version");
3647
3840
        goto err;
3648
3841
    }
3649
3842
    core = core_interface;
3655
3848
    main_dispatcher_init(core);
3656
3849
    ring_init(&reds->channels);
3657
3850
    ring_init(&reds->mig_target_clients);
 
3851
    ring_init(&reds->char_devs_states);
 
3852
    ring_init(&reds->mig_wait_disconnect_clients);
 
3853
    reds->vm_running = TRUE; /* for backward compatibility */
3658
3854
 
3659
3855
    if (!(reds->mig_timer = core->timer_add(migrate_timeout, NULL))) {
3660
3856
        spice_error("migration timer create failed");
3661
3857
    }
3662
 
    if (!(reds->vdi_port_write_timer = core->timer_add(vdi_port_write_retry, NULL)))
3663
 
    {
3664
 
        spice_error("vdi port write timer create failed");
3665
 
    }
3666
 
    reds->vdi_port_write_timer_started = FALSE;
3667
3858
 
3668
3859
#ifdef RED_STATISTICS
3669
3860
    int shm_name_len;
3700
3891
        goto err;
3701
3892
    }
3702
3893
    if (reds->secure_listen_socket != -1) {
3703
 
        reds_init_ssl();
 
3894
        if (reds_init_ssl() < 0) {
 
3895
            goto err;
 
3896
        }
3704
3897
    }
3705
3898
#if HAVE_SASL
3706
3899
    int saslerr;
3716
3909
    inputs_init();
3717
3910
 
3718
3911
    reds->mouse_mode = SPICE_MOUSE_MODE_SERVER;
 
3912
 
 
3913
    reds_client_monitors_config_cleanup();
 
3914
 
3719
3915
    reds->allow_multiple_clients = getenv(SPICE_DEBUG_ALLOW_MC_ENV) != NULL;
3720
3916
    if (reds->allow_multiple_clients) {
3721
 
        spice_printerr("spice: allowing multiple client connections");
 
3917
        spice_warning("spice: allowing multiple client connections (crashy)");
3722
3918
    }
3723
3919
    atexit(reds_exit);
3724
3920
    return 0;
3788
3984
SPICE_GNUC_VISIBLE void spice_server_set_addr(SpiceServer *s, const char *addr, int flags)
3789
3985
{
3790
3986
    spice_assert(reds == s);
3791
 
    strncpy(spice_addr, addr, sizeof(spice_addr));
 
3987
    g_strlcpy(spice_addr, addr, sizeof(spice_addr));
3792
3988
    if (flags & SPICE_ADDR_FLAG_IPV4_ONLY) {
3793
3989
        spice_family = PF_INET;
3794
3990
    }
3804
4000
    return 0;
3805
4001
}
3806
4002
 
 
4003
SPICE_GNUC_VISIBLE int spice_server_set_exit_on_disconnect(SpiceServer *s, int flag)
 
4004
{
 
4005
    spice_assert(reds == s);
 
4006
    exit_on_disconnect = !!flag;
 
4007
    return 0;
 
4008
}
 
4009
 
3807
4010
SPICE_GNUC_VISIBLE int spice_server_set_noauth(SpiceServer *s)
3808
4011
{
3809
4012
    spice_assert(reds == s);
3872
4075
        taTicket.expiration_time = now + lifetime;
3873
4076
    }
3874
4077
    if (passwd != NULL) {
3875
 
        strncpy(taTicket.password, passwd, sizeof(taTicket.password));
 
4078
        g_strlcpy(taTicket.password, passwd, sizeof(taTicket.password));
3876
4079
    } else {
3877
4080
        memset(taTicket.password, 0, sizeof(taTicket.password));
3878
4081
        taTicket.expiration_time = 0;
3896
4099
    memset(&ssl_parameters, 0, sizeof(ssl_parameters));
3897
4100
 
3898
4101
    spice_secure_port = port;
3899
 
    strncpy(ssl_parameters.ca_certificate_file, ca_cert_file,
3900
 
            sizeof(ssl_parameters.ca_certificate_file)-1);
3901
 
    strncpy(ssl_parameters.certs_file, certs_file,
3902
 
            sizeof(ssl_parameters.certs_file)-1);
3903
 
    strncpy(ssl_parameters.private_key_file, private_key_file,
3904
 
            sizeof(ssl_parameters.private_key_file)-1);
 
4102
    g_strlcpy(ssl_parameters.ca_certificate_file, ca_cert_file,
 
4103
              sizeof(ssl_parameters.ca_certificate_file));
 
4104
    g_strlcpy(ssl_parameters.certs_file, certs_file,
 
4105
              sizeof(ssl_parameters.certs_file));
 
4106
    g_strlcpy(ssl_parameters.private_key_file, private_key_file,
 
4107
              sizeof(ssl_parameters.private_key_file));
3905
4108
 
3906
4109
    if (key_passwd) {
3907
 
        strncpy(ssl_parameters.keyfile_password, key_passwd,
3908
 
                sizeof(ssl_parameters.keyfile_password)-1);
 
4110
        g_strlcpy(ssl_parameters.keyfile_password, key_passwd,
 
4111
                  sizeof(ssl_parameters.keyfile_password));
3909
4112
    }
3910
4113
    if (ciphersuite) {
3911
 
        strncpy(ssl_parameters.ciphersuite, ciphersuite,
3912
 
                sizeof(ssl_parameters.ciphersuite)-1);
 
4114
        g_strlcpy(ssl_parameters.ciphersuite, ciphersuite,
 
4115
                  sizeof(ssl_parameters.ciphersuite));
3913
4116
    }
3914
4117
    if (dh_key_file) {
3915
 
        strncpy(ssl_parameters.dh_key_file, dh_key_file,
3916
 
                sizeof(ssl_parameters.dh_key_file)-1);
 
4118
        g_strlcpy(ssl_parameters.dh_key_file, dh_key_file,
 
4119
                  sizeof(ssl_parameters.dh_key_file));
3917
4120
    }
3918
4121
    return 0;
3919
4122
}
3936
4139
{
3937
4140
    spice_assert(reds == s);
3938
4141
    if (comp == SPICE_WAN_COMPRESSION_INVALID) {
3939
 
        spice_printerr("invalid jpeg state");
 
4142
        spice_error("invalid jpeg state");
3940
4143
        return -1;
3941
4144
    }
3942
4145
    // todo: support dynamically changing the state
3948
4151
{
3949
4152
    spice_assert(reds == s);
3950
4153
    if (comp == SPICE_WAN_COMPRESSION_INVALID) {
3951
 
        spice_printerr("invalid zlib_glz state");
 
4154
        spice_error("invalid zlib_glz state");
3952
4155
        return -1;
3953
4156
    }
3954
4157
    // todo: support dynamically changing the state
4097
4300
                                                    const char* cert_subject)
4098
4301
{
4099
4302
    SpiceMigrateInterface *sif;
 
4303
    int try_seamless;
4100
4304
 
4101
 
    spice_printerr("");
 
4305
    spice_info(NULL);
4102
4306
    spice_assert(migration_interface);
4103
4307
    spice_assert(reds == s);
4104
4308
 
4105
4309
    if (reds->expect_migrate) {
4106
 
        spice_printerr("warning: consecutive calls without migration. Canceling previous call");
4107
 
        main_channel_migrate_complete(reds->main_channel, FALSE);
 
4310
        spice_info("consecutive calls without migration. Canceling previous call");
 
4311
        main_channel_migrate_src_complete(reds->main_channel, FALSE);
4108
4312
    }
4109
4313
 
4110
4314
    sif = SPICE_CONTAINEROF(migration_interface->base.sif, SpiceMigrateInterface, base);
4116
4320
 
4117
4321
    reds->expect_migrate = TRUE;
4118
4322
 
 
4323
    /*
 
4324
     * seamless migration support was added to the client after the support in
 
4325
     * agent_connect_tokens, so there shouldn't be contradicition - if
 
4326
     * the client is capable of seamless migration, it is capbable of agent_connected_tokens.
 
4327
     * The demand for agent_connected_tokens support is in order to assure that if migration
 
4328
     * occured when the agent was not connected, the tokens state after migration will still
 
4329
     * be valid (see reds_reset_vdp for more details).
 
4330
     */
 
4331
    try_seamless = reds->seamless_migration_enabled &&
 
4332
                   red_channel_test_remote_cap(&reds->main_channel->base,
 
4333
                   SPICE_MAIN_CAP_AGENT_CONNECTED_TOKENS);
4119
4334
    /* main channel will take care of clients that are still during migration (at target)*/
4120
 
    if (main_channel_migrate_connect(reds->main_channel, reds->mig_spice)) {
 
4335
    if (main_channel_migrate_connect(reds->main_channel, reds->mig_spice,
 
4336
                                     try_seamless)) {
4121
4337
        reds_mig_started();
4122
4338
    } else {
4123
4339
        if (reds->num_clients == 0) {
4124
4340
            reds_mig_release();
4125
 
            spice_printerr("no client connected");
 
4341
            spice_info("no client connected");
4126
4342
        }
4127
4343
        sif->migrate_connect_complete(migration_interface);
4128
4344
    }
4134
4350
                                          int port, int secure_port,
4135
4351
                                          const char* cert_subject)
4136
4352
{
4137
 
    spice_printerr("");
 
4353
    spice_info(NULL);
4138
4354
    spice_assert(!migration_interface);
4139
4355
    spice_assert(reds == s);
4140
4356
 
4147
4363
SPICE_GNUC_VISIBLE int spice_server_migrate_start(SpiceServer *s)
4148
4364
{
4149
4365
    spice_assert(reds == s);
4150
 
    spice_printerr("");
 
4366
    spice_info(NULL);
4151
4367
    if (!reds->mig_spice) {
4152
4368
        return -1;
4153
4369
    }
4173
4389
    SpiceMigrateInterface *sif;
4174
4390
    int ret = 0;
4175
4391
 
4176
 
    spice_printerr("");
 
4392
    spice_info(NULL);
4177
4393
 
4178
4394
    spice_assert(migration_interface);
4179
4395
    spice_assert(reds == s);
4180
4396
 
4181
4397
    sif = SPICE_CONTAINEROF(migration_interface->base.sif, SpiceMigrateInterface, base);
4182
 
    if (!reds->expect_migrate && reds->num_clients) {
4183
 
        spice_printerr("spice_server_migrate_info was not called, disconnecting clients");
 
4398
    if (completed && !reds->expect_migrate && reds->num_clients) {
 
4399
        spice_warning("spice_server_migrate_info was not called, disconnecting clients");
4184
4400
        reds_disconnect();
4185
4401
        ret = -1;
4186
4402
        goto complete;
4187
4403
    }
4188
4404
 
4189
4405
    reds->expect_migrate = FALSE;
 
4406
    if (!reds_main_channel_connected()) {
 
4407
        spice_info("no peer connected");
 
4408
        goto complete;
 
4409
    }
4190
4410
    reds_mig_finished(completed);
4191
 
    ret = 0;
 
4411
    return 0;
4192
4412
complete:
4193
4413
    if (sif->migrate_end_complete) {
4194
4414
        sif->migrate_end_complete(migration_interface);
4200
4420
SPICE_GNUC_VISIBLE int spice_server_migrate_switch(SpiceServer *s)
4201
4421
{
4202
4422
    spice_assert(reds == s);
4203
 
    spice_printerr("");
 
4423
    spice_info(NULL);
4204
4424
    if (!reds->num_clients) {
4205
4425
       return 0;
4206
4426
    }
4209
4429
    return 0;
4210
4430
}
4211
4431
 
 
4432
SPICE_GNUC_VISIBLE void spice_server_vm_start(SpiceServer *s)
 
4433
{
 
4434
    RingItem *item;
 
4435
 
 
4436
    spice_assert(s == reds);
 
4437
    reds->vm_running = TRUE;
 
4438
    RING_FOREACH(item, &reds->char_devs_states) {
 
4439
        SpiceCharDeviceStateItem *st_item;
 
4440
 
 
4441
        st_item = SPICE_CONTAINEROF(item, SpiceCharDeviceStateItem, link);
 
4442
        spice_char_device_start(st_item->st);
 
4443
    }
 
4444
    red_dispatcher_on_vm_start();
 
4445
}
 
4446
 
 
4447
SPICE_GNUC_VISIBLE void spice_server_vm_stop(SpiceServer *s)
 
4448
{
 
4449
    RingItem *item;
 
4450
 
 
4451
    spice_assert(s == reds);
 
4452
    reds->vm_running = FALSE;
 
4453
    RING_FOREACH(item, &reds->char_devs_states) {
 
4454
        SpiceCharDeviceStateItem *st_item;
 
4455
 
 
4456
        st_item = SPICE_CONTAINEROF(item, SpiceCharDeviceStateItem, link);
 
4457
        spice_char_device_stop(st_item->st);
 
4458
    }
 
4459
    red_dispatcher_on_vm_stop();
 
4460
}
 
4461
 
 
4462
SPICE_GNUC_VISIBLE void spice_server_set_seamless_migration(SpiceServer *s, int enable)
 
4463
{
 
4464
    spice_assert(s == reds);
 
4465
    /* seamless migration is not supported with multiple clients */
 
4466
    reds->seamless_migration_enabled = enable && !reds->allow_multiple_clients;
 
4467
    spice_debug("seamless migration enabled=%d", enable);
 
4468
}
 
4469
 
4212
4470
ssize_t reds_stream_read(RedsStream *s, void *buf, size_t nbyte)
4213
4471
{
4214
4472
    ssize_t ret;
4284
4542
    }
4285
4543
 
4286
4544
    reds_stream_remove_watch(s);
4287
 
    spice_printerr("close socket fd %d", s->socket);
 
4545
    spice_info("close socket fd %d", s->socket);
4288
4546
    close(s->socket);
4289
4547
 
4290
4548
    free(s);