mirror of https://gerrit.osmocom.org/libtelnet
remove telnet_send_telopt() as it has no real purpose and using it can have surprising results; added telnet_begin_subnegotiation and telnet_finish_subnegotiation
This commit is contained in:
parent
c0e9fcd165
commit
90e79da676
33
README
33
README
|
@ -112,11 +112,6 @@ IIc. Sending Data
|
||||||
Sends a single "simple" TELNET command, such as the GO-AHEAD
|
Sends a single "simple" TELNET command, such as the GO-AHEAD
|
||||||
commands (255 249).
|
commands (255 249).
|
||||||
|
|
||||||
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 telnet_send_negotiate(telnet_t *telnet, unsigned char cmd,
|
void telnet_send_negotiate(telnet_t *telnet, unsigned char cmd,
|
||||||
unsigned char opt);
|
unsigned char opt);
|
||||||
Sends a TELNET negotiation command. The cmd parameter must be one
|
Sends a TELNET negotiation command. The cmd parameter must be one
|
||||||
|
@ -135,20 +130,38 @@ IIc. Sending Data
|
||||||
|
|
||||||
For sending regular text is may be more convenient to use
|
For sending regular text is may be more convenient to use
|
||||||
telnet_printf().
|
telnet_printf().
|
||||||
|
|
||||||
|
void telnet_begin_subnegotiation(telnet_t *telnet, unsigned char
|
||||||
|
telopt);
|
||||||
|
Sends the header for a TELNET sub-negotiation command for the
|
||||||
|
specified option. All send data following this command will be
|
||||||
|
part of the sub-negotiation data until a call is made to
|
||||||
|
telnet_finish_subnegotiation().
|
||||||
|
|
||||||
|
You should not use telnet_printf() for sending subnegotiation
|
||||||
|
data as it will perform newline translations that usually do not
|
||||||
|
need to be done for subnegotiation data, and may cause problems.
|
||||||
|
|
||||||
|
void telnet_finish_subnegotiation(telnet_t *telnet);
|
||||||
|
Sends the end marker for a TELNET sub-negotiation command. This
|
||||||
|
must be called after (and only after) a call has been made to
|
||||||
|
telnet_begin_subnegotiation() and any negotiation data has been
|
||||||
|
sent.
|
||||||
|
|
||||||
void telnet_send_subnegotiation(telnet_t *telnet,
|
void telnet_send_subnegotiation(telnet_t *telnet,
|
||||||
unsigned char telopt, const char *buffer, unsigned int size);
|
unsigned char telopt, const char *buffer, unsigned int size);
|
||||||
Sends a TELNET sub-negotiation command. The telopt parameter is
|
Sends a TELNET sub-negotiation command. The telopt parameter is
|
||||||
the sub-negotiation option.
|
the sub-negotiation option.
|
||||||
|
|
||||||
Note that the above function is just a shorthand for:
|
Note that this function is just a shorthand for:
|
||||||
telnet_send_telopt(telnet, TELNET_SB, telopt);
|
telnet_begin_subnegotiation(telnet, telopt);
|
||||||
telnet_send_data(telnet, buffer, size);
|
telnet_send_data(telnet, buffer, size);
|
||||||
telnet_send_command(telnet, TELNET_SE);
|
telnet_end_subnegotiation(telnet);
|
||||||
|
|
||||||
For some subnegotiations that involve a lot of complex formatted
|
For some subnegotiations that involve a lot of complex formatted
|
||||||
data to be sent, it may be easier to manually send the SB telopt
|
data to be sent, it may be easier to make calls to both
|
||||||
header and SE footer around mulitple calls to send_data.
|
telnet_begin_negotiation() and telnet_end_subnegotiation() and
|
||||||
|
using telnet_send_data() or telnet_printf2() to format the data.
|
||||||
|
|
||||||
NOTE: telnet_send_subnegotiation() does have special behavior in
|
NOTE: telnet_send_subnegotiation() does have special behavior in
|
||||||
PROXY mode, as in that mode this function will automatically
|
PROXY mode, as in that mode this function will automatically
|
||||||
|
|
51
libtelnet.c
51
libtelnet.c
|
@ -22,6 +22,12 @@
|
||||||
|
|
||||||
#include "libtelnet.h"
|
#include "libtelnet.h"
|
||||||
|
|
||||||
|
/* RFC1143 option negotiation state */
|
||||||
|
typedef struct telnet_rfc1143_t {
|
||||||
|
unsigned char telopt;
|
||||||
|
char us:4, him:4;
|
||||||
|
} telnet_rfc1143_t;
|
||||||
|
|
||||||
/* RFC1143 state names */
|
/* RFC1143 state names */
|
||||||
#define RFC1143_NO 0x00
|
#define RFC1143_NO 0x00
|
||||||
#define RFC1143_YES 0x01
|
#define RFC1143_YES 0x01
|
||||||
|
@ -208,6 +214,13 @@ void _set_rfc1143(telnet_t *telnet, telnet_rfc1143_t q) {
|
||||||
telnet->q[telnet->q_size++] = q;
|
telnet->q[telnet->q_size++] = q;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* send negotiation bytes */
|
||||||
|
static void _send_negotiate(telnet_t *telnet, unsigned char cmd,
|
||||||
|
unsigned char telopt) {
|
||||||
|
char bytes[3] = { TELNET_IAC, cmd, telopt };
|
||||||
|
_send(telnet, bytes, 3);
|
||||||
|
}
|
||||||
|
|
||||||
/* negotiation handling magic for RFC1143 */
|
/* negotiation handling magic for RFC1143 */
|
||||||
static void _negotiate(telnet_t *telnet, unsigned char cmd,
|
static void _negotiate(telnet_t *telnet, unsigned char cmd,
|
||||||
unsigned char telopt) {
|
unsigned char telopt) {
|
||||||
|
@ -244,9 +257,9 @@ static void _negotiate(telnet_t *telnet, unsigned char cmd,
|
||||||
if (_event(telnet, TELNET_EV_WILL, cmd, telopt, 0, 0) == 1) {
|
if (_event(telnet, TELNET_EV_WILL, cmd, telopt, 0, 0) == 1) {
|
||||||
q.him = RFC1143_YES;
|
q.him = RFC1143_YES;
|
||||||
_set_rfc1143(telnet, q);
|
_set_rfc1143(telnet, q);
|
||||||
telnet_send_telopt(telnet, TELNET_DO, telopt);
|
_send_negotiate(telnet, TELNET_DO, telopt);
|
||||||
} else
|
} else
|
||||||
telnet_send_telopt(telnet, TELNET_DONT, telopt);
|
_send_negotiate(telnet, TELNET_DONT, telopt);
|
||||||
break;
|
break;
|
||||||
case RFC1143_YES:
|
case RFC1143_YES:
|
||||||
break;
|
break;
|
||||||
|
@ -272,7 +285,7 @@ static void _negotiate(telnet_t *telnet, unsigned char cmd,
|
||||||
case RFC1143_WANTYES_OP:
|
case RFC1143_WANTYES_OP:
|
||||||
q.him = RFC1143_WANTNO;
|
q.him = RFC1143_WANTNO;
|
||||||
_set_rfc1143(telnet, q);
|
_set_rfc1143(telnet, q);
|
||||||
telnet_send_telopt(telnet, TELNET_DONT, telopt);
|
_send_negotiate(telnet, TELNET_DONT, telopt);
|
||||||
_event(telnet, TELNET_EV_WILL, cmd, telopt, 0, 0);
|
_event(telnet, TELNET_EV_WILL, cmd, telopt, 0, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -286,7 +299,7 @@ static void _negotiate(telnet_t *telnet, unsigned char cmd,
|
||||||
case RFC1143_YES:
|
case RFC1143_YES:
|
||||||
q.him = RFC1143_NO;
|
q.him = RFC1143_NO;
|
||||||
_set_rfc1143(telnet, q);
|
_set_rfc1143(telnet, q);
|
||||||
telnet_send_telopt(telnet, TELNET_DONT, telopt);
|
_send_negotiate(telnet, TELNET_DONT, telopt);
|
||||||
_event(telnet, TELNET_EV_WONT, 0, telopt, 0, 0);
|
_event(telnet, TELNET_EV_WONT, 0, telopt, 0, 0);
|
||||||
break;
|
break;
|
||||||
case RFC1143_WANTNO:
|
case RFC1143_WANTNO:
|
||||||
|
@ -314,9 +327,9 @@ static void _negotiate(telnet_t *telnet, unsigned char cmd,
|
||||||
if (_event(telnet, TELNET_EV_DO, cmd, telopt, 0, 0) == 1) {
|
if (_event(telnet, TELNET_EV_DO, cmd, telopt, 0, 0) == 1) {
|
||||||
q.us = RFC1143_YES;
|
q.us = RFC1143_YES;
|
||||||
_set_rfc1143(telnet, q);
|
_set_rfc1143(telnet, q);
|
||||||
telnet_send_telopt(telnet, TELNET_WILL, telopt);
|
_send_negotiate(telnet, TELNET_WILL, telopt);
|
||||||
} else
|
} else
|
||||||
telnet_send_telopt(telnet, TELNET_WONT, telopt);
|
_send_negotiate(telnet, TELNET_WONT, telopt);
|
||||||
break;
|
break;
|
||||||
case RFC1143_YES:
|
case RFC1143_YES:
|
||||||
break;
|
break;
|
||||||
|
@ -342,7 +355,7 @@ static void _negotiate(telnet_t *telnet, unsigned char cmd,
|
||||||
case RFC1143_WANTYES_OP:
|
case RFC1143_WANTYES_OP:
|
||||||
q.us = RFC1143_WANTNO;
|
q.us = RFC1143_WANTNO;
|
||||||
_set_rfc1143(telnet, q);
|
_set_rfc1143(telnet, q);
|
||||||
telnet_send_telopt(telnet, TELNET_WONT, telopt);
|
_send_negotiate(telnet, TELNET_WONT, telopt);
|
||||||
_event(telnet, TELNET_EV_DO, cmd, telopt, 0, 0);
|
_event(telnet, TELNET_EV_DO, cmd, telopt, 0, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -356,7 +369,7 @@ static void _negotiate(telnet_t *telnet, unsigned char cmd,
|
||||||
case RFC1143_YES:
|
case RFC1143_YES:
|
||||||
q.us = RFC1143_NO;
|
q.us = RFC1143_NO;
|
||||||
_set_rfc1143(telnet, q);
|
_set_rfc1143(telnet, q);
|
||||||
telnet_send_telopt(telnet, TELNET_WONT, telopt);
|
_send_negotiate(telnet, TELNET_WONT, telopt);
|
||||||
_event(telnet, TELNET_EV_DONT, 0, telopt, 0, 0);
|
_event(telnet, TELNET_EV_DONT, 0, telopt, 0, 0);
|
||||||
break;
|
break;
|
||||||
case RFC1143_WANTNO:
|
case RFC1143_WANTNO:
|
||||||
|
@ -675,13 +688,6 @@ void telnet_send_command(telnet_t *telnet, unsigned char cmd) {
|
||||||
_send(telnet, bytes, 2);
|
_send(telnet, bytes, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* send an iac command with telopt */
|
|
||||||
void telnet_send_telopt(telnet_t *telnet, unsigned char cmd,
|
|
||||||
unsigned char telopt) {
|
|
||||||
char bytes[3] = { TELNET_IAC, cmd, telopt };
|
|
||||||
_send(telnet, bytes, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* send negotiation */
|
/* send negotiation */
|
||||||
void telnet_send_negotiate(telnet_t *telnet, unsigned char cmd,
|
void telnet_send_negotiate(telnet_t *telnet, unsigned char cmd,
|
||||||
unsigned char telopt) {
|
unsigned char telopt) {
|
||||||
|
@ -704,7 +710,7 @@ void telnet_send_negotiate(telnet_t *telnet, unsigned char cmd,
|
||||||
case RFC1143_NO:
|
case RFC1143_NO:
|
||||||
q.us = RFC1143_WANTYES;
|
q.us = RFC1143_WANTYES;
|
||||||
_set_rfc1143(telnet, q);
|
_set_rfc1143(telnet, q);
|
||||||
telnet_send_telopt(telnet, TELNET_WILL, telopt);
|
_send_negotiate(telnet, TELNET_WILL, telopt);
|
||||||
break;
|
break;
|
||||||
case RFC1143_YES:
|
case RFC1143_YES:
|
||||||
break;
|
break;
|
||||||
|
@ -731,7 +737,7 @@ void telnet_send_negotiate(telnet_t *telnet, unsigned char cmd,
|
||||||
case RFC1143_YES:
|
case RFC1143_YES:
|
||||||
q.us = RFC1143_WANTNO;
|
q.us = RFC1143_WANTNO;
|
||||||
_set_rfc1143(telnet, q);
|
_set_rfc1143(telnet, q);
|
||||||
telnet_send_telopt(telnet, TELNET_WONT, telopt);
|
_send_negotiate(telnet, TELNET_WONT, telopt);
|
||||||
break;
|
break;
|
||||||
case RFC1143_WANTNO:
|
case RFC1143_WANTNO:
|
||||||
break;
|
break;
|
||||||
|
@ -754,7 +760,7 @@ void telnet_send_negotiate(telnet_t *telnet, unsigned char cmd,
|
||||||
case RFC1143_NO:
|
case RFC1143_NO:
|
||||||
q.him = RFC1143_WANTYES;
|
q.him = RFC1143_WANTYES;
|
||||||
_set_rfc1143(telnet, q);
|
_set_rfc1143(telnet, q);
|
||||||
telnet_send_telopt(telnet, TELNET_DO, telopt);
|
_send_negotiate(telnet, TELNET_DO, telopt);
|
||||||
break;
|
break;
|
||||||
case RFC1143_YES:
|
case RFC1143_YES:
|
||||||
break;
|
break;
|
||||||
|
@ -781,7 +787,7 @@ void telnet_send_negotiate(telnet_t *telnet, unsigned char cmd,
|
||||||
case RFC1143_YES:
|
case RFC1143_YES:
|
||||||
q.him = RFC1143_WANTNO;
|
q.him = RFC1143_WANTNO;
|
||||||
_set_rfc1143(telnet, q);
|
_set_rfc1143(telnet, q);
|
||||||
telnet_send_telopt(telnet, TELNET_DONT, telopt);
|
_send_negotiate(telnet, TELNET_DONT, telopt);
|
||||||
break;
|
break;
|
||||||
case RFC1143_WANTNO:
|
case RFC1143_WANTNO:
|
||||||
break;
|
break;
|
||||||
|
@ -826,9 +832,12 @@ void telnet_send_data(telnet_t *telnet, const char *buffer,
|
||||||
/* send sub-request */
|
/* send sub-request */
|
||||||
void telnet_send_subnegotiation(telnet_t *telnet, unsigned char telopt,
|
void telnet_send_subnegotiation(telnet_t *telnet, unsigned char telopt,
|
||||||
const char *buffer, size_t size) {
|
const char *buffer, size_t size) {
|
||||||
telnet_send_telopt(telnet, TELNET_SB, telopt);
|
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_data(telnet, buffer, size);
|
||||||
telnet_send_command(telnet, TELNET_SE);
|
_send(telnet, se, 2);
|
||||||
|
|
||||||
#ifdef HAVE_ZLIB
|
#ifdef HAVE_ZLIB
|
||||||
/* if we're a proxy and we just sent the COMPRESS2 marker, we must
|
/* if we're a proxy and we just sent the COMPRESS2 marker, we must
|
||||||
|
|
32
libtelnet.h
32
libtelnet.h
|
@ -15,7 +15,6 @@
|
||||||
/* forward declarations */
|
/* forward declarations */
|
||||||
typedef struct telnet_t telnet_t;
|
typedef struct telnet_t telnet_t;
|
||||||
typedef struct telnet_event_t telnet_event_t;
|
typedef struct telnet_event_t telnet_event_t;
|
||||||
typedef struct telnet_rfc1143_t telnet_rfc1143_t;
|
|
||||||
|
|
||||||
/* telnet special values */
|
/* telnet special values */
|
||||||
#define TELNET_IAC 255
|
#define TELNET_IAC 255
|
||||||
|
@ -147,12 +146,6 @@ struct telnet_event_t {
|
||||||
unsigned char accept;
|
unsigned char accept;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* option negotiation state (RFC 1143) */
|
|
||||||
struct telnet_rfc1143_t {
|
|
||||||
unsigned char telopt;
|
|
||||||
char us:4, him:4;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* event handler declaration */
|
/* event handler declaration */
|
||||||
typedef void (*telnet_event_handler_t)(telnet_t *telnet,
|
typedef void (*telnet_event_handler_t)(telnet_t *telnet,
|
||||||
telnet_event_t *event, void *user_data);
|
telnet_event_t *event, void *user_data);
|
||||||
|
@ -199,10 +192,6 @@ extern void telnet_push(telnet_t *telnet, const char *buffer,
|
||||||
/* send an iac command */
|
/* send an iac command */
|
||||||
extern void telnet_send_command(telnet_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 telnet_send_telopt(telnet_t *telnet, unsigned char cmd,
|
|
||||||
unsigned char telopt);
|
|
||||||
|
|
||||||
/* send negotiation, with RFC1143 checking.
|
/* send negotiation, with RFC1143 checking.
|
||||||
* will not actually send unless necessary, but will update internal
|
* will not actually send unless necessary, but will update internal
|
||||||
* negotiation queue.
|
* negotiation queue.
|
||||||
|
@ -214,15 +203,22 @@ extern void telnet_send_negotiate(telnet_t *telnet, unsigned char cmd,
|
||||||
extern void telnet_send_data(telnet_t *telnet,
|
extern void telnet_send_data(telnet_t *telnet,
|
||||||
const char *buffer, size_t size);
|
const char *buffer, size_t size);
|
||||||
|
|
||||||
/* send sub-request, equivalent to:
|
/* send IAC SB followed by the telopt code */
|
||||||
* telnet_send_telopt(telnet, TELNET_SB, telopt)
|
extern void telnet_begin_subnegotiation(telnet_t *telnet,
|
||||||
|
unsigned char telopt);
|
||||||
|
|
||||||
|
/* send IAC SE */
|
||||||
|
#define telnet_finish_subnegotiation(telnet) \
|
||||||
|
telnet_command((telnet), TELNET_SE)
|
||||||
|
|
||||||
|
/* shortcut for sending a complete subnegotiation buffer.
|
||||||
|
* equivalent to:
|
||||||
|
* telnet_begin_subnegotiation(telnet, telopt);
|
||||||
* telnet_send_data(telnet, buffer, size);
|
* telnet_send_data(telnet, buffer, size);
|
||||||
* telnet_send_command(telnet, TELNET_SE);
|
* telnet_finish_subnegotiation(telnet);
|
||||||
* manually generating sequence may be easier for complex subnegotiations
|
|
||||||
* thare are most easily implemented with a series of send_data calls.
|
|
||||||
*/
|
*/
|
||||||
extern void telnet_send_subnegotiation(telnet_t *telnet,
|
extern void telnet_send_subnegotiation(telnet_t *telnet, unsigned char telopt,
|
||||||
unsigned char telopt, const char *buffer, size_t size);
|
const char *buffer, size_t size);
|
||||||
|
|
||||||
/* begin sending compressed data (server only) */
|
/* begin sending compressed data (server only) */
|
||||||
extern void telnet_begin_compress2(telnet_t *telnet);
|
extern void telnet_begin_compress2(telnet_t *telnet);
|
||||||
|
|
Loading…
Reference in New Issue