mirror of https://gerrit.osmocom.org/libtelnet
shorten the output function names to something more reasonable
This commit is contained in:
parent
9b07e92022
commit
4f0c37fc1b
52
README
52
README
|
@ -18,11 +18,14 @@ code under copyright law.
|
|||
|
||||
*** TODO ***
|
||||
|
||||
- automatic MCCP2 handling (controllable by host app)
|
||||
- the negotiate callback behavior needs to be redone so that the
|
||||
app immediately confirms; right now if you set ev->accept=1 when
|
||||
receiving a request to enable you can't immediately start sending
|
||||
ubnegotiations because the confirmation hasn't been sent yet. :/
|
||||
? ZMP parsing
|
||||
? MSSP parsing
|
||||
? TTYPE parsing
|
||||
? ENVIRON/NEW-ENVIRON parsing
|
||||
? telnet-status testing tool
|
||||
|
||||
I. INTRODUCTION
|
||||
=====================================================================
|
||||
|
@ -43,7 +46,7 @@ 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 telnet
|
||||
processor. The third part is the telnet_send_*() functions, which
|
||||
processor. The third part is the libtelnet output functions, which
|
||||
generate TELNET commands and ensure data is properly formatted before
|
||||
sending over the wire. The final part is the event handler
|
||||
interface.
|
||||
|
@ -86,7 +89,7 @@ IIa. Initialization
|
|||
|
||||
IIb. Receiving Data
|
||||
|
||||
void telnet_push(telnet_t *telnet,
|
||||
void telnet_recv(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.
|
||||
|
@ -99,8 +102,7 @@ IIb. Receiving Data
|
|||
|
||||
IIc. Sending Data
|
||||
|
||||
All of the telnet_send_*() functions will invoke the TELNET_EV_SEND
|
||||
event.
|
||||
All of the output 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,11 +110,11 @@ IIc. Sending Data
|
|||
to one of the following functions. Do NOT send or buffer
|
||||
unprocessed output data directly!
|
||||
|
||||
void telnet_send_command(telnet_t *telnet, unsigned char cmd);
|
||||
void telnet_iac(telnet_t *telnet, unsigned char cmd);
|
||||
Sends a single "simple" TELNET command, such as the GO-AHEAD
|
||||
commands (255 249).
|
||||
|
||||
void telnet_send_negotiate(telnet_t *telnet, unsigned char cmd,
|
||||
void telnet_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
|
||||
|
@ -123,8 +125,7 @@ IIc. Sending Data
|
|||
invocations, such as asking for WILL NAWS when NAWS is already on
|
||||
or is currently awaiting response from the remote end.
|
||||
|
||||
void telnet_send_data(telnet_t *telnet, const char *buffer,
|
||||
unsigned int size);
|
||||
void telnet_send(telnet_t *telnet, const char *buffer, size_t size);
|
||||
Sends raw data, which would be either the process output from a
|
||||
server or the user input from a client.
|
||||
|
||||
|
@ -148,22 +149,22 @@ IIc. Sending Data
|
|||
telnet_begin_subnegotiation() and any negotiation data has been
|
||||
sent.
|
||||
|
||||
void telnet_send_subnegotiation(telnet_t *telnet,
|
||||
unsigned char telopt, const char *buffer, unsigned int size);
|
||||
void telnet_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 this function is just a shorthand for:
|
||||
telnet_begin_subnegotiation(telnet, telopt);
|
||||
telnet_send_data(telnet, buffer, size);
|
||||
telnet_end_subnegotiation(telnet);
|
||||
telnet_begin_sb(telnet, telopt);
|
||||
telnet_send(telnet, buffer, size);
|
||||
telnet_end_sb(telnet);
|
||||
|
||||
For some subnegotiations that involve a lot of complex formatted
|
||||
data to be sent, it may be easier to make calls to both
|
||||
telnet_begin_negotiation() and telnet_end_subnegotiation() and
|
||||
using telnet_send_data() or telnet_printf2() to format the data.
|
||||
telnet_begin_sb() and telnet_finish_sb() and using telnet_send()
|
||||
or telnet_printf2() to format the data.
|
||||
|
||||
NOTE: telnet_send_subnegotiation() does have special behavior in
|
||||
NOTE: telnet_subnegotiation() does have special behavior in
|
||||
PROXY mode, as in that mode this function will automatically
|
||||
detect the COMPRESS2 marker and enable zlib compression.
|
||||
|
||||
|
@ -414,20 +415,19 @@ 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 telnet_send_*() family of
|
||||
functions for all data being sent over the TELNET connection.
|
||||
of libtelnet always make use of the libtelnet output 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 telnet_send_data(). This also includes any input
|
||||
passed through to telnet_send(). 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
|
||||
telnet_send_data().
|
||||
telnet_send().
|
||||
|
||||
Any TELNET commands that are to be sent must be given to one of the
|
||||
following: telnet_send_command, telnet_send_negotiate, or
|
||||
telnet_send_subnegotiation().
|
||||
following: telnet_iac, telnet_negotiate, or telnet_subnegotiation().
|
||||
|
||||
If you are attempting to enable COMPRESS2/MCCP2, you must use the
|
||||
telnet_begin_compress2() function.
|
||||
|
@ -447,9 +447,9 @@ zlib shared library.
|
|||
|
||||
libtelnet transparently supports MCCP2. For a server to support
|
||||
MCCP2, the application must begin negotiation of the COMPRESS2 option
|
||||
using telnet_send_negotiate(), for example:
|
||||
using telnet_negotiate(), for example:
|
||||
|
||||
telnet_send_negotiate(&telnet, TELNET_WILL,
|
||||
telnet_negotiate(&telnet, TELNET_WILL,
|
||||
TELNET_OPTION_COMPRESS2, user_data);
|
||||
|
||||
If a favorable DO COMPRESS2 is sent back from the client then the
|
||||
|
|
22
libtelnet.c
22
libtelnet.c
|
@ -591,12 +591,12 @@ static void _process(telnet_t *telnet, const char *buffer,
|
|||
_event(telnet, TELNET_EV_COMPRESS, 1, 0, 0, 0);
|
||||
|
||||
/* any remaining bytes in the buffer are compressed.
|
||||
* we have to re-invoke telnet_push to get those
|
||||
* we have to re-invoke telnet_recv to get those
|
||||
* bytes inflated and abort trying to process the
|
||||
* remaining compressed bytes in the current _process
|
||||
* buffer argument
|
||||
*/
|
||||
telnet_push(telnet, &buffer[start], size - start);
|
||||
telnet_recv(telnet, &buffer[start], size - start);
|
||||
return;
|
||||
}
|
||||
#endif /* HAVE_ZLIB */
|
||||
|
@ -632,7 +632,7 @@ static void _process(telnet_t *telnet, const char *buffer,
|
|||
}
|
||||
|
||||
/* push a bytes into the state tracker */
|
||||
void telnet_push(telnet_t *telnet, const char *buffer,
|
||||
void telnet_recv(telnet_t *telnet, const char *buffer,
|
||||
size_t size) {
|
||||
#ifdef HAVE_ZLIB
|
||||
/* if we have an inflate (decompression) zlib stream, use it */
|
||||
|
@ -683,13 +683,13 @@ void telnet_push(telnet_t *telnet, const char *buffer,
|
|||
}
|
||||
|
||||
/* send an iac command */
|
||||
void telnet_send_command(telnet_t *telnet, unsigned char cmd) {
|
||||
void telnet_iac(telnet_t *telnet, unsigned char cmd) {
|
||||
char bytes[2] = { TELNET_IAC, cmd };
|
||||
_send(telnet, bytes, 2);
|
||||
}
|
||||
|
||||
/* send negotiation */
|
||||
void telnet_send_negotiate(telnet_t *telnet, unsigned char cmd,
|
||||
void telnet_negotiate(telnet_t *telnet, unsigned char cmd,
|
||||
unsigned char telopt) {
|
||||
telnet_rfc1143_t q;
|
||||
|
||||
|
@ -783,7 +783,7 @@ void telnet_send_negotiate(telnet_t *telnet, unsigned char cmd,
|
|||
}
|
||||
|
||||
/* send non-command data (escapes IAC bytes) */
|
||||
void telnet_send_data(telnet_t *telnet, const char *buffer,
|
||||
void telnet_send(telnet_t *telnet, const char *buffer,
|
||||
size_t size) {
|
||||
size_t i, l;
|
||||
|
||||
|
@ -796,7 +796,7 @@ void telnet_send_data(telnet_t *telnet, const char *buffer,
|
|||
l = i + 1;
|
||||
|
||||
/* send escape */
|
||||
telnet_send_command(telnet, TELNET_IAC);
|
||||
telnet_iac(telnet, TELNET_IAC);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -813,13 +813,13 @@ void telnet_begin_subnegotiation(telnet_t *telnet, unsigned char telopt) {
|
|||
|
||||
|
||||
/* send complete subnegotiation */
|
||||
void telnet_send_subnegotiation(telnet_t *telnet, unsigned char telopt,
|
||||
void telnet_subnegotiation(telnet_t *telnet, unsigned char telopt,
|
||||
const char *buffer, size_t size) {
|
||||
const char sb[3] = { TELNET_IAC, TELNET_SB, telopt };
|
||||
static const char se[2] = { TELNET_IAC, TELNET_SE };
|
||||
|
||||
_send(telnet, sb, 3);
|
||||
telnet_send_data(telnet, buffer, size);
|
||||
telnet_send(telnet, buffer, size);
|
||||
_send(telnet, se, 2);
|
||||
|
||||
#ifdef HAVE_ZLIB
|
||||
|
@ -883,7 +883,7 @@ int telnet_printf(telnet_t *telnet, const char *fmt, ...) {
|
|||
|
||||
/* IAC -> IAC IAC */
|
||||
if (buffer[i] == TELNET_IAC)
|
||||
telnet_send_command(telnet, TELNET_IAC);
|
||||
telnet_iac(telnet, TELNET_IAC);
|
||||
/* automatic translation of \r -> CRNUL */
|
||||
else if (buffer[i] == '\r')
|
||||
_send(telnet, CRNUL, 2);
|
||||
|
@ -912,7 +912,7 @@ int telnet_printf2(telnet_t *telnet, const char *fmt, ...) {
|
|||
va_end(va);
|
||||
|
||||
/* send */
|
||||
telnet_send_data(telnet, (char *)buffer, rs);
|
||||
telnet_send(telnet, (char *)buffer, rs);
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
|
21
libtelnet.h
21
libtelnet.h
|
@ -186,38 +186,37 @@ extern void telnet_init(telnet_t *telnet, telnet_event_handler_t eh,
|
|||
extern void telnet_free(telnet_t *telnet);
|
||||
|
||||
/* push a byte buffer into the state tracker */
|
||||
extern void telnet_push(telnet_t *telnet, const char *buffer,
|
||||
extern void telnet_recv(telnet_t *telnet, const char *buffer,
|
||||
size_t size);
|
||||
|
||||
/* send an iac command */
|
||||
extern void telnet_send_command(telnet_t *telnet, unsigned char cmd);
|
||||
extern void telnet_iac(telnet_t *telnet, unsigned char cmd);
|
||||
|
||||
/* send negotiation, with RFC1143 checking.
|
||||
* will not actually send unless necessary, but will update internal
|
||||
* negotiation queue.
|
||||
*/
|
||||
extern void telnet_send_negotiate(telnet_t *telnet, unsigned char cmd,
|
||||
extern void telnet_negotiate(telnet_t *telnet, unsigned char cmd,
|
||||
unsigned char opt);
|
||||
|
||||
/* send non-command data (escapes IAC bytes) */
|
||||
extern void telnet_send_data(telnet_t *telnet,
|
||||
extern void telnet_send(telnet_t *telnet,
|
||||
const char *buffer, size_t size);
|
||||
|
||||
/* send IAC SB followed by the telopt code */
|
||||
extern void telnet_begin_subnegotiation(telnet_t *telnet,
|
||||
extern void telnet_begin_sb(telnet_t *telnet,
|
||||
unsigned char telopt);
|
||||
|
||||
/* send IAC SE */
|
||||
#define telnet_finish_subnegotiation(telnet) \
|
||||
telnet_send_command((telnet), TELNET_SE)
|
||||
#define telnet_finish_sb(telnet) telnet_iac((telnet), TELNET_SE)
|
||||
|
||||
/* shortcut for sending a complete subnegotiation buffer.
|
||||
* equivalent to:
|
||||
* telnet_begin_subnegotiation(telnet, telopt);
|
||||
* telnet_send_data(telnet, buffer, size);
|
||||
* telnet_finish_subnegotiation(telnet);
|
||||
* telnet_begin_sb(telnet, telopt);
|
||||
* telnet_send(telnet, buffer, size);
|
||||
* telnet_finish_sb(telnet);
|
||||
*/
|
||||
extern void telnet_send_subnegotiation(telnet_t *telnet, unsigned char telopt,
|
||||
extern void telnet_subnegotiation(telnet_t *telnet, unsigned char telopt,
|
||||
const char *buffer, size_t size);
|
||||
|
||||
/* begin sending compressed data (server only) */
|
||||
|
|
|
@ -292,7 +292,7 @@ int main(int argc, char **argv) {
|
|||
/* init, welcome */
|
||||
users[i].sock = rs;
|
||||
telnet_init(&users[i].telnet, _event_handler, 0, &users[i]);
|
||||
telnet_send_negotiate(&users[i].telnet, TELNET_WILL,
|
||||
telnet_negotiate(&users[i].telnet, TELNET_WILL,
|
||||
TELNET_TELOPT_COMPRESS2);
|
||||
telnet_printf(&users[i].telnet, "Enter name: ");
|
||||
}
|
||||
|
@ -305,7 +305,7 @@ int main(int argc, char **argv) {
|
|||
|
||||
if (pfd[i].revents & POLLIN) {
|
||||
if ((rs = recv(users[i].sock, buffer, sizeof(buffer), 0)) > 0) {
|
||||
telnet_push(&users[i].telnet, buffer, rs);
|
||||
telnet_recv(&users[i].telnet, buffer, rs);
|
||||
} else if (rs == 0) {
|
||||
printf("Connection closed.\n");
|
||||
close(users[i].sock);
|
||||
|
|
|
@ -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);
|
||||
telnet_send_data(&telnet, crlf, 2);
|
||||
telnet_send(&telnet, crlf, 2);
|
||||
} else {
|
||||
if (do_echo)
|
||||
write(STDOUT_FILENO, buffer + i, 1);
|
||||
telnet_send_data(&telnet, buffer + i, 1);
|
||||
telnet_send(&telnet, buffer + i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -126,8 +126,8 @@ static void _event_handler(telnet_t *telnet, telnet_event_t *ev,
|
|||
char buffer[64];
|
||||
buffer[0] = 0; /* IS code for RFC 1091 */
|
||||
snprintf(buffer + 1, sizeof(buffer) - 1, "%s", getenv("TERM"));
|
||||
telnet_send_subnegotiation(telnet, TELNET_TELOPT_TTYPE,
|
||||
(char *)buffer, 1 + strlen(buffer + 1));
|
||||
telnet_subnegotiation(telnet, TELNET_TELOPT_TTYPE, buffer,
|
||||
1 + strlen(buffer + 1));
|
||||
}
|
||||
break;
|
||||
/* error */
|
||||
|
@ -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) {
|
||||
telnet_push(&telnet, buffer, rs);
|
||||
telnet_recv(&telnet, buffer, rs);
|
||||
} else if (rs == 0) {
|
||||
break;
|
||||
} else {
|
||||
|
|
|
@ -176,7 +176,7 @@ static void _event_handler(telnet_t *telnet, telnet_event_t *ev,
|
|||
print_buffer(ev->buffer, ev->size);
|
||||
printf(COLOR_NORMAL "\n");
|
||||
|
||||
telnet_send_data(&conn->remote->telnet, ev->buffer, ev->size);
|
||||
telnet_send(&conn->remote->telnet, ev->buffer, ev->size);
|
||||
break;
|
||||
/* data must be sent */
|
||||
case TELNET_EV_SEND:
|
||||
|
@ -193,33 +193,33 @@ static void _event_handler(telnet_t *telnet, telnet_event_t *ev,
|
|||
printf("%s IAC %s" COLOR_NORMAL "\n", conn->name,
|
||||
get_cmd(ev->command));
|
||||
|
||||
telnet_send_command(&conn->remote->telnet, ev->command);
|
||||
telnet_iac(&conn->remote->telnet, ev->command);
|
||||
break;
|
||||
/* negotiation, WILL */
|
||||
case TELNET_EV_WILL:
|
||||
printf("%s IAC WILL %d (%s)" COLOR_NORMAL "\n", conn->name,
|
||||
(int)ev->telopt, get_opt(ev->telopt));
|
||||
telnet_send_negotiate(&conn->remote->telnet, TELNET_WILL,
|
||||
telnet_negotiate(&conn->remote->telnet, TELNET_WILL,
|
||||
ev->telopt);
|
||||
break;
|
||||
/* negotiation, WONT */
|
||||
case TELNET_EV_WONT:
|
||||
printf("%s IAC WONT %d (%s)" COLOR_NORMAL "\n", conn->name,
|
||||
(int)ev->telopt, get_opt(ev->telopt));
|
||||
telnet_send_negotiate(&conn->remote->telnet, TELNET_WONT,
|
||||
telnet_negotiate(&conn->remote->telnet, TELNET_WONT,
|
||||
ev->telopt);
|
||||
break;
|
||||
/* negotiation, DO */
|
||||
case TELNET_EV_DO:
|
||||
printf("%s IAC DO %d (%s)" COLOR_NORMAL "\n", conn->name,
|
||||
(int)ev->telopt, get_opt(ev->telopt));
|
||||
telnet_send_negotiate(&conn->remote->telnet, TELNET_DO,
|
||||
telnet_negotiate(&conn->remote->telnet, TELNET_DO,
|
||||
ev->telopt);
|
||||
break;
|
||||
case TELNET_EV_DONT:
|
||||
printf("%s IAC DONT %d (%s)" COLOR_NORMAL "\n", conn->name,
|
||||
(int)ev->telopt, get_opt(ev->telopt));
|
||||
telnet_send_negotiate(&conn->remote->telnet, TELNET_DONT,
|
||||
telnet_negotiate(&conn->remote->telnet, TELNET_DONT,
|
||||
ev->telopt);
|
||||
break;
|
||||
/* subnegotiation */
|
||||
|
@ -232,7 +232,7 @@ static void _event_handler(telnet_t *telnet, telnet_event_t *ev,
|
|||
}
|
||||
printf(COLOR_NORMAL "\n");
|
||||
|
||||
telnet_send_subnegotiation(&conn->remote->telnet, ev->telopt,
|
||||
telnet_subnegotiation(&conn->remote->telnet, ev->telopt,
|
||||
ev->buffer, ev->size);
|
||||
break;
|
||||
/* compression notification */
|
||||
|
@ -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) {
|
||||
telnet_push(&server.telnet, buffer, rs);
|
||||
telnet_recv(&server.telnet, buffer, rs);
|
||||
} else if (rs == 0) {
|
||||
printf("%s DISCONNECTED" COLOR_NORMAL "\n", server.name);
|
||||
break;
|
||||
|
@ -390,7 +390,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) {
|
||||
telnet_push(&client.telnet, buffer, rs);
|
||||
telnet_recv(&client.telnet, buffer, rs);
|
||||
} else if (rs == 0) {
|
||||
printf("%s DISCONNECTED" COLOR_NORMAL "\n", client.name);
|
||||
break;
|
||||
|
|
Loading…
Reference in New Issue