mirror of https://gerrit.osmocom.org/libtelnet
remove the lib/LIB from identifier prefixes; also, swap printf and printf2 so the more common one is the one with the shorter name
This commit is contained in:
parent
156f5862a6
commit
f65f27d77d
357
README
357
README
|
@ -29,8 +29,8 @@ I. INTRODUCTION
|
|||
|
||||
libtelnet provides safe and correct handling of the core TELNET
|
||||
protocol. In addition to the base TELNET protocol, libtelnet also
|
||||
implements the Q method of TELNET option negotiation. libtelnet
|
||||
can be used for writing servers, clients, or proxies.
|
||||
implements the Q method of TELNET option negotiation. libtelnet can
|
||||
be used for writing servers, clients, or proxies.
|
||||
|
||||
For more information on the TELNET protocol, see:
|
||||
|
||||
|
@ -42,65 +42,65 @@ II. LIBTELNET API
|
|||
|
||||
The libtelnet API contains several distinct parts. The first part is
|
||||
the basic initialization and deinitialization routines. The second
|
||||
part is a single function for pushing received data into the
|
||||
libtelnet processor. The third part is the libtelnet_send_*()
|
||||
functions, which generate TELNET commands and ensure data is properly
|
||||
formatted before sending over the wire. The final part is the event
|
||||
handler interface.
|
||||
part is a single function for pushing received data into the telnet
|
||||
processor. The third part is the telnet_send_*() functions, which
|
||||
generate TELNET commands and ensure data is properly formatted before
|
||||
sending over the wire. The final part is the event handler
|
||||
interface.
|
||||
|
||||
IIa. Initialization
|
||||
|
||||
struct libtelnet_t;
|
||||
struct telnet_t;
|
||||
This structure represents the state of the TELNET protocol for a
|
||||
single connection. Each connection utilizing TELNET must have
|
||||
its own libtelnet_t structure, which is passed to all libtelnet
|
||||
API calls.
|
||||
single connection. Each connection utilizing TELNET must have its
|
||||
own telnet_t structure, which is passed to all libtelnet API
|
||||
calls.
|
||||
|
||||
void libtelnet_init(libtelnet_t *telnet, libtelnet_event_handler_t handler,
|
||||
void telnet_init(telnet_t *telnet, telnet_event_handler_t handler,
|
||||
unsigned char flags, void *user_data);
|
||||
The libtelnet_init() function is responsible for initializing
|
||||
the data in a libtelnet_t structure. It must be called
|
||||
immediately after establishing a connection and before any other
|
||||
libtelnet API calls are made.
|
||||
The telnet_init() function is responsible for initializing the
|
||||
data in a telnet_t structure. It must be called immediately after
|
||||
establishing a connection and before any other libtelnet API calls
|
||||
are made.
|
||||
|
||||
The handler parameter must be a function matching the
|
||||
libtelnet_event_handler_t definition. More information about
|
||||
events can be found in section IId.
|
||||
telnet_event_handler_t definition. More information about events
|
||||
can be found in section IId.
|
||||
|
||||
The user_data parameter is passed to the event handler whenver it
|
||||
is invoked. This will usually be a structure container
|
||||
information about the connection, including a socket descriptor
|
||||
for implementing LIBTELNET_EV_SEND event handling.
|
||||
for implementing TELNET_EV_SEND event handling.
|
||||
|
||||
The flags parameter can be any of the following flag constants
|
||||
bit-or'd together, or 0 to leave all options disabled.
|
||||
|
||||
LIBTELNET_FLAG_PROXY
|
||||
TELNET_FLAG_PROXY
|
||||
Operate in proxy mode. This disables the RFC1143 support and
|
||||
enables automatic detection of COMPRESS2 streams.
|
||||
|
||||
boid libtelnet_free(libtelnet_t *telnet);
|
||||
Releases any internal memory allocated by libtelnet. This must
|
||||
be called whenever a connection is closed, or you will incur
|
||||
memory leaks.
|
||||
boid telnet_free(telnet_t *telnet);
|
||||
Releases any internal memory allocated by libtelnet. This must be
|
||||
called whenever a connection is closed, or you will incur memory
|
||||
leaks.
|
||||
|
||||
IIb. Receiving Data
|
||||
|
||||
void libtelnet_push(libtelnet_t *telnet,
|
||||
void telnet_push(telnet_t *telnet,
|
||||
const char *buffer, unsigned int size, void *user_data);
|
||||
When your application receives data over the socket from the
|
||||
remote end, it must pass the received bytes into this function.
|
||||
|
||||
As the TELNET stream is parsed, events will be generated and
|
||||
passed to the event handler given to libtelnet_init(). Of
|
||||
particular interest for data receiving is the LIBTELNET_EV_DATA
|
||||
event, which is triggered for any regular data such as user
|
||||
input or server process output.
|
||||
passed to the event handler given to telnet_init(). Of particular
|
||||
interest for data receiving is the TELNET_EV_DATA event, which is
|
||||
triggered for any regular data such as user input or server
|
||||
process output.
|
||||
|
||||
IIc. Sending Data
|
||||
|
||||
All of the libtelnet_send_*() functions will invoke the
|
||||
LIBTELNET_EV_SEND event.
|
||||
All of the telnet_send_*() functions will invoke the TELNET_EV_SEND
|
||||
event.
|
||||
|
||||
Note: it is very important that ALL data sent to the remote end of
|
||||
the connection be passed through libtelnet. All user input or
|
||||
|
@ -108,186 +108,185 @@ IIc. Sending Data
|
|||
to one of the following functions. Do NOT send or buffer
|
||||
unprocessed output data directly!
|
||||
|
||||
void libtelnet_send_command(libtelnet_t *telnet, unsigned char cmd);
|
||||
void telnet_send_command(telnet_t *telnet, unsigned char cmd);
|
||||
Sends a single "simple" TELNET command, such as the GO-AHEAD
|
||||
commands (255 249).
|
||||
|
||||
void libtelnet_send_command(libtelnet_t *telnet, unsigned char cmd,
|
||||
void telnet_send_telopt(telnet_t *telnet, unsigned char cmd,
|
||||
unsigned char telopt);
|
||||
Sends a TELNET command with an option code following. This is
|
||||
only useful for the WILL, WONT, DO, DONT, and SB commands.
|
||||
|
||||
void libtelnet_send_negotiate(libtelnet_t *telnet,
|
||||
unsigned char cmd, unsigned char opt);
|
||||
Sends a TELNET negotiation command. The cmd parameter must be
|
||||
one of LIBTELNET_WILL, LIBTELNET_DONT, LIBTELNET_DO, or
|
||||
LIBTELNET_DONT. The opt parameter is the option to
|
||||
negotiate.
|
||||
void telnet_send_negotiate(telnet_t *telnet, unsigned char cmd,
|
||||
unsigned char opt);
|
||||
Sends a TELNET negotiation command. The cmd parameter must be one
|
||||
of TELNET_WILL, TELNET_DONT, TELNET_DO, or TELNET_DONT. The opt
|
||||
parameter is the option to negotiate.
|
||||
|
||||
void libtelnet_send_data(libtelnet_t *telnet,
|
||||
const char *buffer, unsigned int size);
|
||||
Sends raw data, which would be either the process output from
|
||||
a server or the user input from a client.
|
||||
Unless in PROXY mode, the RFC1143 support may delay or ellide the
|
||||
request entirely, as appropriate. It will ignore duplicate
|
||||
invocations, such as asking for WILL NAWS when NAWS is already on
|
||||
or is currently awaiting response from the remote end.
|
||||
|
||||
void libtelnet_send_subnegotiation(libtelnet_t *telnet,
|
||||
unsigned char telopt, const char *buffer,
|
||||
void telnet_send_data(telnet_t *telnet, const char *buffer,
|
||||
unsigned int size);
|
||||
Sends a TELNET sub-negotiation command. The telopt parameter
|
||||
is the sub-negotiation option.
|
||||
Sends raw data, which would be either the process output from a
|
||||
server or the user input from a client.
|
||||
|
||||
For sending regular text is may be more convenient to use
|
||||
telnet_printf().
|
||||
|
||||
void telnet_send_subnegotiation(telnet_t *telnet,
|
||||
unsigned char telopt, const char *buffer, unsigned int size);
|
||||
Sends a TELNET sub-negotiation command. The telopt parameter is
|
||||
the sub-negotiation option.
|
||||
|
||||
Note that the above function is just a shorthand for:
|
||||
libtelnet_send_telopt(telnet, LIBTELNET_SB, telopt);
|
||||
libtelnet_send_data(telnet, buffer, size);
|
||||
libtelnet_send_command(telnet, LIBTELNET_SE);
|
||||
telnet_send_telopt(telnet, TELNET_SB, telopt);
|
||||
telnet_send_data(telnet, buffer, size);
|
||||
telnet_send_command(telnet, TELNET_SE);
|
||||
|
||||
For some subnegotiations that involve a lot of complex formatted
|
||||
data to be sent, it may be easier to manually send the SB telopt
|
||||
header and SE footer around mulitple calls to send_data.
|
||||
|
||||
NOTE: libtelnet_send_subnegotiation() does have special behavior
|
||||
in PROXY mode, as in that mode this function will automatically
|
||||
NOTE: telnet_send_subnegotiation() does have special behavior in
|
||||
PROXY mode, as in that mode this function will automatically
|
||||
detect the COMPRESS2 marker and enable zlib compression.
|
||||
|
||||
int libtelnet_printf(libtelnet_t *telnet, const char *fmt, ...);
|
||||
This functions very similarly to fprintf, except that output
|
||||
is sent through libtelnet for processing. This is equivalent
|
||||
to using snprintf() to format data into a buffer and then
|
||||
sending the buffer to libtelnet_send_data(). The return code
|
||||
is the length of the formatted text.
|
||||
int telnet_printf(telnet_t *telnet, const char *fmt, ...);
|
||||
This functions very similarly to fprintf, except that output is
|
||||
sent through libtelnet for processing. IAC bytes are properly
|
||||
escaped, C newlines (\n) are translated into CR LF, and C carriage
|
||||
returns (\r) are translated into CR NUL, all as required by
|
||||
RFC854. The return code is the length of the formatted text.
|
||||
|
||||
NOTE: due to an internal implementation detail, the maximum
|
||||
lenth of the formatted text is 4096 characters.
|
||||
|
||||
int libtelnet_printf2(libtelnet_T *telnet, const char *fmt, ...);
|
||||
Identical to libtelnet_print(), except that this variant will
|
||||
also translate C newlines (\n) into a CRLF and translates
|
||||
carriage returns (\r) into CRNUL, as required by TELNET.
|
||||
|
||||
NOTE: this function should only be used for regular data such
|
||||
as user input (in client applications) or process output (in
|
||||
server applications). If you are formatting data that is part
|
||||
of a subnegotiation, you should always use libtelnet_printf()
|
||||
instead, as you will rarely want newline translation inside of
|
||||
subnegotiations.
|
||||
int telnet_printf2(telnet_t *telnet, const char *fmt, ...);
|
||||
Identical to telnet_printf() except that \r and \n are not
|
||||
translated. This should be used if you are attempting to send
|
||||
raw data inside a subnegotiation or if you have already manually
|
||||
escaped newlines.
|
||||
|
||||
IId. Event Handling
|
||||
|
||||
libtelnet relies on an event-handling mechanism for processing
|
||||
the parsed TELNET protocol stream as well as for buffering and
|
||||
sending output data.
|
||||
libtelnet relies on an event-handling mechanism for processing the
|
||||
parsed TELNET protocol stream as well as for buffering and sending
|
||||
output data.
|
||||
|
||||
When you initialize a libtelnet_t structure with libtelnet_init()
|
||||
you had to pass in an event handler function. This function must
|
||||
meet the following prototype:
|
||||
When you initialize a telnet_t structure with telnet_init() you had
|
||||
to pass in an event handler function. This function must meet the
|
||||
following prototype:
|
||||
|
||||
void (libtelnet_t *telnet, libtelnet_event_t *event,
|
||||
void *user_data);
|
||||
void (telnet_t *telnet, telnet_event_t *event, void *user_data);
|
||||
|
||||
The event structure is detailed below. The user_data value is the
|
||||
pointer passed to libtelnet_init().
|
||||
pointer passed to telnet_init().
|
||||
|
||||
struct libtelnet_event_t {
|
||||
struct telnet_event_t {
|
||||
const char *buffer;
|
||||
unsigned int size;
|
||||
libtelnet_event_type_t type;
|
||||
telnet_event_type_t type;
|
||||
unsigned char command;
|
||||
unsigned char telopt;
|
||||
unsigned char accept;
|
||||
};
|
||||
|
||||
The enumeration values of libtelnet_event_type_t are described in
|
||||
The enumeration values of telnet_event_type_t are described in
|
||||
detail below. Whenever the the event handler is invoked, the
|
||||
application must look at the event->type value and do any
|
||||
necessary processing.
|
||||
application must look at the event->type value and do any necessary
|
||||
processing.
|
||||
|
||||
The only event that MUST be implemented is LIBTELNET_EV_SEND.
|
||||
Most applications will also always want to implement the event
|
||||
LIBTELNET_EV_DATA.
|
||||
The only event that MUST be implemented is TELNET_EV_SEND. Most
|
||||
applications will also always want to implement the event
|
||||
TELNET_EV_DATA.
|
||||
|
||||
Here is an example event handler implementation which includes
|
||||
handlers for several important events.
|
||||
|
||||
void my_event_handler(libtelnet_t *telnet, libtelnet_event_t *ev,
|
||||
void my_event_handler(telnet_t *telnet, telnet_event_t *ev,
|
||||
void *user_data) {
|
||||
struct user_info *user = (struct user_info *)user_data;
|
||||
|
||||
switch (ev->type) {
|
||||
case LIBTELNET_EV_DATA:
|
||||
case TELNET_EV_DATA:
|
||||
process_user_input(user, event->buffer, event->size);
|
||||
break;
|
||||
case LIBTELNET_EV_SEND:
|
||||
case TELNET_EV_SEND:
|
||||
write_to_descriptor(user, event->buffer, event->size);
|
||||
break;
|
||||
case LIBTELNET_EV_ERROR:
|
||||
case TELNET_EV_ERROR:
|
||||
fatal_error("TELNET error: %s", event->buffer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LIBTELNET_EV_DATA:
|
||||
The DATA event is triggered whenever regular data (not part of
|
||||
any special TELNET command) is received. For a client, this
|
||||
will be process output from the server. For a server, this will
|
||||
be input typed by the user.
|
||||
TELNET_EV_DATA:
|
||||
The DATA event is triggered whenever regular data (not part of any
|
||||
special TELNET command) is received. For a client, this will be
|
||||
process output from the server. For a server, this will be input
|
||||
typed by the user.
|
||||
|
||||
The event->buffer value will contain the bytes received and the
|
||||
event->size value will contain the number of bytes received.
|
||||
Note that event->buffer is not NUL terminated!
|
||||
event->size value will contain the number of bytes received. Note
|
||||
that event->buffer is not NUL terminated!
|
||||
|
||||
NOTE: there is no guarantee that user input or server output
|
||||
will be received in whole lines. If you wish to process data
|
||||
a line at a time, you are responsible for buffering the data and
|
||||
checking for line terminators yourself!
|
||||
|
||||
LIBTELNET_EV_SEND:
|
||||
This event is sent whenever libtelnet has generated data that
|
||||
must be sent over the wire to the remove end. Generally that
|
||||
means calling send() or adding the data to your application's
|
||||
output buffer.
|
||||
TELNET_EV_SEND:
|
||||
This event is sent whenever libtelnet has generated data that must
|
||||
be sent over the wire to the remove end. Generally that means
|
||||
calling send() or adding the data to your application's output
|
||||
buffer.
|
||||
|
||||
The event->buffer value will contain the bytes to send and the
|
||||
event->size value will contain the number of bytes to send.
|
||||
Note that event->buffer is not NUL terminated, and may include
|
||||
NUL characters in its data, so always use event->size!
|
||||
event->size value will contain the number of bytes to send. Note
|
||||
that event->buffer is not NUL terminated, and may include NUL
|
||||
characters in its data, so always use event->size!
|
||||
|
||||
NOTE: Your SEND event handler must send or buffer the data in
|
||||
its raw form as provided by libtelnet. If you wish to perform
|
||||
any kind of preprocessing on data you want to send to the other
|
||||
|
||||
LIBTELNET_EV_IAC:
|
||||
TELNET_EV_IAC:
|
||||
The IAC event is triggered whenever a simple IAC command is
|
||||
received, such as the IAC EOR (end of record, also called
|
||||
go ahead or GA) command.
|
||||
received, such as the IAC EOR (end of record, also called go ahead
|
||||
or GA) command.
|
||||
|
||||
The command received is in the event->command value.
|
||||
|
||||
The necessary processing depends on the specific commands; see
|
||||
the TELNET RFC for more information.
|
||||
|
||||
LIBTELNET_EV_WILL:
|
||||
LIBTELNET_EV_DO:
|
||||
The WILL and DO events are sent when a TELNET negotiation
|
||||
command of the same name is received.
|
||||
TELNET_EV_WILL:
|
||||
TELNET_EV_DO:
|
||||
The WILL and DO events are sent when a TELNET negotiation command
|
||||
of the same name is received.
|
||||
|
||||
WILL events are sent by the remote end when they wish to be
|
||||
allowed to turn an option on on their end, or in confirmation
|
||||
after you have sent a DO command to them.
|
||||
|
||||
DO events are sent by the remote end when they wish for you
|
||||
to turn on an option on your end, or in confirmation after you
|
||||
have sent a WILL command to them.
|
||||
DO events are sent by the remote end when they wish for you to
|
||||
turn on an option on your end, or in confirmation after you have
|
||||
sent a WILL command to them.
|
||||
|
||||
In either case, the TELNET option under negotiation will be in
|
||||
event->telopt field.
|
||||
|
||||
If you support the option and wish for it to be enabled you
|
||||
must set the event->accept field to 1, unless this event is
|
||||
a confirmation for a previous WILL/DO command you sent to the
|
||||
remote end. If you do not set event->field to 1 then
|
||||
libtelnet will send a rejection command back to the other end.
|
||||
If you support the option and wish for it to be enabled you must
|
||||
set the event->accept field to 1, unless this event is a
|
||||
confirmation for a previous WILL/DO command you sent to the remote
|
||||
end. If you do not set event->field to 1 then libtelnet will send
|
||||
a rejection command back to the other end.
|
||||
|
||||
libtelnet manages some of the pecularities of negotiation for
|
||||
you. For information on libtelnet's negotiation method, see:
|
||||
libtelnet manages some of the pecularities of negotiation for you.
|
||||
For information on libtelnet's negotiation method, see:
|
||||
|
||||
http://www.faqs.org/rfcs/rfc1143.html
|
||||
|
||||
|
@ -309,12 +308,12 @@ IId. Event Handling
|
|||
Note that in PROXY mode libtelnet will do no processing of its
|
||||
own for you.
|
||||
|
||||
LIBTELNET_EV_WONT:
|
||||
LIBTELNET_EV_DONT:
|
||||
TELNET_EV_WONT:
|
||||
TELNET_EV_DONT:
|
||||
The WONT and DONT events are sent when the remote end of the
|
||||
connection wishes to disable an option, when they are
|
||||
refusing to a support an option that you have asked for, or
|
||||
in confirmation of an option you have asked to be disabled.
|
||||
connection wishes to disable an option, when they are refusing to
|
||||
a support an option that you have asked for, or in confirmation of
|
||||
an option you have asked to be disabled.
|
||||
|
||||
Most commonly WONT and DONT events are sent as rejections of
|
||||
features you requested by sending DO or WILL events. Receiving
|
||||
|
@ -334,27 +333,27 @@ IId. Event Handling
|
|||
Note that in PROXY mode libtelnet will do no processing of its
|
||||
own for you.
|
||||
|
||||
LIBTELNET_EV_SUBNEGOTIATION:
|
||||
TELNET_EV_SUBNEGOTIATION:
|
||||
Triggered whenever a TELNET sub-negotiation has been received.
|
||||
Sub-negotiations include the NAWS option for communicating
|
||||
terminal size to a server, the NEW-ENVIRON and TTYPE options
|
||||
for negotiating terminal features, and MUD-centric protocols
|
||||
such as ZMP, MSSP, and MCCP2.
|
||||
terminal size to a server, the NEW-ENVIRON and TTYPE options for
|
||||
negotiating terminal features, and MUD-centric protocols such as
|
||||
ZMP, MSSP, and MCCP2.
|
||||
|
||||
The event->telopt value is the option under sub-negotiation.
|
||||
The remaining data (if any) is passed in event->buffer and
|
||||
event->size. Note that most subnegotiation commands can
|
||||
include embedded NUL bytes in the subnegotiation data, and
|
||||
the data event->buffer is not NUL terminated, so always use
|
||||
the event->size value!
|
||||
The event->telopt value is the option under sub-negotiation. The
|
||||
remaining data (if any) is passed in event->buffer and
|
||||
event->size. Note that most subnegotiation commands can include
|
||||
embedded NUL bytes in the subnegotiation data, and the data
|
||||
event->buffer is not NUL terminated, so always use the event->size
|
||||
value!
|
||||
|
||||
The meaning and necessary processing for subnegotiations are
|
||||
defined in various TELNET RFCs and other informal
|
||||
specifications. A subnegotiation should never be sent unless
|
||||
the specific option has been enabled through the use of the
|
||||
telnet negotiation feature.
|
||||
defined in various TELNET RFCs and other informal specifications.
|
||||
A subnegotiation should never be sent unless the specific option
|
||||
has been enabled through the use of the telnet negotiation
|
||||
feature.
|
||||
|
||||
LIBTELNET_EV_COMPRESS
|
||||
TELNET_EV_COMPRESS
|
||||
The COMPRESS event notifies the app that COMPRESS2/MCCP2
|
||||
compression has begun or ended. Only servers can send compressed
|
||||
data, and hence only clients will receive compressed data.
|
||||
|
@ -362,25 +361,24 @@ IId. Event Handling
|
|||
The event->command value will be 1 if compression has started and
|
||||
will be 0 if compression has ended.
|
||||
|
||||
LIBTELNET_EV_WARNING
|
||||
The WARNING event is sent whenever something has gone wrong
|
||||
inside of libtelnet (possibly due to malformed data sent by the
|
||||
other end) but which recovery is (likely) possible. It may be
|
||||
safe to continue using the connection, but some data may have
|
||||
been lost or incorrectly interpreted.
|
||||
TELNET_EV_WARNING
|
||||
The WARNING event is sent whenever something has gone wrong inside
|
||||
of libtelnet (possibly due to malformed data sent by the other
|
||||
end) but which recovery is (likely) possible. It may be safe to
|
||||
continue using the connection, but some data may have been lost or
|
||||
incorrectly interpreted.
|
||||
|
||||
The event->buffer value will contain a NUL terminated string
|
||||
explaining the error, and the event->size value containers the
|
||||
length of the string.
|
||||
|
||||
LIBTELNET_EV_ERROR
|
||||
TELNET_EV_ERROR
|
||||
Similar to the WARNING event, the ERROR event is sent whenever
|
||||
something has gone wrong. ERROR events are non-recoverable,
|
||||
however, and the application should immediately close the
|
||||
connection. Whatever has happened is likely going only to
|
||||
result in garbage from libtelnet. This is most likely to
|
||||
happen when a COMPRESS2 stream fails, but other problems can
|
||||
occur.
|
||||
connection. Whatever has happened is likely going only to result
|
||||
in garbage from libtelnet. This is most likely to happen when a
|
||||
COMPRESS2 stream fails, but other problems can occur.
|
||||
|
||||
The event->buffer value will contain a NUL terminated string
|
||||
explaining the error, and the event->size value containers the
|
||||
|
@ -396,30 +394,30 @@ IV. SAFETY AND CORRECTNESS CONSIDERATIONS
|
|||
=====================================================================
|
||||
|
||||
Your existing application may make heavy use of its own output
|
||||
buffering and transmission commands, including hand-made routines
|
||||
for sending TELNET commands and sub-negotiation requests. There are
|
||||
at times subtle issues that need to be handled when communication
|
||||
over the TELNET protocol, not least of which is the need to escape
|
||||
any byte value 0xFF with a special TELNET command.
|
||||
buffering and transmission commands, including hand-made routines for
|
||||
sending TELNET commands and sub-negotiation requests. There are at
|
||||
times subtle issues that need to be handled when communication over
|
||||
the TELNET protocol, not least of which is the need to escape any
|
||||
byte value 0xFF with a special TELNET command.
|
||||
|
||||
For these reasons, it is very important that applications making use
|
||||
of libtelnet always make use of the libtelnet_send_*() family of
|
||||
of libtelnet always make use of the telnet_send_*() family of
|
||||
functions for all data being sent over the TELNET connection.
|
||||
|
||||
In particular, if you are writing a client, all user input must be
|
||||
passed through to libtelnet_send_data(). This also includes any
|
||||
input generated automatically by scripts, triggers, or macros.
|
||||
passed through to telnet_send_data(). This also includes any input
|
||||
generated automatically by scripts, triggers, or macros.
|
||||
|
||||
For a server, any and all output -- including ANSI/VT100 escape
|
||||
codes, regular text, newlines, and so on -- must be passed through
|
||||
to libtelnet_send_data().
|
||||
codes, regular text, newlines, and so on -- must be passed through to
|
||||
telnet_send_data().
|
||||
|
||||
Any TELNET commands that are to be sent must be given to one of the
|
||||
following: libtelnet_send_command, libtelnet_send_negotiate, or
|
||||
libtelnet_send_subnegotiation().
|
||||
following: telnet_send_command, telnet_send_negotiate, or
|
||||
telnet_send_subnegotiation().
|
||||
|
||||
If you are attempting to enable COMPRESS2/MCCP2, you must use the
|
||||
libtelnet_begin_compress2() function.
|
||||
telnet_begin_compress2() function.
|
||||
|
||||
V. MCCP2 COMPRESSION
|
||||
=====================================================================
|
||||
|
@ -435,15 +433,15 @@ when compiling libtelnet.c and pass -lz to the linker to link in the
|
|||
zlib shared library.
|
||||
|
||||
libtelnet transparently supports MCCP2. For a server to support
|
||||
MCCP2, the application must begin negotiation of the COMPRESS2
|
||||
option using libtelnet_send_negotiate(), for example:
|
||||
MCCP2, the application must begin negotiation of the COMPRESS2 option
|
||||
using telnet_send_negotiate(), for example:
|
||||
|
||||
libtelnet_send_negotiate(&telnet, LIBTELNET_WILL,
|
||||
LIBTELNET_OPTION_COMPRESS2, user_data);
|
||||
telnet_send_negotiate(&telnet, TELNET_WILL,
|
||||
TELNET_OPTION_COMPRESS2, user_data);
|
||||
|
||||
If a favorable DO COMPRESS2 is sent back from the client then the
|
||||
server application can begin compression at any time by calling
|
||||
libtelnet_begin_compress2().
|
||||
telnet_begin_compress2().
|
||||
|
||||
If a connection is in PROXY mode and COMPRESS2 support is enabled
|
||||
then libtelnet will automatically detect the start of a COMPRESS2
|
||||
|
@ -452,8 +450,8 @@ stream, in either the sending or receiving direction.
|
|||
VI. TELNET PROXY UTILITY
|
||||
=====================================================================
|
||||
|
||||
The telnet-proxy utility is a small application that serves both as
|
||||
a testbed for libtelnet and as a powerful debugging tool for TELNET
|
||||
The telnet-proxy utility is a small application that serves both as a
|
||||
testbed for libtelnet and as a powerful debugging tool for TELNET
|
||||
servers and clients.
|
||||
|
||||
To use telnet-proxy, you must first compile it using:
|
||||
|
@ -464,8 +462,8 @@ If you do not have zlib installed and wish to disable MCCP2 support
|
|||
then you must first edit the Makefile and remove the -DHAVE_ZLIB and
|
||||
the -lz from the compile flags.
|
||||
|
||||
To run telnet-proxy, you simply give it the server's host name or
|
||||
IP address, the server's port number, and the port number that
|
||||
To run telnet-proxy, you simply give it the server's host name or IP
|
||||
address, the server's port number, and the port number that
|
||||
telnet-proxy should listen on. For example, to connect to the server
|
||||
on mud.example.com port 7800 and to listen on port 5000, run:
|
||||
|
||||
|
@ -475,8 +473,7 @@ You can then connect to the host telnet-proxy is running on (e.g.
|
|||
127.0.0.1) on port 500 and you will automatically be proxied into
|
||||
mud.example.com.
|
||||
|
||||
telnet-proxy will display status information about the data
|
||||
passing through both ends of the tunnel. telnet-proxy can only
|
||||
support a single tunnel at a time. It will continue running until
|
||||
an error occurs or a terminating signal is sent to the proxy
|
||||
process.
|
||||
telnet-proxy will display status information about the data passing
|
||||
through both ends of the tunnel. telnet-proxy can only support a
|
||||
single tunnel at a time. It will continue running until an error
|
||||
occurs or a terminating signal is sent to the proxy process.
|
||||
|
|
378
libtelnet.c
378
libtelnet.c
|
@ -47,10 +47,10 @@ static const size_t _buffer_sizes_count = sizeof(_buffer_sizes) /
|
|||
|
||||
/* event dispatch helper; return value is value of the accept field of the
|
||||
* event struct after dispatch; used for the funky REQUEST event */
|
||||
static int _event(libtelnet_t *telnet, libtelnet_event_type_t type,
|
||||
static int _event(telnet_t *telnet, telnet_event_type_t type,
|
||||
unsigned char command, unsigned char telopt,
|
||||
const char *buffer, size_t size) {
|
||||
libtelnet_event_t ev;
|
||||
telnet_event_t ev;
|
||||
ev.buffer = buffer;
|
||||
ev.size = size;
|
||||
ev.type = type;
|
||||
|
@ -64,8 +64,8 @@ static int _event(libtelnet_t *telnet, libtelnet_event_type_t type,
|
|||
}
|
||||
|
||||
/* error generation function */
|
||||
static libtelnet_error_t _error(libtelnet_t *telnet, unsigned line,
|
||||
const char* func, libtelnet_error_t err, int fatal, const char *fmt,
|
||||
static telnet_error_t _error(telnet_t *telnet, unsigned line,
|
||||
const char* func, telnet_error_t err, int fatal, const char *fmt,
|
||||
...) {
|
||||
char buffer[512];
|
||||
va_list va;
|
||||
|
@ -78,7 +78,7 @@ static libtelnet_error_t _error(libtelnet_t *telnet, unsigned line,
|
|||
fmt, va);
|
||||
va_end(va);
|
||||
|
||||
_event(telnet, fatal ? LIBTELNET_EV_ERROR : LIBTELNET_EV_WARNING, err,
|
||||
_event(telnet, fatal ? TELNET_EV_ERROR : TELNET_EV_WARNING, err,
|
||||
0, (char *)buffer, strlen(buffer));
|
||||
|
||||
return err;
|
||||
|
@ -87,52 +87,52 @@ static libtelnet_error_t _error(libtelnet_t *telnet, unsigned line,
|
|||
#ifdef HAVE_ZLIB
|
||||
/* initialize the zlib box for a telnet box; if deflate is non-zero, it
|
||||
* initializes zlib for delating (compression), otherwise for inflating
|
||||
* (decompression). returns LIBTELNET_EOK on success, something else on
|
||||
* (decompression). returns TELNET_EOK on success, something else on
|
||||
* failure.
|
||||
*/
|
||||
libtelnet_error_t _init_zlib(libtelnet_t *telnet, int deflate, int err_fatal) {
|
||||
telnet_error_t _init_zlib(telnet_t *telnet, int deflate, int err_fatal) {
|
||||
z_stream *z;
|
||||
int rs;
|
||||
|
||||
/* if compression is already enabled, fail loudly */
|
||||
if (telnet->z != 0)
|
||||
return _error(telnet, __LINE__, __func__, LIBTELNET_EBADVAL,
|
||||
return _error(telnet, __LINE__, __func__, TELNET_EBADVAL,
|
||||
err_fatal, "cannot initialize compression twice");
|
||||
|
||||
/* allocate zstream box */
|
||||
if ((z= (z_stream *)calloc(1, sizeof(z_stream))) == 0)
|
||||
return _error(telnet, __LINE__, __func__, LIBTELNET_ENOMEM, err_fatal,
|
||||
return _error(telnet, __LINE__, __func__, TELNET_ENOMEM, err_fatal,
|
||||
"malloc() failed: %s", strerror(errno));
|
||||
|
||||
/* initialize */
|
||||
if (deflate) {
|
||||
if ((rs = deflateInit(z, Z_DEFAULT_COMPRESSION)) != Z_OK) {
|
||||
free(z);
|
||||
return _error(telnet, __LINE__, __func__, LIBTELNET_ECOMPRESS,
|
||||
return _error(telnet, __LINE__, __func__, TELNET_ECOMPRESS,
|
||||
err_fatal, "deflateInit() failed: %s", zError(rs));
|
||||
}
|
||||
telnet->flags |= LIBTELNET_PFLAG_DEFLATE;
|
||||
telnet->flags |= TELNET_PFLAG_DEFLATE;
|
||||
} else {
|
||||
if ((rs = inflateInit(z)) != Z_OK) {
|
||||
free(z);
|
||||
return _error(telnet, __LINE__, __func__, LIBTELNET_ECOMPRESS,
|
||||
return _error(telnet, __LINE__, __func__, TELNET_ECOMPRESS,
|
||||
err_fatal, "inflateInit() failed: %s", zError(rs));
|
||||
}
|
||||
telnet->flags &= ~LIBTELNET_PFLAG_DEFLATE;
|
||||
telnet->flags &= ~TELNET_PFLAG_DEFLATE;
|
||||
}
|
||||
|
||||
telnet->z = z;
|
||||
|
||||
return LIBTELNET_EOK;
|
||||
return TELNET_EOK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* push bytes out, compressing them first if need be */
|
||||
static void _send(libtelnet_t *telnet, const char *buffer,
|
||||
static void _send(telnet_t *telnet, const char *buffer,
|
||||
size_t size) {
|
||||
#ifdef HAVE_ZLIB
|
||||
/* if we have a deflate (compression) zlib box, use it */
|
||||
if (telnet->z != 0 && telnet->flags & LIBTELNET_PFLAG_DEFLATE) {
|
||||
if (telnet->z != 0 && telnet->flags & TELNET_PFLAG_DEFLATE) {
|
||||
char deflate_buffer[1024];
|
||||
int rs;
|
||||
|
||||
|
@ -146,7 +146,7 @@ static void _send(libtelnet_t *telnet, const char *buffer,
|
|||
while (telnet->z->avail_in > 0 || telnet->z->avail_out == 0) {
|
||||
/* compress */
|
||||
if ((rs = deflate(telnet->z, Z_SYNC_FLUSH)) != Z_OK) {
|
||||
_error(telnet, __LINE__, __func__, LIBTELNET_ECOMPRESS, 1,
|
||||
_error(telnet, __LINE__, __func__, TELNET_ECOMPRESS, 1,
|
||||
"deflate() failed: %s", zError(rs));
|
||||
deflateEnd(telnet->z);
|
||||
free(telnet->z);
|
||||
|
@ -154,7 +154,7 @@ static void _send(libtelnet_t *telnet, const char *buffer,
|
|||
break;
|
||||
}
|
||||
|
||||
_event(telnet, LIBTELNET_EV_SEND, 0, 0, deflate_buffer,
|
||||
_event(telnet, TELNET_EV_SEND, 0, 0, deflate_buffer,
|
||||
sizeof(deflate_buffer) - telnet->z->avail_out);
|
||||
|
||||
/* prepare output buffer for next run */
|
||||
|
@ -165,12 +165,12 @@ static void _send(libtelnet_t *telnet, const char *buffer,
|
|||
/* COMPRESS2 is not negotiated, just send */
|
||||
} else
|
||||
#endif /* HAVE_ZLIB */
|
||||
_event(telnet, LIBTELNET_EV_SEND, 0, 0, buffer, size);
|
||||
_event(telnet, TELNET_EV_SEND, 0, 0, buffer, size);
|
||||
}
|
||||
|
||||
/* retrieve RFC1143 option state */
|
||||
libtelnet_rfc1143_t _get_rfc1143(libtelnet_t *telnet, unsigned char telopt) {
|
||||
static const libtelnet_rfc1143_t empty = { 0, 0, 0};
|
||||
telnet_rfc1143_t _get_rfc1143(telnet_t *telnet, unsigned char telopt) {
|
||||
static const telnet_rfc1143_t empty = { 0, 0, 0};
|
||||
int i;
|
||||
|
||||
/* search for entry */
|
||||
|
@ -183,8 +183,8 @@ libtelnet_rfc1143_t _get_rfc1143(libtelnet_t *telnet, unsigned char telopt) {
|
|||
}
|
||||
|
||||
/* save RFC1143 option state */
|
||||
void _set_rfc1143(libtelnet_t *telnet, libtelnet_rfc1143_t q) {
|
||||
libtelnet_rfc1143_t *qtmp;
|
||||
void _set_rfc1143(telnet_t *telnet, telnet_rfc1143_t q) {
|
||||
telnet_rfc1143_t *qtmp;
|
||||
int i;
|
||||
|
||||
/* search for entry */
|
||||
|
@ -198,9 +198,9 @@ void _set_rfc1143(libtelnet_t *telnet, libtelnet_rfc1143_t q) {
|
|||
/* we're going to need to track state for it, so grow the queue
|
||||
* and put the telopt into it; bail on allocation error
|
||||
*/
|
||||
if ((qtmp = (libtelnet_rfc1143_t *)malloc(sizeof(
|
||||
libtelnet_rfc1143_t) * (telnet->q_size + 1))) == 0) {
|
||||
_error(telnet, __LINE__, __func__, LIBTELNET_ENOMEM, 0,
|
||||
if ((qtmp = (telnet_rfc1143_t *)malloc(sizeof(
|
||||
telnet_rfc1143_t) * (telnet->q_size + 1))) == 0) {
|
||||
_error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
|
||||
"malloc() failed: %s", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
@ -209,24 +209,24 @@ void _set_rfc1143(libtelnet_t *telnet, libtelnet_rfc1143_t q) {
|
|||
}
|
||||
|
||||
/* negotiation handling magic for RFC1143 */
|
||||
static void _negotiate(libtelnet_t *telnet, unsigned char cmd,
|
||||
static void _negotiate(telnet_t *telnet, unsigned char cmd,
|
||||
unsigned char telopt) {
|
||||
libtelnet_rfc1143_t q;
|
||||
telnet_rfc1143_t q;
|
||||
|
||||
/* in PROXY mode, just pass it thru and do nothing */
|
||||
if (telnet->flags & LIBTELNET_FLAG_PROXY) {
|
||||
if (telnet->flags & TELNET_FLAG_PROXY) {
|
||||
switch (cmd) {
|
||||
case LIBTELNET_WILL:
|
||||
_event(telnet, LIBTELNET_EV_WILL, 0, telopt, 0, 0);
|
||||
case TELNET_WILL:
|
||||
_event(telnet, TELNET_EV_WILL, 0, telopt, 0, 0);
|
||||
break;
|
||||
case LIBTELNET_WONT:
|
||||
_event(telnet, LIBTELNET_EV_WONT, 0, telopt, 0, 0);
|
||||
case TELNET_WONT:
|
||||
_event(telnet, TELNET_EV_WONT, 0, telopt, 0, 0);
|
||||
break;
|
||||
case LIBTELNET_DO:
|
||||
_event(telnet, LIBTELNET_EV_DO, 0, telopt, 0, 0);
|
||||
case TELNET_DO:
|
||||
_event(telnet, TELNET_EV_DO, 0, telopt, 0, 0);
|
||||
break;
|
||||
case LIBTELNET_DONT:
|
||||
_event(telnet, LIBTELNET_EV_DONT, 0, telopt, 0, 0);
|
||||
case TELNET_DONT:
|
||||
_event(telnet, TELNET_EV_DONT, 0, telopt, 0, 0);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
|
@ -238,28 +238,28 @@ static void _negotiate(libtelnet_t *telnet, unsigned char cmd,
|
|||
/* start processing... */
|
||||
switch (cmd) {
|
||||
/* request to enable option on remote end or confirm DO */
|
||||
case LIBTELNET_WILL:
|
||||
case TELNET_WILL:
|
||||
switch (q.him) {
|
||||
case RFC1143_NO:
|
||||
if (_event(telnet, LIBTELNET_EV_WILL, cmd, telopt, 0, 0) == 1) {
|
||||
if (_event(telnet, TELNET_EV_WILL, cmd, telopt, 0, 0) == 1) {
|
||||
q.him = RFC1143_YES;
|
||||
_set_rfc1143(telnet, q);
|
||||
libtelnet_send_telopt(telnet, LIBTELNET_DO, telopt);
|
||||
telnet_send_telopt(telnet, TELNET_DO, telopt);
|
||||
} else
|
||||
libtelnet_send_telopt(telnet, LIBTELNET_DONT, telopt);
|
||||
telnet_send_telopt(telnet, TELNET_DONT, telopt);
|
||||
break;
|
||||
case RFC1143_YES:
|
||||
break;
|
||||
case RFC1143_WANTNO:
|
||||
q.him = RFC1143_NO;
|
||||
_set_rfc1143(telnet, q);
|
||||
_error(telnet, __LINE__, __func__, LIBTELNET_EPROTOCOL, 0,
|
||||
_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
|
||||
"DONT answered by WILL");
|
||||
break;
|
||||
case RFC1143_WANTNO_OP:
|
||||
q.him = RFC1143_YES;
|
||||
_set_rfc1143(telnet, q);
|
||||
_error(telnet, __LINE__, __func__, LIBTELNET_EPROTOCOL, 0,
|
||||
_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
|
||||
"DONT answered by WILL");
|
||||
break;
|
||||
case RFC1143_WANTYES:
|
||||
|
@ -269,33 +269,33 @@ static void _negotiate(libtelnet_t *telnet, unsigned char cmd,
|
|||
case RFC1143_WANTYES_OP:
|
||||
q.him = RFC1143_WANTNO;
|
||||
_set_rfc1143(telnet, q);
|
||||
libtelnet_send_telopt(telnet, LIBTELNET_DONT, telopt);
|
||||
telnet_send_telopt(telnet, TELNET_DONT, telopt);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
/* request to disable option on remote end, confirm DONT, reject DO */
|
||||
case LIBTELNET_WONT:
|
||||
case TELNET_WONT:
|
||||
switch (q.him) {
|
||||
case RFC1143_NO:
|
||||
break;
|
||||
case RFC1143_YES:
|
||||
q.him = RFC1143_NO;
|
||||
_set_rfc1143(telnet, q);
|
||||
libtelnet_send_telopt(telnet, LIBTELNET_DONT, telopt);
|
||||
_event(telnet, LIBTELNET_EV_WONT, 0, telopt,
|
||||
telnet_send_telopt(telnet, TELNET_DONT, telopt);
|
||||
_event(telnet, TELNET_EV_WONT, 0, telopt,
|
||||
0, 0);
|
||||
break;
|
||||
case RFC1143_WANTNO:
|
||||
q.him = RFC1143_NO;
|
||||
_set_rfc1143(telnet, q);
|
||||
_event(telnet, LIBTELNET_EV_WONT, 0, telopt,
|
||||
_event(telnet, TELNET_EV_WONT, 0, telopt,
|
||||
0, 0);
|
||||
break;
|
||||
case RFC1143_WANTNO_OP:
|
||||
q.him = RFC1143_WANTYES;
|
||||
_set_rfc1143(telnet, q);
|
||||
_event(telnet, LIBTELNET_EV_DO, 0, telopt,
|
||||
_event(telnet, TELNET_EV_DO, 0, telopt,
|
||||
0, 0);
|
||||
break;
|
||||
case RFC1143_WANTYES:
|
||||
|
@ -307,28 +307,28 @@ static void _negotiate(libtelnet_t *telnet, unsigned char cmd,
|
|||
break;
|
||||
|
||||
/* request to enable option on local end or confirm WILL */
|
||||
case LIBTELNET_DO:
|
||||
case TELNET_DO:
|
||||
switch (q.us) {
|
||||
case RFC1143_NO:
|
||||
if (_event(telnet, LIBTELNET_EV_DO, cmd, telopt, 0, 0) == 1) {
|
||||
if (_event(telnet, TELNET_EV_DO, cmd, telopt, 0, 0) == 1) {
|
||||
q.us = RFC1143_YES;
|
||||
_set_rfc1143(telnet, q);
|
||||
libtelnet_send_telopt(telnet, LIBTELNET_WILL, telopt);
|
||||
telnet_send_telopt(telnet, TELNET_WILL, telopt);
|
||||
} else
|
||||
libtelnet_send_telopt(telnet, LIBTELNET_WONT, telopt);
|
||||
telnet_send_telopt(telnet, TELNET_WONT, telopt);
|
||||
break;
|
||||
case RFC1143_YES:
|
||||
break;
|
||||
case RFC1143_WANTNO:
|
||||
q.us = RFC1143_NO;
|
||||
_set_rfc1143(telnet, q);
|
||||
_error(telnet, __LINE__, __func__, LIBTELNET_EPROTOCOL, 0,
|
||||
_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
|
||||
"WONT answered by DO");
|
||||
break;
|
||||
case RFC1143_WANTNO_OP:
|
||||
q.us = RFC1143_YES;
|
||||
_set_rfc1143(telnet, q);
|
||||
_error(telnet, __LINE__, __func__, LIBTELNET_EPROTOCOL, 0,
|
||||
_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
|
||||
"WONT answered by DO");
|
||||
break;
|
||||
case RFC1143_WANTYES:
|
||||
|
@ -338,31 +338,31 @@ static void _negotiate(libtelnet_t *telnet, unsigned char cmd,
|
|||
case RFC1143_WANTYES_OP:
|
||||
q.us = RFC1143_WANTNO;
|
||||
_set_rfc1143(telnet, q);
|
||||
libtelnet_send_telopt(telnet, LIBTELNET_WONT, telopt);
|
||||
telnet_send_telopt(telnet, TELNET_WONT, telopt);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
/* request to disable option on local end, confirm WONT, reject WILL */
|
||||
case LIBTELNET_DONT:
|
||||
case TELNET_DONT:
|
||||
switch (q.us) {
|
||||
case RFC1143_NO:
|
||||
break;
|
||||
case RFC1143_YES:
|
||||
q.us = RFC1143_NO;
|
||||
_set_rfc1143(telnet, q);
|
||||
libtelnet_send_telopt(telnet, LIBTELNET_WONT, telopt);
|
||||
_event(telnet, LIBTELNET_EV_DONT, 0, telopt, 0, 0);
|
||||
telnet_send_telopt(telnet, TELNET_WONT, telopt);
|
||||
_event(telnet, TELNET_EV_DONT, 0, telopt, 0, 0);
|
||||
break;
|
||||
case RFC1143_WANTNO:
|
||||
q.us = RFC1143_NO;
|
||||
_set_rfc1143(telnet, q);
|
||||
_event(telnet, LIBTELNET_EV_WONT, 0, telopt, 0, 0);
|
||||
_event(telnet, TELNET_EV_WONT, 0, telopt, 0, 0);
|
||||
break;
|
||||
case RFC1143_WANTNO_OP:
|
||||
q.us = RFC1143_WANTYES;
|
||||
_set_rfc1143(telnet, q);
|
||||
_event(telnet, LIBTELNET_EV_WILL, 0, telopt, 0, 0);
|
||||
_event(telnet, TELNET_EV_WILL, 0, telopt, 0, 0);
|
||||
break;
|
||||
case RFC1143_WANTYES:
|
||||
case RFC1143_WANTYES_OP:
|
||||
|
@ -375,16 +375,16 @@ static void _negotiate(libtelnet_t *telnet, unsigned char cmd,
|
|||
}
|
||||
|
||||
/* initialize a telnet state tracker */
|
||||
void libtelnet_init(libtelnet_t *telnet, libtelnet_event_handler_t eh,
|
||||
void telnet_init(telnet_t *telnet, telnet_event_handler_t eh,
|
||||
unsigned char flags, void *user_data) {
|
||||
memset(telnet, 0, sizeof(libtelnet_t));
|
||||
memset(telnet, 0, sizeof(telnet_t));
|
||||
telnet->ud = user_data;
|
||||
telnet->eh = eh;
|
||||
telnet->flags = flags;
|
||||
}
|
||||
|
||||
/* free up any memory allocated by a state tracker */
|
||||
void libtelnet_free(libtelnet_t *telnet) {
|
||||
void telnet_free(telnet_t *telnet) {
|
||||
/* free sub-request buffer */
|
||||
if (telnet->buffer != 0) {
|
||||
free(telnet->buffer);
|
||||
|
@ -396,7 +396,7 @@ void libtelnet_free(libtelnet_t *telnet) {
|
|||
#ifdef HAVE_ZLIB
|
||||
/* free zlib box */
|
||||
if (telnet->z != 0) {
|
||||
if (telnet->flags & LIBTELNET_PFLAG_DEFLATE)
|
||||
if (telnet->flags & TELNET_PFLAG_DEFLATE)
|
||||
deflateEnd(telnet->z);
|
||||
else
|
||||
inflateEnd(telnet->z);
|
||||
|
@ -414,7 +414,7 @@ void libtelnet_free(libtelnet_t *telnet) {
|
|||
}
|
||||
|
||||
/* push a byte into the telnet buffer */
|
||||
static libtelnet_error_t _buffer_byte(libtelnet_t *telnet,
|
||||
static telnet_error_t _buffer_byte(telnet_t *telnet,
|
||||
unsigned char byte) {
|
||||
char *new_buffer;
|
||||
size_t i;
|
||||
|
@ -429,20 +429,20 @@ static libtelnet_error_t _buffer_byte(libtelnet_t *telnet,
|
|||
|
||||
/* overflow -- can't grow any more */
|
||||
if (i >= _buffer_sizes_count - 1) {
|
||||
_error(telnet, __LINE__, __func__, LIBTELNET_EOVERFLOW, 0,
|
||||
_error(telnet, __LINE__, __func__, TELNET_EOVERFLOW, 0,
|
||||
"subnegotiation buffer size limit reached");
|
||||
libtelnet_free(telnet);
|
||||
return LIBTELNET_EOVERFLOW;
|
||||
telnet_free(telnet);
|
||||
return TELNET_EOVERFLOW;
|
||||
}
|
||||
|
||||
/* (re)allocate buffer */
|
||||
new_buffer = (char *)realloc(telnet->buffer,
|
||||
_buffer_sizes[i + 1]);
|
||||
if (new_buffer == 0) {
|
||||
_error(telnet, __LINE__, __func__, LIBTELNET_ENOMEM, 0,
|
||||
_error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
|
||||
"realloc() failed");
|
||||
libtelnet_free(telnet);
|
||||
return LIBTELNET_ENOMEM;
|
||||
telnet_free(telnet);
|
||||
return TELNET_ENOMEM;
|
||||
}
|
||||
|
||||
telnet->buffer = new_buffer;
|
||||
|
@ -451,10 +451,10 @@ static libtelnet_error_t _buffer_byte(libtelnet_t *telnet,
|
|||
|
||||
/* push the byte, all set */
|
||||
telnet->buffer[telnet->buffer_pos++] = byte;
|
||||
return LIBTELNET_EOK;
|
||||
return TELNET_EOK;
|
||||
}
|
||||
|
||||
static void _process(libtelnet_t *telnet, const char *buffer,
|
||||
static void _process(telnet_t *telnet, const char *buffer,
|
||||
size_t size) {
|
||||
unsigned char byte;
|
||||
size_t i, start;
|
||||
|
@ -462,146 +462,146 @@ static void _process(libtelnet_t *telnet, const char *buffer,
|
|||
byte = buffer[i];
|
||||
switch (telnet->state) {
|
||||
/* regular data */
|
||||
case LIBTELNET_STATE_DATA:
|
||||
case TELNET_STATE_DATA:
|
||||
/* on an IAC byte, pass through all pending bytes and
|
||||
* switch states */
|
||||
if (byte == LIBTELNET_IAC) {
|
||||
if (byte == TELNET_IAC) {
|
||||
if (i != start)
|
||||
_event(telnet, LIBTELNET_EV_DATA, 0, 0, &buffer[start],
|
||||
_event(telnet, TELNET_EV_DATA, 0, 0, &buffer[start],
|
||||
i - start);
|
||||
telnet->state = LIBTELNET_STATE_IAC;
|
||||
telnet->state = TELNET_STATE_IAC;
|
||||
}
|
||||
break;
|
||||
|
||||
/* IAC command */
|
||||
case LIBTELNET_STATE_IAC:
|
||||
case TELNET_STATE_IAC:
|
||||
switch (byte) {
|
||||
/* subnegotiation */
|
||||
case LIBTELNET_SB:
|
||||
telnet->state = LIBTELNET_STATE_SB;
|
||||
case TELNET_SB:
|
||||
telnet->state = TELNET_STATE_SB;
|
||||
break;
|
||||
/* negotiation commands */
|
||||
case LIBTELNET_WILL:
|
||||
telnet->state = LIBTELNET_STATE_WILL;
|
||||
case TELNET_WILL:
|
||||
telnet->state = TELNET_STATE_WILL;
|
||||
break;
|
||||
case LIBTELNET_WONT:
|
||||
telnet->state = LIBTELNET_STATE_WONT;
|
||||
case TELNET_WONT:
|
||||
telnet->state = TELNET_STATE_WONT;
|
||||
break;
|
||||
case LIBTELNET_DO:
|
||||
telnet->state = LIBTELNET_STATE_DO;
|
||||
case TELNET_DO:
|
||||
telnet->state = TELNET_STATE_DO;
|
||||
break;
|
||||
case LIBTELNET_DONT:
|
||||
telnet->state = LIBTELNET_STATE_DONT;
|
||||
case TELNET_DONT:
|
||||
telnet->state = TELNET_STATE_DONT;
|
||||
break;
|
||||
/* IAC escaping */
|
||||
case LIBTELNET_IAC:
|
||||
_event(telnet, LIBTELNET_EV_DATA, 0, 0, (char*)&byte, 1);
|
||||
case TELNET_IAC:
|
||||
_event(telnet, TELNET_EV_DATA, 0, 0, (char*)&byte, 1);
|
||||
start = i + 1;
|
||||
telnet->state = LIBTELNET_STATE_DATA;
|
||||
telnet->state = TELNET_STATE_DATA;
|
||||
break;
|
||||
/* some other command */
|
||||
default:
|
||||
_event(telnet, LIBTELNET_EV_IAC, byte, 0, 0, 0);
|
||||
_event(telnet, TELNET_EV_IAC, byte, 0, 0, 0);
|
||||
start = i + 1;
|
||||
telnet->state = LIBTELNET_STATE_DATA;
|
||||
telnet->state = TELNET_STATE_DATA;
|
||||
}
|
||||
break;
|
||||
|
||||
/* negotiation commands */
|
||||
case LIBTELNET_STATE_DO:
|
||||
_negotiate(telnet, LIBTELNET_DO, byte);
|
||||
case TELNET_STATE_DO:
|
||||
_negotiate(telnet, TELNET_DO, byte);
|
||||
start = i + 1;
|
||||
telnet->state = LIBTELNET_STATE_DATA;
|
||||
telnet->state = TELNET_STATE_DATA;
|
||||
break;
|
||||
case LIBTELNET_STATE_DONT:
|
||||
_negotiate(telnet, LIBTELNET_DONT, byte);
|
||||
case TELNET_STATE_DONT:
|
||||
_negotiate(telnet, TELNET_DONT, byte);
|
||||
start = i + 1;
|
||||
telnet->state = LIBTELNET_STATE_DATA;
|
||||
telnet->state = TELNET_STATE_DATA;
|
||||
break;
|
||||
case LIBTELNET_STATE_WILL:
|
||||
_negotiate(telnet, LIBTELNET_WILL, byte);
|
||||
case TELNET_STATE_WILL:
|
||||
_negotiate(telnet, TELNET_WILL, byte);
|
||||
start = i + 1;
|
||||
telnet->state = LIBTELNET_STATE_DATA;
|
||||
telnet->state = TELNET_STATE_DATA;
|
||||
break;
|
||||
case LIBTELNET_STATE_WONT:
|
||||
_negotiate(telnet, LIBTELNET_WONT, byte);
|
||||
case TELNET_STATE_WONT:
|
||||
_negotiate(telnet, TELNET_WONT, byte);
|
||||
start = i + 1;
|
||||
telnet->state = LIBTELNET_STATE_DATA;
|
||||
telnet->state = TELNET_STATE_DATA;
|
||||
break;
|
||||
|
||||
/* subnegotiation -- determine subnegotiation telopt */
|
||||
case LIBTELNET_STATE_SB:
|
||||
case TELNET_STATE_SB:
|
||||
telnet->sb_telopt = byte;
|
||||
telnet->buffer_pos = 0;
|
||||
telnet->state = LIBTELNET_STATE_SB_DATA;
|
||||
telnet->state = TELNET_STATE_SB_DATA;
|
||||
break;
|
||||
|
||||
/* subnegotiation -- buffer bytes until end request */
|
||||
case LIBTELNET_STATE_SB_DATA:
|
||||
case TELNET_STATE_SB_DATA:
|
||||
/* IAC command in subnegotiation -- either IAC SE or IAC IAC */
|
||||
if (byte == LIBTELNET_IAC) {
|
||||
telnet->state = LIBTELNET_STATE_SB_DATA_IAC;
|
||||
if (byte == TELNET_IAC) {
|
||||
telnet->state = TELNET_STATE_SB_DATA_IAC;
|
||||
/* buffer the byte, or bail if we can't */
|
||||
} else if (_buffer_byte(telnet, byte) != LIBTELNET_EOK) {
|
||||
} else if (_buffer_byte(telnet, byte) != TELNET_EOK) {
|
||||
start = i + 1;
|
||||
telnet->state = LIBTELNET_STATE_DATA;
|
||||
telnet->state = TELNET_STATE_DATA;
|
||||
}
|
||||
break;
|
||||
|
||||
/* IAC escaping inside a subnegotiation */
|
||||
case LIBTELNET_STATE_SB_DATA_IAC:
|
||||
case TELNET_STATE_SB_DATA_IAC:
|
||||
switch (byte) {
|
||||
/* end subnegotiation */
|
||||
case LIBTELNET_SE:
|
||||
case TELNET_SE:
|
||||
/* return to default state */
|
||||
start = i + 1;
|
||||
telnet->state = LIBTELNET_STATE_DATA;
|
||||
telnet->state = TELNET_STATE_DATA;
|
||||
|
||||
/* invoke callback */
|
||||
_event(telnet, LIBTELNET_EV_SUBNEGOTIATION, 0,
|
||||
_event(telnet, TELNET_EV_SUBNEGOTIATION, 0,
|
||||
telnet->sb_telopt, telnet->buffer, telnet->buffer_pos);
|
||||
|
||||
#ifdef HAVE_ZLIB
|
||||
/* received COMPRESS2 begin marker, setup our zlib box and
|
||||
* start handling the compressed stream if it's not already.
|
||||
*/
|
||||
if (telnet->sb_telopt == LIBTELNET_TELOPT_COMPRESS2) {
|
||||
if (_init_zlib(telnet, 0, 1) != LIBTELNET_EOK)
|
||||
if (telnet->sb_telopt == TELNET_TELOPT_COMPRESS2) {
|
||||
if (_init_zlib(telnet, 0, 1) != TELNET_EOK)
|
||||
break;
|
||||
|
||||
/* notify app that compression was enabled */
|
||||
_event(telnet, LIBTELNET_EV_COMPRESS, 1, 0, 0, 0);
|
||||
_event(telnet, TELNET_EV_COMPRESS, 1, 0, 0, 0);
|
||||
|
||||
/* any remaining bytes in the buffer are compressed.
|
||||
* we have to re-invoke libtelnet_push to get those
|
||||
* we have to re-invoke telnet_push to get those
|
||||
* bytes inflated and abort trying to process the
|
||||
* remaining compressed bytes in the current _process
|
||||
* buffer argument
|
||||
*/
|
||||
libtelnet_push(telnet, &buffer[start], size - start);
|
||||
telnet_push(telnet, &buffer[start], size - start);
|
||||
return;
|
||||
}
|
||||
#endif /* HAVE_ZLIB */
|
||||
|
||||
break;
|
||||
/* escaped IAC byte */
|
||||
case LIBTELNET_IAC:
|
||||
case TELNET_IAC:
|
||||
/* push IAC into buffer */
|
||||
if (_buffer_byte(telnet, LIBTELNET_IAC) !=
|
||||
LIBTELNET_EOK) {
|
||||
if (_buffer_byte(telnet, TELNET_IAC) !=
|
||||
TELNET_EOK) {
|
||||
start = i + 1;
|
||||
telnet->state = LIBTELNET_STATE_DATA;
|
||||
telnet->state = TELNET_STATE_DATA;
|
||||
} else {
|
||||
telnet->state = LIBTELNET_STATE_SB_DATA;
|
||||
telnet->state = TELNET_STATE_SB_DATA;
|
||||
}
|
||||
break;
|
||||
/* something else -- protocol error */
|
||||
default:
|
||||
_error(telnet, __LINE__, __func__, LIBTELNET_EPROTOCOL, 0,
|
||||
_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
|
||||
"unexpected byte after IAC inside SB: %d",
|
||||
byte);
|
||||
start = i + 1;
|
||||
telnet->state = LIBTELNET_STATE_DATA;
|
||||
telnet->state = TELNET_STATE_DATA;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -609,16 +609,16 @@ static void _process(libtelnet_t *telnet, const char *buffer,
|
|||
}
|
||||
|
||||
/* pass through any remaining bytes */
|
||||
if (telnet->state == LIBTELNET_STATE_DATA && i != start)
|
||||
_event(telnet, LIBTELNET_EV_DATA, 0, 0, buffer + start, i - start);
|
||||
if (telnet->state == TELNET_STATE_DATA && i != start)
|
||||
_event(telnet, TELNET_EV_DATA, 0, 0, buffer + start, i - start);
|
||||
}
|
||||
|
||||
/* push a bytes into the state tracker */
|
||||
void libtelnet_push(libtelnet_t *telnet, const char *buffer,
|
||||
void telnet_push(telnet_t *telnet, const char *buffer,
|
||||
size_t size) {
|
||||
#ifdef HAVE_ZLIB
|
||||
/* if we have an inflate (decompression) zlib stream, use it */
|
||||
if (telnet->z != 0 && !(telnet->flags & LIBTELNET_PFLAG_DEFLATE)) {
|
||||
if (telnet->z != 0 && !(telnet->flags & TELNET_PFLAG_DEFLATE)) {
|
||||
char inflate_buffer[4096];
|
||||
int rs;
|
||||
|
||||
|
@ -640,7 +640,7 @@ void libtelnet_push(libtelnet_t *telnet, const char *buffer,
|
|||
_process(telnet, inflate_buffer, sizeof(inflate_buffer) -
|
||||
telnet->z->avail_out);
|
||||
else
|
||||
_error(telnet, __LINE__, __func__, LIBTELNET_ECOMPRESS, 1,
|
||||
_error(telnet, __LINE__, __func__, TELNET_ECOMPRESS, 1,
|
||||
"inflate() failed: %s", zError(rs));
|
||||
|
||||
/* prepare output buffer for next run */
|
||||
|
@ -649,7 +649,7 @@ void libtelnet_push(libtelnet_t *telnet, const char *buffer,
|
|||
|
||||
/* on error (or on end of stream) disable further inflation */
|
||||
if (rs != Z_OK) {
|
||||
_event(telnet, LIBTELNET_EV_COMPRESS, 0, 0, 0, 0);
|
||||
_event(telnet, TELNET_EV_COMPRESS, 0, 0, 0, 0);
|
||||
|
||||
inflateEnd(telnet->z);
|
||||
free(telnet->z);
|
||||
|
@ -665,26 +665,26 @@ void libtelnet_push(libtelnet_t *telnet, const char *buffer,
|
|||
}
|
||||
|
||||
/* send an iac command */
|
||||
void libtelnet_send_command(libtelnet_t *telnet, unsigned char cmd) {
|
||||
char bytes[2] = { LIBTELNET_IAC, cmd };
|
||||
void telnet_send_command(telnet_t *telnet, unsigned char cmd) {
|
||||
char bytes[2] = { TELNET_IAC, cmd };
|
||||
_send(telnet, bytes, 2);
|
||||
}
|
||||
|
||||
/* send an iac command with telopt */
|
||||
void libtelnet_send_telopt(libtelnet_t *telnet, unsigned char cmd,
|
||||
void telnet_send_telopt(telnet_t *telnet, unsigned char cmd,
|
||||
unsigned char telopt) {
|
||||
char bytes[3] = { LIBTELNET_IAC, cmd, telopt };
|
||||
char bytes[3] = { TELNET_IAC, cmd, telopt };
|
||||
_send(telnet, bytes, 3);
|
||||
}
|
||||
|
||||
/* send negotiation */
|
||||
void libtelnet_send_negotiate(libtelnet_t *telnet, unsigned char cmd,
|
||||
void telnet_send_negotiate(telnet_t *telnet, unsigned char cmd,
|
||||
unsigned char telopt) {
|
||||
libtelnet_rfc1143_t q;
|
||||
telnet_rfc1143_t q;
|
||||
|
||||
/* if we're in proxy mode, just send it now */
|
||||
if (telnet->flags & LIBTELNET_FLAG_PROXY) {
|
||||
char bytes[3] = { LIBTELNET_IAC, cmd, telopt };
|
||||
if (telnet->flags & TELNET_FLAG_PROXY) {
|
||||
char bytes[3] = { TELNET_IAC, cmd, telopt };
|
||||
_send(telnet, bytes, 3);
|
||||
return;
|
||||
}
|
||||
|
@ -694,12 +694,12 @@ void libtelnet_send_negotiate(libtelnet_t *telnet, unsigned char cmd,
|
|||
|
||||
switch (cmd) {
|
||||
/* advertise willingess to support an option */
|
||||
case LIBTELNET_WILL:
|
||||
case TELNET_WILL:
|
||||
switch (q.us) {
|
||||
case RFC1143_NO:
|
||||
q.us = RFC1143_WANTYES;
|
||||
_set_rfc1143(telnet, q);
|
||||
_negotiate(telnet, LIBTELNET_WILL, telopt);
|
||||
_negotiate(telnet, TELNET_WILL, telopt);
|
||||
break;
|
||||
case RFC1143_YES:
|
||||
break;
|
||||
|
@ -719,14 +719,14 @@ void libtelnet_send_negotiate(libtelnet_t *telnet, unsigned char cmd,
|
|||
break;
|
||||
|
||||
/* force turn-off of locally enabled option */
|
||||
case LIBTELNET_WONT:
|
||||
case TELNET_WONT:
|
||||
switch (q.us) {
|
||||
case RFC1143_NO:
|
||||
break;
|
||||
case RFC1143_YES:
|
||||
q.us = RFC1143_WANTNO;
|
||||
_set_rfc1143(telnet, q);
|
||||
_negotiate(telnet, LIBTELNET_WONT, telopt);
|
||||
_negotiate(telnet, TELNET_WONT, telopt);
|
||||
break;
|
||||
case RFC1143_WANTNO:
|
||||
break;
|
||||
|
@ -744,12 +744,12 @@ void libtelnet_send_negotiate(libtelnet_t *telnet, unsigned char cmd,
|
|||
break;
|
||||
|
||||
/* ask remote end to enable an option */
|
||||
case LIBTELNET_DO:
|
||||
case TELNET_DO:
|
||||
switch (q.him) {
|
||||
case RFC1143_NO:
|
||||
q.him = RFC1143_WANTYES;
|
||||
_set_rfc1143(telnet, q);
|
||||
_negotiate(telnet, LIBTELNET_DO, telopt);
|
||||
_negotiate(telnet, TELNET_DO, telopt);
|
||||
break;
|
||||
case RFC1143_YES:
|
||||
break;
|
||||
|
@ -769,14 +769,14 @@ void libtelnet_send_negotiate(libtelnet_t *telnet, unsigned char cmd,
|
|||
break;
|
||||
|
||||
/* demand remote end disable an option */
|
||||
case LIBTELNET_DONT:
|
||||
case TELNET_DONT:
|
||||
switch (q.him) {
|
||||
case RFC1143_NO:
|
||||
break;
|
||||
case RFC1143_YES:
|
||||
q.him = RFC1143_WANTNO;
|
||||
_set_rfc1143(telnet, q);
|
||||
_negotiate(telnet, LIBTELNET_DONT, telopt);
|
||||
_negotiate(telnet, TELNET_DONT, telopt);
|
||||
break;
|
||||
case RFC1143_WANTNO:
|
||||
break;
|
||||
|
@ -796,20 +796,20 @@ void libtelnet_send_negotiate(libtelnet_t *telnet, unsigned char cmd,
|
|||
}
|
||||
|
||||
/* send non-command data (escapes IAC bytes) */
|
||||
void libtelnet_send_data(libtelnet_t *telnet, const char *buffer,
|
||||
void telnet_send_data(telnet_t *telnet, const char *buffer,
|
||||
size_t size) {
|
||||
size_t i, l;
|
||||
|
||||
for (l = i = 0; i != size; ++i) {
|
||||
/* dump prior portion of text, send escaped bytes */
|
||||
if (buffer[i] == LIBTELNET_IAC) {
|
||||
if (buffer[i] == TELNET_IAC) {
|
||||
/* dump prior text if any */
|
||||
if (i != l)
|
||||
_send(telnet, buffer + l, i - l);
|
||||
l = i + 1;
|
||||
|
||||
/* send escape */
|
||||
libtelnet_send_command(telnet, LIBTELNET_IAC);
|
||||
telnet_send_command(telnet, TELNET_IAC);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -819,67 +819,50 @@ void libtelnet_send_data(libtelnet_t *telnet, const char *buffer,
|
|||
}
|
||||
|
||||
/* send sub-request */
|
||||
void libtelnet_send_subnegotiation(libtelnet_t *telnet, unsigned char telopt,
|
||||
void telnet_send_subnegotiation(telnet_t *telnet, unsigned char telopt,
|
||||
const char *buffer, size_t size) {
|
||||
libtelnet_send_telopt(telnet, LIBTELNET_SB, telopt);
|
||||
libtelnet_send_data(telnet, buffer, size);
|
||||
libtelnet_send_command(telnet, LIBTELNET_SE);
|
||||
telnet_send_telopt(telnet, TELNET_SB, telopt);
|
||||
telnet_send_data(telnet, buffer, size);
|
||||
telnet_send_command(telnet, TELNET_SE);
|
||||
|
||||
#ifdef HAVE_ZLIB
|
||||
/* if we're a proxy and we just sent the COMPRESS2 marker, we must
|
||||
* make sure all further data is compressed if not already.
|
||||
*/
|
||||
if (telnet->flags & LIBTELNET_FLAG_PROXY &&
|
||||
telopt == LIBTELNET_TELOPT_COMPRESS2) {
|
||||
if (telnet->flags & TELNET_FLAG_PROXY &&
|
||||
telopt == TELNET_TELOPT_COMPRESS2) {
|
||||
|
||||
if (_init_zlib(telnet, 1, 1) != LIBTELNET_EOK)
|
||||
if (_init_zlib(telnet, 1, 1) != TELNET_EOK)
|
||||
return;
|
||||
|
||||
/* notify app that compression was enabled */
|
||||
_event(telnet, LIBTELNET_EV_COMPRESS, 1, 0, 0, 0);
|
||||
_event(telnet, TELNET_EV_COMPRESS, 1, 0, 0, 0);
|
||||
}
|
||||
#endif /* HAVE_ZLIB */
|
||||
}
|
||||
|
||||
void libtelnet_begin_compress2(libtelnet_t *telnet) {
|
||||
void telnet_begin_compress2(telnet_t *telnet) {
|
||||
#ifdef HAVE_ZLIB
|
||||
static const char compress2[] = { LIBTELNET_IAC, LIBTELNET_SB,
|
||||
LIBTELNET_TELOPT_COMPRESS2, LIBTELNET_IAC, LIBTELNET_SE };
|
||||
static const char compress2[] = { TELNET_IAC, TELNET_SB,
|
||||
TELNET_TELOPT_COMPRESS2, TELNET_IAC, TELNET_SE };
|
||||
|
||||
/* attempt to create output stream first, bail if we can't */
|
||||
if (_init_zlib(telnet, 1, 0) != LIBTELNET_EOK)
|
||||
if (_init_zlib(telnet, 1, 0) != TELNET_EOK)
|
||||
return;
|
||||
|
||||
/* send compression marker. we send directly to the event handler
|
||||
* instead of passing through _send because _send would result in
|
||||
* the compress marker itself being compressed.
|
||||
*/
|
||||
_event(telnet, LIBTELNET_EV_SEND, 0, 0, compress2, sizeof(compress2));
|
||||
_event(telnet, TELNET_EV_SEND, 0, 0, compress2, sizeof(compress2));
|
||||
|
||||
/* notify app that compression was successfully enabled */
|
||||
_event(telnet, LIBTELNET_EV_COMPRESS, 1, 0, 0, 0);
|
||||
_event(telnet, TELNET_EV_COMPRESS, 1, 0, 0, 0);
|
||||
#endif /* HAVE_ZLIB */
|
||||
}
|
||||
|
||||
/* send formatted data through libtelnet_send_data */
|
||||
int libtelnet_printf(libtelnet_t *telnet, const char *fmt, ...) {
|
||||
char buffer[4096];
|
||||
va_list va;
|
||||
int rs;
|
||||
|
||||
/* format */
|
||||
va_start(va, fmt);
|
||||
rs = vsnprintf(buffer, sizeof(buffer), fmt, va);
|
||||
va_end(va);
|
||||
|
||||
/* send */
|
||||
libtelnet_send_data(telnet, (char *)buffer, rs);
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
/* send formatted data with \r and \n translation in addition to IAC IAC */
|
||||
int libtelnet_printf2(libtelnet_t *telnet, const char *fmt, ...) {
|
||||
int telnet_printf(telnet_t *telnet, const char *fmt, ...) {
|
||||
static const char CRLF[] = { '\r', '\n' };
|
||||
static const char CRNUL[] = { '\r', '\0' };
|
||||
char buffer[4096];
|
||||
|
@ -894,7 +877,7 @@ int libtelnet_printf2(libtelnet_t *telnet, const char *fmt, ...) {
|
|||
/* send */
|
||||
for (l = i = 0; i != rs; ++i) {
|
||||
/* special characters */
|
||||
if (buffer[i] == LIBTELNET_IAC || buffer[i] == '\r' ||
|
||||
if (buffer[i] == TELNET_IAC || buffer[i] == '\r' ||
|
||||
buffer[i] == '\n') {
|
||||
/* dump prior portion of text */
|
||||
if (i != l)
|
||||
|
@ -902,8 +885,8 @@ int libtelnet_printf2(libtelnet_t *telnet, const char *fmt, ...) {
|
|||
l = i + 1;
|
||||
|
||||
/* IAC -> IAC IAC */
|
||||
if (buffer[i] == LIBTELNET_IAC)
|
||||
libtelnet_send_command(telnet, LIBTELNET_IAC);
|
||||
if (buffer[i] == TELNET_IAC)
|
||||
telnet_send_command(telnet, TELNET_IAC);
|
||||
/* automatic translation of \r -> CRNUL */
|
||||
else if (buffer[i] == '\r')
|
||||
_send(telnet, CRNUL, 2);
|
||||
|
@ -919,3 +902,20 @@ int libtelnet_printf2(libtelnet_t *telnet, const char *fmt, ...) {
|
|||
|
||||
return rs;
|
||||
}
|
||||
|
||||
/* send formatted data through telnet_send_data */
|
||||
int telnet_printf2(telnet_t *telnet, const char *fmt, ...) {
|
||||
char buffer[4096];
|
||||
va_list va;
|
||||
int rs;
|
||||
|
||||
/* format */
|
||||
va_start(va, fmt);
|
||||
rs = vsnprintf(buffer, sizeof(buffer), fmt, va);
|
||||
va_end(va);
|
||||
|
||||
/* send */
|
||||
telnet_send_data(telnet, (char *)buffer, rs);
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
|
259
libtelnet.h
259
libtelnet.h
|
@ -13,132 +13,132 @@
|
|||
#define LIBTELNET_INCLUDE 1
|
||||
|
||||
/* forward declarations */
|
||||
typedef struct libtelnet_t libtelnet_t;
|
||||
typedef struct libtelnet_event_t libtelnet_event_t;
|
||||
typedef struct libtelnet_rfc1143_t libtelnet_rfc1143_t;
|
||||
typedef struct telnet_t telnet_t;
|
||||
typedef struct telnet_event_t telnet_event_t;
|
||||
typedef struct telnet_rfc1143_t telnet_rfc1143_t;
|
||||
|
||||
/* telnet special values */
|
||||
#define LIBTELNET_IAC 255
|
||||
#define LIBTELNET_DONT 254
|
||||
#define LIBTELNET_DO 253
|
||||
#define LIBTELNET_WONT 252
|
||||
#define LIBTELNET_WILL 251
|
||||
#define LIBTELNET_SB 250
|
||||
#define LIBTELNET_SB 250
|
||||
#define LIBTELNET_GA 249
|
||||
#define LIBTELNET_EL 248
|
||||
#define LIBTELNET_EC 247
|
||||
#define LIBTELNET_AYT 246
|
||||
#define LIBTELNET_AO 245
|
||||
#define LIBTELNET_IP 244
|
||||
#define LIBTELNET_BREAK 243
|
||||
#define LIBTELNET_DM 242
|
||||
#define LIBTELNET_NOP 241
|
||||
#define LIBTELNET_SE 240
|
||||
#define LIBTELNET_EOR 239
|
||||
#define LIBTELNET_ABORT 238
|
||||
#define LIBTELNET_SUSP 237
|
||||
#define LIBTELNET_EOF 236
|
||||
#define TELNET_IAC 255
|
||||
#define TELNET_DONT 254
|
||||
#define TELNET_DO 253
|
||||
#define TELNET_WONT 252
|
||||
#define TELNET_WILL 251
|
||||
#define TELNET_SB 250
|
||||
#define TELNET_SB 250
|
||||
#define TELNET_GA 249
|
||||
#define TELNET_EL 248
|
||||
#define TELNET_EC 247
|
||||
#define TELNET_AYT 246
|
||||
#define TELNET_AO 245
|
||||
#define TELNET_IP 244
|
||||
#define TELNET_BREAK 243
|
||||
#define TELNET_DM 242
|
||||
#define TELNET_NOP 241
|
||||
#define TELNET_SE 240
|
||||
#define TELNET_EOR 239
|
||||
#define TELNET_ABORT 238
|
||||
#define TELNET_SUSP 237
|
||||
#define TELNET_EOF 236
|
||||
|
||||
/* telnet options */
|
||||
#define LIBTELNET_TELOPT_BINARY 0
|
||||
#define LIBTELNET_TELOPT_ECHO 1
|
||||
#define LIBTELNET_TELOPT_RCP 2
|
||||
#define LIBTELNET_TELOPT_SGA 3
|
||||
#define LIBTELNET_TELOPT_NAMS 4
|
||||
#define LIBTELNET_TELOPT_STATUS 5
|
||||
#define LIBTELNET_TELOPT_TM 6
|
||||
#define LIBTELNET_TELOPT_RCTE 7
|
||||
#define LIBTELNET_TELOPT_NAOL 8
|
||||
#define LIBTELNET_TELOPT_NAOP 9
|
||||
#define LIBTELNET_TELOPT_NAOCRD 10
|
||||
#define LIBTELNET_TELOPT_NAOHTS 11
|
||||
#define LIBTELNET_TELOPT_NAOHTD 12
|
||||
#define LIBTELNET_TELOPT_NAOFFD 13
|
||||
#define LIBTELNET_TELOPT_NAOVTS 14
|
||||
#define LIBTELNET_TELOPT_NAOVTD 15
|
||||
#define LIBTELNET_TELOPT_NAOLFD 16
|
||||
#define LIBTELNET_TELOPT_XASCII 17
|
||||
#define LIBTELNET_TELOPT_LOGOUT 18
|
||||
#define LIBTELNET_TELOPT_BM 19
|
||||
#define LIBTELNET_TELOPT_DET 20
|
||||
#define LIBTELNET_TELOPT_SUPDUP 21
|
||||
#define LIBTELNET_TELOPT_SUPDUPOUTPUT 22
|
||||
#define LIBTELNET_TELOPT_SNDLOC 23
|
||||
#define LIBTELNET_TELOPT_TTYPE 24
|
||||
#define LIBTELNET_TELOPT_EOR 25
|
||||
#define LIBTELNET_TELOPT_TUID 26
|
||||
#define LIBTELNET_TELOPT_OUTMRK 27
|
||||
#define LIBTELNET_TELOPT_TTYLOC 28
|
||||
#define LIBTELNET_TELOPT_3270REGIME 29
|
||||
#define LIBTELNET_TELOPT_X3PAD 30
|
||||
#define LIBTELNET_TELOPT_NAWS 31
|
||||
#define LIBTELNET_TELOPT_TSPEED 32
|
||||
#define LIBTELNET_TELOPT_LFLOW 33
|
||||
#define LIBTELNET_TELOPT_LINEMODE 34
|
||||
#define LIBTELNET_TELOPT_XDISPLOC 35
|
||||
#define LIBTELNET_TELOPT_ENVIRON 36
|
||||
#define LIBTELNET_TELOPT_AUTHENTICATION 37
|
||||
#define LIBTELNET_TELOPT_ENCRYPT 38
|
||||
#define LIBTELNET_TELOPT_NEW_ENVIRON 39
|
||||
#define LIBTELNET_TELOPT_COMPRESS 85
|
||||
#define LIBTELNET_TELOPT_COMPRESS2 86
|
||||
#define LIBTELNET_TELOPT_ZMP 93
|
||||
#define LIBTELNET_TELOPT_EXOPL 255
|
||||
#define TELNET_TELOPT_BINARY 0
|
||||
#define TELNET_TELOPT_ECHO 1
|
||||
#define TELNET_TELOPT_RCP 2
|
||||
#define TELNET_TELOPT_SGA 3
|
||||
#define TELNET_TELOPT_NAMS 4
|
||||
#define TELNET_TELOPT_STATUS 5
|
||||
#define TELNET_TELOPT_TM 6
|
||||
#define TELNET_TELOPT_RCTE 7
|
||||
#define TELNET_TELOPT_NAOL 8
|
||||
#define TELNET_TELOPT_NAOP 9
|
||||
#define TELNET_TELOPT_NAOCRD 10
|
||||
#define TELNET_TELOPT_NAOHTS 11
|
||||
#define TELNET_TELOPT_NAOHTD 12
|
||||
#define TELNET_TELOPT_NAOFFD 13
|
||||
#define TELNET_TELOPT_NAOVTS 14
|
||||
#define TELNET_TELOPT_NAOVTD 15
|
||||
#define TELNET_TELOPT_NAOLFD 16
|
||||
#define TELNET_TELOPT_XASCII 17
|
||||
#define TELNET_TELOPT_LOGOUT 18
|
||||
#define TELNET_TELOPT_BM 19
|
||||
#define TELNET_TELOPT_DET 20
|
||||
#define TELNET_TELOPT_SUPDUP 21
|
||||
#define TELNET_TELOPT_SUPDUPOUTPUT 22
|
||||
#define TELNET_TELOPT_SNDLOC 23
|
||||
#define TELNET_TELOPT_TTYPE 24
|
||||
#define TELNET_TELOPT_EOR 25
|
||||
#define TELNET_TELOPT_TUID 26
|
||||
#define TELNET_TELOPT_OUTMRK 27
|
||||
#define TELNET_TELOPT_TTYLOC 28
|
||||
#define TELNET_TELOPT_3270REGIME 29
|
||||
#define TELNET_TELOPT_X3PAD 30
|
||||
#define TELNET_TELOPT_NAWS 31
|
||||
#define TELNET_TELOPT_TSPEED 32
|
||||
#define TELNET_TELOPT_LFLOW 33
|
||||
#define TELNET_TELOPT_LINEMODE 34
|
||||
#define TELNET_TELOPT_XDISPLOC 35
|
||||
#define TELNET_TELOPT_ENVIRON 36
|
||||
#define TELNET_TELOPT_AUTHENTICATION 37
|
||||
#define TELNET_TELOPT_ENCRYPT 38
|
||||
#define TELNET_TELOPT_NEW_ENVIRON 39
|
||||
#define TELNET_TELOPT_COMPRESS 85
|
||||
#define TELNET_TELOPT_COMPRESS2 86
|
||||
#define TELNET_TELOPT_ZMP 93
|
||||
#define TELNET_TELOPT_EXOPL 255
|
||||
|
||||
/* libtelnet feature flags */
|
||||
#define LIBTELNET_FLAG_PROXY (1<<0)
|
||||
#define TELNET_FLAG_PROXY (1<<0)
|
||||
|
||||
#define LIBTELNET_PFLAG_DEFLATE (1<<7)
|
||||
#define TELNET_PFLAG_DEFLATE (1<<7)
|
||||
|
||||
/* telnet states */
|
||||
enum libtelnet_state_t {
|
||||
LIBTELNET_STATE_DATA = 0,
|
||||
LIBTELNET_STATE_IAC,
|
||||
LIBTELNET_STATE_DO,
|
||||
LIBTELNET_STATE_DONT,
|
||||
LIBTELNET_STATE_WILL,
|
||||
LIBTELNET_STATE_WONT,
|
||||
LIBTELNET_STATE_SB,
|
||||
LIBTELNET_STATE_SB_DATA,
|
||||
LIBTELNET_STATE_SB_DATA_IAC
|
||||
enum telnet_state_t {
|
||||
TELNET_STATE_DATA = 0,
|
||||
TELNET_STATE_IAC,
|
||||
TELNET_STATE_DO,
|
||||
TELNET_STATE_DONT,
|
||||
TELNET_STATE_WILL,
|
||||
TELNET_STATE_WONT,
|
||||
TELNET_STATE_SB,
|
||||
TELNET_STATE_SB_DATA,
|
||||
TELNET_STATE_SB_DATA_IAC
|
||||
};
|
||||
typedef enum libtelnet_state_t libtelnet_state_t;
|
||||
typedef enum telnet_state_t telnet_state_t;
|
||||
|
||||
/* error codes */
|
||||
enum libtelnet_error_t {
|
||||
LIBTELNET_EOK = 0,
|
||||
LIBTELNET_EBADVAL, /* invalid parameter, or API misuse */
|
||||
LIBTELNET_ENOMEM, /* memory allocation failure */
|
||||
LIBTELNET_EOVERFLOW, /* data exceeds buffer size */
|
||||
LIBTELNET_EPROTOCOL, /* invalid sequence of special bytes */
|
||||
LIBTELNET_ECOMPRESS /* error handling compressed streams */
|
||||
enum telnet_error_t {
|
||||
TELNET_EOK = 0,
|
||||
TELNET_EBADVAL, /* invalid parameter, or API misuse */
|
||||
TELNET_ENOMEM, /* memory allocation failure */
|
||||
TELNET_EOVERFLOW, /* data exceeds buffer size */
|
||||
TELNET_EPROTOCOL, /* invalid sequence of special bytes */
|
||||
TELNET_ECOMPRESS /* error handling compressed streams */
|
||||
};
|
||||
typedef enum libtelnet_error_t libtelnet_error_t;
|
||||
typedef enum telnet_error_t telnet_error_t;
|
||||
|
||||
/* event codes */
|
||||
enum libtelnet_event_type_t {
|
||||
LIBTELNET_EV_DATA = 0,
|
||||
LIBTELNET_EV_SEND,
|
||||
LIBTELNET_EV_IAC,
|
||||
LIBTELNET_EV_WILL,
|
||||
LIBTELNET_EV_WONT,
|
||||
LIBTELNET_EV_DO,
|
||||
LIBTELNET_EV_DONT,
|
||||
LIBTELNET_EV_SUBNEGOTIATION,
|
||||
LIBTELNET_EV_COMPRESS,
|
||||
LIBTELNET_EV_WARNING,
|
||||
LIBTELNET_EV_ERROR
|
||||
enum telnet_event_type_t {
|
||||
TELNET_EV_DATA = 0,
|
||||
TELNET_EV_SEND,
|
||||
TELNET_EV_IAC,
|
||||
TELNET_EV_WILL,
|
||||
TELNET_EV_WONT,
|
||||
TELNET_EV_DO,
|
||||
TELNET_EV_DONT,
|
||||
TELNET_EV_SUBNEGOTIATION,
|
||||
TELNET_EV_COMPRESS,
|
||||
TELNET_EV_WARNING,
|
||||
TELNET_EV_ERROR
|
||||
};
|
||||
typedef enum libtelnet_event_type_t libtelnet_event_type_t;
|
||||
typedef enum telnet_event_type_t telnet_event_type_t;
|
||||
|
||||
/* event information */
|
||||
struct libtelnet_event_t {
|
||||
struct telnet_event_t {
|
||||
/* data buffer: for DATA, SEND, SUBNEGOTIATION, and ERROR events */
|
||||
const char *buffer;
|
||||
size_t size;
|
||||
/* type of event */
|
||||
enum libtelnet_event_type_t type;
|
||||
enum telnet_event_type_t type;
|
||||
/* IAC command */
|
||||
unsigned char command;
|
||||
/* telopt info: for negotiation events SUBNEGOTIATION */
|
||||
|
@ -148,27 +148,27 @@ struct libtelnet_event_t {
|
|||
};
|
||||
|
||||
/* option negotiation state (RFC 1143) */
|
||||
struct libtelnet_rfc1143_t {
|
||||
struct telnet_rfc1143_t {
|
||||
unsigned char telopt;
|
||||
char us:4, him:4;
|
||||
};
|
||||
|
||||
/* event handler declaration */
|
||||
typedef void (*libtelnet_event_handler_t)(libtelnet_t *telnet,
|
||||
libtelnet_event_t *event, void *user_data);
|
||||
typedef void (*telnet_event_handler_t)(telnet_t *telnet,
|
||||
telnet_event_t *event, void *user_data);
|
||||
|
||||
/* state tracker */
|
||||
struct libtelnet_t {
|
||||
struct telnet_t {
|
||||
/* user data */
|
||||
void *ud;
|
||||
/* event handler */
|
||||
libtelnet_event_handler_t eh;
|
||||
telnet_event_handler_t eh;
|
||||
#ifdef HAVE_ZLIB
|
||||
/* zlib (mccp2) compression */
|
||||
z_stream *z;
|
||||
#endif
|
||||
/* RFC1143 option negotiation states */
|
||||
struct libtelnet_rfc1143_t *q;
|
||||
struct telnet_rfc1143_t *q;
|
||||
/* sub-request buffer */
|
||||
char *buffer;
|
||||
/* current size of the buffer */
|
||||
|
@ -176,7 +176,7 @@ struct libtelnet_t {
|
|||
/* current buffer write position (also length of buffer data) */
|
||||
size_t buffer_pos;
|
||||
/* current state */
|
||||
enum libtelnet_state_t state;
|
||||
enum telnet_state_t state;
|
||||
/* option flags */
|
||||
unsigned char flags;
|
||||
/* current subnegotiation telopt */
|
||||
|
@ -186,57 +186,58 @@ struct libtelnet_t {
|
|||
};
|
||||
|
||||
/* initialize a telnet state tracker */
|
||||
extern void libtelnet_init(libtelnet_t *telnet, libtelnet_event_handler_t eh,
|
||||
extern void telnet_init(telnet_t *telnet, telnet_event_handler_t eh,
|
||||
unsigned char flags, void *user_data);
|
||||
|
||||
/* free up any memory allocated by a state tracker */
|
||||
extern void libtelnet_free(libtelnet_t *telnet);
|
||||
extern void telnet_free(telnet_t *telnet);
|
||||
|
||||
/* push a byte buffer into the state tracker */
|
||||
extern void libtelnet_push(libtelnet_t *telnet, const char *buffer,
|
||||
extern void telnet_push(telnet_t *telnet, const char *buffer,
|
||||
size_t size);
|
||||
|
||||
/* send an iac command */
|
||||
extern void libtelnet_send_command(libtelnet_t *telnet, unsigned char cmd);
|
||||
extern void telnet_send_command(telnet_t *telnet, unsigned char cmd);
|
||||
|
||||
/* send an iac command with a telopt */
|
||||
extern void libtelnet_send_telopt(libtelnet_t *telnet, unsigned char cmd,
|
||||
extern void telnet_send_telopt(telnet_t *telnet, unsigned char cmd,
|
||||
unsigned char telopt);
|
||||
|
||||
/* send negotiation, with RFC1143 checking.
|
||||
* will not actually send unless necessary, but will update internal
|
||||
* negotiation queue.
|
||||
*/
|
||||
extern void libtelnet_send_negotiate(libtelnet_t *telnet, unsigned char cmd,
|
||||
extern void telnet_send_negotiate(telnet_t *telnet, unsigned char cmd,
|
||||
unsigned char opt);
|
||||
|
||||
/* send non-command data (escapes IAC bytes) */
|
||||
extern void libtelnet_send_data(libtelnet_t *telnet,
|
||||
extern void telnet_send_data(telnet_t *telnet,
|
||||
const char *buffer, size_t size);
|
||||
|
||||
/* send sub-request, equivalent to:
|
||||
* libtelnet_send_telopt(telnet, LIBTELNET_SB, telopt)
|
||||
* libtelnet_send_data(telnet, buffer, size);
|
||||
* libtelnet_send_command(telnet, LIBTELNET_SE);
|
||||
* telnet_send_telopt(telnet, TELNET_SB, telopt)
|
||||
* telnet_send_data(telnet, buffer, size);
|
||||
* telnet_send_command(telnet, TELNET_SE);
|
||||
* manually generating sequence may be easier for complex subnegotiations
|
||||
* thare are most easily implemented with a series of send_data calls.
|
||||
*/
|
||||
extern void libtelnet_send_subnegotiation(libtelnet_t *telnet,
|
||||
extern void telnet_send_subnegotiation(telnet_t *telnet,
|
||||
unsigned char telopt, const char *buffer, size_t size);
|
||||
|
||||
/* begin sending compressed data (server only) */
|
||||
extern void libtelnet_begin_compress2(libtelnet_t *telnet);
|
||||
extern void telnet_begin_compress2(telnet_t *telnet);
|
||||
|
||||
/* send formatted data (through libtelnet_send_data) */
|
||||
/* printf type checking feature in GCC and some other compilers */
|
||||
#ifdef __GNUC__
|
||||
# define LIBTELNET_GNU_PRINTF(f,a) __attribute__((printf(f, a)))
|
||||
# define TELNET_GNU_PRINTF(f,a) __attribute__((printf(f, a)))
|
||||
#else
|
||||
# define LIBTELNET_GNU_PRINTF(f,a)
|
||||
# define TELNET_GNU_PRINTF(f,a)
|
||||
#endif
|
||||
|
||||
extern int libtelnet_printf(libtelnet_t *telnet, const char *fmt, ...);
|
||||
/* send formatted data with \r and \n translated, and IAC escaped */
|
||||
extern int telnet_printf(telnet_t *telnet, const char *fmt, ...);
|
||||
|
||||
/* send formatted data with \r and \n translated */
|
||||
extern int libtelnet_printf2(libtelnet_t *telnet, const char *fmt, ...);
|
||||
/* send formatted data with just IAC escaped */
|
||||
extern int telnet_printf2(telnet_t *telnet, const char *fmt, ...);
|
||||
|
||||
#endif /* !defined(LIBTELNET_INCLUDE) */
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
#include "libtelnet.h"
|
||||
|
||||
static struct termios orig_tios;
|
||||
static libtelnet_t telnet;
|
||||
static telnet_t telnet;
|
||||
static int do_echo;
|
||||
|
||||
static void _cleanup(void) {
|
||||
|
@ -48,11 +48,11 @@ static void _input(char *buffer, int size) {
|
|||
if (buffer[i] == '\r' || buffer[i] == '\n') {
|
||||
if (do_echo)
|
||||
write(STDOUT_FILENO, crlf, 2);
|
||||
libtelnet_send_data(&telnet, crlf, 2);
|
||||
telnet_send_data(&telnet, crlf, 2);
|
||||
} else {
|
||||
if (do_echo)
|
||||
write(STDOUT_FILENO, buffer + i, 1);
|
||||
libtelnet_send_data(&telnet, buffer + i, 1);
|
||||
telnet_send_data(&telnet, buffer + i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -76,49 +76,49 @@ static void _send(int sock, const char *buffer, size_t size) {
|
|||
}
|
||||
}
|
||||
|
||||
static void _event_handler(libtelnet_t *telnet, libtelnet_event_t *ev,
|
||||
static void _event_handler(telnet_t *telnet, telnet_event_t *ev,
|
||||
void *user_data) {
|
||||
int sock = *(int*)user_data;
|
||||
|
||||
switch (ev->type) {
|
||||
/* data received */
|
||||
case LIBTELNET_EV_DATA:
|
||||
case TELNET_EV_DATA:
|
||||
write(STDOUT_FILENO, ev->buffer, ev->size);
|
||||
break;
|
||||
/* data must be sent */
|
||||
case LIBTELNET_EV_SEND:
|
||||
case TELNET_EV_SEND:
|
||||
_send(sock, ev->buffer, ev->size);
|
||||
break;
|
||||
/* request to enable remote feature (or receipt) */
|
||||
case LIBTELNET_EV_WILL:
|
||||
case TELNET_EV_WILL:
|
||||
/* we accept COMPRESS2 (MCCP) */
|
||||
if (ev->telopt == LIBTELNET_TELOPT_COMPRESS2)
|
||||
if (ev->telopt == TELNET_TELOPT_COMPRESS2)
|
||||
ev->accept = 1;
|
||||
|
||||
/* we'll agree to turn off our echo if server wants us to stop */
|
||||
else if (ev->telopt == LIBTELNET_TELOPT_ECHO) {
|
||||
else if (ev->telopt == TELNET_TELOPT_ECHO) {
|
||||
do_echo = 0;
|
||||
ev->accept = 1;
|
||||
}
|
||||
break;
|
||||
/* notification of disabling remote feature (or receipt) */
|
||||
case LIBTELNET_EV_WONT:
|
||||
if (ev->telopt == LIBTELNET_TELOPT_ECHO)
|
||||
case TELNET_EV_WONT:
|
||||
if (ev->telopt == TELNET_TELOPT_ECHO)
|
||||
do_echo = 1;
|
||||
break;
|
||||
/* request to enable local feature (or receipt) */
|
||||
case LIBTELNET_EV_DO:
|
||||
case TELNET_EV_DO:
|
||||
/* we support the TTYPE option */
|
||||
if (ev->telopt == LIBTELNET_TELOPT_TTYPE)
|
||||
if (ev->telopt == TELNET_TELOPT_TTYPE)
|
||||
ev->accept = 1;
|
||||
break;
|
||||
/* demand to disable local feature (or receipt) */
|
||||
case LIBTELNET_EV_DONT:
|
||||
case TELNET_EV_DONT:
|
||||
break;
|
||||
/* respond to particular subnegotiations */
|
||||
case LIBTELNET_EV_SUBNEGOTIATION:
|
||||
case TELNET_EV_SUBNEGOTIATION:
|
||||
/* respond with our terminal type */
|
||||
if (ev->telopt == LIBTELNET_TELOPT_TTYPE) {
|
||||
if (ev->telopt == TELNET_TELOPT_TTYPE) {
|
||||
/* NOTE: we just assume the server sent a legitimate
|
||||
* sub-negotiation, as there really isn't anything else
|
||||
* it's allowed to send
|
||||
|
@ -126,12 +126,12 @@ static void _event_handler(libtelnet_t *telnet, libtelnet_event_t *ev,
|
|||
char buffer[64];
|
||||
buffer[0] = 0; /* IS code for RFC 1091 */
|
||||
snprintf(buffer + 1, sizeof(buffer) - 1, "%s", getenv("TERM"));
|
||||
libtelnet_send_subnegotiation(telnet, LIBTELNET_TELOPT_TTYPE,
|
||||
telnet_send_subnegotiation(telnet, TELNET_TELOPT_TTYPE,
|
||||
(char *)buffer, 1 + strlen(buffer + 1));
|
||||
}
|
||||
break;
|
||||
/* error */
|
||||
case LIBTELNET_EV_ERROR:
|
||||
case TELNET_EV_ERROR:
|
||||
fprintf(stderr, "ERROR: %s\n", ev->buffer);
|
||||
exit(1);
|
||||
default:
|
||||
|
@ -202,7 +202,7 @@ int main(int argc, char **argv) {
|
|||
do_echo = 1;
|
||||
|
||||
/* initialize telnet box */
|
||||
libtelnet_init(&telnet, _event_handler, 0, &sock);
|
||||
telnet_init(&telnet, _event_handler, 0, &sock);
|
||||
|
||||
/* initialize poll descriptors */
|
||||
memset(pfd, 0, sizeof(pfd));
|
||||
|
@ -229,7 +229,7 @@ int main(int argc, char **argv) {
|
|||
/* read from client */
|
||||
if (pfd[1].revents & POLLIN) {
|
||||
if ((rs = recv(sock, buffer, sizeof(buffer), 0)) > 0) {
|
||||
libtelnet_push(&telnet, buffer, rs);
|
||||
telnet_push(&telnet, buffer, rs);
|
||||
} else if (rs == 0) {
|
||||
break;
|
||||
} else {
|
||||
|
@ -241,7 +241,7 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
|
||||
/* clean up */
|
||||
libtelnet_free(&telnet);
|
||||
telnet_free(&telnet);
|
||||
close(sock);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
struct conn_t {
|
||||
const char *name;
|
||||
int sock;
|
||||
libtelnet_t telnet;
|
||||
telnet_t telnet;
|
||||
struct conn_t *remote;
|
||||
};
|
||||
|
||||
|
@ -165,21 +165,21 @@ static void _send(int sock, const char *buffer, size_t size) {
|
|||
}
|
||||
}
|
||||
|
||||
static void _event_handler(libtelnet_t *telnet, libtelnet_event_t *ev,
|
||||
static void _event_handler(telnet_t *telnet, telnet_event_t *ev,
|
||||
void *user_data) {
|
||||
struct conn_t *conn = (struct conn_t*)user_data;
|
||||
|
||||
switch (ev->type) {
|
||||
/* data received */
|
||||
case LIBTELNET_EV_DATA:
|
||||
case TELNET_EV_DATA:
|
||||
printf("%s DATA: ", conn->name);
|
||||
print_buffer(ev->buffer, ev->size);
|
||||
printf(COLOR_NORMAL "\n");
|
||||
|
||||
libtelnet_send_data(&conn->remote->telnet, ev->buffer, ev->size);
|
||||
telnet_send_data(&conn->remote->telnet, ev->buffer, ev->size);
|
||||
break;
|
||||
/* data must be sent */
|
||||
case LIBTELNET_EV_SEND:
|
||||
case TELNET_EV_SEND:
|
||||
/* DONT SPAM
|
||||
printf("%s SEND: ", conn->name);
|
||||
print_buffer(ev->buffer, ev->size);
|
||||
|
@ -189,41 +189,41 @@ static void _event_handler(libtelnet_t *telnet, libtelnet_event_t *ev,
|
|||
_send(conn->sock, ev->buffer, ev->size);
|
||||
break;
|
||||
/* IAC command */
|
||||
case LIBTELNET_EV_IAC:
|
||||
case TELNET_EV_IAC:
|
||||
printf("%s IAC %s" COLOR_NORMAL "\n", conn->name,
|
||||
get_cmd(ev->command));
|
||||
|
||||
libtelnet_send_command(&conn->remote->telnet, ev->command);
|
||||
telnet_send_command(&conn->remote->telnet, ev->command);
|
||||
break;
|
||||
/* negotiation, WILL */
|
||||
case LIBTELNET_EV_WILL:
|
||||
case TELNET_EV_WILL:
|
||||
printf("%s IAC WILL %d (%s)" COLOR_NORMAL "\n", conn->name,
|
||||
(int)ev->telopt, get_opt(ev->telopt));
|
||||
libtelnet_send_negotiate(&conn->remote->telnet, LIBTELNET_WILL,
|
||||
telnet_send_negotiate(&conn->remote->telnet, TELNET_WILL,
|
||||
ev->telopt);
|
||||
break;
|
||||
/* negotiation, WONT */
|
||||
case LIBTELNET_EV_WONT:
|
||||
case TELNET_EV_WONT:
|
||||
printf("%s IAC WONT %d (%s)" COLOR_NORMAL "\n", conn->name,
|
||||
(int)ev->telopt, get_opt(ev->telopt));
|
||||
libtelnet_send_negotiate(&conn->remote->telnet, LIBTELNET_WONT,
|
||||
telnet_send_negotiate(&conn->remote->telnet, TELNET_WONT,
|
||||
ev->telopt);
|
||||
break;
|
||||
/* negotiation, DO */
|
||||
case LIBTELNET_EV_DO:
|
||||
case TELNET_EV_DO:
|
||||
printf("%s IAC DO %d (%s)" COLOR_NORMAL "\n", conn->name,
|
||||
(int)ev->telopt, get_opt(ev->telopt));
|
||||
libtelnet_send_negotiate(&conn->remote->telnet, LIBTELNET_DO,
|
||||
telnet_send_negotiate(&conn->remote->telnet, TELNET_DO,
|
||||
ev->telopt);
|
||||
break;
|
||||
case LIBTELNET_EV_DONT:
|
||||
case TELNET_EV_DONT:
|
||||
printf("%s IAC DONT %d (%s)" COLOR_NORMAL "\n", conn->name,
|
||||
(int)ev->telopt, get_opt(ev->telopt));
|
||||
libtelnet_send_negotiate(&conn->remote->telnet, LIBTELNET_DONT,
|
||||
telnet_send_negotiate(&conn->remote->telnet, TELNET_DONT,
|
||||
ev->telopt);
|
||||
break;
|
||||
/* subnegotiation */
|
||||
case LIBTELNET_EV_SUBNEGOTIATION:
|
||||
case TELNET_EV_SUBNEGOTIATION:
|
||||
printf("%s SUB %d (%s)", conn->name, (int)ev->telopt,
|
||||
get_opt(ev->telopt));
|
||||
if (ev->size > 0) {
|
||||
|
@ -232,20 +232,20 @@ static void _event_handler(libtelnet_t *telnet, libtelnet_event_t *ev,
|
|||
}
|
||||
printf(COLOR_NORMAL "\n");
|
||||
|
||||
libtelnet_send_subnegotiation(&conn->remote->telnet, ev->telopt,
|
||||
telnet_send_subnegotiation(&conn->remote->telnet, ev->telopt,
|
||||
ev->buffer, ev->size);
|
||||
break;
|
||||
/* compression notification */
|
||||
case LIBTELNET_EV_COMPRESS:
|
||||
case TELNET_EV_COMPRESS:
|
||||
printf("%s COMPRESSION %s" COLOR_NORMAL "\n", conn->name,
|
||||
ev->command ? "ON" : "OFF");
|
||||
break;
|
||||
/* warning */
|
||||
case LIBTELNET_EV_WARNING:
|
||||
case TELNET_EV_WARNING:
|
||||
printf("%s WARNING: %s" COLOR_NORMAL "\n", conn->name, ev->buffer);
|
||||
break;
|
||||
/* error */
|
||||
case LIBTELNET_EV_ERROR:
|
||||
case TELNET_EV_ERROR:
|
||||
printf("%s ERROR: %s" COLOR_NORMAL "\n", conn->name, ev->buffer);
|
||||
exit(1);
|
||||
}
|
||||
|
@ -357,9 +357,9 @@ int main(int argc, char **argv) {
|
|||
client.remote = &server;
|
||||
|
||||
/* initialize telnet boxes */
|
||||
libtelnet_init(&server.telnet, _event_handler, LIBTELNET_FLAG_PROXY,
|
||||
telnet_init(&server.telnet, _event_handler, TELNET_FLAG_PROXY,
|
||||
&server);
|
||||
libtelnet_init(&client.telnet, _event_handler, LIBTELNET_FLAG_PROXY,
|
||||
telnet_init(&client.telnet, _event_handler, TELNET_FLAG_PROXY,
|
||||
&client);
|
||||
|
||||
/* initialize poll descriptors */
|
||||
|
@ -374,7 +374,7 @@ int main(int argc, char **argv) {
|
|||
/* read from server */
|
||||
if (pfd[0].revents & POLLIN) {
|
||||
if ((rs = recv(server.sock, buffer, sizeof(buffer), 0)) > 0) {
|
||||
libtelnet_push(&server.telnet, buffer, rs);
|
||||
telnet_push(&server.telnet, buffer, rs);
|
||||
} else if (rs == 0) {
|
||||
printf("%s DISCONNECTED" COLOR_NORMAL "\n", server.name);
|
||||
break;
|
||||
|
@ -388,7 +388,7 @@ int main(int argc, char **argv) {
|
|||
/* read from client */
|
||||
if (pfd[1].revents & POLLIN) {
|
||||
if ((rs = recv(client.sock, buffer, sizeof(buffer), 0)) > 0) {
|
||||
libtelnet_push(&client.telnet, buffer, rs);
|
||||
telnet_push(&client.telnet, buffer, rs);
|
||||
} else if (rs == 0) {
|
||||
printf("%s DISCONNECTED" COLOR_NORMAL "\n", client.name);
|
||||
break;
|
||||
|
@ -401,8 +401,8 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
|
||||
/* clean up */
|
||||
libtelnet_free(&server.telnet);
|
||||
libtelnet_free(&client.telnet);
|
||||
telnet_free(&server.telnet);
|
||||
telnet_free(&client.telnet);
|
||||
close(server.sock);
|
||||
close(client.sock);
|
||||
|
||||
|
|
Loading…
Reference in New Issue