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
|
||||
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,
|
||||
unsigned char opt);
|
||||
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
|
||||
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,
|
||||
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:
|
||||
telnet_send_telopt(telnet, TELNET_SB, telopt);
|
||||
Note that this function is just a shorthand for:
|
||||
telnet_begin_subnegotiation(telnet, telopt);
|
||||
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
|
||||
data to be sent, it may be easier to manually send the SB telopt
|
||||
header and SE footer around mulitple calls to send_data.
|
||||
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.
|
||||
|
||||
NOTE: telnet_send_subnegotiation() does have special behavior in
|
||||
PROXY mode, as in that mode this function will automatically
|
||||
|
|
51
libtelnet.c
51
libtelnet.c
|
@ -22,6 +22,12 @@
|
|||
|
||||
#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 */
|
||||
#define RFC1143_NO 0x00
|
||||
#define RFC1143_YES 0x01
|
||||
|
@ -208,6 +214,13 @@ void _set_rfc1143(telnet_t *telnet, telnet_rfc1143_t 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 */
|
||||
static void _negotiate(telnet_t *telnet, unsigned char cmd,
|
||||
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) {
|
||||
q.him = RFC1143_YES;
|
||||
_set_rfc1143(telnet, q);
|
||||
telnet_send_telopt(telnet, TELNET_DO, telopt);
|
||||
_send_negotiate(telnet, TELNET_DO, telopt);
|
||||
} else
|
||||
telnet_send_telopt(telnet, TELNET_DONT, telopt);
|
||||
_send_negotiate(telnet, TELNET_DONT, telopt);
|
||||
break;
|
||||
case RFC1143_YES:
|
||||
break;
|
||||
|
@ -272,7 +285,7 @@ static void _negotiate(telnet_t *telnet, unsigned char cmd,
|
|||
case RFC1143_WANTYES_OP:
|
||||
q.him = RFC1143_WANTNO;
|
||||
_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);
|
||||
break;
|
||||
}
|
||||
|
@ -286,7 +299,7 @@ static void _negotiate(telnet_t *telnet, unsigned char cmd,
|
|||
case RFC1143_YES:
|
||||
q.him = RFC1143_NO;
|
||||
_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);
|
||||
break;
|
||||
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) {
|
||||
q.us = RFC1143_YES;
|
||||
_set_rfc1143(telnet, q);
|
||||
telnet_send_telopt(telnet, TELNET_WILL, telopt);
|
||||
_send_negotiate(telnet, TELNET_WILL, telopt);
|
||||
} else
|
||||
telnet_send_telopt(telnet, TELNET_WONT, telopt);
|
||||
_send_negotiate(telnet, TELNET_WONT, telopt);
|
||||
break;
|
||||
case RFC1143_YES:
|
||||
break;
|
||||
|
@ -342,7 +355,7 @@ static void _negotiate(telnet_t *telnet, unsigned char cmd,
|
|||
case RFC1143_WANTYES_OP:
|
||||
q.us = RFC1143_WANTNO;
|
||||
_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);
|
||||
break;
|
||||
}
|
||||
|
@ -356,7 +369,7 @@ static void _negotiate(telnet_t *telnet, unsigned char cmd,
|
|||
case RFC1143_YES:
|
||||
q.us = RFC1143_NO;
|
||||
_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);
|
||||
break;
|
||||
case RFC1143_WANTNO:
|
||||
|
@ -675,13 +688,6 @@ void telnet_send_command(telnet_t *telnet, unsigned char cmd) {
|
|||
_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 */
|
||||
void telnet_send_negotiate(telnet_t *telnet, unsigned char cmd,
|
||||
unsigned char telopt) {
|
||||
|
@ -704,7 +710,7 @@ void telnet_send_negotiate(telnet_t *telnet, unsigned char cmd,
|
|||
case RFC1143_NO:
|
||||
q.us = RFC1143_WANTYES;
|
||||
_set_rfc1143(telnet, q);
|
||||
telnet_send_telopt(telnet, TELNET_WILL, telopt);
|
||||
_send_negotiate(telnet, TELNET_WILL, telopt);
|
||||
break;
|
||||
case RFC1143_YES:
|
||||
break;
|
||||
|
@ -731,7 +737,7 @@ void telnet_send_negotiate(telnet_t *telnet, unsigned char cmd,
|
|||
case RFC1143_YES:
|
||||
q.us = RFC1143_WANTNO;
|
||||
_set_rfc1143(telnet, q);
|
||||
telnet_send_telopt(telnet, TELNET_WONT, telopt);
|
||||
_send_negotiate(telnet, TELNET_WONT, telopt);
|
||||
break;
|
||||
case RFC1143_WANTNO:
|
||||
break;
|
||||
|
@ -754,7 +760,7 @@ void telnet_send_negotiate(telnet_t *telnet, unsigned char cmd,
|
|||
case RFC1143_NO:
|
||||
q.him = RFC1143_WANTYES;
|
||||
_set_rfc1143(telnet, q);
|
||||
telnet_send_telopt(telnet, TELNET_DO, telopt);
|
||||
_send_negotiate(telnet, TELNET_DO, telopt);
|
||||
break;
|
||||
case RFC1143_YES:
|
||||
break;
|
||||
|
@ -781,7 +787,7 @@ void telnet_send_negotiate(telnet_t *telnet, unsigned char cmd,
|
|||
case RFC1143_YES:
|
||||
q.him = RFC1143_WANTNO;
|
||||
_set_rfc1143(telnet, q);
|
||||
telnet_send_telopt(telnet, TELNET_DONT, telopt);
|
||||
_send_negotiate(telnet, TELNET_DONT, telopt);
|
||||
break;
|
||||
case RFC1143_WANTNO:
|
||||
break;
|
||||
|
@ -826,9 +832,12 @@ void telnet_send_data(telnet_t *telnet, const char *buffer,
|
|||
/* send sub-request */
|
||||
void telnet_send_subnegotiation(telnet_t *telnet, unsigned char telopt,
|
||||
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_command(telnet, TELNET_SE);
|
||||
_send(telnet, se, 2);
|
||||
|
||||
#ifdef HAVE_ZLIB
|
||||
/* 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 */
|
||||
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 TELNET_IAC 255
|
||||
|
@ -147,12 +146,6 @@ struct telnet_event_t {
|
|||
unsigned char accept;
|
||||
};
|
||||
|
||||
/* option negotiation state (RFC 1143) */
|
||||
struct telnet_rfc1143_t {
|
||||
unsigned char telopt;
|
||||
char us:4, him:4;
|
||||
};
|
||||
|
||||
/* event handler declaration */
|
||||
typedef void (*telnet_event_handler_t)(telnet_t *telnet,
|
||||
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 */
|
||||
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.
|
||||
* will not actually send unless necessary, but will update internal
|
||||
* 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,
|
||||
const char *buffer, size_t size);
|
||||
|
||||
/* send sub-request, equivalent to:
|
||||
* telnet_send_telopt(telnet, TELNET_SB, telopt)
|
||||
/* send IAC SB followed by the telopt code */
|
||||
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_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.
|
||||
* telnet_finish_subnegotiation(telnet);
|
||||
*/
|
||||
extern void telnet_send_subnegotiation(telnet_t *telnet,
|
||||
unsigned char telopt, const char *buffer, size_t size);
|
||||
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 telnet_begin_compress2(telnet_t *telnet);
|
||||
|
|
Loading…
Reference in New Issue