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

View File

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

View File

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