GUACAMOLE-860: Add TN5250 packet processing.
This commit is contained in:
parent
b9330e5850
commit
0c8f79a6a0
@ -35,18 +35,20 @@ libguac_client_tn5250_la_SOURCES = \
|
|||||||
input.c \
|
input.c \
|
||||||
pipe.c \
|
pipe.c \
|
||||||
settings.c \
|
settings.c \
|
||||||
tn5250.c \
|
tn5250.c \
|
||||||
user.c
|
user.c \
|
||||||
|
lib5250/lib5250.c
|
||||||
|
|
||||||
noinst_HEADERS = \
|
noinst_HEADERS = \
|
||||||
argv.h \
|
argv.h \
|
||||||
client.h \
|
client.h \
|
||||||
clipboard.h \
|
clipboard.h \
|
||||||
input.h \
|
input.h \
|
||||||
pipe.h \
|
pipe.h \
|
||||||
settings.h \
|
settings.h \
|
||||||
tn5250.h \
|
tn5250.h \
|
||||||
user.h
|
user.h \
|
||||||
|
lib5250/lib5250.h
|
||||||
|
|
||||||
libguac_client_tn5250_la_CFLAGS = \
|
libguac_client_tn5250_la_CFLAGS = \
|
||||||
-Werror -Wall -Iinclude \
|
-Werror -Wall -Iinclude \
|
||||||
|
105
src/protocols/tn5250/lib5250/lib5250.c
Normal file
105
src/protocols/tn5250/lib5250/lib5250.c
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "lib5250.h"
|
||||||
|
#include "tn5250.h"
|
||||||
|
|
||||||
|
#include <guacamole/client.h>
|
||||||
|
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
int guac_lib5250_process_packet(const char* data, guac_client* client) {
|
||||||
|
|
||||||
|
guac_client_log(client, GUAC_LOG_DEBUG, "%s: Processing expected TN5250 SNA data.", __func__);
|
||||||
|
|
||||||
|
guac_lib5250_packet* packet = (guac_lib5250_packet*) data;
|
||||||
|
|
||||||
|
if (ntohs(packet->type) != GUAC_LIB5250_SNA_GDS) {
|
||||||
|
guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR,
|
||||||
|
"%s: Unexpected SNA packet typing parsing TN5250 packet: 0x%x",
|
||||||
|
__func__, ntohs(packet->type));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (packet->opcode) {
|
||||||
|
|
||||||
|
case GUAC_LIB5250_OPCODE_NOOP:
|
||||||
|
guac_client_log(client, GUAC_LOG_TRACE, "%s: Received opcode no-op.", __func__);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GUAC_LIB5250_OPCODE_INVITE:
|
||||||
|
guac_client_log(client, GUAC_LOG_TRACE, "%s: Received opcode invite.", __func__);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GUAC_LIB5250_OPCODE_OUTPUT:
|
||||||
|
guac_client_log(client, GUAC_LOG_TRACE, "%s: Received opcode output.", __func__);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GUAC_LIB5250_OPCODE_PUTGET:
|
||||||
|
guac_client_log(client, GUAC_LOG_TRACE, "%s: Received opcode put/get.", __func__);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GUAC_LIB5250_OPCODE_SAVESCREEN:
|
||||||
|
guac_client_log(client, GUAC_LOG_TRACE, "%s: Received opcode save screen.", __func__);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GUAC_LIB5250_OPCODE_RESTORESCREEN:
|
||||||
|
guac_client_log(client, GUAC_LOG_TRACE, "%s: Received opcode restore screen.", __func__);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GUAC_LIB5250_OPCODE_READIMMEDIATE:
|
||||||
|
guac_client_log(client, GUAC_LOG_TRACE, "%s: Received opcode read immediate.", __func__);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GUAC_LIB5250_OPCODE_READSCREEN:
|
||||||
|
guac_client_log(client, GUAC_LOG_TRACE, "%s: Received opcode read screen.", __func__);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GUAC_LIB5250_OPCODE_CANCELINVITE:
|
||||||
|
guac_client_log(client, GUAC_LOG_TRACE, "%s: Received opcode cancel invite.", __func__);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GUAC_LIB5250_OPCODE_MSGON:
|
||||||
|
guac_client_log(client, GUAC_LOG_TRACE, "%s: Received opcode msg on.", __func__);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GUAC_LIB5250_OPCODE_MSGOFF:
|
||||||
|
guac_client_log(client, GUAC_LOG_TRACE, "%s: Received opcode msg off.", __func__);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
guac_client_log(client, GUAC_LOG_TRACE, "%s: Received unknown opcode.", __func__);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
guac_client_log(client, GUAC_LOG_TRACE, "%s: SNA data length: %d bytes.", __func__, ntohs(packet->len));
|
||||||
|
guac_client_log(client, GUAC_LOG_TRACE, "%s: Packet type: 0x%x", __func__, ntohs(packet->type));
|
||||||
|
guac_client_log(client, GUAC_LOG_TRACE, "%s: Reserved space: 0x%x", __func__, ntohs(packet->reserved));
|
||||||
|
guac_client_log(client, GUAC_LOG_TRACE, "%s: Variable header length: 0x%x.", __func__, packet->varlen);
|
||||||
|
guac_client_log(client, GUAC_LOG_TRACE, "%s: SNA Flags: 0x%x", __func__, packet->flags);
|
||||||
|
guac_client_log(client, GUAC_LOG_TRACE, "%s: SNA Rerved flags: 0x%x", __func__, packet->reserved_flags);
|
||||||
|
guac_client_log(client, GUAC_LOG_TRACE, "%s: SNA Opcode: 0x%x", __func__, packet->opcode);
|
||||||
|
|
||||||
|
guac_client_log(client, GUAC_LOG_TRACE, "%s: WHOLE ENCHILADA: 0x%x", __func__, packet);
|
||||||
|
|
||||||
|
guac_client_log(client, GUAC_LOG_WARNING, "%s: Everything else is unimplemented, now.", __func__);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
207
src/protocols/tn5250/lib5250/lib5250.h
Normal file
207
src/protocols/tn5250/lib5250/lib5250.h
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GUAC_LIB5250_H
|
||||||
|
#define GUAC_LIB5250_H
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "tn5250.h"
|
||||||
|
|
||||||
|
#include <guacamole/client.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The General Data Stream SNA packet type.
|
||||||
|
*/
|
||||||
|
#define GUAC_LIB5250_SNA_GDS 0x12a0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An enum that represents all of the available terminal types according to
|
||||||
|
* RFC1205, the specification that documents the Telnet 5250 (TN5250)
|
||||||
|
* standard.
|
||||||
|
*/
|
||||||
|
typedef enum guac_lib5250_terminal {
|
||||||
|
|
||||||
|
/* 24 x 80 Double-Byte Character Set color display */
|
||||||
|
GUAC_LIB5250_TERMINAL_IBM_5555_C01,
|
||||||
|
|
||||||
|
/* 24 x 80 Double-Byte Character Set (DBCS) */
|
||||||
|
GUAC_LIB5250_TERMINAL_IBM_5555_B01,
|
||||||
|
|
||||||
|
/* 27 x 132 color display */
|
||||||
|
GUAC_LIB5250_TERMINAL_IBM_3477_FC,
|
||||||
|
|
||||||
|
/* 27 x 132 monochrome display */
|
||||||
|
GUAC_LIB5250_TERMINAL_IBM_3477_FG,
|
||||||
|
|
||||||
|
/* 27 x 132 monochrome display */
|
||||||
|
GUAC_LIB5250_TERMINAL_IBM_3180_2,
|
||||||
|
|
||||||
|
/* 24 x 80 color display */
|
||||||
|
GUAC_LIB5250_TERMINAL_IBM_3179_2,
|
||||||
|
|
||||||
|
/* 24 x 80 monochrome display */
|
||||||
|
GUAC_LIB5250_TERMINAL_IBM_3196_A1,
|
||||||
|
|
||||||
|
/* 24 x 80 color display */
|
||||||
|
GUAC_LIB5250_TERMINAL_IBM_5292_2,
|
||||||
|
|
||||||
|
/* 24 x 80 monochrome display */
|
||||||
|
GUAC_LIB5250_TERMINAL_IBM_5291_1,
|
||||||
|
|
||||||
|
/* 24 x 80 monochrome display */
|
||||||
|
GUAC_LIB5250_TERMINAL_IBM_5251_11
|
||||||
|
|
||||||
|
} guac_lib5250_terminal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A data type that captures a terminal type, from the guac_lib5250_terminal
|
||||||
|
* enum, and the capabilities associated with that terminal.
|
||||||
|
*/
|
||||||
|
typedef struct guac_lib5250_terminal_cap {
|
||||||
|
|
||||||
|
/* The name of the terminal. */
|
||||||
|
guac_lib5250_terminal name;
|
||||||
|
|
||||||
|
/* The number of rows supported on the terminal. */
|
||||||
|
unsigned int rows;
|
||||||
|
|
||||||
|
/* The number of columns supports on the terminal. */
|
||||||
|
unsigned int cols;
|
||||||
|
|
||||||
|
/* 1 if the terminal supports colors, 0 if it is monochrome. */
|
||||||
|
unsigned int color;
|
||||||
|
|
||||||
|
/* The number of bytes-per-character the terminal supports. This must
|
||||||
|
* be either 1 or 2. */
|
||||||
|
unsigned int charbytes;
|
||||||
|
|
||||||
|
} guac_lib5250_terminal_cap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of the possible TN5250 opcodes, which can be sent to the client to
|
||||||
|
* direct it to do something with the terminal. These are documented in RFC1205.
|
||||||
|
*/
|
||||||
|
typedef enum guac_lib5250_opcode {
|
||||||
|
|
||||||
|
/* No Operation */
|
||||||
|
GUAC_LIB5250_OPCODE_NOOP = 0x00,
|
||||||
|
|
||||||
|
/* Invite terminal */
|
||||||
|
GUAC_LIB5250_OPCODE_INVITE = 0x01,
|
||||||
|
|
||||||
|
/* Output only */
|
||||||
|
GUAC_LIB5250_OPCODE_OUTPUT = 0x02,
|
||||||
|
|
||||||
|
/* Put/Get */
|
||||||
|
GUAC_LIB5250_OPCODE_PUTGET = 0x03,
|
||||||
|
|
||||||
|
/* Save screen */
|
||||||
|
GUAC_LIB5250_OPCODE_SAVESCREEN = 0x04,
|
||||||
|
|
||||||
|
/* Restore screen */
|
||||||
|
GUAC_LIB5250_OPCODE_RESTORESCREEN = 0x05,
|
||||||
|
|
||||||
|
/* Read immediate */
|
||||||
|
GUAC_LIB5250_OPCODE_READIMMEDIATE = 0x06,
|
||||||
|
|
||||||
|
/* Read screen */
|
||||||
|
GUAC_LIB5250_OPCODE_READSCREEN = 0x08,
|
||||||
|
|
||||||
|
/* Cancel invite */
|
||||||
|
GUAC_LIB5250_OPCODE_CANCELINVITE = 0x0A,
|
||||||
|
|
||||||
|
/* Message light on */
|
||||||
|
GUAC_LIB5250_OPCODE_MSGON = 0x0B,
|
||||||
|
|
||||||
|
/* Message light off */
|
||||||
|
GUAC_LIB5250_OPCODE_MSGOFF = 0x0C
|
||||||
|
|
||||||
|
} guac_lib5250_opcode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A data type that defines the structure of the packet for 5250 communication
|
||||||
|
* across telnet. The structure of this packet is based off of the definition
|
||||||
|
* in RFC1205.
|
||||||
|
*/
|
||||||
|
typedef struct guac_lib5250_packet {
|
||||||
|
|
||||||
|
/* The length of the entire logical record. */
|
||||||
|
uint16_t len;
|
||||||
|
|
||||||
|
/* The SNA record type. This should always be 0x12A0, which is the
|
||||||
|
* General Data Stream record. */
|
||||||
|
uint16_t type;
|
||||||
|
|
||||||
|
/* Empty space, should be zerod. */
|
||||||
|
uint16_t reserved;
|
||||||
|
|
||||||
|
/* The length of the variable portion of the header, in octets. According
|
||||||
|
* to the RFC, this should always be 0x04. */
|
||||||
|
uint8_t varlen;
|
||||||
|
|
||||||
|
/* Flags associated with the header, as documented in the RFC. The
|
||||||
|
* bits are as follows:
|
||||||
|
* Bit 0: ERR - Data stream output error.
|
||||||
|
* Bit 1: ATN - Indicates Attention key was pressed.
|
||||||
|
* Bit 2-4: Reserved, zeros.
|
||||||
|
* Bit 5: SRQ - System Request key has been pressed.
|
||||||
|
* Bit 6: TRQ - Test Request key has been pressed.
|
||||||
|
* Bit 7: HLP - Help in Error State, with actual help code sent as data after
|
||||||
|
* the header.
|
||||||
|
*/
|
||||||
|
uint8_t flags;
|
||||||
|
|
||||||
|
/* At present, the remaining 8 bits of flags are not used at all. As old
|
||||||
|
* as RFC1205 is, I doubt that's likely to change. These bits should be
|
||||||
|
* all zeroes.
|
||||||
|
*/
|
||||||
|
uint8_t reserved_flags;
|
||||||
|
|
||||||
|
/* The operation code, as requested by the sender. Valid values for this
|
||||||
|
* are in the gauc_lib5250_opcode enum.
|
||||||
|
*/
|
||||||
|
uint8_t opcode;
|
||||||
|
|
||||||
|
/* What remains is the data in the packet, which should consume the
|
||||||
|
* remainder of the space that the header did not take up. The packet
|
||||||
|
* should also be terminated with a Telnet IAC EOR record, 0xffef.
|
||||||
|
*/
|
||||||
|
void* data;
|
||||||
|
|
||||||
|
} guac_lib5250_packet __attribute__ ((aligned));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the packet that libtelnet has received and then takes action
|
||||||
|
* based on the contents of the packet.
|
||||||
|
*
|
||||||
|
* @param data
|
||||||
|
* The data buffer delivered by libtelnet, which should be binary telnet
|
||||||
|
* data that is the actual TN5250 protocol.
|
||||||
|
*
|
||||||
|
* @param client
|
||||||
|
* The Guacamole client associated with this connection.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* Zero if the data was successfully processed, non-zero otherwise.
|
||||||
|
*/
|
||||||
|
int guac_lib5250_process_packet(const char* data, guac_client* client);
|
||||||
|
|
||||||
|
#endif // GUAC_LIB5250_H
|
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include "argv.h"
|
#include "argv.h"
|
||||||
#include "tn5250.h"
|
#include "tn5250.h"
|
||||||
|
#include "lib5250/lib5250.h"
|
||||||
#include "terminal/terminal.h"
|
#include "terminal/terminal.h"
|
||||||
|
|
||||||
#include <guacamole/client.h>
|
#include <guacamole/client.h>
|
||||||
@ -55,9 +56,6 @@ static const telnet_telopt_t __telnet_options[] = {
|
|||||||
{ TELNET_TELOPT_ECHO, TELNET_WONT, TELNET_DO },
|
{ TELNET_TELOPT_ECHO, TELNET_WONT, TELNET_DO },
|
||||||
{ TELNET_TELOPT_EOR, TELNET_WILL, TELNET_DO },
|
{ TELNET_TELOPT_EOR, TELNET_WILL, TELNET_DO },
|
||||||
{ TELNET_TELOPT_TTYPE, TELNET_WILL, TELNET_DONT },
|
{ TELNET_TELOPT_TTYPE, TELNET_WILL, TELNET_DONT },
|
||||||
{ TELNET_TELOPT_COMPRESS2, TELNET_WONT, TELNET_DO },
|
|
||||||
{ TELNET_TELOPT_MSSP, TELNET_WONT, TELNET_DO },
|
|
||||||
{ TELNET_TELOPT_NAWS, TELNET_WILL, TELNET_DONT },
|
|
||||||
{ TELNET_TELOPT_NEW_ENVIRON, TELNET_WILL, TELNET_DONT },
|
{ TELNET_TELOPT_NEW_ENVIRON, TELNET_WILL, TELNET_DONT },
|
||||||
{ -1, 0, 0 }
|
{ -1, 0, 0 }
|
||||||
};
|
};
|
||||||
@ -65,12 +63,21 @@ static const telnet_telopt_t __telnet_options[] = {
|
|||||||
/**
|
/**
|
||||||
* Write the entire buffer given to the specified file descriptor, retrying
|
* Write the entire buffer given to the specified file descriptor, retrying
|
||||||
* the write automatically if necessary. This function will return a value
|
* the write automatically if necessary. This function will return a value
|
||||||
* not equal to the buffer's size iff an error occurs which prevents all
|
* not equal to the buffer's size if an error occurs which prevents all
|
||||||
* future writes.
|
* future writes.
|
||||||
*
|
*
|
||||||
* @param fd The file descriptor to write to.
|
* @param fd
|
||||||
* @param buffer The buffer to write.
|
* The file descriptor to write to.
|
||||||
* @param size The number of bytes from the buffer to write.
|
*
|
||||||
|
* @param buffer
|
||||||
|
* The buffer to write.
|
||||||
|
*
|
||||||
|
* @param size
|
||||||
|
* The number of bytes from the buffer to write.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* Return a value equal to the buffer's size on success, or a value not
|
||||||
|
* equal to the buffer's size or a negative value on failure.
|
||||||
*/
|
*/
|
||||||
static int __guac_tn5250_write_all(int fd, const char* buffer, int size) {
|
static int __guac_tn5250_write_all(int fd, const char* buffer, int size) {
|
||||||
|
|
||||||
@ -271,6 +278,15 @@ static void guac_tn5250_search(guac_client* client, const char* buffer, int size
|
|||||||
* Event handler, as defined by libtelnet. This function is passed to
|
* Event handler, as defined by libtelnet. This function is passed to
|
||||||
* telnet_init() and will be called for every event fired by libtelnet,
|
* telnet_init() and will be called for every event fired by libtelnet,
|
||||||
* including feature enable/disable and receipt/transmission of data.
|
* including feature enable/disable and receipt/transmission of data.
|
||||||
|
*
|
||||||
|
* @param tn5250
|
||||||
|
* The telnet_t object associated with the event.
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* The telnet_event_t that has fired.
|
||||||
|
*
|
||||||
|
* @param data
|
||||||
|
* User data provided to the event.
|
||||||
*/
|
*/
|
||||||
static void __guac_tn5250_event_handler(telnet_t* tn5250, telnet_event_t* event, void* data) {
|
static void __guac_tn5250_event_handler(telnet_t* tn5250, telnet_event_t* event, void* data) {
|
||||||
|
|
||||||
@ -286,10 +302,15 @@ static void __guac_tn5250_event_handler(telnet_t* tn5250, telnet_event_t* event,
|
|||||||
"%s: Received %d bytes of data from remote side.", __func__, event->data.size);
|
"%s: Received %d bytes of data from remote side.", __func__, event->data.size);
|
||||||
if (tn5250_client->binary_mode) {
|
if (tn5250_client->binary_mode) {
|
||||||
guac_client_log(client, GUAC_LOG_TRACE,
|
guac_client_log(client, GUAC_LOG_TRACE,
|
||||||
"%s: Receiving binary data - it will not be printed to the screen.",
|
"%s: Receiving binary data, which will not go directly to the terminal.",
|
||||||
__func__);
|
__func__);
|
||||||
|
if (guac_lib5250_process_packet(event->data.buffer, client)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
guac_client_log(client, GUAC_LOG_TRACE,
|
||||||
|
"%s: Writing ASCII output directly to terminal.", __func__);
|
||||||
guac_terminal_write(tn5250_client->term, event->data.buffer, event->data.size);
|
guac_terminal_write(tn5250_client->term, event->data.buffer, event->data.size);
|
||||||
guac_tn5250_search(client, event->data.buffer, event->data.size);
|
guac_tn5250_search(client, event->data.buffer, event->data.size);
|
||||||
}
|
}
|
||||||
@ -308,6 +329,7 @@ static void __guac_tn5250_event_handler(telnet_t* tn5250, telnet_event_t* event,
|
|||||||
case TELNET_EV_WILL:
|
case TELNET_EV_WILL:
|
||||||
if (event->neg.telopt == TELNET_TELOPT_ECHO)
|
if (event->neg.telopt == TELNET_TELOPT_ECHO)
|
||||||
tn5250_client->echo_enabled = 0; /* Disable local echo, as remote will echo */
|
tn5250_client->echo_enabled = 0; /* Disable local echo, as remote will echo */
|
||||||
|
|
||||||
if (event->neg.telopt == TELNET_TELOPT_EOR) {
|
if (event->neg.telopt == TELNET_TELOPT_EOR) {
|
||||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||||
"%s: Received End of Record support from remote side.",
|
"%s: Received End of Record support from remote side.",
|
||||||
@ -366,6 +388,14 @@ static void __guac_tn5250_event_handler(telnet_t* tn5250, telnet_event_t* event,
|
|||||||
if (event->ttype.cmd == TELNET_TTYPE_SEND) {
|
if (event->ttype.cmd == TELNET_TTYPE_SEND) {
|
||||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||||
"%s: Sending terminal type \"%s\" to remote side.", __func__, settings->terminal_type);
|
"%s: Sending terminal type \"%s\" to remote side.", __func__, settings->terminal_type);
|
||||||
|
|
||||||
|
/* Apparently sending the TERMINAL TYPE to an IBMi system over
|
||||||
|
* telnet requires both sending the TERM environment variable
|
||||||
|
* and responding to the actual telnet TTYPE inquiry. */
|
||||||
|
telnet_begin_newenviron(tn5250, TELNET_ENVIRON_IS);
|
||||||
|
telnet_newenviron_value(tn5250, TELNET_ENVIRON_VAR, "TERM");
|
||||||
|
telnet_newenviron_value(tn5250, TELNET_ENVIRON_VALUE, settings->terminal_type);
|
||||||
|
telnet_finish_sb(tn5250);
|
||||||
telnet_ttype_is(tn5250_client->tn5250, settings->terminal_type);
|
telnet_ttype_is(tn5250_client->tn5250, settings->terminal_type);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -376,8 +406,10 @@ static void __guac_tn5250_event_handler(telnet_t* tn5250, telnet_event_t* event,
|
|||||||
"%s: Received environment request from the remote side.",
|
"%s: Received environment request from the remote side.",
|
||||||
__func__);
|
__func__);
|
||||||
/* Only send USER if entire environment was requested */
|
/* Only send USER if entire environment was requested */
|
||||||
if (event->environ.size == 0)
|
if (event->environ.size == 0) {
|
||||||
|
guac_client_log(client, GUAC_LOG_TRACE, "%s: Sending username to remote server: %s", __func__, settings->username);
|
||||||
guac_tn5250_send_user(tn5250, settings->username);
|
guac_tn5250_send_user(tn5250, settings->username);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -427,8 +459,11 @@ static void __guac_tn5250_event_handler(telnet_t* tn5250, telnet_event_t* event,
|
|||||||
* continuously reads from the terminal's STDIN and transfers all read
|
* continuously reads from the terminal's STDIN and transfers all read
|
||||||
* data to the tn5250 connection.
|
* data to the tn5250 connection.
|
||||||
*
|
*
|
||||||
* @param data The current guac_client instance.
|
* @param data
|
||||||
* @return Always NULL.
|
* The current guac_client instance.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* Always NULL.
|
||||||
*/
|
*/
|
||||||
static void* __guac_tn5250_input_thread(void* data) {
|
static void* __guac_tn5250_input_thread(void* data) {
|
||||||
|
|
||||||
@ -454,8 +489,9 @@ static void* __guac_tn5250_input_thread(void* data) {
|
|||||||
* with the given guac_client, which will have been populated by
|
* with the given guac_client, which will have been populated by
|
||||||
* guac_client_init.
|
* guac_client_init.
|
||||||
*
|
*
|
||||||
* @return The connected tn5250 instance, if successful, or NULL if the
|
* @return
|
||||||
* connection fails for any reason.
|
* The connected tn5250 instance, if successful, or NULL if the
|
||||||
|
* connection fails for any reason.
|
||||||
*/
|
*/
|
||||||
static telnet_t* __guac_tn5250_create_session(guac_client* client) {
|
static telnet_t* __guac_tn5250_create_session(guac_client* client) {
|
||||||
|
|
||||||
@ -553,8 +589,11 @@ static telnet_t* __guac_tn5250_create_session(guac_client* client) {
|
|||||||
* Sends a 16-bit value over the given tn5250 connection with the byte order
|
* Sends a 16-bit value over the given tn5250 connection with the byte order
|
||||||
* required by the tn5250 protocol.
|
* required by the tn5250 protocol.
|
||||||
*
|
*
|
||||||
* @param tn5250 The tn5250 connection to use.
|
* @param tn5250
|
||||||
* @param value The value to send.
|
* The tn5250 connection to use.
|
||||||
|
*
|
||||||
|
* @param value
|
||||||
|
* The value to send.
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
static void __guac_tn5250_send_uint16(telnet_t* tn5250, uint16_t value) {
|
static void __guac_tn5250_send_uint16(telnet_t* tn5250, uint16_t value) {
|
||||||
@ -571,33 +610,32 @@ static void __guac_tn5250_send_uint16(telnet_t* tn5250, uint16_t value) {
|
|||||||
/**
|
/**
|
||||||
* Sends an 8-bit value over the given tn5250 connection.
|
* Sends an 8-bit value over the given tn5250 connection.
|
||||||
*
|
*
|
||||||
* @param tn5250 The tn5250 connection to use.
|
* @param tn5250
|
||||||
* @param value The value to send.
|
* The tn5250 connection to use.
|
||||||
|
*
|
||||||
|
* @param value
|
||||||
|
* The value to send.
|
||||||
*/
|
*/
|
||||||
|
/*
|
||||||
static void __guac_tn5250_send_uint8(telnet_t* tn5250, uint8_t value) {
|
static void __guac_tn5250_send_uint8(telnet_t* tn5250, uint8_t value) {
|
||||||
telnet_send(tn5250, (char*) (&value), 1);
|
telnet_send(tn5250, (char*) (&value), 1);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
void guac_tn5250_send_user(telnet_t* tn5250, const char* username) {
|
void guac_tn5250_send_user(telnet_t* tn5250, const char* username) {
|
||||||
|
|
||||||
/* IAC SB NEW-ENVIRON IS */
|
/* IAC SB NEW-ENVIRON IS */
|
||||||
telnet_begin_sb(tn5250, TELNET_TELOPT_NEW_ENVIRON);
|
telnet_begin_newenviron(tn5250, TELNET_ENVIRON_IS);
|
||||||
__guac_tn5250_send_uint8(tn5250, TELNET_ENVIRON_IS);
|
|
||||||
|
|
||||||
/* Only send username if defined */
|
/* Only send username if defined */
|
||||||
if (username != NULL) {
|
if (username != NULL) {
|
||||||
|
|
||||||
/* VAR "USER" */
|
telnet_newenviron_value(tn5250, TELNET_ENVIRON_VAR, "USER");
|
||||||
__guac_tn5250_send_uint8(tn5250, TELNET_ENVIRON_VAR);
|
telnet_newenviron_value(tn5250, TELNET_ENVIRON_VALUE, username);
|
||||||
telnet_send(tn5250, "USER", 4);
|
|
||||||
|
|
||||||
/* VALUE username */
|
|
||||||
__guac_tn5250_send_uint8(tn5250, TELNET_ENVIRON_VALUE);
|
|
||||||
telnet_send(tn5250, username, strlen(username));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* IAC SE */
|
/* IAC SB */
|
||||||
telnet_finish_sb(tn5250);
|
telnet_finish_sb(tn5250);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -635,21 +673,6 @@ void* guac_tn5250_client_thread(void* data) {
|
|||||||
char buffer[8192];
|
char buffer[8192];
|
||||||
int wait_result;
|
int wait_result;
|
||||||
|
|
||||||
/* If Wake-on-LAN is enabled, attempt to wake. */
|
|
||||||
if (settings->wol_send_packet) {
|
|
||||||
guac_client_log(client, GUAC_LOG_DEBUG, "Sending Wake-on-LAN packet, "
|
|
||||||
"and pausing for %d seconds.", settings->wol_wait_time);
|
|
||||||
|
|
||||||
/* Send the Wake-on-LAN request. */
|
|
||||||
if (guac_wol_wake(settings->wol_mac_addr, settings->wol_broadcast_addr,
|
|
||||||
settings->wol_udp_port))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* If wait time is specified, sleep for that amount of time. */
|
|
||||||
if (settings->wol_wait_time > 0)
|
|
||||||
guac_timestamp_msleep(settings->wol_wait_time * 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set up screen recording, if requested */
|
/* Set up screen recording, if requested */
|
||||||
if (settings->recording_path != NULL) {
|
if (settings->recording_path != NULL) {
|
||||||
tn5250_client->recording = guac_recording_create(client,
|
tn5250_client->recording = guac_recording_create(client,
|
||||||
|
Loading…
Reference in New Issue
Block a user