client.c (5606B)
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 "argv.h" 21#include "client.h" 22#include "kubernetes.h" 23#include "settings.h" 24#include "user.h" 25 26#include <guacamole/argv.h> 27#include <guacamole/client.h> 28#include <guacamole/mem.h> 29#include <guacamole/socket.h> 30#include <libwebsockets.h> 31 32#include <langinfo.h> 33#include <locale.h> 34#include <pthread.h> 35#include <stdlib.h> 36#include <string.h> 37 38guac_client* guac_kubernetes_lws_current_client = NULL; 39 40/** 41 * Logging callback invoked by libwebsockets to log a single line of logging 42 * output. As libwebsockets messages are all generally low-level, the log 43 * level provided by libwebsockets is ignored here, with all messages logged 44 * instead at guacd's debug level. 45 * 46 * @param level 47 * The libwebsockets log level associated with the log message. This value 48 * is ignored by this implementation of the logging callback. 49 * 50 * @param line 51 * The line of logging output to log. 52 */ 53static void guac_kubernetes_log(int level, const char* line) { 54 55 char buffer[1024]; 56 57 /* Drop log message if there's nowhere to log yet */ 58 if (guac_kubernetes_lws_current_client == NULL) 59 return; 60 61 /* Trim length of line to fit buffer (plus null terminator) */ 62 int length = strlen(line); 63 if (length > sizeof(buffer) - 1) 64 length = sizeof(buffer) - 1; 65 66 /* Copy as much of the received line as will fit in the buffer */ 67 memcpy(buffer, line, length); 68 69 /* If the line ends with a newline character, trim the character */ 70 if (length > 0 && buffer[length - 1] == '\n') 71 length--; 72 73 /* Null-terminate the trimmed string */ 74 buffer[length] = '\0'; 75 76 /* Log using guacd's own log facilities */ 77 guac_client_log(guac_kubernetes_lws_current_client, GUAC_LOG_DEBUG, 78 "libwebsockets: %s", buffer); 79 80} 81 82/** 83 * A pending join handler implementation that will synchronize the connection 84 * state for all pending users prior to them being promoted to full user. 85 * 86 * @param client 87 * The client whose pending users are about to be promoted to full users, 88 * and therefore need their connection state synchronized. 89 * 90 * @return 91 * Always zero. 92 */ 93static int guac_kubernetes_join_pending_handler(guac_client* client) { 94 95 guac_kubernetes_client* kubernetes_client = 96 (guac_kubernetes_client*) client->data; 97 98 /* Synchronize the terminal state to all pending users */ 99 if (kubernetes_client->term != NULL) { 100 guac_socket* broadcast_socket = client->pending_socket; 101 guac_terminal_sync_users(kubernetes_client->term, client, broadcast_socket); 102 guac_kubernetes_send_current_argv_batch(client, broadcast_socket); 103 guac_socket_flush(broadcast_socket); 104 } 105 106 return 0; 107 108} 109 110int guac_client_init(guac_client* client) { 111 112 /* Ensure reference to main guac_client remains available in all 113 * libwebsockets contexts */ 114 guac_kubernetes_lws_current_client = client; 115 116 /* Redirect libwebsockets logging */ 117 lws_set_log_level(LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_INFO, 118 guac_kubernetes_log); 119 120 /* Set client args */ 121 client->args = GUAC_KUBERNETES_CLIENT_ARGS; 122 123 /* Allocate client instance data */ 124 guac_kubernetes_client* kubernetes_client = guac_mem_zalloc(sizeof(guac_kubernetes_client)); 125 client->data = kubernetes_client; 126 127 /* Set handlers */ 128 client->join_handler = guac_kubernetes_user_join_handler; 129 client->join_pending_handler = guac_kubernetes_join_pending_handler; 130 client->free_handler = guac_kubernetes_client_free_handler; 131 client->leave_handler = guac_kubernetes_user_leave_handler; 132 133 /* Register handlers for argument values that may be sent after the handshake */ 134 guac_argv_register(GUAC_KUBERNETES_ARGV_COLOR_SCHEME, guac_kubernetes_argv_callback, NULL, GUAC_ARGV_OPTION_ECHO); 135 guac_argv_register(GUAC_KUBERNETES_ARGV_FONT_NAME, guac_kubernetes_argv_callback, NULL, GUAC_ARGV_OPTION_ECHO); 136 guac_argv_register(GUAC_KUBERNETES_ARGV_FONT_SIZE, guac_kubernetes_argv_callback, NULL, GUAC_ARGV_OPTION_ECHO); 137 138 /* Set locale and warn if not UTF-8 */ 139 setlocale(LC_CTYPE, ""); 140 if (strcmp(nl_langinfo(CODESET), "UTF-8") != 0) { 141 guac_client_log(client, GUAC_LOG_INFO, 142 "Current locale does not use UTF-8. Some characters may " 143 "not render correctly."); 144 } 145 146 /* Success */ 147 return 0; 148 149} 150 151int guac_kubernetes_client_free_handler(guac_client* client) { 152 153 guac_kubernetes_client* kubernetes_client = 154 (guac_kubernetes_client*) client->data; 155 156 /* Wait client thread to terminate */ 157 pthread_join(kubernetes_client->client_thread, NULL); 158 159 /* Free settings */ 160 if (kubernetes_client->settings != NULL) 161 guac_kubernetes_settings_free(kubernetes_client->settings); 162 163 guac_mem_free(kubernetes_client); 164 return 0; 165 166} 167