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:
Sean Middleditch 2009-03-19 15:17:13 -04:00
parent c0e9fcd165
commit 90e79da676
3 changed files with 67 additions and 49 deletions

33
README
View File

@ -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

View File

@ -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

View File

@ -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);