Commit 1b7d7301 for guacamole.apache.org
commit 1b7d730183660d49a35de62243161c0308aea8ca
Author: Ciro Iriarte <ciro.iriarte@gmail.com>
Date: Mon Nov 2 11:39:09 2026 -0300
GUACAMOLE-2301: Use named constants and automatic config.h inclusion.
- Include config.h automatically via AM_CPPFLAGS, as the other protocol
plugins do, and drop the explicit includes.
- Define the Pause, Break and Ctrl+0 keysyms that send a serial break as
named constants.
- Replace the RFC2217 COM-PORT-OPTION command #defines with an enum, and
name the SET-PARITY and SET-CONTROL values instead of using bare numbers.
- Document why control pipe tokens are limited to 64 bytes, and discard
oversized tokens entirely. Previously the buffer was reset but the rest
of the token kept accumulating, so the tail of an oversized token could
be dispatched as a command.
diff --git a/src/protocols/serial/Makefile.am b/src/protocols/serial/Makefile.am
index f9cbcc46..cd23b99e 100644
--- a/src/protocols/serial/Makefile.am
+++ b/src/protocols/serial/Makefile.am
@@ -24,6 +24,8 @@
#
AUTOMAKE_OPTIONS = foreign
+
+AM_CPPFLAGS = -include config.h
ACLOCAL_AMFLAGS = -I m4
lib_LTLIBRARIES = libguac-client-serial.la
diff --git a/src/protocols/serial/argv.c b/src/protocols/serial/argv.c
index 94a101bf..8952bc5b 100644
--- a/src/protocols/serial/argv.c
+++ b/src/protocols/serial/argv.c
@@ -17,7 +17,6 @@
* under the License.
*/
-#include "config.h"
#include "argv.h"
#include "serial.h"
#include "terminal/terminal.h"
diff --git a/src/protocols/serial/client.c b/src/protocols/serial/client.c
index e781d5ce..c8f91ff9 100644
--- a/src/protocols/serial/client.c
+++ b/src/protocols/serial/client.c
@@ -17,7 +17,6 @@
* under the License.
*/
-#include "config.h"
#include "argv.h"
#include "client.h"
#include "serial.h"
diff --git a/src/protocols/serial/clipboard.c b/src/protocols/serial/clipboard.c
index 53a59456..41aad4ad 100644
--- a/src/protocols/serial/clipboard.c
+++ b/src/protocols/serial/clipboard.c
@@ -17,7 +17,6 @@
* under the License.
*/
-#include "config.h"
#include "clipboard.h"
#include "serial.h"
#include "terminal/terminal.h"
diff --git a/src/protocols/serial/input.c b/src/protocols/serial/input.c
index 1147e242..bca1385f 100644
--- a/src/protocols/serial/input.c
+++ b/src/protocols/serial/input.c
@@ -17,7 +17,6 @@
* under the License.
*/
-#include "config.h"
#include "input.h"
#include "serial.h"
#include "stream.h"
@@ -31,6 +30,22 @@
#include <sys/types.h>
#include <unistd.h>
+/**
+ * The X11 keysym of the Pause key. Pressing this key sends a serial break.
+ */
+#define GUAC_SERIAL_KEYSYM_PAUSE 0xFF13
+
+/**
+ * The X11 keysym of the Break key. Pressing this key sends a serial break.
+ */
+#define GUAC_SERIAL_KEYSYM_BREAK 0xFF6B
+
+/**
+ * The keysym which, while Ctrl is held, sends a serial break. This is an
+ * alternative for keyboards which lack a Pause or Break key.
+ */
+#define GUAC_SERIAL_KEYSYM_CTRL_BREAK '0'
+
int guac_serial_user_mouse_handler(guac_user* user, int x, int y, int mask) {
guac_client* client = user->client;
@@ -68,12 +83,12 @@ int guac_serial_user_key_handler(guac_user* user, int keysym, int pressed) {
/* Intercept and handle Pause / Break / Ctrl+0 as a serial break */
if (pressed && (
- keysym == 0xFF13 /* Pause */
- || keysym == 0xFF6B /* Break */
+ keysym == GUAC_SERIAL_KEYSYM_PAUSE
+ || keysym == GUAC_SERIAL_KEYSYM_BREAK
|| (
guac_terminal_get_mod_ctrl(term)
- && keysym == '0'
- ) /* Ctrl + 0 */
+ && keysym == GUAC_SERIAL_KEYSYM_CTRL_BREAK
+ )
)) {
/* Send a serial break if the connection is established */
diff --git a/src/protocols/serial/local.c b/src/protocols/serial/local.c
index 9eff0456..ace38bda 100644
--- a/src/protocols/serial/local.c
+++ b/src/protocols/serial/local.c
@@ -17,8 +17,6 @@
* under the License.
*/
-#include "config.h"
-
#include "local.h"
#include "settings.h"
#include "stream.h"
diff --git a/src/protocols/serial/pipe.c b/src/protocols/serial/pipe.c
index 3f94c271..11cb48b9 100644
--- a/src/protocols/serial/pipe.c
+++ b/src/protocols/serial/pipe.c
@@ -17,7 +17,6 @@
* under the License.
*/
-#include "config.h"
#include "pipe.h"
#include "serial.h"
#include "stream.h"
@@ -29,10 +28,15 @@
#include <guacamole/user.h>
#include <ctype.h>
+#include <stdbool.h>
#include <string.h>
/**
- * The maximum length, in bytes, of a single control command token.
+ * The size, in bytes, of the buffer holding a single control command token,
+ * including its null terminator. The longest recognized command ("dtr-off" or
+ * "rts-off") is 7 bytes, so this leaves generous room for future commands
+ * while keeping the per-stream buffer small and fixed. Tokens which do not fit
+ * cannot be valid commands and are discarded in their entirety.
*/
#define GUAC_SERIAL_CONTROL_TOKEN_LENGTH 64
@@ -52,6 +56,13 @@ typedef struct guac_serial_control_stream {
*/
int length;
+ /**
+ * Whether the current token has exceeded the token buffer and is being
+ * discarded. While true, all characters up to the next whitespace are
+ * ignored, so that no part of an oversized token is dispatched.
+ */
+ bool discarding;
+
} guac_serial_control_stream;
/**
@@ -133,20 +144,25 @@ static int guac_serial_control_blob_handler(guac_user* user,
/* A whitespace character completes the current token */
if (isspace((unsigned char) c)) {
- if (cs->length > 0) {
+ if (cs->length > 0 && !cs->discarding) {
cs->token[cs->length] = '\0';
guac_serial_control_dispatch(user, cs->token);
- cs->length = 0;
}
+ cs->length = 0;
+ cs->discarding = false;
}
+ /* Ignore the remainder of an oversized token */
+ else if (cs->discarding)
+ continue;
+
/* Accumulate non-whitespace characters into the current token */
else if (cs->length < GUAC_SERIAL_CONTROL_TOKEN_LENGTH - 1)
cs->token[cs->length++] = c;
- /* Oversized token; drop it to resynchronize on the next whitespace */
+ /* Oversized token; discard it up to the next whitespace */
else
- cs->length = 0;
+ cs->discarding = true;
}
@@ -181,8 +197,9 @@ static int guac_serial_control_end_handler(guac_user* user,
guac_serial_control_stream* cs =
(guac_serial_control_stream*) stream->data;
- /* Dispatch any trailing token not followed by whitespace */
- if (cs != NULL && cs->length > 0) {
+ /* Dispatch any trailing token not followed by whitespace, unless it is
+ * an oversized token being discarded */
+ if (cs != NULL && cs->length > 0 && !cs->discarding) {
cs->token[cs->length] = '\0';
guac_serial_control_dispatch(user, cs->token);
}
diff --git a/src/protocols/serial/rfc2217.c b/src/protocols/serial/rfc2217.c
index daac58ed..a186ea08 100644
--- a/src/protocols/serial/rfc2217.c
+++ b/src/protocols/serial/rfc2217.c
@@ -17,8 +17,6 @@
* under the License.
*/
-#include "config.h"
-
#include "rfc2217.h"
#include "settings.h"
#include "stream.h"
@@ -50,36 +48,75 @@
#define GUAC_SERIAL_TELOPT_COMPORT 44
/**
- * COM-PORT-OPTION client-to-server command: set the serial line speed. The
- * data is a 4-byte big-endian unsigned integer giving the speed in bits per
- * second.
+ * The client-to-server command codes of the RFC2217 COM-PORT-OPTION, as sent
+ * in the first byte of each COM-PORT-OPTION subnegotiation. The values are
+ * defined by RFC 2217 and must not be changed.
*/
-#define GUAC_SERIAL_RFC2217_SET_BAUDRATE 1
+typedef enum guac_serial_rfc2217_command {
+
+ /**
+ * Set the serial line speed. The data is a 4-byte big-endian unsigned
+ * integer giving the speed in bits per second.
+ */
+ GUAC_SERIAL_RFC2217_SET_BAUDRATE = 1,
+
+ /**
+ * Set the number of data bits. The data is a single byte (5 through 8).
+ */
+ GUAC_SERIAL_RFC2217_SET_DATASIZE = 2,
+
+ /**
+ * Set the parity. The data is a single guac_serial_rfc2217_parity
+ * value.
+ */
+ GUAC_SERIAL_RFC2217_SET_PARITY = 3,
+
+ /**
+ * Set the number of stop bits. The data is a single byte (1=1 stop bit,
+ * 2=2 stop bits).
+ */
+ GUAC_SERIAL_RFC2217_SET_STOPSIZE = 4,
+
+ /**
+ * Set flow control, the break state, or the DTR/RTS modem control lines.
+ * The data is a single guac_serial_rfc2217_control value.
+ */
+ GUAC_SERIAL_RFC2217_SET_CONTROL = 5
+
+} guac_serial_rfc2217_command;
/**
- * COM-PORT-OPTION client-to-server command: set the number of data bits. The
- * data is a single byte (5 through 8).
+ * The values of the RFC2217 COM-PORT-OPTION SET-PARITY command. The values are
+ * defined by RFC 2217 and must not be changed.
*/
-#define GUAC_SERIAL_RFC2217_SET_DATASIZE 2
+typedef enum guac_serial_rfc2217_parity {
-/**
- * COM-PORT-OPTION client-to-server command: set the parity. The data is a
- * single byte (1=none, 2=odd, 3=even, 4=mark, 5=space).
- */
-#define GUAC_SERIAL_RFC2217_SET_PARITY 3
+ /**
+ * No parity bit.
+ */
+ GUAC_SERIAL_RFC2217_PARITY_NONE = 1,
-/**
- * COM-PORT-OPTION client-to-server command: set the number of stop bits. The
- * data is a single byte (1=1 stop bit, 2=2 stop bits).
- */
-#define GUAC_SERIAL_RFC2217_SET_STOPSIZE 4
+ /**
+ * Odd parity.
+ */
+ GUAC_SERIAL_RFC2217_PARITY_ODD = 2,
-/**
- * COM-PORT-OPTION client-to-server command: set line/flow control and break
- * state. The data is a single byte. For flow control: 1=none, 2=xon/xoff,
- * 3=rts/cts. For the break signal: 5=break on, 6=break off.
- */
-#define GUAC_SERIAL_RFC2217_SET_CONTROL 5
+ /**
+ * Even parity.
+ */
+ GUAC_SERIAL_RFC2217_PARITY_EVEN = 3,
+
+ /**
+ * The parity bit is always set (mark).
+ */
+ GUAC_SERIAL_RFC2217_PARITY_MARK = 4,
+
+ /**
+ * The parity bit is always clear (space).
+ */
+ GUAC_SERIAL_RFC2217_PARITY_SPACE = 5
+
+} guac_serial_rfc2217_parity;
/**
* Writes the entire buffer given to the specified file descriptor, retrying
@@ -133,9 +170,10 @@ static int guac_serial_rfc2217_write_all(int fd, const char* buffer, int size) {
* The single byte of data associated with the command.
*/
static void guac_serial_rfc2217_send_byte(telnet_t* telnet,
- unsigned char command, unsigned char value) {
+ guac_serial_rfc2217_command command, unsigned char value) {
+ unsigned char code = (unsigned char) command;
telnet_begin_sb(telnet, GUAC_SERIAL_TELOPT_COMPORT);
- telnet_send(telnet, (char*) &command, 1);
+ telnet_send(telnet, (char*) &code, 1);
telnet_send(telnet, (char*) &value, 1);
telnet_finish_sb(telnet);
}
@@ -172,57 +210,57 @@ static void guac_serial_rfc2217_set_line(telnet_t* telnet,
guac_serial_rfc2217_send_byte(telnet, GUAC_SERIAL_RFC2217_SET_DATASIZE,
(unsigned char) settings->data_bits);
- /* SET-PARITY (1=none, 2=odd, 3=even, 4=mark, 5=space) */
- unsigned char parity;
+ /* SET-PARITY */
+ guac_serial_rfc2217_parity parity;
switch (settings->parity) {
case GUAC_SERIAL_PARITY_ODD:
- parity = 2;
+ parity = GUAC_SERIAL_RFC2217_PARITY_ODD;
break;
case GUAC_SERIAL_PARITY_EVEN:
- parity = 3;
+ parity = GUAC_SERIAL_RFC2217_PARITY_EVEN;
break;
case GUAC_SERIAL_PARITY_MARK:
- parity = 4;
+ parity = GUAC_SERIAL_RFC2217_PARITY_MARK;
break;
case GUAC_SERIAL_PARITY_SPACE:
- parity = 5;
+ parity = GUAC_SERIAL_RFC2217_PARITY_SPACE;
break;
default:
- parity = 1;
+ parity = GUAC_SERIAL_RFC2217_PARITY_NONE;
break;
}
guac_serial_rfc2217_send_byte(telnet, GUAC_SERIAL_RFC2217_SET_PARITY,
- parity);
+ (unsigned char) parity);
/* SET-STOPSIZE (1=1 stop bit, 2=2 stop bits) */
guac_serial_rfc2217_send_byte(telnet, GUAC_SERIAL_RFC2217_SET_STOPSIZE,
(unsigned char) settings->stop_bits);
- /* SET-CONTROL flow control (1=none, 2=xon/xoff, 3=rts/cts) */
- unsigned char flow;
+ /* SET-CONTROL flow control */
+ guac_serial_rfc2217_control flow;
switch (settings->flow_control) {
case GUAC_SERIAL_FLOW_XON_XOFF:
- flow = 2;
+ flow = GUAC_SERIAL_RFC2217_CONTROL_FLOW_XON_XOFF;
break;
case GUAC_SERIAL_FLOW_RTS_CTS:
- flow = 3;
+ flow = GUAC_SERIAL_RFC2217_CONTROL_FLOW_RTS_CTS;
break;
default:
- flow = 1;
+ flow = GUAC_SERIAL_RFC2217_CONTROL_FLOW_NONE;
break;
}
guac_serial_rfc2217_send_byte(telnet, GUAC_SERIAL_RFC2217_SET_CONTROL,
- flow);
+ (unsigned char) flow);
}
@@ -408,20 +446,23 @@ int guac_serial_rfc2217_send_break(guac_serial_stream* stream) {
telnet_t* telnet = (telnet_t*) stream->telnet;
/* SET-CONTROL: break on */
- guac_serial_rfc2217_send_byte(telnet, GUAC_SERIAL_RFC2217_SET_CONTROL, 5);
+ guac_serial_rfc2217_send_byte(telnet, GUAC_SERIAL_RFC2217_SET_CONTROL,
+ GUAC_SERIAL_RFC2217_CONTROL_BREAK_ON);
/* Hold the line low for the configured duration */
if (stream->break_duration > 0)
usleep((useconds_t) stream->break_duration * 1000);
/* SET-CONTROL: break off */
- guac_serial_rfc2217_send_byte(telnet, GUAC_SERIAL_RFC2217_SET_CONTROL, 6);
+ guac_serial_rfc2217_send_byte(telnet, GUAC_SERIAL_RFC2217_SET_CONTROL,
+ GUAC_SERIAL_RFC2217_CONTROL_BREAK_OFF);
return 0;
}
-void guac_serial_rfc2217_set_control(guac_serial_stream* stream, int value) {
+void guac_serial_rfc2217_set_control(guac_serial_stream* stream,
+ guac_serial_rfc2217_control value) {
guac_serial_rfc2217_send_byte((telnet_t*) stream->telnet,
GUAC_SERIAL_RFC2217_SET_CONTROL, (unsigned char) value);
}
@@ -494,7 +535,8 @@ int guac_serial_rfc2217_send_break(guac_serial_stream* stream) {
return 0;
}
-void guac_serial_rfc2217_set_control(guac_serial_stream* stream, int value) {
+void guac_serial_rfc2217_set_control(guac_serial_stream* stream,
+ guac_serial_rfc2217_control value) {
/* RFC2217 unavailable; a stream with this backend is never created */
(void) stream;
(void) value;
diff --git a/src/protocols/serial/rfc2217.h b/src/protocols/serial/rfc2217.h
index d21f0459..2c74b4a6 100644
--- a/src/protocols/serial/rfc2217.h
+++ b/src/protocols/serial/rfc2217.h
@@ -25,6 +25,61 @@
#include <guacamole/client.h>
+/**
+ * The values of the RFC2217 COM-PORT-OPTION SET-CONTROL command, which sets
+ * flow control, the break state, or the DTR/RTS modem control lines of the
+ * remote serial port. The values are defined by RFC 2217 and must not be
+ * changed.
+ */
+typedef enum guac_serial_rfc2217_control {
+
+ /**
+ * Use no flow control.
+ */
+ GUAC_SERIAL_RFC2217_CONTROL_FLOW_NONE = 1,
+
+ /**
+ * Use XON/XOFF software flow control.
+ */
+ GUAC_SERIAL_RFC2217_CONTROL_FLOW_XON_XOFF = 2,
+
+ /**
+ * Use RTS/CTS hardware flow control.
+ */
+ GUAC_SERIAL_RFC2217_CONTROL_FLOW_RTS_CTS = 3,
+
+ /**
+ * Begin a break, holding the transmit line low.
+ */
+ GUAC_SERIAL_RFC2217_CONTROL_BREAK_ON = 5,
+
+ /**
+ * End a break, releasing the transmit line.
+ */
+ GUAC_SERIAL_RFC2217_CONTROL_BREAK_OFF = 6,
+
+ /**
+ * Assert the DTR modem control line.
+ */
+ GUAC_SERIAL_RFC2217_CONTROL_DTR_ON = 8,
+
+ /**
+ * Deassert the DTR modem control line.
+ */
+ GUAC_SERIAL_RFC2217_CONTROL_DTR_OFF = 9,
+
+ /**
+ * Assert the RTS modem control line.
+ */
+ GUAC_SERIAL_RFC2217_CONTROL_RTS_ON = 11,
+
+ /**
+ * Deassert the RTS modem control line.
+ */
+ GUAC_SERIAL_RFC2217_CONTROL_RTS_OFF = 12
+
+} guac_serial_rfc2217_control;
+
/**
* Opens an RFC2217 (telnet COM-PORT-OPTION) connection to the network serial
* server described by the given settings, negotiates the configured serial line
@@ -143,17 +198,18 @@ int guac_serial_rfc2217_send_break(guac_serial_stream* stream);
/**
* Sends a COM-PORT-OPTION SET-CONTROL subnegotiation with the given control
* value to the remote end of an RFC2217 connection. Used to toggle the modem
- * control lines (e.g. DTR ON=8, DTR OFF=9, RTS ON=11, RTS OFF=12 per RFC 2217).
- * This must only be called on a stream whose backend is
+ * control lines. This must only be called on a stream whose backend is
* GUAC_SERIAL_BACKEND_RFC2217.
*
* @param stream
* The RFC2217 serial stream on which to send the SET-CONTROL command.
*
* @param value
- * The RFC 2217 SET-CONTROL value to send.
+ * The SET-CONTROL value to send, such as
+ * GUAC_SERIAL_RFC2217_CONTROL_DTR_ON.
*/
-void guac_serial_rfc2217_set_control(guac_serial_stream* stream, int value);
+void guac_serial_rfc2217_set_control(guac_serial_stream* stream,
+ guac_serial_rfc2217_control value);
/**
* Frees the libtelnet session associated with the given stream, if any. Safe
diff --git a/src/protocols/serial/serial.c b/src/protocols/serial/serial.c
index 84f70fd8..ece1af3f 100644
--- a/src/protocols/serial/serial.c
+++ b/src/protocols/serial/serial.c
@@ -17,8 +17,6 @@
* under the License.
*/
-#include "config.h"
-
#include "argv.h"
#include "rfc2217.h"
#include "serial.h"
diff --git a/src/protocols/serial/settings.c b/src/protocols/serial/settings.c
index 88eb6e2d..9e9e54f8 100644
--- a/src/protocols/serial/settings.c
+++ b/src/protocols/serial/settings.c
@@ -17,8 +17,6 @@
* under the License.
*/
-#include "config.h"
-
#include "argv.h"
#include "common/defaults.h"
#include "common/clipboard.h"
diff --git a/src/protocols/serial/stream.c b/src/protocols/serial/stream.c
index c2db391b..5803b148 100644
--- a/src/protocols/serial/stream.c
+++ b/src/protocols/serial/stream.c
@@ -17,8 +17,6 @@
* under the License.
*/
-#include "config.h"
-
#include "local.h"
#include "rfc2217.h"
#include "settings.h"
@@ -292,13 +290,13 @@ int guac_serial_stream_set_line(guac_serial_stream* stream,
break;
case GUAC_SERIAL_BACKEND_RFC2217: {
- /* RFC2217 SET-CONTROL values: DTR ON=8, DTR OFF=9, RTS ON=11,
- * RTS OFF=12 */
- int value;
+ guac_serial_rfc2217_control value;
if (line == GUAC_SERIAL_CONTROL_LINE_DTR)
- value = state ? 8 : 9;
+ value = state ? GUAC_SERIAL_RFC2217_CONTROL_DTR_ON
+ : GUAC_SERIAL_RFC2217_CONTROL_DTR_OFF;
else
- value = state ? 11 : 12;
+ value = state ? GUAC_SERIAL_RFC2217_CONTROL_RTS_ON
+ : GUAC_SERIAL_RFC2217_CONTROL_RTS_OFF;
guac_serial_rfc2217_set_control(stream, value);
break;
}
diff --git a/src/protocols/serial/tcp.c b/src/protocols/serial/tcp.c
index 104a93cf..9f511c15 100644
--- a/src/protocols/serial/tcp.c
+++ b/src/protocols/serial/tcp.c
@@ -17,8 +17,6 @@
* under the License.
*/
-#include "config.h"
-
#include "settings.h"
#include "stream.h"
#include "tcp.h"
diff --git a/src/protocols/serial/user.c b/src/protocols/serial/user.c
index 531deb0f..fb7ee4a4 100644
--- a/src/protocols/serial/user.c
+++ b/src/protocols/serial/user.c
@@ -17,8 +17,6 @@
* under the License.
*/
-#include "config.h"
-
#include "argv.h"
#include "clipboard.h"
#include "input.h"