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
29 #include "sipe-appshare.h"
30 #include "sipe-appshare-client.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
;
60 sipe_appshare_free(struct sipe_appshare
*appshare
)
62 if (appshare
->rdp_channel_readable_watch_id
!= 0) {
63 g_source_destroy(g_main_context_find_source_by_id(NULL
,
64 appshare
->rdp_channel_readable_watch_id
));
67 if (appshare
->rdp_channel_writable_watch_id
!= 0) {
68 g_source_destroy(g_main_context_find_source_by_id(NULL
,
69 appshare
->rdp_channel_writable_watch_id
));
72 if (appshare
->channel
) {
75 g_io_channel_shutdown(appshare
->channel
, TRUE
, &error
);
77 SIPE_DEBUG_ERROR("Error shutting down RDP channel: %s",
81 g_io_channel_unref(appshare
->channel
);
84 if (appshare
->socket
) {
85 g_object_unref(appshare
->socket
);
88 if (appshare
->ask_ctx
) {
89 sipe_user_close_ask(appshare
->ask_ctx
);
92 g_free(appshare
->client
.cmdline
);
93 if (appshare
->client
.free_cb
) {
94 appshare
->client
.free_cb(&appshare
->client
);
101 rdp_channel_readable_cb(GIOChannel
*channel
,
102 GIOCondition condition
,
105 struct sipe_appshare
*appshare
= data
;
106 GError
*error
= NULL
;
110 if (condition
& G_IO_HUP
) {
111 struct sipe_media_call
*call
= appshare
->stream
->call
;
113 sipe_backend_media_hangup(call
->backend_private
, TRUE
);
117 buffer
= g_malloc(2048);
118 while (sipe_media_stream_is_writable(appshare
->stream
)) {
121 status
= g_io_channel_read_chars(channel
,
123 &bytes_read
, &error
);
125 struct sipe_media_call
*call
= appshare
->stream
->call
;
127 SIPE_DEBUG_ERROR("Error reading from RDP channel: %s",
130 sipe_backend_media_hangup(call
->backend_private
, TRUE
);
135 if (status
== G_IO_STATUS_EOF
) {
136 struct sipe_media_call
*call
= appshare
->stream
->call
;
138 sipe_backend_media_hangup(call
->backend_private
, TRUE
);
143 if (bytes_read
== 0) {
147 sipe_media_stream_write(appshare
->stream
, (guint8
*)buffer
,
149 SIPE_DEBUG_INFO("Written: %" G_GSIZE_FORMAT
"\n", bytes_read
);
157 socket_connect_cb(SIPE_UNUSED_PARAMETER GIOChannel
*channel
,
158 SIPE_UNUSED_PARAMETER GIOCondition condition
,
161 struct sipe_appshare
*appshare
= data
;
162 GError
*error
= NULL
;
163 GSocket
*data_socket
;
166 data_socket
= g_socket_accept(appshare
->socket
, NULL
, &error
);
168 struct sipe_media_call
*call
= appshare
->stream
->call
;
170 SIPE_DEBUG_ERROR("Error accepting RDP client connection: %s",
173 sipe_backend_media_hangup(call
->backend_private
, TRUE
);
177 g_io_channel_shutdown(appshare
->channel
, TRUE
, &error
);
179 struct sipe_media_call
*call
= appshare
->stream
->call
;
181 SIPE_DEBUG_ERROR("Error shutting down RDP channel: %s",
184 g_object_unref(data_socket
);
185 sipe_backend_media_hangup(call
->backend_private
, TRUE
);
188 g_io_channel_unref(appshare
->channel
);
190 g_object_unref(appshare
->socket
);
191 appshare
->socket
= data_socket
;
193 fd
= g_socket_get_fd(appshare
->socket
);
195 struct sipe_media_call
*call
= appshare
->stream
->call
;
197 SIPE_DEBUG_ERROR_NOFORMAT("Invalid file descriptor for RDP client connection socket");
198 sipe_backend_media_hangup(call
->backend_private
, TRUE
);
201 appshare
->channel
= g_io_channel_unix_new(fd
);
203 // No encoding for binary data
204 g_io_channel_set_encoding(appshare
->channel
, NULL
, &error
);
206 struct sipe_media_call
*call
= appshare
->stream
->call
;
208 SIPE_DEBUG_ERROR("Error setting RDP channel encoding: %s",
211 sipe_backend_media_hangup(call
->backend_private
, TRUE
);
215 appshare
->rdp_channel_readable_watch_id
=
216 g_io_add_watch(appshare
->channel
, G_IO_IN
| G_IO_HUP
,
217 rdp_channel_readable_cb
, appshare
);
223 launch_rdp_client(struct sipe_appshare
*appshare
)
225 struct sipe_rdp_client
*client
= &appshare
->client
;
226 struct sipe_media_call
*call
= appshare
->stream
->call
;
227 GSocketAddress
*address
;
228 GError
*error
= NULL
;
231 address
= client
->get_listen_address_cb(client
);
233 sipe_backend_media_hangup(call
->backend_private
, TRUE
);
237 appshare
->socket
= g_socket_new(g_socket_address_get_family(address
),
238 G_SOCKET_TYPE_STREAM
,
239 G_SOCKET_PROTOCOL_DEFAULT
,
242 SIPE_DEBUG_ERROR("Can't create RDP client listen socket: %s",
245 g_object_unref(address
);
246 sipe_backend_media_hangup(call
->backend_private
, TRUE
);
250 g_socket_set_blocking(appshare
->socket
, FALSE
);
252 g_socket_bind(appshare
->socket
, address
, TRUE
, &error
);
253 g_object_unref(address
);
255 SIPE_DEBUG_ERROR("Can't bind to RDP client socket: %s",
258 sipe_backend_media_hangup(call
->backend_private
, TRUE
);
262 g_socket_listen(appshare
->socket
, &error
);
264 SIPE_DEBUG_ERROR("Can't listen on RDP client socket: %s",
267 sipe_backend_media_hangup(call
->backend_private
, TRUE
);
271 fd
= g_socket_get_fd(appshare
->socket
);
273 SIPE_DEBUG_ERROR_NOFORMAT("Invalid file descriptor for RDP client listen socket");
274 sipe_backend_media_hangup(call
->backend_private
, TRUE
);
277 appshare
->channel
= g_io_channel_unix_new(fd
);
279 appshare
->rdp_channel_readable_watch_id
=
280 g_io_add_watch(appshare
->channel
, G_IO_IN
,
281 socket_connect_cb
, appshare
);
283 address
= g_socket_get_local_address(appshare
->socket
, &error
);
285 SIPE_DEBUG_ERROR("Couldn't get appshare socket address: %s",
288 sipe_backend_media_hangup(call
->backend_private
, TRUE
);
292 if (!client
->launch_cb(client
, address
, appshare
->stream
)) {
293 sipe_backend_media_hangup(call
->backend_private
, TRUE
);
296 g_object_unref(address
);
300 rdp_client_channel_write(struct sipe_appshare
*appshare
)
303 GError
*error
= NULL
;
305 g_io_channel_write_chars(appshare
->channel
,
306 appshare
->rdp_channel_buffer_pos
,
307 appshare
->rdp_channel_buffer_len
,
308 &bytes_written
, &error
);
310 SIPE_DEBUG_ERROR("Couldn't write data to RDP client: %s",
316 g_io_channel_flush(appshare
->channel
, &error
);
318 if (g_error_matches(error
, G_IO_CHANNEL_ERROR
,
319 G_IO_CHANNEL_ERROR_PIPE
)) {
320 /* Ignore broken pipe here and wait for the call to be
321 * hung up upon G_IO_HUP in client_channel_cb(). */
326 SIPE_DEBUG_ERROR("Couldn't flush RDP channel: %s",
332 appshare
->rdp_channel_buffer_pos
+= bytes_written
;
333 appshare
->rdp_channel_buffer_len
-= bytes_written
;
335 return bytes_written
;
339 delayed_hangup_cb(SIPE_UNUSED_PARAMETER
struct sipe_core_private
*sipe_private
,
342 struct sipe_media_call
*call
= data
;
344 sipe_backend_media_hangup(call
->backend_private
, TRUE
);
348 rdp_channel_writable_cb(SIPE_UNUSED_PARAMETER GIOChannel
*channel
,
349 SIPE_UNUSED_PARAMETER GIOCondition condition
,
352 struct sipe_appshare
*appshare
= data
;
353 struct sipe_media_call
*call
= appshare
->stream
->call
;
355 if (rdp_client_channel_write(appshare
) < 0) {
356 sipe_backend_media_hangup(call
->backend_private
, TRUE
);
360 if (appshare
->rdp_channel_buffer_len
== 0) {
361 // Writing done, disconnect writable watch.
362 appshare
->rdp_channel_writable_watch_id
= 0;
370 read_cb(struct sipe_media_stream
*stream
)
372 struct sipe_appshare
*appshare
= sipe_media_stream_get_data(stream
);
374 gssize bytes_written
= 0;
376 if (appshare
->rdp_channel_writable_watch_id
!= 0) {
377 // Data still in the buffer. Let the client read it first.
381 while (bytes_read
== (gint
)bytes_written
) {
382 bytes_read
= sipe_backend_media_stream_read(stream
,
383 (guint8
*)appshare
->rdp_channel_buffer
,
384 sizeof (appshare
->rdp_channel_buffer
));
385 if (bytes_read
== 0) {
389 appshare
->rdp_channel_buffer_pos
= appshare
->rdp_channel_buffer
;
390 appshare
->rdp_channel_buffer_len
= bytes_read
;
392 bytes_written
= rdp_client_channel_write(appshare
);
394 if (bytes_written
< 0) {
395 /* Don't deallocate stream while in its read callback.
396 * Schedule call hangup to be executed after we're back
397 * in the message loop. */
398 sipe_schedule_seconds(sipe_media_get_sipe_core_private(stream
->call
),
399 "appshare delayed hangup",
400 stream
->call
->backend_private
,
408 if (bytes_read
!= (gint
)bytes_written
) {
409 /* Schedule writing of the buffer's remainder to when
410 * RDP channel becomes writable again. */
411 appshare
->rdp_channel_writable_watch_id
=
412 g_io_add_watch(appshare
->channel
, G_IO_OUT
,
413 rdp_channel_writable_cb
,
419 writable_cb(struct sipe_media_stream
*stream
)
421 struct sipe_appshare
*appshare
= sipe_media_stream_get_data(stream
);
423 if (!appshare
->socket
) {
424 launch_rdp_client(appshare
);
429 accept_cb(SIPE_UNUSED_PARAMETER
struct sipe_core_private
*sipe_private
,
432 struct sipe_appshare
*appshare
= data
;
433 appshare
->ask_ctx
= NULL
;
435 sipe_backend_media_accept(appshare
->stream
->call
->backend_private
, TRUE
);
439 decline_cb(SIPE_UNUSED_PARAMETER
struct sipe_core_private
*sipe_private
,
442 struct sipe_appshare
*appshare
= data
;
443 appshare
->ask_ctx
= NULL
;
445 sipe_backend_media_hangup(appshare
->stream
->call
->backend_private
, TRUE
);
448 static struct sipe_user_ask_ctx
*
449 ask_accept_applicationsharing(struct sipe_core_private
*sipe_private
,
451 SipeUserAskCb accept_cb
,
452 SipeUserAskCb decline_cb
,
455 struct sipe_user_ask_ctx
*ctx
;
456 gchar
*alias
= sipe_buddy_get_alias(sipe_private
, from
);
457 gchar
*ask_msg
= g_strdup_printf(_("%s wants to start presenting"),
458 alias
? alias
: from
);
460 ctx
= sipe_user_ask(sipe_private
, ask_msg
,
461 _("Accept"), accept_cb
,
462 _("Decline"), decline_cb
,
471 static struct sipe_appshare
*
472 initialize_appshare(struct sipe_media_stream
*stream
)
474 struct sipe_appshare
*appshare
;
475 struct sipe_media_call
*call
;
476 struct sipe_core_private
*sipe_private
;
477 const gchar
*cmdline
;
480 sipe_private
= sipe_media_get_sipe_core_private(call
);
482 appshare
= g_new0(struct sipe_appshare
, 1);
483 appshare
->stream
= stream
;
485 sipe_media_stream_set_data(stream
, appshare
,
486 (GDestroyNotify
)sipe_appshare_free
);
488 cmdline
= sipe_backend_setting(SIPE_CORE_PUBLIC
,
489 SIPE_SETTING_RDP_CLIENT
);
490 if (is_empty(cmdline
))
492 appshare
->client
.cmdline
= g_strdup(cmdline
);
494 if (strstr(cmdline
, "xfreerdp")) {
495 sipe_appshare_xfreerdp_init(&appshare
->client
);
496 } else if (strstr(cmdline
, "remmina")) {
497 sipe_appshare_remmina_init(&appshare
->client
);
499 sipe_backend_notify_error(SIPE_CORE_PUBLIC
,
500 _("Application sharing error"),
501 _("Unknown remote desktop client configured."));
502 sipe_backend_media_hangup(call
->backend_private
, TRUE
);
506 sipe_media_stream_add_extra_attribute(stream
,
507 "x-applicationsharing-session-id", "1");
508 sipe_media_stream_add_extra_attribute(stream
,
509 "x-applicationsharing-role", "viewer");
510 sipe_media_stream_add_extra_attribute(stream
,
511 "x-applicationsharing-media-type", "rdp");
513 stream
->read_cb
= read_cb
;
514 stream
->writable_cb
= writable_cb
;
520 process_incoming_invite_appshare(struct sipe_core_private
*sipe_private
,
523 struct sipe_media_call
*call
;
524 struct sipe_media_stream
*stream
;
525 struct sipe_appshare
*appshare
;
527 call
= process_incoming_invite_call(sipe_private
, msg
);
532 stream
= sipe_core_media_get_stream_by_id(call
, "applicationsharing");
534 sipe_backend_media_hangup(call
->backend_private
, TRUE
);
538 appshare
= initialize_appshare(stream
);
543 from
= parse_from(sipmsg_find_header(msg
, "From"));
544 appshare
->ask_ctx
= ask_accept_applicationsharing(sipe_private
, from
,
553 connect_conference(struct sipe_core_private
*sipe_private
,
554 struct sipe_chat_session
*chat_session
)
556 struct sipe_media_call
*call
;
557 struct sipe_media_stream
*stream
;
560 chat_session
->appshare_ask_ctx
= NULL
;
562 uri
= sipe_conf_build_uri(chat_session
->id
, "applicationsharing");
564 call
= sipe_media_call_new(sipe_private
, uri
, NULL
,
566 SIPE_MEDIA_CALL_NO_UI
);
570 stream
= sipe_media_stream_add(call
, "applicationsharing",
571 SIPE_MEDIA_APPLICATION
,
572 SIPE_ICE_RFC_5245
, TRUE
, 0);
574 sipe_backend_notify_error(SIPE_CORE_PUBLIC
,
575 _("Application sharing error"),
576 _("Couldn't connect application sharing"));
577 sipe_backend_media_hangup(call
->backend_private
, FALSE
);
580 sipe_media_stream_add_extra_attribute(stream
, "connection", "new");
581 sipe_media_stream_add_extra_attribute(stream
, "setup", "active");
583 initialize_appshare(stream
);
587 sipe_core_appshare_connect_conference(struct sipe_core_public
*sipe_public
,
588 struct sipe_chat_session
*chat_session
,
589 gboolean user_must_accept
)
591 if (user_must_accept
) {
594 if (chat_session
->appshare_ask_ctx
) {
595 // Accept dialog already opened.
599 if (chat_session
->title
) {
600 from
= chat_session
->title
;
601 } else if (chat_session
->organizer
) {
602 from
= chat_session
->organizer
;
604 from
= chat_session
->id
;
607 chat_session
->appshare_ask_ctx
=
608 ask_accept_applicationsharing(SIPE_CORE_PRIVATE
,
610 (SipeUserAskCb
)connect_conference
,
614 connect_conference(SIPE_CORE_PRIVATE
, chat_session
);