From bfc641efb17d8975b985cff4e400502782770050 Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Sun, 22 Mar 2009 16:26:06 -0400 Subject: [PATCH] clean up and document the telopt table stuff --- README | 55 ++++++++++++++++++++++++++++++++++++++++++------- libtelnet.c | 13 +++++++++--- libtelnet.h | 6 +++--- telnet-chatd.c | 8 ++++++- telnet-client.c | 6 +++--- 5 files changed, 71 insertions(+), 17 deletions(-) diff --git a/README b/README index 1c56b94..19da318 100644 --- a/README +++ b/README @@ -53,19 +53,60 @@ interface. IIa. Initialization - struct telnet_t; - This structure represents the state of the TELNET protocol for a - single connection. Each connection utilizing TELNET must have its - own telnet_t structure, which is passed to all libtelnet API - calls. + Using libtelnet requires the initialization of a telnet_t structure + which stores all current state for a single TELNET connection. - void telnet_init(telnet_t *telnet, telnet_event_handler_t handler, - unsigned char flags, void *user_data); + Initializing a telnet_t structure requires several pieces of data. + One of these is the telopt support table, which specifies which + TELNET options your application supports both locally and remotely. + This table is comprised of telnet_telopt_t structures, one for each + supported option. Each entry specifies the option supported, + whether the option is supported locally or remotely. + + struct telnet_telopt_t { + short telopt; + unsigned char us; + unsigned char him; + }; + + The us field denotes whether your application supporst the telopt + locally. It should be set to TELNET_WILL if you support it and to + TELNET_WONT if you don't. The him field denotes whether the telopt + is supported on the remote end, and should be TELNET_DO if yes and + TELNET_DONT if not. + + When definition the telopt table you must include an end marker + entry, which is simply an entry with telopt set to -1. For + example: + + static const telnet_telopt_t my_telopts[] = { + { TELNET_TELOPT_ECHO, TELNET_WILL, TELNET_DONT }, + { TELNET_TELOPT_TTYPE, TELNET_WILL, TELNET_DONT }, + { TELNET_TELOPT_COMPRESS2, TELNET_WONT, TELNET_DO }, + { TELNET_TELOPT_ZMP, TELNET_WONT, TELNET_DO }, + { TELNET_TELOPT_MSSP, TELNET_WONT, TELNET_DO }, + { TELNET_TELOPT_BINARY, TELNET_WILL, TELNET_DO }, + { TELNET_TELOPT_NAWS, TELNET_WILL, TELNET_DONT }, + { -1, 0, 0 } + }; + + If you need to dynamically alter supported options on a + per-connection basis then you may use a different tables + (dynamically allocated if necessary) per call to telnet_init() or + you share a single constant table like the above example between + all connections if you support a fixed set of options. Most + applications will support only a fixed set of options. + + void telnet_init(telnet_t *telnet, const telnet_telopts_t *telopts, + telnet_event_handler_t handler, unsigned char flags, + void *user_data); The telnet_init() function is responsible for initializing the data in a telnet_t structure. It must be called immediately after establishing a connection and before any other libtelnet API calls are made. + The telopts field is the telopt support table as described above. + The handler parameter must be a function matching the telnet_event_handler_t definition. More information about events can be found in section IId. diff --git a/libtelnet.c b/libtelnet.c index 4559385..381e8c3 100644 --- a/libtelnet.c +++ b/libtelnet.c @@ -188,9 +188,16 @@ static INLINE int _check_telopt(telnet_t *telnet, unsigned char telopt, return 0; /* loop unti found or end marker (us and him both 0) */ - for (i = 0; telnet->telopts[i].telopt != -1; ++i) - if (telnet->telopts[i].telopt == telopt) - return us ? telnet->telopts[i].us : telnet->telopts[i].him; + for (i = 0; telnet->telopts[i].telopt != -1; ++i) { + if (telnet->telopts[i].telopt == telopt) { + if (us && telnet->telopts[i].us == TELNET_WILL) + return 1; + else if (!us && telnet->telopts[i].him == TELNET_DO) + return 1; + else + return 0; + } + } /* not found, so not supported */ return 0; diff --git a/libtelnet.h b/libtelnet.h index c9f2583..a6f4dcd 100644 --- a/libtelnet.h +++ b/libtelnet.h @@ -24,7 +24,6 @@ typedef struct telnet_telopt_t telnet_telopt_t; #define TELNET_WONT 252 #define TELNET_WILL 251 #define TELNET_SB 250 -#define TELNET_SB 250 #define TELNET_GA 249 #define TELNET_EL 248 #define TELNET_EC 247 @@ -153,8 +152,9 @@ typedef void (*telnet_event_handler_t)(telnet_t *telnet, /* telopt support table element; use telopt of -1 for end marker */ struct telnet_telopt_t { - short telopt; - short us:1, him:1; + short telopt; /* one of the TELOPT codes or -1 */ + unsigned char us; /* TELNET_WILL or TELNET_WONT */ + unsigned char him; /* TELNET_DO or TELNET_DONT */ }; /* state tracker */ diff --git a/telnet-chatd.c b/telnet-chatd.c index 5d1813a..aa56e63 100644 --- a/telnet-chatd.c +++ b/telnet-chatd.c @@ -29,6 +29,11 @@ #define MAX_USERS 64 #define LINEBUFFER_SIZE 256 +const telnet_telopt_t telopts[] = { + { TELNET_TELOPT_COMPRESS2, TELNET_WILL, TELNET_DONT }, + { -1, 0, 0 } +}; + struct user_t { char *name; int sock; @@ -291,7 +296,8 @@ int main(int argc, char **argv) { /* init, welcome */ users[i].sock = rs; - telnet_init(&users[i].telnet, 0, _event_handler, 0, &users[i]); + telnet_init(&users[i].telnet, telopts, _event_handler, 0, + &users[i]); telnet_negotiate(&users[i].telnet, TELNET_WILL, TELNET_TELOPT_COMPRESS2); telnet_printf(&users[i].telnet, "Enter name: "); diff --git a/telnet-client.c b/telnet-client.c index 26cfaa8..f380cd3 100644 --- a/telnet-client.c +++ b/telnet-client.c @@ -33,9 +33,9 @@ static telnet_t telnet; static int do_echo; static const telnet_telopt_t telopts[] = { - { TELNET_TELOPT_ECHO, 0, 1 }, - { TELNET_TELOPT_COMPRESS2, 0, 1 }, - { TELNET_TELOPT_TTYPE, 1, 0 }, + { TELNET_TELOPT_ECHO, TELNET_WONT, TELNET_DO }, + { TELNET_TELOPT_COMPRESS2, TELNET_WONT, TELNET_DO }, + { TELNET_TELOPT_TTYPE, TELNET_WILL, TELNET_DONT }, { -1, 0, 0 } };