spice-channel: add property total-bytes-read
[spice-gtk:teuf-spice-gtk.git] / gtk / spice-channel.c
1 /* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3    Copyright (C) 2010 Red Hat, Inc.
4
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with this library; if not, see <http://www.gnu.org/licenses/>.
17 */
18 #include "spice-client.h"
19 #include "spice-common.h"
20
21 #include "spice-channel-priv.h"
22 #include "spice-session-priv.h"
23 #include "spice-marshal.h"
24
25 #include <openssl/rsa.h>
26 #include <openssl/evp.h>
27 #include <openssl/x509.h>
28 #include <openssl/ssl.h>
29 #include <openssl/err.h>
30 #include <openssl/x509v3.h>
31 #ifdef HAVE_SYS_SOCKET_H
32 #include <sys/socket.h>
33 #endif
34 #ifdef HAVE_NETINET_IN_H
35 #include <netinet/in.h>
36 #endif
37 #ifdef HAVE_ARPA_INET_H
38 #include <arpa/inet.h>
39 #endif
40 #include <ctype.h>
41
42 #include "gio-coroutine.h"
43
44 static void spice_channel_handle_msg(SpiceChannel *channel, spice_msg_in *msg);
45 static void spice_channel_send_msg(SpiceChannel *channel, spice_msg_out *out, gboolean buffered);
46 static void spice_channel_send_link(SpiceChannel *channel);
47 static void channel_disconnect(SpiceChannel *channel);
48
49 /**
50  * SECTION:spice-channel
51  * @short_description: the base channel class
52  * @title: Spice Channel
53  * @section_id:
54  * @see_also: #SpiceSession, #SpiceMainChannel and other channels
55  * @stability: Stable
56  * @include: spice-channel.h
57  *
58  * #SpiceChannel is the base class for the different kind of Spice
59  * channel connections, such as #SpiceMainChannel, or
60  * #SpiceInputsChannel.
61  */
62
63 /* ------------------------------------------------------------------ */
64 /* gobject glue                                                       */
65
66 #define SPICE_CHANNEL_GET_PRIVATE(obj)                                  \
67     (G_TYPE_INSTANCE_GET_PRIVATE ((obj), SPICE_TYPE_CHANNEL, spice_channel))
68
69 G_DEFINE_TYPE(SpiceChannel, spice_channel, G_TYPE_OBJECT);
70
71 /* Properties */
72 enum {
73     PROP_0,
74     PROP_SESSION,
75     PROP_CHANNEL_TYPE,
76     PROP_CHANNEL_ID,
77     PROP_TOTAL_READ_BYTES,
78 };
79
80 /* Signals */
81 enum {
82     SPICE_CHANNEL_EVENT,
83     SPICE_CHANNEL_OPEN_FD,
84
85     SPICE_CHANNEL_LAST_SIGNAL,
86 };
87
88 static guint signals[SPICE_CHANNEL_LAST_SIGNAL];
89
90 static void spice_channel_iterate_write(SpiceChannel *channel);
91 static void spice_channel_iterate_read(SpiceChannel *channel);
92
93 static void spice_channel_init(SpiceChannel *channel)
94 {
95     spice_channel *c;
96
97     c = channel->priv = SPICE_CHANNEL_GET_PRIVATE(channel);
98
99     c->serial = 1;
100     c->fd = -1;
101     strcpy(c->name, "?");
102     c->caps = g_array_new(FALSE, TRUE, sizeof(guint32));
103     c->common_caps = g_array_new(FALSE, TRUE, sizeof(guint32));
104     c->remote_caps = g_array_new(FALSE, TRUE, sizeof(guint32));
105     c->remote_common_caps = g_array_new(FALSE, TRUE, sizeof(guint32));
106     spice_channel_set_common_capability(channel, SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION);
107 }
108
109 static void spice_channel_constructed(GObject *gobject)
110 {
111     SpiceChannel *channel = SPICE_CHANNEL(gobject);
112     spice_channel *c = channel->priv;
113     const char *desc = spice_channel_type_to_string(c->channel_type);
114
115     snprintf(c->name, sizeof(c->name), "%s-%d:%d",
116              desc ? desc : "unknown", c->channel_type, c->channel_id);
117     SPICE_DEBUG("%s: %s", c->name, __FUNCTION__);
118
119     c->connection_id = spice_session_get_connection_id(c->session);
120     spice_session_channel_new(c->session, channel);
121
122     /* Chain up to the parent class */
123     if (G_OBJECT_CLASS(spice_channel_parent_class)->constructed)
124         G_OBJECT_CLASS(spice_channel_parent_class)->constructed(gobject);
125 }
126
127 static void spice_channel_dispose(GObject *gobject)
128 {
129     SpiceChannel *channel = SPICE_CHANNEL(gobject);
130     spice_channel *c = channel->priv;
131
132     SPICE_DEBUG("%s: %s %p", c->name, __FUNCTION__, gobject);
133
134     if (c->session)
135         spice_session_channel_destroy(c->session, channel);
136
137     spice_channel_disconnect(channel, SPICE_CHANNEL_CLOSED);
138
139     if (c->session) {
140          g_object_unref(c->session);
141          c->session = NULL;
142     }
143
144     /* Chain up to the parent class */
145     if (G_OBJECT_CLASS(spice_channel_parent_class)->dispose)
146         G_OBJECT_CLASS(spice_channel_parent_class)->dispose(gobject);
147 }
148
149 static void spice_channel_finalize(GObject *gobject)
150 {
151     SpiceChannel *channel = SPICE_CHANNEL(gobject);
152     spice_channel *c = channel->priv;
153
154     SPICE_DEBUG("%s: %s %p", c->name, __FUNCTION__, gobject);
155
156     g_idle_remove_by_data (gobject);
157
158     if (c->caps)
159         g_array_free(c->caps, TRUE);
160
161     if (c->common_caps)
162         g_array_free(c->common_caps, TRUE);
163
164     if (c->remote_caps)
165         g_array_free(c->remote_caps, TRUE);
166
167     if (c->remote_common_caps)
168         g_array_free(c->remote_common_caps, TRUE);
169
170     /* Chain up to the parent class */
171     if (G_OBJECT_CLASS(spice_channel_parent_class)->finalize)
172         G_OBJECT_CLASS(spice_channel_parent_class)->finalize(gobject);
173 }
174
175 static void spice_channel_get_property(GObject    *gobject,
176                                        guint       prop_id,
177                                        GValue     *value,
178                                        GParamSpec *pspec)
179 {
180     SpiceChannel *channel = SPICE_CHANNEL(gobject);
181     spice_channel *c = channel->priv;
182
183     switch (prop_id) {
184     case PROP_SESSION:
185         g_value_set_object(value, c->session);
186         break;
187     case PROP_CHANNEL_TYPE:
188         g_value_set_int(value, c->channel_type);
189         break;
190     case PROP_CHANNEL_ID:
191         g_value_set_int(value, c->channel_id);
192         break;
193     case PROP_TOTAL_READ_BYTES:
194         g_value_set_uint(value, c->total_read_bytes);
195         break;
196     default:
197         G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, pspec);
198         break;
199     }
200 }
201
202 G_GNUC_INTERNAL
203 gint spice_channel_get_channel_id(SpiceChannel *channel)
204 {
205     spice_channel *c = SPICE_CHANNEL_GET_PRIVATE(channel);
206
207     g_return_val_if_fail(c != NULL, 0);
208     return c->channel_id;
209 }
210
211 G_GNUC_INTERNAL
212 gint spice_channel_get_channel_type(SpiceChannel *channel)
213 {
214     spice_channel *c = SPICE_CHANNEL_GET_PRIVATE(channel);
215
216     g_return_val_if_fail(c != NULL, 0);
217     return c->channel_type;
218 }
219
220 static void spice_channel_set_property(GObject      *gobject,
221                                        guint         prop_id,
222                                        const GValue *value,
223                                        GParamSpec   *pspec)
224 {
225     SpiceChannel *channel = SPICE_CHANNEL(gobject);
226     spice_channel *c = channel->priv;
227
228     switch (prop_id) {
229     case PROP_SESSION:
230         c->session = g_value_dup_object(value);
231         break;
232     case PROP_CHANNEL_TYPE:
233         c->channel_type = g_value_get_int(value);
234         break;
235     case PROP_CHANNEL_ID:
236         c->channel_id = g_value_get_int(value);
237         break;
238     default:
239         G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, pspec);
240         break;
241     }
242 }
243
244 static void spice_channel_class_init(SpiceChannelClass *klass)
245 {
246     GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
247
248     klass->iterate_write = spice_channel_iterate_write;
249     klass->iterate_read  = spice_channel_iterate_read;
250     klass->channel_disconnect = channel_disconnect;
251
252     gobject_class->constructed  = spice_channel_constructed;
253     gobject_class->dispose      = spice_channel_dispose;
254     gobject_class->finalize     = spice_channel_finalize;
255     gobject_class->get_property = spice_channel_get_property;
256     gobject_class->set_property = spice_channel_set_property;
257     klass->handle_msg           = spice_channel_handle_msg;
258
259     g_object_class_install_property
260         (gobject_class, PROP_SESSION,
261          g_param_spec_object("spice-session",
262                              "Spice session",
263                              "",
264                              SPICE_TYPE_SESSION,
265                              G_PARAM_READWRITE |
266                              G_PARAM_CONSTRUCT_ONLY |
267                              G_PARAM_STATIC_NAME |
268                              G_PARAM_STATIC_NICK |
269                              G_PARAM_STATIC_BLURB));
270
271     g_object_class_install_property
272         (gobject_class, PROP_CHANNEL_TYPE,
273          g_param_spec_int("channel-type",
274                           "Channel type",
275                           "",
276                           -1, INT_MAX, -1,
277                           G_PARAM_READWRITE |
278                           G_PARAM_CONSTRUCT_ONLY |
279                           G_PARAM_STATIC_NAME |
280                           G_PARAM_STATIC_NICK |
281                           G_PARAM_STATIC_BLURB));
282
283     g_object_class_install_property
284         (gobject_class, PROP_CHANNEL_ID,
285          g_param_spec_int("channel-id",
286                           "Channel ID",
287                           "",
288                           -1, INT_MAX, -1,
289                           G_PARAM_READWRITE |
290                           G_PARAM_CONSTRUCT_ONLY |
291                           G_PARAM_STATIC_NAME |
292                           G_PARAM_STATIC_NICK |
293                           G_PARAM_STATIC_BLURB));
294
295     g_object_class_install_property
296         (gobject_class, PROP_TOTAL_READ_BYTES,
297          g_param_spec_uint("total-read-bytes",
298                            "Total read bytes",
299                            "",
300                            0, UINT_MAX, 0,
301                            G_PARAM_READABLE |
302                            G_PARAM_STATIC_STRINGS));
303
304     /**
305      * SpiceChannel::channel-event:
306      * @channel: the channel that emitted the signal
307      * @event: a #SpiceChannelEvent
308      *
309      * The #SpiceChannel::channel-event signal is emitted when the
310      * state of the connection change.
311      **/
312     signals[SPICE_CHANNEL_EVENT] =
313         g_signal_new("channel-event",
314                      G_OBJECT_CLASS_TYPE(gobject_class),
315                      G_SIGNAL_RUN_FIRST,
316                      G_STRUCT_OFFSET(SpiceChannelClass, channel_event),
317                      NULL, NULL,
318                      g_cclosure_marshal_VOID__INT,
319                      G_TYPE_NONE,
320                      1,
321                      G_TYPE_INT);
322
323     /**
324      * SpiceChannel::open-fd:
325      * @channel: the channel that emitted the signal
326      * @with_tls: wether TLS connection is requested
327      *
328      * The #SpiceChannel::open-fd signal is emitted when a new
329      * connection is requested. This signal is emitted when the
330      * connection is made with spice_session_open_fd().
331      **/
332     signals[SPICE_CHANNEL_OPEN_FD] =
333         g_signal_new("open-fd",
334                      G_OBJECT_CLASS_TYPE(gobject_class),
335                      G_SIGNAL_RUN_FIRST,
336                      G_STRUCT_OFFSET(SpiceChannelClass, open_fd),
337                      NULL, NULL,
338                      g_cclosure_marshal_VOID__INT,
339                      G_TYPE_NONE,
340                      1,
341                      G_TYPE_INT);
342
343     g_type_class_add_private(klass, sizeof(spice_channel));
344
345     SSL_library_init();
346     SSL_load_error_strings();
347 }
348
349 /* ---------------------------------------------------------------- */
350 /* private msg api                                                  */
351
352 G_GNUC_INTERNAL
353 spice_msg_in *spice_msg_in_new(SpiceChannel *channel)
354 {
355     spice_msg_in *in;
356
357     g_return_val_if_fail(channel != NULL, NULL);
358
359     in = spice_new0(spice_msg_in, 1);
360     in->refcount = 1;
361     in->channel  = channel;
362     return in;
363 }
364
365 G_GNUC_INTERNAL
366 spice_msg_in *spice_msg_in_sub_new(SpiceChannel *channel, spice_msg_in *parent,
367                                    SpiceSubMessage *sub)
368 {
369     spice_msg_in *in;
370
371     g_return_val_if_fail(channel != NULL, NULL);
372
373     in = spice_msg_in_new(channel);
374     in->header.type = sub->type;
375     in->header.size = sub->size;
376     in->data = (uint8_t*)(sub+1);
377     in->dpos = sub->size;
378     in->parent = parent;
379     spice_msg_in_ref(parent);
380     return in;
381 }
382
383 G_GNUC_INTERNAL
384 void spice_msg_in_ref(spice_msg_in *in)
385 {
386     g_return_if_fail(in != NULL);
387
388     in->refcount++;
389 }
390
391 G_GNUC_INTERNAL
392 void spice_msg_in_unref(spice_msg_in *in)
393 {
394     g_return_if_fail(in != NULL);
395
396     in->refcount--;
397     if (in->refcount > 0)
398         return;
399     if (in->parsed)
400         in->pfree(in->parsed);
401     if (in->parent) {
402         spice_msg_in_unref(in->parent);
403     } else {
404         free(in->data);
405     }
406     free(in);
407 }
408
409 G_GNUC_INTERNAL
410 int spice_msg_in_type(spice_msg_in *in)
411 {
412     g_return_val_if_fail(in != NULL, -1);
413
414     return in->header.type;
415 }
416
417 G_GNUC_INTERNAL
418 void *spice_msg_in_parsed(spice_msg_in *in)
419 {
420     g_return_val_if_fail(in != NULL, NULL);
421
422     return in->parsed;
423 }
424
425 G_GNUC_INTERNAL
426 void *spice_msg_in_raw(spice_msg_in *in, int *len)
427 {
428     g_return_val_if_fail(in != NULL, NULL);
429     g_return_val_if_fail(len != NULL, NULL);
430
431     *len = in->dpos;
432     return in->data;
433 }
434
435 static void hexdump(char *prefix, unsigned char *data, int len)
436 {
437     int i;
438
439     for (i = 0; i < len; i++) {
440         if (i % 16 == 0)
441             fprintf(stderr, "%s:", prefix);
442         if (i % 4 == 0)
443             fprintf(stderr, " ");
444         fprintf(stderr, " %02x", data[i]);
445         if (i % 16 == 15)
446             fprintf(stderr, "\n");
447     }
448     if (i % 16 != 0)
449         fprintf(stderr, "\n");
450 }
451
452 G_GNUC_INTERNAL
453 void spice_msg_in_hexdump(spice_msg_in *in)
454 {
455     spice_channel *c = in->channel->priv;
456
457     fprintf(stderr, "--\n<< hdr: %s serial %" PRIu64 " type %d size %d sub-list %d\n",
458             c->name, in->header.serial, in->header.type,
459             in->header.size, in->header.sub_list);
460     hexdump("<< msg", in->data, in->dpos);
461 }
462
463 G_GNUC_INTERNAL
464 void spice_msg_out_hexdump(spice_msg_out *out, unsigned char *data, int len)
465 {
466     spice_channel *c = out->channel->priv;
467
468     fprintf(stderr, "--\n>> hdr: %s serial %" PRIu64 " type %d size %d sub-list %d\n",
469             c->name, out->header->serial, out->header->type,
470             out->header->size, out->header->sub_list);
471     hexdump(">> msg", data, len);
472 }
473
474 G_GNUC_INTERNAL
475 spice_msg_out *spice_msg_out_new(SpiceChannel *channel, int type)
476 {
477     spice_channel *c = channel->priv;
478     spice_msg_out *out;
479
480     g_return_val_if_fail(c != NULL, NULL);
481
482     out = spice_new0(spice_msg_out, 1);
483     out->refcount = 1;
484     out->channel  = channel;
485
486     out->marshallers = c->marshallers;
487     out->marshaller = spice_marshaller_new();
488     out->header = (SpiceDataHeader *)
489         spice_marshaller_reserve_space(out->marshaller, sizeof(SpiceDataHeader));
490     spice_marshaller_set_base(out->marshaller, sizeof(SpiceDataHeader));
491     out->header->serial = c->serial++;
492     out->header->type = type;
493     out->header->sub_list = 0;
494     return out;
495 }
496
497 G_GNUC_INTERNAL
498 void spice_msg_out_ref(spice_msg_out *out)
499 {
500     g_return_if_fail(out != NULL);
501
502     out->refcount++;
503 }
504
505 G_GNUC_INTERNAL
506 void spice_msg_out_unref(spice_msg_out *out)
507 {
508     g_return_if_fail(out != NULL);
509
510     out->refcount--;
511     if (out->refcount > 0)
512         return;
513     spice_marshaller_destroy(out->marshaller);
514     free(out);
515 }
516
517 /* system context */
518 G_GNUC_INTERNAL
519 void spice_msg_out_send(spice_msg_out *out)
520 {
521     g_return_if_fail(out != NULL);
522
523     out->header->size =
524         spice_marshaller_get_total_size(out->marshaller) - sizeof(SpiceDataHeader);
525     spice_channel_send_msg(out->channel, out, TRUE);
526
527     /* TODO: we currently flush/wakeup immediately all buffered messages */
528     spice_channel_wakeup(out->channel);
529 }
530
531 /* coroutine context */
532 G_GNUC_INTERNAL
533 void spice_msg_out_send_internal(spice_msg_out *out)
534 {
535     g_return_if_fail(out != NULL);
536
537     out->header->size =
538         spice_marshaller_get_total_size(out->marshaller) - sizeof(SpiceDataHeader);
539     spice_channel_send_msg(out->channel, out, FALSE);
540 }
541
542 /* ---------------------------------------------------------------- */
543
544 struct SPICE_CHANNEL_EVENT {
545     SpiceChannelEvent event;
546 };
547
548 /* main context */
549 static void do_emit_main_context(GObject *object, int signum, gpointer params)
550 {
551     switch (signum) {
552     case SPICE_CHANNEL_EVENT: {
553         struct SPICE_CHANNEL_EVENT *p = params;
554         g_signal_emit(object, signals[signum], 0, p->event);
555         break;
556     }
557     case SPICE_CHANNEL_OPEN_FD:
558         g_warning("this signal is only sent directly from main context");
559         break;
560     default:
561         g_warn_if_reached();
562     }
563 }
564
565 /*
566  * Write all 'data' of length 'datalen' bytes out to
567  * the wire
568  */
569 /* coroutine context */
570 static void spice_channel_flush_wire(SpiceChannel *channel,
571                                      const void *data,
572                                      size_t datalen)
573 {
574     spice_channel *c = channel->priv;
575     const char *ptr = data;
576     size_t offset = 0;
577     GIOCondition cond;
578
579     while (offset < datalen) {
580         int ret;
581
582         if (c->has_error) return;
583
584         cond = 0;
585         if (c->tls) {
586             ret = SSL_write(c->ssl, ptr+offset, datalen-offset);
587             if (ret < 0) {
588                 ret = SSL_get_error(c->ssl, ret);
589                 if (ret == SSL_ERROR_WANT_READ)
590                     cond |= G_IO_IN;
591                 if (ret == SSL_ERROR_WANT_WRITE)
592                     cond |= G_IO_OUT;
593                 ret = -1;
594             }
595         } else {
596             GError *error = NULL;
597             ret = g_socket_send(c->sock, ptr+offset, datalen-offset,
598                                 NULL, &error);
599             if (ret < 0) {
600                 if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
601                     cond = G_IO_OUT;
602                 } else {
603                     SPICE_DEBUG("Send error %s", error->message);
604                 }
605                 g_clear_error(&error);
606                 ret = -1;
607             }
608         }
609         if (ret == -1) {
610             if (cond != 0) {
611                 g_io_wait(c->sock, cond);
612             } else {
613                 SPICE_DEBUG("Closing the channel: spice_channel_flush %d", errno);
614                 c->has_error = TRUE;
615                 return;
616             }
617         }
618         if (ret == 0) {
619             SPICE_DEBUG("Closing the connection: spice_channel_flush");
620             c->has_error = TRUE;
621             return;
622         }
623         offset += ret;
624     }
625 }
626
627 #if HAVE_SASL
628 /*
629  * Encode all buffered data, write all encrypted data out
630  * to the wire
631  */
632 static void spice_channel_flush_sasl(SpiceChannel *channel, const void *data, size_t len)
633 {
634     spice_channel *c = channel->priv;
635     const char *output;
636     unsigned int outputlen;
637     int err;
638
639     err = sasl_encode(c->sasl_conn, data, len, &output, &outputlen);
640     if (err != SASL_OK) {
641         g_warning ("Failed to encode SASL data %s",
642                    sasl_errstring(err, NULL, NULL));
643         c->has_error = TRUE;
644         return;
645     }
646
647     //SPICE_DEBUG("Flush SASL %d: %p %d", len, output, outputlen);
648     spice_channel_flush_wire(channel, output, outputlen);
649 }
650 #endif
651
652 /* coroutine context */
653 static void spice_channel_write(SpiceChannel *channel, const void *data, size_t len)
654 {
655 #if HAVE_SASL
656     spice_channel *c = channel->priv;
657
658     if (c->sasl_conn)
659         spice_channel_flush_sasl(channel, data, len);
660     else
661 #endif
662         spice_channel_flush_wire(channel, data, len);
663 }
664
665 /*
666  * Read at least 1 more byte of data straight off the wire
667  * into the requested buffer.
668  */
669 /* coroutine context */
670 static int spice_channel_read_wire(SpiceChannel *channel, void *data, size_t len)
671 {
672     spice_channel *c = channel->priv;
673     int ret;
674     GIOCondition cond;
675
676 reread:
677
678     if (c->has_error) return 0; /* has_error is set by disconnect(), return no error */
679
680     cond = 0;
681     if (c->tls) {
682         ret = SSL_read(c->ssl, data, len);
683         if (ret < 0) {
684             ret = SSL_get_error(c->ssl, ret);
685             if (ret == SSL_ERROR_WANT_READ)
686                 cond |= G_IO_IN;
687             if (ret == SSL_ERROR_WANT_WRITE)
688                 cond |= G_IO_OUT;
689             ret = -1;
690         }
691     } else {
692         GError *error = NULL;
693         ret = g_socket_receive(c->sock, data, len, NULL, &error);
694         if (ret < 0) {
695             if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
696                 cond = G_IO_IN;
697             } else {
698                 SPICE_DEBUG("Read error %s", error->message);
699             }
700             g_clear_error(&error);
701             ret = -1;
702         }
703     }
704
705     if (ret == -1) {
706         if (cond != 0) {
707             if (c->wait_interruptible) {
708                 if (!g_io_wait_interruptible(&c->wait, c->sock, cond)) {
709                     // SPICE_DEBUG("Read blocking interrupted %d", priv->has_error);
710                     return -EAGAIN;
711                 }
712             } else {
713                 g_io_wait(c->sock, cond);
714             }
715             goto reread;
716         } else {
717             c->has_error = TRUE;
718             return -errno;
719         }
720     }
721     if (ret == 0) {
722         SPICE_DEBUG("Closing the connection: spice_channel_read() - ret=0");
723         c->has_error = TRUE;
724         return 0;
725     }
726
727     return ret;
728 }
729
730 #if HAVE_SASL
731 /*
732  * Read at least 1 more byte of data out of the SASL decrypted
733  * data buffer, into the internal read buffer
734  */
735 static int spice_channel_read_sasl(SpiceChannel *channel, void *data, size_t len)
736 {
737     spice_channel *c = channel->priv;
738
739     /* SPICE_DEBUG("Read %lu SASL %p size %d offset %d", len, c->sasl_decoded, */
740     /*             c->sasl_decoded_length, c->sasl_decoded_offset); */
741
742     if (c->sasl_decoded == NULL || c->sasl_decoded_length == 0) {
743         char encoded[8192]; /* should stay lower than maxbufsize */
744         int err, ret;
745
746         g_warn_if_fail(c->sasl_decoded_offset == 0);
747
748         ret = spice_channel_read_wire(channel, encoded, sizeof(encoded));
749         if (ret < 0)
750             return ret;
751
752         err = sasl_decode(c->sasl_conn, encoded, ret,
753                           &c->sasl_decoded, &c->sasl_decoded_length);
754         if (err != SASL_OK) {
755             g_warning("Failed to decode SASL data %s",
756                       sasl_errstring(err, NULL, NULL));
757             c->has_error = TRUE;
758             return -EINVAL;
759         }
760         c->sasl_decoded_offset = 0;
761     }
762
763     if (c->sasl_decoded_length == 0)
764         return 0;
765
766     len = MIN(c->sasl_decoded_length - c->sasl_decoded_offset, len);
767     memcpy(data, c->sasl_decoded + c->sasl_decoded_offset, len);
768     c->sasl_decoded_offset += len;
769
770     if (c->sasl_decoded_offset == c->sasl_decoded_length) {
771         c->sasl_decoded_length = c->sasl_decoded_offset = 0;
772         c->sasl_decoded = NULL;
773     }
774
775     return len;
776 }
777 #endif
778
779 /*
780  * Fill the 'data' buffer up with exactly 'len' bytes worth of data
781  */
782 /* coroutine context */
783 static int spice_channel_read(SpiceChannel *channel, void *data, size_t length)
784 {
785     spice_channel *c = channel->priv;
786     gsize len = length;
787     int ret;
788
789     while (len > 0) {
790         if (c->has_error) return 0; /* has_error is set by disconnect(), return no error */
791
792 #if HAVE_SASL
793         if (c->sasl_conn)
794             ret = spice_channel_read_sasl(channel, data, len);
795         else
796 #endif
797             ret = spice_channel_read_wire(channel, data, len);
798         if (ret < 0)
799             return ret;
800         g_assert(ret <= len);
801         len -= ret;
802         data = ((char*)data) + ret;
803 #if DEBUG
804         if (len > 0)
805             SPICE_DEBUG("still needs %" G_GSIZE_FORMAT, len);
806 #endif
807     }
808     c->total_read_bytes += length;
809
810     return length;
811 }
812
813 /* coroutine context */
814 static void spice_channel_send_spice_ticket(SpiceChannel *channel)
815 {
816     spice_channel *c = channel->priv;
817     EVP_PKEY *pubkey;
818     int nRSASize;
819     BIO *bioKey;
820     RSA *rsa;
821     char *password;
822     uint8_t *encrypted;
823     int rc;
824
825     bioKey = BIO_new(BIO_s_mem());
826     g_return_if_fail(bioKey != NULL);
827
828     BIO_write(bioKey, c->peer_msg->pub_key, SPICE_TICKET_PUBKEY_BYTES);
829     pubkey = d2i_PUBKEY_bio(bioKey, NULL);
830     g_return_if_fail(pubkey != NULL);
831
832     rsa = pubkey->pkey.rsa;
833     nRSASize = RSA_size(rsa);
834
835     encrypted = g_alloca(nRSASize);
836     /*
837       The use of RSA encryption limit the potential maximum password length.
838       for RSA_PKCS1_OAEP_PADDING it is RSA_size(rsa) - 41.
839     */
840     g_object_get(c->session, "password", &password, NULL);
841     if (password == NULL)
842         password = g_strdup("");
843     rc = RSA_public_encrypt(strlen(password) + 1, (uint8_t*)password,
844                             encrypted, rsa, RSA_PKCS1_OAEP_PADDING);
845     g_warn_if_fail(rc > 0);
846
847     spice_channel_write(channel, encrypted, nRSASize);
848     memset(encrypted, 0, nRSASize);
849     EVP_PKEY_free(pubkey);
850     BIO_free(bioKey);
851     g_free(password);
852 }
853
854 /* coroutine context */
855 static void spice_channel_recv_auth(SpiceChannel *channel)
856 {
857     spice_channel *c = channel->priv;
858     uint32_t link_res;
859     int rc;
860
861     rc = spice_channel_read(channel, &link_res, sizeof(link_res));
862     if (rc != sizeof(link_res)) {
863         g_critical("incomplete auth reply (%d/%" G_GSIZE_FORMAT ")",
864                    rc, sizeof(link_res));
865         emit_main_context(channel, SPICE_CHANNEL_EVENT, SPICE_CHANNEL_ERROR_LINK);
866         return;
867     }
868
869     if (link_res != SPICE_LINK_ERR_OK) {
870         g_critical("link result: reply %d", link_res);
871         emit_main_context(channel, SPICE_CHANNEL_EVENT, SPICE_CHANNEL_ERROR_AUTH);
872         return;
873     }
874
875     c->state = SPICE_CHANNEL_STATE_READY;
876
877     emit_main_context(channel, SPICE_CHANNEL_EVENT, SPICE_CHANNEL_OPENED);
878
879     if (c->state != SPICE_CHANNEL_STATE_MIGRATING)
880         spice_channel_up(channel);
881 }
882
883 G_GNUC_INTERNAL
884 void spice_channel_up(SpiceChannel *channel)
885 {
886     spice_channel *c = channel->priv;
887
888     SPICE_DEBUG("%s: channel up, state %d", c->name, c->state);
889
890     if (SPICE_CHANNEL_GET_CLASS(channel)->channel_up)
891         SPICE_CHANNEL_GET_CLASS(channel)->channel_up(channel);
892 }
893
894 /* coroutine context */
895 static void spice_channel_send_link(SpiceChannel *channel)
896 {
897     spice_channel *c = channel->priv;
898     uint8_t *buffer, *p;
899     int protocol, i;
900
901     c->link_hdr.magic = SPICE_MAGIC;
902     c->link_hdr.size = sizeof(c->link_msg);
903
904     g_object_get(c->session, "protocol", &protocol, NULL);
905     switch (protocol) {
906     case 1: /* protocol 1 == major 1, old 0.4 protocol, last active minor */
907         c->link_hdr.major_version = 1;
908         c->link_hdr.minor_version = 3;
909         c->parser = spice_get_server_channel_parser1(c->channel_type, NULL);
910         c->marshallers = spice_message_marshallers_get1();
911         break;
912     case SPICE_VERSION_MAJOR: /* protocol 2 == current */
913         c->link_hdr.major_version = SPICE_VERSION_MAJOR;
914         c->link_hdr.minor_version = SPICE_VERSION_MINOR;
915         c->parser = spice_get_server_channel_parser(c->channel_type, NULL);
916         c->marshallers = spice_message_marshallers_get();
917         break;
918     default:
919         g_critical("unknown major %d", protocol);
920         return;
921     }
922
923     c->link_msg.connection_id = c->connection_id;
924     c->link_msg.channel_type  = c->channel_type;
925     c->link_msg.channel_id    = c->channel_id;
926     c->link_msg.caps_offset   = sizeof(c->link_msg);
927
928     c->link_msg.num_common_caps = c->common_caps->len;
929     c->link_msg.num_channel_caps = c->caps->len;
930     c->link_hdr.size += (c->link_msg.num_common_caps +
931                          c->link_msg.num_channel_caps) * sizeof(uint32_t);
932
933     buffer = spice_malloc(sizeof(c->link_hdr) + c->link_hdr.size);
934     p = buffer;
935
936     memcpy(p, &c->link_hdr, sizeof(c->link_hdr)); p += sizeof(c->link_hdr);
937     memcpy(p, &c->link_msg, sizeof(c->link_msg)); p += sizeof(c->link_msg);
938
939     for (i = 0; i < c->common_caps->len; i++) {
940         *(uint32_t *)p = g_array_index(c->common_caps, uint32_t, i);
941         p += sizeof(uint32_t);
942     }
943     for (i = 0; i < c->caps->len; i++) {
944         *(uint32_t *)p = g_array_index(c->caps, uint32_t, i);
945         p += sizeof(uint32_t);
946     }
947
948     spice_channel_write(channel, buffer, p - buffer);
949     free(buffer);
950 }
951
952 /* coroutine context */
953 static void spice_channel_recv_link_hdr(SpiceChannel *channel)
954 {
955     spice_channel *c = channel->priv;
956     int rc;
957
958     rc = spice_channel_read(channel, &c->peer_hdr, sizeof(c->peer_hdr));
959     if (rc != sizeof(c->peer_hdr)) {
960         g_critical("incomplete link header (%d/%" G_GSIZE_FORMAT ")",
961                    rc, sizeof(c->peer_hdr));
962         goto error;
963     }
964     if (c->peer_hdr.magic != SPICE_MAGIC) {
965         g_critical("invalid SPICE_MAGIC!");
966         goto error;
967     }
968
969     if (c->peer_hdr.major_version != c->link_hdr.major_version) {
970         if (c->peer_hdr.major_version == 1) {
971             /* enter spice 0.4 mode */
972             g_object_set(c->session, "protocol", 1, NULL);
973             SPICE_DEBUG("%s: switching to protocol 1 (spice 0.4)", c->name);
974             SPICE_CHANNEL_GET_CLASS(channel)->channel_disconnect(channel);
975             spice_channel_connect(channel);
976             return;
977         }
978         g_critical("major mismatch (got %d, expected %d)",
979                    c->peer_hdr.major_version, c->link_hdr.major_version);
980         goto error;
981     }
982
983     c->peer_msg = spice_malloc(c->peer_hdr.size);
984     c->state = SPICE_CHANNEL_STATE_LINK_MSG;
985     return;
986
987 error:
988     emit_main_context(channel, SPICE_CHANNEL_EVENT, SPICE_CHANNEL_ERROR_LINK);
989 }
990
991 #if HAVE_SASL
992 /*
993  * NB, keep in sync with similar method in spice/server/reds.c
994  */
995 static gchar *addr_to_string(GSocketAddress *addr)
996 {
997     GInetSocketAddress *iaddr = G_INET_SOCKET_ADDRESS(addr);
998     guint16 port;
999     GInetAddress *host;
1000     gchar *hoststr;
1001     gchar *ret;
1002
1003     host = g_inet_socket_address_get_address(iaddr);
1004     port = g_inet_socket_address_get_port(iaddr);
1005     hoststr = g_inet_address_to_string(host);
1006
1007     ret = g_strdup_printf("%s;%hu", hoststr, port);
1008     g_free(hoststr);
1009
1010     return ret;
1011 }
1012
1013 static gboolean
1014 spice_channel_gather_sasl_credentials(SpiceChannel *channel,
1015                                        sasl_interact_t *interact)
1016 {
1017     spice_channel *c;
1018     int ninteract;
1019
1020     g_return_val_if_fail(channel != NULL, FALSE);
1021     g_return_val_if_fail(channel->priv != NULL, FALSE);
1022
1023     c = channel->priv;
1024
1025     /* FIXME: we could keep connection open and ask connection details if missing */
1026
1027     for (ninteract = 0 ; interact[ninteract].id != 0 ; ninteract++) {
1028         switch (interact[ninteract].id) {
1029         case SASL_CB_AUTHNAME:
1030         case SASL_CB_USER:
1031             g_warn_if_reached();
1032             break;
1033
1034         case SASL_CB_PASS:
1035             if (spice_session_get_password(c->session) == NULL)
1036                 return FALSE;
1037
1038             interact[ninteract].result =  spice_session_get_password(c->session);
1039             interact[ninteract].len = strlen(interact[ninteract].result);
1040             break;
1041         }
1042     }
1043
1044     SPICE_DEBUG("Filled SASL interact");
1045
1046     return TRUE;
1047 }
1048
1049 /*
1050  *
1051  * Init msg from server
1052  *
1053  *  u32 mechlist-length
1054  *  u8-array mechlist-string
1055  *
1056  * Start msg to server
1057  *
1058  *  u32 mechname-length
1059  *  u8-array mechname-string
1060  *  u32 clientout-length
1061  *  u8-array clientout-string
1062  *
1063  * Start msg from server
1064  *
1065  *  u32 serverin-length
1066  *  u8-array serverin-string
1067  *  u8 continue
1068  *
1069  * Step msg to server
1070  *
1071  *  u32 clientout-length
1072  *  u8-array clientout-string
1073  *
1074  * Step msg from server
1075  *
1076  *  u32 serverin-length
1077  *  u8-array serverin-string
1078  *  u8 continue
1079  */
1080
1081 #define SASL_MAX_MECHLIST_LEN 300
1082 #define SASL_MAX_MECHNAME_LEN 100
1083 #define SASL_MAX_DATA_LEN (1024 * 1024)
1084
1085 /* Perform the SASL authentication process
1086  */
1087 static gboolean spice_channel_perform_auth_sasl(SpiceChannel *channel)
1088 {
1089     spice_channel *c;
1090     sasl_conn_t *saslconn = NULL;
1091     sasl_security_properties_t secprops;
1092     const char *clientout;
1093     char *serverin = NULL;
1094     unsigned int clientoutlen;
1095     int err;
1096     char *localAddr = NULL, *remoteAddr = NULL;
1097     const void *val;
1098     sasl_ssf_t ssf;
1099     sasl_callback_t saslcb[] = {
1100         { .id = SASL_CB_PASS },
1101         { .id = 0 },
1102     };
1103     sasl_interact_t *interact = NULL;
1104     guint32 len;
1105     char *mechlist;
1106     const char *mechname;
1107     gboolean ret = FALSE;
1108     GSocketAddress *addr;
1109     guint8 complete;
1110
1111     g_return_val_if_fail(channel != NULL, FALSE);
1112     g_return_val_if_fail(channel->priv != NULL, FALSE);
1113
1114     c = channel->priv;
1115
1116     /* Sets up the SASL library as a whole */
1117     err = sasl_client_init(NULL);
1118     SPICE_DEBUG("Client initialize SASL authentication %d", err);
1119     if (err != SASL_OK) {
1120         g_critical("failed to initialize SASL library: %d (%s)",
1121                    err, sasl_errstring(err, NULL, NULL));
1122         goto error;
1123     }
1124
1125     /* Get local address in form  IPADDR:PORT */
1126     addr = g_socket_get_local_address(c->sock, NULL);
1127     if (!addr) {
1128         g_critical("failed to get local address");
1129         goto error;
1130     }
1131     if ((g_socket_address_get_family(addr) == G_SOCKET_FAMILY_IPV4 ||
1132          g_socket_address_get_family(addr) == G_SOCKET_FAMILY_IPV6) &&
1133         (localAddr = addr_to_string(addr)) == NULL)
1134         goto error;
1135
1136     /* Get remote address in form  IPADDR:PORT */
1137     addr = g_socket_get_remote_address(c->sock, NULL);
1138     if (!addr) {
1139         g_critical("failed to get peer address");
1140         goto error;
1141     }
1142     if ((g_socket_address_get_family(addr) == G_SOCKET_FAMILY_IPV4 ||
1143          g_socket_address_get_family(addr) == G_SOCKET_FAMILY_IPV6) &&
1144         (remoteAddr = addr_to_string(addr)) == NULL)
1145         goto error;
1146
1147     SPICE_DEBUG("Client SASL new host:'%s' local:'%s' remote:'%s'",
1148                 spice_session_get_host(c->session), localAddr, remoteAddr);
1149
1150     /* Setup a handle for being a client */
1151     err = sasl_client_new("spice",
1152                           spice_session_get_host(c->session),
1153                           localAddr,
1154                           remoteAddr,
1155                           saslcb,
1156                           SASL_SUCCESS_DATA,
1157                           &saslconn);
1158     g_free(localAddr);
1159     g_free(remoteAddr);
1160
1161     if (err != SASL_OK) {
1162         g_critical("Failed to create SASL client context: %d (%s)",
1163                    err, sasl_errstring(err, NULL, NULL));
1164         goto error;
1165     }
1166
1167     if (c->ssl) {
1168         sasl_ssf_t ssf;
1169
1170         ssf = SSL_get_cipher_bits(c->ssl, NULL);
1171         err = sasl_setprop(saslconn, SASL_SSF_EXTERNAL, &ssf);
1172         if (err != SASL_OK) {
1173             g_critical("cannot set SASL external SSF %d (%s)",
1174                        err, sasl_errstring(err, NULL, NULL));
1175             goto error;
1176         }
1177     }
1178
1179     memset(&secprops, 0, sizeof secprops);
1180     /* If we've got TLS, we don't care about SSF */
1181     secprops.min_ssf = c->ssl ? 0 : 56; /* Equiv to DES supported by all Kerberos */
1182     secprops.max_ssf = c->ssl ? 0 : 100000; /* Very strong ! AES == 256 */
1183     secprops.maxbufsize = 100000;
1184     /* If we're not TLS, then forbid any anonymous or trivially crackable auth */
1185     secprops.security_flags = c->ssl ? 0 :
1186         SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT;
1187
1188     err = sasl_setprop(saslconn, SASL_SEC_PROPS, &secprops);
1189     if (err != SASL_OK) {
1190         g_critical("cannot set security props %d (%s)",
1191                    err, sasl_errstring(err, NULL, NULL));
1192         goto error;
1193     }
1194
1195     /* Get the supported mechanisms from the server */
1196     spice_channel_read(channel, &len, sizeof(len));
1197     if (c->has_error)
1198         goto error;
1199     if (len > SASL_MAX_MECHLIST_LEN) {
1200         g_critical("mechlistlen %d too long", len);
1201         goto error;
1202     }
1203
1204     mechlist = g_malloc(len + 1);
1205     spice_channel_read(channel, mechlist, len);
1206     mechlist[len] = '\0';
1207     if (c->has_error) {
1208         g_free(mechlist);
1209         mechlist = NULL;
1210         goto error;
1211     }
1212
1213 restart:
1214     /* Start the auth negotiation on the client end first */
1215     SPICE_DEBUG("Client start negotiation mechlist '%s'", mechlist);
1216     err = sasl_client_start(saslconn,
1217                             mechlist,
1218                             &interact,
1219                             &clientout,
1220                             &clientoutlen,
1221                             &mechname);
1222     if (err != SASL_OK && err != SASL_CONTINUE && err != SASL_INTERACT) {
1223         g_critical("Failed to start SASL negotiation: %d (%s)",
1224                    err, sasl_errdetail(saslconn));
1225         g_free(mechlist);
1226         mechlist = NULL;
1227         goto error;
1228     }
1229
1230     /* Need to gather some credentials from the client */
1231     if (err == SASL_INTERACT) {
1232         if (!spice_channel_gather_sasl_credentials(channel, interact)) {
1233             g_critical("Failed to collect auth credentials");
1234             goto error;
1235         }
1236         goto restart;
1237     }
1238
1239     SPICE_DEBUG("Server start negotiation with mech %s. Data %d bytes %p '%s'",
1240                 mechname, clientoutlen, clientout, clientout);
1241
1242     if (clientoutlen > SASL_MAX_DATA_LEN) {
1243         g_critical("SASL negotiation data too long: %d bytes",
1244                    clientoutlen);
1245         goto error;
1246     }
1247
1248     /* Send back the chosen mechname */
1249     len = strlen(mechname);
1250     spice_channel_write(channel, &len, sizeof(guint32));
1251     spice_channel_write(channel, mechname, len);
1252
1253     /* NB, distinction of NULL vs "" is *critical* in SASL */
1254     if (clientout) {
1255         len += clientoutlen + 1;
1256         spice_channel_write(channel, &len, sizeof(guint32));
1257         spice_channel_write(channel, clientout, len);
1258     } else {
1259         len = 0;
1260         spice_channel_write(channel, &len, sizeof(guint32));
1261     }
1262
1263     if (c->has_error)
1264         goto error;
1265
1266     SPICE_DEBUG("Getting sever start negotiation reply");
1267     /* Read the 'START' message reply from server */
1268     spice_channel_read(channel, &len, sizeof(len));
1269     if (c->has_error)
1270         goto error;
1271     if (len > SASL_MAX_DATA_LEN) {
1272         g_critical("SASL negotiation data too long: %d bytes",
1273                    len);
1274         goto error;
1275     }
1276
1277     /* NB, distinction of NULL vs "" is *critical* in SASL */
1278     if (len > 0) {
1279         serverin = g_malloc(len);
1280         spice_channel_read(channel, serverin, len);
1281         serverin[len - 1] = '\0';
1282         len--;
1283     } else {
1284         serverin = NULL;
1285     }
1286     spice_channel_read(channel, &complete, sizeof(guint8));
1287     if (c->has_error)
1288         goto error;
1289
1290     SPICE_DEBUG("Client start result complete: %d. Data %d bytes %p '%s'",
1291                 complete, len, serverin, serverin);
1292
1293     /* Loop-the-loop...
1294      * Even if the server has completed, the client must *always* do at least one step
1295      * in this loop to verify the server isn't lying about something. Mutual auth */
1296     for (;;) {
1297     restep:
1298         err = sasl_client_step(saslconn,
1299                                serverin,
1300                                len,
1301                                &interact,
1302                                &clientout,
1303                                &clientoutlen);
1304         if (err != SASL_OK && err != SASL_CONTINUE && err != SASL_INTERACT) {
1305             g_critical("Failed SASL step: %d (%s)",
1306                        err, sasl_errdetail(saslconn));
1307             goto error;
1308         }
1309
1310         /* Need to gather some credentials from the client */
1311         if (err == SASL_INTERACT) {
1312             if (!spice_channel_gather_sasl_credentials(channel,
1313                                                        interact)) {
1314                 g_critical("%s", "Failed to collect auth credentials");
1315                 goto error;
1316             }
1317             goto restep;
1318         }
1319
1320         if (serverin) {
1321             g_free(serverin);
1322             serverin = NULL;
1323         }
1324
1325         SPICE_DEBUG("Client step result %d. Data %d bytes %p '%s'", err, clientoutlen, clientout, clientout);
1326
1327         /* Previous server call showed completion & we're now locally complete too */
1328         if (complete && err == SASL_OK)
1329             break;
1330
1331         /* Not done, prepare to talk with the server for another iteration */
1332
1333         /* NB, distinction of NULL vs "" is *critical* in SASL */
1334         if (clientout) {
1335             len = clientoutlen + 1;
1336             spice_channel_write(channel, &len, sizeof(guint32));
1337             spice_channel_write(channel, clientout, len);
1338         } else {
1339             len = 0;
1340             spice_channel_write(channel, &len, sizeof(guint32));
1341         }
1342
1343         if (c->has_error)
1344             goto error;
1345
1346         SPICE_DEBUG("Server step with %d bytes %p", clientoutlen, clientout);
1347
1348         spice_channel_read(channel, &len, sizeof(guint32));
1349         if (c->has_error)
1350             goto error;
1351         if (len > SASL_MAX_DATA_LEN) {
1352             g_critical("SASL negotiation data too long: %d bytes", len);
1353             goto error;
1354         }
1355
1356         /* NB, distinction of NULL vs "" is *critical* in SASL */
1357         if (len) {
1358             serverin = g_malloc(len);
1359             spice_channel_read(channel, serverin, len);
1360             serverin[len - 1] = '\0';
1361             len--;
1362         } else {
1363             serverin = NULL;
1364         }
1365
1366         spice_channel_read(channel, &complete, sizeof(guint8));
1367         if (c->has_error)
1368             goto error;
1369
1370         SPICE_DEBUG("Client step result complete: %d. Data %d bytes %p '%s'",
1371                     complete, len, serverin, serverin);
1372
1373         /* This server call shows complete, and earlier client step was OK */
1374         if (complete) {
1375             g_free(serverin);
1376             serverin = NULL;
1377             if (err == SASL_CONTINUE) /* something went wrong */
1378                 goto complete;
1379             break;
1380         }
1381     }
1382
1383     /* Check for suitable SSF if non-TLS */
1384     if (!c->ssl) {
1385         err = sasl_getprop(saslconn, SASL_SSF, &val);
1386         if (err != SASL_OK) {
1387             g_critical("cannot query SASL ssf on connection %d (%s)",
1388                        err, sasl_errstring(err, NULL, NULL));
1389             goto error;
1390         }
1391         ssf = *(const int *)val;
1392         SPICE_DEBUG("SASL SSF value %d", ssf);
1393         if (ssf < 56) { /* 56 == DES level, good for Kerberos */
1394             g_critical("negotiation SSF %d was not strong enough", ssf);
1395             goto error;
1396         }
1397     }
1398
1399 complete:
1400     SPICE_DEBUG("%s", "SASL authentication complete");
1401     spice_channel_read(channel, &len, sizeof(len));
1402     if (len != SPICE_LINK_ERR_OK)
1403         emit_main_context(channel, SPICE_CHANNEL_EVENT, SPICE_CHANNEL_ERROR_AUTH);
1404     ret = len == SPICE_LINK_ERR_OK;
1405     /* This must come *after* check-auth-result, because the former
1406      * is defined to be sent unencrypted, and setting saslconn turns
1407      * on the SSF layer encryption processing */
1408     c->sasl_conn = saslconn;
1409     return ret;
1410
1411 error:
1412     if (saslconn)
1413         sasl_dispose(&saslconn);
1414     if (!c->has_error)
1415         emit_main_context(channel, SPICE_CHANNEL_EVENT, SPICE_CHANNEL_ERROR_AUTH);
1416     c->has_error = TRUE; /* force disconnect */
1417     return FALSE;
1418 }
1419 #endif /* HAVE_SASL */
1420
1421 /* coroutine context */
1422 static void spice_channel_recv_link_msg(SpiceChannel *channel)
1423 {
1424     spice_channel *c;
1425     int rc, num_caps, i;
1426
1427     g_return_if_fail(channel != NULL);
1428     g_return_if_fail(channel->priv != NULL);
1429
1430     c = channel->priv;
1431
1432     rc = spice_channel_read(channel, (uint8_t*)c->peer_msg + c->peer_pos,
1433                             c->peer_hdr.size - c->peer_pos);
1434     c->peer_pos += rc;
1435     if (c->peer_pos != c->peer_hdr.size) {
1436         g_critical("%s: %s: incomplete link reply (%d/%d)",
1437                   c->name, __FUNCTION__, rc, c->peer_hdr.size);
1438         emit_main_context(channel, SPICE_CHANNEL_EVENT, SPICE_CHANNEL_ERROR_LINK);
1439         return;
1440     }
1441     switch (c->peer_msg->error) {
1442     case SPICE_LINK_ERR_OK:
1443         /* nothing */
1444         break;
1445     case SPICE_LINK_ERR_NEED_SECURED:
1446         c->tls = true;
1447         SPICE_DEBUG("%s: switching to tls", c->name);
1448         SPICE_CHANNEL_GET_CLASS(channel)->channel_disconnect(channel);
1449         spice_channel_connect(channel);
1450         return;
1451     default:
1452         g_warning("%s: %s: unhandled error %d",
1453                 c->name, __FUNCTION__, c->peer_msg->error);
1454         goto error;
1455     }
1456
1457     num_caps = c->peer_msg->num_channel_caps + c->peer_msg->num_common_caps;
1458     SPICE_DEBUG("%s: %s: %d caps", c->name, __FUNCTION__, num_caps);
1459
1460     /* see original spice/client code: */
1461     /* g_return_if_fail(c->peer_msg + c->peer_msg->caps_offset * sizeof(uint32_t) > c->peer_msg + c->peer_hdr.size); */
1462
1463     uint32_t *caps = (uint32_t *)((uint8_t *)c->peer_msg + c->peer_msg->caps_offset);
1464
1465     g_array_set_size(c->remote_common_caps, c->peer_msg->num_common_caps);
1466     for (i = 0; i < c->peer_msg->num_common_caps; i++, caps++) {
1467         g_array_index(c->remote_common_caps, uint32_t, i) = *caps;
1468         SPICE_DEBUG("got common caps %u:0x%X", i, *caps);
1469     }
1470
1471     g_array_set_size(c->remote_caps, c->peer_msg->num_channel_caps);
1472     for (i = 0; i < c->peer_msg->num_channel_caps; i++, caps++) {
1473         g_array_index(c->remote_caps, uint32_t, i) = *caps;
1474         SPICE_DEBUG("got channel caps %u:0x%X", i, *caps);
1475     }
1476
1477     c->state = SPICE_CHANNEL_STATE_AUTH;
1478     if (!spice_channel_test_common_capability(channel,
1479             SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION)) {
1480         SPICE_DEBUG("Server supports spice ticket auth only");
1481         spice_channel_send_spice_ticket(channel);
1482     } else {
1483         SpiceLinkAuthMechanism auth = { 0, };
1484
1485 #if HAVE_SASL
1486         if (spice_channel_test_common_capability(channel, SPICE_COMMON_CAP_AUTH_SASL)) {
1487             SPICE_DEBUG("Choosing SASL mechanism");
1488             auth.auth_mechanism = SPICE_COMMON_CAP_AUTH_SASL;
1489             spice_channel_write(channel, &auth, sizeof(auth));
1490             spice_channel_perform_auth_sasl(channel);
1491         } else
1492 #endif
1493         if (spice_channel_test_common_capability(channel, SPICE_COMMON_CAP_AUTH_SPICE)) {
1494             auth.auth_mechanism = SPICE_COMMON_CAP_AUTH_SPICE;
1495             spice_channel_write(channel, &auth, sizeof(auth));
1496             spice_channel_send_spice_ticket(channel);
1497         } else {
1498             g_warning("No compatible AUTH mechanism");
1499             goto error;
1500         }
1501     }
1502
1503     return;
1504
1505 error:
1506     SPICE_CHANNEL_GET_CLASS(channel)->channel_disconnect(channel);
1507     emit_main_context(channel, SPICE_CHANNEL_EVENT, SPICE_CHANNEL_ERROR_LINK);
1508 }
1509
1510 /* system context */
1511 static void spice_channel_buffered_write(SpiceChannel *channel, const void *data, size_t size)
1512 {
1513     spice_channel *c = channel->priv;
1514     size_t left;
1515
1516     left = c->xmit_buffer_capacity - c->xmit_buffer_size;
1517     if (left < size) {
1518         c->xmit_buffer_capacity += size + 4095;
1519         c->xmit_buffer_capacity &= ~4095;
1520
1521         c->xmit_buffer = g_realloc(c->xmit_buffer, c->xmit_buffer_capacity);
1522     }
1523
1524     memcpy(&c->xmit_buffer[c->xmit_buffer_size], data, size);
1525
1526     c->xmit_buffer_size += size;
1527 }
1528
1529 /* system context */
1530 /* TODO: we currently flush/wakeup immediately all buffered messages */
1531 G_GNUC_INTERNAL
1532 void spice_channel_wakeup(SpiceChannel *channel)
1533 {
1534     spice_channel *c = channel->priv;
1535
1536     g_io_wakeup(&c->wait);
1537 }
1538
1539 /* coroutine context if @buffered is FALSE,
1540    system context if @buffered is TRUE */
1541 static void spice_channel_send_msg(SpiceChannel *channel, spice_msg_out *out, gboolean buffered)
1542 {
1543     uint8_t *data;
1544     int free_data;
1545     size_t len;
1546
1547     g_return_if_fail(channel != NULL);
1548     g_return_if_fail(out != NULL);
1549
1550     data = spice_marshaller_linearize(out->marshaller, 0,
1551                                       &len, &free_data);
1552     /* spice_msg_out_hexdump(out, data, len); */
1553     if (buffered)
1554         spice_channel_buffered_write(channel, data, len);
1555     else
1556         spice_channel_write(channel, data, len);
1557     if (free_data) {
1558         free(data);
1559     }
1560 }
1561
1562 /* coroutine context */
1563 G_GNUC_INTERNAL
1564 void spice_channel_recv_msg(SpiceChannel *channel,
1565                             handler_msg_in msg_handler, gpointer data)
1566 {
1567     spice_channel *c = channel->priv;
1568     spice_msg_in *in;
1569     int rc;
1570
1571     if (!c->msg_in) {
1572         c->msg_in = spice_msg_in_new(channel);
1573     }
1574     in = c->msg_in;
1575
1576     /* receive message */
1577     if (in->hpos < sizeof(in->header)) {
1578         rc = spice_channel_read(channel, (uint8_t*)&in->header + in->hpos,
1579                                 sizeof(in->header) - in->hpos);
1580         if (rc < 0) {
1581             g_critical("recv hdr: %s", strerror(errno));
1582             return;
1583         }
1584         in->hpos += rc;
1585         if (in->hpos < sizeof(in->header))
1586             return;
1587         in->data = spice_malloc(in->header.size);
1588     }
1589     if (in->dpos < in->header.size) {
1590         rc = spice_channel_read(channel, in->data + in->dpos,
1591                                 in->header.size - in->dpos);
1592         if (rc < 0) {
1593             g_critical("recv msg: %s", strerror(errno));
1594             return;
1595         }
1596         in->dpos += rc;
1597         if (in->dpos < in->header.size)
1598             return;
1599     }
1600
1601     if (in->header.sub_list) {
1602         SpiceSubMessageList *sub_list;
1603         SpiceSubMessage *sub;
1604         spice_msg_in *sub_in;
1605         int i;
1606
1607         sub_list = (SpiceSubMessageList *)(in->data + in->header.sub_list);
1608         for (i = 0; i < sub_list->size; i++) {
1609             sub = (SpiceSubMessage *)(in->data + sub_list->sub_messages[i]);
1610             sub_in = spice_msg_in_sub_new(channel, in, sub);
1611             sub_in->parsed = c->parser(sub_in->data, sub_in->data + sub_in->dpos,
1612                                        sub_in->header.type, c->peer_hdr.minor_version,
1613                                        &sub_in->psize, &sub_in->pfree);
1614             if (sub_in->parsed == NULL) {
1615                 g_critical("failed to parse sub-message: %s type %d",
1616                            c->name, sub_in->header.type);
1617                 return;
1618             }
1619             msg_handler(channel, sub_in, data);
1620             spice_msg_in_unref(sub_in);
1621         }
1622     }
1623
1624     /* ack message */
1625     if (c->message_ack_count) {
1626         c->message_ack_count--;
1627         if (!c->message_ack_count) {
1628             spice_msg_out *out = spice_msg_out_new(channel, SPICE_MSGC_ACK);
1629             spice_msg_out_send_internal(out);
1630             spice_msg_out_unref(out);
1631             c->message_ack_count = c->message_ack_window;
1632         }
1633     }
1634
1635     /* parse message */
1636     in->parsed = c->parser(in->data, in->data + in->dpos, in->header.type,
1637                            c->peer_hdr.minor_version, &in->psize, &in->pfree);
1638     if (in->parsed == NULL) {
1639         g_critical("failed to parse message: %s type %d",
1640                    c->name, in->header.type);
1641         goto end;
1642     }
1643
1644     /* process message */
1645     c->msg_in = NULL; /* the function is reentrant, reset state */
1646     /* spice_msg_in_hexdump(in); */
1647     msg_handler(channel, in, data);
1648
1649 end:
1650     /* release message */
1651     c->msg_in = NULL;
1652     spice_msg_in_unref(in);
1653 }
1654
1655 const gchar* spice_channel_type_to_string(gint type)
1656 {
1657     static const char *to_string[] = {
1658         NULL,
1659         [ SPICE_CHANNEL_MAIN ] = "main",
1660         [ SPICE_CHANNEL_DISPLAY ] = "display",
1661         [ SPICE_CHANNEL_INPUTS ] = "inputs",
1662         [ SPICE_CHANNEL_CURSOR ] = "cursor",
1663         [ SPICE_CHANNEL_PLAYBACK ] = "playback",
1664         [ SPICE_CHANNEL_RECORD ] = "record",
1665         [ SPICE_CHANNEL_TUNNEL ] = "tunnel",
1666         [ SPICE_CHANNEL_SMARTCARD ] = "smartcard"
1667     };
1668     const char *str = NULL;
1669
1670     if (type >= 0 && type < sizeof(to_string)) {
1671         str = to_string[type];
1672     }
1673
1674     return str ? str : "unknown channel type";
1675 }
1676
1677 /**
1678  * spice_channel_new:
1679  * @s: the @SpiceSession the channel is linked to
1680  * @type: the requested SPICE_CHANNEL type
1681  * @id: the channel-id
1682  *
1683  * Create a new #SpiceChannel of type @type, and channel ID @id.
1684  *
1685  * Returns: a #SpiceChannel
1686  **/
1687 SpiceChannel *spice_channel_new(SpiceSession *s, int type, int id)
1688 {
1689     SpiceChannel *channel;
1690     GType gtype = 0;
1691
1692     g_return_val_if_fail(s != NULL, NULL);
1693
1694     switch (type) {
1695     case SPICE_CHANNEL_MAIN:
1696         gtype = SPICE_TYPE_MAIN_CHANNEL;
1697         break;
1698     case SPICE_CHANNEL_DISPLAY:
1699         gtype = SPICE_TYPE_DISPLAY_CHANNEL;
1700         break;
1701     case SPICE_CHANNEL_CURSOR:
1702         gtype = SPICE_TYPE_CURSOR_CHANNEL;
1703         break;
1704     case SPICE_CHANNEL_INPUTS:
1705         gtype = SPICE_TYPE_INPUTS_CHANNEL;
1706         break;
1707     case SPICE_CHANNEL_PLAYBACK:
1708         gtype = SPICE_TYPE_PLAYBACK_CHANNEL;
1709         break;
1710     case SPICE_CHANNEL_RECORD:
1711         gtype = SPICE_TYPE_RECORD_CHANNEL;
1712         break;
1713 #ifdef USE_SMARTCARD
1714     case SPICE_CHANNEL_SMARTCARD:
1715         gtype = SPICE_TYPE_SMARTCARD_CHANNEL;
1716         break;
1717 #endif
1718     default:
1719         g_debug("unsupported channel kind: %s: %d",
1720                 spice_channel_type_to_string(type), type);
1721         return NULL;
1722     }
1723     channel = SPICE_CHANNEL(g_object_new(gtype,
1724                                          "spice-session", s,
1725                                          "channel-type", type,
1726                                          "channel-id", id,
1727                                          NULL));
1728     return channel;
1729 }
1730
1731 /**
1732  * spice_channel_destroy:
1733  * @channel:
1734  *
1735  * Disconnect and unref the @channel. Called by @spice_session_disconnect()
1736  *
1737  **/
1738 void spice_channel_destroy(SpiceChannel *channel)
1739 {
1740     g_return_if_fail(channel != NULL);
1741
1742     SPICE_DEBUG("channel destroy");
1743     spice_channel_disconnect(channel, SPICE_CHANNEL_NONE);
1744     g_object_unref(channel);
1745 }
1746
1747 /* coroutine context */
1748 static void spice_channel_iterate_write(SpiceChannel *channel)
1749 {
1750     spice_channel *c = channel->priv;
1751
1752     if (c->xmit_buffer_size) {
1753         spice_channel_write(channel, c->xmit_buffer, c->xmit_buffer_size);
1754         c->xmit_buffer_size = 0;
1755     }
1756 }
1757
1758 /* coroutine context */
1759 static void spice_channel_iterate_read(SpiceChannel *channel)
1760 {
1761     spice_channel *c = channel->priv;
1762
1763     /* TODO: get rid of state, and use coroutine state */
1764     switch (c->state) {
1765     case SPICE_CHANNEL_STATE_LINK_HDR:
1766         spice_channel_recv_link_hdr(channel);
1767         break;
1768     case SPICE_CHANNEL_STATE_LINK_MSG:
1769         spice_channel_recv_link_msg(channel);
1770         break;
1771     case SPICE_CHANNEL_STATE_AUTH:
1772         spice_channel_recv_auth(channel);
1773         break;
1774     case SPICE_CHANNEL_STATE_READY:
1775         spice_channel_recv_msg(channel,
1776             (handler_msg_in)SPICE_CHANNEL_GET_CLASS(channel)->handle_msg, NULL);
1777         break;
1778     default:
1779         g_critical("unknown state %d", c->state);
1780     }
1781 }
1782
1783 /* coroutine context */
1784 static gboolean spice_channel_iterate(SpiceChannel *channel)
1785 {
1786     spice_channel *c = channel->priv;
1787     GIOCondition ret;
1788
1789     do {
1790         while (c->state == SPICE_CHANNEL_STATE_MIGRATING) {
1791             /* freeze coroutine */
1792             coroutine_yield(NULL);
1793             g_return_val_if_fail(c->state != SPICE_CHANNEL_STATE_MIGRATING, FALSE);
1794         }
1795
1796         if (c->has_error) {
1797             SPICE_DEBUG("channel has error, breaking loop");
1798             return FALSE;
1799         }
1800
1801         SPICE_CHANNEL_GET_CLASS(channel)->iterate_write(channel);
1802         ret = g_io_wait_interruptible(&c->wait, c->sock, G_IO_IN);
1803 #ifdef WIN32
1804         /* FIXME: windows gsocket is buggy, it doesn't return correct condition... */
1805         ret = g_socket_condition_check(c->sock, G_IO_IN);
1806 #endif
1807     } while (ret == 0); /* ret == 0 means no IO condition, but woken up */
1808
1809     if (ret & (G_IO_ERR|G_IO_HUP)) {
1810         SPICE_DEBUG("got socket error before read(): %d", ret);
1811         emit_main_context(channel, SPICE_CHANNEL_EVENT,
1812                           c->state == SPICE_CHANNEL_STATE_READY ?
1813                           SPICE_CHANNEL_ERROR_IO : SPICE_CHANNEL_ERROR_LINK);
1814         c->has_error = TRUE;
1815         return FALSE;
1816     }
1817
1818     do
1819         SPICE_CHANNEL_GET_CLASS(channel)->iterate_read(channel);
1820 #if HAVE_SASL
1821     while (c->sasl_decoded != NULL);
1822 #else
1823     while (FALSE);
1824 #endif
1825
1826     return TRUE;
1827 }
1828
1829 /* we use an idle function to allow the coroutine to exit before we actually
1830  * unref the object since the coroutine's state is part of the object */
1831 static gboolean spice_channel_delayed_unref(gpointer data)
1832 {
1833     SpiceChannel *channel = SPICE_CHANNEL(data);
1834     spice_channel *c = channel->priv;
1835
1836     g_return_val_if_fail(channel != NULL, FALSE);
1837     SPICE_DEBUG("Delayed unref channel %s %p", c->name, channel);
1838
1839     g_return_val_if_fail(c->coroutine.exited == TRUE, FALSE);
1840
1841     g_object_unref(G_OBJECT(data));
1842
1843     return FALSE;
1844 }
1845
1846 /* coroutine context */
1847 static void *spice_channel_coroutine(void *data)
1848 {
1849     SpiceChannel *channel = SPICE_CHANNEL(data);
1850     spice_channel *c = channel->priv;
1851     guint verify;
1852
1853     SPICE_DEBUG("Started background coroutine %p for %s", &c->coroutine, c->name);
1854
1855     if (spice_session_get_client_provided_socket(c->session)) {
1856         if (c->fd < 0) {
1857             g_critical("fd not provided!");
1858             goto cleanup;
1859         }
1860
1861         if (!(c->sock = g_socket_new_from_fd(c->fd, NULL))) {
1862                 SPICE_DEBUG("Failed to open socket from fd %d", c->fd);
1863                 return FALSE;
1864         }
1865
1866         g_socket_set_blocking(c->sock, FALSE);
1867         goto connected;
1868     }
1869
1870 reconnect:
1871     c->sock = spice_session_channel_open_host(c->session, c->tls);
1872     if (c->sock == NULL) {
1873         if (!c->tls) {
1874             SPICE_DEBUG("connection failed, trying with TLS port");
1875             c->tls = true; /* FIXME: does that really work with provided fd */
1876             goto reconnect;
1877         } else {
1878             SPICE_DEBUG("Connect error");
1879             emit_main_context(channel, SPICE_CHANNEL_EVENT, SPICE_CHANNEL_ERROR_CONNECT);
1880             goto cleanup;
1881         }
1882     }
1883
1884     c->has_error = FALSE;
1885
1886     if (c->tls) {
1887         int rc;
1888
1889         c->ctx = SSL_CTX_new(TLSv1_method());
1890         if (c->ctx == NULL) {
1891             g_critical("SSL_CTX_new failed");
1892             goto cleanup;
1893         }
1894
1895         verify = spice_session_get_verify(c->session);
1896         if (verify &
1897             (SPICE_SESSION_VERIFY_SUBJECT | SPICE_SESSION_VERIFY_HOSTNAME)) {
1898             const gchar *ca_file = spice_session_get_ca_file (c->session);
1899
1900             g_warn_if_fail(ca_file != NULL);
1901             SPICE_DEBUG("CA file: %s", ca_file);
1902             rc = SSL_CTX_load_verify_locations(c->ctx, ca_file, NULL);
1903             if (rc != 1)
1904                 g_warning("loading ca certs from %s failed", ca_file);
1905
1906             if (rc != 1) {
1907                 if (verify & SPICE_SESSION_VERIFY_PUBKEY) {
1908                     g_warning("only pubkey active");
1909                     verify = SPICE_SESSION_VERIFY_PUBKEY;
1910                 } else
1911                     goto cleanup;
1912             }
1913         }
1914
1915         {
1916             const gchar *ciphers = spice_session_get_ciphers(c->session);
1917             if (ciphers != NULL) {
1918                 rc = SSL_CTX_set_cipher_list(c->ctx, ciphers);
1919                 if (rc != 1)
1920                     g_warning("loading cipher list %s failed", ciphers);
1921             }
1922         }
1923
1924         c->ssl = SSL_new(c->ctx);
1925         if (c->ssl == NULL) {
1926             g_critical("SSL_new failed");
1927             goto cleanup;
1928         }
1929         rc = SSL_set_fd(c->ssl, g_socket_get_fd(c->sock));
1930         if (rc <= 0) {
1931             g_critical("SSL_set_fd failed");
1932             goto cleanup;
1933         }
1934
1935
1936         {
1937             guint8 *pubkey;
1938             guint pubkey_len;
1939
1940             spice_session_get_pubkey(c->session, &pubkey, &pubkey_len);
1941             c->sslverify = spice_openssl_verify_new(c->ssl, verify,
1942                 spice_session_get_host(c->session),
1943                 (char*)pubkey, pubkey_len,
1944                 spice_session_get_cert_subject(c->session));
1945         }
1946
1947 ssl_reconnect:
1948         rc = SSL_connect(c->ssl);
1949         if (rc <= 0) {
1950             rc = SSL_get_error(c->ssl, rc);
1951             if (rc == SSL_ERROR_WANT_READ || rc == SSL_ERROR_WANT_WRITE) {
1952                 g_io_wait(c->sock, G_IO_OUT|G_IO_ERR|G_IO_HUP);
1953                 goto ssl_reconnect;
1954             } else {
1955                 g_warning("%s: SSL_connect: %s",
1956                           c->name, ERR_error_string(rc, NULL));
1957                 emit_main_context(channel, SPICE_CHANNEL_EVENT, SPICE_CHANNEL_ERROR_TLS);
1958                 goto cleanup;
1959             }
1960         }
1961     }
1962
1963 connected:
1964     c->state = SPICE_CHANNEL_STATE_LINK_HDR;
1965     spice_channel_send_link(channel);
1966
1967     while (spice_channel_iterate(channel))
1968         ;
1969
1970     /* TODO: improve it, this is a bit hairy, c->coroutine will be
1971        overwritten on (re)connect, so we skip the normal cleanup
1972        path. Ideally, we shouldn't use the same channel structure? */
1973     if (c->state == SPICE_CHANNEL_STATE_CONNECTING) {
1974         g_object_unref(channel);
1975         goto end;
1976     }
1977
1978 cleanup:
1979     SPICE_DEBUG("Coroutine exit %s", c->name);
1980
1981     SPICE_CHANNEL_GET_CLASS(channel)->channel_disconnect(channel);
1982
1983     g_idle_add(spice_channel_delayed_unref, data);
1984
1985 end:
1986     /* Co-routine exits now - the SpiceChannel object may no longer exist,
1987        so don't do anything else now unless you like SEGVs */
1988     return NULL;
1989 }
1990
1991 static gboolean connect_delayed(gpointer data)
1992 {
1993     SpiceChannel *channel = data;
1994     spice_channel *c = channel->priv;
1995     struct coroutine *co;
1996
1997     SPICE_DEBUG("Open coroutine starting %p", channel);
1998     c->connect_delayed_id = 0;
1999
2000     co = &c->coroutine;
2001
2002     co->stack_size = 16 << 20; /* 16Mb */
2003     co->entry = spice_channel_coroutine;
2004     co->release = NULL;
2005
2006     coroutine_init(co);
2007     coroutine_yieldto(co, channel);
2008
2009     return FALSE;
2010 }
2011
2012 static gboolean channel_connect(SpiceChannel *channel)
2013 {
2014     spice_channel *c = channel->priv;
2015
2016     g_return_val_if_fail(c != NULL, FALSE);
2017
2018     if (c->session == NULL || c->channel_type == -1 || c->channel_id == -1) {
2019         /* unset properties or unknown channel type */
2020         g_warning("%s: channel setup incomplete", __FUNCTION__);
2021         return false;
2022     }
2023     if (c->state != SPICE_CHANNEL_STATE_UNCONNECTED) {
2024         g_warning("Invalid channel_connect state: %d", c->state);
2025         return true;
2026     }
2027
2028     if (spice_session_get_client_provided_socket(c->session)) {
2029         if (c->fd == -1) {
2030             g_signal_emit(channel, signals[SPICE_CHANNEL_OPEN_FD], 0, c->tls);
2031             return true;
2032         }
2033     }
2034     c->state = SPICE_CHANNEL_STATE_CONNECTING;
2035
2036     g_return_val_if_fail(c->sock == NULL, FALSE);
2037     g_object_ref(G_OBJECT(channel)); /* Unref'd when co-routine exits */
2038
2039     /* we connect in idle, to let previous coroutine exit, if present */
2040     c->connect_delayed_id = g_idle_add(connect_delayed, channel);
2041
2042     return true;
2043 }
2044
2045 /**
2046  * spice_channel_connect:
2047  * @channel:
2048  *
2049  * Connect the channel, using #SpiceSession connection informations
2050  *
2051  * Returns: %TRUE on success.
2052  **/
2053 gboolean spice_channel_connect(SpiceChannel *channel)
2054 {
2055     g_return_val_if_fail(SPICE_IS_CHANNEL(channel), FALSE);
2056     spice_channel *c = channel->priv;
2057
2058     if (c->state == SPICE_CHANNEL_STATE_CONNECTING)
2059         return TRUE;
2060
2061     return channel_connect(channel);
2062 }
2063
2064 /**
2065  * spice_channel_open_fd:
2066  * @channel:
2067  * @fd: a file descriptor (socket)
2068  *
2069  * Connect the channel using @fd socket.
2070  *
2071  * Returns: %TRUE on success.
2072  **/
2073 gboolean spice_channel_open_fd(SpiceChannel *channel, int fd)
2074 {
2075     spice_channel *c = SPICE_CHANNEL_GET_PRIVATE(channel);
2076
2077     g_return_val_if_fail(c != NULL, FALSE);
2078     g_return_val_if_fail(fd >= 0, FALSE);
2079
2080     c->fd = fd;
2081
2082     return channel_connect(channel);
2083 }
2084
2085 /* system or coroutine context */
2086 static void channel_disconnect(SpiceChannel *channel)
2087 {
2088     spice_channel *c = SPICE_CHANNEL_GET_PRIVATE(channel);
2089
2090     g_return_if_fail(c != NULL);
2091
2092     if (c->state == SPICE_CHANNEL_STATE_UNCONNECTED) {
2093         return;
2094     }
2095
2096     c->has_error = TRUE; /* break the loop */
2097
2098     if (c->connect_delayed_id) {
2099         g_source_remove(c->connect_delayed_id);
2100         c->connect_delayed_id = 0;
2101     }
2102
2103 #if HAVE_SASL
2104     if (c->sasl_conn) {
2105         sasl_dispose(&c->sasl_conn);
2106         c->sasl_conn = NULL;
2107         c->sasl_decoded_offset = c->sasl_decoded_length = 0;
2108     }
2109 #endif
2110
2111     spice_openssl_verify_free(c->sslverify);
2112     c->sslverify = NULL;
2113
2114     if (c->ssl) {
2115         SSL_free(c->ssl);
2116         c->ssl = NULL;
2117     }
2118
2119     if (c->ctx) {
2120         SSL_CTX_free(c->ctx);
2121         c->ctx = NULL;
2122     }
2123
2124     if (c->sock) {
2125         g_socket_close(c->sock, NULL);
2126         g_object_unref(c->sock);
2127         c->sock = NULL;
2128     }
2129     c->fd = -1;
2130
2131     free(c->peer_msg);
2132     c->peer_msg = NULL;
2133     c->peer_pos = 0;
2134
2135     if (c->xmit_buffer) {
2136         g_free(c->xmit_buffer);
2137         c->xmit_buffer = NULL;
2138         c->xmit_buffer_size = 0;
2139         c->xmit_buffer_capacity = 0;
2140     }
2141
2142     g_array_set_size(c->remote_common_caps, 0);
2143     g_array_set_size(c->remote_caps, 0);
2144     g_array_set_size(c->common_caps, 0);
2145     g_array_set_size(c->caps, 0);
2146
2147     if (c->state == SPICE_CHANNEL_STATE_READY)
2148         emit_main_context(channel, SPICE_CHANNEL_EVENT, SPICE_CHANNEL_CLOSED);
2149     g_return_if_fail(SPICE_IS_CHANNEL(channel));
2150     c->state = SPICE_CHANNEL_STATE_UNCONNECTED;
2151 }
2152
2153 /**
2154  * spice_channel_disconnect:
2155  * @channel:
2156  * @reason: a channel event emitted on main context (or #SPICE_CHANNEL_NONE)
2157  *
2158  * Close the socket and reset connection specific data. Finally, emit
2159  * @reason #SpiceChannel::channel-event on main context if not
2160  * #SPICE_CHANNEL_NONE.
2161  **/
2162 void spice_channel_disconnect(SpiceChannel *channel, SpiceChannelEvent reason)
2163 {
2164     spice_channel *c = SPICE_CHANNEL_GET_PRIVATE(channel);
2165
2166     g_return_if_fail(c != NULL);
2167
2168     if (c->state == SPICE_CHANNEL_STATE_UNCONNECTED)
2169         return;
2170
2171     if (reason == SPICE_CHANNEL_SWITCHING)
2172         c->state = SPICE_CHANNEL_STATE_SWITCHING;
2173
2174     c->has_error = TRUE; /* break the loop */
2175
2176     if (c->state == SPICE_CHANNEL_STATE_MIGRATING) {
2177         c->state = SPICE_CHANNEL_STATE_READY;
2178         coroutine_yieldto(&c->coroutine, NULL);
2179     } else
2180         spice_channel_wakeup(channel);
2181
2182     if (reason != SPICE_CHANNEL_NONE) {
2183         g_signal_emit(G_OBJECT(channel), signals[SPICE_CHANNEL_EVENT], 0, reason);
2184     }
2185 }
2186
2187 static gboolean test_capability(GArray *caps, guint32 cap)
2188 {
2189     guint32 c, word_index = cap / 32;
2190     gboolean ret;
2191
2192     if (caps == NULL)
2193         return FALSE;
2194
2195     if (caps->len < word_index + 1)
2196         return FALSE;
2197
2198     c = g_array_index(caps, guint32, word_index);
2199     ret = (c & (1 << (cap % 32))) != 0;
2200
2201     SPICE_DEBUG("test cap %d in 0x%X: %s", cap, c, ret ? "yes" : "no");
2202     return ret;
2203 }
2204
2205 /**
2206  * spice_channel_test_capability:
2207  * @self:
2208  * @cap:
2209  *
2210  * Test availability of remote "channel kind capability".
2211  *
2212  * Returns: %TRUE if @cap (channel kind capability) is available.
2213  **/
2214 gboolean spice_channel_test_capability(SpiceChannel *self, guint32 cap)
2215 {
2216     spice_channel *c;
2217
2218     g_return_val_if_fail(SPICE_IS_CHANNEL(self), FALSE);
2219
2220     c = self->priv;
2221     return test_capability(c->remote_caps, cap);
2222 }
2223
2224 /**
2225  * spice_channel_test_common_capability:
2226  * @self:
2227  * @cap:
2228  *
2229  * Test availability of remote "common channel capability".
2230  *
2231  * Returns: %TRUE if @cap (common channel capability) is available.
2232  **/
2233 gboolean spice_channel_test_common_capability(SpiceChannel *self, guint32 cap)
2234 {
2235     spice_channel *c;
2236
2237     g_return_val_if_fail(SPICE_IS_CHANNEL(self), FALSE);
2238
2239     c = self->priv;
2240     return test_capability(c->remote_common_caps, cap);
2241 }
2242
2243 static void set_capability(GArray *caps, guint32 cap)
2244 {
2245     guint word_index = cap / 32;
2246
2247     g_return_if_fail(caps != NULL);
2248
2249     if (caps->len <= word_index)
2250         g_array_set_size(caps, word_index + 1);
2251
2252     g_array_index(caps, guint32, word_index) =
2253         g_array_index(caps, guint32, word_index) | (1 << (cap % 32));
2254 }
2255
2256 /**
2257  * spice_channel_set_capability:
2258  * @channel:
2259  * @cap: a capability
2260  *
2261  * Enable specific channel-kind capability.
2262  **/
2263 /* FIXME: we may want to make caps read only from outside */
2264 void spice_channel_set_capability(SpiceChannel *channel, guint32 cap)
2265 {
2266     spice_channel *c;
2267
2268     g_return_if_fail(SPICE_IS_CHANNEL(channel));
2269
2270     c = channel->priv;
2271     set_capability(c->caps, cap);
2272 }
2273
2274 G_GNUC_INTERNAL
2275 void spice_channel_set_common_capability(SpiceChannel *channel, guint32 cap)
2276 {
2277     spice_channel *c;
2278
2279     g_return_if_fail(SPICE_IS_CHANNEL(channel));
2280
2281     c = channel->priv;
2282     set_capability(c->common_caps, cap);
2283 }
2284
2285 G_GNUC_INTERNAL
2286 SpiceSession* spice_channel_get_session(SpiceChannel *channel)
2287 {
2288     g_return_val_if_fail(SPICE_IS_CHANNEL(channel), NULL);
2289
2290     return channel->priv->session;
2291 }
2292
2293 G_GNUC_INTERNAL
2294 void spice_channel_swap(SpiceChannel *channel, SpiceChannel *swap)
2295 {
2296     spice_channel *c = SPICE_CHANNEL_GET_PRIVATE(channel);
2297     spice_channel *s = SPICE_CHANNEL_GET_PRIVATE(swap);
2298
2299     g_return_if_fail(c != NULL);
2300     g_return_if_fail(s != NULL);
2301
2302     g_return_if_fail(s->session != NULL);
2303     g_return_if_fail(s->sock != NULL);
2304
2305     {
2306         GSocket *sock = c->sock;
2307         SSL_CTX *ctx = c->ctx;
2308         SSL *ssl = c->ssl;
2309         SpiceOpenSSLVerify *sslverify = c->sslverify;
2310
2311         c->sock = s->sock;
2312         c->ctx = s->ctx;
2313         c->ssl = s->ssl;
2314         c->sslverify = s->sslverify;
2315
2316         s->sock = sock;
2317         s->ctx = ctx;
2318         s->ssl = ssl;
2319         s->sslverify = sslverify;
2320     }
2321
2322 #if HAVE_SASL
2323     {
2324         sasl_conn_t *sasl_conn = c->sasl_conn;
2325         const char *sasl_decoded = c->sasl_decoded;
2326         unsigned int sasl_decoded_length = c->sasl_decoded_length;
2327         unsigned int sasl_decoded_offset = c->sasl_decoded_offset;
2328
2329         c->sasl_conn = s->sasl_conn;
2330         c->sasl_decoded = s->sasl_decoded;
2331         c->sasl_decoded_length = s->sasl_decoded_length;
2332         c->sasl_decoded_offset = s->sasl_decoded_offset;
2333
2334         s->sasl_conn = sasl_conn;
2335         s->sasl_decoded = sasl_decoded;
2336         s->sasl_decoded_length = sasl_decoded_length;
2337         s->sasl_decoded_offset = sasl_decoded_offset;
2338     }
2339 #endif
2340 }
2341
2342 static const spice_msg_handler base_handlers[] = {
2343     [ SPICE_MSG_SET_ACK ]                  = spice_channel_handle_set_ack,
2344     [ SPICE_MSG_PING ]                     = spice_channel_handle_ping,
2345     [ SPICE_MSG_NOTIFY ]                   = spice_channel_handle_notify,
2346     [ SPICE_MSG_DISCONNECTING ]            = spice_channel_handle_disconnect,
2347     [ SPICE_MSG_WAIT_FOR_CHANNELS ]        = spice_channel_handle_wait_for_channels,
2348     [ SPICE_MSG_MIGRATE ]                  = spice_channel_handle_migrate,
2349 };
2350
2351 /* coroutine context */
2352 static void spice_channel_handle_msg(SpiceChannel *channel, spice_msg_in *msg)
2353 {
2354     int type = spice_msg_in_type(msg);
2355
2356     g_return_if_fail(type < SPICE_N_ELEMENTS(base_handlers));
2357     g_return_if_fail(base_handlers[type] != NULL);
2358
2359     base_handlers[type](channel, msg);
2360 }