2 * @file sipe-appshare.c
6 * Copyright (C) 2014-2016 SIPE Project <http://sipe.sourceforge.net/>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include "sipe-appshare.h"
29 #include "sipe-appshare-xfreerdp.h"
30 #include "sipe-appshare-remmina.h"
31 #include "sipe-backend.h"
32 #include "sipe-buddy.h"
33 #include "sipe-chat.h"
34 #include "sipe-common.h"
35 #include "sipe-conf.h"
36 #include "sipe-core.h"
37 #include "sipe-core-private.h"
38 #include "sipe-media.h"
40 #include "sipe-schedule.h"
41 #include "sipe-user.h"
42 #include "sipe-utils.h"
44 struct sipe_appshare
{
45 struct sipe_media_stream
*stream
;
48 guint rdp_channel_readable_watch_id
;
49 guint rdp_channel_writable_watch_id
;
50 struct sipe_user_ask_ctx
*ask_ctx
;
52 gchar rdp_channel_buffer
[0x800];
53 gchar
*rdp_channel_buffer_pos
;
54 gsize rdp_channel_buffer_len
;
56 struct sipe_rdp_client client
;
59 typedef gboolean (*rdp_init_func
)(struct sipe_rdp_client
*);
61 rdp_init_func rdp_init_functions
[] = {
62 sipe_appshare_remmina_init
,
63 sipe_appshare_xfreerdp_init
,
68 sipe_appshare_free(struct sipe_appshare
*appshare
)
70 if (appshare
->rdp_channel_readable_watch_id
!= 0) {
71 g_source_destroy(g_main_context_find_source_by_id(NULL
,
72 appshare
->rdp_channel_readable_watch_id
));
75 if (appshare
->rdp_channel_writable_watch_id
!= 0) {
76 g_source_destroy(g_main_context_find_source_by_id(NULL
,
77 appshare
->rdp_channel_writable_watch_id
));
80 if (appshare
->channel
) {
83 g_io_channel_shutdown(appshare
->channel
, TRUE
, &error
);
85 SIPE_DEBUG_ERROR("Error shutting down RDP channel: %s",
89 g_io_channel_unref(appshare
->channel
);
92 if (appshare
->socket
) {
93 g_object_unref(appshare
->socket
);
96 if (appshare
->ask_ctx
) {
97 sipe_user_close_ask(appshare
->ask_ctx
);
100 if (appshare
->client
.free_cb
) {
101 appshare
->client
.free_cb(&appshare
->client
);
108 rdp_channel_readable_cb(GIOChannel
*channel
,
109 GIOCondition condition
,
112 struct sipe_appshare
*appshare
= data
;
113 GError
*error
= NULL
;
117 if (condition
& G_IO_HUP
) {
118 struct sipe_media_call
*call
= appshare
->stream
->call
;
120 sipe_backend_media_hangup(call
->backend_private
, TRUE
);
124 buffer
= g_malloc(2048);
125 while (sipe_media_stream_is_writable(appshare
->stream
)) {
128 status
= g_io_channel_read_chars(channel
,
130 &bytes_read
, &error
);
132 struct sipe_media_call
*call
= appshare
->stream
->call
;
134 SIPE_DEBUG_ERROR("Error reading from RDP channel: %s",
137 sipe_backend_media_hangup(call
->backend_private
, TRUE
);
142 if (status
== G_IO_STATUS_EOF
) {
143 struct sipe_media_call
*call
= appshare
->stream
->call
;
145 sipe_backend_media_hangup(call
->backend_private
, TRUE
);
150 if (bytes_read
== 0) {
154 sipe_media_stream_write(appshare
->stream
, (guint8
*)buffer
,
156 SIPE_DEBUG_INFO("Written: %" G_GSIZE_FORMAT
"\n", bytes_read
);
164 socket_connect_cb(SIPE_UNUSED_PARAMETER GIOChannel
*channel
,
165 SIPE_UNUSED_PARAMETER GIOCondition condition
,
168 struct sipe_appshare
*appshare
= data
;
169 GError
*error
= NULL
;
170 GSocket
*data_socket
;
172 data_socket
= g_socket_accept(appshare
->socket
, NULL
, &error
);
174 struct sipe_media_call
*call
= appshare
->stream
->call
;
176 SIPE_DEBUG_ERROR("Error accepting RDP client connection: %s",
179 sipe_backend_media_hangup(call
->backend_private
, TRUE
);
183 g_io_channel_shutdown(appshare
->channel
, TRUE
, &error
);
185 struct sipe_media_call
*call
= appshare
->stream
->call
;
187 SIPE_DEBUG_ERROR("Error shutting down RDP channel: %s",
190 g_object_unref(data_socket
);
191 sipe_backend_media_hangup(call
->backend_private
, TRUE
);
194 g_io_channel_unref(appshare
->channel
);
196 g_object_unref(appshare
->socket
);
197 appshare
->socket
= data_socket
;
199 appshare
->channel
= g_io_channel_unix_new(
200 g_socket_get_fd(appshare
->socket
));
202 // No encoding for binary data
203 g_io_channel_set_encoding(appshare
->channel
, NULL
, &error
);
205 struct sipe_media_call
*call
= appshare
->stream
->call
;
207 SIPE_DEBUG_ERROR("Error setting RDP channel encoding: %s",
210 sipe_backend_media_hangup(call
->backend_private
, TRUE
);
214 appshare
->rdp_channel_readable_watch_id
=
215 g_io_add_watch(appshare
->channel
, G_IO_IN
| G_IO_HUP
,
216 rdp_channel_readable_cb
, appshare
);
222 launch_rdp_client(struct sipe_appshare
*appshare
)
224 struct sipe_rdp_client
*client
= &appshare
->client
;
225 struct sipe_media_call
*call
= appshare
->stream
->call
;
226 GSocketAddress
*address
;
227 GError
*error
= NULL
;
229 address
= client
->get_listen_address_cb(client
);
231 sipe_backend_media_hangup(call
->backend_private
, TRUE
);
235 appshare
->socket
= g_socket_new(g_socket_address_get_family(address
),
236 G_SOCKET_TYPE_STREAM
,
237 G_SOCKET_PROTOCOL_DEFAULT
,
240 SIPE_DEBUG_ERROR("Can't create RDP client listen socket: %s",
243 sipe_backend_media_hangup(call
->backend_private
, TRUE
);
247 g_socket_set_blocking(appshare
->socket
, FALSE
);
249 g_socket_bind(appshare
->socket
, address
, TRUE
, &error
);
250 g_object_unref(address
);
252 SIPE_DEBUG_ERROR("Can't bind to RDP client socket: %s",
255 sipe_backend_media_hangup(call
->backend_private
, TRUE
);
259 g_socket_listen(appshare
->socket
, &error
);
261 SIPE_DEBUG_ERROR("Can't listen on RDP client socket: %s",
264 sipe_backend_media_hangup(call
->backend_private
, TRUE
);
268 appshare
->channel
= g_io_channel_unix_new(
269 g_socket_get_fd(appshare
->socket
));
270 appshare
->rdp_channel_readable_watch_id
=
271 g_io_add_watch(appshare
->channel
, G_IO_IN
,
272 socket_connect_cb
, appshare
);
274 address
= g_socket_get_local_address(appshare
->socket
, &error
);
276 SIPE_DEBUG_ERROR("Couldn't get appshare socket address: %s",
279 sipe_backend_media_hangup(call
->backend_private
, TRUE
);
283 if (!client
->launch_cb(client
, address
, appshare
->stream
)) {
284 sipe_backend_media_hangup(call
->backend_private
, TRUE
);
287 g_object_unref(address
);
291 rdp_client_channel_write(struct sipe_appshare
*appshare
)
294 GError
*error
= NULL
;
296 g_io_channel_write_chars(appshare
->channel
,
297 appshare
->rdp_channel_buffer_pos
,
298 appshare
->rdp_channel_buffer_len
,
299 &bytes_written
, &error
);
301 SIPE_DEBUG_ERROR("Couldn't write data to RDP client: %s",
307 g_io_channel_flush(appshare
->channel
, &error
);
309 if (g_error_matches(error
, G_IO_CHANNEL_ERROR
,
310 G_IO_CHANNEL_ERROR_PIPE
)) {
311 /* Ignore broken pipe here and wait for the call to be
312 * hung up upon G_IO_HUP in client_channel_cb(). */
317 SIPE_DEBUG_ERROR("Couldn't flush RDP channel: %s",
323 appshare
->rdp_channel_buffer_pos
+= bytes_written
;
324 appshare
->rdp_channel_buffer_len
-= bytes_written
;
326 return bytes_written
;
330 delayed_hangup_cb(SIPE_UNUSED_PARAMETER
struct sipe_core_private
*sipe_private
,
333 struct sipe_media_call
*call
= data
;
335 sipe_backend_media_hangup(call
->backend_private
, TRUE
);
339 rdp_channel_writable_cb(SIPE_UNUSED_PARAMETER GIOChannel
*channel
,
340 SIPE_UNUSED_PARAMETER GIOCondition condition
,
343 struct sipe_appshare
*appshare
= data
;
344 struct sipe_media_call
*call
= appshare
->stream
->call
;
346 if (rdp_client_channel_write(appshare
) < 0) {
347 sipe_backend_media_hangup(call
->backend_private
, TRUE
);
351 if (appshare
->rdp_channel_buffer_len
== 0) {
352 // Writing done, disconnect writable watch.
353 appshare
->rdp_channel_writable_watch_id
= 0;
361 read_cb(struct sipe_media_stream
*stream
)
363 struct sipe_appshare
*appshare
= sipe_media_stream_get_data(stream
);
365 gssize bytes_written
= 0;
367 if (appshare
->rdp_channel_writable_watch_id
!= 0) {
368 // Data still in the buffer. Let the client read it first.
372 while (bytes_read
== (gint
)bytes_written
) {
373 bytes_read
= sipe_backend_media_stream_read(stream
,
374 (guint8
*)appshare
->rdp_channel_buffer
,
375 sizeof (appshare
->rdp_channel_buffer
));
376 if (bytes_read
== 0) {
380 appshare
->rdp_channel_buffer_pos
= appshare
->rdp_channel_buffer
;
381 appshare
->rdp_channel_buffer_len
= bytes_read
;
383 bytes_written
= rdp_client_channel_write(appshare
);
385 if (bytes_written
< 0) {
386 /* Don't deallocate stream while in its read callback.
387 * Schedule call hangup to be executed after we're back
388 * in the message loop. */
389 sipe_schedule_seconds(sipe_media_get_sipe_core_private(stream
->call
),
390 "appshare delayed hangup",
391 stream
->call
->backend_private
,
399 if (bytes_read
!= (gint
)bytes_written
) {
400 /* Schedule writing of the buffer's remainder to when
401 * RDP channel becomes writable again. */
402 appshare
->rdp_channel_writable_watch_id
=
403 g_io_add_watch(appshare
->channel
, G_IO_OUT
,
404 rdp_channel_writable_cb
,
410 writable_cb(struct sipe_media_stream
*stream
)
412 struct sipe_appshare
*appshare
= sipe_media_stream_get_data(stream
);
414 if (!appshare
->socket
) {
415 launch_rdp_client(appshare
);
420 accept_cb(SIPE_UNUSED_PARAMETER
struct sipe_core_private
*sipe_private
,
423 struct sipe_appshare
*appshare
= data
;
424 appshare
->ask_ctx
= NULL
;
426 sipe_backend_media_accept(appshare
->stream
->call
->backend_private
, TRUE
);
430 decline_cb(SIPE_UNUSED_PARAMETER
struct sipe_core_private
*sipe_private
,
433 struct sipe_appshare
*appshare
= data
;
434 appshare
->ask_ctx
= NULL
;
436 sipe_backend_media_hangup(appshare
->stream
->call
->backend_private
, TRUE
);
439 static struct sipe_user_ask_ctx
*
440 ask_accept_applicationsharing(struct sipe_core_private
*sipe_private
,
442 SipeUserAskCb accept_cb
,
443 SipeUserAskCb decline_cb
,
446 struct sipe_user_ask_ctx
*ctx
;
447 gchar
*alias
= sipe_buddy_get_alias(sipe_private
, from
);
448 gchar
*ask_msg
= g_strdup_printf(_("%s wants to start presenting"),
449 alias
? alias
: from
);
451 ctx
= sipe_user_ask(sipe_private
, ask_msg
,
452 _("Accept"), accept_cb
,
453 _("Decline"), decline_cb
,
462 static struct sipe_appshare
*
463 initialize_appshare(struct sipe_media_stream
*stream
)
465 struct sipe_appshare
*appshare
;
466 struct sipe_media_call
*call
;
467 struct sipe_core_private
*sipe_private
;
468 SipeRDPClient client
;
471 sipe_private
= sipe_media_get_sipe_core_private(call
);
473 appshare
= g_new0(struct sipe_appshare
, 1);
474 appshare
->stream
= stream
;
476 sipe_media_stream_set_data(stream
, appshare
,
477 (GDestroyNotify
)sipe_appshare_free
);
479 client
= sipe_backend_appshare_get_rdp_client(SIPE_CORE_PUBLIC
);
480 if (!rdp_init_functions
[client
](&appshare
->client
)) {
481 /* Preferred client isn't available. Fall back to whatever
482 * application we can find. */
485 for (init
= rdp_init_functions
; *init
; ++init
) {
486 if ((*init
)(&appshare
->client
)) {
492 sipe_backend_notify_error(SIPE_CORE_PUBLIC
,
493 _("Application sharing error"),
494 _("Remote desktop client isn't installed."));
495 sipe_backend_media_hangup(call
->backend_private
, TRUE
);
500 sipe_media_stream_add_extra_attribute(stream
,
501 "x-applicationsharing-session-id", "1");
502 sipe_media_stream_add_extra_attribute(stream
,
503 "x-applicationsharing-role", "viewer");
504 sipe_media_stream_add_extra_attribute(stream
,
505 "x-applicationsharing-media-type", "rdp");
507 stream
->read_cb
= read_cb
;
508 stream
->writable_cb
= writable_cb
;
514 process_incoming_invite_appshare(struct sipe_core_private
*sipe_private
,
517 struct sipe_media_call
*call
;
518 struct sipe_media_stream
*stream
;
519 struct sipe_appshare
*appshare
;
521 call
= process_incoming_invite_call(sipe_private
, msg
);
526 stream
= sipe_core_media_get_stream_by_id(call
, "applicationsharing");
528 sipe_backend_media_hangup(call
->backend_private
, TRUE
);
532 appshare
= initialize_appshare(stream
);
537 from
= parse_from(sipmsg_find_header(msg
, "From"));
538 appshare
->ask_ctx
= ask_accept_applicationsharing(sipe_private
, from
,
547 connect_conference(struct sipe_core_private
*sipe_private
,
548 struct sipe_chat_session
*chat_session
)
550 struct sipe_media_call
*call
;
551 struct sipe_media_stream
*stream
;
554 uri
= sipe_conf_build_uri(chat_session
->id
, "applicationsharing");
556 call
= sipe_media_call_new(sipe_private
, uri
, NULL
,
558 SIPE_MEDIA_CALL_NO_UI
);
562 stream
= sipe_media_stream_add(call
, "applicationsharing",
563 SIPE_MEDIA_APPLICATION
,
564 SIPE_ICE_RFC_5245
, TRUE
, 0);
566 sipe_backend_notify_error(SIPE_CORE_PUBLIC
,
567 _("Application sharing error"),
568 _("Couldn't connect application sharing"));
569 sipe_backend_media_hangup(call
->backend_private
, FALSE
);
572 sipe_media_stream_add_extra_attribute(stream
, "connection", "new");
573 sipe_media_stream_add_extra_attribute(stream
, "setup", "active");
575 initialize_appshare(stream
);
579 sipe_core_appshare_connect_conference(struct sipe_core_public
*sipe_public
,
580 struct sipe_chat_session
*chat_session
,
581 gboolean user_must_accept
)
583 if (user_must_accept
) {
586 if (chat_session
->title
) {
587 from
= chat_session
->title
;
588 } else if (chat_session
->organizer
) {
589 from
= chat_session
->organizer
;
591 from
= chat_session
->id
;
594 ask_accept_applicationsharing(SIPE_CORE_PRIVATE
, from
,
595 (SipeUserAskCb
)connect_conference
,
599 connect_conference(SIPE_CORE_PRIVATE
, chat_session
);