mirror of https://gerrit.osmocom.org/libtelnet
Merge branch 'master' into rfc1143
Conflicts: libtelnet.c
This commit is contained in:
commit
35b95beeda
42
README
42
README
|
@ -57,9 +57,8 @@ IIa. Initialization
|
|||
its own libtelnet_t structure, which is passed to all libtelnet
|
||||
API calls.
|
||||
|
||||
void libtelnet_init(struct libtelnet_t *telnet,
|
||||
libtelnet_event_handler_t handler, enum libtelnet_mode_t mode,
|
||||
void *user_data);
|
||||
void libtelnet_init(libtelnet_t *telnet, libtelnet_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
|
||||
|
@ -74,22 +73,19 @@ IIa. Initialization
|
|||
information about the connection, including a socket descriptor
|
||||
for implementing LIBTELNET_EV_SEND event handling.
|
||||
|
||||
The mode parameter must be one of LIBTELNET_MODE_SERVER,
|
||||
LIBTELNET_MODE_CLIENT, or LIBTELNET_MODE_PROXY. These slightly
|
||||
alter the behavior of libtelnet in certain instances. If you are
|
||||
implementing a TELNET server, use the SERVER mode. If you are
|
||||
implementing a client, use the CLIENT mode. The PROXY mode
|
||||
enables special behavior for telnet-proxy (or similar
|
||||
applications).
|
||||
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 - operate in proxy mode
|
||||
|
||||
boid libtelnet_free(struct libtelnet_t *telnet);
|
||||
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.
|
||||
|
||||
IIb. Receiving Data
|
||||
|
||||
void libtelnet_push(struct libtelnet_t *telnet,
|
||||
void libtelnet_push(libtelnet_t *telnet,
|
||||
unsigned 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.
|
||||
|
@ -111,24 +107,23 @@ IIc. Sending Data
|
|||
to libtelnet_send_data(). Do NOT send or buffer unprocessed output
|
||||
data directly!
|
||||
|
||||
void libtelnet_send_command(struct libtelnet_t *telnet,
|
||||
unsigned char cmd);
|
||||
void libtelnet_send_command(libtelnet_t *telnet, unsigned char cmd);
|
||||
Sends a single "simple" TELNET command, such as the GO-AHEAD
|
||||
commands (255 249).
|
||||
|
||||
void libtelnet_send_negotiate(struct libtelnet_t *telnet,
|
||||
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 libtelnet_send_data(struct libtelnet_t *telnet,
|
||||
unsigned char *buffer, unsigned int size);
|
||||
void libtelnet_send_data(libtelnet_t *telnet, unsigned 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.
|
||||
|
||||
void libtelnet_send_subnegotiation(struct libtelnet_t *telnet,
|
||||
void libtelnet_send_subnegotiation(libtelnet_t *telnet,
|
||||
unsigned char opt, unsigned char *buffer, unsigned int size);
|
||||
Sends a TELNET sub-negotiation command. The opt parameter
|
||||
is the sub-negotiation option.
|
||||
|
@ -150,11 +145,12 @@ IId. Event Handling
|
|||
pointer passed to libtelnet_init().
|
||||
|
||||
struct libtelnet_event_t {
|
||||
enum libtelnet_event_type_t type;
|
||||
unsigned char command;
|
||||
unsigned char telopt;
|
||||
unsigned char *buffer;
|
||||
unsigned int size;
|
||||
libtelnet_event_type_t type;
|
||||
unsigned char command;
|
||||
unsigned char telopt;
|
||||
unsigned char accept;
|
||||
};
|
||||
|
||||
The enumeration values of libtelnet_event_type_t are described in
|
||||
|
@ -169,8 +165,8 @@ IId. Event Handling
|
|||
Here is an example event handler implementation which includes
|
||||
handlers for several important events.
|
||||
|
||||
void my_event_handler(struct libtelnet_t *telnet,
|
||||
libtelnet_event_t *ev, void *user_data) {
|
||||
void my_event_handler(libtelnet_t *telnet, libtelnet_event_t *ev,
|
||||
void *user_data) {
|
||||
struct user_info *user = (struct user_info *)user_data;
|
||||
|
||||
switch (ev->type) {
|
||||
|
|
206
libtelnet.c
206
libtelnet.c
|
@ -42,15 +42,15 @@ static const unsigned int _buffer_sizes[] = {
|
|||
8192,
|
||||
16384,
|
||||
};
|
||||
static const unsigned int _buffer_sizes_count =
|
||||
sizeof(_buffer_sizes) / sizeof(_buffer_sizes[0]);
|
||||
static const unsigned int _buffer_sizes_count = sizeof(_buffer_sizes) /
|
||||
sizeof(_buffer_sizes[0]);
|
||||
|
||||
/* 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(struct libtelnet_t *telnet,
|
||||
enum libtelnet_event_type_t type, unsigned char command,
|
||||
unsigned char telopt, unsigned char *buffer, unsigned int size) {
|
||||
struct libtelnet_event_t ev;
|
||||
static int _event(libtelnet_t *telnet, libtelnet_event_type_t type,
|
||||
unsigned char command, unsigned char telopt, unsigned char *buffer,
|
||||
unsigned int size) {
|
||||
libtelnet_event_t ev;
|
||||
ev.buffer = buffer;
|
||||
ev.size = size;
|
||||
ev.type = type;
|
||||
|
@ -64,14 +64,14 @@ static int _event(struct libtelnet_t *telnet,
|
|||
}
|
||||
|
||||
/* error generation function */
|
||||
static void _error(struct libtelnet_t *telnet, unsigned line, const char* func,
|
||||
enum libtelnet_error_t err, int fatal, const char *fmt, ...) {
|
||||
static libtelnet_error_t _error(libtelnet_t *telnet, unsigned line,
|
||||
const char* func, libtelnet_error_t err, int fatal, const char *fmt,
|
||||
...) {
|
||||
char buffer[512];
|
||||
va_list va;
|
||||
|
||||
/* format error intro */
|
||||
snprintf(buffer, sizeof(buffer), "%s:%u in %s: ",
|
||||
__FILE__, line, func);
|
||||
snprintf(buffer, sizeof(buffer), "%s:%u in %s: ", __FILE__, line, func);
|
||||
|
||||
va_start(va, fmt);
|
||||
vsnprintf(buffer + strlen(buffer), sizeof(buffer) - strlen(buffer),
|
||||
|
@ -80,42 +80,49 @@ static void _error(struct libtelnet_t *telnet, unsigned line, const char* func,
|
|||
|
||||
_event(telnet, fatal ? LIBTELNET_EV_ERROR : LIBTELNET_EV_WARNING, err,
|
||||
0, (unsigned char *)buffer, strlen(buffer));
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* initialize the zlib box for a telnet box; if deflate is non-zero, it
|
||||
* initializes zlib for delating (compression), otherwise for inflating
|
||||
* (decompression)
|
||||
* (decompression). returns LIBTELNET_EOK on success, something else on
|
||||
* failure.
|
||||
*/
|
||||
z_stream *_init_zlib(struct libtelnet_t *telnet, int deflate, int err_fatal) {
|
||||
z_stream *zlib;
|
||||
libtelnet_error_t _init_zlib(libtelnet_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,
|
||||
err_fatal, "cannot initialize compression twice");
|
||||
|
||||
/* allocate zstream box */
|
||||
if ((zlib = (z_stream *)calloc(1, sizeof(z_stream)))
|
||||
== 0) {
|
||||
_error(telnet, __LINE__, __func__, LIBTELNET_ENOMEM, err_fatal,
|
||||
if ((z= (z_stream *)calloc(1, sizeof(z_stream))) == 0)
|
||||
return _error(telnet, __LINE__, __func__, LIBTELNET_ENOMEM, err_fatal,
|
||||
"malloc() failed: %s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* initialize */
|
||||
if (deflate) {
|
||||
if ((rs = deflateInit(zlib, Z_DEFAULT_COMPRESSION)) != Z_OK) {
|
||||
free(zlib);
|
||||
_error(telnet, __LINE__, __func__, LIBTELNET_ECOMPRESS, err_fatal,
|
||||
"deflateInit() failed: %s", zError(rs));
|
||||
return 0;
|
||||
if ((rs = deflateInit(z, Z_DEFAULT_COMPRESSION)) != Z_OK) {
|
||||
free(z);
|
||||
return _error(telnet, __LINE__, __func__, LIBTELNET_ECOMPRESS,
|
||||
err_fatal, "deflateInit() failed: %s", zError(rs));
|
||||
}
|
||||
telnet->flags |= LIBTELNET_PFLAG_DEFLATE;
|
||||
} else {
|
||||
if ((rs = inflateInit(zlib)) != Z_OK) {
|
||||
free(zlib);
|
||||
_error(telnet, __LINE__, __func__, LIBTELNET_ECOMPRESS, err_fatal,
|
||||
"inflateInit() failed: %s", zError(rs));
|
||||
return 0;
|
||||
if ((rs = inflateInit(z)) != Z_OK) {
|
||||
free(z);
|
||||
return _error(telnet, __LINE__, __func__, LIBTELNET_ECOMPRESS,
|
||||
err_fatal, "inflateInit() failed: %s", zError(rs));
|
||||
}
|
||||
telnet->flags &= ~LIBTELNET_PFLAG_DEFLATE;
|
||||
}
|
||||
|
||||
return zlib;
|
||||
telnet->z = z;
|
||||
|
||||
return LIBTELNET_EOK;
|
||||
}
|
||||
|
||||
/* negotiation handling magic */
|
||||
|
@ -295,16 +302,16 @@ static void _negotiate(struct libtelnet_t *telnet, unsigned char cmd,
|
|||
}
|
||||
|
||||
/* initialize a telnet state tracker */
|
||||
void libtelnet_init(struct libtelnet_t *telnet, libtelnet_event_handler_t eh,
|
||||
enum libtelnet_mode_t mode, void *user_data) {
|
||||
memset(telnet, 0, sizeof(struct libtelnet_t));
|
||||
void libtelnet_init(libtelnet_t *telnet, libtelnet_event_handler_t eh,
|
||||
unsigned char flags, void *user_data) {
|
||||
memset(telnet, 0, sizeof(libtelnet_t));
|
||||
telnet->ud = user_data;
|
||||
telnet->eh = eh;
|
||||
telnet->mode = mode;
|
||||
telnet->flags = flags;
|
||||
}
|
||||
|
||||
/* free up any memory allocated by a state tracker */
|
||||
void libtelnet_free(struct libtelnet_t *telnet) {
|
||||
void libtelnet_free(libtelnet_t *telnet) {
|
||||
/* free sub-request buffer */
|
||||
if (telnet->buffer != 0) {
|
||||
free(telnet->buffer);
|
||||
|
@ -313,16 +320,14 @@ void libtelnet_free(struct libtelnet_t *telnet) {
|
|||
telnet->buffer_pos = 0;
|
||||
}
|
||||
|
||||
/* free zlib box(es) */
|
||||
if (telnet->z_inflate != 0) {
|
||||
inflateEnd(telnet->z_inflate);
|
||||
free(telnet->z_inflate);
|
||||
telnet->z_inflate = 0;
|
||||
}
|
||||
if (telnet->z_deflate != 0) {
|
||||
deflateEnd(telnet->z_deflate);
|
||||
free(telnet->z_deflate);
|
||||
telnet->z_deflate = 0;
|
||||
/* free zlib box */
|
||||
if (telnet->z != 0) {
|
||||
if (telnet->flags & LIBTELNET_PFLAG_DEFLATE)
|
||||
deflateEnd(telnet->z);
|
||||
else
|
||||
inflateEnd(telnet->z);
|
||||
free(telnet->z);
|
||||
telnet->z = 0;
|
||||
}
|
||||
|
||||
/* free RFC1143 queue */
|
||||
|
@ -334,7 +339,7 @@ void libtelnet_free(struct libtelnet_t *telnet) {
|
|||
}
|
||||
|
||||
/* push a byte into the telnet buffer */
|
||||
static enum libtelnet_error_t _buffer_byte(struct libtelnet_t *telnet,
|
||||
static libtelnet_error_t _buffer_byte(libtelnet_t *telnet,
|
||||
unsigned char byte) {
|
||||
unsigned char *new_buffer;
|
||||
int i;
|
||||
|
@ -374,7 +379,7 @@ static enum libtelnet_error_t _buffer_byte(struct libtelnet_t *telnet,
|
|||
return LIBTELNET_EOK;
|
||||
}
|
||||
|
||||
static void _process(struct libtelnet_t *telnet, unsigned char *buffer,
|
||||
static void _process(libtelnet_t *telnet, unsigned char *buffer,
|
||||
unsigned int size) {
|
||||
unsigned char byte;
|
||||
unsigned int i, start;
|
||||
|
@ -487,11 +492,10 @@ static void _process(struct libtelnet_t *telnet, unsigned char *buffer,
|
|||
* handling the compressed stream if it's not already.
|
||||
*/
|
||||
if (telnet->sb_telopt == LIBTELNET_TELOPT_COMPRESS2 &&
|
||||
telnet->z_inflate == 0 &&
|
||||
(telnet->mode == LIBTELNET_MODE_CLIENT ||
|
||||
telnet->mode == LIBTELNET_MODE_PROXY)) {
|
||||
telnet->z == 0 &&
|
||||
telnet->flags & LIBTELNET_FLAG_PROXY) {
|
||||
|
||||
if ((telnet->z_inflate = _init_zlib(telnet, 0, 1)) == 0)
|
||||
if (_init_zlib(telnet, 0, 1) != LIBTELNET_EOK)
|
||||
break;
|
||||
|
||||
/* notify app that compression was enabled */
|
||||
|
@ -539,47 +543,46 @@ static void _process(struct libtelnet_t *telnet, unsigned char *buffer,
|
|||
}
|
||||
|
||||
/* push a bytes into the state tracker */
|
||||
void libtelnet_push(struct libtelnet_t *telnet, unsigned char *buffer,
|
||||
void libtelnet_push(libtelnet_t *telnet, unsigned char *buffer,
|
||||
unsigned int size) {
|
||||
#ifdef HAVE_ZLIB
|
||||
/* if we have an inflate (decompression) zlib stream, use it */
|
||||
if (telnet->z_inflate != 0) {
|
||||
if (telnet->z != 0) {
|
||||
unsigned char inflate_buffer[4096];
|
||||
int rs;
|
||||
|
||||
/* initialize zlib state */
|
||||
telnet->z_inflate->next_in = buffer;
|
||||
telnet->z_inflate->avail_in = size;
|
||||
telnet->z_inflate->next_out = inflate_buffer;
|
||||
telnet->z_inflate->avail_out = sizeof(inflate_buffer);
|
||||
telnet->z->next_in = buffer;
|
||||
telnet->z->avail_in = size;
|
||||
telnet->z->next_out = inflate_buffer;
|
||||
telnet->z->avail_out = sizeof(inflate_buffer);
|
||||
|
||||
/* inflate until buffer exhausted and all output is produced */
|
||||
while (telnet->z_inflate->avail_in > 0 ||
|
||||
telnet->z_inflate->avail_out == 0) {
|
||||
while (telnet->z->avail_in > 0 || telnet->z->avail_out == 0) {
|
||||
/* reset output buffer */
|
||||
|
||||
/* decompress */
|
||||
rs = inflate(telnet->z_inflate, Z_SYNC_FLUSH);
|
||||
rs = inflate(telnet->z, Z_SYNC_FLUSH);
|
||||
|
||||
/* process the decompressed bytes on success */
|
||||
if (rs == Z_OK || rs == Z_STREAM_END)
|
||||
_process(telnet, inflate_buffer, sizeof(inflate_buffer) -
|
||||
telnet->z_inflate->avail_out);
|
||||
telnet->z->avail_out);
|
||||
else
|
||||
_error(telnet, __LINE__, __func__, LIBTELNET_ECOMPRESS, 1,
|
||||
"inflate() failed: %s", zError(rs));
|
||||
|
||||
/* prepare output buffer for next run */
|
||||
telnet->z_inflate->next_out = inflate_buffer;
|
||||
telnet->z_inflate->avail_out = sizeof(inflate_buffer);
|
||||
telnet->z->next_out = inflate_buffer;
|
||||
telnet->z->avail_out = sizeof(inflate_buffer);
|
||||
|
||||
/* on error (or on end of stream) disable further inflation */
|
||||
if (rs != Z_OK) {
|
||||
_event(telnet, LIBTELNET_EV_COMPRESS, 0, 0, 0, 0);
|
||||
|
||||
inflateEnd(telnet->z_inflate);
|
||||
free(telnet->z_inflate);
|
||||
telnet->z_inflate = 0;
|
||||
inflateEnd(telnet->z);
|
||||
free(telnet->z);
|
||||
telnet->z = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -590,39 +593,38 @@ void libtelnet_push(struct libtelnet_t *telnet, unsigned char *buffer,
|
|||
_process(telnet, buffer, size);
|
||||
}
|
||||
|
||||
static void _send(struct libtelnet_t *telnet, unsigned char *buffer,
|
||||
static void _send(libtelnet_t *telnet, unsigned char *buffer,
|
||||
unsigned int size) {
|
||||
#ifdef HAVE_ZLIB
|
||||
/* if we have a deflate (compression) zlib box, use it */
|
||||
if (telnet->z_deflate != 0) {
|
||||
if (telnet->z != 0) {
|
||||
unsigned char deflate_buffer[1024];
|
||||
int rs;
|
||||
|
||||
/* initialize z_deflate state */
|
||||
telnet->z_deflate->next_in = buffer;
|
||||
telnet->z_deflate->avail_in = size;
|
||||
telnet->z_deflate->next_out = deflate_buffer;
|
||||
telnet->z_deflate->avail_out = sizeof(deflate_buffer);
|
||||
/* initialize z state */
|
||||
telnet->z->next_in = buffer;
|
||||
telnet->z->avail_in = size;
|
||||
telnet->z->next_out = deflate_buffer;
|
||||
telnet->z->avail_out = sizeof(deflate_buffer);
|
||||
|
||||
/* deflate until buffer exhausted and all output is produced */
|
||||
while (telnet->z_deflate->avail_in > 0 ||
|
||||
telnet->z_deflate->avail_out == 0) {
|
||||
while (telnet->z->avail_in > 0 || telnet->z->avail_out == 0) {
|
||||
/* compress */
|
||||
if ((rs = deflate(telnet->z_deflate, Z_SYNC_FLUSH)) != Z_OK) {
|
||||
if ((rs = deflate(telnet->z, Z_SYNC_FLUSH)) != Z_OK) {
|
||||
_error(telnet, __LINE__, __func__, LIBTELNET_ECOMPRESS, 1,
|
||||
"deflate() failed: %s", zError(rs));
|
||||
deflateEnd(telnet->z_deflate);
|
||||
free(telnet->z_deflate);
|
||||
telnet->z_deflate = 0;
|
||||
deflateEnd(telnet->z);
|
||||
free(telnet->z);
|
||||
telnet->z = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
_event(telnet, LIBTELNET_EV_SEND, 0, 0, deflate_buffer,
|
||||
sizeof(deflate_buffer) - telnet->z_deflate->avail_out);
|
||||
sizeof(deflate_buffer) - telnet->z->avail_out);
|
||||
|
||||
/* prepare output buffer for next run */
|
||||
telnet->z_deflate->next_out = deflate_buffer;
|
||||
telnet->z_deflate->avail_out = sizeof(deflate_buffer);
|
||||
telnet->z->next_out = deflate_buffer;
|
||||
telnet->z->avail_out = sizeof(deflate_buffer);
|
||||
}
|
||||
|
||||
/* COMPRESS2 is not negotiated, just send */
|
||||
|
@ -632,20 +634,20 @@ static void _send(struct libtelnet_t *telnet, unsigned char *buffer,
|
|||
}
|
||||
|
||||
/* send an iac command */
|
||||
void libtelnet_send_command(struct libtelnet_t *telnet, unsigned char cmd) {
|
||||
void libtelnet_send_command(libtelnet_t *telnet, unsigned char cmd) {
|
||||
unsigned char bytes[2] = { LIBTELNET_IAC, cmd };
|
||||
_send(telnet, bytes, 2);
|
||||
}
|
||||
|
||||
/* send negotiation */
|
||||
void libtelnet_send_negotiate(struct libtelnet_t *telnet, unsigned char cmd,
|
||||
void libtelnet_send_negotiate(libtelnet_t *telnet, unsigned char cmd,
|
||||
unsigned char opt) {
|
||||
unsigned char bytes[3] = { LIBTELNET_IAC, cmd, opt };
|
||||
_send(telnet, bytes, 3);
|
||||
}
|
||||
|
||||
/* send non-command data (escapes IAC bytes) */
|
||||
void libtelnet_send_data(struct libtelnet_t *telnet, unsigned char *buffer,
|
||||
void libtelnet_send_data(libtelnet_t *telnet, unsigned char *buffer,
|
||||
unsigned int size) {
|
||||
unsigned int i, l;
|
||||
for (l = i = 0; i != size; ++i) {
|
||||
|
@ -667,8 +669,8 @@ void libtelnet_send_data(struct libtelnet_t *telnet, unsigned char *buffer,
|
|||
}
|
||||
|
||||
/* send sub-request */
|
||||
void libtelnet_send_subnegotiation(struct libtelnet_t *telnet,
|
||||
unsigned char opt, unsigned char *buffer, unsigned int size) {
|
||||
void libtelnet_send_subnegotiation(libtelnet_t *telnet, unsigned char opt,
|
||||
unsigned char *buffer, unsigned int size) {
|
||||
libtelnet_send_command(telnet, LIBTELNET_SB);
|
||||
libtelnet_send_data(telnet, &opt, 1);
|
||||
libtelnet_send_data(telnet, buffer, size);
|
||||
|
@ -678,11 +680,11 @@ void libtelnet_send_subnegotiation(struct libtelnet_t *telnet,
|
|||
/* 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->mode == LIBTELNET_MODE_PROXY &&
|
||||
telnet->z_deflate == 0 &&
|
||||
if (telnet->flags & LIBTELNET_FLAG_PROXY &&
|
||||
telnet->z == 0 &&
|
||||
opt == LIBTELNET_TELOPT_COMPRESS2) {
|
||||
|
||||
if ((telnet->z_deflate = _init_zlib(telnet, 1, 1)) == 0)
|
||||
if (_init_zlib(telnet, 1, 1) != LIBTELNET_EOK)
|
||||
return;
|
||||
|
||||
/* notify app that compression was enabled */
|
||||
|
@ -691,33 +693,27 @@ void libtelnet_send_subnegotiation(struct libtelnet_t *telnet,
|
|||
#endif /* HAVE_ZLIB */
|
||||
}
|
||||
|
||||
void libtelnet_begin_compress2(struct libtelnet_t *telnet) {
|
||||
void libtelnet_begin_compress2(libtelnet_t *telnet) {
|
||||
#ifdef HAVE_ZLIB
|
||||
z_stream *zlib;
|
||||
unsigned char compress2[] = { LIBTELNET_IAC, LIBTELNET_SB,
|
||||
LIBTELNET_TELOPT_COMPRESS2, LIBTELNET_IAC, LIBTELNET_SE };
|
||||
|
||||
/* don't do this if we've already got a compression stream */
|
||||
if (telnet->z_deflate != 0) {
|
||||
if (telnet->z != 0) {
|
||||
_error(telnet, __LINE__, __func__, LIBTELNET_EBADVAL, 0,
|
||||
"compression already enabled");
|
||||
return;
|
||||
}
|
||||
|
||||
/* only supported by servers */
|
||||
if (telnet->mode != LIBTELNET_MODE_SERVER) {
|
||||
_error(telnet, __LINE__, __func__, LIBTELNET_EBADVAL, 0,
|
||||
"only supported in SERVER mode");
|
||||
return;
|
||||
}
|
||||
|
||||
/* attempt to create output stream first, bail if we can't */
|
||||
if ((zlib = _init_zlib(telnet, 1, 0)) == 0)
|
||||
if (_init_zlib(telnet, 1, 0) != LIBTELNET_EOK)
|
||||
return;
|
||||
|
||||
/* send compression marker */
|
||||
libtelnet_send_subnegotiation(telnet, LIBTELNET_TELOPT_COMPRESS2, 0, 0);
|
||||
|
||||
/* set our deflate stream */
|
||||
telnet->z_deflate = zlib;
|
||||
/* 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));
|
||||
#endif /* HAVE_ZLIB */
|
||||
}
|
||||
|
||||
|
|
55
libtelnet.h
55
libtelnet.h
|
@ -13,8 +13,12 @@
|
|||
#define LIBTELNET_INCLUDE 1
|
||||
|
||||
/* forward declarations */
|
||||
struct libtelnet_t;
|
||||
struct libtelnet_cb_t;
|
||||
typedef struct libtelnet_t libtelnet_t;
|
||||
typedef struct libtelnet_event_t libtelnet_event_t;
|
||||
typedef enum libtelnet_mode_t libtelnet_mode_t;
|
||||
typedef enum libtelnet_state_t libtelnet_state_t;
|
||||
typedef enum libtelnet_error_t libtelnet_error_t;
|
||||
typedef enum libtelnet_event_type_t libtelnet_event_type_t;
|
||||
|
||||
/* telnet special values */
|
||||
#define LIBTELNET_IAC 255
|
||||
|
@ -85,12 +89,10 @@ struct libtelnet_cb_t;
|
|||
#define LIBTELNET_TELOPT_ZMP 93
|
||||
#define LIBTELNET_TELOPT_EXOPL 255
|
||||
|
||||
/* libtelnet modes */
|
||||
enum libtelnet_mode_t {
|
||||
LIBTELNET_MODE_SERVER = 0,
|
||||
LIBTELNET_MODE_CLIENT,
|
||||
LIBTELNET_MODE_PROXY
|
||||
};
|
||||
/* libtelnet feature flags */
|
||||
#define LIBTELNET_FLAG_PROXY (1<<0)
|
||||
|
||||
#define LIBTELNET_PFLAG_DEFLATE (1<<7)
|
||||
|
||||
/* telnet states */
|
||||
enum libtelnet_state_t {
|
||||
|
@ -152,8 +154,8 @@ struct libtelnet_rfc1143_t {
|
|||
};
|
||||
|
||||
/* event handler declaration */
|
||||
typedef void (*libtelnet_event_handler_t)(struct libtelnet_t *telnet,
|
||||
struct libtelnet_event_t *event, void *user_data);
|
||||
typedef void (*libtelnet_event_handler_t)(libtelnet_t *telnet,
|
||||
libtelnet_event_t *event, void *user_data);
|
||||
|
||||
/* state tracker */
|
||||
struct libtelnet_t {
|
||||
|
@ -163,8 +165,7 @@ struct libtelnet_t {
|
|||
libtelnet_event_handler_t eh;
|
||||
#ifdef HAVE_ZLIB
|
||||
/* zlib (mccp2) compression */
|
||||
z_stream *z_deflate;
|
||||
z_stream *z_inflate;
|
||||
z_stream *z;
|
||||
#endif
|
||||
/* RFC1143 option negotiation states */
|
||||
struct libtelnet_rfc1143_t *q;
|
||||
|
@ -176,8 +177,8 @@ struct libtelnet_t {
|
|||
unsigned int buffer_pos;
|
||||
/* current state */
|
||||
enum libtelnet_state_t state;
|
||||
/* processing mode */
|
||||
enum libtelnet_mode_t mode;
|
||||
/* option flags */
|
||||
unsigned char flags;
|
||||
/* current subnegotiation telopt */
|
||||
unsigned char sb_telopt;
|
||||
/* length of RFC1143 queue */
|
||||
|
@ -185,35 +186,33 @@ struct libtelnet_t {
|
|||
};
|
||||
|
||||
/* initialize a telnet state tracker */
|
||||
extern void libtelnet_init(struct libtelnet_t *telnet,
|
||||
libtelnet_event_handler_t eh, enum libtelnet_mode_t mode,
|
||||
void *user_data);
|
||||
extern void libtelnet_init(libtelnet_t *telnet, libtelnet_event_handler_t eh,
|
||||
unsigned char flags, void *user_data);
|
||||
|
||||
/* free up any memory allocated by a state tracker */
|
||||
extern void libtelnet_free(struct libtelnet_t *telnet);
|
||||
extern void libtelnet_free(libtelnet_t *telnet);
|
||||
|
||||
/* push a byte buffer into the state tracker */
|
||||
extern void libtelnet_push(struct libtelnet_t *telnet,
|
||||
unsigned char *buffer, unsigned int size);
|
||||
extern void libtelnet_push(libtelnet_t *telnet, unsigned char *buffer,
|
||||
unsigned int size);
|
||||
|
||||
/* send an iac command */
|
||||
extern void libtelnet_send_command(struct libtelnet_t *telnet,
|
||||
unsigned char cmd);
|
||||
extern void libtelnet_send_command(libtelnet_t *telnet, unsigned char cmd);
|
||||
|
||||
/* send negotiation */
|
||||
extern void libtelnet_send_negotiate(struct libtelnet_t *telnet,
|
||||
unsigned char cmd, unsigned char opt);
|
||||
extern void libtelnet_send_negotiate(libtelnet_t *telnet, unsigned char cmd,
|
||||
unsigned char opt);
|
||||
|
||||
/* send non-command data (escapes IAC bytes) */
|
||||
extern void libtelnet_send_data(struct libtelnet_t *telnet,
|
||||
unsigned char *buffer, unsigned int size);
|
||||
extern void libtelnet_send_data(libtelnet_t *telnet, unsigned char *buffer,
|
||||
unsigned int size);
|
||||
|
||||
/* send sub-request */
|
||||
extern void libtelnet_send_subnegotiation(struct libtelnet_t *telnet,
|
||||
extern void libtelnet_send_subnegotiation(libtelnet_t *telnet,
|
||||
unsigned char opt, unsigned char *buffer, unsigned int size);
|
||||
|
||||
/* begin sending compressed data (server only) */
|
||||
extern void libtelnet_begin_compress2(struct libtelnet_t *telnet);
|
||||
extern void libtelnet_begin_compress2(libtelnet_t *telnet);
|
||||
|
||||
/* return the status of a specific TELNET option on our end (US) */
|
||||
extern int libtelnet_get_telopt_local(struct libtelnet_t *telnet,
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
#include "libtelnet.h"
|
||||
|
||||
static struct termios orig_tios;
|
||||
static struct libtelnet_t telnet;
|
||||
static libtelnet_t telnet;
|
||||
static int do_echo;
|
||||
|
||||
static void _cleanup(void) {
|
||||
|
@ -76,8 +76,8 @@ static void _send(int sock, unsigned char *buffer, unsigned int size) {
|
|||
}
|
||||
}
|
||||
|
||||
static void _event_handler(struct libtelnet_t *telnet,
|
||||
struct libtelnet_event_t *ev, void *user_data) {
|
||||
static void _event_handler(libtelnet_t *telnet, libtelnet_event_t *ev,
|
||||
void *user_data) {
|
||||
int sock = *(int*)user_data;
|
||||
|
||||
switch (ev->type) {
|
||||
|
@ -202,7 +202,7 @@ int main(int argc, char **argv) {
|
|||
do_echo = 1;
|
||||
|
||||
/* initialize telnet box */
|
||||
libtelnet_init(&telnet, _event_handler, LIBTELNET_MODE_CLIENT, &sock);
|
||||
libtelnet_init(&telnet, _event_handler, 0, &sock);
|
||||
|
||||
/* initialize poll descriptors */
|
||||
memset(pfd, 0, sizeof(pfd));
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
struct conn_t {
|
||||
const char *name;
|
||||
int sock;
|
||||
struct libtelnet_t telnet;
|
||||
libtelnet_t telnet;
|
||||
struct conn_t *remote;
|
||||
};
|
||||
|
||||
|
@ -161,8 +161,8 @@ static void _send(int sock, unsigned char *buffer, unsigned int size) {
|
|||
}
|
||||
}
|
||||
|
||||
static void _event_handler(struct libtelnet_t *telnet,
|
||||
struct libtelnet_event_t *ev, void *user_data) {
|
||||
static void _event_handler(libtelnet_t *telnet, libtelnet_event_t *ev,
|
||||
void *user_data) {
|
||||
struct conn_t *conn = (struct conn_t*)user_data;
|
||||
|
||||
switch (ev->type) {
|
||||
|
@ -355,9 +355,9 @@ int main(int argc, char **argv) {
|
|||
client.remote = &server;
|
||||
|
||||
/* initialize telnet boxes */
|
||||
libtelnet_init(&server.telnet, _event_handler, LIBTELNET_MODE_PROXY,
|
||||
libtelnet_init(&server.telnet, _event_handler, LIBTELNET_FLAG_PROXY,
|
||||
&server);
|
||||
libtelnet_init(&client.telnet, _event_handler, LIBTELNET_MODE_PROXY,
|
||||
libtelnet_init(&client.telnet, _event_handler, LIBTELNET_FLAG_PROXY,
|
||||
&client);
|
||||
|
||||
/* initialize poll descriptors */
|
||||
|
|
Loading…
Reference in New Issue