terminal-stdin-stream.c (5330B)
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 "terminal/common.h" 21#include "terminal/terminal.h" 22#include "terminal/terminal-priv.h" 23 24#include <guacamole/protocol.h> 25#include <guacamole/socket.h> 26#include <guacamole/user.h> 27 28/** 29 * Handler for "blob" instructions which writes the data of received 30 * blobs to STDIN of the terminal associated with the stream. 31 * 32 * @see guac_user_blob_handler 33 */ 34static int guac_terminal_input_stream_blob_handler(guac_user* user, 35 guac_stream* stream, void* data, int length) { 36 37 guac_terminal* term = (guac_terminal*) stream->data; 38 39 /* Attempt to write received data */ 40 guac_terminal_lock(term); 41 int result = guac_terminal_write_all(term->stdin_pipe_fd[1], data, length); 42 guac_terminal_unlock(term); 43 44 /* Acknowledge receipt of data and result of write attempt */ 45 if (result <= 0) { 46 47 guac_user_log(user, GUAC_LOG_DEBUG, 48 "Attempt to write to STDIN via an inbound stream failed."); 49 50 guac_protocol_send_ack(user->socket, stream, 51 "Attempt to write to STDIN failed.", 52 GUAC_PROTOCOL_STATUS_SUCCESS); 53 54 } 55 else { 56 57 guac_user_log(user, GUAC_LOG_DEBUG, 58 "%i bytes successfully written to STDIN from an inbound stream.", 59 length); 60 61 guac_protocol_send_ack(user->socket, stream, 62 "Data written to STDIN.", 63 GUAC_PROTOCOL_STATUS_SUCCESS); 64 65 } 66 67 guac_socket_flush(user->socket); 68 return 0; 69 70} 71 72/** 73 * Handler for "end" instructions which disassociates the given 74 * stream from the terminal, allowing user input to resume. 75 * 76 * @see guac_user_end_handler 77 */ 78static int guac_terminal_input_stream_end_handler(guac_user* user, 79 guac_stream* stream) { 80 81 guac_terminal* term = (guac_terminal*) stream->data; 82 83 /* Reset input stream, unblocking user input */ 84 guac_terminal_lock(term); 85 term->input_stream = NULL; 86 guac_terminal_unlock(term); 87 88 guac_user_log(user, GUAC_LOG_DEBUG, "Inbound stream closed. User input " 89 "will now resume affecting STDIN."); 90 91 return 0; 92 93} 94 95/** 96 * Internal implementation of guac_terminal_send_stream() which assumes 97 * that the guac_terminal has already been locked through a call to 98 * guac_terminal_lock(). The semantics of all parameters and the return 99 * value are identical to guac_terminal_send_stream(). 100 * 101 * @see guac_terminal_send_stream() 102 */ 103static int __guac_terminal_send_stream(guac_terminal* term, guac_user* user, 104 guac_stream* stream) { 105 106 /* Deny redirecting STDIN if terminal is not started */ 107 if (!term->started) { 108 109 guac_user_log(user, GUAC_LOG_DEBUG, "Attempt to direct the contents " 110 "of an inbound stream to STDIN denied. The terminal is not " 111 "yet ready for input."); 112 113 guac_protocol_send_ack(user->socket, stream, 114 "Terminal not yet started.", 115 GUAC_PROTOCOL_STATUS_RESOURCE_CONFLICT); 116 117 guac_socket_flush(user->socket); 118 return 1; 119 120 } 121 122 /* If a stream is already being used for STDIN, deny creation of 123 * further streams */ 124 if (term->input_stream != NULL) { 125 126 guac_user_log(user, GUAC_LOG_DEBUG, "Attempt to direct the contents " 127 "of an inbound stream to STDIN denied. STDIN is already " 128 "being read from an inbound stream."); 129 130 guac_protocol_send_ack(user->socket, stream, 131 "STDIN is already being read from a stream.", 132 GUAC_PROTOCOL_STATUS_RESOURCE_CONFLICT); 133 134 guac_socket_flush(user->socket); 135 return 1; 136 137 } 138 139 guac_user_log(user, GUAC_LOG_DEBUG, "Now reading STDIN from inbound " 140 "stream. User input will no longer affect STDIN until the " 141 "stream is closed."); 142 143 stream->blob_handler = guac_terminal_input_stream_blob_handler; 144 stream->end_handler = guac_terminal_input_stream_end_handler; 145 stream->data = term; 146 147 /* Block user input until stream is ended */ 148 term->input_stream = stream; 149 150 /* Acknowledge redirection from stream */ 151 guac_protocol_send_ack(user->socket, stream, 152 "Now reading STDIN from stream.", 153 GUAC_PROTOCOL_STATUS_SUCCESS); 154 155 guac_socket_flush(user->socket); 156 return 0; 157 158} 159 160int guac_terminal_send_stream(guac_terminal* term, guac_user* user, 161 guac_stream* stream) { 162 163 int result; 164 165 guac_terminal_lock(term); 166 result = __guac_terminal_send_stream(term, user, stream); 167 guac_terminal_unlock(term); 168 169 return result; 170 171} 172