client.c (6041B)
1/* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 20#include "config.h" 21 22#include "client.h" 23#include "user.h" 24#include "vnc.h" 25 26#ifdef ENABLE_COMMON_SSH 27#include "common-ssh/sftp.h" 28#include "common-ssh/ssh.h" 29#include "common-ssh/user.h" 30#endif 31 32#ifdef ENABLE_PULSE 33#include "pulse/pulse.h" 34#endif 35 36#include <guacamole/client.h> 37#include <guacamole/mem.h> 38#include <guacamole/recording.h> 39 40#include <pthread.h> 41#include <stdlib.h> 42#include <string.h> 43 44#ifdef ENABLE_PULSE 45/** 46 * Add the provided user to the provided audio stream. 47 * 48 * @param user 49 * The pending user who should be added to the audio stream. 50 * 51 * @param data 52 * The audio stream that the user should be added to. 53 * 54 * @return 55 * Always NULL. 56 */ 57static void* guac_vnc_sync_pending_user_audio(guac_user* user, void* data) { 58 59 /* Add the user to the stream */ 60 guac_pa_stream* audio = (guac_pa_stream*) data; 61 guac_pa_stream_add_user(audio, user); 62 63 return NULL; 64 65} 66#endif 67 68/** 69 * A pending join handler implementation that will synchronize the connection 70 * state for all pending users prior to them being promoted to full user. 71 * 72 * @param client 73 * The client whose pending users are about to be promoted. 74 * 75 * @return 76 * Always zero. 77 */ 78static int guac_vnc_join_pending_handler(guac_client* client) { 79 80 guac_vnc_client* vnc_client = (guac_vnc_client*) client->data; 81 guac_socket* broadcast_socket = client->pending_socket; 82 83#ifdef ENABLE_PULSE 84 /* Synchronize any audio stream for each pending user */ 85 if (vnc_client->audio) 86 guac_client_foreach_pending_user( 87 client, guac_vnc_sync_pending_user_audio, vnc_client->audio); 88#endif 89 90 /* Synchronize with current display */ 91 if (vnc_client->display != NULL) { 92 guac_common_display_dup(vnc_client->display, client, broadcast_socket); 93 guac_socket_flush(broadcast_socket); 94 } 95 96 return 0; 97 98} 99 100int guac_client_init(guac_client* client) { 101 102 /* Set client args */ 103 client->args = GUAC_VNC_CLIENT_ARGS; 104 105 /* Alloc client data */ 106 guac_vnc_client* vnc_client = guac_mem_zalloc(sizeof(guac_vnc_client)); 107 client->data = vnc_client; 108 109#ifdef ENABLE_VNC_TLS_LOCKING 110 /* Initialize the TLS write lock */ 111 pthread_mutex_init(&vnc_client->tls_lock, NULL); 112#endif 113 114 /* Init clipboard */ 115 vnc_client->clipboard = guac_common_clipboard_alloc(); 116 117 /* Set handlers */ 118 client->join_handler = guac_vnc_user_join_handler; 119 client->join_pending_handler = guac_vnc_join_pending_handler; 120 client->leave_handler = guac_vnc_user_leave_handler; 121 client->free_handler = guac_vnc_client_free_handler; 122 123 return 0; 124} 125 126int guac_vnc_client_free_handler(guac_client* client) { 127 128 guac_vnc_client* vnc_client = (guac_vnc_client*) client->data; 129 guac_vnc_settings* settings = vnc_client->settings; 130 131 /* Clean up VNC client*/ 132 rfbClient* rfb_client = vnc_client->rfb_client; 133 if (rfb_client != NULL) { 134 135 /* Wait for client thread to finish */ 136 pthread_join(vnc_client->client_thread, NULL); 137 138 /* Free memory that may not be free'd by libvncclient's 139 * rfbClientCleanup() prior to libvncclient 0.9.12 */ 140 141 if (rfb_client->frameBuffer != NULL) { 142 free(rfb_client->frameBuffer); 143 rfb_client->frameBuffer = NULL; 144 } 145 146 if (rfb_client->raw_buffer != NULL) { 147 free(rfb_client->raw_buffer); 148 rfb_client->raw_buffer = NULL; 149 } 150 151 if (rfb_client->rcSource != NULL) { 152 free(rfb_client->rcSource); 153 rfb_client->rcSource = NULL; 154 } 155 156 /* Free VNC rfbClientData linked list (may not be free'd by 157 * rfbClientCleanup(), depending on libvncclient version) */ 158 159 while (rfb_client->clientData != NULL) { 160 rfbClientData* next = rfb_client->clientData->next; 161 free(rfb_client->clientData); 162 rfb_client->clientData = next; 163 } 164 165 rfbClientCleanup(rfb_client); 166 167 } 168 169#ifdef ENABLE_COMMON_SSH 170 /* Free SFTP filesystem, if loaded */ 171 if (vnc_client->sftp_filesystem) 172 guac_common_ssh_destroy_sftp_filesystem(vnc_client->sftp_filesystem); 173 174 /* Free SFTP session */ 175 if (vnc_client->sftp_session) 176 guac_common_ssh_destroy_session(vnc_client->sftp_session); 177 178 /* Free SFTP user */ 179 if (vnc_client->sftp_user) 180 guac_common_ssh_destroy_user(vnc_client->sftp_user); 181 182 guac_common_ssh_uninit(); 183#endif 184 185 /* Clean up recording, if in progress */ 186 if (vnc_client->recording != NULL) 187 guac_recording_free(vnc_client->recording); 188 189 /* Free clipboard */ 190 if (vnc_client->clipboard != NULL) 191 guac_common_clipboard_free(vnc_client->clipboard); 192 193 /* Free display */ 194 if (vnc_client->display != NULL) 195 guac_common_display_free(vnc_client->display); 196 197#ifdef ENABLE_PULSE 198 /* If audio enabled, stop streaming */ 199 if (vnc_client->audio) 200 guac_pa_stream_free(vnc_client->audio); 201#endif 202 203 /* Free parsed settings */ 204 if (settings != NULL) 205 guac_vnc_settings_free(settings); 206 207#ifdef ENABLE_VNC_TLS_LOCKING 208 /* Clean up TLS lock mutex. */ 209 pthread_mutex_destroy(&(vnc_client->tls_lock)); 210#endif 211 212 /* Free generic data struct */ 213 guac_mem_free(client->data); 214 215 return 0; 216} 217