mirror of https://gerrit.osmocom.org/libtelnet
pass user_data to libtelnet_init() only instead of having to pass it to every function call
This commit is contained in:
parent
da0e695e62
commit
9f79cc5029
28
README
28
README
|
@ -20,7 +20,6 @@ code under copyright law.
|
|||
|
||||
- RFC 1143 option negotiation algorithm
|
||||
- automatic MCCP2 handling (controllable by host app)
|
||||
? MCCP1
|
||||
? ZMP parsing
|
||||
? MSSP parsing
|
||||
? ENVIRON/NEW-ENVIRON parsing
|
||||
|
@ -59,7 +58,8 @@ IIa. Initialization
|
|||
API calls.
|
||||
|
||||
void libtelnet_init(struct libtelnet_t *telnet,
|
||||
libtelnet_event_handler_t handler, enum libtelnet_mode_t mode);
|
||||
libtelnet_event_handler_t handler, enum libtelnet_mode_t mode,
|
||||
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
|
||||
|
@ -69,6 +69,11 @@ IIa. Initialization
|
|||
libtelnet_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.
|
||||
|
||||
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
|
||||
|
@ -98,8 +103,7 @@ IIb. Receiving Data
|
|||
IIc. Sending Data
|
||||
|
||||
All of the libtelnet_send_*() functions will invoke the
|
||||
LIBTELNET_EV_SEND event. The user_data parameter to each of these
|
||||
functions is passed through to the callback.
|
||||
LIBTELNET_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,25 +112,24 @@ IIc. Sending Data
|
|||
data directly!
|
||||
|
||||
void libtelnet_send_command(struct libtelnet_t *telnet,
|
||||
unsigned char cmd, void *user_data);
|
||||
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,
|
||||
unsigned char cmd, unsigned char opt, void *user_data);
|
||||
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 *user_data);
|
||||
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,
|
||||
unsigned char opt, unsigned char *buffer, unsigned int size,
|
||||
void *user_data);
|
||||
unsigned char opt, unsigned char *buffer, unsigned int size);
|
||||
Sends a TELNET sub-negotiation command. The opt parameter
|
||||
is the sub-negotiation option.
|
||||
|
||||
|
@ -141,9 +144,10 @@ IId. Event Handling
|
|||
meet the following prototype:
|
||||
|
||||
void (libtelnet_t *telnet, libtelnet_event_t *event,
|
||||
void *user_data);
|
||||
|
||||
The libtelnet_event_t structure has the following definition:
|
||||
void *user_data);
|
||||
|
||||
The event structure is detailed below. The user_data value is the
|
||||
pointer passed to libtelnet_init().
|
||||
|
||||
struct libtelnet_event_t {
|
||||
enum libtelnet_event_type_t type;
|
||||
|
|
138
libtelnet.c
138
libtelnet.c
|
@ -26,14 +26,14 @@
|
|||
#ifdef ERROR
|
||||
# undef ERROR
|
||||
#endif
|
||||
#define ERROR(telnet, code, user_data, msg) \
|
||||
_error(telnet, __FILE__, __LINE__, code, user_data, "%s", msg)
|
||||
#define ERROR_NOMEM(telnet, user_data, msg) \
|
||||
_error(telnet, __FILE__, __LINE__, LIBTELNET_ENOMEM, user_data, \
|
||||
#define ERROR(telnet, code, msg) \
|
||||
_error(telnet, __FILE__, __LINE__, code, "%s", msg)
|
||||
#define ERROR_NOMEM(telnet, msg) \
|
||||
_error(telnet, __FILE__, __LINE__, LIBTELNET_ENOMEM, \
|
||||
"%s: %s", msg, strerror(errno))
|
||||
#define ERROR_ZLIB(telnet, user_data, rs, msg) \
|
||||
#define ERROR_ZLIB(telnet, rs, msg) \
|
||||
_error(telnet, __FILE__, __LINE__, LIBTELNET_EUNKNOWN, \
|
||||
user_data, "%s: %s", msg, zError(rs))
|
||||
"%s: %s", msg, zError(rs))
|
||||
|
||||
/* buffer sizes */
|
||||
static const unsigned int _buffer_sizes[] = {
|
||||
|
@ -49,8 +49,7 @@ static const unsigned int _buffer_sizes_count =
|
|||
/* event dispatch helper */
|
||||
static void _event(struct libtelnet_t *telnet,
|
||||
enum libtelnet_event_type_t type, unsigned char command,
|
||||
unsigned char telopt, unsigned char *buffer, unsigned int size,
|
||||
void *user_data) {
|
||||
unsigned char telopt, unsigned char *buffer, unsigned int size) {
|
||||
struct libtelnet_event_t ev;
|
||||
ev.type = type;
|
||||
ev.command = command;
|
||||
|
@ -58,12 +57,12 @@ static void _event(struct libtelnet_t *telnet,
|
|||
ev.buffer = buffer;
|
||||
ev.size = size;
|
||||
|
||||
telnet->eh(telnet, &ev, user_data);
|
||||
telnet->eh(telnet, &ev, telnet->ud);
|
||||
}
|
||||
|
||||
/* error generation function */
|
||||
static void _error(struct libtelnet_t *telnet, const char *file, unsigned line,
|
||||
enum libtelnet_error_t err, void *user_data, const char *fmt, ...) {
|
||||
enum libtelnet_error_t err, const char *fmt, ...) {
|
||||
char buffer[512];
|
||||
va_list va;
|
||||
|
||||
|
@ -76,22 +75,21 @@ static void _error(struct libtelnet_t *telnet, const char *file, unsigned line,
|
|||
fmt, va);
|
||||
va_end(va);
|
||||
|
||||
_event(telnet, LIBTELNET_EV_ERROR, err, 0, 0, 0, user_data);
|
||||
_event(telnet, LIBTELNET_EV_ERROR, err, 0, 0, 0);
|
||||
}
|
||||
|
||||
/* initialize the zlib box for a telnet box; if deflate is non-zero, it
|
||||
* initializes zlib for delating (compression), otherwise for inflating
|
||||
* (decompression)
|
||||
*/
|
||||
z_stream *_init_zlib(struct libtelnet_t *telnet, int deflate,
|
||||
void *user_data) {
|
||||
z_stream *_init_zlib(struct libtelnet_t *telnet, int deflate) {
|
||||
z_stream *zlib;
|
||||
int rs;
|
||||
|
||||
/* allocate zstream box */
|
||||
if ((zlib = (z_stream *)calloc(1, sizeof(z_stream)))
|
||||
== 0) {
|
||||
ERROR_NOMEM(telnet, user_data, "malloc() failed");
|
||||
ERROR_NOMEM(telnet, "malloc() failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -99,13 +97,13 @@ z_stream *_init_zlib(struct libtelnet_t *telnet, int deflate,
|
|||
if (deflate) {
|
||||
if ((rs = deflateInit(zlib, Z_DEFAULT_COMPRESSION)) != Z_OK) {
|
||||
free(zlib);
|
||||
ERROR_ZLIB(telnet, user_data, rs, "deflateInit() failed");
|
||||
ERROR_ZLIB(telnet, rs, "deflateInit() failed");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if ((rs = inflateInit(zlib)) != Z_OK) {
|
||||
free(zlib);
|
||||
ERROR_ZLIB(telnet, user_data, rs, "inflateInit() failed");
|
||||
ERROR_ZLIB(telnet, rs, "inflateInit() failed");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -115,8 +113,9 @@ z_stream *_init_zlib(struct libtelnet_t *telnet, int deflate,
|
|||
|
||||
/* initialize a telnet state tracker */
|
||||
void libtelnet_init(struct libtelnet_t *telnet, libtelnet_event_handler_t eh,
|
||||
enum libtelnet_mode_t mode) {
|
||||
enum libtelnet_mode_t mode, void *user_data) {
|
||||
memset(telnet, 0, sizeof(struct libtelnet_t));
|
||||
telnet->ud = user_data;
|
||||
telnet->eh = eh;
|
||||
telnet->mode = mode;
|
||||
}
|
||||
|
@ -146,7 +145,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,
|
||||
unsigned char byte, void *user_data) {
|
||||
unsigned char byte) {
|
||||
unsigned char *new_buffer;
|
||||
int i;
|
||||
|
||||
|
@ -161,7 +160,7 @@ static enum libtelnet_error_t _buffer_byte(struct libtelnet_t *telnet,
|
|||
/* overflow -- can't grow any more */
|
||||
if (i >= _buffer_sizes_count - 1) {
|
||||
_error(telnet, __FILE__, __LINE__, LIBTELNET_EOVERFLOW,
|
||||
user_data, "subnegotiation buffer size limit reached");
|
||||
"subnegotiation buffer size limit reached");
|
||||
libtelnet_free(telnet);
|
||||
return LIBTELNET_EOVERFLOW;
|
||||
}
|
||||
|
@ -170,7 +169,7 @@ static enum libtelnet_error_t _buffer_byte(struct libtelnet_t *telnet,
|
|||
new_buffer = (unsigned char *)realloc(telnet->buffer,
|
||||
_buffer_sizes[i + 1]);
|
||||
if (new_buffer == 0) {
|
||||
ERROR_NOMEM(telnet, user_data, "realloc() failed");
|
||||
ERROR_NOMEM(telnet, "realloc() failed");
|
||||
libtelnet_free(telnet);
|
||||
return LIBTELNET_ENOMEM;
|
||||
}
|
||||
|
@ -185,7 +184,7 @@ static enum libtelnet_error_t _buffer_byte(struct libtelnet_t *telnet,
|
|||
}
|
||||
|
||||
static void _process(struct libtelnet_t *telnet, unsigned char *buffer,
|
||||
unsigned int size, void *user_data) {
|
||||
unsigned int size) {
|
||||
unsigned char byte;
|
||||
unsigned int i, start;
|
||||
for (i = start = 0; i != size; ++i) {
|
||||
|
@ -198,7 +197,7 @@ static void _process(struct libtelnet_t *telnet, unsigned char *buffer,
|
|||
if (byte == LIBTELNET_IAC) {
|
||||
if (i != start)
|
||||
_event(telnet, LIBTELNET_EV_DATA, 0, 0, &buffer[start],
|
||||
i - start, user_data);
|
||||
i - start);
|
||||
telnet->state = LIBTELNET_STATE_IAC;
|
||||
}
|
||||
break;
|
||||
|
@ -225,13 +224,13 @@ static void _process(struct libtelnet_t *telnet, unsigned char *buffer,
|
|||
break;
|
||||
/* IAC escaping */
|
||||
case LIBTELNET_IAC:
|
||||
_event(telnet, LIBTELNET_EV_DATA, 0, 0, &byte, 1, user_data);
|
||||
_event(telnet, LIBTELNET_EV_DATA, 0, 0, &byte, 1);
|
||||
start = i + 1;
|
||||
telnet->state = LIBTELNET_STATE_DATA;
|
||||
break;
|
||||
/* some other command */
|
||||
default:
|
||||
_event(telnet, LIBTELNET_EV_IAC, byte, 0, 0, 0, user_data);
|
||||
_event(telnet, LIBTELNET_EV_IAC, byte, 0, 0, 0);
|
||||
start = i + 1;
|
||||
telnet->state = LIBTELNET_STATE_DATA;
|
||||
}
|
||||
|
@ -239,26 +238,22 @@ static void _process(struct libtelnet_t *telnet, unsigned char *buffer,
|
|||
|
||||
/* negotiation commands */
|
||||
case LIBTELNET_STATE_DO:
|
||||
_event(telnet, LIBTELNET_EV_NEGOTIATE, LIBTELNET_DO, byte,
|
||||
0, 0, user_data);
|
||||
_event(telnet, LIBTELNET_EV_NEGOTIATE, LIBTELNET_DO, byte, 0, 0);
|
||||
start = i + 1;
|
||||
telnet->state = LIBTELNET_STATE_DATA;
|
||||
break;
|
||||
case LIBTELNET_STATE_DONT:
|
||||
_event(telnet, LIBTELNET_EV_NEGOTIATE, LIBTELNET_DONT, byte,
|
||||
0, 0, user_data);
|
||||
_event(telnet, LIBTELNET_EV_NEGOTIATE, LIBTELNET_DONT, byte, 0, 0);
|
||||
start = i + 1;
|
||||
telnet->state = LIBTELNET_STATE_DATA;
|
||||
break;
|
||||
case LIBTELNET_STATE_WILL:
|
||||
_event(telnet, LIBTELNET_EV_NEGOTIATE, LIBTELNET_WILL, byte,
|
||||
0, 0, user_data);
|
||||
_event(telnet, LIBTELNET_EV_NEGOTIATE, LIBTELNET_WILL, byte, 0, 0);
|
||||
start = i + 1;
|
||||
telnet->state = LIBTELNET_STATE_DATA;
|
||||
break;
|
||||
case LIBTELNET_STATE_WONT:
|
||||
_event(telnet, LIBTELNET_EV_NEGOTIATE, LIBTELNET_WONT, byte,
|
||||
0, 0, user_data);
|
||||
_event(telnet, LIBTELNET_EV_NEGOTIATE, LIBTELNET_WONT, byte, 0, 0);
|
||||
start = i + 1;
|
||||
telnet->state = LIBTELNET_STATE_DATA;
|
||||
break;
|
||||
|
@ -276,8 +271,7 @@ static void _process(struct libtelnet_t *telnet, unsigned char *buffer,
|
|||
if (byte == LIBTELNET_IAC) {
|
||||
telnet->state = LIBTELNET_STATE_SB_DATA_IAC;
|
||||
/* buffer the byte, or bail if we can't */
|
||||
} else if (_buffer_byte(telnet, byte, user_data) !=
|
||||
LIBTELNET_EOK) {
|
||||
} else if (_buffer_byte(telnet, byte) != LIBTELNET_EOK) {
|
||||
start = i + 1;
|
||||
telnet->state = LIBTELNET_STATE_DATA;
|
||||
}
|
||||
|
@ -294,8 +288,7 @@ static void _process(struct libtelnet_t *telnet, unsigned char *buffer,
|
|||
|
||||
/* invoke callback */
|
||||
_event(telnet, LIBTELNET_EV_SUBNEGOTIATION, 0,
|
||||
telnet->sb_telopt, telnet->buffer, telnet->length,
|
||||
user_data);
|
||||
telnet->sb_telopt, telnet->buffer, telnet->length);
|
||||
|
||||
#ifdef HAVE_ZLIB
|
||||
/* if we are a client or a proxy and just received the
|
||||
|
@ -307,13 +300,12 @@ static void _process(struct libtelnet_t *telnet, unsigned char *buffer,
|
|||
(telnet->mode == LIBTELNET_MODE_CLIENT ||
|
||||
telnet->mode == LIBTELNET_MODE_PROXY)) {
|
||||
|
||||
if ((telnet->z_inflate = _init_zlib(telnet, 0, user_data))
|
||||
if ((telnet->z_inflate = _init_zlib(telnet, 0))
|
||||
== 0)
|
||||
break;
|
||||
|
||||
/* notify app that compression was enabled */
|
||||
_event(telnet, LIBTELNET_EV_COMPRESS, 1, 0, 0, 0,
|
||||
user_data);
|
||||
_event(telnet, LIBTELNET_EV_COMPRESS, 1, 0, 0, 0);
|
||||
|
||||
/* any remaining bytes in the buffer are compressed.
|
||||
* we have to re-invoke libtelnet_push to get those
|
||||
|
@ -321,8 +313,7 @@ static void _process(struct libtelnet_t *telnet, unsigned char *buffer,
|
|||
* remaining compressed bytes in the current _process
|
||||
* buffer argument
|
||||
*/
|
||||
libtelnet_push(telnet, &buffer[start], size - start,
|
||||
user_data);
|
||||
libtelnet_push(telnet, &buffer[start], size - start);
|
||||
return;
|
||||
}
|
||||
#endif /* HAVE_ZLIB */
|
||||
|
@ -331,7 +322,7 @@ static void _process(struct libtelnet_t *telnet, unsigned char *buffer,
|
|||
/* escaped IAC byte */
|
||||
case LIBTELNET_IAC:
|
||||
/* push IAC into buffer */
|
||||
if (_buffer_byte(telnet, LIBTELNET_IAC, user_data) !=
|
||||
if (_buffer_byte(telnet, LIBTELNET_IAC) !=
|
||||
LIBTELNET_EOK) {
|
||||
start = i + 1;
|
||||
telnet->state = LIBTELNET_STATE_DATA;
|
||||
|
@ -342,7 +333,7 @@ static void _process(struct libtelnet_t *telnet, unsigned char *buffer,
|
|||
/* something else -- protocol error */
|
||||
default:
|
||||
_error(telnet, __FILE__, __LINE__, LIBTELNET_EPROTOCOL,
|
||||
user_data, "unexpected byte after IAC inside SB: %d",
|
||||
"unexpected byte after IAC inside SB: %d",
|
||||
byte);
|
||||
start = i + 1;
|
||||
telnet->state = LIBTELNET_STATE_DATA;
|
||||
|
@ -354,13 +345,12 @@ static void _process(struct libtelnet_t *telnet, unsigned 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,
|
||||
user_data);
|
||||
_event(telnet, LIBTELNET_EV_DATA, 0, 0, buffer + start, i - start);
|
||||
}
|
||||
|
||||
/* push a bytes into the state tracker */
|
||||
void libtelnet_push(struct libtelnet_t *telnet, unsigned char *buffer,
|
||||
unsigned int size, void *user_data) {
|
||||
unsigned int size) {
|
||||
#ifdef HAVE_ZLIB
|
||||
/* if we have an inflate (decompression) zlib stream, use it */
|
||||
if (telnet->z_inflate != 0) {
|
||||
|
@ -383,9 +373,9 @@ void libtelnet_push(struct libtelnet_t *telnet, unsigned char *buffer,
|
|||
/* 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, user_data);
|
||||
telnet->z_inflate->avail_out);
|
||||
else
|
||||
ERROR_ZLIB(telnet, user_data, rs, "inflate() failed");
|
||||
ERROR_ZLIB(telnet, rs, "inflate() failed");
|
||||
|
||||
/* prepare output buffer for next run */
|
||||
telnet->z_inflate->next_out = inflate_buffer;
|
||||
|
@ -393,7 +383,7 @@ void libtelnet_push(struct libtelnet_t *telnet, unsigned 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, user_data);
|
||||
_event(telnet, LIBTELNET_EV_COMPRESS, 0, 0, 0, 0);
|
||||
|
||||
inflateEnd(telnet->z_inflate);
|
||||
free(telnet->z_inflate);
|
||||
|
@ -405,11 +395,11 @@ void libtelnet_push(struct libtelnet_t *telnet, unsigned char *buffer,
|
|||
/* COMPRESS2 is not negotiated, just process */
|
||||
} else
|
||||
#endif /* HAVE_ZLIB */
|
||||
_process(telnet, buffer, size, user_data);
|
||||
_process(telnet, buffer, size);
|
||||
}
|
||||
|
||||
static void _send(struct libtelnet_t *telnet, unsigned char *buffer,
|
||||
unsigned int size, void *user_data) {
|
||||
unsigned int size) {
|
||||
#ifdef HAVE_ZLIB
|
||||
/* if we have a deflate (compression) zlib box, use it */
|
||||
if (telnet->z_deflate != 0) {
|
||||
|
@ -426,7 +416,7 @@ static void _send(struct libtelnet_t *telnet, unsigned char *buffer,
|
|||
while (telnet->z_deflate->avail_in > 0 || telnet->z_deflate->avail_out == 0) {
|
||||
/* compress */
|
||||
if ((rs = deflate(telnet->z_deflate, Z_SYNC_FLUSH)) != Z_OK) {
|
||||
ERROR_ZLIB(telnet, user_data, rs, "deflate() failed");
|
||||
ERROR_ZLIB(telnet, rs, "deflate() failed");
|
||||
deflateEnd(telnet->z_deflate);
|
||||
free(telnet->z_deflate);
|
||||
telnet->z_deflate = 0;
|
||||
|
@ -434,8 +424,7 @@ static void _send(struct libtelnet_t *telnet, unsigned char *buffer,
|
|||
}
|
||||
|
||||
_event(telnet, LIBTELNET_EV_SEND, 0, 0, deflate_buffer,
|
||||
sizeof(deflate_buffer) - telnet->z_deflate->avail_out,
|
||||
user_data);
|
||||
sizeof(deflate_buffer) - telnet->z_deflate->avail_out);
|
||||
|
||||
/* prepare output buffer for next run */
|
||||
telnet->z_deflate->next_out = deflate_buffer;
|
||||
|
@ -445,53 +434,51 @@ static void _send(struct libtelnet_t *telnet, unsigned char *buffer,
|
|||
/* COMPRESS2 is not negotiated, just send */
|
||||
} else
|
||||
#endif /* HAVE_ZLIB */
|
||||
_event(telnet, LIBTELNET_EV_SEND, 0, 0, buffer, size, user_data);
|
||||
_event(telnet, LIBTELNET_EV_SEND, 0, 0, buffer, size);
|
||||
}
|
||||
|
||||
/* send an iac command */
|
||||
void libtelnet_send_command(struct libtelnet_t *telnet, unsigned char cmd,
|
||||
void *user_data) {
|
||||
void libtelnet_send_command(struct libtelnet_t *telnet, unsigned char cmd) {
|
||||
unsigned char bytes[2] = { LIBTELNET_IAC, cmd };
|
||||
_send(telnet, bytes, 2, user_data);
|
||||
_send(telnet, bytes, 2);
|
||||
}
|
||||
|
||||
/* send negotiation */
|
||||
void libtelnet_send_negotiate(struct libtelnet_t *telnet, unsigned char cmd,
|
||||
unsigned char opt, void *user_data) {
|
||||
unsigned char opt) {
|
||||
unsigned char bytes[3] = { LIBTELNET_IAC, cmd, opt };
|
||||
_send(telnet, bytes, 3, user_data);
|
||||
_send(telnet, bytes, 3);
|
||||
}
|
||||
|
||||
/* send non-command data (escapes IAC bytes) */
|
||||
void libtelnet_send_data(struct libtelnet_t *telnet, unsigned char *buffer,
|
||||
unsigned int size, void *user_data) {
|
||||
unsigned int size) {
|
||||
unsigned int i, l;
|
||||
for (l = i = 0; i != size; ++i) {
|
||||
/* dump prior portion of text, send escaped bytes */
|
||||
if (buffer[i] == LIBTELNET_IAC) {
|
||||
/* dump prior text if any */
|
||||
if (i != l)
|
||||
_send(telnet, buffer + l, i - l, user_data);
|
||||
_send(telnet, buffer + l, i - l);
|
||||
l = i + 1;
|
||||
|
||||
/* send escape */
|
||||
libtelnet_send_command(telnet, LIBTELNET_IAC, user_data);
|
||||
libtelnet_send_command(telnet, LIBTELNET_IAC);
|
||||
}
|
||||
}
|
||||
|
||||
/* send whatever portion of buffer is left */
|
||||
if (i != l)
|
||||
_send(telnet, buffer + l, i - l, user_data);
|
||||
_send(telnet, buffer + l, i - l);
|
||||
}
|
||||
|
||||
/* send sub-request */
|
||||
void libtelnet_send_subnegotiation(struct libtelnet_t *telnet,
|
||||
unsigned char opt, unsigned char *buffer, unsigned int size,
|
||||
void *user_data) {
|
||||
libtelnet_send_command(telnet, LIBTELNET_SB, user_data);
|
||||
libtelnet_send_data(telnet, &opt, 1, user_data);
|
||||
libtelnet_send_data(telnet, buffer, size, user_data);
|
||||
libtelnet_send_command(telnet, LIBTELNET_SE, user_data);
|
||||
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);
|
||||
libtelnet_send_command(telnet, LIBTELNET_SE);
|
||||
|
||||
#ifdef HAVE_ZLIB
|
||||
/* if we're a proxy and we just sent the COMPRESS2 marker, we must
|
||||
|
@ -501,16 +488,16 @@ void libtelnet_send_subnegotiation(struct libtelnet_t *telnet,
|
|||
telnet->z_deflate == 0 &&
|
||||
opt == LIBTELNET_TELOPT_COMPRESS2) {
|
||||
|
||||
if ((telnet->z_deflate = _init_zlib(telnet, 1, user_data)) == 0)
|
||||
if ((telnet->z_deflate = _init_zlib(telnet, 1)) == 0)
|
||||
return;
|
||||
|
||||
/* notify app that compression was enabled */
|
||||
_event(telnet, LIBTELNET_EV_COMPRESS, 1, 0, 0, 0, user_data);
|
||||
_event(telnet, LIBTELNET_EV_COMPRESS, 1, 0, 0, 0);
|
||||
}
|
||||
#endif /* HAVE_ZLIB */
|
||||
}
|
||||
|
||||
void libtelnet_begin_compress2(struct libtelnet_t *telnet, void *user_data) {
|
||||
void libtelnet_begin_compress2(struct libtelnet_t *telnet) {
|
||||
#ifdef HAVE_ZLIB
|
||||
z_stream *zlib;
|
||||
|
||||
|
@ -523,12 +510,11 @@ void libtelnet_begin_compress2(struct libtelnet_t *telnet, void *user_data) {
|
|||
return;
|
||||
|
||||
/* attempt to create output stream first, bail if we can't */
|
||||
if ((zlib = _init_zlib(telnet, 1, user_data)) == 0)
|
||||
if ((zlib = _init_zlib(telnet, 1)) == 0)
|
||||
return;
|
||||
|
||||
/* send compression marker */
|
||||
libtelnet_send_subnegotiation(telnet, LIBTELNET_TELOPT_COMPRESS2, 0, 0,
|
||||
user_data);
|
||||
libtelnet_send_subnegotiation(telnet, LIBTELNET_TELOPT_COMPRESS2, 0, 0);
|
||||
|
||||
/* set our deflate stream */
|
||||
telnet->z_deflate = zlib;
|
||||
|
|
19
libtelnet.h
19
libtelnet.h
|
@ -144,6 +144,8 @@ typedef void (*libtelnet_event_handler_t)(struct libtelnet_t *telnet,
|
|||
|
||||
/* state tracker */
|
||||
struct libtelnet_t {
|
||||
/* user data */
|
||||
void *ud;
|
||||
/* event handler */
|
||||
libtelnet_event_handler_t eh;
|
||||
#ifdef HAVE_ZLIB
|
||||
|
@ -167,34 +169,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);
|
||||
libtelnet_event_handler_t eh, enum libtelnet_mode_t mode,
|
||||
void *user_data);
|
||||
|
||||
/* free up any memory allocated by a state tracker */
|
||||
extern void libtelnet_free(struct 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, void *user_data);
|
||||
unsigned char *buffer, unsigned int size);
|
||||
|
||||
/* send an iac command */
|
||||
extern void libtelnet_send_command(struct libtelnet_t *telnet,
|
||||
unsigned char cmd, void *user_data);
|
||||
unsigned char cmd);
|
||||
|
||||
/* send negotiation */
|
||||
extern void libtelnet_send_negotiate(struct libtelnet_t *telnet,
|
||||
unsigned char cmd, unsigned char opt, void *user_data);
|
||||
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, void *user_data);
|
||||
unsigned char *buffer, unsigned int size);
|
||||
|
||||
/* send sub-request */
|
||||
extern void libtelnet_send_subnegotiation(struct libtelnet_t *telnet,
|
||||
unsigned char opt, unsigned char *buffer, unsigned int size,
|
||||
void *user_data);
|
||||
unsigned char opt, unsigned char *buffer, unsigned int size);
|
||||
|
||||
/* begin sending compressed data (server only) */
|
||||
extern void libtelnet_begin_compress2(struct libtelnet_t *telnet,
|
||||
void *user_data);
|
||||
extern void libtelnet_begin_compress2(struct libtelnet_t *telnet);
|
||||
|
||||
#endif /* !defined(LIBTELNET_INCLUDE) */
|
||||
|
|
|
@ -172,8 +172,7 @@ static void _event_handler(struct libtelnet_t *telnet,
|
|||
print_buffer(ev->buffer, ev->size);
|
||||
printf(COLOR_NORMAL "\n");
|
||||
|
||||
libtelnet_send_data(&conn->remote->telnet, ev->buffer, ev->size,
|
||||
conn->remote);
|
||||
libtelnet_send_data(&conn->remote->telnet, ev->buffer, ev->size);
|
||||
break;
|
||||
/* data must be sent */
|
||||
case LIBTELNET_EV_SEND:
|
||||
|
@ -190,8 +189,7 @@ static void _event_handler(struct libtelnet_t *telnet,
|
|||
printf("%s IAC %s" COLOR_NORMAL "\n", conn->name,
|
||||
get_cmd(ev->command));
|
||||
|
||||
libtelnet_send_command(&conn->remote->telnet, ev->command,
|
||||
conn->remote);
|
||||
libtelnet_send_command(&conn->remote->telnet, ev->command);
|
||||
break;
|
||||
/* negotiation */
|
||||
case LIBTELNET_EV_NEGOTIATE:
|
||||
|
@ -199,7 +197,7 @@ static void _event_handler(struct libtelnet_t *telnet,
|
|||
get_cmd(ev->command), (int)ev->telopt, get_opt(ev->telopt));
|
||||
|
||||
libtelnet_send_negotiate(&conn->remote->telnet, ev->command,
|
||||
ev->telopt, conn->remote);
|
||||
ev->telopt);
|
||||
break;
|
||||
/* subnegotiation */
|
||||
case LIBTELNET_EV_SUBNEGOTIATION:
|
||||
|
@ -212,7 +210,7 @@ static void _event_handler(struct libtelnet_t *telnet,
|
|||
printf(COLOR_NORMAL "\n");
|
||||
|
||||
libtelnet_send_subnegotiation(&conn->remote->telnet, ev->telopt,
|
||||
ev->buffer, ev->size, conn->remote);
|
||||
ev->buffer, ev->size);
|
||||
break;
|
||||
/* compression notification */
|
||||
case LIBTELNET_EV_COMPRESS:
|
||||
|
@ -333,8 +331,10 @@ int main(int argc, char **argv) {
|
|||
client.remote = &server;
|
||||
|
||||
/* initialize telnet boxes */
|
||||
libtelnet_init(&server.telnet, _event_handler, LIBTELNET_MODE_PROXY);
|
||||
libtelnet_init(&client.telnet, _event_handler, LIBTELNET_MODE_PROXY);
|
||||
libtelnet_init(&server.telnet, _event_handler, LIBTELNET_MODE_PROXY,
|
||||
&server);
|
||||
libtelnet_init(&client.telnet, _event_handler, LIBTELNET_MODE_PROXY,
|
||||
&client);
|
||||
|
||||
/* initialize poll descriptors */
|
||||
memset(pfd, 0, sizeof(pfd));
|
||||
|
@ -348,7 +348,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, (void*)&server);
|
||||
libtelnet_push(&server.telnet, buffer, rs);
|
||||
} else if (rs == 0) {
|
||||
printf("%s DISCONNECTED" COLOR_NORMAL "\n", server.name);
|
||||
break;
|
||||
|
@ -362,7 +362,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, (void*)&client);
|
||||
libtelnet_push(&client.telnet, buffer, rs);
|
||||
} else if (rs == 0) {
|
||||
printf("%s DISCONNECTED" COLOR_NORMAL "\n", client.name);
|
||||
break;
|
||||
|
|
Loading…
Reference in New Issue