documentation
diff --git a/README b/README
index 20ee2ba..97c84e7 100644
--- a/README
+++ b/README
@@ -2,8 +2,10 @@
libtelnet - TELNET protocol handling library
=====================================================================
-Sean Middleditch
-sean@sourcemud.org
+ http://github.com/elanthis/libtelnet
+
+ Sean Middleditch
+ sean@sourcemud.org
---------------------------------------------------------------------
The author or authors of this code dedicate any and all copyright
@@ -35,23 +37,239 @@
and disabling options, or processing subrequests) must be implemented
by the application author.
+For more information on the TELNET protocol, see:
+
+ http://www.faqs.org/rfcs/rfc854.html
+
II. LIBTELNET API
=====================================================================
-FIXME: fill in notes about user-facing API
+The libtelnet API contains several distinct parts. The first part is
+the basic initialization and deinitialization routines. The second
+part is a single function for pushing received data into the
+libtelnet processor. The third part is the libtelnet_send_*()
+functions, which generate TELNET commands and ensure data is properly
+formatted before sending over the wire. The final part is the
+libtelnet_*_cb() functions.
+
+The libtelnet_*_cb() functions (callback fuctions from here out) are
+not actually implemented by libtelnet, but are used by it. The
+libtelnet.h header includes declarations for the functions but it is
+the application's responsibility to provide implementations of these
+functions.
+
+IIa. Initialization
+
+ struct libtelnet_t;
+ This structure represents the state of the TELNET protocol for a
+ single connection. Each connection utilizing TELNET must have
+ its own libtelnet_t structure, which is passed to all libtelnet
+ API calls.
+
+ void libtelnet_init(struct libtelnet_t *telnet,
+ enum libtelnet_mode_t mode);
+ The libtelnet_init() function is responsible for initializing
+ the data in a libtelnet_t structure. It must be called
+ immediately after establishing a connection and before any other
+ libtelnet API calls are made.
+
+ The mode parameter must be one of LIBTELNET_MODE_SERVER or
+ LIBTELNET_MODE_CLIENT. These slightly alter the behavior of
+ libtelnet in certain instances. If you are implementing a
+ TELNET server, use the SERVER mode. If you are implementing a
+ client, use the CLIENT mode.
+
+ boid libtelnet_free(struct libtelnet_t *telnet);
+ Releases any internal memory allocated by libtelnet. This must
+ be called whenever a connection is closed, or you will incur
+ memory leaks.
+
+IIb. Receiving Data
+
+ void libtelnet_push(struct libtelnet_t *telnet,
+ unsigned char *buffer, unsigned int size, void *user_data);
+ When your application receives data over the socket from the
+ remote end, it must pass the received bytes into this function.
+ Callback functions will be invoked as the buffer is processed,
+ and the user_data parameter will be passed to each callback.
+
+IIc. Sending Data
+
+ Note that all of the libtelnet_send_*() functions will invoke
+ the libtelnet_send_cb() callback function. The user_data parameter
+ to each of these functions is passed through to the callback.
+
+ void libtelnet_send_command(struct libtelnet_t *telnet,
+ unsigned char cmd, void *user_data);
+ Sends a single "simple" TELNET command, such as the GO-AHEAD
+ commands (255 249).
+
+ void libtelnet_send_negotiate(struct libtelnet_t *telnet,
+ unsigned char cmd, unsigned char opt, void *user_data);
+ Sends a TELNET negotiation command. The cmd parameter must be
+ one of LIBTELNET_WILL, LIBTELNET_DONT, LIBTELNET_DO, or
+ LIBTELNET_DONT. The opt parameter is the option to
+ negotiate.
+
+ void libtelnet_send_data(struct libtelnet_t *telnet,
+ unsigned char *buffer, unsigned int size, void *user_data);
+ Sends raw data, which would be either the process output from
+ a server or the user input from a client.
+
+ void libtelnet_send_subnegotiation(struct libtelnet_t *telnet,
+ unsigned char opt, unsigned char *buffer, unsigned int size,
+ void *user_data);
+ Sends a TELNET sub-negotiation command. The opt parameter
+ is the sub-negotiation option.
+
+IId. Callbacks
+
+ The application is responsible for implementing these functions.
+ The function definitions are included in libtelnet.h. If any of
+ these functions are not implemented and linked into the application
+ then libtelnet.o will generate linker errors for undefined symbols.
+
+ void libtelnet_data_cb(struct libtelnet_t *telnet,
+ unsigned char *buffer, unsigned int size, void *user_data);
+ Regular data has been received by the remote end. For a server,
+ this would be input typed by the client; for a client, this is
+ process output generated by the server.
+
+ Note that data is not line-buffered by libtelnet. A single
+ line of input may be broken into pieces and given to
+ consecutive calls to libtelnet_data_cb(). If you are doing
+ line-based processing of data, it is your responsibility to
+ buffer data and find the line breaks.
+
+ void libtelnet_send_cb(struct libtelnet_t *telnet,
+ unsigned char *buffer, unsigned int size, void *user_data);
+ This is called whenever libtelnet has generated output to be
+ send to the remote end of the connection. In most cases this
+ will be a simple wrapper arround your applications network
+ output buffering/transmission code.
+
+ You can pass socket information through the user_data
+ parameter to libtelnet calls so that it is available in this
+ callback.
+
+ void libtelnet_command_cb(struct libtelnet_t *telnet,
+ unsigned char cmd, void *user_data);
+ Called whenever a "simpler" TELNET command has arrived, such
+ as GO-AHEAD commands (255 249). The necessary processing
+ depends on the specific commands; see the TELNET RFC for
+ more information.
+
+ void libtelnet_negotiate_cb(struct libtelnet_t *telnet,
+ unsigned char cmd, unsigned char opt, void *user_data);
+ This function is called whenever a TELNET negotiation command
+ has been received. The cmd parameter will be one of
+ LIBTELNET_WILL, LIBTELNET_WONT, LIBTELNET_DO, or LIBTELNET_DONT.
+ The opt parameter is the option being negotiated.
+
+ libtelnet does not currently manage negotiation for you. For
+ best practice in implementing TELNET negotiation, see:
+
+ http://www.faqs.org/rfcs/rfc1143.html
+
+ void libtelnet_subnegotiation_cb(struct libtelnet_t *telnet,
+ unsigned char opt, unsigned char *data, unsigned int size,
+ void *user_data);
+ Called whenever a TELNET sub-negotiation has been received.
+ Sub-negotiations include the NAWS option for communicating
+ terminal size to a server, the NEW-ENVIRON and TTYPE options
+ for negotiating terminal features, and MUD-centric protocols
+ such as ZMP, MSSP, and MCCP2.
+
+ The opt parameter is the option under sub-negotiation. The
+ remaining data (if any) is passed in the buffer.
+
+ void libtelnet_compress_cb(struct libtelnet_t *telnet,
+ char enabled, void *user_data);
+ The callback is invoked whenever the COMPRESS2 (MCCP2)
+ feature is enabled or disabled. For servers, this is called
+ immediately after beginning compression after a client accepts
+ the COMPRESS2 option. For clients, this is called immediately
+ after a compress stream begin or ends.
+
+ The enabled parameter is 1 if compression has begun and 0 if
+ compression has ended.
III. INTEGRATING LIBTELNET
=====================================================================
FIXME: fill in notes about implementing the libtelnet_*_cb functions
-IV. OUTPUT PROCESSING
+IV. SAFETY AND CORRECTNESS CONSIDERATIONS
=====================================================================
-FIXME: fill in notes about output buffering recommendations
+Your existing application may make heavy use of its own output
+buffering and transmission commands, including hand-made routines
+for sending TELNET commands and sub-negotiation requests. There are
+at times subtle issues that need to be handled when communication
+over the TELNET protocol, not least of which is the need to escape
+any byte value 0xFF with a special TELNET command.
-V. SAFETY AND CORRECTNESS CONSIDERATIONS
+For these reasons, it is very important that applications making use
+of libtelnet always make use of the libtelnet_send_*() family of
+functions for all data being sent over the TELNET connection.
+
+V. MCCP2 COMPRESSION
=====================================================================
-FIXME: fill in notes about recommending the user of libtelnet over
-all output functions for ensuring safety
+The MCCP2 (COMPRESS2) TELNET extension allows for the compression of
+all traffic sent from server to client. For more information:
+
+ http://www.mudbytes.net/index.php?a=articles&s=mccp
+
+libtelnet transparently supports MCCP2. For a server to support
+MCCP2, the application must begin negotiation of the COMPRESS2
+option using libtelnet_send_negotiate(), for example:
+
+ libtelnet_send_negotiate(&telnet, LIBTELNET_WILL,
+ LIBTELNET_OPTION_COMPRESS2, user_data);
+
+libtelnet will automatically detect if the client responds favoribly
+and will begin compressing data. For clients, no action must be
+taken, as libtelnet will automatically handle the requests.
+
+NOTE: libtelnet will still invoke the callback functions for
+negotiation and sub-negotiation commands relating to MCCP2. Do not
+respond to these.
+
+In order for libtelnet to support MCCP2, zlib must be installed and
+enabled when compiling libtelnet. Use -DHAVE_ZLIB to enable zlib
+when compiling libtelnet.c and pass -lz to the linker to link in the
+zlib shared library.
+
+VI. TELNET PROXY UTILITY
+=====================================================================
+
+The telnet-proxy utility is a small application that serves both as
+a testbed for libtelnet and as a powerful debugging tool for TELNET
+servers and clients.
+
+To use telnet-proxy, you must first compile it using:
+
+ $ make
+
+If you do not have zlib installed and wish to disable MCCP2 support
+then you must first edit the Makefile and remove the -DHAVE_ZLIB and
+the -lz from the compile flags.
+
+To run telnet-proxy, you simply give it the server's IP address
+(telnet-proxy does not support hostname resolution, nor IPv6), the
+server's port number, and the port number that telnet-proxy should
+listen on. For example, to connect to the server on 209.85.171.100
+port 7800 and to listen on port 5000, run:
+
+ $ ./telnet-proxy 209.85.171.100 7800 5000
+
+You can then connect to the host telnet-proxy is running on (e.g.
+127.0.0.1, or the machine's public IP) on port 500 and you will
+automatically be proxied into 209.85.171.100.
+
+telnet-proxy will display status information about the data
+passing through both ends of the tunnel. Once either end
+disconnects, telnet-proxy will close. telnet-proxy can only
+support a single tunnel at a time and must be restarted for each
+connection.